as a result SSM will now always try and follow Jack settings while attached.master
| @@ -103,6 +103,8 @@ JackClient::JackClient() | |||
| m_JackInputCount = 4; | |||
| m_JackOutputCount = 4; | |||
| m_Client=NULL; | |||
| m_JackSampleRate = -1; | |||
| m_JackBufferSize = -1; | |||
| } | |||
| ///////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -191,6 +193,9 @@ bool JackClient::Attach() | |||
| return false; | |||
| } | |||
| m_JackSampleRate = jack_get_sample_rate(m_Client); | |||
| m_JackBufferSize = jack_get_buffer_size(m_Client); | |||
| jack_set_process_callback(m_Client, JackProcess, this); | |||
| jack_set_sample_rate_callback (m_Client, SampleRateChange, this); | |||
| jack_on_shutdown (m_Client, JackShutdown, this); | |||
| @@ -211,6 +216,9 @@ bool JackClient::Attach() | |||
| return false; | |||
| } | |||
| // tells ssm to go back to callback mode | |||
| RunCallback(RunContext, true); | |||
| m_Attached=true; | |||
| cerr<<"connected to jack..."<<endl; | |||
| @@ -228,13 +236,13 @@ void JackClient::Detach() | |||
| jack_client_close(m_Client); | |||
| m_Client=NULL; | |||
| m_Attached=false; | |||
| } | |||
| if (JackProcessInstanceID==m_JackInstanceID) | |||
| JackProcessInstanceID = -1; | |||
| // tells ssm to go back to non callback mode | |||
| RunCallback(RunContext, false); | |||
| if (JackProcessInstanceID==m_JackInstanceID) | |||
| JackProcessInstanceID = -1; | |||
| // tells ssm to go back to non callback mode | |||
| RunCallback(RunContext, false); | |||
| } | |||
| } | |||
| ///////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -458,28 +466,12 @@ JackPlugin::~JackPlugin() | |||
| } | |||
| } | |||
| bool JackPlugin::Kill() | |||
| { | |||
| m_IsDead=true; | |||
| UpdatePluginInfoWithHost(); | |||
| RemoveAllInputs (); | |||
| RemoveAllOutputs (); | |||
| UpdatePluginInfoWithHost(); | |||
| m_JackClient->Detach(); | |||
| delete m_JackClient; | |||
| m_JackClient=NULL; | |||
| return true; | |||
| } | |||
| PluginInfo &JackPlugin::Initialise(const HostInfo *Host) | |||
| { | |||
| PluginInfo& Info= SpiralPlugin::Initialise(Host); | |||
| host=Host; | |||
| m_JackClient->SetCallback(cb_Update,m_Parent); | |||
| return Info; | |||
| } | |||
| @@ -490,47 +482,6 @@ SpiralGUIType *JackPlugin::CreateGUI() | |||
| this,m_AudioCH,m_HostInfo); | |||
| } | |||
| void JackPlugin::SetNumberPorts (int nInputs, int nOutputs) { | |||
| UpdatePluginInfoWithHost(); | |||
| RemoveAllInputs (); | |||
| RemoveAllOutputs (); | |||
| m_PluginInfo.NumInputs = 0; | |||
| m_PluginInfo.NumOutputs = 0; | |||
| m_PluginInfo.PortTips.clear (); | |||
| CreatePorts (nInputs, nOutputs, true); | |||
| UpdatePluginInfoWithHost (); | |||
| } | |||
| void JackPlugin::CreatePorts (int nInputs, int nOutputs, bool AddPorts) { | |||
| m_PluginInfo.PortTips.clear(); | |||
| m_PluginInfo.NumInputs = nInputs; | |||
| m_JackClient->SetJackInputCount(nInputs); | |||
| for (int n=0; n<nInputs; n++) | |||
| { | |||
| char Temp[256]; | |||
| sprintf(Temp,"SSM Input %d",n); | |||
| m_PluginInfo.PortTips.push_back(Temp); | |||
| } | |||
| m_PluginInfo.NumOutputs = nOutputs; | |||
| m_JackClient->SetJackOutputCount(nOutputs); | |||
| for (int n=0; n<nOutputs; n++) | |||
| { | |||
| char Temp[256]; | |||
| sprintf(Temp,"SSM Output %d",n); | |||
| m_PluginInfo.PortTips.push_back(Temp); | |||
| } | |||
| if (AddPorts) { | |||
| for (int n=0; n<nInputs; n++) AddInput(); | |||
| for (int n=0; n<nOutputs; n++) AddOutput(); | |||
| } | |||
| } | |||
| void JackPlugin::Execute() | |||
| { | |||
| } | |||
| @@ -539,50 +490,13 @@ void JackPlugin::ExecuteCommands() | |||
| { | |||
| if (m_IsDead) return; | |||
| bool commandwaiting = m_AudioCH->IsCommandWaiting(); | |||
| int command = (commandwaiting)?(int)m_AudioCH->GetCommand():0; | |||
| if (commandwaiting) | |||
| if (m_AudioCH->IsCommandWaiting()) | |||
| { | |||
| switch (command) { | |||
| switch (m_AudioCH->GetCommand()) { | |||
| case SET_PORT_COUNT : | |||
| SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs); | |||
| } | |||
| } | |||
| break; | |||
| // we want to process this whether we are connected to stuff or not | |||
| JackClient* pJack=m_JackClient; | |||
| // connect the buffers up if we are plugged into something | |||
| for (int n=0; n<pJack->GetJackOutputCount(); n++) | |||
| { | |||
| if (InputExists(n)) | |||
| { | |||
| pJack->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer()); | |||
| } | |||
| else | |||
| { | |||
| pJack->SetOutputBuf(n,NULL); | |||
| } | |||
| } | |||
| for (int n=0; n<pJack->GetJackInputCount(); n++) | |||
| { | |||
| if (OutputExists(n)) | |||
| { | |||
| pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); | |||
| } | |||
| else | |||
| { | |||
| pJack->SetInputBuf(n,NULL); | |||
| } | |||
| } | |||
| if (commandwaiting) | |||
| { | |||
| switch (command) | |||
| { | |||
| case UPDATE_NAMES : | |||
| { | |||
| int c=0; | |||
| @@ -626,12 +540,128 @@ void JackPlugin::ExecuteCommands() | |||
| } | |||
| break; | |||
| default : break; | |||
| } | |||
| } | |||
| m_Connected=m_JackClient->IsAttached(); | |||
| } | |||
| bool JackPlugin::Kill() | |||
| { | |||
| m_IsDead=true; | |||
| UpdatePluginInfoWithHost(); | |||
| RemoveAllInputs (); | |||
| RemoveAllOutputs (); | |||
| UpdatePluginInfoWithHost(); | |||
| if (m_JackClient) | |||
| { | |||
| m_JackClient->Detach(); | |||
| delete m_JackClient; | |||
| m_JackClient=NULL; | |||
| } | |||
| return true; | |||
| } | |||
| void JackPlugin::Reset() | |||
| { | |||
| // we want to process this whether we are connected to stuff or not | |||
| JackClient* pJack=m_JackClient; | |||
| // connect the buffers up if we are plugged into something | |||
| for (int n=0; n<pJack->GetJackOutputCount(); n++) | |||
| { | |||
| pJack->SetOutputBuf(n,NULL); | |||
| } | |||
| for (int n=0; n<pJack->GetJackInputCount(); n++) | |||
| { | |||
| pJack->SetInputBuf(n,NULL); | |||
| } | |||
| ResetPorts(); | |||
| } | |||
| void JackPlugin::ProcessAudio() | |||
| { | |||
| if (m_IsDead) return; | |||
| // Make sure all plugins match Jack's SampleRate and Buffersize | |||
| if ((m_JackClient->JackSampleRate() != -1) && (m_JackClient->JackBufferSize() != -1)) | |||
| { | |||
| ChangeBufferAndSampleRate(m_JackClient->JackBufferSize(), m_JackClient->JackSampleRate(), m_Parent); | |||
| } | |||
| // connect the buffers up if we are plugged into something | |||
| for (int n=0; n<m_JackClient->GetJackOutputCount(); n++) | |||
| { | |||
| if (InputExists(n)) | |||
| { | |||
| m_JackClient->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer()); | |||
| } | |||
| else | |||
| { | |||
| m_JackClient->SetOutputBuf(n,NULL); | |||
| } | |||
| } | |||
| for (int n=0; n<m_JackClient->GetJackInputCount(); n++) | |||
| { | |||
| if (OutputExists(n)) | |||
| { | |||
| m_JackClient->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); | |||
| } | |||
| else | |||
| { | |||
| m_JackClient->SetInputBuf(n,NULL); | |||
| } | |||
| } | |||
| } | |||
| void JackPlugin::SetNumberPorts (int nInputs, int nOutputs) { | |||
| UpdatePluginInfoWithHost(); | |||
| RemoveAllInputs (); | |||
| RemoveAllOutputs (); | |||
| m_PluginInfo.NumInputs = 0; | |||
| m_PluginInfo.NumOutputs = 0; | |||
| m_PluginInfo.PortTips.clear (); | |||
| CreatePorts (nInputs, nOutputs, true); | |||
| UpdatePluginInfoWithHost (); | |||
| } | |||
| void JackPlugin::CreatePorts (int nInputs, int nOutputs, bool AddPorts) { | |||
| m_PluginInfo.PortTips.clear(); | |||
| m_PluginInfo.NumInputs = nInputs; | |||
| m_JackClient->SetJackInputCount(nInputs); | |||
| for (int n=0; n<nInputs; n++) | |||
| { | |||
| char Temp[256]; | |||
| sprintf(Temp,"SSM Input %d",n); | |||
| m_PluginInfo.PortTips.push_back(Temp); | |||
| } | |||
| m_PluginInfo.NumOutputs = nOutputs; | |||
| m_JackClient->SetJackOutputCount(nOutputs); | |||
| for (int n=0; n<nOutputs; n++) | |||
| { | |||
| char Temp[256]; | |||
| sprintf(Temp,"SSM Output %d",n); | |||
| m_PluginInfo.PortTips.push_back(Temp); | |||
| } | |||
| if (AddPorts) { | |||
| for (int n=0; n<nInputs; n++) AddInput(); | |||
| for (int n=0; n<nOutputs; n++) AddOutput(); | |||
| } | |||
| } | |||
| void JackPlugin::StreamOut (ostream &s) | |||
| { | |||
| s << m_Version << " " << m_GUIArgs.NumInputs << " " << m_GUIArgs.NumOutputs << " "; | |||
| @@ -66,6 +66,8 @@ public: | |||
| void SetJackInputCount(int JackInputCount) { m_JackInputCount=JackInputCount; } | |||
| int GetJackOutputCount() { return m_JackOutputCount; } | |||
| void SetJackOutputCount(int JackOutputCount) { m_JackOutputCount=JackOutputCount; } | |||
| long int JackSampleRate() { return m_JackSampleRate; } | |||
| long int JackBufferSize() { return m_JackBufferSize; } | |||
| class JackPort | |||
| { | |||
| @@ -107,6 +109,9 @@ private: | |||
| int m_JackOutputCount; | |||
| int m_JackInstanceID; | |||
| long int m_JackSampleRate; | |||
| long int m_JackBufferSize; | |||
| static int JackProcessInstanceID; | |||
| void(*RunCallback)(void*, bool m); | |||
| @@ -115,7 +120,7 @@ private: | |||
| /////////////////////////////////////////////////// | |||
| class JackPlugin : public SpiralPlugin | |||
| class JackPlugin : public AudioDriver | |||
| { | |||
| public: | |||
| JackPlugin(); | |||
| @@ -124,16 +129,21 @@ public: | |||
| virtual PluginInfo& Initialise(const HostInfo *Host); | |||
| virtual SpiralGUIType* CreateGUI(); | |||
| virtual void Execute(); | |||
| virtual void ExecuteCommands(); | |||
| /* General Plugin Function */ | |||
| virtual void Execute(); | |||
| virtual void ExecuteCommands(); | |||
| virtual bool Kill(); | |||
| virtual void StreamOut(std::ostream &s); | |||
| virtual void StreamIn(std::istream &s); | |||
| virtual bool Kill(); | |||
| virtual void Reset(); | |||
| /* Audio Driver Specific Functions */ | |||
| virtual bool IsAudioDriver() { return true; } | |||
| virtual AudioProcessType ProcessType() { return AudioDriver::ALWAYS; } | |||
| virtual void ProcessAudio(); | |||
| /* Jack Plugin Specific Functions */ | |||
| JackClient *GetJackClient() { return m_JackClient; } | |||
| void SetNumberPorts (int nInputs, int nOutputs); | |||
| enum GUICommands{NONE,UPDATE_NAMES,SET_PORT_COUNT,CHECK_PORT_CHANGES}; | |||
| @@ -145,10 +155,12 @@ public: | |||
| }; | |||
| void Attach() { m_JackClient->Attach(); } | |||
| void Detach() { m_JackClient->Detach(); } | |||
| private: | |||
| const HostInfo* host; | |||
| void Detach() { m_JackClient->Detach(); } | |||
| /* Jack Plugin Streaming - soon to be obsolete and for backward compatibility only*/ | |||
| virtual void StreamOut(std::ostream &s); | |||
| virtual void StreamIn(std::istream &s); | |||
| private: | |||
| GUIArgs m_GUIArgs; | |||
| int m_Version; | |||
| @@ -169,7 +181,7 @@ private: | |||
| bool m_Connected; | |||
| JackClient *m_JackClient; | |||
| int m_JackInstanceID; | |||
| //clunky work-around for unique ID | |||
| static int JackInstanceCount; | |||
| }; | |||
| @@ -53,7 +53,7 @@ static const int IN_SHLEN = 2; | |||
| static const int OUT_MAIN = 0; | |||
| static const HostInfo* host; | |||
| OSSOutput* OSSOutput::m_Singleton = NULL; | |||
| OSSClient* OSSClient::m_Singleton = NULL; | |||
| int OutputPlugin::m_RefCount=0; | |||
| int OutputPlugin::m_NoExecuted=0; | |||
| OutputPlugin::Mode OutputPlugin::m_Mode=NO_MODE; | |||
| @@ -117,7 +117,7 @@ OutputPlugin::~OutputPlugin() | |||
| if (m_RefCount==0) | |||
| { | |||
| cb_Blocking(m_Parent,false); | |||
| OSSOutput::PackUpAndGoHome(); | |||
| OSSClient::PackUpAndGoHome(); | |||
| m_Mode=NO_MODE; | |||
| } | |||
| } | |||
| @@ -126,7 +126,7 @@ PluginInfo &OutputPlugin::Initialise(const HostInfo *Host) | |||
| { | |||
| PluginInfo& Info= SpiralPlugin::Initialise(Host); | |||
| host=Host; | |||
| OSSOutput::Get()->AllocateBuffer(); | |||
| OSSClient::Get()->AllocateBuffer(); | |||
| return Info; | |||
| } | |||
| @@ -140,7 +140,7 @@ SpiralGUIType *OutputPlugin::CreateGUI() | |||
| bool OutputPlugin::Kill() | |||
| { | |||
| m_IsDead=true; | |||
| OSSOutput::Get()->Kill(); | |||
| OSSClient::Get()->Kill(); | |||
| m_Mode=CLOSED; | |||
| cb_Blocking(m_Parent,false); | |||
| return true; | |||
| @@ -150,23 +150,23 @@ void OutputPlugin::Reset() | |||
| { | |||
| if (m_IsDead) return; | |||
| m_IsDead=true; | |||
| OSSOutput::Get()->Kill(); | |||
| OSSClient::Get()->Kill(); | |||
| cb_Blocking(m_Parent,false); | |||
| ResetPorts(); | |||
| OSSOutput::Get()->AllocateBuffer(); | |||
| OSSClient::Get()->AllocateBuffer(); | |||
| switch (m_Mode) | |||
| { | |||
| case INPUT : | |||
| OSSOutput::Get()->OpenRead(); | |||
| OSSClient::Get()->OpenRead(); | |||
| cb_Blocking(m_Parent,true); | |||
| break; | |||
| case OUTPUT : | |||
| OSSOutput::Get()->OpenWrite(); | |||
| OSSClient::Get()->OpenWrite(); | |||
| cb_Blocking(m_Parent,true); | |||
| break; | |||
| case DUPLEX : | |||
| OSSOutput::Get()->OpenReadWrite(); | |||
| OSSClient::Get()->OpenReadWrite(); | |||
| cb_Blocking(m_Parent,true); | |||
| break; | |||
| @@ -183,7 +183,7 @@ void OutputPlugin::Execute() | |||
| if (m_Mode==NO_MODE && m_RefCount==1) | |||
| { | |||
| if (OSSOutput::Get()->OpenWrite()) | |||
| if (OSSClient::Get()->OpenWrite()) | |||
| { | |||
| cb_Blocking(m_Parent,true); | |||
| m_Mode=OUTPUT; | |||
| @@ -193,11 +193,11 @@ void OutputPlugin::Execute() | |||
| if (m_Mode==OUTPUT || m_Mode==DUPLEX) | |||
| { | |||
| OSSOutput::Get()->SendStereo(GetInput(0),GetInput(1)); | |||
| OSSClient::Get()->SendStereo(GetInput(0),GetInput(1)); | |||
| } | |||
| if (m_Mode==INPUT || m_Mode==DUPLEX) | |||
| OSSOutput::Get()->GetStereo(GetOutputBuf(0),GetOutputBuf(1)); | |||
| OSSClient::Get()->GetStereo(GetOutputBuf(0),GetOutputBuf(1)); | |||
| } | |||
| void OutputPlugin::ExecuteCommands() | |||
| @@ -205,36 +205,26 @@ void OutputPlugin::ExecuteCommands() | |||
| if (m_IsDead) | |||
| return; | |||
| // Only Play() once per set of plugins | |||
| m_NoExecuted--; | |||
| if (m_NoExecuted<=0) | |||
| { | |||
| if (m_Mode==INPUT || m_Mode==DUPLEX) OSSOutput::Get()->Read(); | |||
| if (m_Mode==OUTPUT || m_Mode==DUPLEX) OSSOutput::Get()->Play(); | |||
| m_NoExecuted=m_RefCount; | |||
| } | |||
| if (m_AudioCH->IsCommandWaiting()) | |||
| { | |||
| switch(m_AudioCH->GetCommand()) | |||
| { | |||
| case OPENREAD : | |||
| if (OSSOutput::Get()->OpenRead()) | |||
| if (OSSClient::Get()->OpenRead()) | |||
| { | |||
| m_Mode=INPUT; | |||
| //cb_Blocking(m_Parent,true); | |||
| } | |||
| break; | |||
| case OPENWRITE : | |||
| if (OSSOutput::Get()->OpenWrite()) | |||
| if (OSSClient::Get()->OpenWrite()) | |||
| { | |||
| m_Mode=OUTPUT; | |||
| cb_Blocking(m_Parent,true); | |||
| } | |||
| break; | |||
| case OPENDUPLEX : | |||
| if (OSSOutput::Get()->OpenReadWrite()) | |||
| if (OSSClient::Get()->OpenReadWrite()) | |||
| { | |||
| m_Mode=DUPLEX; | |||
| cb_Blocking(m_Parent,true); | |||
| @@ -243,10 +233,10 @@ void OutputPlugin::ExecuteCommands() | |||
| case CLOSE : | |||
| m_Mode=CLOSED; | |||
| cb_Blocking(m_Parent,false); | |||
| OSSOutput::Get()->Close(); | |||
| OSSClient::Get()->Close(); | |||
| break; | |||
| case SET_VOLUME : | |||
| OSSOutput::Get()->SetVolume(m_Volume); | |||
| OSSClient::Get()->SetVolume(m_Volume); | |||
| break; | |||
| case CLEAR_NOTIFY: | |||
| m_NotifyOpenOut=false; | |||
| @@ -256,10 +246,25 @@ void OutputPlugin::ExecuteCommands() | |||
| } | |||
| } | |||
| void OutputPlugin::ProcessAudio() | |||
| { | |||
| if (m_IsDead) | |||
| return; | |||
| // Only Play() once per set of plugins | |||
| m_NoExecuted--; | |||
| if (m_NoExecuted<=0) | |||
| { | |||
| if (m_Mode==INPUT || m_Mode==DUPLEX) OSSClient::Get()->Read(); | |||
| if (m_Mode==OUTPUT || m_Mode==DUPLEX) OSSClient::Get()->Play(); | |||
| m_NoExecuted=m_RefCount; | |||
| } | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| ////////////////////////////////////////////////////////////////////// | |||
| OSSOutput::OSSOutput() : | |||
| OSSClient::OSSClient() : | |||
| m_Amp(0.5), | |||
| m_Channels(2), | |||
| m_ReadBufferNum(0), | |||
| @@ -276,7 +281,7 @@ m_IsDead(false) | |||
| ////////////////////////////////////////////////////////////////////// | |||
| OSSOutput::~OSSOutput() | |||
| OSSClient::~OSSClient() | |||
| { | |||
| Close(); | |||
| DeallocateBuffer(); | |||
| @@ -284,7 +289,7 @@ OSSOutput::~OSSOutput() | |||
| ////////////////////////////////////////////////////////////////////// | |||
| void OSSOutput::AllocateBuffer() | |||
| void OSSClient::AllocateBuffer() | |||
| { | |||
| if (m_Buffer[0]==NULL) | |||
| { | |||
| @@ -296,11 +301,9 @@ void OSSOutput::AllocateBuffer() | |||
| m_InBuffer[0] = (short*) calloc(m_BufSizeBytes/2,m_BufSizeBytes); | |||
| m_InBuffer[1] = (short*) calloc(m_BufSizeBytes/2,m_BufSizeBytes); | |||
| } | |||
| m_Wav.SetSamplerate(host->SAMPLERATE); | |||
| } | |||
| void OSSOutput::DeallocateBuffer() | |||
| void OSSClient::DeallocateBuffer() | |||
| { | |||
| if (m_Buffer[0]!=NULL) | |||
| { | |||
| @@ -316,7 +319,7 @@ void OSSOutput::DeallocateBuffer() | |||
| ////////////////////////////////////////////////////////////////////// | |||
| void OSSOutput::SendStereo(const Sample *ldata,const Sample *rdata) | |||
| void OSSClient::SendStereo(const Sample *ldata,const Sample *rdata) | |||
| { | |||
| if (m_Channels!=2) return; | |||
| @@ -349,7 +352,7 @@ void OSSOutput::SendStereo(const Sample *ldata,const Sample *rdata) | |||
| ////////////////////////////////////////////////////////////////////// | |||
| void OSSOutput::Play() | |||
| void OSSClient::Play() | |||
| { | |||
| int BufferToSend=!m_WriteBufferNum; | |||
| @@ -365,18 +368,13 @@ void OSSOutput::Play() | |||
| write(m_Dspfd,m_Buffer[BufferToSend],m_BufSizeBytes); | |||
| } | |||
| if(m_Wav.Recording()) | |||
| { | |||
| m_Wav.Save(m_Buffer[BufferToSend],m_BufSizeBytes); | |||
| } | |||
| memset(m_Buffer[BufferToSend],0,m_BufSizeBytes); | |||
| m_WriteBufferNum=BufferToSend; | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| void OSSOutput::GetStereo(Sample *ldata,Sample *rdata) | |||
| void OSSClient::GetStereo(Sample *ldata,Sample *rdata) | |||
| { | |||
| if (m_Channels!=2) return; | |||
| @@ -395,7 +393,7 @@ void OSSOutput::GetStereo(Sample *ldata,Sample *rdata) | |||
| ////////////////////////////////////////////////////////////////////// | |||
| void OSSOutput::Read() | |||
| void OSSClient::Read() | |||
| { | |||
| int BufferToRead=!m_ReadBufferNum; | |||
| @@ -415,7 +413,7 @@ void OSSOutput::Read() | |||
| ////////////////////////////////////////////////////////////////////// | |||
| bool OSSOutput::Close() | |||
| bool OSSClient::Close() | |||
| { | |||
| cerr<<"Closing dsp output"<<endl; | |||
| close(m_Dspfd); | |||
| @@ -425,7 +423,7 @@ bool OSSOutput::Close() | |||
| ////////////////////////////////////////////////////////////////////// | |||
| bool OSSOutput::OpenWrite() | |||
| bool OSSClient::OpenWrite() | |||
| { | |||
| int result,val; | |||
| cerr<<"Opening dsp output"<<endl; | |||
| @@ -489,7 +487,7 @@ bool OSSOutput::OpenWrite() | |||
| ////////////////////////////////////////////////////////////////////// | |||
| bool OSSOutput::OpenRead() | |||
| bool OSSClient::OpenRead() | |||
| { | |||
| int result,val; | |||
| @@ -524,7 +522,7 @@ bool OSSOutput::OpenRead() | |||
| ////////////////////////////////////////////////////////////////////// | |||
| bool OSSOutput::OpenReadWrite() | |||
| bool OSSClient::OpenReadWrite() | |||
| { | |||
| int result,val; | |||
| cerr<<"Opening dsp output (duplex)"<<endl; | |||
| @@ -23,12 +23,12 @@ | |||
| #ifndef OutputPLUGIN | |||
| #define OutputPLUGIN | |||
| class OSSOutput | |||
| class OSSClient | |||
| { | |||
| public: | |||
| static OSSOutput *Get() { if(!m_Singleton) m_Singleton=new OSSOutput; return m_Singleton; } | |||
| static OSSClient *Get() { if(!m_Singleton) m_Singleton=new OSSClient; return m_Singleton; } | |||
| static void PackUpAndGoHome() { if(m_Singleton) { delete m_Singleton; m_Singleton=NULL; } } | |||
| ~OSSOutput(); | |||
| ~OSSClient(); | |||
| void AllocateBuffer(); | |||
| void DeallocateBuffer(); | |||
| @@ -39,8 +39,7 @@ public: | |||
| float GetVolume() {return m_Amp;} | |||
| void Play(); | |||
| void Read(); | |||
| void WavOpen(char* name) {m_Wav.Open(name,WavFile::WRITE, WavFile::STEREO);} | |||
| void WavClose() {m_Wav.Close();} | |||
| short *GetBuffer() {return m_Buffer[m_WriteBufferNum];} | |||
| bool OpenReadWrite(); | |||
| @@ -49,9 +48,9 @@ public: | |||
| bool Close(); | |||
| void Kill() { m_IsDead = true; m_OutputOk=false; PackUpAndGoHome(); } | |||
| private: | |||
| static OSSOutput* m_Singleton; | |||
| static OSSClient* m_Singleton; | |||
| OSSOutput(); | |||
| OSSClient(); | |||
| short *m_Buffer[2]; | |||
| short *m_InBuffer[2]; | |||
| @@ -59,7 +58,7 @@ private: | |||
| int m_Dspfd; | |||
| float m_Amp; | |||
| int m_Channels; | |||
| WavFile m_Wav; | |||
| int m_ReadBufferNum; | |||
| int m_WriteBufferNum; | |||
| bool m_OutputOk; | |||
| @@ -67,7 +66,7 @@ private: | |||
| }; | |||
| class OutputPlugin : public SpiralPlugin | |||
| class OutputPlugin : public AudioDriver | |||
| { | |||
| public: | |||
| enum Mode {NO_MODE,INPUT,OUTPUT,DUPLEX,CLOSED}; | |||
| @@ -77,26 +76,34 @@ public: | |||
| virtual PluginInfo& Initialise(const HostInfo *Host); | |||
| virtual SpiralGUIType* CreateGUI(); | |||
| virtual void Execute(); | |||
| virtual bool Kill(); | |||
| virtual void Reset(); | |||
| virtual void ExecuteCommands(); | |||
| virtual void StreamOut(std::ostream &s) {} | |||
| virtual void StreamIn(std::istream &s) {} | |||
| /* General Plugin Function */ | |||
| virtual void Execute(); | |||
| virtual void ExecuteCommands(); | |||
| virtual bool Kill(); | |||
| virtual void Reset(); | |||
| /* Audio Driver Specific Functions */ | |||
| virtual bool IsAudioDriver() { return true; } | |||
| virtual AudioProcessType ProcessType() { return AudioDriver::ALWAYS; } | |||
| virtual void ProcessAudio(); | |||
| /* OSS Plugin Specific Functions */ | |||
| enum GUICommands {NONE, OPENREAD, OPENWRITE, OPENDUPLEX, CLOSE, SET_VOLUME, CLEAR_NOTIFY}; | |||
| float m_Volume; | |||
| Mode GetMode() { return m_Mode; } | |||
| /* OSS Plugin Streaming - soon to be obsolete and for backward compatibility only*/ | |||
| virtual void StreamOut(std::ostream &s) {} | |||
| virtual void StreamIn(std::istream &s) {} | |||
| private: | |||
| static int m_RefCount; | |||
| static int m_NoExecuted; | |||
| static Mode m_Mode; | |||
| bool m_NotifyOpenOut; | |||
| bool m_CheckedAlready; | |||
| bool m_Recmode; | |||
| }; | |||
| #endif | |||
| @@ -73,7 +73,7 @@ void OutputPluginGUI::Update() | |||
| void OutputPluginGUI::UpdateValues(SpiralPlugin *o) | |||
| { | |||
| Volume->value(OSSOutput::Get()->GetVolume()); | |||
| Volume->value(OSSClient::Get()->GetVolume()); | |||
| } | |||
| //// Callbacks //// | |||
| @@ -47,12 +47,15 @@ struct PluginInfo | |||
| struct HostInfo | |||
| { | |||
| int BUFSIZE; | |||
| int SAMPLERATE; | |||
| /* obsolete - REMOVE SOON */ | |||
| int FRAGSIZE; | |||
| int FRAGCOUNT; | |||
| int SAMPLERATE; | |||
| std::string OUTPUTFILE; | |||
| std::string MIDIFILE; | |||
| int POLY; | |||
| unsigned GUI_COLOUR; | |||
| unsigned SCOPE_BG_COLOUR; | |||
| unsigned SCOPE_FG_COLOUR; | |||
| @@ -102,7 +105,7 @@ public: | |||
| void UpdatePluginInfoWithHost(); | |||
| void SetInPortType(PluginInfo &pinfo, int port, Sample::SampleType type); | |||
| void SetOutPortType(PluginInfo &pinfo, int port, Sample::SampleType type); | |||
| void SetOutPortType(PluginInfo &pinfo, int port, Sample::SampleType type); | |||
| // Callbacks to main engine. Should only called by plugin hosts. | |||
| void SetUpdateInfoCallback(int ID, void(*s)(int, void *)); | |||
| @@ -115,8 +118,9 @@ public: | |||
| bool IsTerminal() { return m_IsTerminal; } | |||
| bool IsDead() { return m_IsDead; } | |||
| ChannelHandler *GetChannelHandler() { return m_AudioCH; } | |||
| ChannelHandler *GetChannelHandler() { return m_AudioCH; } | |||
| virtual bool IsAudioDriver() { return false; } | |||
| protected: | |||
| ChannelHandler *m_AudioCH; | |||
| @@ -178,4 +182,37 @@ private: | |||
| int m_HostID; | |||
| }; | |||
| class AudioDriver : public SpiralPlugin | |||
| { | |||
| public: | |||
| /* if this is an ALWAYS process then ProcessAudio must | |||
| always be called regardless whether it has something to | |||
| process or not, so it is run along side GUI commands, | |||
| ala ExecuteCommands, and is run even if paused. | |||
| If its MANUAL we are the ones doing the pushing of data | |||
| so we don't have to worry about it if we aren't hooked up, | |||
| and we do have to worry about synchronization with other | |||
| plugins, so ProcessAudio should be run along side of | |||
| regular audio updates, ala Execute. This is eg. for | |||
| a File Output driver. | |||
| NEVER means we never need to run ProcessAudio, eg, | |||
| a dummy audio driver. | |||
| */ | |||
| enum AudioProcessType { ALWAYS, MANUAL, NEVER }; | |||
| virtual bool IsAudioDriver() { return true; } | |||
| virtual void ProcessAudio()=0; | |||
| virtual AudioProcessType ProcessType() { return NEVER; } | |||
| // Callbacks to main engine. Should only called by plugin hosts. | |||
| void SetChangeBufferAndSampleRateCallback(void(*s)(long unsigned int, long unsigned int, void *)) { ChangeBufferAndSampleRate = s; } ; | |||
| protected: | |||
| void (*ChangeBufferAndSampleRate)(long unsigned int BufferSize, long unsigned int SampleRate, void *); | |||
| }; | |||
| #endif | |||
| @@ -77,13 +77,18 @@ SynthModular::SynthModular(): | |||
| m_NextID(0), | |||
| m_PauseAudio(false) | |||
| { | |||
| /* Shared Audio State Information */ | |||
| m_Info.BUFSIZE = SpiralInfo::BUFSIZE; | |||
| m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE; | |||
| /* obsolete - REMOVE SOON */ | |||
| m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE; | |||
| m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT; | |||
| m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE; | |||
| m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE; | |||
| m_Info.MIDIFILE = SpiralInfo::MIDIFILE; | |||
| m_Info.POLY = SpiralInfo::POLY; | |||
| /* Shared GUI Preferences Information */ | |||
| m_Info.GUI_COLOUR = SpiralInfo::GUI_COLOUR; | |||
| m_Info.SCOPE_BG_COLOUR = SpiralInfo::SCOPE_BG_COLOUR; | |||
| m_Info.SCOPE_FG_COLOUR = SpiralInfo::SCOPE_FG_COLOUR; | |||
| @@ -145,8 +150,6 @@ void SynthModular::Update() | |||
| { | |||
| m_CH.UpdateDataNow(); | |||
| if (m_PauseAudio) return; | |||
| // for all the plugins | |||
| for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin(); | |||
| i!=m_DeviceWinMap.end(); i++) | |||
| @@ -160,21 +163,35 @@ void SynthModular::Update() | |||
| //Erase Device from DeviceWinMap | |||
| m_DeviceWinMap.erase(i); | |||
| } | |||
| else if (i->second->m_Device && !m_ResetingAudioThread) // if it's not a comment and we aren't reseting | |||
| else if (i->second->m_Device) // if it's not a comment | |||
| { | |||
| #ifdef DEBUG_PLUGINS | |||
| cerr<<"Updating channelhandler of plugin "<<i->second->m_PluginID<<endl; | |||
| #endif | |||
| if ((!m_ResetingAudioThread) && (!m_PauseAudio)) | |||
| { | |||
| #ifdef DEBUG_PLUGINS | |||
| cerr<<"Updating channelhandler of plugin "<<i->second->m_PluginID<<endl; | |||
| #endif | |||
| // updates the data from the gui thread, if it's not blocking | |||
| i->second->m_Device->UpdateChannelHandler(); | |||
| // updates the data from the gui thread, if it's not blocking | |||
| i->second->m_Device->UpdateChannelHandler(); | |||
| #ifdef DEBUG_PLUGINS | |||
| cerr<<"Finished updating"<<endl; | |||
| #endif | |||
| #ifdef DEBUG_PLUGINS | |||
| cerr<<"Finished updating"<<endl; | |||
| #endif | |||
| // run any commands we've received from the GUI's | |||
| i->second->m_Device->ExecuteCommands(); | |||
| // run any commands we've received from the GUI's | |||
| i->second->m_Device->ExecuteCommands(); | |||
| } | |||
| // If this is an audio device see if we always need to ProcessAudio here | |||
| if (i->second->m_Device->IsAudioDriver()) | |||
| { | |||
| AudioDriver *driver = ((AudioDriver *)i->second->m_Device); | |||
| if (driver->ProcessType() == AudioDriver::ALWAYS) | |||
| { | |||
| driver->ProcessAudio(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -185,7 +202,7 @@ void SynthModular::Update() | |||
| { | |||
| // use the graphsort order to remove internal latency | |||
| map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(*i); | |||
| if (di!=m_DeviceWinMap.end() && di->second->m_Device && (! di->second->m_Device->IsDead())) | |||
| if (di!=m_DeviceWinMap.end() && di->second->m_Device && (! di->second->m_Device->IsDead()) && (!m_PauseAudio)) | |||
| { | |||
| #ifdef DEBUG_PLUGINS | |||
| cerr<<"Executing plugin "<<di->second->m_PluginID<<endl; | |||
| @@ -198,6 +215,17 @@ void SynthModular::Update() | |||
| else | |||
| { | |||
| di->second->m_Device->Execute(); | |||
| // If this is an audio device see if we need to ProcessAudio here | |||
| if (di->second->m_Device->IsAudioDriver()) | |||
| { | |||
| AudioDriver *driver = ((AudioDriver *)di->second->m_Device); | |||
| if (driver->ProcessType() == AudioDriver::MANUAL) | |||
| { | |||
| driver->ProcessAudio(); | |||
| } | |||
| } | |||
| } | |||
| #ifdef DEBUG_PLUGINS | |||
| @@ -258,6 +286,13 @@ void SynthModular::UpdatePluginGUIs() | |||
| } | |||
| m_Canvas->Poll(); | |||
| if (m_HostNeedsUpdate) | |||
| { | |||
| cout << "Updating SampleRate to: " << SpiralInfo::SAMPLERATE << " and Buffer Size to: " << SpiralInfo::BUFSIZE << " to match current Audio Driver." << endl; | |||
| UpdateHostInfo(); | |||
| m_HostNeedsUpdate = false; | |||
| } | |||
| } | |||
| ////////////////////////////////////////////////////////// | |||
| @@ -353,6 +388,16 @@ SpiralWindowType *SynthModular::CreateWindow() | |||
| m_NewComment->callback((Fl_Callback*)cb_NewComment); | |||
| m_Toolbar->add(m_NewComment); | |||
| m_PlayPause = new Fl_Button(0, 0, but, but, "Play/Pause"); | |||
| m_PlayPause->type(0); | |||
| m_PlayPause->box(FL_PLASTIC_UP_BOX); | |||
| m_PlayPause->color(SpiralInfo::GUICOL_Button); | |||
| m_PlayPause->selection_color(SpiralInfo::GUICOL_Tool); | |||
| m_PlayPause->labelsize (1); | |||
| m_PlayPause->tooltip("Play/Pause"); | |||
| m_PlayPause->callback((Fl_Callback*)cb_PlayPause); | |||
| m_Toolbar->add(m_PlayPause); | |||
| m_GroupFiller = new Fl_Group (0, 0, 0, ToolbarHeight, ""); | |||
| m_GroupFiller->color(SpiralInfo::GUICOL_Button); | |||
| m_Topbar->add (m_GroupFiller); | |||
| @@ -634,6 +679,11 @@ DeviceWin* SynthModular::NewDeviceWin(int n, int x, int y) | |||
| nlw->m_Device->SetUpdateCallback(cb_Update); | |||
| nlw->m_Device->SetParent((void*)this); | |||
| if ( AudioDriver *driver = dynamic_cast<AudioDriver*>(nlw->m_Device) ) | |||
| { | |||
| driver->SetChangeBufferAndSampleRateCallback(cb_ChangeBufferAndSampleRate); | |||
| } | |||
| PluginInfo PInfo = nlw->m_Device->Initialise(&m_Info); | |||
| SpiralGUIType *temp = nlw->m_Device->CreateGUI(); | |||
| Fl_Pixmap *Pix = new Fl_Pixmap(Plugin->GetIcon()); | |||
| @@ -728,16 +778,35 @@ void SynthModular::AddComment(int n) | |||
| ////////////////////////////////////////////////////////// | |||
| void SynthModular::cb_ChangeBufferAndSampleRate_i(long int NewBufferSize, long int NewSamplerate) | |||
| { | |||
| if (SpiralInfo::BUFSIZE != NewBufferSize) | |||
| { | |||
| // update the settings | |||
| SpiralInfo::BUFSIZE = NewBufferSize; | |||
| m_HostNeedsUpdate = true; | |||
| } | |||
| if (SpiralInfo::SAMPLERATE != NewSamplerate) | |||
| { | |||
| SpiralInfo::SAMPLERATE = NewSamplerate; | |||
| m_HostNeedsUpdate = true; | |||
| } | |||
| } | |||
| void SynthModular::UpdateHostInfo() | |||
| { | |||
| /* Pause Audio */ | |||
| PauseAudio(); | |||
| // update the settings | |||
| /* update the settings */ | |||
| m_Info.BUFSIZE = SpiralInfo::BUFSIZE; | |||
| m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE; | |||
| /* obsolete - REMOVE SOON */ | |||
| m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE; | |||
| m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT; | |||
| m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE; | |||
| m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE; | |||
| m_Info.MIDIFILE = SpiralInfo::MIDIFILE; | |||
| m_Info.POLY = SpiralInfo::POLY; | |||
| @@ -1334,6 +1403,21 @@ void SynthModular::cb_NewComment(Fl_Button* o, void* v) | |||
| ////////////////////////////////////////////////////////// | |||
| inline void SynthModular::cb_PlayPause_i(Fl_Button* o, void* v) | |||
| { | |||
| if (m_ResetingAudioThread) return; | |||
| if (IsPaused()) | |||
| ResumeAudio(); | |||
| else | |||
| PauseAudio(); | |||
| } | |||
| void SynthModular::cb_PlayPause(Fl_Button* o, void* v) | |||
| {((SynthModular*)(o->parent()->user_data()))->cb_PlayPause_i(o,v);} | |||
| ////////////////////////////////////////////////////////// | |||
| inline void SynthModular::cb_GroupTab_i(Fl_Tabs* o, void* v) | |||
| { | |||
| m_GroupTab->redraw(); | |||
| @@ -134,6 +134,7 @@ private: | |||
| HostInfo m_Info; | |||
| bool m_ResetingAudioThread; | |||
| bool m_HostNeedsUpdate; | |||
| static DeviceGUIInfo BuildDeviceGUIInfo(PluginInfo &PInfo); | |||
| @@ -158,6 +159,7 @@ private: | |||
| Fl_Button *m_New; | |||
| Fl_Button *m_Options; | |||
| Fl_Button *m_NewComment; | |||
| Fl_Button *m_PlayPause; | |||
| Fl_Tabs *m_GroupTab; | |||
| Fl_Canvas *m_Canvas; | |||
| @@ -187,7 +189,9 @@ private: | |||
| static void cb_Save(Fl_Button* o, void* v); | |||
| inline void cb_New_i(Fl_Button* o, void* v); | |||
| static void cb_New(Fl_Button* o, void* v); | |||
| inline void cb_PlayPause_i(Fl_Button* o, void* v); | |||
| static void cb_PlayPause(Fl_Button* o, void* v); | |||
| inline void cb_MergePatch_i(); | |||
| static void cb_MergePatch(Fl_Canvas* o, SynthModular*v) { v->cb_MergePatch_i(); }; | |||
| @@ -208,6 +212,13 @@ private: | |||
| static void cb_Blocking(void* o, bool Mode); | |||
| static void cb_UpdatePluginInfo(int ID, void *PluginInfo); | |||
| inline void cb_ChangeBufferAndSampleRate_i(long int NewBufferSize, long int NewSamplerate); | |||
| static void cb_ChangeBufferAndSampleRate(long unsigned int NewBufferSize, long unsigned int NewSamplerate, void *o) | |||
| { | |||
| ((SynthModular*)o)->cb_ChangeBufferAndSampleRate_i(NewBufferSize, NewSamplerate); | |||
| } | |||
| DeviceGroup m_Copied; | |||
| inline void cb_CutDeviceGroup_i(); | |||