--- jsampler/trunk/src/org/jsampler/DefaultSamplerChannelModel.java 2007/04/02 20:48:15 1142 +++ jsampler/trunk/src/org/jsampler/DefaultSamplerChannelModel.java 2007/04/02 21:18:31 1143 @@ -1,7 +1,7 @@ /* * JSampler - a java front-end for LinuxSampler * - * Copyright (C) 2005 Grigor Kirilov Iliev + * Copyright (C) 2005-2006 Grigor Iliev * * This file is part of JSampler. * @@ -30,26 +30,31 @@ import net.sf.juife.event.TaskEvent; import net.sf.juife.event.TaskListener; +import org.jsampler.event.EffectSendsEvent; +import org.jsampler.event.EffectSendsListener; import org.jsampler.event.SamplerChannelEvent; import org.jsampler.event.SamplerChannelListener; +import org.jsampler.task.Channel; +import org.jsampler.task.Channel.SetMidiInputChannel; +import org.jsampler.task.Channel.SetMidiInputDevice; +import org.jsampler.task.Channel.SetMidiInputPort; +import org.jsampler.task.Channel.SetMute; +import org.jsampler.task.Channel.SetSolo; +import org.jsampler.task.Channel.SetVolume; +import org.jsampler.task.Channel.UpdateFxSendInfo; import org.jsampler.task.DuplicateChannels; import org.jsampler.task.LoadEngine; import org.jsampler.task.LoadInstrument; -import org.jsampler.task.ResetChannel; -import org.jsampler.task.SetChannelAudioOutputDevice; -import org.jsampler.task.SetChannelMidiInputChannel; -import org.jsampler.task.SetChannelMidiInputDevice; -import org.jsampler.task.SetChannelMidiInputPort; -import org.jsampler.task.SetChannelVolume; -import org.jsampler.task.SetMuteChannel; -import org.jsampler.task.SetSoloChannel; +import org.linuxsampler.lscp.FxSend; import org.linuxsampler.lscp.SamplerChannel; /** * This class provides default implementation of the SamplerChannelModel interface. + * Note that all methods that begin with setBackend alter the settings + * on the backend side. * @author Grigor Iliev */ public class DefaultSamplerChannelModel implements SamplerChannelModel { @@ -60,6 +65,10 @@ private final Vector listeners = new Vector(); + private final Vector fxListeners = new Vector(); + + private final Vector fxSends = new Vector(); + /** * Creates a new instance of DefaultSamplerChannelModel using the * specified channel settings. @@ -87,11 +96,25 @@ removeSamplerChannelListener(SamplerChannelListener l) { listeners.remove(l); } /** + * Registers the specified listener for receiving event messages. + * @param l The EffectSendsListener to register. + */ + public void + addEffectSendsListener(EffectSendsListener l) { fxListeners.add(l); } + + /** + * Removes the specified listener. + * @param l The EffectSendsListener to remove. + */ + public void + removeEffectSendsListener(EffectSendsListener l) { fxListeners.remove(l); } + + /** * Gets the sampler channel number. * @return The sampler channel number or -1 if the sampler channel number is not set. */ public int - getChannelID() { return channel == null ? -1 : channel.getChannelID(); } + getChannelId() { return channel == null ? -1 : channel.getChannelId(); } /** * Gets the current settings of the sampler channel. @@ -104,8 +127,7 @@ /** * Sets the current settings of the sampler channel. * Note that this method does not changes the channel settings on - * the back-end. It is invoked to update them when the back-end - * notifies that the channel settings are changed. + * the backend. It is invoked just notify for channel settings' changes. * @param channel A SamplerChannel instance containing * the new settings for this sampler channel. * @throws IllegalArgumentException If channel is null. @@ -128,6 +150,8 @@ /** * Sets the number of active disk streams. + * Note that this method does not alter the number + * of active disk streams on the backend side. * @param count The new number of active disk streams. */ public void @@ -147,6 +171,8 @@ /** * Sets the number of active voices. + * Note that this method does not alter the number + * of active voices on the backend side. * @param count The new number of active voices. */ public void @@ -158,12 +184,12 @@ } /** - * Sets the sampler engine type to be used. + * Schedules a new task for setting the sampler engine type to be used. * @param engine The name of the engine type to be used. */ public void - setEngineType(String engine) { - final LoadEngine loadEngine = new LoadEngine(engine, getChannelID()); + setBackendEngineType(String engine) { + final LoadEngine loadEngine = new LoadEngine(engine, getChannelId()); final SamplerChannelEvent event = new SamplerChannelEvent(this); loadEngine.addTaskListener(new TaskListener() { @@ -183,13 +209,13 @@ } /** - * Sets the mute mode of the channel. + * Schedules a new task for setting the mute mode of the channel. * @param mute Specifies the mute mode. If true the channel is muted, else * the channel is unmuted. */ public void - setMute(boolean mute) { - final SetMuteChannel smc = new SetMuteChannel(getChannelID(), mute); + setBackendMute(boolean mute) { + final SetMute smc = new SetMute(getChannelId(), mute); final SamplerChannelEvent event = new SamplerChannelEvent(this); smc.addTaskListener(new TaskListener() { @@ -209,13 +235,13 @@ } /** - * Sets the solo mode of the channel. + * Schedules a new task for setting on the backend side the solo mode of the channel. * @param solo Specifies the solo mode. If true the channel is soloed, else * the channel is unsoloed. */ public void - setSolo(boolean solo) { - final SetSoloChannel ssc = new SetSoloChannel(getChannelID(), solo); + setBackendSolo(boolean solo) { + final SetSolo ssc = new SetSolo(getChannelId(), solo); final SamplerChannelEvent event = new SamplerChannelEvent(this); ssc.addTaskListener(new TaskListener() { @@ -235,12 +261,12 @@ } /** - * Sets the channel volume. + * Schedules a new task for setting the channel volume on the backend side. * @param volume Specifies the new volume value. */ public void - setVolume(float volume) { - final SetChannelVolume scv = new SetChannelVolume(getChannelID(), volume); + setBackendVolume(float volume) { + final SetVolume scv = new SetVolume(getChannelId(), volume); final SamplerChannelEvent event = new SamplerChannelEvent(this); scv.addTaskListener(new TaskListener() { @@ -260,12 +286,13 @@ } /** - * Sets the MIDI input device of the channel represented by this model. - * @param deviceID Specifies the numerical ID of the MIDI input device to be set. + * Schedules a new task for setting on the backend side the MIDI input + * device of the channel represented by this model. + * @param deviceId Specifies the numerical ID of the MIDI input device to be set. */ public void - setMidiInputDevice(int deviceID) { - final Task scmid = new SetChannelMidiInputDevice(getChannelID(), deviceID); + setBackendMidiInputDevice(int deviceId) { + final Task scmid = new SetMidiInputDevice(getChannelId(), deviceId); final SamplerChannelEvent event = new SamplerChannelEvent(this); scmid.addTaskListener(new TaskListener() { @@ -285,12 +312,13 @@ } /** - * Sets the MIDI input port of the channel represented by this model. + * Schedules a new task for setting (on the backend side) the + * MIDI input port of the channel represented by this model. * @param port Specifies the number of the MIDI input port. */ public void - setMidiInputPort(int port) { - final Task scmip = new SetChannelMidiInputPort(getChannelID(), port); + setBackendMidiInputPort(int port) { + final Task scmip = new SetMidiInputPort(getChannelId(), port); final SamplerChannelEvent event = new SamplerChannelEvent(this); scmip.addTaskListener(new TaskListener() { @@ -310,13 +338,14 @@ } /** - * Sets the MIDI channel that the channel represented by this model should listen to. + * Schedules a new task for setting (on the backend side) the MIDI channel + * that the channel represented by this model should listen to. * @param channel Specifies the MIDI channel that the channel * represented by this model should listen to. */ public void - setMidiInputChannel(int channel) { - final Task scmic = new SetChannelMidiInputChannel(getChannelID(), channel); + setBackendMidiInputChannel(int channel) { + final Task scmic = new SetMidiInputChannel(getChannelId(), channel); final SamplerChannelEvent event = new SamplerChannelEvent(this); scmic.addTaskListener(new TaskListener() { @@ -336,12 +365,13 @@ } /** - * Sets the audio output device of the channel represented by this model. - * @param deviceID Specifies the numerical ID of the audio output device to be set. + * Schedules a new task for setting (on the backend side) the audio output + * device of the channel represented by this model. + * @param deviceId Specifies the numerical ID of the audio output device to be set. */ public void - setAudioOutputDevice(int deviceID) { - final Task scaod = new SetChannelAudioOutputDevice(getChannelID(), deviceID); + setBackendAudioOutputDevice(int deviceId) { + final Task scaod = new Channel.SetAudioOutputDevice(getChannelId(), deviceId); final SamplerChannelEvent event = new SamplerChannelEvent(this); scaod.addTaskListener(new TaskListener() { @@ -361,33 +391,292 @@ } /** - * Loads and assigns the specified instrument + * Sets the destination of the destination of the specified audio channel. + * @param audioSrc The numerical ID of the sampler channel's audio + * output channel, which should be rerouted. + * @param audioDst The audio channel of the selected audio output device + * where audioSrc should be routed to. + */ + public void + setBackendAudioOutputChannel(int audioSrc, int audioDst) { + final Task t; + t = new Channel.SetAudioOutputChannel(getChannelId(), audioSrc, audioDst); + final SamplerChannelEvent event = new SamplerChannelEvent(this); + + t.addTaskListener(new TaskListener() { + public void + taskPerformed(TaskEvent e) { + /* + * Because with the invokation of the method the task is considered + * to be done, if the task fails, we must notify for a channel + * changes. This should be done to revert the old channel settings. + */ + if(t.doneWithErrors()) fireSamplerChannelChanged(event); + } + }); + CC.getTaskQueue().add(t); + } + + /** + * Schedules a new task for assigning (on the backend side) the + * specified MIDI instrument map to this sampler channel. + * @param mapId Specify the numerical ID of the MIDI instrument + * map that should be assigned to this sampler + * channel or -1 to remove the current map binding. + */ + public void + setBackendMidiInstrumentMap(int mapId) { + final Task t = new Channel.SetMidiInstrumentMap(getChannelId(), mapId); + final SamplerChannelEvent event = new SamplerChannelEvent(this); + + t.addTaskListener(new TaskListener() { + public void + taskPerformed(TaskEvent e) { + /* + * Because with the invokation of the method the task is considered + * to be done, if the task fails, we must notify for a channel + * changes. This should be done to revert the old channel settings. + */ + if(t.doneWithErrors()) fireSamplerChannelChanged(event); + } + }); + CC.getTaskQueue().add(t); + } + + /** + * Schedules a new task for loading and assigning the specified instrument * to the sampler channel represented by this model. * @param filename The file name of the instrument to be loaded. * @param InstrIndex The index of the instrument in the instrument file to be loaded. */ public void - loadInstrument(String filename, int InstrIndex) { - final Task li = new LoadInstrument(filename, InstrIndex, getChannelID()); + loadBackendInstrument(String filename, int InstrIndex) { + final Task li = new LoadInstrument(filename, InstrIndex, getChannelId()); CC.getTaskQueue().add(li); // We leave this event to be notified by the LinuxSampler notification system. } - /** Resets the channel. */ + /** Schedules a new task for reseting the channel. */ public void - resetChannel() { - CC.getTaskQueue().add(new ResetChannel(getChannelID())); + resetBackendChannel() { + CC.getTaskQueue().add(new org.jsampler.task.Channel.Reset(getChannelId())); // We leave this event to be notified by the LinuxSampler notification system. } - /** Duplicates the channel. */ + /** Schedules a new task for duplicating the channel. */ public void - duplicateChannel() { + duplicateBackendChannel() { CC.getTaskQueue().add(new DuplicateChannels(getChannelInfo())); } + /** + * Schedules a new task for adding a new effect send on the + * backend side. The effect send will be actually added to this model + * when the backend notifies for its creation. + * @param midiCtrl Defines the MIDI controller, which + * will be able alter the effect send level. + */ + public void + addBackendFxSend(int midiCtrl) { + CC.getTaskQueue().add(new Channel.AddFxSend(getChannelId(), midiCtrl)); + // We leave this event to be notified by the LinuxSampler notification system. + } + + /** + * Schedules a new task for adding a new effect send on the + * backend side. The effect send will be actually added to this model + * when the backend notifies for its creation. + * @param midiCtrl Defines the MIDI controller, which + * will be able alter the effect send level. + * @param name The name of the effect send entity. + * The name does not have to be unique. + */ + public void + addBackendFxSend(int midiCtrl, String name) { + CC.getTaskQueue().add(new Channel.AddFxSend(getChannelId(), midiCtrl, name)); + // We leave this event to be notified by the LinuxSampler notification system. + } + + /** + * Adds the specified effect send. + * @param fxSend The effect send to be added. + */ + public void + addFxSend(FxSend fxSend) { + fxSends.add(fxSend); + fireFxSendAdded(fxSend); + } + + /** + * Schedules a new task for removing the specified effect send on the backend side. + * @param fxSendId The ID of the effect send to remove. + */ + public void + removeBackendFxSend(int fxSendId) { + CC.getTaskQueue().add(new Channel.RemoveFxSend(getChannelId(), fxSendId)); + } + + /** + * Gets the effect send at the specified position. + * @param index The index of the effect send to be returned. + * @return The effect send at the specified position. + */ + public FxSend + getFxSend(int index) { return fxSends.get(index); } + + /** + * Gets the effect send with the specified ID. + * @param fxSendId The ID of the effect send to return. + * @return The effect send with the specified ID or null + * if there is no effect send with ID fxSendId. + */ + public FxSend + getFxSendById(int fxSendId) { + for(FxSend fxs : fxSends) { + if(fxs.getFxSendId() == fxSendId) return fxs; + } + + return null; + } + + /** + * Removes the effect send at the specified position. + * @param index The position of the effect send to remove. + * @return The removed effect send. + */ + public FxSend + removeFxSend(int index) { + FxSend fxs = fxSends.remove(index); + fireFxSendRemoved(fxs); + return fxs; + } + + /** + * Removes the specified effect send. + * @param fxSendId The ID of the effect send to remove. + * @return true if the effect send is removed successfully, false + * if the channel does not contain effect send with ID fxSendId. + */ + public boolean + removeFxSendById(int fxSendId) { + for(int i = 0; i < fxSends.size(); i++) { + FxSend fxs = fxSends.get(i); + if(fxs.getFxSendId() == fxSendId) { + fxSends.remove(i); + fireFxSendRemoved(fxs); + return true; + } + } + + return false; + } + + /** Removes all effect sends from this channel. */ + public void + removeAllFxSends() { + for(int i = fxSends.size() - 1; i >= 0; i--) { + FxSend fxs = fxSends.get(i); + fxSends.removeElementAt(i); + fireFxSendRemoved(fxs); + } + } + + /** + * Updates the specified effect send. + * @param fxSend The effect send to update. + */ + public void + updateFxSend(FxSend fxSend) { + for(int i = 0; i < fxSends.size(); i++) { + FxSend fxs = fxSends.get(i); + if(fxs.getFxSendId() == fxSend.getFxSendId()) { + fxSends.setElementAt(fxSend, i); + fireFxSendUpdated(fxSend); + return; + } + } + } + + /** + * Gets the current number of effect sends. + * @return The current number of effect sends. + */ + public int + getFxSendCount() { return fxSends.size(); } + + /** + * Gets the current list of effect sends. + * @return The current list of effect sends. + */ + public FxSend[] + getFxSends() { return fxSends.toArray(new FxSend[fxSends.size()]); } + + /** + * Sets the name of the specified effect send. + * @param fxSend The numerical ID of the effect send. + * @param name The new name of the effect send entity. + */ + public void + setBackendFxSendName(final int fxSend, String name) { + final Task t = new Channel.SetFxSendName(getChannelId(), fxSend, name); + t.addTaskListener(new TaskListener() { + public void + taskPerformed(TaskEvent e) { + /* + * Because with the invokation of the method the task is considered + * to be done, if the task fails, we must update the settings. + */ + if(t.doneWithErrors()) { + int id = getChannelId(); + CC.getTaskQueue().add(new UpdateFxSendInfo(id, fxSend)); + } + } + }); + CC.getTaskQueue().add(t); + } + + /** + * Sets the destination of an effect send's audio channel. + * @param fxSend The numerical ID of the effect send entity to be rerouted. + * @param audioSrc The numerical ID of the effect send's audio output channel, + * which should be rerouted. + * @param audioDst The audio channel of the selected audio output device + * where audioSrc should be routed to. + */ + public void + setBackendFxSendAudioOutputChannel(int fxSend, int audioSrc, int audioDst) { + Task t = new Channel.SetFxSendAudioOutputChannel ( + getChannelId(), fxSend, audioSrc, audioDst + ); + + CC.getTaskQueue().add(t); + } + + /** + * Sets the MIDI controller of the specified effect send. + * @param fxSend The numerical ID of the effect send. + * @param midiCtrl The MIDI controller which shall be + * able to modify the effect send's send level. + */ + public void + setBackendFxSendMidiController(int fxSend, int midiCtrl) { + Task t = new Channel.SetFxSendMidiController(getChannelId(), fxSend, midiCtrl); + CC.getTaskQueue().add(t); + } + + /** + * Sets the volume of the specified effect send. + * @param fxSend The numerical ID of the effect + * send, which volume should be changed. + * @param level The new volume value. + */ + public void + setBackendFxSendLevel(int fxSend, float level) { + CC.getTaskQueue().add(new Channel.SetFxSendLevel(getChannelId(), fxSend, level)); + } + /** Notifies listeners that the sampler channel settings has changed. */ protected void fireSamplerChannelChanged() { @@ -447,4 +736,66 @@ fireVoiceCountChanged(SamplerChannelEvent e) { for(SamplerChannelListener l : listeners) l.voiceCountChanged(e); } + + /** + * Notifies listeners that the specified effect send has been added to the channel. + */ + protected void + fireFxSendAdded(FxSend fxSend) { + final EffectSendsEvent e = new EffectSendsEvent(this, fxSend); + + SwingUtilities.invokeLater(new Runnable() { + public void + run() { fireFxSendAdded(e); } + }); + } + + /** + * Notifies listeners that the specified effect send has been added to the channel. + * This method should be invoked from the event-dispatching thread. + */ + protected void + fireFxSendAdded(EffectSendsEvent e) { + for(EffectSendsListener l : fxListeners) l.effectSendAdded(e); + } + + /** Notifies listeners that the specified effect send has been removed. */ + protected void + fireFxSendRemoved(FxSend fxSend) { + final EffectSendsEvent e = new EffectSendsEvent(this, fxSend); + + SwingUtilities.invokeLater(new Runnable() { + public void + run() { fireFxSendRemoved(e); } + }); + } + + /** + * Notifies listeners that the specified effect send has been removed. + * This method should be invoked from the event-dispatching thread. + */ + protected void + fireFxSendRemoved(EffectSendsEvent e) { + for(EffectSendsListener l : fxListeners) l.effectSendRemoved(e); + } + + /** Notifies listeners that the specified effect send has been updated. */ + protected void + fireFxSendUpdated(FxSend fxSend) { + final EffectSendsEvent e = new EffectSendsEvent(this, fxSend); + + SwingUtilities.invokeLater(new Runnable() { + public void + run() { fireFxSendUpdated(e); } + }); + } + + /** + * Notifies listeners that the specified effect send has been updated. + * This method should be invoked from the event-dispatching thread. + */ + protected void + fireFxSendUpdated(EffectSendsEvent e) { + for(EffectSendsListener l : fxListeners) l.effectSendChanged(e); + } }