You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1154 lines
31KB

  1. /* SpiralSynthModular
  2. * Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <string>
  19. #include <iostream>
  20. #include <fstream>
  21. #include <sstream>
  22. #include <FL/Fl.H>
  23. #include <FL/Enumerations.H>
  24. #include <FL/fl_file_chooser.h>
  25. #include <FL/Fl_Box.h>
  26. #include <FL/Fl_Tooltip.h>
  27. #include "SpiralSynthModular.h"
  28. #include "SpiralSound/PluginManager.h"
  29. #include "SpiralSound/Plugins/SpiralPluginGUI.h"
  30. #include "GUI/SSM.xpm"
  31. #include "GUI/load.xpm"
  32. #include "GUI/save.xpm"
  33. #include "GUI/new.xpm"
  34. #include "GUI/options.xpm"
  35. #include "GUI/edit.xpm"
  36. #include "GUI/comment.xpm"
  37. #include "GUI/Widgets/PawfalYesNo.h"
  38. //#define DEBUG_PLUGINS
  39. //#define DEBUG_STREAM
  40. const static string LABEL = "SpiralSynthModular "+VER_STRING;
  41. static string TITLEBAR;
  42. static const int FILE_VERSION = 3;
  43. static int Numbers[512];
  44. static const int MAIN_WIDTH = 700;
  45. static const int MAIN_HEIGHT = 300;
  46. static const int SLIDER_WIDTH = 15;
  47. static const int TOOLBOX_HEIGHT = MAIN_HEIGHT-40;
  48. static const int TOOLBOX_WIDTH = 132+SLIDER_WIDTH;
  49. static const int ICON_DEPTH = 3;
  50. static const int COMMENT_ID = -1;
  51. using namespace std;
  52. map<int,DeviceWin*> SynthModular::m_DeviceWinMap;
  53. bool SynthModular::m_CallbackUpdateMode = false;
  54. bool SynthModular::m_BlockingOutputPluginIsReady = false;
  55. //////////////////////////////////////////////////////////
  56. DeviceWin::~DeviceWin()
  57. {
  58. }
  59. //////////////////////////////////////////////////////////
  60. SynthModular::SynthModular():
  61. m_NextID(0),
  62. m_NextPluginButton(1),
  63. m_NextPluginButtonXPos(5),
  64. m_NextPluginButtonYPos(20),
  65. m_PauseAudio(false)
  66. {
  67. m_Info.BUFSIZE = SpiralInfo::BUFSIZE;
  68. m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE;
  69. m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT;
  70. m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE;
  71. m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE;
  72. m_Info.MIDIFILE = SpiralInfo::MIDIFILE;
  73. m_Info.POLY = SpiralInfo::POLY;
  74. //m_Info.GUI_COLOUR = SpiralInfo::GUI_COLOUR;
  75. for (int n=0; n<512; n++) Numbers[n]=n;
  76. m_CH.Register("PauseAudio",&m_PauseAudio);
  77. }
  78. //////////////////////////////////////////////////////////
  79. SynthModular::~SynthModular()
  80. {
  81. ClearUp();
  82. PluginManager::Get()->PackUpAndGoHome();
  83. }
  84. //////////////////////////////////////////////////////////
  85. void SynthModular::ClearUp()
  86. {
  87. PauseAudio();
  88. for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  89. i!=m_DeviceWinMap.end(); i++)
  90. {
  91. if (i->second->m_DeviceGUI->GetPluginWindow())
  92. {
  93. i->second->m_DeviceGUI->GetPluginWindow()->hide();
  94. m_MainWindow->remove(i->second->m_DeviceGUI->GetPluginWindow());
  95. }
  96. // deleted by Canvas::Remove()? seems to cause random crashes
  97. //delete i->second->m_DeviceGUI;
  98. delete i->second->m_Device;
  99. }
  100. m_Canvas->Clear();
  101. m_DeviceWinMap.clear();
  102. m_NextID=0;
  103. ResumeAudio();
  104. }
  105. //////////////////////////////////////////////////////////
  106. void SynthModular::Update()
  107. {
  108. m_CH.UpdateDataNow();
  109. if (m_PauseAudio) return;
  110. // for all the plugins
  111. for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  112. i!=m_DeviceWinMap.end(); i++)
  113. {
  114. if (i->second->m_Device) // if it's not a comment
  115. {
  116. #ifdef DEBUG_PLUGINS
  117. cerr<<"Updating channelhandler of plugin "<<i->second->m_PluginID<<endl;
  118. #endif
  119. // updates the data from the gui thread, if it's not blocking
  120. i->second->m_Device->UpdateChannelHandler();
  121. #ifdef DEBUG_PLUGINS
  122. cerr<<"Finished updating"<<endl;
  123. #endif
  124. // run any commands we've received from the GUI's
  125. i->second->m_Device->ExecuteCommands();
  126. }
  127. }
  128. // run the plugins (only ones connected to anything)
  129. list<int> ExecutionOrder = m_Canvas->GetGraph()->GetSortedList();
  130. for (list<int>::reverse_iterator i=ExecutionOrder.rbegin();
  131. i!=ExecutionOrder.rend(); i++)
  132. {
  133. // use the graphsort order to remove internal latency
  134. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(*i);
  135. if (di!=m_DeviceWinMap.end() && di->second->m_Device)
  136. {
  137. #ifdef DEBUG_PLUGINS
  138. cerr<<"Executing plugin "<<di->second->m_PluginID<<endl;
  139. #endif
  140. di->second->m_Device->Execute();
  141. #ifdef DEBUG_PLUGINS
  142. cerr<<"Finished executing"<<endl;
  143. #endif
  144. }
  145. }
  146. }
  147. //////////////////////////////////////////////////////////
  148. void SynthModular::UpdatePluginGUIs()
  149. {
  150. // see if any need deleting
  151. for (map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  152. i!=m_DeviceWinMap.end(); i++)
  153. {
  154. if (i->second->m_DeviceGUI->GetPluginWindow())
  155. {
  156. SpiralPluginGUI *GUI=(SpiralPluginGUI *)i->second->m_DeviceGUI->GetPluginWindow();
  157. GUI->Update();
  158. }
  159. if (i->second->m_DeviceGUI->Killed())
  160. {
  161. PauseAudio();
  162. if (i->second->m_Device)
  163. {
  164. delete i->second->m_Device;
  165. }
  166. if (i->second->m_DeviceGUI->GetPluginWindow())
  167. {
  168. i->second->m_DeviceGUI->GetPluginWindow()->hide();
  169. m_MainWindow->remove(i->second->m_DeviceGUI->GetPluginWindow());
  170. }
  171. i->second->m_DeviceGUI->Clear();
  172. m_Canvas->RemoveDevice(i->second->m_DeviceGUI);
  173. // deleted by Canvas::Remove()? seems to cause random crashes
  174. //delete i->second->m_DeviceGUI;
  175. m_DeviceWinMap.erase(i);
  176. ResumeAudio();
  177. break;
  178. }
  179. }
  180. m_Canvas->Poll();
  181. }
  182. //////////////////////////////////////////////////////////
  183. SpiralWindowType *SynthModular::CreateWindow()
  184. {
  185. int xoff=0, yoff=10, but=64, gap=MAIN_HEIGHT/4, n=0;
  186. m_TopWindow = new SpiralWindowType(MAIN_WIDTH, MAIN_HEIGHT*2, LABEL.c_str());
  187. m_TopWindow->resizable(m_TopWindow);
  188. m_TopTile = new Fl_Tile(0,0,MAIN_WIDTH, MAIN_HEIGHT*2, "");
  189. m_TopWindow->add(m_TopTile);
  190. m_MainWindow = new Fl_Tile(0,0,MAIN_WIDTH, MAIN_HEIGHT, "");
  191. m_MainWindow->color(SpiralSynthModularInfo::GUICOL_Canvas);
  192. //m_MainWindow->callback((Fl_Callback*)cb_Close);
  193. m_MainWindow->user_data((void*)(this));
  194. m_TopTile->add(m_MainWindow);
  195. m_MainButtons = new Fl_Group(0, 0, but, MAIN_HEIGHT, "");
  196. m_MainButtons->type(1);
  197. m_MainButtons->color(SpiralSynthModularInfo::GUICOL_Tool);
  198. m_MainButtons->box(FL_FLAT_BOX);
  199. m_MainButtons->user_data((void*)(this));
  200. m_MainWindow->add(m_MainButtons);
  201. m_AppScroll = new Fl_Scroll(but, 0, MAIN_WIDTH-but, MAIN_HEIGHT, "");
  202. m_AppScroll->scrollbar.align(FL_ALIGN_RIGHT);
  203. m_MainWindow->add(m_AppScroll);
  204. //m_MainWindow->resizable(m_AppScroll);
  205. m_AppGroup = new Fl_Group(-5000, -5000, 10000, 10000, "");
  206. m_AppGroup->type(1);
  207. m_AppGroup->box(FL_FLAT_BOX);
  208. m_AppGroup->labeltype(FL_ENGRAVED_LABEL);
  209. m_AppGroup->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  210. m_AppGroup->color(SpiralSynthModularInfo::GUICOL_Canvas);
  211. m_AppScroll->add(m_AppGroup);
  212. m_Load = new Fl_Button(xoff, 5+yoff, but, but, "");
  213. m_Load->box(FL_NO_BOX);
  214. Fl_Pixmap *tPix = new Fl_Pixmap(load_xpm);
  215. m_Load->image(tPix->copy(tPix->w(),tPix->h()));
  216. m_Load->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  217. m_Load->tooltip("Load a patch file");
  218. m_Load->callback((Fl_Callback*)cb_Load);
  219. m_MainButtons->add(m_Load);
  220. n++;
  221. m_Save = new Fl_Button(xoff, n*gap+yoff, but, but, "");
  222. m_Save->box(FL_NO_BOX);
  223. tPix = new Fl_Pixmap(save_xpm);
  224. m_Save->image(tPix->copy(tPix->w(),tPix->h()));
  225. delete tPix;
  226. m_Save->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  227. m_Save->tooltip("Save a patch file");
  228. m_Save->callback((Fl_Callback*)cb_Save);
  229. m_MainButtons->add(m_Save);
  230. n++;
  231. m_New = new Fl_Button(xoff, n*gap+yoff, but, but, "");
  232. m_New->box(FL_NO_BOX);
  233. tPix = new Fl_Pixmap(new_xpm);
  234. m_New->image(tPix->copy(tPix->w(),tPix->h()));
  235. delete tPix;
  236. m_New->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  237. m_New->tooltip("New patch");
  238. m_New->callback((Fl_Callback*)cb_New);
  239. m_MainButtons->add(m_New);
  240. n++;
  241. m_Options = new Fl_Button(xoff, n*gap+yoff, but, but, "");
  242. m_Options->box(FL_NO_BOX);
  243. tPix = new Fl_Pixmap(options_xpm);
  244. m_Options->image(tPix->copy(tPix->w(),tPix->h()));
  245. delete tPix;
  246. m_Options->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  247. m_Options->tooltip("Options");
  248. m_Options->callback((Fl_Callback*)cb_Rload);
  249. m_MainButtons->add(m_Options);
  250. n++;
  251. /*m_OpenEditor = new Fl_Button(5+xoff, n*gap+yoff, but, but, "");
  252. m_OpenEditor->box(FL_NO_BOX);
  253. tPix = new Fl_Pixmap(edit_xpm);
  254. m_OpenEditor->image(tPix->copy(tPix->w(),tPix->h()));
  255. delete tPix;
  256. m_OpenEditor->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  257. m_OpenEditor->tooltip("Open/Close Editor");
  258. m_OpenEditor->callback((Fl_Callback*)cb_OpenEditor);
  259. m_MainButtons->add(m_OpenEditor);
  260. n++;*/
  261. /////////////////
  262. m_EditorWindow = new Fl_Tile(0,MAIN_HEIGHT,MAIN_WIDTH, MAIN_HEIGHT, "");
  263. m_EditorWindow->color(SpiralSynthModularInfo::GUICOL_Tool);
  264. m_TopTile->add(m_EditorWindow);
  265. int edy = MAIN_HEIGHT;
  266. Fl_Group *Left = new Fl_Group(0,MAIN_HEIGHT,TOOLBOX_WIDTH,MAIN_HEIGHT);
  267. m_EditorWindow->add(Left);
  268. m_EditorWindow->resizable(Left);
  269. m_ToolBox = new Fl_Scroll(0,0+edy,TOOLBOX_WIDTH, TOOLBOX_HEIGHT, "");
  270. m_ToolBox->type(Fl_Scroll::VERTICAL_ALWAYS);
  271. m_ToolBox->box(FL_FLAT_BOX);
  272. m_ToolBox->labeltype(FL_ENGRAVED_LABEL);
  273. m_ToolBox->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  274. m_ToolBox->scrollbar.align(FL_ALIGN_LEFT);
  275. m_ToolBox->color(SpiralSynthModularInfo::GUICOL_Tool);
  276. m_ToolBox->user_data((void*)(this));
  277. Left->add(m_ToolBox);
  278. // m_EditorWindow->resizable(m_ToolBox);
  279. m_ToolPack = new Fl_Pack(SLIDER_WIDTH+5,5+edy,TOOLBOX_WIDTH-10, TOOLBOX_HEIGHT-40,"");
  280. m_ToolPack->type(FL_VERTICAL);
  281. m_ToolPack->box(FL_NO_BOX);
  282. m_ToolPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  283. m_ToolPack->user_data((void*)(this));
  284. m_ToolBox->add(m_ToolPack);
  285. //m_EditorWindow->resizable(m_ToolBox);
  286. xoff=0; yoff=MAIN_HEIGHT+TOOLBOX_HEIGHT;
  287. m_Buttons = new Fl_Group(xoff, yoff, TOOLBOX_WIDTH, MAIN_HEIGHT*2-TOOLBOX_HEIGHT, "");
  288. m_Buttons->type(1);
  289. m_Buttons->color(SpiralSynthModularInfo::GUICOL_Tool);
  290. m_Buttons->box(FL_FLAT_BOX);
  291. m_Buttons->user_data((void*)(this));
  292. Left->add(m_Buttons);
  293. m_CanvasScroll = new Fl_Scroll(TOOLBOX_WIDTH, 0+edy, MAIN_WIDTH-TOOLBOX_WIDTH, MAIN_HEIGHT, "");
  294. m_EditorWindow->add(m_CanvasScroll);
  295. m_EditorWindow->resizable(m_CanvasScroll);
  296. m_Canvas = new Fl_Canvas(-5000, -5000, 10000, 10000, "");
  297. m_Canvas->type(1);
  298. m_Canvas->box(FL_FLAT_BOX);
  299. m_Canvas->labeltype(FL_ENGRAVED_LABEL);
  300. m_Canvas->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  301. m_Canvas->color(SpiralSynthModularInfo::GUICOL_Canvas);
  302. m_Canvas->user_data((void*)(this));
  303. m_Canvas->SetConnectionCallback((Fl_Callback*)cb_Connection);
  304. m_Canvas->SetUnconnectCallback((Fl_Callback*)cb_Unconnect);
  305. m_Canvas->SetAddDeviceCallback((Fl_Callback*)cb_NewDeviceFromMenu);
  306. m_CanvasScroll->add(m_Canvas);
  307. m_NewComment = new Fl_Button(TOOLBOX_WIDTH/2-16, MAIN_HEIGHT*2-25, 40, 40, "");
  308. m_NewComment->box(FL_NO_BOX);
  309. m_Canvas->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  310. tPix = new Fl_Pixmap(comment_xpm);
  311. m_NewComment->image(tPix->copy(tPix->w(),tPix->h()));
  312. delete tPix;
  313. m_NewComment->color(SpiralSynthModularInfo::GUICOL_Button);
  314. m_NewComment->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  315. m_NewComment->type(0);
  316. m_NewComment->shortcut(FL_F + 10);
  317. m_NewComment->tooltip("New comment in editor");
  318. m_NewComment->user_data((void*)(this));
  319. m_NewComment->callback((Fl_Callback*)cb_NewComment);
  320. m_Buttons->add(m_NewComment);
  321. m_SettingsWindow = new SettingsWindow;
  322. m_SettingsWindow->RegisterApp(this);
  323. return m_TopWindow;
  324. }
  325. //////////////////////////////////////////////////////////
  326. void SynthModular::LoadPlugins(string pluginPath)
  327. {
  328. int Width = 40;
  329. int Height = 40;
  330. int SWidth = 256;
  331. int SHeight = 256;
  332. Fl_Pixmap pic(SSM_xpm);
  333. Fl_Double_Window* Splash = new Fl_Double_Window((Fl::w()/2)-(SWidth/2),
  334. (Fl::h()/2)-(SHeight/2),
  335. SWidth,SHeight,"SSM");
  336. Splash->border(0);
  337. Fl_Box* pbut = new Fl_Box(0,8,SWidth,SHeight,"");
  338. pbut->box(FL_NO_BOX);
  339. pic.label(pbut);
  340. Fl_Box *splashtext = new Fl_Box(5,SHeight-20,200,20,"Loading...");
  341. splashtext->labelsize(10);
  342. splashtext->box(FL_NO_BOX);
  343. splashtext->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
  344. Splash->add(pbut);
  345. Splash->add(splashtext);
  346. Splash->show();
  347. int ID=-1;
  348. int Icon=0;
  349. Fl_Pack *IconPack;
  350. IconPack = new Fl_Pack(0,0,TOOLBOX_WIDTH-SLIDER_WIDTH,Height,"");
  351. IconPack->type(FL_HORIZONTAL);
  352. IconPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  353. IconPack->user_data((void*)(this));
  354. m_ToolPack->add(IconPack);
  355. for (vector<string>::iterator i=SpiralSynthModularInfo::PLUGINVEC.begin();
  356. i!=SpiralSynthModularInfo::PLUGINVEC.end(); i++)
  357. {
  358. string Fullpath;
  359. if (pluginPath=="")
  360. {
  361. Fullpath=SpiralSynthModularInfo::PLUGIN_PATH+*i;
  362. }
  363. else
  364. {
  365. Fullpath=pluginPath+*"/"+*i;
  366. }
  367. ID=PluginManager::Get()->LoadPlugin(Fullpath.c_str());
  368. if (ID!=PluginError)
  369. {
  370. #ifdef DEBUG_PLUGINS
  371. cerr<<"Plugin ["<<*i<<"] = "<<ID<<endl;
  372. #endif
  373. if (Icon>=ICON_DEPTH)
  374. {
  375. Icon=0;
  376. IconPack = new Fl_Pack(0,0,TOOLBOX_WIDTH-SLIDER_WIDTH,Height,"");
  377. IconPack->type(FL_HORIZONTAL);
  378. IconPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  379. IconPack->user_data((void*)(this));
  380. m_ToolPack->add(IconPack);
  381. }
  382. Fl_Button *NewButton = new Fl_Button(0,0,Width,Height,"");
  383. NewButton->labelsize(10);
  384. Fl_Pixmap *tPix = new Fl_Pixmap(PluginManager::Get()->GetPlugin(ID)->GetIcon());
  385. NewButton->image(tPix->copy(tPix->w(),tPix->h()));
  386. delete tPix;
  387. IconPack->add(NewButton);
  388. NewButton->type(0);
  389. NewButton->box(FL_PLASTIC_UP_BOX);
  390. NewButton->align(FL_ALIGN_INSIDE|FL_ALIGN_TOP);
  391. NewButton->color(SpiralSynthModularInfo::GUICOL_Button);
  392. NewButton->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  393. string tooltip=*i;
  394. // find the first / if there is one, and get rid of everything before and including it
  395. unsigned int p = tooltip.find ('/');
  396. if (p < tooltip.length()) tooltip.erase (0, p);
  397. // find last . and get rid of everything after and including it
  398. p = tooltip.rfind ('.');
  399. unsigned int l = tooltip.length ();
  400. if (p < l) tooltip.erase (p, l);
  401. m_Canvas->AddPluginName (tooltip, PluginManager::Get()->GetPlugin(ID)->ID);
  402. splashtext->label (tooltip.c_str());
  403. Splash->redraw();
  404. NewButton->tooltip (tooltip.c_str());
  405. NewButton->callback((Fl_Callback*)cb_NewDevice,&Numbers[ID]);
  406. NewButton->show();
  407. m_DeviceVec.push_back(NewButton);
  408. Icon++;
  409. m_ToolBox->redraw();
  410. m_NextPluginButton++;
  411. Fl::check();
  412. }
  413. }
  414. Splash->hide();
  415. delete Splash;
  416. }
  417. //////////////////////////////////////////////////////////
  418. DeviceGUIInfo SynthModular::BuildDeviceGUIInfo(PluginInfo &PInfo)
  419. {
  420. DeviceGUIInfo Info;
  421. int Height=50;
  422. // tweak the size if we have too many ins/outs
  423. if (PInfo.NumInputs>4 || PInfo.NumOutputs>4)
  424. {
  425. if (PInfo.NumInputs<PInfo.NumOutputs)
  426. {
  427. Height=PInfo.NumOutputs*10+5;
  428. }
  429. else
  430. {
  431. Height=PInfo.NumInputs*10+5;
  432. }
  433. }
  434. // Make the guiinfo struct
  435. Info.XPos = 0;
  436. Info.YPos = 0;
  437. Info.Width = 40;
  438. Info.Height = Height;
  439. Info.NumInputs = PInfo.NumInputs;
  440. Info.NumOutputs = PInfo.NumOutputs;
  441. Info.Name = PInfo.Name;
  442. Info.PortTips = PInfo.PortTips;
  443. Info.PortTypes = PInfo.PortTypes;
  444. return Info;
  445. }
  446. //////////////////////////////////////////////////////////
  447. DeviceWin* SynthModular::NewDeviceWin(int n, int x, int y)
  448. {
  449. DeviceWin *nlw = new DeviceWin;
  450. const HostsideInfo* Plugin=PluginManager::Get()->GetPlugin(n);
  451. if (!Plugin) return NULL;
  452. nlw->m_Device=Plugin->CreateInstance();
  453. if (!nlw->m_Device)
  454. {
  455. return NULL;
  456. }
  457. nlw->m_Device->SetBlockingCallback(cb_Blocking);
  458. nlw->m_Device->SetUpdateCallback(cb_Update);
  459. nlw->m_Device->SetParent((void*)this);
  460. PluginInfo PInfo = nlw->m_Device->Initialise(&m_Info);
  461. SpiralGUIType *temp = nlw->m_Device->CreateGUI();
  462. Fl_Pixmap *Pix = new Fl_Pixmap(Plugin->GetIcon());
  463. nlw->m_PluginID = n;
  464. if (temp)
  465. {
  466. temp->hide();
  467. temp->position(200,50);
  468. m_AppGroup->add(temp);
  469. m_MainWindow->redraw();
  470. }
  471. DeviceGUIInfo Info=BuildDeviceGUIInfo(PInfo);
  472. Info.XPos = x; //TOOLBOX_WIDTH+(rand()%400);
  473. Info.YPos = y; //rand()%400;
  474. nlw->m_DeviceGUI = new Fl_DeviceGUI(Info, temp, Pix);
  475. m_Canvas->add(nlw->m_DeviceGUI);
  476. m_Canvas->redraw();
  477. return nlw;
  478. }
  479. //////////////////////////////////////////////////////////
  480. void SynthModular::AddDevice(int n, int x=-1, int y=-1)
  481. {
  482. //cerr<<"Adding "<<m_NextID<<endl;
  483. if (x==-1)
  484. {
  485. x = m_CanvasScroll->x()+50;
  486. y = m_CanvasScroll->y()+50;
  487. }
  488. DeviceWin* temp = NewDeviceWin(n,x,y);
  489. if (temp)
  490. {
  491. int ID=m_NextID++;
  492. //cerr<<"adding device "<<ID<<endl;
  493. temp->m_DeviceGUI->SetID(ID);
  494. temp->m_Device->SetUpdateInfoCallback(ID,cb_UpdatePluginInfo);
  495. m_DeviceWinMap[ID]=temp;
  496. }
  497. }
  498. //////////////////////////////////////////////////////////
  499. DeviceWin* SynthModular::NewComment(int n, int x=-1, int y=-1)
  500. {
  501. DeviceWin *nlw = new DeviceWin;
  502. if (x==-1)
  503. {
  504. x = m_CanvasScroll->x()+50;
  505. y = m_CanvasScroll->y()+50;
  506. }
  507. nlw->m_Device=NULL;
  508. nlw->m_PluginID = COMMENT_ID;
  509. DeviceGUIInfo Info;
  510. Info.XPos = x;
  511. Info.YPos = y;
  512. Info.Width = 50;
  513. Info.Height = 20;
  514. Info.NumInputs = 0;
  515. Info.NumOutputs = 0;
  516. Info.Name = "";
  517. nlw->m_DeviceGUI = new Fl_CommentGUI(Info, NULL, NULL);
  518. m_Canvas->add(nlw->m_DeviceGUI);
  519. m_Canvas->redraw();
  520. return nlw;
  521. }
  522. //////////////////////////////////////////////////////////
  523. void SynthModular::AddComment(int n)
  524. {
  525. //cerr<<"Adding "<<m_NextID<<endl;
  526. DeviceWin* temp = NewComment(n);
  527. if (temp)
  528. {
  529. int ID=m_NextID++;
  530. //cerr<<"adding comment "<<ID<<endl;
  531. temp->m_DeviceGUI->SetID(ID);
  532. m_DeviceWinMap[ID]=temp;
  533. }
  534. }
  535. //////////////////////////////////////////////////////////
  536. void SynthModular::UpdateHostInfo()
  537. {
  538. // used to use string streams, but this seems to cause a compiler bug
  539. // at the moment, so fall back to using a temporary file
  540. //std::stringstream str;
  541. fstream ofs("___temp.ssmtmp",ios::out);
  542. //str<<*this;
  543. ofs<<*this;
  544. ClearUp();
  545. // update the settings
  546. m_Info.BUFSIZE = SpiralInfo::BUFSIZE;
  547. m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE;
  548. m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT;
  549. m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE;
  550. m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE;
  551. m_Info.MIDIFILE = SpiralInfo::MIDIFILE;
  552. m_Info.POLY = SpiralInfo::POLY;
  553. fstream ifs("___temp.ssmtmp",ios::in);
  554. //str>>*this;
  555. ifs>>*this;
  556. system("rm -f ___temp.ssmtmp");
  557. }
  558. //////////////////////////////////////////////////////////
  559. // called when a callback output plugin wants to run the audio thread
  560. void SynthModular::cb_Update(void* o, bool mode)
  561. {
  562. m_CallbackUpdateMode=mode;
  563. ((SynthModular*)o)->Update();
  564. }
  565. // called by a blocking output plugin to notify the engine its ready to
  566. // take control of the update timing (so take the brakes off)
  567. void SynthModular::cb_Blocking(void* o, bool mode)
  568. {
  569. m_BlockingOutputPluginIsReady=mode;
  570. }
  571. //////////////////////////////////////////////////////////
  572. istream &operator>>(istream &s, SynthModular &o)
  573. {
  574. o.PauseAudio();
  575. string dummy,dummy2;
  576. int ver;
  577. s>>dummy>>dummy>>dummy>>ver;
  578. if (ver>FILE_VERSION)
  579. {
  580. SpiralInfo::Alert("Bad file, or more recent version.");
  581. return s;
  582. }
  583. if (ver>2)
  584. {
  585. int MainWinX,MainWinY,MainWinW,MainWinH;
  586. int EditWinX,EditWinY,EditWinW,EditWinH;
  587. s>>MainWinX>>MainWinY>>MainWinW>>MainWinH;
  588. s>>EditWinX>>EditWinY>>EditWinW>>EditWinH;
  589. //o.m_MainWindow->resize(MainWinX,MainWinY,MainWinW,MainWinH);
  590. //o.m_EditorWindow->resize(EditWinX,EditWinY,EditWinW,EditWinH);
  591. }
  592. int Num, ID, PluginID, x,y,ps,px,py;
  593. s>>dummy>>Num;
  594. for(int n=0; n<Num; n++)
  595. {
  596. #ifdef DEBUG_STREAM
  597. cerr<<"Loading Device "<<n<<endl;
  598. #endif
  599. s>>dummy;
  600. s>>ID;
  601. s>>dummy2;
  602. s>>PluginID;
  603. s>>x>>y;
  604. #ifdef DEBUG_STREAM
  605. cerr<<dummy<<" "<<ID<<" "<<dummy2<<" "<<PluginID<<" "<<x<<" "<<y<<endl;
  606. #endif
  607. if (ver>1) s>>ps>>px>>py;
  608. // Check we're not duplicating an ID
  609. if (o.m_DeviceWinMap.find(ID)!=o.m_DeviceWinMap.end())
  610. {
  611. SpiralInfo::Alert("Duplicate device ID found in file - aborting load");
  612. return s;
  613. }
  614. if (PluginID==COMMENT_ID)
  615. {
  616. DeviceWin* temp = o.NewComment(PluginID, x, y);
  617. if (temp)
  618. {
  619. temp->m_DeviceGUI->SetID(ID);
  620. o.m_DeviceWinMap[ID]=temp;
  621. ((Fl_CommentGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI))->StreamIn(s); // load the plugin
  622. if (o.m_NextID<=ID) o.m_NextID=ID+1;
  623. }
  624. }
  625. else
  626. {
  627. DeviceWin* temp = o.NewDeviceWin(PluginID, x, y);
  628. if (temp)
  629. {
  630. temp->m_DeviceGUI->SetID(ID);
  631. temp->m_Device->SetUpdateInfoCallback(ID,o.cb_UpdatePluginInfo);
  632. o.m_DeviceWinMap[ID]=temp;
  633. o.m_DeviceWinMap[ID]->m_Device->StreamIn(s); // load the plugin
  634. if (ver>1 && o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow())
  635. {
  636. // set the GUI up with the loaded values
  637. // looks messy, but if we do it here, the plugin and it's gui can remain
  638. // totally seperated.
  639. ((SpiralPluginGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()))->
  640. UpdateValues(o.m_DeviceWinMap[ID]->m_Device);
  641. // updates the data in the channel buffers, so the values don't
  642. // get overwritten in the next tick. (should maybe be somewhere else)
  643. o.m_DeviceWinMap[ID]->m_Device->GetChannelHandler()->FlushChannels();
  644. // position the plugin window in the main window
  645. o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->position(px,py);
  646. if (ps) o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->show();
  647. else o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->hide();
  648. // load external files
  649. o.m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(o.m_FilePath+"_files/");
  650. }
  651. if (o.m_NextID<=ID) o.m_NextID=ID+1;
  652. }
  653. else
  654. {
  655. // can't really recover if the plugin ID doesn't match a plugin, as
  656. // we have no idea how much data in the stream belongs to this plugin
  657. SpiralInfo::Alert("Error in stream, can't really recover data from here on.");
  658. return s;
  659. }
  660. }
  661. }
  662. s>>*o.m_Canvas;
  663. o.ResumeAudio();
  664. return s;
  665. }
  666. //////////////////////////////////////////////////////////
  667. ostream &operator<<(ostream &s, SynthModular &o)
  668. {
  669. o.PauseAudio();
  670. s<<"SpiralSynthModular File Ver "<<FILE_VERSION<<endl;
  671. // make external files dir
  672. bool ExternalDirUsed=false;
  673. string command("mkdir "+o.m_FilePath+"_files");
  674. system(command.c_str());
  675. if (FILE_VERSION>2)
  676. {
  677. s<<o.m_MainWindow->x()<<" "<<o.m_MainWindow->y()<<" ";
  678. s<<o.m_MainWindow->w()<<" "<<o.m_MainWindow->h()<<" ";
  679. s<<o.m_EditorWindow->x()<<" "<<o.m_EditorWindow->y()<<" ";
  680. s<<o.m_EditorWindow->w()<<" "<<o.m_EditorWindow->h()<<endl;
  681. }
  682. // save out the SynthModular
  683. s<<"SectionList"<<endl;
  684. s<<o.m_DeviceWinMap.size()<<endl;
  685. for(map<int,DeviceWin*>::iterator i=o.m_DeviceWinMap.begin();
  686. i!=o.m_DeviceWinMap.end(); i++)
  687. {
  688. s<<endl;
  689. s<<"Device ";
  690. s<<i->first<<" "; // save the id
  691. s<<"Plugin ";
  692. s<<i->second->m_PluginID<<endl;
  693. s<<i->second->m_DeviceGUI->x()<<" ";
  694. s<<i->second->m_DeviceGUI->y()<<" ";
  695. if (i->second->m_DeviceGUI->GetPluginWindow())
  696. {
  697. s<<i->second->m_DeviceGUI->GetPluginWindow()->visible()<<" ";
  698. s<<i->second->m_DeviceGUI->GetPluginWindow()->x()<<" ";
  699. s<<i->second->m_DeviceGUI->GetPluginWindow()->y()<<" ";
  700. }
  701. else
  702. {
  703. s<<0<<" "<<0<<" "<<0;
  704. }
  705. s<<endl;
  706. if (i->second->m_PluginID==COMMENT_ID)
  707. {
  708. // save the comment gui
  709. ((Fl_CommentGUI*)(i->second->m_DeviceGUI))->StreamOut(s);
  710. }
  711. else
  712. {
  713. // save the plugin
  714. i->second->m_Device->StreamOut(s);
  715. }
  716. s<<endl;
  717. // save external files
  718. if (i->second->m_Device && i->second->m_Device->SaveExternalFiles(o.m_FilePath+"_files/"))
  719. {
  720. ExternalDirUsed=true;
  721. }
  722. }
  723. s<<endl<<*o.m_Canvas<<endl;
  724. // remove it if it wasn't used
  725. if (!ExternalDirUsed)
  726. {
  727. // i guess rmdir won't work if there is something in the dir
  728. // anyway, but best to be on the safe side. (could do rm -rf) :)
  729. string command("rmdir "+o.m_FilePath+"_files");
  730. system(command.c_str());
  731. }
  732. o.ResumeAudio();
  733. return s;
  734. }
  735. //////////////////////////////////////////////////////////
  736. inline void SynthModular::cb_Close_i(Fl_Window* o, void* v)
  737. {
  738. m_SettingsWindow->hide();
  739. delete m_SettingsWindow;
  740. m_EditorWindow->hide();
  741. delete m_EditorWindow;
  742. o->hide();
  743. }
  744. void SynthModular::cb_Close(Fl_Window* o, void* v)
  745. {((SynthModular*)(o->user_data()))->cb_Close_i(o,v);}
  746. //////////////////////////////////////////////////////////
  747. inline void SynthModular::cb_Load_i(Fl_Button* o, void* v)
  748. {
  749. if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("Load - Lose changes to current patch?"))
  750. {
  751. return;
  752. }
  753. char *fn=fl_file_chooser("Load a patch", "*.ssm", NULL);
  754. if (fn && fn!='\0')
  755. {
  756. ifstream inf(fn);
  757. if (inf)
  758. {
  759. m_FilePath=fn;
  760. ClearUp();
  761. inf>>*this;
  762. TITLEBAR=LABEL+" "+fn;
  763. m_TopWindow->label(TITLEBAR.c_str());
  764. }
  765. }
  766. }
  767. void SynthModular::cb_Load(Fl_Button* o, void* v)
  768. {((SynthModular*)(o->parent()->user_data()))->cb_Load_i(o,v);}
  769. //////////////////////////////////////////////////////////
  770. inline void SynthModular::cb_Save_i(Fl_Button* o, void* v)
  771. {
  772. char *fn=fl_file_chooser("Save a patch", "*.ssm", NULL);
  773. if (fn && fn!='\0')
  774. {
  775. ifstream ifl(fn);
  776. if (ifl)
  777. {
  778. if (!Pawfal_YesNo("File [%s] exists, overwrite?",fn))
  779. {
  780. return;
  781. }
  782. }
  783. ofstream of(fn);
  784. if (of)
  785. {
  786. m_FilePath=fn;
  787. of<<*this;
  788. TITLEBAR=LABEL+" "+fn;
  789. m_TopWindow->label(TITLEBAR.c_str());
  790. }
  791. }
  792. }
  793. void SynthModular::cb_Save(Fl_Button* o, void* v)
  794. {((SynthModular*)(o->parent()->user_data()))->cb_Save_i(o,v);}
  795. //////////////////////////////////////////////////////////
  796. inline void SynthModular::cb_New_i(Fl_Button* o, void* v)
  797. {
  798. if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("New - Lose changes to current patch?"))
  799. {
  800. return;
  801. }
  802. m_TopWindow->label(TITLEBAR.c_str());
  803. ClearUp();
  804. }
  805. void SynthModular::cb_New(Fl_Button* o, void* v)
  806. {((SynthModular*)(o->parent()->user_data()))->cb_New_i(o,v);}
  807. //////////////////////////////////////////////////////////
  808. inline void SynthModular::cb_NewDevice_i(Fl_Button* o, void* v)
  809. {
  810. AddDevice(*((int*)v));
  811. }
  812. void SynthModular::cb_NewDevice(Fl_Button* o, void* v)
  813. {((SynthModular*)(o->parent()->user_data()))->cb_NewDevice_i(o,v);}
  814. //////////////////////////////////////////////////////////
  815. inline void SynthModular::cb_NewDeviceFromMenu_i(Fl_Canvas* o, void* v)
  816. {
  817. AddDevice(*((int*)v),*((int*)v+1),*((int*)v+2));
  818. }
  819. void SynthModular::cb_NewDeviceFromMenu(Fl_Canvas* o, void* v)
  820. {((SynthModular*)(o->user_data()))->cb_NewDeviceFromMenu_i(o,v);}
  821. //////////////////////////////////////////////////////////
  822. inline void SynthModular::cb_NewComment_i(Fl_Button* o, void* v)
  823. {
  824. AddComment(-1);
  825. }
  826. void SynthModular::cb_NewComment(Fl_Button* o, void* v)
  827. {((SynthModular*)(o->user_data()))->cb_NewComment_i(o,v);}
  828. //////////////////////////////////////////////////////////
  829. inline void SynthModular::cb_OpenEditor_i(Fl_Button* o, void* v)
  830. {
  831. //if (m_EditorWindow->shown()) m_EditorWindow->hide();
  832. //else m_EditorWindow->show();
  833. }
  834. void SynthModular::cb_OpenEditor(Fl_Button* o, void* v)
  835. {((SynthModular*)(o->parent()->user_data()))->cb_OpenEditor_i(o,v);}
  836. //////////////////////////////////////////////////////////
  837. inline void SynthModular::cb_Rload_i(Fl_Button* o, void* v)
  838. {
  839. m_SettingsWindow->show();
  840. /*PluginManager::Get()->UnloadAll();
  841. m_ToolBox->remove(m_ToolPack);
  842. delete m_ToolPack;
  843. m_ToolPack = new Fl_Pack(5,20,TOOLBOX_WIDTH-10, TOOLBOX_HEIGHT-40,"");
  844. m_ToolPack->type(FL_VERTICAL);
  845. m_ToolPack->box(FL_NO_BOX);
  846. m_ToolPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  847. m_ToolPack->user_data((void*)(this));
  848. m_ToolBox->add(m_ToolPack);
  849. m_ToolBox->redraw();
  850. LoadPlugins();*/
  851. }
  852. void SynthModular::cb_Rload(Fl_Button* o, void* v)
  853. {((SynthModular*)(o->parent()->user_data()))->cb_Rload_i(o,v);}
  854. //////////////////////////////////////////////////////////
  855. inline void SynthModular::cb_Connection_i(Fl_Canvas* o, void* v)
  856. {
  857. CanvasWire *Wire;
  858. Wire=(CanvasWire*)v;
  859. map<int,DeviceWin*>::iterator si=m_DeviceWinMap.find(Wire->OutputID);
  860. if (si==m_DeviceWinMap.end())
  861. {
  862. char num[32];
  863. sprintf(num,"%d",Wire->OutputID);
  864. SpiralInfo::Alert("Warning: Connection problem - can't find source "+string(num));
  865. return;
  866. }
  867. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(Wire->InputID);
  868. if (di==m_DeviceWinMap.end())
  869. {
  870. char num[32];
  871. sprintf(num,"%d",Wire->InputID);
  872. SpiralInfo::Alert("Warning: Connection problem - can't find destination "+string(num));
  873. return;
  874. }
  875. Sample *sample=NULL;
  876. if (!si->second->m_Device->GetOutput(Wire->OutputPort,&sample))
  877. {
  878. char num[32];
  879. sprintf(num,"%d,%d",Wire->OutputID,Wire->OutputPort);
  880. SpiralInfo::Alert("Warning: Connection problem - can't find source output "+string(num));
  881. return;
  882. }
  883. if (!di->second->m_Device->SetInput(Wire->InputPort,(const Sample*)sample))
  884. {
  885. char num[32];
  886. sprintf(num,"%d,%d",Wire->InputID,Wire->InputPort);
  887. SpiralInfo::Alert("Warning: Connection problem - can't find source input "+string(num));
  888. return;
  889. }
  890. }
  891. void SynthModular::cb_Connection(Fl_Canvas* o, void* v)
  892. {((SynthModular*)(o->user_data()))->cb_Connection_i(o,v);}
  893. //////////////////////////////////////////////////////////
  894. inline void SynthModular::cb_Unconnect_i(Fl_Canvas* o, void* v)
  895. {
  896. CanvasWire *Wire;
  897. Wire=(CanvasWire*)v;
  898. //cerr<<Wire->InputID<<" "<<Wire->InputPort<<endl;
  899. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(Wire->InputID);
  900. if (di==m_DeviceWinMap.end())
  901. {
  902. //cerr<<"Can't find destination device "<<Wire->InputID<<endl;
  903. return;
  904. }
  905. if (!di->second->m_Device->SetInput(Wire->InputPort,NULL))
  906. { cerr<<"Can't find destination device's Input"<<endl; return; }
  907. }
  908. void SynthModular::cb_Unconnect(Fl_Canvas* o, void* v)
  909. {((SynthModular*)(o->user_data()))->cb_Unconnect_i(o,v);}
  910. //////////////////////////////////////////////////////////
  911. void SynthModular::cb_UpdatePluginInfo(int ID, void *PInfo)
  912. {
  913. map<int,DeviceWin*>::iterator i=m_DeviceWinMap.find(ID);
  914. if (i!=m_DeviceWinMap.end())
  915. {
  916. DeviceGUIInfo Info=BuildDeviceGUIInfo(*((PluginInfo*)PInfo));
  917. (*i).second->m_DeviceGUI->Setup(Info);
  918. (*i).second->m_DeviceGUI->redraw();
  919. }
  920. }
  921. //////////////////////////////////////////////////////////
  922. void SynthModular::LoadPatch(const char *fn)
  923. {
  924. ifstream inf(fn);
  925. if (inf)
  926. {
  927. m_FilePath=fn;
  928. ClearUp();
  929. inf>>*this;
  930. TITLEBAR=LABEL+" "+fn;
  931. m_TopWindow->label(TITLEBAR.c_str());
  932. }
  933. }
  934. //////////////////////////////////////////////////////////