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.

1124 lines
30KB

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