| @@ -205,19 +205,19 @@ void Fl_DeviceGUI::Setup(const DeviceGUIInfo& Info, bool FirstTime) | |||
| int PortDist=10; | |||
| int PortNum=0; | |||
| m_MiniHeight=Info.Height+TitleBarHeight; | |||
| m_MiniHeight=m_Info.Height+TitleBarHeight; | |||
| bool Maximised = (m_PluginWindow && m_PluginWindow->visible()); | |||
| if (!Maximised) | |||
| { | |||
| h(m_MiniHeight); | |||
| OutputX=x()+PortGroupWidth+Info.Width+4; | |||
| OutputX=x()+PortGroupWidth+m_Info.Width+4; | |||
| } | |||
| else | |||
| { | |||
| OutputX=x()+w()-8; | |||
| } | |||
| for (int n=0; n<Info.NumInputs; n++) | |||
| for (int n=0; n<m_Info.NumInputs; n++) | |||
| { | |||
| Fl_PortButton* NewInput = new Fl_PortButton(InputX,StartY+PortDist*n,PortSize,PortSize,""); | |||
| NewInput->type(1); | |||
| @@ -226,7 +226,7 @@ void Fl_DeviceGUI::Setup(const DeviceGUIInfo& Info, bool FirstTime) | |||
| NewInput->box(FL_ROUNDED_BOX); | |||
| Fl_Color col = (Fl_Color) WIRE_COL0; | |||
| switch (Info.PortTypes[n]) { | |||
| switch (m_Info.PortTypes[n]) { | |||
| case 0: col = (Fl_Color) WIRE_COL0; | |||
| break; | |||
| case 1: col = (Fl_Color) WIRE_COL1; | |||
| @@ -242,14 +242,14 @@ void Fl_DeviceGUI::Setup(const DeviceGUIInfo& Info, bool FirstTime) | |||
| NewInput->selection_color(col); | |||
| NewInput->down_box(FL_ROUNDED_BOX); | |||
| NewInput->tooltip(Info.PortTips[n].c_str()); | |||
| NewInput->tooltip(m_Info.PortTips[n].c_str()); | |||
| NewInput->callback((Fl_Callback*)cb_Port,(void*)&Numbers[PortNum]); | |||
| m_PortVec.push_back(NewInput); | |||
| add(NewInput); | |||
| PortNum++; | |||
| } | |||
| for (int n=0; n<Info.NumOutputs; n++) | |||
| for (int n=0; n<m_Info.NumOutputs; n++) | |||
| { | |||
| Fl_PortButton* NewOutput= NewOutput = new Fl_PortButton(OutputX,StartY+PortDist*n,PortSize,PortSize,""); | |||
| NewOutput->type(1); | |||
| @@ -258,7 +258,7 @@ void Fl_DeviceGUI::Setup(const DeviceGUIInfo& Info, bool FirstTime) | |||
| NewOutput->box(FL_ROUNDED_BOX); | |||
| Fl_Color col = (Fl_Color) WIRE_COL0; | |||
| switch (Info.PortTypes[n+Info.NumInputs]) { | |||
| switch (m_Info.PortTypes[n+m_Info.NumInputs]) { | |||
| case 0: col = (Fl_Color) WIRE_COL0; | |||
| break; | |||
| case 1: col = (Fl_Color) WIRE_COL1; | |||
| @@ -274,7 +274,7 @@ void Fl_DeviceGUI::Setup(const DeviceGUIInfo& Info, bool FirstTime) | |||
| NewOutput->selection_color(col); | |||
| NewOutput->down_box(FL_ROUNDED_BOX); | |||
| NewOutput->tooltip(Info.PortTips[n+Info.NumInputs].c_str()); | |||
| NewOutput->tooltip(m_Info.PortTips[n+m_Info.NumInputs].c_str()); | |||
| NewOutput->callback((Fl_Callback*)cb_Port,(void*)&Numbers[PortNum]); | |||
| m_PortVec.push_back(NewOutput); | |||
| add(NewOutput); | |||
| @@ -136,8 +136,21 @@ SpiralGUIType *OutputPlugin::CreateGUI() | |||
| return new OutputPluginGUI(m_PluginInfo.Width, m_PluginInfo.Height, this, m_AudioCH, m_HostInfo); | |||
| } | |||
| bool OutputPlugin::Kill() | |||
| { | |||
| m_IsDead=true; | |||
| OSSOutput::Get()->Kill(); | |||
| m_Mode=CLOSED; | |||
| cb_Blocking(m_Parent,false); | |||
| return true; | |||
| } | |||
| void OutputPlugin::Execute() | |||
| { | |||
| if (m_IsDead) | |||
| return; | |||
| if (m_Mode==NO_MODE && m_RefCount==1) | |||
| { | |||
| if (OSSOutput::Get()->OpenWrite()) | |||
| @@ -148,44 +161,9 @@ void OutputPlugin::Execute() | |||
| } | |||
| } | |||
| //if (m_Mode==NO_MODE || m_Mode==CLOSED) cb_Blocking(m_Parent,false); | |||
| //else cb_Blocking(m_Parent,true); | |||
| if (m_Mode==OUTPUT || m_Mode==DUPLEX) | |||
| { | |||
| OSSOutput::Get()->SendStereo(GetInput(0),GetInput(1)); | |||
| // can't open GUI stuff here | |||
| /* for (int n=0; n<m_HostInfo->BUFSIZE;n++) | |||
| { | |||
| // can't open GUI stuff here | |||
| if (GetInput(2,n)!=0) | |||
| { | |||
| if (! m_CheckedAlready) | |||
| { | |||
| m_CheckedAlready=true; | |||
| // an experimental line, should *theoretically* cut down on CPU time. | |||
| n=m_HostInfo->BUFSIZE; | |||
| if (! m_Recmode) | |||
| { | |||
| char *fn=fl_file_chooser("Pick a Wav file to save to", "*.wav", NULL); | |||
| if (fn && fn!="") | |||
| { | |||
| OSSOutput::Get()->WavOpen(fn); | |||
| } | |||
| m_Recmode=true; | |||
| } | |||
| else | |||
| { | |||
| OSSOutput::Get()->WavClose(); | |||
| m_Recmode=false; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| m_CheckedAlready=false; | |||
| }*/ | |||
| } | |||
| if (m_Mode==INPUT || m_Mode==DUPLEX) | |||
| @@ -194,8 +172,10 @@ void OutputPlugin::Execute() | |||
| void OutputPlugin::ExecuteCommands() | |||
| { | |||
| // Only Play() once per set of plugins | |||
| if (m_IsDead) | |||
| return; | |||
| // Only Play() once per set of plugins | |||
| m_NoExecuted--; | |||
| if (m_NoExecuted<=0) | |||
| { | |||
| @@ -254,7 +234,9 @@ m_Amp(0.5), | |||
| m_Channels(2), | |||
| m_ReadBufferNum(0), | |||
| m_WriteBufferNum(0), | |||
| m_OutputOk(false) | |||
| m_OutputOk(false), | |||
| m_IsDead(false) | |||
| { | |||
| m_Buffer[0]=NULL; | |||
| m_Buffer[1]=NULL; | |||
| @@ -267,6 +249,7 @@ m_OutputOk(false) | |||
| OSSOutput::~OSSOutput() | |||
| { | |||
| Close(); | |||
| DeallocateBuffer(); | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| @@ -287,6 +270,20 @@ void OSSOutput::AllocateBuffer() | |||
| m_Wav.SetSamplerate(host->SAMPLERATE); | |||
| } | |||
| void OSSOutput::DeallocateBuffer() | |||
| { | |||
| if (m_Buffer[0]!=NULL) | |||
| { | |||
| m_BufSizeBytes=0; | |||
| // initialise for stereo | |||
| free(m_Buffer[0]); | |||
| free(m_Buffer[1]); | |||
| free(m_InBuffer[0]); | |||
| free(m_InBuffer[1]); | |||
| } | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| void OSSOutput::SendStereo(const Sample *ldata,const Sample *rdata) | |||
| @@ -297,6 +294,8 @@ void OSSOutput::SendStereo(const Sample *ldata,const Sample *rdata) | |||
| float t; | |||
| for (int n=0; n<host->BUFSIZE; n++) | |||
| { | |||
| if (m_IsDead) return; | |||
| // stereo channels - interleave | |||
| if (ldata) | |||
| { | |||
| @@ -354,6 +353,8 @@ void OSSOutput::GetStereo(Sample *ldata,Sample *rdata) | |||
| int on=0; | |||
| for (int n=0; n<host->BUFSIZE; n++) | |||
| { | |||
| if (m_IsDead) return; | |||
| // stereo channels - interleave | |||
| if (ldata) ldata->Set(n,(m_InBuffer[m_ReadBufferNum][on]*m_Amp)/(float)SHRT_MAX); | |||
| on++; | |||
| @@ -31,6 +31,7 @@ public: | |||
| ~OSSOutput(); | |||
| void AllocateBuffer(); | |||
| void DeallocateBuffer(); | |||
| void SendStereo(const Sample *ldata,const Sample *rdata); | |||
| void GetStereo(Sample *ldata,Sample *rdata); | |||
| void SetVolume(float s) {m_Amp=s;} | |||
| @@ -46,7 +47,7 @@ public: | |||
| bool OpenWrite(); | |||
| bool OpenRead(); | |||
| bool Close(); | |||
| void Kill() { m_IsDead = true; m_OutputOk=false; PackUpAndGoHome(); } | |||
| private: | |||
| static OSSOutput* m_Singleton; | |||
| @@ -62,6 +63,7 @@ private: | |||
| int m_ReadBufferNum; | |||
| int m_WriteBufferNum; | |||
| bool m_OutputOk; | |||
| bool m_IsDead; | |||
| }; | |||
| @@ -76,6 +78,7 @@ public: | |||
| virtual PluginInfo& Initialise(const HostInfo *Host); | |||
| virtual SpiralGUIType* CreateGUI(); | |||
| virtual void Execute(); | |||
| virtual bool Kill(); | |||
| virtual void ExecuteCommands(); | |||
| virtual void StreamOut(std::ostream &s) {} | |||
| virtual void StreamIn(std::istream &s) {} | |||
| @@ -33,7 +33,7 @@ SpiralPlugin::SpiralPlugin() | |||
| m_Parent=NULL; | |||
| m_HostID=-1; | |||
| m_IsTerminal=false; | |||
| m_IsDead=false; | |||
| m_AudioCH = new ChannelHandler; | |||
| } | |||
| @@ -77,6 +77,8 @@ public: | |||
| // execute the audio | |||
| virtual void Execute()=0; | |||
| virtual bool Kill() {m_IsDead = true; return true;} | |||
| // run the commands from the GUI | |||
| virtual void ExecuteCommands() {} | |||
| // create the GUI, do not store the pointer - it wont be threadsafe to use it | |||
| @@ -110,6 +112,7 @@ public: | |||
| void UpdateChannelHandler(); | |||
| // is the plugin connected to an external device (oss/alsa/jack) | |||
| bool IsTerminal() { return m_IsTerminal; } | |||
| bool IsDead() { return m_IsDead; } | |||
| ChannelHandler *GetChannelHandler() { return m_AudioCH; } | |||
| @@ -161,6 +164,7 @@ protected: | |||
| void (*cb_Blocking)(void*o ,bool m); | |||
| bool m_IsTerminal; | |||
| bool m_IsDead; | |||
| private: | |||
| @@ -115,13 +115,15 @@ void SynthModular::ClearUp() | |||
| for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin(); | |||
| i!=m_DeviceWinMap.end(); i++) | |||
| { | |||
| if (i->second->m_Device->Kill()); | |||
| i->second->m_DeviceGUI->Clear(); | |||
| if (i->second->m_DeviceGUI->GetPluginWindow()) | |||
| { | |||
| i->second->m_DeviceGUI->GetPluginWindow()->hide(); | |||
| //m_MainWindow->remove(i->second->m_DeviceGUI->GetPluginWindow()); | |||
| } | |||
| // deleted by Canvas::Remove()? seems to cause random crashes | |||
| //delete i->second->m_DeviceGUI; | |||
| //Delete Device | |||
| delete i->second->m_Device; | |||
| i->second->m_Device=NULL; | |||
| } | |||
| @@ -134,7 +136,6 @@ void SynthModular::ClearUp() | |||
| } | |||
| ////////////////////////////////////////////////////////// | |||
| void SynthModular::Update() | |||
| { | |||
| m_CH.UpdateDataNow(); | |||
| @@ -145,7 +146,16 @@ void SynthModular::Update() | |||
| for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin(); | |||
| i!=m_DeviceWinMap.end(); i++) | |||
| { | |||
| if (i->second->m_Device) // if it's not a comment | |||
| if (i->second->m_Device && i->second->m_Device->IsDead()) | |||
| { | |||
| //Delete Device | |||
| delete i->second->m_Device; | |||
| i->second->m_Device=NULL; | |||
| //Erase Device from DeviceWinMap | |||
| m_DeviceWinMap.erase(i); | |||
| } | |||
| 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; | |||
| @@ -170,7 +180,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) | |||
| if (di!=m_DeviceWinMap.end() && di->second->m_Device && (! di->second->m_Device->IsDead())) | |||
| { | |||
| #ifdef DEBUG_PLUGINS | |||
| cerr<<"Executing plugin "<<di->second->m_PluginID<<endl; | |||
| @@ -193,15 +203,25 @@ void SynthModular::UpdatePluginGUIs() | |||
| for (map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin(); | |||
| i!=m_DeviceWinMap.end(); i++) | |||
| { | |||
| if (i->second->m_DeviceGUI->GetPluginWindow()) | |||
| if (i->second->m_DeviceGUI && i->second->m_DeviceGUI->GetPluginWindow()) | |||
| { | |||
| SpiralPluginGUI *GUI=(SpiralPluginGUI *)i->second->m_DeviceGUI->GetPluginWindow(); | |||
| GUI->Update(); | |||
| } | |||
| if (i->second->m_DeviceGUI->Killed()) | |||
| if (i->second->m_DeviceGUI && i->second->m_DeviceGUI->Killed()) | |||
| { | |||
| PauseAudio(); | |||
| bool erase = true; | |||
| //Stop processing of audio if any | |||
| if (i->second->m_Device) | |||
| { | |||
| if (i->second->m_Device->Kill()); | |||
| erase = false; | |||
| } | |||
| //Clear GUI Device | |||
| i->second->m_DeviceGUI->Clear(); | |||
| // Hide Device GUI FIRST | |||
| if (i->second->m_DeviceGUI->GetPluginWindow()) | |||
| @@ -209,28 +229,16 @@ void SynthModular::UpdatePluginGUIs() | |||
| i->second->m_DeviceGUI->GetPluginWindow()->hide(); | |||
| } | |||
| // Clear and remove Device GUI from canvas | |||
| i->second->m_DeviceGUI->Clear(); | |||
| //Remove Device GUI from canvas | |||
| m_Canvas->RemoveDevice(i->second->m_DeviceGUI); | |||
| // Delete Device GUI - must delete here or sometimes plugin will randomly crash | |||
| // SOMETIMES AT THIS POINT THE WHOLE THING JUST LOCKS UP | |||
| // In the previous version of this code this next line was commented out | |||
| // with the comment "deleted by Canvas::Remove()? seems to cause random crashes" | |||
| //Delete Device GUI - must delete here or sometimes plugin will randomly crash | |||
| delete i->second->m_DeviceGUI; | |||
| i->second->m_DeviceGUI = NULL; | |||
| // Delete Device Sometimes deleting audio before GUI causes an odd crash, so do it afterword | |||
| if (i->second->m_Device) | |||
| { | |||
| delete i->second->m_Device; | |||
| i->second->m_Device=NULL; | |||
| } | |||
| // Erase Device from DeviceWinMap | |||
| m_DeviceWinMap.erase(i); | |||
| ResumeAudio(); | |||
| break; | |||
| //Erase from winmap if no audio to do it | |||
| if (erase) | |||
| m_DeviceWinMap.erase(i); | |||
| } | |||
| } | |||
| @@ -912,49 +920,52 @@ ostream &operator<<(ostream &s, SynthModular &o) | |||
| for(map<int,DeviceWin*>::iterator i=o.m_DeviceWinMap.begin(); | |||
| i!=o.m_DeviceWinMap.end(); i++) | |||
| { | |||
| s<<endl; | |||
| s<<"Device "; | |||
| s<<i->first<<" "; // save the id | |||
| s<<"Plugin "; | |||
| s<<i->second->m_PluginID<<endl; | |||
| s<<i->second->m_DeviceGUI->x()<<" "; | |||
| s<<i->second->m_DeviceGUI->y()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetName().size()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetName()<<" "; | |||
| if (i->second->m_DeviceGUI->GetPluginWindow()) | |||
| { | |||
| s<<i->second->m_DeviceGUI->GetPluginWindow()->visible()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetPluginWindow()->x()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetPluginWindow()->y()<<" "; | |||
| } | |||
| else | |||
| { | |||
| s<<0<<" "<<0<<" "<<0; | |||
| } | |||
| s<<endl; | |||
| if (i->second->m_PluginID==COMMENT_ID) | |||
| { | |||
| // save the comment gui | |||
| ((Fl_CommentGUI*)(i->second->m_DeviceGUI))->StreamOut(s); | |||
| } | |||
| else | |||
| { | |||
| // save the plugin | |||
| i->second->m_Device->StreamOut(s); | |||
| } | |||
| s<<endl; | |||
| // save external files | |||
| if (i->second->m_Device && i->second->m_Device->SaveExternalFiles(o.m_FilePath+"_files/")) | |||
| { | |||
| if (i->second->m_DeviceGUI && i->second->m_Device) | |||
| { | |||
| ExternalDirUsed=true; | |||
| s<<endl; | |||
| s<<"Device "; | |||
| s<<i->first<<" "; // save the id | |||
| s<<"Plugin "; | |||
| s<<i->second->m_PluginID<<endl; | |||
| s<<i->second->m_DeviceGUI->x()<<" "; | |||
| s<<i->second->m_DeviceGUI->y()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetName().size()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetName()<<" "; | |||
| if (i->second->m_DeviceGUI->GetPluginWindow()) | |||
| { | |||
| s<<i->second->m_DeviceGUI->GetPluginWindow()->visible()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetPluginWindow()->x()<<" "; | |||
| s<<i->second->m_DeviceGUI->GetPluginWindow()->y()<<" "; | |||
| } | |||
| else | |||
| { | |||
| s<<0<<" "<<0<<" "<<0; | |||
| } | |||
| s<<endl; | |||
| if (i->second->m_PluginID==COMMENT_ID) | |||
| { | |||
| // save the comment gui | |||
| ((Fl_CommentGUI*)(i->second->m_DeviceGUI))->StreamOut(s); | |||
| } | |||
| else | |||
| { | |||
| // save the plugin | |||
| i->second->m_Device->StreamOut(s); | |||
| } | |||
| s<<endl; | |||
| // save external files | |||
| if (i->second->m_Device && i->second->m_Device->SaveExternalFiles(o.m_FilePath+"_files/")) | |||
| { | |||
| ExternalDirUsed=true; | |||
| } | |||
| } | |||
| } | |||
| s<<endl<<*o.m_Canvas<<endl; | |||
| // remove it if it wasn't used | |||