--- linuxsampler/trunk/src/Sampler.h 2004/05/02 17:45:43 57 +++ linuxsampler/trunk/src/Sampler.h 2009/07/12 19:52:20 1937 @@ -2,7 +2,8 @@ * * * LinuxSampler - modular, streaming capable sampler * * * - * Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck * + * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * + * Copyright (C) 2005 - 2009 Christian Schoenebeck * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -25,103 +26,123 @@ #include #include +#include "EventListeners.h" #include "common/global.h" -#include "common/LinuxSamplerException.h" -#include "engines/common/Engine.h" -#include "mididriver/MidiInputDevice.h" -#include "audiodriver/AudioOutputDevice.h" +#include "common/Exception.h" +#include "engines/EngineChannel.h" +#include "drivers/midi/MidiInputDevice.h" +#include "drivers/audio/AudioOutputDevice.h" namespace LinuxSampler { - /** - * Which sampler engine to be used. - */ - enum engine_type_t { - engine_type_gig - }; - - /** - * Which audio output system to be used. - */ - enum audio_output_type_t { - audio_output_type_alsa, - audio_output_type_jack - }; - - /** - * Which MIDI input system to be used. - */ - enum midi_input_type_t { - midi_input_type_alsa - }; - // just symbol prototyping class Sampler; - /** LinuxSampler sampler channel + /** @brief LinuxSampler sampler channel * - * Encapsulates one sampler engine, one connection to a MIDI input - * device and one connection to an audio output device. You cannot - * create an instance of this class on you own, you have to use the - * AddSamplerChannel() method of the Sampler object to create a new - * sampler channel. + * Encapsulates a channel of a specific sampler engine type, one + * connection to a MIDI input device and one connection to an audio + * output device. You cannot create an instance of this class on your + * own, you have to use the AddSamplerChannel() method of the Sampler + * object to create a new sampler channel. */ class SamplerChannel { public: /** - * Deploy a sampler engine of the given type for this sampler - * channnel. If there was already a sampler engine deployed on - * this sampler channel, then the old engine will automatically - * be destroyed. + * Assign a sampler engine type to this sampler channel. * - * @param EngineType - type of the engine to deploy + * @param EngineType - type of the engine to use + * @throws Exception - if \a EngineType is invalid + * @see Sampler::AvailableEngineTypes() */ - void LoadEngine(engine_type_t EngineType); + void SetEngineType(String EngineType) throw (Exception); /** - * Connect this sampler channel to an audio output device (that - * is audio output driver) of the given type. If the audio - * output for the desired audio output system is not yet - * created, then it will be created automatically, but with - * default settings though. If this sampler channel was already - * connected to an audio output device, then the old connection - * will automatically be removed before. + * Connect this sampler channel to an audio output device, that + * is an instance of an audio output driver. If this sampler + * channel was already connected to an audio output device, then + * the old connection will automatically be removed before. * - * @param AudioType - audio output system to connect to + * @param pDevice - audio output device to connect to + * @throws Exception in case the audio device is tried to be + * changed while the sampler channel is used by a + * host plugin (e.g. VST, AU, DSSI, LV2) which + * don't allow to change the audio output device */ - void SetAudioOutputDevice(audio_output_type_t AudioType); + void SetAudioOutputDevice(AudioOutputDevice* pDevice) throw (Exception); /** - * Connect this sampler channel to and MIDI input device (that - * is MIDI input driver) of the given type. If the MIDI input - * driver for the desired MIDI input system is not yet created, - * then it will be created automatically, but with default - * settings though. If this sampler channel was already - * connected to a MIDI input device, then the old connection - * will automatically be removed before. + * Connect this sampler channel to a MIDI input device. * - * @param MidiType - MIDI input system to connect to + * @param pDevice - MIDI input device to connect to + * @throws Exception in case the MIDI device is tried to be changed + * while the sampler channel is being used by a + * host plugin (e.g. VST, AU, DSSI, LV2) which + * don't allow to change the MIDI port or even + * device + */ + void SetMidiInputDevice(MidiInputDevice *pDevice) throw (Exception); + + /** + * Connect this sampler channel to a MIDI input port. + * + * @param MidiPort - MIDI port to connect to + * @throws Exception in case the MIDI port is tried to be changed + * while the sampler channel is being used by a + * host plugin (e.g. VST, AU, DSSI, LV2) which + * don't allow to change the MIDI port + */ + void SetMidiInputPort(int MidiPort) throw (Exception); + + /** + * Define on which MIDI channel(s) this sampler channel should + * listen to. By default, that is after creation of a new + * sampler channel, the sampler channel will listen to all MIDI + * channels. + * + * @param MidiChannel - MIDI channel to listen + */ + void SetMidiInputChannel(midi_chan_t MidiChannel); + + /** + * Connect this sampler channel to a MIDI input triplet. + * + * @param pDevice - MIDI input device to connect to + * @param iMidiPort - MIDI port to connect to * @param MidiChannel - optional: MIDI channel on which the * sampler channel should listen to * (default: listen on all MIDI channels) + * @throws Exception in case the MIDI port is tried to be changed + * while the sampler channel is being used by a + * host plugin (e.g. VST, AU, DSSI, LV2) which + * don't allow to change the MIDI port */ - void SetMidiInputDevice(midi_input_type_t MidiType, MidiInputDevice::midi_chan_t MidiChannel = MidiInputDevice::midi_chan_all); + void SetMidiInput(MidiInputDevice* pDevice, int iMidiPort, midi_chan_t MidiChannel = midi_chan_all) throw (Exception); /** - * Returns the engine that was deployed on this sampler channel. + * Returns the EngineChannel object that was deployed on this + * sampler channel appropriate to the given sampler engine type. * * @returns pointer to engine or NULL if no engine deployed */ - Engine* GetEngine(); + EngineChannel* GetEngineChannel(); /** - * Returns the MIDI input device to which this sampler channel - * is currently connected to. + * Returns the MIDI input channel to which this sampler + * channel is currently connected to. * - * @returns pointer to MIDI input device or NULL if not - * connected + * @returns The MIDI input channel on which the sampler + * channel is listening to. */ - MidiInputDevice* GetMidiInputDevice(); + midi_chan_t GetMidiInputChannel(); + + /** + * Returns the MIDI input port number to which this sampler + * channel is currently connected to. + * + * @returns MIDI input port number or -1 if not connected + */ + int GetMidiInputPort(); /** * Returns the audio output device to which this sampler channel @@ -133,25 +154,76 @@ AudioOutputDevice* GetAudioOutputDevice(); /** + * Returns the MIDI input device to which this sampler channel + * is currently connected to. + * + * @returns pointer to MIDI input device or NULL if not + * connected + */ + MidiInputDevice* GetMidiInputDevice(); + + /** * Returns the index number of this sampler channel within the * Sampler instance. */ uint Index(); + /** Returns the sampler to which this channel belongs */ + Sampler* GetSampler(); + + /////////////////////////////////////////////////////////////// + // Event Listener methods + + /** + * Registers the specified listener to be notified + * when the engine type of this sampler channel is changed. + */ + void AddEngineChangeListener(EngineChangeListener* l); + + /** + * Removes the specified listener. + */ + void RemoveEngineChangeListener(EngineChangeListener* l); + + /** + * Removes the specified listener. + */ + void RemoveAllEngineChangeListeners(); + + /** + * Notifies listeners that the engine type of this sampler + * channel is going to be changed soon. + */ + void fireEngineToBeChanged(); + + /** + * Notifies listeners that the engine + * type of this sampler channel is changed. + */ + void fireEngineChanged(); + + protected: SamplerChannel(Sampler* pS); - ~SamplerChannel(); + virtual ~SamplerChannel(); + + /** Getting MIDI input device port given its index number. */ + MidiInputPort* __GetMidiInputDevicePort(int iMidiPort); Sampler* pSampler; - Engine* pEngine; - MidiInputDevice* pMidiInputDevice; + EngineChannel* pEngineChannel; AudioOutputDevice* pAudioOutputDevice; + MidiInputDevice* pMidiInputDevice; int iIndex; friend class Sampler; + private: + int iMidiPort; ///< Don't access directly, read GetMidiInputPort() instead ! + midi_chan_t midiChannel; ///< Don't access directly, read GetMidiInputChannel() instead ! + ListenerList llEngineChangeListeners; }; - /** LinuxSampler main class + /** @brief LinuxSampler main class * * This is the toplevel class for a LinuxSampler instance. * @@ -159,45 +231,52 @@ * sampler channel can individually be deployed with it's own sampler * engine, connected to an arbitrary MIDI input device and connected to * an arbitrary audio output device. Here an example setup: + * @code + * S.Channel MIDI in S.Engine Audio out + * ------------------------------------------------------------------- + * 0 Alsa -> gig::Engine -> Jack + * 1 VSTi -> Akai::Engine -> VSTi + * 2 Jack -> DLS::Engine -> Jack + * 3 Jack -> SF::Engine -> Alsa * - * S.Channel. MIDI in S.Engine Audio out - * ------------------------------------------------------------------- - * 0 Alsa -> gig::Engine -> Jack - * 1 VSTi -> Akai::Engine -> VSTi - * 2 Jack -> DLS::Engine -> Jack - * 3 Jack -> SF::Engine -> Alsa - * - * ... (and so on) ... + * ... (and so on) ... + * @endcode * * Note that not all audio and MIDI backends and sampler engines listed - * in the example above are already implemented! + * in the example above might already been implemented! * * As you can see in the example setup, LinuxSampler is capable to use * several, different audio output and MIDI input systems * simultaniously at the same time. Here the example setup shown in the - * ascpect of MIDI input and audio output devices / drivers: - * - * ######################### ######################### - * # AudioOutputDeviceJack # # AudioOutputDeviceVSTi # - * ######################### ######################### - * ^ ^ ^ - * /------------>|Sampler Channel 0|-----/ | | - * | /--------->|Sampler Channel 1|---------------------/ - * | | /---->|Sampler Channel 2|---------/ - * | | | /->|Sampler Channel 3|------------>######################### - * | | | | ... (and so on) ... # AudioOutputDeviceAlsa # - * | | | | ######################### - * | | | \----------------------------------------------------\ - * | | \-------------------------------------------\ | - * | \--------------------\ | | - * | | | | - * ####################### ####################### ####################### - * # MidiInputDeviceAlsa # # MidiInputDeviceVSTi # # MidiInputDeviceJack # - * ####################### ####################### ####################### + * aspect of MIDI input and audio output devices / drivers: + * @code + * ######################### ######################### + * # AudioOutputDeviceJack # # AudioOutputDeviceVSTi # + * ######################### ######################### + * ^ ^ ^ + * /------------>|Sampler Channel 0|-----/ | | + * | /--------->|Sampler Channel 1|---------------------/ + * | | /------>|Sampler Channel 2|---------/ + * | | | /--->|Sampler Channel 3|------------>######################### + * | | | | ... (and so on) ... # AudioOutputDeviceAlsa # + * | | | | ######################### + * | | | \-----------------------------------------------------\ + * | | \--------------------------------------------\ | + * | \--------------------\ | | + * | | | | + * ####################### ####################### ####################### + * # MidiInputDeviceAlsa # # MidiInputDeviceVSTi # # MidiInputDeviceJack # + * ####################### ####################### ####################### + * @endcode * * As you can see in this example setup, one device (that is midi input * driver / audio output driver) can be connected multiple times to * different sampler channels. + * + * It's even possible to create multiple instances of the same driver, for + * example multiple instances of the Alsa output driver to use multiple + * sound cards at the same time, or multiple instances of the JACK audio + * output driver to leverage SMP systems or boxes with several hard discs. */ class Sampler { public: @@ -209,7 +288,7 @@ /** * Destructor. */ - ~Sampler(); + virtual ~Sampler(); /** * Returns the number of sampler channels currently allocated. @@ -217,7 +296,11 @@ uint SamplerChannels(); /** - * Create and add a new sampler channel to this Sampler instance. + * Create and add a new sampler channel to this Sampler + * instance. For race condition reasons the new channel will use + * an index past the last already existing sampler channel + * index (in case the index limit was not reached yet, otherwise + * a free index starting from 0 is searched). * * @returns pointer to new sampler channel */ @@ -232,6 +315,11 @@ SamplerChannel* GetSamplerChannel(uint uiSamplerChannel); /** + * Returns all created sampler channels. + */ + std::map GetSamplerChannels(); + + /** * Destroy and remove the given sampler channel from this * Sampler instance. * @@ -249,48 +337,405 @@ void RemoveSamplerChannel(uint uiSamplerChannel); /** - * Create an audio output device of the given type. + * Destroy and remove all sampler channels from this + * Sampler instance. + */ + void RemoveAllSamplerChannels(); + + /** + * Returns the names of all available audio output drivers. + */ + std::vector AvailableAudioOutputDrivers(); + + /** + * Returns the names of all available MIDI input drivers. + */ + std::vector AvailableMidiInputDrivers(); + + /** + * Returns the names of all available sampler engine types. + * @see SamplerChannel::SetEngineType() + */ + std::vector AvailableEngineTypes(); + + /** + * Create an audio output device. * - * @param AudioType - desired audio output system to use + * @param AudioDriver - name of the audio driver + * @param Parameters - eventually needed driver parameters to + * create the device * @returns pointer to created audio output device + * @throws Exception if device could not be created + */ + AudioOutputDevice* CreateAudioOutputDevice(String AudioDriver, std::map Parameters) throw (Exception); + + /** + * Create a midi input device. + * + * @param MidiDriver - name of the midi driver + * @param Parameters - eventually needed driver parameters to + * create the device + * @returns pointer to created midi input device + * @throws Exception if device could not be created + */ + MidiInputDevice* CreateMidiInputDevice(String MidiDriver, std::map Parameters) throw (Exception); + + /** + * Returns the number of all created audio output devices. + */ + uint AudioOutputDevices(); + + /** + * Returns the number of all created MIDI input devices. + */ + uint MidiInputDevices(); + + /** + * Returns all created audio output devices. + */ + std::map GetAudioOutputDevices(); + + /** + * Returns all created MIDI input devices. */ - AudioOutputDevice* CreateAudioOutputDevice(audio_output_type_t AudioType); + std::map GetMidiInputDevices(); /** - * Returns the audio output device of the given type. + * Destroy the given audio output device and takes care if there + * are still sampler engines connected to this device, etc. * - * @param AudioType - desired audio output system to use - * @returns pointer to audio output device or NULL if device of - * desired type is not yet created + * @throws Exception if sampler channels are still + * connected to the device */ - AudioOutputDevice* GetAudioOutputDevice(audio_output_type_t AudioType); + void DestroyAudioOutputDevice(AudioOutputDevice* pDevice) throw (Exception); /** - * Create a MIDI input device of the given type. + * Destroy all audio output devices and takes care if there + * are still sampler engines connected to devices, etc. * - * @param MidiType - desired MIDI input system to use - * @returns pointer to created MIDI input device + * Note: non-autonomous devices, that is devices associated with + * host plugin instances like VST, AU, DSSI, LV2 are not + * destroyed by this method. + * + * @throws Exception if sampler channels are still + * connected to device */ - MidiInputDevice* CreateMidiInputDevice(midi_input_type_t MidiType); + void DestroyAllAudioOutputDevices() throw (Exception); /** - * Returns the MIDI input device of the given type. + * Destroy the given MIDI input device and takes care if there + * are still sampler engines connected to this device, etc. * - * @param MidiType - desired MIDI input system to use - * @returns pointer to MIDI input device or NULL if device of - * desired type is not yet created + * @throws Exception if sampler channels are still + * connected to the device */ - MidiInputDevice* GetMidiInputDevice(midi_input_type_t MidiType); + void DestroyMidiInputDevice(MidiInputDevice* pDevice) throw (Exception); + /** + * Destroy all MIDI input devices and take care if there + * are still sampler engines connected to device, etc. + * + * Note: non-autonomous devices, that is devices associated with + * host plugin instances like VST, AU, DSSI, LV2 are not + * destroyed by this method. + * + * @throws Exception if sampler channels are still + * connected to device + */ + void DestroyAllMidiInputDevices() throw (Exception); + + /** + * Gets the current number of all active streams. + * @returns The current number of all active streams. + */ + int GetDiskStreamCount(); + + /** + * Gets the current number of all active voices. + * @returns The current number of all active voices. + */ + int GetVoiceCount(); + + /** + * Reset the whole sampler. Destroy all engines, sampler + * channels, MIDI input devices and audio output devices. + */ + void Reset(); + + /////////////////////////////////////////////////////////////// + // Event Listener methods + + /** + * Registers the specified listener to be notified + * when the number of sampler chanels is changed. + */ + void AddChannelCountListener(ChannelCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveChannelCountListener(ChannelCountListener* l); + + /** + * Registers the specified listener to be notified + * when the number of audio output devices is changed. + */ + void AddAudioDeviceCountListener(AudioDeviceCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveAudioDeviceCountListener(AudioDeviceCountListener* l); + + /** + * Registers the specified listener to be notified + * when the number of MIDI input devices is changed. + */ + void AddMidiDeviceCountListener(MidiDeviceCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveMidiDeviceCountListener(MidiDeviceCountListener* l); + + /** + * Registers the specified listener to be notified when the number + * of active voices in a particular sampler channel is changed. + */ + void AddVoiceCountListener(VoiceCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveVoiceCountListener(VoiceCountListener* l); + + /** + * Notifies listeners that the number of active voices + * on the specified sampler channel is changed. + * @param ChannelId The numerical ID of the sampler channel. + * @param NewCount The new number of active voices. + */ + void fireVoiceCountChanged(int ChannelId, int NewCount); + + /** + * Registers the specified listener to be notified when the number + * of active disk streams in a particular sampler channel is changed. + */ + void AddStreamCountListener(StreamCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveStreamCountListener(StreamCountListener* l); + + /** + * Notifies listeners that the number of active disk streams + * on the specified sampler channel is changed. + * @param ChannelId The numerical ID of the sampler channel. + * @param NewCount The new number of active disk streams. + */ + void fireStreamCountChanged(int ChannelId, int NewCount); + + /** + * Registers the specified listener to be + * notified when the fill state of the disk stream + * buffers on a specific sampler channel is changed. + */ + void AddBufferFillListener(BufferFillListener* l); + + /** + * Removes the specified listener. + */ + void RemoveBufferFillListener(BufferFillListener* l); + + /** + * Notifies listeners that the fill state of the disk stream + * buffers on the specified sampler channel is changed. + * @param ChannelId The numerical ID of the sampler channel. + * @param FillData The buffer fill data for the specified sampler channel. + */ + void fireBufferFillChanged(int ChannelId, String FillData); + + /** + * Registers the specified listener to be notified + * when total number of active voices is changed. + */ + void AddTotalVoiceCountListener(TotalVoiceCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveTotalVoiceCountListener(TotalVoiceCountListener* l); + + /** + * Notifies listeners that the total number of active voices is changed. + * @param NewCount The new number of active voices. + */ + void fireTotalVoiceCountChanged(int NewCount); + + /** + * Registers the specified listener to be notified when the number + * of total streams is changed. + */ + void AddTotalStreamCountListener(TotalStreamCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveTotalStreamCountListener(TotalStreamCountListener* l); + + /** + * Notifies listeners that the total number of total streams changed. + * @param NewCount The new number of total streams. + */ + void fireTotalStreamCountChanged(int NewCount); + + /** + * Registers the specified listener to be notified when the number + * of effect sends on a particular sampler channel is changed. + */ + void AddFxSendCountListener(FxSendCountListener* l); + + /** + * Removes the specified listener. + */ + void RemoveFxSendCountListener(FxSendCountListener* l); + + /** + * Notifies listeners about the current number of voices, + * streams and total voices, and the current fill state of + * the disk stream buffers. + */ + void fireStatistics(); + + /////////////////////////////////////////////////////////////// + // system specific methods + + /** + * Advise the FPU to treat denormal floating point numbers as + * zero, to avoid severe performance penalty when dealing with + * such extreme floating point values. + * + * @returns @c true if FPU supports it, @c false otherwise + */ + static bool EnableDenormalsAreZeroMode(); + +#if defined(WIN32) + /** + * Gets the directory where the liblinuxsampler dll is located. + * Note: this method is currently only available for Windows. + * @returns installation directory + */ + static String GetInstallDir(); +#endif protected: - typedef std::map AudioOutputDeviceMap; - typedef std::map MidiInputDeviceMap; + /** + * Notifies listeners that the number of sampler channels has been changed. + * @param NewCount The new number of sampler channels. + */ + void fireChannelCountChanged(int NewCount); + + /** + * Notifies listeners that the specified sampler channel has just + * been added. + * @param pChannel The new sampler channel. + */ + void fireChannelAdded(SamplerChannel* pChannel); + + /** + * Notifies listeners that the specified sampler channel is + * going to be removed soon. + * @param pChannel sampler channel to be removed. + */ + void fireChannelToBeRemoved(SamplerChannel* pChannel); + + /** + * Notifies listeners that the number of audio output devices has been changed. + * @param NewCount The new number of audio output devices. + */ + void fireAudioDeviceCountChanged(int NewCount); + + /** + * Notifies listeners that the number of MIDI input devices has been changed. + * @param NewCount The new number of MIDI input devices. + */ + void fireMidiDeviceCountChanged(int NewCount); - std::vector vSamplerChannels; ///< contains all created sampler channels - AudioOutputDeviceMap AudioOutputDevices; ///< contains all created audio output devices - MidiInputDeviceMap MidiInputDevices; + /** + * Notifies listeners that the supplied MIDI input device is + * going to be destroyed soon. + * @param pDevice MIDI input device to be destroyed + */ + void fireMidiDeviceToBeDestroyed(MidiInputDevice* pDevice); + + /** + * Notifies listeners that the supplied MIDI input device was + * just created. + * @param pDevice new MIDI input device + */ + void fireMidiDeviceCreated(MidiInputDevice* pDevice); + + /** + * Notifies listeners that the number of effect sends + * on a particular sampler channel is changed. + * @param ChannelId The numerical ID of the sampler channel. + * @param NewCount The new number of sampler channels. + */ + void fireFxSendCountChanged(int ChannelId, int NewCount); + + typedef std::map SamplerChannelMap; + + SamplerChannelMap mSamplerChannels; ///< contains all created sampler channels + + // statistics cache + uint uiOldTotalVoiceCount; + uint uiOldTotalStreamCount; + std::map mOldVoiceCounts; + std::map mOldStreamCounts; friend class SamplerChannel; + + private: + ListenerList llChannelCountListeners; + ListenerList llAudioDeviceCountListeners; + ListenerList llMidiDeviceCountListeners; + ListenerList llVoiceCountListeners; + ListenerList llStreamCountListeners; + ListenerList llBufferFillListeners; + ListenerList llTotalStreamCountListeners; + ListenerList llTotalVoiceCountListeners; + ListenerList llFxSendCountListeners; + + class EventHandler : public EngineChangeListener, public FxSendCountListener { + public: + void SetSampler(Sampler* pSampler) { this->pSampler = pSampler; } + + /** + * Invoked when the engine type of the specified sampler + * channel is going to be changed soon. + * @param ChannelId The numerical ID of the sampler channel + */ + virtual void EngineToBeChanged(int ChannelId); + + /** + * Invoked when the engine type of the + * specified sampler channel is changed. + * @param ChannelId The numerical ID of the sampler + * channel, which engine type has been changed. + */ + virtual void EngineChanged(int ChannelId); + + /** + * Invoked when the number of effect sends + * on the specified sampler channel has changed. + * @param ChannelId The numerical ID of the sampler channel. + * @param NewCount The new number of effect sends. + */ + virtual void FxSendCountChanged(int ChannelId, int NewCount); + + private: + Sampler* pSampler; + } eventHandler; }; }