/*
* Created on Sep 12, 2004
*
* Copyright (c) 2005 Peter Johan Salomonsen (http://www.petersalomonsen.com)
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Frinika is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.synth;
import com.frinika.voiceserver.VoiceServer;
import com.frinika.voiceserver.VoiceInterrupt;
import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Vector;
import javax.sound.midi.*;
import com.frinika.audio.*;
import com.frinika.synth.envelope.MidiVolume;
/**
* @author Peter Johan Salomonsen
*
*/
public abstract class Synth implements MidiChannel {
protected boolean sustain = false;
protected HashMap<Integer,Oscillator> keys = new HashMap<Integer,Oscillator>();
protected HashMap<Integer,Oscillator> sustainedKeys = new HashMap<Integer,Oscillator>();
protected LinkedList<Oscillator> oscillators = new LinkedList<Oscillator>();
protected PreOscillator preOscillator;
protected PostOscillator postOscillator;
private String instrumentName = "New Synth";
private Vector<InstrumentNameListener> instrumentNameListeners = new Vector<InstrumentNameListener>();
private boolean mute;
SynthRack frinikaSynth;
public Synth(SynthRack synth)
{
this.frinikaSynth = synth;
preOscillator = new PreOscillator(this);
postOscillator = new PostOscillator(this);
preOscillator.nextVoice = postOscillator;
postOscillator.nextVoice = MasterVoice.getDefaultInstance();
synth.getVoiceServer().addTransmitter(postOscillator);
synth.getVoiceServer().addTransmitter(preOscillator);
}
protected synchronized void addOscillator(int noteNumber, Oscillator osc)
{
try
{
if(sustain)
{
sustainedKeys.get(new Integer(noteNumber)).release();
sustainedKeys.remove(new Integer(noteNumber));
}
else
{
keys.get(new Integer(noteNumber)).release();
keys.remove(new Integer(noteNumber));
}
} catch(NullPointerException e) {}
osc.nextVoice = postOscillator;
frinikaSynth.getVoiceServer().addTransmitter(osc);
keys.put(new Integer(noteNumber),osc);
oscillators.add(osc);
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#noteOff(int, int)
*/
public void noteOff(int noteNumber, int velocity) {
noteOff(noteNumber);
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#noteOff(int)
*/
public synchronized void noteOff(int noteNumber) {
if(sustain)
sustainedKeys.put(new Integer(noteNumber),keys.get(new Integer(noteNumber)));
else
{
Oscillator voice = keys.get(new Integer(noteNumber));
if(voice!=null)
voice.release();
}
keys.remove(new Integer(noteNumber));
}
public abstract void loadSettings(Serializable settings);
public abstract Serializable getSettings();
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#setPolyPressure(int, int)
*/
public void setPolyPressure(int noteNumber, int pressure) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getPolyPressure(int)
*/
public int getPolyPressure(int noteNumber) {
// TODO Auto-generated method stub
return 0;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#setChannelPressure(int)
*/
public void setChannelPressure(int pressure) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getChannelPressure()
*/
public int getChannelPressure() {
// TODO Auto-generated method stub
return 0;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#controlChange(int, int)
*/
public void controlChange(int controller, final int value) {
switch(controller)
{
case 1:
preOscillator.setVibratoAmount(value);
break;
case 2:
preOscillator.setVibratoFrequency((float)value);
break;
case 10:
getAudioOutput().interruptTransmitter(postOscillator, new VoiceInterrupt() {
public void doInterrupt() {
postOscillator.setPan(value);
}
});
break;
case 7:
getAudioOutput().interruptTransmitter(postOscillator, new VoiceInterrupt() {
public void doInterrupt() {
postOscillator.setVolume(MidiVolume.midiVolumeToAmplitudeRatio(value));
}
});
break;
case 20:
getAudioOutput().interruptTransmitter(postOscillator, new VoiceInterrupt() {
public void doInterrupt() {
postOscillator.setOverDriveAmount(value);
}
});
break;
case 22:
getAudioOutput().interruptTransmitter(postOscillator, new VoiceInterrupt() {
public void doInterrupt() {
postOscillator.setEchoAmount(value);
}
});
break;
case 23:
getAudioOutput().interruptTransmitter(postOscillator, new VoiceInterrupt() {
public void doInterrupt() {
postOscillator.setEchoLength(value);
}
});
break;
case 64:
if(value>63 )
enableSustain();
else
disableSustain();
break;
case 91:
getAudioOutput().interruptTransmitter(postOscillator, new VoiceInterrupt() {
public void doInterrupt() {
postOscillator.setReverb(MidiVolume.midiVolumeToAmplitudeRatio(value));
}
});
break;
}
}
void enableSustain()
{
getAudioOutput().interruptTransmitter(preOscillator, new VoiceInterrupt() {
public void doInterrupt() {
sustain = true;
}
});
}
synchronized void disableSustain()
{
sustain = false;
for(Oscillator osc : oscillators)
if(!keys.containsValue(osc))
osc.release();
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getController(int)
*/
public int getController(int controller) {
// TODO Auto-generated method stub
return 0;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#programChange(int)
*/
public void programChange(int program) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#programChange(int, int)
*/
public void programChange(int bank, int program) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getProgram()
*/
public int getProgram() {
// TODO Auto-generated method stub
return 0;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#setPitchBend(int)
*/
public void setPitchBend(final int bend) {
getAudioOutput().interruptTransmitter(preOscillator, new VoiceInterrupt() {
public void doInterrupt() {
preOscillator.pitchBend = bend;
preOscillator.pitchBendFactor = (float)Math.pow(2.0,( ((double)(bend-0x2000) / (double)0x1000)/12.0));
}
});
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getPitchBend()
*/
public int getPitchBend() {
return preOscillator.pitchBend;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#resetAllControllers()
*/
public void resetAllControllers() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#allNotesOff()
*/
public void allNotesOff() {
for(Oscillator osc : oscillators)
osc.release();
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#allSoundOff()
*/
public void allSoundOff() {
for(Oscillator osc : oscillators)
frinikaSynth.getVoiceServer().removeTransmitter(osc);
frinikaSynth.getVoiceServer().removeTransmitter(postOscillator);
frinikaSynth.getVoiceServer().removeTransmitter(preOscillator);
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#localControl(boolean)
*/
public boolean localControl(boolean on) {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#setMono(boolean)
*/
public void setMono(boolean on) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getMono()
*/
public boolean getMono() {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#setOmni(boolean)
*/
public void setOmni(boolean on) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getOmni()
*/
public boolean getOmni() {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#setMute(boolean)
*/
public void setMute(boolean mute) {
this.mute = mute;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getMute()
*/
public boolean getMute() {
return mute;
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#setSolo(boolean)
*/
public void setSolo(boolean soloState) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.sound.midi.MidiChannel#getSolo()
*/
public boolean getSolo() {
// TODO Auto-generated method stub
return false;
}
public VoiceServer getAudioOutput() {
return frinikaSynth.getVoiceServer();
}
public void close()
{
allSoundOff();
}
/**
*
*/
public void showGUI() {
System.out.println("Sorry, no GUI...");
}
/**
* @return
*/
public String getInstrumentName() {
return instrumentName;
}
public void setInstrumentName(String instrumentName)
{
this.instrumentName = instrumentName;
for(InstrumentNameListener instrumentNameListener : instrumentNameListeners )
instrumentNameListener.instrumentNameChange(this,instrumentName);
}
/**
* @param strip
*/
public void addInstrumentNameListener(InstrumentNameListener instrumentNameListener) {
instrumentNameListeners.add(instrumentNameListener);
}
/**
* @param adapter
*/
public void removeInstrumentNameListener(InstrumentNameListener instrumentNameListener) {
instrumentNameListeners.remove(instrumentNameListener);
}
/**
* @return Returns the postOscillator.
*/
public final PostOscillator getPostOscillator() {
return postOscillator;
}
/**
* @return Returns the preOscillator.
*/
public final PreOscillator getPreOscillator() {
return preOscillator;
}
/**
* @return Returns the frinikaSynth.
*/
public SynthRack getFrinikaSynth() {
return frinikaSynth;
}
@Override
public String toString() {
return getInstrumentName();
}
}