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.

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