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.

1477 lines
37KB

  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 <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <dirent.h>
  25. #include <dlfcn.h>
  26. #include <FL/Fl.H>
  27. #include <FL/Enumerations.H>
  28. #include <FL/fl_file_chooser.h>
  29. #include <FL/Fl_Box.h>
  30. #include <FL/Fl_Tooltip.h>
  31. #include "SpiralSynthModular.h"
  32. #include "SpiralSound/PluginManager.h"
  33. #include "SpiralSound/SpiralInfo.h"
  34. #include "SpiralSound/Plugins/SpiralPluginGUI.h"
  35. #include "GUI/SSM.xpm"
  36. #include "GUI/load.xpm"
  37. #include "GUI/save.xpm"
  38. #include "GUI/new.xpm"
  39. #include "GUI/options.xpm"
  40. #include "GUI/comment.xpm"
  41. #include "GUI/Widgets/PawfalYesNo.h"
  42. //#define DEBUG_PLUGINS
  43. //#define DEBUG_STREAM
  44. const static string LABEL = "SpiralSynthModular "+VER_STRING;
  45. static string TITLEBAR;
  46. static const int FILE_VERSION = 4;
  47. static int Numbers[512];
  48. static const int MAIN_WIDTH = 700;
  49. static const int MAIN_HEIGHT = 600;
  50. static const int SLIDER_WIDTH = 15;
  51. static const int ICON_DEPTH = 3;
  52. static const int COMMENT_ID = -1;
  53. using namespace std;
  54. map<int,DeviceWin*> SynthModular::m_DeviceWinMap;
  55. bool SynthModular::m_CallbackUpdateMode = false;
  56. bool SynthModular::m_BlockingOutputPluginIsReady = false;
  57. //////////////////////////////////////////////////////////
  58. DeviceWin::~DeviceWin()
  59. {
  60. }
  61. //////////////////////////////////////////////////////////
  62. SynthModular::SynthModular():
  63. m_NextID(0),
  64. m_PauseAudio(false)
  65. {
  66. m_Info.BUFSIZE = SpiralInfo::BUFSIZE;
  67. m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE;
  68. m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT;
  69. m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE;
  70. m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE;
  71. m_Info.MIDIFILE = SpiralInfo::MIDIFILE;
  72. m_Info.POLY = SpiralInfo::POLY;
  73. m_Info.GUI_COLOUR = SpiralInfo::GUI_COLOUR;
  74. m_Info.SCOPE_BG_COLOUR = SpiralInfo::SCOPE_BG_COLOUR;
  75. m_Info.SCOPE_FG_COLOUR = SpiralInfo::SCOPE_FG_COLOUR;
  76. m_Info.SCOPE_SEL_COLOUR = SpiralInfo::SCOPE_SEL_COLOUR;
  77. m_Info.SCOPE_IND_COLOUR = SpiralInfo::SCOPE_IND_COLOUR;
  78. m_Info.SCOPE_MRK_COLOUR = SpiralInfo::SCOPE_MRK_COLOUR;
  79. m_Info.GUICOL_Device = SpiralInfo::GUICOL_Device;
  80. m_Info.GUIDEVICE_Box = SpiralInfo::GUIDEVICE_Box;
  81. for (int n=0; n<512; n++) Numbers[n]=n;
  82. m_CH.Register("PauseAudio",&m_PauseAudio);
  83. }
  84. //////////////////////////////////////////////////////////
  85. SynthModular::~SynthModular()
  86. {
  87. ClearUp();
  88. PluginManager::Get()->PackUpAndGoHome();
  89. system("rm -f ___temp.ssmcopytmp");
  90. }
  91. //////////////////////////////////////////////////////////
  92. void SynthModular::ClearUp()
  93. {
  94. PauseAudio();
  95. for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  96. i!=m_DeviceWinMap.end(); i++)
  97. {
  98. //Stop processing of audio if any
  99. if (i->second->m_Device)
  100. {
  101. if (i->second->m_Device->Kill());
  102. }
  103. i->second->m_DeviceGUI->Clear();
  104. if (i->second->m_DeviceGUI->GetPluginWindow())
  105. {
  106. i->second->m_DeviceGUI->GetPluginWindow()->hide();
  107. }
  108. //Delete Device
  109. delete i->second->m_Device;
  110. i->second->m_Device=NULL;
  111. }
  112. m_Canvas->Clear();
  113. m_DeviceWinMap.clear();
  114. m_NextID=0;
  115. ResumeAudio();
  116. }
  117. //////////////////////////////////////////////////////////
  118. void SynthModular::Update()
  119. {
  120. m_CH.UpdateDataNow();
  121. if (m_PauseAudio) return;
  122. // for all the plugins
  123. for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  124. i!=m_DeviceWinMap.end(); i++)
  125. {
  126. if (i->second->m_Device && i->second->m_Device->IsDead())
  127. {
  128. //Delete Device
  129. delete i->second->m_Device;
  130. i->second->m_Device=NULL;
  131. //Erase Device from DeviceWinMap
  132. m_DeviceWinMap.erase(i);
  133. }
  134. else if (i->second->m_Device) // if it's not a comment
  135. {
  136. #ifdef DEBUG_PLUGINS
  137. cerr<<"Updating channelhandler of plugin "<<i->second->m_PluginID<<endl;
  138. #endif
  139. // updates the data from the gui thread, if it's not blocking
  140. i->second->m_Device->UpdateChannelHandler();
  141. #ifdef DEBUG_PLUGINS
  142. cerr<<"Finished updating"<<endl;
  143. #endif
  144. // run any commands we've received from the GUI's
  145. i->second->m_Device->ExecuteCommands();
  146. }
  147. }
  148. // run the plugins (only ones connected to anything)
  149. list<int> ExecutionOrder = m_Canvas->GetGraph()->GetSortedList();
  150. for (list<int>::reverse_iterator i=ExecutionOrder.rbegin();
  151. i!=ExecutionOrder.rend(); i++)
  152. {
  153. // use the graphsort order to remove internal latency
  154. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(*i);
  155. if (di!=m_DeviceWinMap.end() && di->second->m_Device && (! di->second->m_Device->IsDead()))
  156. {
  157. #ifdef DEBUG_PLUGINS
  158. cerr<<"Executing plugin "<<di->second->m_PluginID<<endl;
  159. #endif
  160. di->second->m_Device->Execute();
  161. #ifdef DEBUG_PLUGINS
  162. cerr<<"Finished executing"<<endl;
  163. #endif
  164. }
  165. }
  166. }
  167. //////////////////////////////////////////////////////////
  168. void SynthModular::UpdatePluginGUIs()
  169. {
  170. // see if any need deleting
  171. for (map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  172. i!=m_DeviceWinMap.end(); i++)
  173. {
  174. if (i->second->m_DeviceGUI && i->second->m_DeviceGUI->GetPluginWindow())
  175. {
  176. SpiralPluginGUI *GUI=(SpiralPluginGUI *)i->second->m_DeviceGUI->GetPluginWindow();
  177. GUI->Update();
  178. }
  179. if (i->second->m_DeviceGUI && i->second->m_DeviceGUI->Killed())
  180. {
  181. bool erase = true;
  182. //Stop processing of audio if any
  183. if (i->second->m_Device)
  184. {
  185. if (i->second->m_Device->Kill());
  186. erase = false;
  187. }
  188. //Clear GUI Device
  189. i->second->m_DeviceGUI->Clear();
  190. // Hide Device GUI FIRST
  191. if (i->second->m_DeviceGUI->GetPluginWindow())
  192. {
  193. i->second->m_DeviceGUI->GetPluginWindow()->hide();
  194. }
  195. //Remove Device GUI from canvas
  196. m_Canvas->RemoveDevice(i->second->m_DeviceGUI);
  197. //Delete Device GUI - must delete here or sometimes plugin will randomly crash
  198. delete i->second->m_DeviceGUI;
  199. i->second->m_DeviceGUI = NULL;
  200. //Erase from winmap if no audio to do it
  201. if (erase)
  202. m_DeviceWinMap.erase(i);
  203. }
  204. }
  205. m_Canvas->Poll();
  206. }
  207. //////////////////////////////////////////////////////////
  208. SpiralWindowType *SynthModular::CreateWindow()
  209. {
  210. m_TopWindow = new SpiralWindowType(MAIN_WIDTH, MAIN_HEIGHT, LABEL.c_str());
  211. //m_TopWindow->resizable(m_TopWindow);
  212. int but=50;
  213. int ToolbarHeight=but+0;
  214. m_Topbar = new Fl_Pack (0, 0, MAIN_WIDTH, ToolbarHeight, "");
  215. m_Topbar->user_data((void*)(this));
  216. m_Topbar->type(FL_HORIZONTAL);
  217. m_Topbar->color(SpiralInfo::GUICOL_Button);
  218. m_TopWindow->add(m_Topbar);
  219. m_ToolbarPanel = new Fl_Pack (0, 0, but*5, ToolbarHeight, "");
  220. m_ToolbarPanel->user_data((void*)(this));
  221. m_ToolbarPanel->type(FL_VERTICAL);
  222. m_ToolbarPanel->color(SpiralInfo::GUICOL_Button);
  223. m_Topbar->add(m_ToolbarPanel);
  224. m_Toolbar = new Fl_Pack (0, 0, but*5, but, "");
  225. m_Toolbar->user_data((void*)(this));
  226. m_Toolbar->type(FL_HORIZONTAL);
  227. m_Toolbar->color(SpiralInfo::GUICOL_Button);
  228. m_ToolbarPanel->add(m_Toolbar);
  229. m_Load = new Fl_Button(0, 0, but, but, "");
  230. Fl_Pixmap *tPix = new Fl_Pixmap(load_xpm);
  231. m_Load->image(tPix->copy());
  232. delete tPix;
  233. m_Load->type(0);
  234. m_Load->box(FL_PLASTIC_UP_BOX);
  235. m_Load->color(SpiralInfo::GUICOL_Button);
  236. m_Load->selection_color(SpiralInfo::GUICOL_Tool);
  237. m_Load->labelsize (1);
  238. m_Load->tooltip("Load a patch file");
  239. m_Load->callback((Fl_Callback*)cb_Load);
  240. m_Toolbar->add(m_Load);
  241. m_Save = new Fl_Button(0, 0, but, but, "");
  242. tPix = new Fl_Pixmap(save_xpm);
  243. m_Save->image(tPix->copy());
  244. delete tPix;
  245. m_Save->type(0);
  246. m_Save->box(FL_PLASTIC_UP_BOX);
  247. m_Save->color(SpiralInfo::GUICOL_Button);
  248. m_Save->selection_color(SpiralInfo::GUICOL_Tool);
  249. m_Save->labelsize (1);
  250. m_Save->tooltip("Save a patch file");
  251. m_Save->callback((Fl_Callback*)cb_Save);
  252. m_Toolbar->add(m_Save);
  253. m_New = new Fl_Button(0, 0, but, but, "");
  254. tPix = new Fl_Pixmap(new_xpm);
  255. m_New->image(tPix->copy());
  256. delete tPix;
  257. m_New->type(0);
  258. m_New->box(FL_PLASTIC_UP_BOX);
  259. m_New->color(SpiralInfo::GUICOL_Button);
  260. m_New->selection_color(SpiralInfo::GUICOL_Tool);
  261. m_New->labelsize (1);
  262. m_New->tooltip("New patch");
  263. m_New->callback((Fl_Callback*)cb_New);
  264. m_Toolbar->add(m_New);
  265. m_Options = new Fl_Button(0, 0, but, but, "");
  266. tPix = new Fl_Pixmap(options_xpm);
  267. m_Options->image(tPix->copy());
  268. delete tPix;
  269. m_Options->type(0);
  270. m_Options->box(FL_PLASTIC_UP_BOX);
  271. m_Options->color(SpiralInfo::GUICOL_Button);
  272. m_Options->selection_color(SpiralInfo::GUICOL_Tool);
  273. m_Options->labelsize (1);
  274. m_Options->tooltip("Options");
  275. m_Options->callback((Fl_Callback*)cb_Rload);
  276. m_Toolbar->add(m_Options);
  277. m_NewComment = new Fl_Button(0, 0, but, but, "");
  278. tPix = new Fl_Pixmap(comment_xpm);
  279. m_NewComment->image(tPix->copy());
  280. delete tPix;
  281. m_NewComment->type(0);
  282. m_NewComment->box(FL_PLASTIC_UP_BOX);
  283. m_NewComment->color(SpiralInfo::GUICOL_Button);
  284. m_NewComment->selection_color(SpiralInfo::GUICOL_Tool);
  285. m_NewComment->labelsize (1);
  286. m_NewComment->tooltip("New comment");
  287. m_NewComment->callback((Fl_Callback*)cb_NewComment);
  288. m_Toolbar->add(m_NewComment);
  289. m_GroupFiller = new Fl_Group (0, 0, 0, ToolbarHeight, "");
  290. m_GroupFiller->color(SpiralInfo::GUICOL_Button);
  291. m_Topbar->add (m_GroupFiller);
  292. m_GroupTab = new Fl_Tabs (0, 0, MAIN_WIDTH-m_GroupFiller->w()-but*5, ToolbarHeight, "");
  293. m_GroupTab->user_data ((void*)(this));
  294. m_GroupTab->box(FL_PLASTIC_DOWN_BOX);
  295. m_GroupTab->color(SpiralInfo::GUICOL_Button);
  296. m_GroupTab->callback((Fl_Callback*)cb_GroupTab);
  297. m_Topbar->add (m_GroupTab);
  298. m_Topbar->resizable(m_GroupTab);
  299. /////////////////
  300. m_CanvasScroll = new Fl_Scroll(0, ToolbarHeight, MAIN_WIDTH, MAIN_HEIGHT-ToolbarHeight, "");
  301. m_TopWindow->add(m_CanvasScroll);
  302. m_TopWindow->resizable(m_CanvasScroll);
  303. m_Canvas = new Fl_Canvas(-5000, -5000, 10000, 10000, "");
  304. m_Canvas->type(1);
  305. m_Canvas->box(FL_FLAT_BOX);
  306. m_Canvas->labeltype(FL_ENGRAVED_LABEL);
  307. m_Canvas->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  308. m_Canvas->color(SpiralInfo::GUICOL_Canvas);
  309. m_Canvas->user_data((void*)(this));
  310. m_Canvas->SetConnectionCallback((Fl_Callback*)cb_Connection);
  311. m_Canvas->SetUnconnectCallback((Fl_Callback*)cb_Unconnect);
  312. m_Canvas->SetAddDeviceCallback((Fl_Callback*)cb_NewDeviceFromMenu);
  313. m_Canvas->SetCutDeviceGroupCallback((Fl_Callback*)cb_CutDeviceGroup);
  314. m_Canvas->SetCopyDeviceGroupCallback((Fl_Callback*)cb_CopyDeviceGroup);
  315. m_Canvas->SetPasteDeviceGroupCallback((Fl_Callback*)cb_PasteDeviceGroup);
  316. m_Canvas->SetMergePatchCallback((Fl_Callback*)cb_MergePatch);
  317. m_CanvasScroll->add(m_Canvas);
  318. m_SettingsWindow = new SettingsWindow;
  319. m_SettingsWindow->RegisterApp(this);
  320. return m_TopWindow;
  321. }
  322. //////////////////////////////////////////////////////////
  323. vector<string> SynthModular::BuildPluginList (const string &Path) {
  324. // Scan plugin path for plugins.
  325. DIR *dp;
  326. struct dirent *ep;
  327. struct stat sb;
  328. void *handle;
  329. string fullpath;
  330. const char *path = Path.c_str();
  331. vector<string> ret;
  332. dp = opendir(path);
  333. if (!dp) {
  334. cerr << "WARNING: Could not open path " << path << endl;
  335. }
  336. else {
  337. while ((ep = readdir(dp))) {
  338. // Need full path
  339. fullpath = path;
  340. fullpath.append(ep->d_name);
  341. // Stat file to get type
  342. if (!stat(fullpath.c_str(), &sb)) {
  343. // We only want regular files
  344. if (S_ISREG(sb.st_mode)) {
  345. // We're not fussed about resolving symbols yet, since we are just
  346. // checking if it's a DLL.
  347. handle = dlopen(fullpath.c_str(), RTLD_LAZY);
  348. if (!handle) {
  349. cerr << "WARNING: File " << path << ep->d_name
  350. << " could not be examined" << endl;
  351. cerr << "dlerror() output:" << endl;
  352. cerr << dlerror() << endl;
  353. }
  354. else {
  355. // It's a DLL. Add name to list
  356. ret.push_back(ep->d_name);
  357. }
  358. }
  359. }
  360. }
  361. }
  362. return ret;
  363. }
  364. void SynthModular::LoadPlugins(string pluginPath)
  365. {
  366. int Width = 35;
  367. int Height = 35;
  368. int SWidth = 256;
  369. int SHeight = 256;
  370. Fl_Pixmap pic(SSM_xpm);
  371. Fl_Double_Window* Splash = new Fl_Double_Window((Fl::w()/2)-(SWidth/2),
  372. (Fl::h()/2)-(SHeight/2),
  373. SWidth,SHeight,"SSM");
  374. Splash->border(0);
  375. Fl_Box* pbut = new Fl_Box(0,8,SWidth,SHeight,"");
  376. pbut->box(FL_NO_BOX);
  377. pic.label(pbut);
  378. Fl_Box *splashtext = new Fl_Box(5,SHeight-20,200,20,"Loading...");
  379. splashtext->labelsize(10);
  380. splashtext->box(FL_NO_BOX);
  381. splashtext->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
  382. Splash->add(pbut);
  383. Splash->add(splashtext);
  384. Splash->show();
  385. int ID=-1;
  386. vector<string> PluginVector;
  387. if (SpiralInfo::USEPLUGINLIST) {
  388. PluginVector=SpiralInfo::PLUGINVEC;
  389. }
  390. else {
  391. if (pluginPath.empty()) {
  392. PluginVector=BuildPluginList (SpiralInfo::PLUGIN_PATH);
  393. }
  394. else {
  395. string::iterator i = pluginPath.end() - 1;
  396. if (*i != '/') pluginPath += '/';
  397. PluginVector=BuildPluginList(pluginPath);
  398. }
  399. }
  400. for (vector<string>::iterator i=PluginVector.begin();
  401. i!=PluginVector.end(); i++)
  402. {
  403. string Fullpath;
  404. if (pluginPath=="")
  405. {
  406. Fullpath=SpiralInfo::PLUGIN_PATH+*i;
  407. }
  408. else
  409. {
  410. Fullpath=pluginPath+*"/"+*i;
  411. }
  412. ID=PluginManager::Get()->LoadPlugin(Fullpath.c_str());
  413. if (ID!=PluginError)
  414. {
  415. #ifdef DEBUG_PLUGINS
  416. cerr << ID << " = Plugin [" << *i << "]" << endl;
  417. #endif
  418. Fl_ToolButton *NewButton = new Fl_ToolButton(0,0,Width,Height,"");
  419. NewButton->user_data((void*)(this));
  420. NewButton->labelsize(1);
  421. Fl_Pixmap *tPix = new Fl_Pixmap(PluginManager::Get()->GetPlugin(ID)->GetIcon());
  422. NewButton->image(tPix->copy(tPix->w(),tPix->h()));
  423. delete tPix;
  424. string GroupName = PluginManager::Get()->GetPlugin(ID)->GetGroupName();
  425. Fl_Pack* the_group=NULL;
  426. // find or create this group, and add an icon
  427. map<string,Fl_Pack*>::iterator gi=m_PluginGroupMap.find(GroupName);
  428. if (gi==m_PluginGroupMap.end())
  429. {
  430. the_group = new Fl_Pack (m_GroupTab->x(), 16, m_GroupTab->w(), m_GroupTab->h()-15, GroupName.c_str());
  431. the_group->type(FL_HORIZONTAL);
  432. the_group->labelsize(8);
  433. the_group->color(SpiralInfo::GUICOL_Button);
  434. the_group->user_data((void*)(this));
  435. //m_GroupTab->add(the_group);
  436. m_GroupTab->value(the_group);
  437. m_PluginGroupMap[GroupName]=the_group;
  438. }
  439. else
  440. {
  441. the_group=gi->second;
  442. }
  443. NewButton->type(0);
  444. NewButton->box(FL_NO_BOX);
  445. NewButton->down_box(FL_NO_BOX);
  446. //NewButton->color(SpiralInfo::GUICOL_Button);
  447. //NewButton->selection_color(SpiralInfo::GUICOL_Button);
  448. the_group->add(NewButton);
  449. string tooltip=*i;
  450. // find the first / if there is one, and get rid of everything before and including it
  451. unsigned int p = tooltip.find ('/');
  452. if (p < tooltip.length()) tooltip.erase (0, p);
  453. // find last . and get rid of everything after and including it
  454. p = tooltip.rfind ('.');
  455. unsigned int l = tooltip.length ();
  456. if (p < l) tooltip.erase (p, l);
  457. m_Canvas->AddPluginName (tooltip, PluginManager::Get()->GetPlugin(ID)->ID);
  458. splashtext->label (tooltip.c_str());
  459. Splash->redraw();
  460. NewButton->tooltip (tooltip.c_str());
  461. NewButton->callback((Fl_Callback*)cb_NewDevice,&Numbers[ID]);
  462. NewButton->show();
  463. m_DeviceVec.push_back(NewButton);
  464. the_group->redraw();
  465. // m_NextPluginButton++;
  466. Fl::check();
  467. }
  468. }
  469. map<string,Fl_Pack*>::iterator PlugGrp;
  470. for (PlugGrp = m_PluginGroupMap.begin(); PlugGrp!= m_PluginGroupMap.end(); ++PlugGrp)
  471. {
  472. m_GroupTab->add(PlugGrp->second);
  473. PlugGrp->second->add(new Fl_Box(0,0,600,100,""));
  474. }
  475. // try to show the SpiralSound group
  476. PlugGrp = m_PluginGroupMap.find("SpiralSound");
  477. // can't find it - show the first plugin group
  478. if (PlugGrp==m_PluginGroupMap.end()) PlugGrp=m_PluginGroupMap.begin();
  479. m_GroupTab->value(PlugGrp->second);
  480. Splash->hide();
  481. delete Splash;
  482. }
  483. //////////////////////////////////////////////////////////
  484. DeviceGUIInfo SynthModular::BuildDeviceGUIInfo(PluginInfo &PInfo)
  485. {
  486. DeviceGUIInfo Info;
  487. int Height=50;
  488. // tweak the size if we have too many ins/outs
  489. if (PInfo.NumInputs>4 || PInfo.NumOutputs>4)
  490. {
  491. if (PInfo.NumInputs<PInfo.NumOutputs)
  492. {
  493. Height=PInfo.NumOutputs*10+5;
  494. }
  495. else
  496. {
  497. Height=PInfo.NumInputs*10+5;
  498. }
  499. }
  500. // Make the guiinfo struct
  501. Info.XPos = 0;
  502. Info.YPos = 0;
  503. Info.Width = 40;
  504. Info.Height = Height;
  505. Info.NumInputs = PInfo.NumInputs;
  506. Info.NumOutputs = PInfo.NumOutputs;
  507. Info.Name = PInfo.Name;
  508. Info.PortTips = PInfo.PortTips;
  509. Info.PortTypes = PInfo.PortTypes;
  510. return Info;
  511. }
  512. //////////////////////////////////////////////////////////
  513. DeviceWin* SynthModular::NewDeviceWin(int n, int x, int y)
  514. {
  515. DeviceWin *nlw = new DeviceWin;
  516. const HostsideInfo* Plugin=PluginManager::Get()->GetPlugin(n);
  517. if (!Plugin) return NULL;
  518. nlw->m_Device=Plugin->CreateInstance();
  519. if (!nlw->m_Device) return NULL;
  520. nlw->m_Device->SetBlockingCallback(cb_Blocking);
  521. nlw->m_Device->SetUpdateCallback(cb_Update);
  522. nlw->m_Device->SetParent((void*)this);
  523. PluginInfo PInfo = nlw->m_Device->Initialise(&m_Info);
  524. SpiralGUIType *temp = nlw->m_Device->CreateGUI();
  525. Fl_Pixmap *Pix = new Fl_Pixmap(Plugin->GetIcon());
  526. nlw->m_PluginID = n;
  527. if (temp) temp->position(x+10,y);
  528. DeviceGUIInfo Info=BuildDeviceGUIInfo(PInfo);
  529. Info.XPos = x; //TOOLBOX_WIDTH+(rand()%400);
  530. Info.YPos = y; //rand()%400;
  531. nlw->m_DeviceGUI = new Fl_DeviceGUI(Info, temp, Pix, nlw->m_Device->IsTerminal());
  532. Fl_Canvas::SetDeviceCallbacks(nlw->m_DeviceGUI, m_Canvas);
  533. m_Canvas->add(nlw->m_DeviceGUI);
  534. m_Canvas->redraw();
  535. return nlw;
  536. }
  537. //////////////////////////////////////////////////////////
  538. void SynthModular::AddDevice(int n, int x=-1, int y=-1)
  539. {
  540. //cerr<<"Adding "<<m_NextID<<endl;
  541. if (x==-1)
  542. {
  543. x = m_CanvasScroll->x()+50;
  544. y = m_CanvasScroll->y()+50;
  545. }
  546. DeviceWin* temp = NewDeviceWin(n,x,y);
  547. if (temp)
  548. {
  549. int ID=m_NextID++;
  550. //cerr<<"adding device "<<ID<<endl;
  551. temp->m_DeviceGUI->SetID(ID);
  552. temp->m_Device->SetUpdateInfoCallback(ID,cb_UpdatePluginInfo);
  553. m_DeviceWinMap[ID]=temp;
  554. }
  555. }
  556. //////////////////////////////////////////////////////////
  557. DeviceWin* SynthModular::NewComment(int n, int x=-1, int y=-1)
  558. {
  559. DeviceWin *nlw = new DeviceWin;
  560. if (x==-1)
  561. {
  562. x = m_CanvasScroll->x()+50;
  563. y = m_CanvasScroll->y()+50;
  564. }
  565. nlw->m_Device=NULL;
  566. nlw->m_PluginID = COMMENT_ID;
  567. DeviceGUIInfo Info;
  568. Info.XPos = x;
  569. Info.YPos = y;
  570. Info.Width = 50;
  571. Info.Height = 20;
  572. Info.NumInputs = 0;
  573. Info.NumOutputs = 0;
  574. Info.Name = "";
  575. nlw->m_DeviceGUI = new Fl_CommentGUI(Info, NULL, NULL);
  576. Fl_Canvas::SetDeviceCallbacks(nlw->m_DeviceGUI, m_Canvas);
  577. m_Canvas->add(nlw->m_DeviceGUI);
  578. m_Canvas->redraw();
  579. return nlw;
  580. }
  581. //////////////////////////////////////////////////////////
  582. void SynthModular::AddComment(int n)
  583. {
  584. //cerr<<"Adding "<<m_NextID<<endl;
  585. DeviceWin* temp = NewComment(n);
  586. if (temp)
  587. {
  588. int ID=m_NextID++;
  589. //cerr<<"adding comment "<<ID<<endl;
  590. temp->m_DeviceGUI->SetID(ID);
  591. m_DeviceWinMap[ID]=temp;
  592. }
  593. }
  594. //////////////////////////////////////////////////////////
  595. void SynthModular::UpdateHostInfo()
  596. {
  597. // used to use string streams, but this seems to cause a compiler bug
  598. // at the moment, so fall back to using a temporary file
  599. //std::stringstream str;
  600. fstream ofs("___temp.ssmtmp",ios::out);
  601. //str<<*this;
  602. ofs<<*this;
  603. ClearUp();
  604. // update the settings
  605. m_Info.BUFSIZE = SpiralInfo::BUFSIZE;
  606. m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE;
  607. m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT;
  608. m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE;
  609. m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE;
  610. m_Info.MIDIFILE = SpiralInfo::MIDIFILE;
  611. m_Info.POLY = SpiralInfo::POLY;
  612. fstream ifs("___temp.ssmtmp",ios::in);
  613. //str>>*this;
  614. ifs>>*this;
  615. system("rm -f ___temp.ssmtmp");
  616. }
  617. //////////////////////////////////////////////////////////
  618. // called when a callback output plugin wants to run the audio thread
  619. void SynthModular::cb_Update(void* o, bool mode)
  620. {
  621. m_CallbackUpdateMode=mode;
  622. ((SynthModular*)o)->Update();
  623. }
  624. // called by a blocking output plugin to notify the engine its ready to
  625. // take control of the update timing (so take the brakes off)
  626. void SynthModular::cb_Blocking(void* o, bool mode)
  627. {
  628. m_BlockingOutputPluginIsReady=mode;
  629. }
  630. //////////////////////////////////////////////////////////
  631. inline void SynthModular::cb_CutDeviceGroup_i()
  632. {
  633. if (! m_Canvas->HaveSelection())
  634. return;
  635. //show some warning here
  636. cb_CopyDeviceGroup_i();
  637. for (unsigned int i=0; i<m_Canvas->Selection().m_DeviceIds.size(); i++)
  638. {
  639. int ID = m_Canvas->Selection().m_DeviceIds[i];
  640. Fl_DeviceGUI::Kill(m_DeviceWinMap[ID]->m_DeviceGUI);
  641. }
  642. Fl_Canvas::ClearSelection(m_Canvas);
  643. }
  644. //////////////////////////////////////////////////////////
  645. inline void SynthModular::cb_MergePatch_i()
  646. {
  647. char *fn=fl_file_chooser("Merge a patch", "*.ssm", NULL);
  648. if (fn && fn!='\0')
  649. {
  650. ifstream in(fn);
  651. if (in)
  652. {
  653. fstream inf;
  654. inf.open(fn,ios::in);
  655. m_MergeFilePath=fn;
  656. StreamPatchIn(inf, false, true);
  657. m_Canvas->StreamSelectionWiresIn(inf, m_Copied.m_DeviceIds, true, false);
  658. inf.close();
  659. }
  660. }
  661. }
  662. //////////////////////////////////////////////////////////
  663. inline void SynthModular::cb_CopyDeviceGroup_i()
  664. {
  665. if (! m_Canvas->HaveSelection())
  666. return;
  667. m_Copied.devices.open("___temp.ssmcopytmp",ios::out);
  668. m_Copied.devicecount = 0;
  669. m_Copied.m_DeviceIds.clear();
  670. if (m_FilePath != "")
  671. {
  672. m_Copied.devices<<true<<" ";
  673. m_Copied.devices<<m_FilePath<<endl;
  674. }
  675. else
  676. m_Copied.devices<<false<<endl;
  677. for (unsigned int i=0; i<m_Canvas->Selection().m_DeviceIds.size(); i++)
  678. {
  679. int ID = m_Canvas->Selection().m_DeviceIds[i];
  680. std::map<int,DeviceWin*>::iterator i = m_DeviceWinMap.find(ID);
  681. m_Copied.m_DeviceIds[ID] = ID;
  682. m_Copied.devicecount += 1;
  683. m_Copied.devices<<"Device ";
  684. m_Copied.devices<<i->first<<" "; // save the id
  685. m_Copied.devices<<"Plugin ";
  686. m_Copied.devices<<i->second->m_PluginID<<endl;
  687. m_Copied.devices<<i->second->m_DeviceGUI->x()<<" ";
  688. m_Copied.devices<<i->second->m_DeviceGUI->y()<<" ";
  689. m_Copied.devices<<i->second->m_DeviceGUI->GetName().size()<<" ";
  690. m_Copied.devices<<i->second->m_DeviceGUI->GetName()<<" ";
  691. if (i->second->m_DeviceGUI->GetPluginWindow())
  692. {
  693. m_Copied.devices<<i->second->m_DeviceGUI->GetPluginWindow()->visible()<<" ";
  694. m_Copied.devices<<i->second->m_DeviceGUI->GetPluginWindow()->x()<<" ";
  695. m_Copied.devices<<i->second->m_DeviceGUI->GetPluginWindow()->y()<<" ";
  696. }
  697. else
  698. {
  699. m_Copied.devices<<0<<" "<<0<<" "<<0;
  700. }
  701. m_Copied.devices<<endl;
  702. if (i->second->m_PluginID==COMMENT_ID)
  703. {
  704. // save the comment gui
  705. ((Fl_CommentGUI*)(i->second->m_DeviceGUI))->StreamOut(m_Copied.devices);
  706. }
  707. else
  708. {
  709. // save the plugin
  710. i->second->m_Device->StreamOut(m_Copied.devices);
  711. }
  712. m_Copied.devices<<endl;
  713. }
  714. m_Canvas->StreamSelectionWiresOut(m_Copied.devices);
  715. m_Copied.devices.close();
  716. Fl_Canvas::EnablePaste(m_Canvas);
  717. };
  718. //////////////////////////////////////////////////////////
  719. inline void SynthModular::cb_PasteDeviceGroup_i()
  720. {
  721. if (m_Copied.devicecount <= 0)
  722. return;
  723. m_Copied.devices.open("___temp.ssmcopytmp",ios::in);
  724. StreamPatchIn(m_Copied.devices, true, false);
  725. m_Canvas->StreamSelectionWiresIn(m_Copied.devices, m_Copied.m_DeviceIds, false, true);
  726. m_Copied.devices.close();
  727. };
  728. //////////////////////////////////////////////////////////
  729. iostream &SynthModular::StreamPatchIn(iostream &s, bool paste, bool merge)
  730. {
  731. //if we are merging as opposed to loading a new patch
  732. //we have no need to pause audio
  733. if (!merge && !paste)
  734. PauseAudio();
  735. //if we are pasting we don't have any of the file version
  736. //or saving information. since its internal we didn't
  737. //need it, but we do have other things we might need to load
  738. bool has_file_path;
  739. string m_FromFilePath;
  740. string dummy,dummy2;
  741. int ver;
  742. if (paste)
  743. {
  744. m_Copied.devices>>has_file_path;
  745. if (has_file_path)
  746. m_Copied.devices>>m_FromFilePath;
  747. }
  748. else
  749. {
  750. s>>dummy>>dummy>>dummy>>ver;
  751. if (ver>FILE_VERSION)
  752. {
  753. SpiralInfo::Alert("Bad file, or more recent version.");
  754. return s;
  755. }
  756. if (ver>2)
  757. {
  758. int MainWinX,MainWinY,MainWinW,MainWinH;
  759. int EditWinX,EditWinY,EditWinW,EditWinH;
  760. s>>MainWinX>>MainWinY>>MainWinW>>MainWinH;
  761. s>>EditWinX>>EditWinY>>EditWinW>>EditWinH;
  762. //o.m_MainWindow->resize(MainWinX,MainWinY,MainWinW,MainWinH);
  763. //o.m_EditorWindow->resize(EditWinX,EditWinY,EditWinW,EditWinH);
  764. }
  765. if (merge)
  766. m_FromFilePath = m_MergeFilePath;
  767. }
  768. //wether pasting or merging we need to clear the current
  769. //selection so we can replace it with the new devices
  770. if (paste || merge)
  771. Fl_Canvas::ClearSelection(m_Canvas);
  772. int Num, ID, PluginID, x,y,ps,px,py;
  773. if (paste)
  774. {
  775. Num = m_Copied.devicecount;
  776. }
  777. else
  778. {
  779. s>>dummy>>Num;
  780. }
  781. for(int n=0; n<Num; n++)
  782. {
  783. #ifdef DEBUG_STREAM
  784. cerr<<"Loading Device "<<n<<endl;
  785. #endif
  786. s>>dummy; // "Device"
  787. s>>ID;
  788. s>>dummy2; // "Plugin"
  789. s>>PluginID;
  790. s>>x>>y;
  791. string Name;
  792. if (paste || ver>3)
  793. {
  794. // load the device name
  795. int size;
  796. char Buf[1024];
  797. s>>size;
  798. s.ignore(1);
  799. if (size > 0) {
  800. s.get(Buf,size+1);
  801. Name=Buf;
  802. } else {
  803. Name = "";
  804. }
  805. }
  806. #ifdef DEBUG_STREAM
  807. cerr<<dummy<<" "<<ID<<" "<<dummy2<<" "<<PluginID<<" "<<x<<" "<<y<<endl;
  808. #endif
  809. if (paste || ver>1) s>>ps>>px>>py;
  810. //if we are merging a patch or pasting we will change duplicate ID's
  811. if (!paste && !merge)
  812. {
  813. // Check we're not duplicating an ID
  814. if (m_DeviceWinMap.find(ID)!=m_DeviceWinMap.end())
  815. {
  816. SpiralInfo::Alert("Duplicate device ID found in file - aborting load");
  817. return s;
  818. }
  819. }
  820. if (PluginID==COMMENT_ID)
  821. {
  822. DeviceWin* temp = NewComment(PluginID, x, y);
  823. if (temp)
  824. {
  825. if (paste || merge)
  826. {
  827. m_Copied.m_DeviceIds[ID] = m_NextID++;
  828. ID = m_Copied.m_DeviceIds[ID];
  829. }
  830. temp->m_DeviceGUI->SetID(ID);
  831. m_DeviceWinMap[ID]=temp;
  832. ((Fl_CommentGUI*)(m_DeviceWinMap[ID]->m_DeviceGUI))->StreamIn(s); // load the plugin
  833. if (paste || merge)
  834. Fl_Canvas::AppendSelection(ID, m_Canvas);
  835. else
  836. if (m_NextID<=ID) m_NextID=ID+1;
  837. }
  838. }
  839. else
  840. {
  841. DeviceWin* temp = NewDeviceWin(PluginID, x, y);
  842. if (temp)
  843. {
  844. int oldID=ID;
  845. if (paste || merge)
  846. {
  847. m_Copied.m_DeviceIds[ID] = m_NextID++;
  848. ID = m_Copied.m_DeviceIds[ID];
  849. }
  850. temp->m_DeviceGUI->SetID(ID);
  851. if (paste || ver>3)
  852. {
  853. // set the titlebars
  854. temp->m_DeviceGUI->SetName(Name);
  855. }
  856. temp->m_Device->SetUpdateInfoCallback(ID,cb_UpdatePluginInfo);
  857. m_DeviceWinMap[ID]=temp;
  858. m_DeviceWinMap[ID]->m_Device->StreamIn(s); // load the plugin
  859. // load external files
  860. if (paste || merge)
  861. m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(m_FromFilePath+"_files/", oldID);
  862. else
  863. m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(m_FilePath+"_files/");
  864. if ((paste || ver>1) && m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow())
  865. {
  866. // set the GUI up with the loaded values
  867. // looks messy, but if we do it here, the plugin and it's gui can remain
  868. // totally seperated.
  869. ((SpiralPluginGUI*)(m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()))->
  870. UpdateValues(m_DeviceWinMap[ID]->m_Device);
  871. // updates the data in the channel buffers, so the values don't
  872. // get overwritten in the next tick. (should maybe be somewhere else)
  873. m_DeviceWinMap[ID]->m_Device->GetChannelHandler()->FlushChannels();
  874. // position the plugin window in the main window
  875. //m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->position(px,py);
  876. if (ps)
  877. {
  878. m_DeviceWinMap[ID]->m_DeviceGUI->Maximise();
  879. // reposition after maximise
  880. m_DeviceWinMap[ID]->m_DeviceGUI->position(x,y);
  881. }
  882. else m_DeviceWinMap[ID]->m_DeviceGUI->Minimise();
  883. if (paste || merge)
  884. Fl_Canvas::AppendSelection(ID, m_Canvas);
  885. }
  886. if (!paste && !merge)
  887. if (m_NextID<=ID) m_NextID=ID+1;
  888. }
  889. else
  890. {
  891. // can't really recover if the plugin ID doesn't match a plugin, as
  892. // we have no idea how much data in the stream belongs to this plugin
  893. SpiralInfo::Alert("Error in stream, can't really recover data from here on.");
  894. return s;
  895. }
  896. }
  897. }
  898. if (!paste && !merge)
  899. {
  900. s>>*m_Canvas;
  901. ResumeAudio();
  902. }
  903. return s;
  904. }
  905. iostream &operator>>(iostream &s, SynthModular &o)
  906. {
  907. return o.StreamPatchIn(s, false, false);
  908. }
  909. //////////////////////////////////////////////////////////
  910. ostream &operator<<(ostream &s, SynthModular &o)
  911. {
  912. o.PauseAudio();
  913. s<<"SpiralSynthModular File Ver "<<FILE_VERSION<<endl;
  914. // make external files dir
  915. bool ExternalDirUsed=false;
  916. string command("mkdir "+o.m_FilePath+"_files");
  917. system(command.c_str());
  918. if (FILE_VERSION>2)
  919. {
  920. s<<o.m_TopWindow->x()<<" "<<o.m_TopWindow->y()<<" ";
  921. s<<o.m_TopWindow->w()<<" "<<o.m_TopWindow->h()<<" ";
  922. s<<0<<" "<<0<<" ";
  923. s<<0<<" "<<0<<endl;
  924. }
  925. // save out the SynthModular
  926. s<<"SectionList"<<endl;
  927. s<<o.m_DeviceWinMap.size()<<endl;
  928. for(map<int,DeviceWin*>::iterator i=o.m_DeviceWinMap.begin();
  929. i!=o.m_DeviceWinMap.end(); i++)
  930. {
  931. if (i->second->m_DeviceGUI && i->second->m_Device)
  932. {
  933. s<<endl;
  934. s<<"Device ";
  935. s<<i->first<<" "; // save the id
  936. s<<"Plugin ";
  937. s<<i->second->m_PluginID<<endl;
  938. s<<i->second->m_DeviceGUI->x()<<" ";
  939. s<<i->second->m_DeviceGUI->y()<<" ";
  940. s<<i->second->m_DeviceGUI->GetName().size()<<" ";
  941. s<<i->second->m_DeviceGUI->GetName()<<" ";
  942. if (i->second->m_DeviceGUI->GetPluginWindow())
  943. {
  944. s<<i->second->m_DeviceGUI->GetPluginWindow()->visible()<<" ";
  945. s<<i->second->m_DeviceGUI->GetPluginWindow()->x()<<" ";
  946. s<<i->second->m_DeviceGUI->GetPluginWindow()->y()<<" ";
  947. }
  948. else
  949. {
  950. s<<0<<" "<<0<<" "<<0;
  951. }
  952. s<<endl;
  953. if (i->second->m_PluginID==COMMENT_ID)
  954. {
  955. // save the comment gui
  956. ((Fl_CommentGUI*)(i->second->m_DeviceGUI))->StreamOut(s);
  957. }
  958. else
  959. {
  960. // save the plugin
  961. i->second->m_Device->StreamOut(s);
  962. }
  963. s<<endl;
  964. // save external files
  965. if (i->second->m_Device && i->second->m_Device->SaveExternalFiles(o.m_FilePath+"_files/"))
  966. {
  967. ExternalDirUsed=true;
  968. }
  969. }
  970. }
  971. s<<endl<<*o.m_Canvas<<endl;
  972. // remove it if it wasn't used
  973. if (!ExternalDirUsed)
  974. {
  975. // i guess rmdir won't work if there is something in the dir
  976. // anyway, but best to be on the safe side. (could do rm -rf) :)
  977. string command("rmdir "+o.m_FilePath+"_files");
  978. system(command.c_str());
  979. }
  980. o.ResumeAudio();
  981. return s;
  982. }
  983. //////////////////////////////////////////////////////////
  984. inline void SynthModular::cb_Close_i(Fl_Window* o, void* v)
  985. {
  986. m_SettingsWindow->hide();
  987. delete m_SettingsWindow;
  988. m_TopWindow->hide();
  989. delete m_TopWindow;
  990. o->hide();
  991. }
  992. void SynthModular::cb_Close(Fl_Window* o, void* v)
  993. {((SynthModular*)(o->user_data()))->cb_Close_i(o,v);}
  994. //////////////////////////////////////////////////////////
  995. inline void SynthModular::cb_Load_i(Fl_Button* o, void* v)
  996. {
  997. if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("Load - Lose changes to current patch?"))
  998. {
  999. return;
  1000. }
  1001. char *fn=fl_file_chooser("Load a patch", "*.ssm", NULL);
  1002. if (fn && fn!='\0')
  1003. {
  1004. ifstream in(fn);
  1005. if (in)
  1006. {
  1007. fstream inf;
  1008. inf.open(fn,ios::in);
  1009. m_FilePath=fn;
  1010. ClearUp();
  1011. inf>>*this;
  1012. inf.close();
  1013. TITLEBAR=LABEL+" "+fn;
  1014. m_TopWindow->label(TITLEBAR.c_str());
  1015. }
  1016. }
  1017. }
  1018. void SynthModular::cb_Load(Fl_Button* o, void* v)
  1019. {((SynthModular*)(o->parent()->user_data()))->cb_Load_i(o,v);}
  1020. //////////////////////////////////////////////////////////
  1021. inline void SynthModular::cb_Save_i(Fl_Button* o, void* v)
  1022. {
  1023. char *fn=fl_file_chooser("Save a patch", "*.ssm", NULL);
  1024. if (fn && fn!='\0')
  1025. {
  1026. ifstream ifl(fn);
  1027. if (ifl)
  1028. {
  1029. if (!Pawfal_YesNo("File [%s] exists, overwrite?",fn))
  1030. {
  1031. return;
  1032. }
  1033. }
  1034. ofstream of(fn);
  1035. if (of)
  1036. {
  1037. m_FilePath=fn;
  1038. of<<*this;
  1039. TITLEBAR=LABEL+" "+fn;
  1040. m_TopWindow->label(TITLEBAR.c_str());
  1041. }
  1042. else
  1043. {
  1044. fl_message(string("Error saving "+string(fn)).c_str());
  1045. }
  1046. }
  1047. }
  1048. void SynthModular::cb_Save(Fl_Button* o, void* v)
  1049. {((SynthModular*)(o->parent()->user_data()))->cb_Save_i(o,v);}
  1050. //////////////////////////////////////////////////////////
  1051. inline void SynthModular::cb_New_i(Fl_Button* o, void* v)
  1052. {
  1053. if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("New - Lose changes to current patch?"))
  1054. {
  1055. return;
  1056. }
  1057. m_TopWindow->label(TITLEBAR.c_str());
  1058. ClearUp();
  1059. }
  1060. void SynthModular::cb_New(Fl_Button* o, void* v)
  1061. {((SynthModular*)(o->parent()->user_data()))->cb_New_i(o,v);}
  1062. //////////////////////////////////////////////////////////
  1063. inline void SynthModular::cb_NewDevice_i(Fl_Button* o, void* v)
  1064. {
  1065. AddDevice(*((int*)v));
  1066. }
  1067. void SynthModular::cb_NewDevice(Fl_Button* o, void* v)
  1068. {((SynthModular*)(o->parent()->user_data()))->cb_NewDevice_i(o,v);}
  1069. //////////////////////////////////////////////////////////
  1070. inline void SynthModular::cb_NewDeviceFromMenu_i(Fl_Canvas* o, void* v)
  1071. {
  1072. AddDevice(*((int*)v),*((int*)v+1),*((int*)v+2));
  1073. }
  1074. void SynthModular::cb_NewDeviceFromMenu(Fl_Canvas* o, void* v)
  1075. {((SynthModular*)(o->user_data()))->cb_NewDeviceFromMenu_i(o,v);}
  1076. //////////////////////////////////////////////////////////
  1077. inline void SynthModular::cb_NewComment_i(Fl_Button* o, void* v)
  1078. {
  1079. AddComment(-1);
  1080. }
  1081. void SynthModular::cb_NewComment(Fl_Button* o, void* v)
  1082. {((SynthModular*)(o->parent()->user_data()))->cb_NewComment_i(o,v);}
  1083. //////////////////////////////////////////////////////////
  1084. inline void SynthModular::cb_GroupTab_i(Fl_Tabs* o, void* v)
  1085. {
  1086. m_GroupTab->redraw();
  1087. }
  1088. void SynthModular::cb_GroupTab(Fl_Tabs* o, void* v)
  1089. {((SynthModular*)(o->parent()->user_data()))->cb_GroupTab_i(o,v);}
  1090. //////////////////////////////////////////////////////////
  1091. inline void SynthModular::cb_Rload_i(Fl_Button* o, void* v)
  1092. {
  1093. m_SettingsWindow->show();
  1094. /*PluginManager::Get()->UnloadAll();
  1095. m_ToolBox->remove(m_ToolPack);
  1096. delete m_ToolPack;
  1097. m_ToolPack = new Fl_Pack(5,20,TOOLBOX_WIDTH-10, TOOLBOX_HEIGHT-40,"");
  1098. m_ToolPack->type(FL_VERTICAL);
  1099. m_ToolPack->box(FL_NO_BOX);
  1100. m_ToolPack->color(SpiralInfo::GUICOL_Tool);
  1101. m_ToolPack->user_data((void*)(this));
  1102. m_ToolBox->add(m_ToolPack);
  1103. m_ToolBox->redraw();
  1104. LoadPlugins();*/
  1105. }
  1106. void SynthModular::cb_Rload(Fl_Button* o, void* v)
  1107. {((SynthModular*)(o->parent()->user_data()))->cb_Rload_i(o,v);}
  1108. //////////////////////////////////////////////////////////
  1109. inline void SynthModular::cb_Connection_i(Fl_Canvas* o, void* v)
  1110. {
  1111. CanvasWire *Wire;
  1112. Wire=(CanvasWire*)v;
  1113. map<int,DeviceWin*>::iterator si=m_DeviceWinMap.find(Wire->OutputID);
  1114. if (si==m_DeviceWinMap.end())
  1115. {
  1116. char num[32];
  1117. sprintf(num,"%d",Wire->OutputID);
  1118. SpiralInfo::Alert("Warning: Connection problem - can't find source "+string(num));
  1119. return;
  1120. }
  1121. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(Wire->InputID);
  1122. if (di==m_DeviceWinMap.end())
  1123. {
  1124. char num[32];
  1125. sprintf(num,"%d",Wire->InputID);
  1126. SpiralInfo::Alert("Warning: Connection problem - can't find destination "+string(num));
  1127. return;
  1128. }
  1129. Sample *sample=NULL;
  1130. if (!si->second->m_Device->GetOutput(Wire->OutputPort,&sample))
  1131. {
  1132. char num[32];
  1133. sprintf(num,"%d,%d",Wire->OutputID,Wire->OutputPort);
  1134. SpiralInfo::Alert("Warning: Connection problem - can't find source output "+string(num));
  1135. return;
  1136. }
  1137. if (!di->second->m_Device->SetInput(Wire->InputPort,(const Sample*)sample))
  1138. {
  1139. char num[32];
  1140. sprintf(num,"%d,%d",Wire->InputID,Wire->InputPort);
  1141. SpiralInfo::Alert("Warning: Connection problem - can't find source input "+string(num));
  1142. return;
  1143. }
  1144. }
  1145. void SynthModular::cb_Connection(Fl_Canvas* o, void* v)
  1146. {((SynthModular*)(o->user_data()))->cb_Connection_i(o,v);}
  1147. //////////////////////////////////////////////////////////
  1148. inline void SynthModular::cb_Unconnect_i(Fl_Canvas* o, void* v)
  1149. {
  1150. CanvasWire *Wire;
  1151. Wire=(CanvasWire*)v;
  1152. //cerr<<Wire->InputID<<" "<<Wire->InputPort<<endl;
  1153. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(Wire->InputID);
  1154. if (di==m_DeviceWinMap.end())
  1155. {
  1156. //cerr<<"Can't find destination device "<<Wire->InputID<<endl;
  1157. return;
  1158. }
  1159. SpiralPlugin *Plugin=di->second->m_Device;
  1160. if (Plugin && !Plugin->SetInput(Wire->InputPort,NULL))
  1161. { cerr<<"Can't find destination device's Input"<<endl; return; }
  1162. }
  1163. void SynthModular::cb_Unconnect(Fl_Canvas* o, void* v)
  1164. {((SynthModular*)(o->user_data()))->cb_Unconnect_i(o,v);}
  1165. //////////////////////////////////////////////////////////
  1166. void SynthModular::cb_UpdatePluginInfo(int ID, void *PInfo)
  1167. {
  1168. map<int,DeviceWin*>::iterator i=m_DeviceWinMap.find(ID);
  1169. if (i!=m_DeviceWinMap.end())
  1170. {
  1171. DeviceGUIInfo Info=BuildDeviceGUIInfo(*((PluginInfo*)PInfo));
  1172. (*i).second->m_DeviceGUI->Setup(Info);
  1173. (*i).second->m_DeviceGUI->redraw();
  1174. }
  1175. }
  1176. //////////////////////////////////////////////////////////
  1177. void SynthModular::LoadPatch(const char *fn)
  1178. {
  1179. ifstream in(fn);
  1180. if (in)
  1181. {
  1182. fstream inf;
  1183. inf.open(fn, std::ios::in);
  1184. m_FilePath=fn;
  1185. ClearUp();
  1186. inf>>*this;
  1187. inf.close();
  1188. TITLEBAR=LABEL+" "+fn;
  1189. m_TopWindow->label(TITLEBAR.c_str());
  1190. }
  1191. }
  1192. //////////////////////////////////////////////////////////