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.

1079 lines
29KB

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