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.

1594 lines
41KB

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