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.

1064 lines
28KB

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