/*
* FluidSynthesizer.java
*
* This file is part of Tritonus: http://www.tritonus.org/
*/
/*
* Copyright (c) 2006 by Henri Manson
* Copyright (c) 2006 by Matthias Pfisterer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
|<--- this code is formatted to fit into 80 columns --->|
*/
package org.tritonus.midi.device.fluidsynth;
import javax.sound.midi.*;
import org.tritonus.share.TDebug;
import org.tritonus.share.midi.TMidiChannel;
import org.tritonus.share.midi.TDirectSynthesizer;
import org.tritonus.midi.sb.fluidsynth.FluidSoundbank;
public class FluidSynthesizer
extends TDirectSynthesizer
implements Synthesizer
{
private MidiChannel channels[];
private FluidSoundbank defaultSoundbank;
private int defaultbankSfontID;
// native pointers 64 bit maximum
private long settingsPtr;
private long synthPtr;
private long audioDriverPtr;
static
{
loadNativeLibrary();
}
/** Load the native library for fluidsynth.
*/
private static void loadNativeLibrary()
{
if (TDebug.TraceFluidNative) TDebug.out("FluidSynthesizer.loadNativeLibrary(): loading native library tritonusfluid");
try
{
System.loadLibrary("tritonusfluid");
// only reached if no exception occures
setTrace(TDebug.TraceFluidNative);
}
catch (Error e)
{
if (TDebug.TraceFluidNative ||
TDebug.TraceAllExceptions)
{
TDebug.out(e);
}
// throw e;
}
if (TDebug.TraceFluidNative) TDebug.out("FluidSynthesizer.loadNativeLibrary(): loaded");
}
/**
* Constructor.
*/
public FluidSynthesizer(MidiDevice.Info info) throws Exception
{
super(info);
}
protected void openImpl()
throws MidiUnavailableException
{
if (newSynth() < 0)
{
throw new MidiUnavailableException("Low-level initialization of the synthesizer failed");
}
if (TDebug.TraceSynthesizer) TDebug.out("FluidSynthesizer: " + Long.toHexString(synthPtr));
channels = new MidiChannel[16];
for (int i = 0; i < 16; i++)
{
channels[i] = new NewFluidMidiChannel(i);
}
String sfontFile =
System.getProperty("tritonus.fluidsynth.defaultsoundbank");
if (sfontFile != null && ! sfontFile.equals(""))
{
int sfontID = loadSoundFont(sfontFile);
setDefaultSoundBank(sfontID);
String strBankOffset =
System.getProperty("tritonus.fluidsynth.defaultsoundbankoffset");
if (strBankOffset != null && ! strBankOffset.equals(""))
{
setBankOffset(sfontID, Integer.parseInt(strBankOffset));
}
}
}
protected void closeImpl()
{
if (TDebug.TraceSynthesizer) TDebug.out("FluidSynthesizer.closeImpl(): "
+ Long.toHexString(synthPtr));
deleteSynth();
super.closeImpl();
}
public void setDefaultSoundBank(int sfontID)
{
defaultSoundbank = new FluidSoundbank(this, sfontID);
defaultbankSfontID = sfontID;
}
protected void finalize(){
if (TDebug.TraceSynthesizer) TDebug.out("finalize: " + Long.toHexString(synthPtr));
close();
}
public native int loadSoundFont(String filename);
public native void setBankOffset(int sfontID, int offset);
public native void setGain(float gain);
/* $$mp: currently not functional because fluid_synth_set_reverb_preset()
* is not present in fluidsynth 1.0.6.
*/
public native void setReverbPreset(int reverbPreset);
public native int getMaxPolyphony();
protected native int newSynth();
protected native void deleteSynth();
/**
* Turns a note on.
*
* The implementation calls fluid_synth_noteoff().
*
* @param nChannel the channel
* @param nNoteNumber the note
* @param nVelocity the velocity
*/
native void noteOn(int nChannel, int nNoteNumber, int nVelocity);
/**
* Turns a note off.
*
* The implementation calls fluid_synth_noteon().
*
* @param nChannel the channel
* @param nNoteNumber the note
* @param nVelocity the velocity
*/
native void noteOff(int nChannel, int nNoteNumber, int nVelocity);
/**
* Changes a controller on the synthesizer.
*
* The implementation calls fluid_synth_cc().
*
* @param nChannel the channel
* @param nController the controller number
* @param nValue the controller value
*/
native void controlChange(int nChannel, int nController, int nValue);
/**
* Obtains the value of a controller.
*
* The implementation calls fluid_synth_get_cc().
*
* @param nChannel the channel
* @param nController the controller number
* @return the controller value
*/
native int getController(int nChannel, int nController);
/**
* Sets the program for a channel.
*
* The implementation calls fluid_synth_program_change().
*
* @param nChannel the channel
* @param nProgram the program number
*/
native void programChange(int nChannel, int nProgram);
/**
* Obtains the program set for a channel.
*
* The implementation calls fluid_synth_get_program().
*
* @param nChannel the channel
* @return the program number set for this channel
*/
native int getProgram(int nChannel);
/**
* Sets the pitch bend for a channel.
*
* The implementation calls fluid_synth_pitch_bend().
*
* @param nChannel the channel
* @param nBend the pitch bend value
*/
native void setPitchBend(int nChannel, int nBend);
/**
* Obtains the pitch bend for a channel.
*
* The implementations calls fluid_synth_get_pitch_bend().
*
* @param nChannel the channel
* @return the pitch bend value.
*/
native int getPitchBend(int nChannel);
/** Sets tracing in the native code.
* Note that this method can either be called directly or (recommended)
* the system property "tritonus.TraceFluidNative" can be set to true.
*
* @see org.tritonus.share.TDebug
*/
public static native void setTrace(boolean bTrace);
public boolean isSoundbankSupported(Soundbank soundbank)
{
return (soundbank instanceof FluidSoundbank);
}
public boolean loadAllInstruments(Soundbank soundbank)
{
checkSoundbank(soundbank);
return true;
}
public void unloadAllInstruments(Soundbank soundbank)
{
checkSoundbank(soundbank);
}
public void unloadInstruments(Soundbank soundbank, Patch[] patchList)
{
checkSoundbank(soundbank);
}
public boolean loadInstruments(Soundbank soundbank, Patch[] patchList)
{
checkSoundbank(soundbank);
return true;
}
public void unloadInstrument(Instrument instrument)
{
checkInstrument(instrument);
}
public boolean loadInstrument(Instrument instrument)
{
checkInstrument(instrument);
return true;
}
public Instrument[] getAvailableInstruments()
{
return null;
}
public MidiChannel[] getChannels()
{
return channels;
}
public Soundbank getDefaultSoundbank()
{
return defaultSoundbank;
}
public long getLatency()
{
return 0L;
}
public Instrument[] getLoadedInstruments()
{
return null;
}
public VoiceStatus[] getVoiceStatus()
{
return new VoiceStatus[0];
}
public boolean remapInstrument(Instrument from, Instrument to)
{
checkInstrument(from);
checkInstrument(to);
return true;
}
/** Checks if the soundbank is supported by this synthesizer implementation.
*
* @param sb the soundbank to check
* @throws IllegalArgumentException if the soundbank is not supported
*/
private void checkSoundbank(Soundbank sb)
{
if (! isSoundbankSupported(sb))
throw new IllegalArgumentException("soundbank is not supported");
}
/**
* Checks if the instrument belongs to a soundbank that is supported by this
* synthesizer implementation.
*
* @param instr the instrument to check
* @throws IllegalArgumentException if the instrument's soundbank
* is not supported
*/
private void checkInstrument(Instrument instr)
{
checkSoundbank(instr.getSoundbank());
}
private class NewFluidMidiChannel
extends TMidiChannel
{
public NewFluidMidiChannel(int nChannel)
{
super(nChannel);
}
public void noteOn(int nNoteNumber, int nVelocity)
{
FluidSynthesizer.this.noteOn(getChannel(), nNoteNumber, nVelocity);
}
public void noteOff(int nNoteNumber, int nVelocity)
{
FluidSynthesizer.this.noteOff(getChannel(), nNoteNumber, nVelocity);
}
public void noteOff(int nNoteNumber)
{
noteOff(nNoteNumber, 0);
}
/**
* Fluidsynth does not implement poly pressure (aftertouch). Therefore,
* this method does nothing.
*/
public void setPolyPressure(int nNoteNumber, int nPressure)
{
}
/**
* Fluidsynth does not implement poly pressure (aftertouch). Therefore,
* this method always return 0.
*/
public int getPolyPressure(int nNoteNumber)
{
return 0;
}
/**
* Fluidsynth does not implement channel pressure. Therefore,
* this method does nothing.
*/
public void setChannelPressure(int nPressure)
{
}
/**
* Fluidsynth does not implement channel pressure. Therefore,
* this method always returns 0.
*/
public int getChannelPressure()
{
return 0;
}
public void controlChange(int nController, int nValue)
{
FluidSynthesizer.this.controlChange(getChannel(), nController,
nValue);
}
public int getController(int nController)
{
return FluidSynthesizer.this.getController(getChannel(),
nController);
}
public void programChange(int nProgram)
{
FluidSynthesizer.this.programChange(getChannel(), nProgram);
}
public int getProgram()
{
return FluidSynthesizer.this.getProgram(getChannel());
}
public void setPitchBend(int nBend)
{
FluidSynthesizer.this.setPitchBend(getChannel(), nBend);
}
public int getPitchBend()
{
return FluidSynthesizer.this.getPitchBend(getChannel());
}
// TODO: emulate by manipulating volume
public void setMute(boolean bMute)
{
}
public boolean getMute()
{
return false;
}
public void setSolo(boolean bSolo)
{
}
public boolean getSolo()
{
return false;
}
}
}
/* FluidSynthesizer.java */