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.

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