--- linuxsampler/trunk/src/drivers/audio/AudioOutputDevice.cpp 2005/05/19 19:25:14 554 +++ linuxsampler/trunk/src/drivers/audio/AudioOutputDevice.cpp 2013/02/02 18:52:15 2410 @@ -3,7 +3,7 @@ * LinuxSampler - modular, streaming capable sampler * * * * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * - * Copyright (C) 2005 Christian Schoenebeck * + * Copyright (C) 2005 - 2010 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 * @@ -23,6 +23,8 @@ #include "AudioOutputDeviceFactory.h" #include "AudioOutputDevice.h" +#include "../../common/global_private.h" +#include "../../common/IDGenerator.h" namespace LinuxSampler { @@ -56,7 +58,7 @@ return true; } - void AudioOutputDevice::ParameterActive::OnSetValue(bool b) throw (LinuxSamplerException) { + void AudioOutputDevice::ParameterActive::OnSetValue(bool b) throw (Exception) { if (b) ((AudioOutputDevice*)pDevice)->Play(); else ((AudioOutputDevice*)pDevice)->Stop(); } @@ -109,7 +111,12 @@ return std::vector(); } - void AudioOutputDevice::ParameterSampleRate::OnSetValue(int i) throw (LinuxSamplerException) { + int AudioOutputDevice::ParameterSampleRate::ValueAsInt() { + return (pDevice) ? (int) ((AudioOutputDevice*)pDevice)->SampleRate() + : DeviceCreationParameterInt::ValueAsInt(); + } + + void AudioOutputDevice::ParameterSampleRate::OnSetValue(int i) throw (Exception) { /* cannot happen, as parameter is fix */ } @@ -150,7 +157,7 @@ } optional AudioOutputDevice::ParameterChannels::RangeMinAsInt(std::map Parameters) { - return optional::nothing; + return 1; } optional AudioOutputDevice::ParameterChannels::RangeMaxAsInt(std::map Parameters) { @@ -161,7 +168,7 @@ return std::vector(); } - void AudioOutputDevice::ParameterChannels::OnSetValue(int i) throw (LinuxSamplerException) { + void AudioOutputDevice::ParameterChannels::OnSetValue(int i) throw (Exception) { ((AudioOutputDevice*)pDevice)->AcquireChannels(i); } @@ -174,8 +181,10 @@ // *************** AudioOutputDevice *************** // * - AudioOutputDevice::AudioOutputDevice(std::map DriverParameters) { + AudioOutputDevice::AudioOutputDevice(std::map DriverParameters) + : EnginesReader(Engines) { this->Parameters = DriverParameters; + EffectChainIDs = new IDGenerator(); } AudioOutputDevice::~AudioOutputDevice() { @@ -183,39 +192,66 @@ { std::vector::iterator iter = Channels.begin(); while (iter != Channels.end()) { - Channels.erase(iter); delete *iter; iter++; } - + Channels.clear(); } // delete all device parameters { std::map::iterator iter = Parameters.begin(); while (iter != Parameters.end()) { - Parameters.erase(iter); delete iter->second; iter++; } + Parameters.clear(); + } + + // delete all master effect chains + { + std::vector::iterator iter = vEffectChains.begin(); + while (iter != vEffectChains.end()) { + delete *iter; + iter++; + } + vEffectChains.clear(); } + + delete EffectChainIDs; } void AudioOutputDevice::Connect(Engine* pEngine) { - if (Engines.find(pEngine) == Engines.end()) { - Engines.insert(pEngine); + std::set& engines = Engines.GetConfigForUpdate(); + if (engines.find(pEngine) == engines.end()) { + engines.insert(pEngine); + Engines.SwitchConfig().insert(pEngine); // make sure the engine knows about the connection //pEngine->Connect(this); } } void AudioOutputDevice::Disconnect(Engine* pEngine) { - if (Engines.find(pEngine) != Engines.end()) { // if clause to prevent disconnect loop - Engines.erase(pEngine); + std::set& engines = Engines.GetConfigForUpdate(); + if (engines.find(pEngine) != engines.end()) { // if clause to prevent disconnect loop + engines.erase(pEngine); + Engines.SwitchConfig().erase(pEngine); // make sure the engine knows about the disconnection //pEngine->DisconnectAudioOutputDevice(); } } + + void AudioOutputDevice::ReconnectAll() { + // copy by value, not by reference here ! + std::set engines = Engines.GetConfigForUpdate(); + { + std::set::iterator iterEngine = engines.begin(); + std::set::iterator end = engines.end(); + for (; iterEngine != end; iterEngine++) { + (*iterEngine)->ReconnectAudioOutputDevice(); + } + } + } AudioChannel* AudioOutputDevice::Channel(uint ChannelIndex) { return (ChannelIndex < Channels.size()) ? Channels[ChannelIndex] : NULL; @@ -229,10 +265,73 @@ } } + uint AudioOutputDevice::ChannelCount() { + return Channels.size(); + } + std::map AudioOutputDevice::DeviceParameters() { return Parameters; } + EffectChain* AudioOutputDevice::AddSendEffectChain() { + EffectChain* pChain = new EffectChain(this, EffectChainIDs->create()); + vEffectChains.push_back(pChain); + return pChain; + } + + void AudioOutputDevice::RemoveSendEffectChain(uint iChain) throw (Exception) { + if (iChain >= vEffectChains.size()) + throw Exception( + "Could not remove send effect chain " + ToString(iChain) + + ", index out of bounds" + ); + std::vector::iterator iter = vEffectChains.begin(); + for (int i = 0; i < iChain; ++i) ++iter; + EffectChainIDs->destroy((*iter)->ID()); + vEffectChains.erase(iter); + } + + EffectChain* AudioOutputDevice::SendEffectChain(uint iChain) const { + if (iChain >= vEffectChains.size()) return NULL; + return vEffectChains[iChain]; + } + + EffectChain* AudioOutputDevice::SendEffectChainByID(uint iChainID) const { + for (int i = 0; i < SendEffectChainCount(); i++) { + if (SendEffectChain(i)->ID() == iChainID) return SendEffectChain(i); + } + + return NULL; + } + + uint AudioOutputDevice::SendEffectChainCount() const { + return vEffectChains.size(); + } + + // TODO: to be removed + EffectChain* AudioOutputDevice::AddMasterEffectChain() { + return AddSendEffectChain(); + } + + // TODO: to be removed + void AudioOutputDevice::RemoveMasterEffectChain(uint iChain) throw (Exception) { + RemoveSendEffectChain(iChain); + } + + // TODO: to be removed + EffectChain* AudioOutputDevice::MasterEffectChain(uint iChain) const { + return SendEffectChain(iChain); + } + + // TODO: to be removed + uint AudioOutputDevice::MasterEffectChainCount() const { + return SendEffectChainCount(); + } + + float AudioOutputDevice::latency() { + return float(MaxSamplesPerCycle()) / float(SampleRate()); + } + int AudioOutputDevice::RenderAudio(uint Samples) { if (Channels.empty()) return 0; @@ -241,18 +340,26 @@ std::vector::iterator iterChannels = Channels.begin(); std::vector::iterator end = Channels.end(); for (; iterChannels != end; iterChannels++) - (*iterChannels)->Clear(); // zero out audio buffer + (*iterChannels)->Clear(Samples); // zero out audio buffer + } + // do the same for master effects + { + std::vector::iterator iterChains = vEffectChains.begin(); + std::vector::iterator end = vEffectChains.end(); + for (; iterChains != end; ++iterChains) + (*iterChains)->ClearAllChannels(); // zero out audio buffers } int result = 0; // let all connected engines render audio for the current audio fragment cycle + const std::set& engines = EnginesReader.Lock(); #if CONFIG_RT_EXCEPTIONS try #endif // CONFIG_RT_EXCEPTIONS { - std::set::iterator iterEngine = Engines.begin(); - std::set::iterator end = Engines.end(); + std::set::iterator iterEngine = engines.begin(); + std::set::iterator end = engines.end(); for (; iterEngine != end; iterEngine++) { int res = (*iterEngine)->RenderAudio(Samples); if (res != 0) result = res; @@ -264,6 +371,24 @@ exit(EXIT_FAILURE); } #endif // CONFIG_RT_EXCEPTIONS + EnginesReader.Unlock(); + + // now that the engines (might) have left fx send signals for master + // effects, render all master effects + { + std::vector::iterator iterChains = vEffectChains.begin(); + std::vector::iterator end = vEffectChains.end(); + for (; iterChains != end; ++iterChains) { + if (!(*iterChains)->EffectCount()) continue; + (*iterChains)->RenderAudio(Samples); + // mix the result of the last effect in the chain to the audio + // output device channel(s) + Effect* pLastEffect = + (*iterChains)->GetEffect((*iterChains)->EffectCount() - 1); + for (int iChan = 0; iChan < pLastEffect->OutputChannelCount() && iChan < ChannelCount(); ++iChan) + pLastEffect->OutputChannel(iChan)->MixTo(Channel(iChan), Samples); + } + } return result; } @@ -276,7 +401,7 @@ std::vector::iterator iterChannels = Channels.begin(); std::vector::iterator end = Channels.end(); for (; iterChannels != end; iterChannels++) - (*iterChannels)->Clear(); // zero out audio buffer + (*iterChannels)->Clear(Samples); // zero out audio buffer } return 0;