/* SpiralSynthModular * Copyleft (C) 2002 David Griffiths * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SpiralSynthModular.h" #include "SpiralSound/PluginManager.h" #include "SpiralSound/Plugins/SpiralPluginGUI.h" #include "GUI/SSM.xpm" #include "GUI/load.xpm" #include "GUI/save.xpm" #include "GUI/new.xpm" #include "GUI/options.xpm" #include "GUI/edit.xpm" #include "GUI/comment.xpm" #include "GUI/Widgets/PawfalYesNo.h" //#define DEBUG_PLUGINS //#define DEBUG_STREAM const static string LABEL = "SpiralSynthModular "+VER_STRING; static string TITLEBAR; static const int FILE_VERSION = 4; static int Numbers[512]; static const int MAIN_WIDTH = 700; static const int MAIN_HEIGHT = 600; static const int SLIDER_WIDTH = 15; static const int TOOLBOX_HEIGHT = MAIN_HEIGHT; static const int TOOLBOX_WIDTH = 132+SLIDER_WIDTH; static const int ICON_DEPTH = 3; static const int COMMENT_ID = -1; using namespace std; map SynthModular::m_DeviceWinMap; bool SynthModular::m_CallbackUpdateMode = false; bool SynthModular::m_BlockingOutputPluginIsReady = false; ////////////////////////////////////////////////////////// DeviceWin::~DeviceWin() { } ////////////////////////////////////////////////////////// SynthModular::SynthModular(): m_NextID(0), m_NextPluginButton(1), m_NextPluginButtonXPos(5), m_NextPluginButtonYPos(20), m_PauseAudio(false) { m_Info.BUFSIZE = SpiralInfo::BUFSIZE; 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; //m_Info.GUI_COLOUR = SpiralInfo::GUI_COLOUR; for (int n=0; n<512; n++) Numbers[n]=n; m_CH.Register("PauseAudio",&m_PauseAudio); } ////////////////////////////////////////////////////////// SynthModular::~SynthModular() { ClearUp(); PluginManager::Get()->PackUpAndGoHome(); } ////////////////////////////////////////////////////////// void SynthModular::ClearUp() { PauseAudio(); for(map::iterator i=m_DeviceWinMap.begin(); i!=m_DeviceWinMap.end(); i++) { 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 i->second->m_Device; i->second->m_Device=NULL; } m_Canvas->Clear(); m_DeviceWinMap.clear(); m_NextID=0; ResumeAudio(); } ////////////////////////////////////////////////////////// void SynthModular::Update() { m_CH.UpdateDataNow(); if (m_PauseAudio) return; // for all the plugins for(map::iterator i=m_DeviceWinMap.begin(); i!=m_DeviceWinMap.end(); i++) { if (i->second->m_Device) // if it's not a comment { #ifdef DEBUG_PLUGINS cerr<<"Updating channelhandler of plugin "<second->m_PluginID<second->m_Device->UpdateChannelHandler(); #ifdef DEBUG_PLUGINS cerr<<"Finished updating"<second->m_Device->ExecuteCommands(); } } // run the plugins (only ones connected to anything) list ExecutionOrder = m_Canvas->GetGraph()->GetSortedList(); for (list::reverse_iterator i=ExecutionOrder.rbegin(); i!=ExecutionOrder.rend(); i++) { // use the graphsort order to remove internal latency map::iterator di=m_DeviceWinMap.find(*i); if (di!=m_DeviceWinMap.end() && di->second->m_Device) { #ifdef DEBUG_PLUGINS cerr<<"Executing plugin "<second->m_PluginID<second->m_Device->Execute(); #ifdef DEBUG_PLUGINS cerr<<"Finished executing"<::iterator i=m_DeviceWinMap.begin(); i!=m_DeviceWinMap.end(); i++) { if (i->second->m_DeviceGUI->GetPluginWindow()) { SpiralPluginGUI *GUI=(SpiralPluginGUI *)i->second->m_DeviceGUI->GetPluginWindow(); GUI->Update(); } if (i->second->m_DeviceGUI->Killed()) { PauseAudio(); if (i->second->m_Device) { delete i->second->m_Device; i->second->m_Device=NULL; } if (i->second->m_DeviceGUI->GetPluginWindow()) { i->second->m_DeviceGUI->GetPluginWindow()->hide(); //m_MainWindow->remove(i->second->m_DeviceGUI->GetPluginWindow()); } i->second->m_DeviceGUI->Clear(); m_Canvas->RemoveDevice(i->second->m_DeviceGUI); // deleted by Canvas::Remove()? seems to cause random crashes //delete i->second->m_DeviceGUI; m_DeviceWinMap.erase(i); ResumeAudio(); break; } } m_Canvas->Poll(); } ////////////////////////////////////////////////////////// SpiralWindowType *SynthModular::CreateWindow() { int xoff=0, yoff=10, but=64, gap=MAIN_HEIGHT/5, n=0; m_TopWindow = new SpiralWindowType(MAIN_WIDTH, MAIN_HEIGHT, LABEL.c_str()); m_TopWindow->resizable(m_TopWindow); m_MainButtons = new Fl_Group(0, 0, but, MAIN_HEIGHT, ""); m_MainButtons->type(1); m_MainButtons->color(SpiralSynthModularInfo::GUICOL_Tool); m_MainButtons->box(FL_FLAT_BOX); m_MainButtons->user_data((void*)(this)); m_TopWindow->add(m_MainButtons); m_Load = new Fl_Button(xoff, 5+yoff, but, but, ""); m_Load->box(FL_NO_BOX); Fl_Pixmap *tPix = new Fl_Pixmap(load_xpm); m_Load->image(tPix->copy(tPix->w(),tPix->h())); m_Load->selection_color(SpiralSynthModularInfo::GUICOL_Tool); m_Load->tooltip("Load a patch file"); m_Load->callback((Fl_Callback*)cb_Load); m_MainButtons->add(m_Load); n++; m_Save = new Fl_Button(xoff, n*gap+yoff, but, but, ""); m_Save->box(FL_NO_BOX); tPix = new Fl_Pixmap(save_xpm); m_Save->image(tPix->copy(tPix->w(),tPix->h())); delete tPix; m_Save->selection_color(SpiralSynthModularInfo::GUICOL_Tool); m_Save->tooltip("Save a patch file"); m_Save->callback((Fl_Callback*)cb_Save); m_MainButtons->add(m_Save); n++; m_New = new Fl_Button(xoff, n*gap+yoff, but, but, ""); m_New->box(FL_NO_BOX); tPix = new Fl_Pixmap(new_xpm); m_New->image(tPix->copy(tPix->w(),tPix->h())); delete tPix; m_New->selection_color(SpiralSynthModularInfo::GUICOL_Tool); m_New->tooltip("New patch"); m_New->callback((Fl_Callback*)cb_New); m_MainButtons->add(m_New); n++; m_Options = new Fl_Button(xoff, n*gap+yoff, but, but, ""); m_Options->box(FL_NO_BOX); tPix = new Fl_Pixmap(options_xpm); m_Options->image(tPix->copy(tPix->w(),tPix->h())); delete tPix; m_Options->selection_color(SpiralSynthModularInfo::GUICOL_Tool); m_Options->tooltip("Options"); m_Options->callback((Fl_Callback*)cb_Rload); m_MainButtons->add(m_Options); n++; m_NewComment = new Fl_Button(xoff, n*gap+yoff, but, but, ""); m_NewComment->box(FL_NO_BOX); tPix = new Fl_Pixmap(comment_xpm); m_NewComment->image(tPix->copy(tPix->w(),tPix->h())); delete tPix; m_NewComment->selection_color(SpiralSynthModularInfo::GUICOL_Tool); m_NewComment->tooltip("New comment"); m_NewComment->callback((Fl_Callback*)cb_NewComment); m_MainButtons->add(m_NewComment); n++; ///////////////// int edy = 0; Fl_Group *Left = new Fl_Group(MAIN_WIDTH-TOOLBOX_WIDTH,0,TOOLBOX_WIDTH,MAIN_HEIGHT); Left->box(FL_FLAT_BOX); Left->color(SpiralSynthModularInfo::GUICOL_Tool); Left->user_data((void*)(this)); m_TopWindow->add(Left); m_GroupName = new Fl_Box(MAIN_WIDTH-TOOLBOX_WIDTH,0,TOOLBOX_WIDTH,16,""); m_GroupName->labelsize(12); m_GroupName->color(SpiralSynthModularInfo::GUICOL_Canvas); m_GroupName->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); m_GroupName->box(FL_BORDER_BOX); Left->add(m_GroupName); m_PluginGroupLeft = new Fl_Button(MAIN_WIDTH-TOOLBOX_WIDTH, 0, 16, 16, "@<"); m_PluginGroupLeft->callback((Fl_Callback*)cb_PluginGroupLeft); Left->add(m_PluginGroupLeft); m_PluginGroupRight = new Fl_Button(MAIN_WIDTH-16, 0, 16, 16, "@>"); m_PluginGroupRight->callback((Fl_Callback*)cb_PluginGroupRight); Left->add(m_PluginGroupRight); m_ToolBox = new Fl_Scroll(MAIN_WIDTH-TOOLBOX_WIDTH,0+edy+16,TOOLBOX_WIDTH, TOOLBOX_HEIGHT-16, ""); m_ToolBox->type(Fl_Scroll::VERTICAL_ALWAYS); m_ToolBox->box(FL_FLAT_BOX); m_ToolBox->labeltype(FL_ENGRAVED_LABEL); m_ToolBox->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); m_ToolBox->scrollbar.align(FL_ALIGN_RIGHT); m_ToolBox->color(SpiralSynthModularInfo::GUICOL_Tool); m_ToolBox->user_data((void*)(this)); Left->add(m_ToolBox); m_TopWindow->resizable(m_ToolBox); m_CanvasScroll = new Fl_Scroll(but, 0, MAIN_WIDTH-TOOLBOX_WIDTH-but, MAIN_HEIGHT, ""); m_TopWindow->add(m_CanvasScroll); m_TopWindow->resizable(m_CanvasScroll); m_Canvas = new Fl_Canvas(-5000, -5000, 10000, 10000, ""); m_Canvas->type(1); m_Canvas->box(FL_FLAT_BOX); m_Canvas->labeltype(FL_ENGRAVED_LABEL); m_Canvas->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); m_Canvas->color(SpiralSynthModularInfo::GUICOL_Canvas); m_Canvas->user_data((void*)(this)); m_Canvas->SetConnectionCallback((Fl_Callback*)cb_Connection); m_Canvas->SetUnconnectCallback((Fl_Callback*)cb_Unconnect); m_Canvas->SetAddDeviceCallback((Fl_Callback*)cb_NewDeviceFromMenu); m_CanvasScroll->add(m_Canvas); m_SettingsWindow = new SettingsWindow; m_SettingsWindow->RegisterApp(this); return m_TopWindow; } ////////////////////////////////////////////////////////// SynthModular::ToolBox::ToolBox(Fl_Scroll *parent, void* user) { int Width = 40; int Height = 40; m_Icon=0; m_ToolPack = new Fl_Pack(MAIN_WIDTH-TOOLBOX_WIDTH+5,20,TOOLBOX_WIDTH-10, TOOLBOX_HEIGHT-60,""); m_ToolPack->type(FL_VERTICAL); m_ToolPack->box(FL_NO_BOX); m_ToolPack->color(SpiralSynthModularInfo::GUICOL_Tool); m_ToolPack->user_data(user); parent->add(m_ToolPack); m_IconPack = new Fl_Pack(0,0,TOOLBOX_WIDTH-SLIDER_WIDTH,Height,""); m_IconPack->type(FL_HORIZONTAL); m_IconPack->color(SpiralSynthModularInfo::GUICOL_Tool); m_IconPack->user_data(m_ToolPack->user_data()); m_ToolPack->add(m_IconPack); } void SynthModular::ToolBox::AddIcon(Fl_Button *Icon) { int Width = 40; int Height = 40; if (m_Icon>=ICON_DEPTH) { m_Icon=0; m_IconPack = new Fl_Pack(0,0,TOOLBOX_WIDTH-SLIDER_WIDTH,Height,""); m_IconPack->type(FL_HORIZONTAL); m_IconPack->color(SpiralSynthModularInfo::GUICOL_Tool); m_IconPack->user_data(m_ToolPack->user_data()); m_ToolPack->add(m_IconPack); } m_IconPack->add(Icon); m_Icon++; } vector SynthModular::BuildPluginList(const string &Path) { // Scan plugin path for plugins. DIR *dp; struct dirent *ep; struct stat sb; void *handle; string fullpath; const char *path = Path.c_str(); vector ret; dp = opendir(path); if (!dp) { cerr << "WARNING: Could not open path " << path << endl; } else { while ((ep = readdir(dp))) { // Need full path fullpath = path; fullpath.append(ep->d_name); // Stat file to get type if (!stat(fullpath.c_str(), &sb)) { // We only want regular files if (S_ISREG(sb.st_mode)) { // We're not fussed about resolving symbols yet, since we are just // checking if it's a DLL. handle = dlopen(fullpath.c_str(), RTLD_LAZY); if (!handle) { cerr << "WARNING: File " << path << ep->d_name << " could not be examined" << endl; cerr << "dlerror() output:" << endl; cerr << dlerror() << endl; } else { // It's a DLL. Add name to list ret.push_back(ep->d_name); } } } } } return ret; } void SynthModular::LoadPlugins(string pluginPath) { int Width = 40; int Height = 40; int SWidth = 256; int SHeight = 256; Fl_Pixmap pic(SSM_xpm); Fl_Double_Window* Splash = new Fl_Double_Window((Fl::w()/2)-(SWidth/2), (Fl::h()/2)-(SHeight/2), SWidth,SHeight,"SSM"); Splash->border(0); Fl_Box* pbut = new Fl_Box(0,8,SWidth,SHeight,""); pbut->box(FL_NO_BOX); pic.label(pbut); Fl_Box *splashtext = new Fl_Box(5,SHeight-20,200,20,"Loading..."); splashtext->labelsize(10); splashtext->box(FL_NO_BOX); splashtext->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT); Splash->add(pbut); Splash->add(splashtext); Splash->show(); int ID=-1; vector PluginVector; if (SpiralSynthModularInfo::USEPLUGINLIST) { PluginVector=SpiralSynthModularInfo::PLUGINVEC; } else { if (!pluginPath.empty()) PluginVector=BuildPluginList(pluginPath); else PluginVector=BuildPluginList(SpiralSynthModularInfo::PLUGIN_PATH); } for (vector::iterator i=PluginVector.begin(); i!=PluginVector.end(); i++) { string Fullpath; if (pluginPath=="") { Fullpath=SpiralSynthModularInfo::PLUGIN_PATH+*i; } else { Fullpath=pluginPath+*"/"+*i; } ID=PluginManager::Get()->LoadPlugin(Fullpath.c_str()); if (ID!=PluginError) { #ifdef DEBUG_PLUGINS cerr<<"Plugin ["<<*i<<"] = "<labelsize(10); Fl_Pixmap *tPix = new Fl_Pixmap(PluginManager::Get()->GetPlugin(ID)->GetIcon()); NewButton->image(tPix->copy(tPix->w(),tPix->h())); delete tPix; string GroupName = PluginManager::Get()->GetPlugin(ID)->GetGroupName(); ToolBox* Tool=NULL; map::iterator ti=m_PluginGroupMap.find(GroupName); if (ti==m_PluginGroupMap.end()) { if (Tool) Tool->GetToolPack()->hide(); Tool = new ToolBox(m_ToolBox,(void*)(this)); m_PluginGroupMap[GroupName]=Tool; Tool->GetToolPack()->hide(); } else { Tool=ti->second; } Tool->AddIcon(NewButton); NewButton->type(0); NewButton->box(FL_PLASTIC_UP_BOX); NewButton->align(FL_ALIGN_INSIDE|FL_ALIGN_TOP); NewButton->color(SpiralSynthModularInfo::GUICOL_Button); NewButton->selection_color(SpiralSynthModularInfo::GUICOL_Tool); string tooltip=*i; // find the first / if there is one, and get rid of everything before and including it unsigned int p = tooltip.find ('/'); if (p < tooltip.length()) tooltip.erase (0, p); // find last . and get rid of everything after and including it p = tooltip.rfind ('.'); unsigned int l = tooltip.length (); if (p < l) tooltip.erase (p, l); m_Canvas->AddPluginName (tooltip, PluginManager::Get()->GetPlugin(ID)->ID); splashtext->label (tooltip.c_str()); Splash->redraw(); NewButton->tooltip (tooltip.c_str()); NewButton->callback((Fl_Callback*)cb_NewDevice,&Numbers[ID]); NewButton->show(); m_DeviceVec.push_back(NewButton); m_ToolBox->redraw(); m_NextPluginButton++; Fl::check(); } } // try to show the SpiralSound group m_CurrentGroup=m_PluginGroupMap.find("SpiralSound"); if (m_CurrentGroup==m_PluginGroupMap.end()) { // can't find it - show the first plugin group m_CurrentGroup=m_PluginGroupMap.begin(); m_CurrentGroup->second->GetToolPack()->show(); m_GroupName->label(m_CurrentGroup->first.c_str()); } m_CurrentGroup->second->GetToolPack()->show(); m_GroupName->label(m_CurrentGroup->first.c_str()); Splash->hide(); delete Splash; } ////////////////////////////////////////////////////////// DeviceGUIInfo SynthModular::BuildDeviceGUIInfo(PluginInfo &PInfo) { DeviceGUIInfo Info; int Height=50; // tweak the size if we have too many ins/outs if (PInfo.NumInputs>4 || PInfo.NumOutputs>4) { if (PInfo.NumInputsGetPlugin(n); if (!Plugin) return NULL; nlw->m_Device=Plugin->CreateInstance(); if (!nlw->m_Device) { return NULL; } nlw->m_Device->SetBlockingCallback(cb_Blocking); nlw->m_Device->SetUpdateCallback(cb_Update); nlw->m_Device->SetParent((void*)this); PluginInfo PInfo = nlw->m_Device->Initialise(&m_Info); SpiralGUIType *temp = nlw->m_Device->CreateGUI(); Fl_Pixmap *Pix = new Fl_Pixmap(Plugin->GetIcon()); nlw->m_PluginID = n; if (temp) { temp->position(x+10,y); } DeviceGUIInfo Info=BuildDeviceGUIInfo(PInfo); Info.XPos = x; //TOOLBOX_WIDTH+(rand()%400); Info.YPos = y; //rand()%400; nlw->m_DeviceGUI = new Fl_DeviceGUI(Info, temp, Pix, nlw->m_Device->IsTerminal()); m_Canvas->add(nlw->m_DeviceGUI); m_Canvas->redraw(); return nlw; } ////////////////////////////////////////////////////////// void SynthModular::AddDevice(int n, int x=-1, int y=-1) { //cerr<<"Adding "<x()+50; y = m_CanvasScroll->y()+50; } DeviceWin* temp = NewDeviceWin(n,x,y); if (temp) { int ID=m_NextID++; //cerr<<"adding device "<m_DeviceGUI->SetID(ID); temp->m_Device->SetUpdateInfoCallback(ID,cb_UpdatePluginInfo); m_DeviceWinMap[ID]=temp; } } ////////////////////////////////////////////////////////// DeviceWin* SynthModular::NewComment(int n, int x=-1, int y=-1) { DeviceWin *nlw = new DeviceWin; if (x==-1) { x = m_CanvasScroll->x()+50; y = m_CanvasScroll->y()+50; } nlw->m_Device=NULL; nlw->m_PluginID = COMMENT_ID; DeviceGUIInfo Info; Info.XPos = x; Info.YPos = y; Info.Width = 50; Info.Height = 20; Info.NumInputs = 0; Info.NumOutputs = 0; Info.Name = ""; nlw->m_DeviceGUI = new Fl_CommentGUI(Info, NULL, NULL); m_Canvas->add(nlw->m_DeviceGUI); m_Canvas->redraw(); return nlw; } ////////////////////////////////////////////////////////// void SynthModular::AddComment(int n) { //cerr<<"Adding "<m_DeviceGUI->SetID(ID); m_DeviceWinMap[ID]=temp; } } ////////////////////////////////////////////////////////// void SynthModular::UpdateHostInfo() { // used to use string streams, but this seems to cause a compiler bug // at the moment, so fall back to using a temporary file //std::stringstream str; fstream ofs("___temp.ssmtmp",ios::out); //str<<*this; ofs<<*this; ClearUp(); // update the settings m_Info.BUFSIZE = SpiralInfo::BUFSIZE; 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; fstream ifs("___temp.ssmtmp",ios::in); //str>>*this; ifs>>*this; system("rm -f ___temp.ssmtmp"); } ////////////////////////////////////////////////////////// // called when a callback output plugin wants to run the audio thread void SynthModular::cb_Update(void* o, bool mode) { m_CallbackUpdateMode=mode; ((SynthModular*)o)->Update(); } // called by a blocking output plugin to notify the engine its ready to // take control of the update timing (so take the brakes off) void SynthModular::cb_Blocking(void* o, bool mode) { m_BlockingOutputPluginIsReady=mode; } ////////////////////////////////////////////////////////// istream &operator>>(istream &s, SynthModular &o) { o.PauseAudio(); string dummy,dummy2; int ver; s>>dummy>>dummy>>dummy>>ver; if (ver>FILE_VERSION) { SpiralInfo::Alert("Bad file, or more recent version."); return s; } if (ver>2) { int MainWinX,MainWinY,MainWinW,MainWinH; int EditWinX,EditWinY,EditWinW,EditWinH; s>>MainWinX>>MainWinY>>MainWinW>>MainWinH; s>>EditWinX>>EditWinY>>EditWinW>>EditWinH; //o.m_MainWindow->resize(MainWinX,MainWinY,MainWinW,MainWinH); //o.m_EditorWindow->resize(EditWinX,EditWinY,EditWinW,EditWinH); } int Num, ID, PluginID, x,y,ps,px,py; s>>dummy>>Num; for(int n=0; n>dummy; s>>ID; s>>dummy2; s>>PluginID; s>>x>>y; string Name; if (ver>3) { // load the device name int size; char Buf[1024]; s>>size; s.ignore(1); s.get(Buf,size+1); Name=Buf; } #ifdef DEBUG_STREAM cerr<1) s>>ps>>px>>py; // Check we're not duplicating an ID if (o.m_DeviceWinMap.find(ID)!=o.m_DeviceWinMap.end()) { SpiralInfo::Alert("Duplicate device ID found in file - aborting load"); return s; } if (PluginID==COMMENT_ID) { DeviceWin* temp = o.NewComment(PluginID, x, y); if (temp) { temp->m_DeviceGUI->SetID(ID); o.m_DeviceWinMap[ID]=temp; ((Fl_CommentGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI))->StreamIn(s); // load the plugin if (o.m_NextID<=ID) o.m_NextID=ID+1; } } else { DeviceWin* temp = o.NewDeviceWin(PluginID, x, y); if (temp) { temp->m_DeviceGUI->SetID(ID); if (ver>3) { // set the titlebars temp->m_DeviceGUI->SetName(Name); } temp->m_Device->SetUpdateInfoCallback(ID,o.cb_UpdatePluginInfo); o.m_DeviceWinMap[ID]=temp; o.m_DeviceWinMap[ID]->m_Device->StreamIn(s); // load the plugin // load external files o.m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(o.m_FilePath+"_files/"); if (ver>1 && o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()) { // set the GUI up with the loaded values // looks messy, but if we do it here, the plugin and it's gui can remain // totally seperated. ((SpiralPluginGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()))-> UpdateValues(o.m_DeviceWinMap[ID]->m_Device); // updates the data in the channel buffers, so the values don't // get overwritten in the next tick. (should maybe be somewhere else) o.m_DeviceWinMap[ID]->m_Device->GetChannelHandler()->FlushChannels(); // position the plugin window in the main window //o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->position(px,py); if (ps) o.m_DeviceWinMap[ID]->m_DeviceGUI->Maximise(); else o.m_DeviceWinMap[ID]->m_DeviceGUI->Minimise(); } if (o.m_NextID<=ID) o.m_NextID=ID+1; } else { // can't really recover if the plugin ID doesn't match a plugin, as // we have no idea how much data in the stream belongs to this plugin SpiralInfo::Alert("Error in stream, can't really recover data from here on."); return s; } } } s>>*o.m_Canvas; o.ResumeAudio(); return s; } ////////////////////////////////////////////////////////// ostream &operator<<(ostream &s, SynthModular &o) { o.PauseAudio(); s<<"SpiralSynthModular File Ver "<2) { s<x()<<" "<y()<<" "; s<w()<<" "<h()<<" "; s<<0<<" "<<0<<" "; s<<0<<" "<<0<::iterator i=o.m_DeviceWinMap.begin(); i!=o.m_DeviceWinMap.end(); i++) { s<first<<" "; // save the id s<<"Plugin "; s<second->m_PluginID<second->m_DeviceGUI->x()<<" "; s<second->m_DeviceGUI->y()<<" "; s<second->m_DeviceGUI->GetName().size()<<" "; s<second->m_DeviceGUI->GetName()<<" "; if (i->second->m_DeviceGUI->GetPluginWindow()) { s<second->m_DeviceGUI->GetPluginWindow()->visible()<<" "; s<second->m_DeviceGUI->GetPluginWindow()->x()<<" "; s<second->m_DeviceGUI->GetPluginWindow()->y()<<" "; } else { s<<0<<" "<<0<<" "<<0; } s<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<second->m_Device && i->second->m_Device->SaveExternalFiles(o.m_FilePath+"_files/")) { ExternalDirUsed=true; } } s<hide(); delete m_SettingsWindow; m_TopWindow->hide(); delete m_TopWindow; o->hide(); } void SynthModular::cb_Close(Fl_Window* o, void* v) {((SynthModular*)(o->user_data()))->cb_Close_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_Load_i(Fl_Button* o, void* v) { if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("Load - Lose changes to current patch?")) { return; } char *fn=fl_file_chooser("Load a patch", "*.ssm", NULL); if (fn && fn!='\0') { ifstream inf(fn); if (inf) { m_FilePath=fn; ClearUp(); inf>>*this; TITLEBAR=LABEL+" "+fn; m_TopWindow->label(TITLEBAR.c_str()); } } } void SynthModular::cb_Load(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_Load_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_Save_i(Fl_Button* o, void* v) { char *fn=fl_file_chooser("Save a patch", "*.ssm", NULL); if (fn && fn!='\0') { ifstream ifl(fn); if (ifl) { if (!Pawfal_YesNo("File [%s] exists, overwrite?",fn)) { return; } } ofstream of(fn); if (of) { m_FilePath=fn; of<<*this; TITLEBAR=LABEL+" "+fn; m_TopWindow->label(TITLEBAR.c_str()); } } } void SynthModular::cb_Save(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_Save_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_New_i(Fl_Button* o, void* v) { if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("New - Lose changes to current patch?")) { return; } m_TopWindow->label(TITLEBAR.c_str()); ClearUp(); } void SynthModular::cb_New(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_New_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_NewDevice_i(Fl_Button* o, void* v) { AddDevice(*((int*)v)); } void SynthModular::cb_NewDevice(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_NewDevice_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_NewDeviceFromMenu_i(Fl_Canvas* o, void* v) { AddDevice(*((int*)v),*((int*)v+1),*((int*)v+2)); } void SynthModular::cb_NewDeviceFromMenu(Fl_Canvas* o, void* v) {((SynthModular*)(o->user_data()))->cb_NewDeviceFromMenu_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_NewComment_i(Fl_Button* o, void* v) { AddComment(-1); } void SynthModular::cb_NewComment(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_NewComment_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_PluginGroupLeft_i(Fl_Button* o, void* v) { m_CurrentGroup->second->GetToolPack()->hide(); m_CurrentGroup++; if (m_CurrentGroup==m_PluginGroupMap.end()) m_CurrentGroup=m_PluginGroupMap.begin(); m_CurrentGroup->second->GetToolPack()->show(); m_GroupName->label(m_CurrentGroup->first.c_str()); } void SynthModular::cb_PluginGroupLeft(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_PluginGroupLeft_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_PluginGroupRight_i(Fl_Button* o, void* v) { m_CurrentGroup->second->GetToolPack()->hide(); m_CurrentGroup++; if (m_CurrentGroup==m_PluginGroupMap.end()) m_CurrentGroup=m_PluginGroupMap.begin(); m_CurrentGroup->second->GetToolPack()->show(); m_GroupName->label(m_CurrentGroup->first.c_str()); } void SynthModular::cb_PluginGroupRight(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_PluginGroupRight_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_Rload_i(Fl_Button* o, void* v) { m_SettingsWindow->show(); /*PluginManager::Get()->UnloadAll(); m_ToolBox->remove(m_ToolPack); delete m_ToolPack; m_ToolPack = new Fl_Pack(5,20,TOOLBOX_WIDTH-10, TOOLBOX_HEIGHT-40,""); m_ToolPack->type(FL_VERTICAL); m_ToolPack->box(FL_NO_BOX); m_ToolPack->color(SpiralSynthModularInfo::GUICOL_Tool); m_ToolPack->user_data((void*)(this)); m_ToolBox->add(m_ToolPack); m_ToolBox->redraw(); LoadPlugins();*/ } void SynthModular::cb_Rload(Fl_Button* o, void* v) {((SynthModular*)(o->parent()->user_data()))->cb_Rload_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_Connection_i(Fl_Canvas* o, void* v) { CanvasWire *Wire; Wire=(CanvasWire*)v; map::iterator si=m_DeviceWinMap.find(Wire->OutputID); if (si==m_DeviceWinMap.end()) { char num[32]; sprintf(num,"%d",Wire->OutputID); SpiralInfo::Alert("Warning: Connection problem - can't find source "+string(num)); return; } map::iterator di=m_DeviceWinMap.find(Wire->InputID); if (di==m_DeviceWinMap.end()) { char num[32]; sprintf(num,"%d",Wire->InputID); SpiralInfo::Alert("Warning: Connection problem - can't find destination "+string(num)); return; } Sample *sample=NULL; if (!si->second->m_Device->GetOutput(Wire->OutputPort,&sample)) { char num[32]; sprintf(num,"%d,%d",Wire->OutputID,Wire->OutputPort); SpiralInfo::Alert("Warning: Connection problem - can't find source output "+string(num)); return; } if (!di->second->m_Device->SetInput(Wire->InputPort,(const Sample*)sample)) { char num[32]; sprintf(num,"%d,%d",Wire->InputID,Wire->InputPort); SpiralInfo::Alert("Warning: Connection problem - can't find source input "+string(num)); return; } } void SynthModular::cb_Connection(Fl_Canvas* o, void* v) {((SynthModular*)(o->user_data()))->cb_Connection_i(o,v);} ////////////////////////////////////////////////////////// inline void SynthModular::cb_Unconnect_i(Fl_Canvas* o, void* v) { CanvasWire *Wire; Wire=(CanvasWire*)v; //cerr<InputID<<" "<InputPort<::iterator di=m_DeviceWinMap.find(Wire->InputID); if (di==m_DeviceWinMap.end()) { //cerr<<"Can't find destination device "<InputID<second->m_Device; if (Plugin && !Plugin->SetInput(Wire->InputPort,NULL)) { cerr<<"Can't find destination device's Input"<user_data()))->cb_Unconnect_i(o,v);} ////////////////////////////////////////////////////////// void SynthModular::cb_UpdatePluginInfo(int ID, void *PInfo) { map::iterator i=m_DeviceWinMap.find(ID); if (i!=m_DeviceWinMap.end()) { DeviceGUIInfo Info=BuildDeviceGUIInfo(*((PluginInfo*)PInfo)); (*i).second->m_DeviceGUI->Setup(Info); (*i).second->m_DeviceGUI->redraw(); } } ////////////////////////////////////////////////////////// void SynthModular::LoadPatch(const char *fn) { ifstream inf(fn); if (inf) { m_FilePath=fn; ClearUp(); inf>>*this; TITLEBAR=LABEL+" "+fn; m_TopWindow->label(TITLEBAR.c_str()); } } //////////////////////////////////////////////////////////