PageRenderTime 501ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/JUCE/examples/audio plugin host/Source/FilterGraph.cpp

https://github.com/plasm-language/pyplasm
C++ | 416 lines | 299 code | 88 blank | 29 comment | 36 complexity | 8cc13ce634eecdab8955956f58482ce3 MD5 | raw file
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../JuceLibraryCode/JuceHeader.h"
  18. #include "MainHostWindow.h"
  19. #include "FilterGraph.h"
  20. #include "InternalFilters.h"
  21. #include "GraphEditorPanel.h"
  22. //==============================================================================
  23. const int FilterGraph::midiChannelNumber = 0x1000;
  24. FilterGraph::FilterGraph (AudioPluginFormatManager& formatManager_)
  25. : FileBasedDocument (filenameSuffix,
  26. filenameWildcard,
  27. "Load a filter graph",
  28. "Save a filter graph"),
  29. formatManager (formatManager_), lastUID (0)
  30. {
  31. InternalPluginFormat internalFormat;
  32. addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioInputFilter), 0.5f, 0.1f);
  33. addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiInputFilter), 0.25f, 0.1f);
  34. addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioOutputFilter), 0.5f, 0.9f);
  35. setChangedFlag (false);
  36. }
  37. FilterGraph::~FilterGraph()
  38. {
  39. graph.clear();
  40. }
  41. uint32 FilterGraph::getNextUID() noexcept
  42. {
  43. return ++lastUID;
  44. }
  45. //==============================================================================
  46. int FilterGraph::getNumFilters() const noexcept
  47. {
  48. return graph.getNumNodes();
  49. }
  50. const AudioProcessorGraph::Node::Ptr FilterGraph::getNode (const int index) const noexcept
  51. {
  52. return graph.getNode (index);
  53. }
  54. const AudioProcessorGraph::Node::Ptr FilterGraph::getNodeForId (const uint32 uid) const noexcept
  55. {
  56. return graph.getNodeForId (uid);
  57. }
  58. void FilterGraph::addFilter (const PluginDescription* desc, double x, double y)
  59. {
  60. if (desc != nullptr)
  61. {
  62. AudioProcessorGraph::Node* node = nullptr;
  63. String errorMessage;
  64. if (AudioPluginInstance* instance = formatManager.createPluginInstance (*desc, graph.getSampleRate(), graph.getBlockSize(), errorMessage))
  65. node = graph.addNode (instance);
  66. if (node != nullptr)
  67. {
  68. node->properties.set ("x", x);
  69. node->properties.set ("y", y);
  70. changed();
  71. }
  72. else
  73. {
  74. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  75. TRANS("Couldn't create filter"),
  76. errorMessage);
  77. }
  78. }
  79. }
  80. void FilterGraph::removeFilter (const uint32 id)
  81. {
  82. PluginWindow::closeCurrentlyOpenWindowsFor (id);
  83. if (graph.removeNode (id))
  84. changed();
  85. }
  86. void FilterGraph::disconnectFilter (const uint32 id)
  87. {
  88. if (graph.disconnectNode (id))
  89. changed();
  90. }
  91. void FilterGraph::removeIllegalConnections()
  92. {
  93. if (graph.removeIllegalConnections())
  94. changed();
  95. }
  96. void FilterGraph::setNodePosition (const int nodeId, double x, double y)
  97. {
  98. const AudioProcessorGraph::Node::Ptr n (graph.getNodeForId (nodeId));
  99. if (n != nullptr)
  100. {
  101. n->properties.set ("x", jlimit (0.0, 1.0, x));
  102. n->properties.set ("y", jlimit (0.0, 1.0, y));
  103. }
  104. }
  105. void FilterGraph::getNodePosition (const int nodeId, double& x, double& y) const
  106. {
  107. x = y = 0;
  108. const AudioProcessorGraph::Node::Ptr n (graph.getNodeForId (nodeId));
  109. if (n != nullptr)
  110. {
  111. x = (double) n->properties ["x"];
  112. y = (double) n->properties ["y"];
  113. }
  114. }
  115. //==============================================================================
  116. int FilterGraph::getNumConnections() const noexcept
  117. {
  118. return graph.getNumConnections();
  119. }
  120. const AudioProcessorGraph::Connection* FilterGraph::getConnection (const int index) const noexcept
  121. {
  122. return graph.getConnection (index);
  123. }
  124. const AudioProcessorGraph::Connection* FilterGraph::getConnectionBetween (uint32 sourceFilterUID, int sourceFilterChannel,
  125. uint32 destFilterUID, int destFilterChannel) const noexcept
  126. {
  127. return graph.getConnectionBetween (sourceFilterUID, sourceFilterChannel,
  128. destFilterUID, destFilterChannel);
  129. }
  130. bool FilterGraph::canConnect (uint32 sourceFilterUID, int sourceFilterChannel,
  131. uint32 destFilterUID, int destFilterChannel) const noexcept
  132. {
  133. return graph.canConnect (sourceFilterUID, sourceFilterChannel,
  134. destFilterUID, destFilterChannel);
  135. }
  136. bool FilterGraph::addConnection (uint32 sourceFilterUID, int sourceFilterChannel,
  137. uint32 destFilterUID, int destFilterChannel)
  138. {
  139. const bool result = graph.addConnection (sourceFilterUID, sourceFilterChannel,
  140. destFilterUID, destFilterChannel);
  141. if (result)
  142. changed();
  143. return result;
  144. }
  145. void FilterGraph::removeConnection (const int index)
  146. {
  147. graph.removeConnection (index);
  148. changed();
  149. }
  150. void FilterGraph::removeConnection (uint32 sourceFilterUID, int sourceFilterChannel,
  151. uint32 destFilterUID, int destFilterChannel)
  152. {
  153. if (graph.removeConnection (sourceFilterUID, sourceFilterChannel,
  154. destFilterUID, destFilterChannel))
  155. changed();
  156. }
  157. void FilterGraph::clear()
  158. {
  159. PluginWindow::closeAllCurrentlyOpenWindows();
  160. graph.clear();
  161. changed();
  162. }
  163. //==============================================================================
  164. String FilterGraph::getDocumentTitle()
  165. {
  166. if (! getFile().exists())
  167. return "Unnamed";
  168. return getFile().getFileNameWithoutExtension();
  169. }
  170. void FilterGraph::newDocument()
  171. {
  172. clear();
  173. setFile (File());
  174. InternalPluginFormat internalFormat;
  175. addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioInputFilter), 0.5f, 0.1f);
  176. addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiInputFilter), 0.25f, 0.1f);
  177. addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioOutputFilter), 0.5f, 0.9f);
  178. setChangedFlag (false);
  179. }
  180. Result FilterGraph::loadDocument (const File& file)
  181. {
  182. XmlDocument doc (file);
  183. ScopedPointer<XmlElement> xml (doc.getDocumentElement());
  184. if (xml == nullptr || ! xml->hasTagName ("FILTERGRAPH"))
  185. return Result::fail ("Not a valid filter graph file");
  186. restoreFromXml (*xml);
  187. return Result::ok();
  188. }
  189. Result FilterGraph::saveDocument (const File& file)
  190. {
  191. ScopedPointer<XmlElement> xml (createXml());
  192. if (! xml->writeToFile (file, String::empty))
  193. return Result::fail ("Couldn't write to the file");
  194. return Result::ok();
  195. }
  196. File FilterGraph::getLastDocumentOpened()
  197. {
  198. RecentlyOpenedFilesList recentFiles;
  199. recentFiles.restoreFromString (getAppProperties().getUserSettings()
  200. ->getValue ("recentFilterGraphFiles"));
  201. return recentFiles.getFile (0);
  202. }
  203. void FilterGraph::setLastDocumentOpened (const File& file)
  204. {
  205. RecentlyOpenedFilesList recentFiles;
  206. recentFiles.restoreFromString (getAppProperties().getUserSettings()
  207. ->getValue ("recentFilterGraphFiles"));
  208. recentFiles.addFile (file);
  209. getAppProperties().getUserSettings()
  210. ->setValue ("recentFilterGraphFiles", recentFiles.toString());
  211. }
  212. //==============================================================================
  213. static XmlElement* createNodeXml (AudioProcessorGraph::Node* const node) noexcept
  214. {
  215. AudioPluginInstance* plugin = dynamic_cast <AudioPluginInstance*> (node->getProcessor());
  216. if (plugin == nullptr)
  217. {
  218. jassertfalse;
  219. return nullptr;
  220. }
  221. XmlElement* e = new XmlElement ("FILTER");
  222. e->setAttribute ("uid", (int) node->nodeId);
  223. e->setAttribute ("x", node->properties ["x"].toString());
  224. e->setAttribute ("y", node->properties ["y"].toString());
  225. for (int i = 0; i < PluginWindow::NumTypes; ++i)
  226. {
  227. PluginWindow::WindowFormatType type = (PluginWindow::WindowFormatType) i;
  228. if (node->properties.contains (getOpenProp (type)))
  229. {
  230. e->setAttribute (getLastXProp (type), node->properties[getLastXProp (type)].toString());
  231. e->setAttribute (getLastYProp (type), node->properties[getLastYProp (type)].toString());
  232. e->setAttribute (getOpenProp (type), node->properties[getOpenProp (type)].toString());
  233. }
  234. }
  235. PluginDescription pd;
  236. plugin->fillInPluginDescription (pd);
  237. e->addChildElement (pd.createXml());
  238. XmlElement* state = new XmlElement ("STATE");
  239. MemoryBlock m;
  240. node->getProcessor()->getStateInformation (m);
  241. state->addTextElement (m.toBase64Encoding());
  242. e->addChildElement (state);
  243. return e;
  244. }
  245. void FilterGraph::createNodeFromXml (const XmlElement& xml)
  246. {
  247. PluginDescription pd;
  248. forEachXmlChildElement (xml, e)
  249. {
  250. if (pd.loadFromXml (*e))
  251. break;
  252. }
  253. String errorMessage;
  254. AudioPluginInstance* instance = formatManager.createPluginInstance (pd, graph.getSampleRate(), graph.getBlockSize(), errorMessage);
  255. if (instance == nullptr)
  256. {
  257. // xxx handle ins + outs
  258. }
  259. if (instance == nullptr)
  260. return;
  261. AudioProcessorGraph::Node::Ptr node (graph.addNode (instance, xml.getIntAttribute ("uid")));
  262. if (const XmlElement* const state = xml.getChildByName ("STATE"))
  263. {
  264. MemoryBlock m;
  265. m.fromBase64Encoding (state->getAllSubText());
  266. node->getProcessor()->setStateInformation (m.getData(), (int) m.getSize());
  267. }
  268. node->properties.set ("x", xml.getDoubleAttribute ("x"));
  269. node->properties.set ("y", xml.getDoubleAttribute ("y"));
  270. for (int i = 0; i < PluginWindow::NumTypes; ++i)
  271. {
  272. PluginWindow::WindowFormatType type = (PluginWindow::WindowFormatType) i;
  273. if (xml.hasAttribute (getOpenProp (type)))
  274. {
  275. node->properties.set (getLastXProp (type), xml.getIntAttribute (getLastXProp (type)));
  276. node->properties.set (getLastYProp (type), xml.getIntAttribute (getLastYProp (type)));
  277. node->properties.set (getOpenProp (type), xml.getIntAttribute (getOpenProp (type)));
  278. if (node->properties[getOpenProp (type)])
  279. {
  280. AudioProcessor* const processor = node->getProcessor();
  281. jassert (processor != nullptr);
  282. if (PluginWindow* const w = PluginWindow::getWindowFor (node, type))
  283. w->toFront (true);
  284. }
  285. }
  286. }
  287. }
  288. XmlElement* FilterGraph::createXml() const
  289. {
  290. XmlElement* xml = new XmlElement ("FILTERGRAPH");
  291. for (int i = 0; i < graph.getNumNodes(); ++i)
  292. xml->addChildElement (createNodeXml (graph.getNode (i)));
  293. for (int i = 0; i < graph.getNumConnections(); ++i)
  294. {
  295. const AudioProcessorGraph::Connection* const fc = graph.getConnection(i);
  296. XmlElement* e = new XmlElement ("CONNECTION");
  297. e->setAttribute ("srcFilter", (int) fc->sourceNodeId);
  298. e->setAttribute ("srcChannel", fc->sourceChannelIndex);
  299. e->setAttribute ("dstFilter", (int) fc->destNodeId);
  300. e->setAttribute ("dstChannel", fc->destChannelIndex);
  301. xml->addChildElement (e);
  302. }
  303. return xml;
  304. }
  305. void FilterGraph::restoreFromXml (const XmlElement& xml)
  306. {
  307. clear();
  308. forEachXmlChildElementWithTagName (xml, e, "FILTER")
  309. {
  310. createNodeFromXml (*e);
  311. changed();
  312. }
  313. forEachXmlChildElementWithTagName (xml, e, "CONNECTION")
  314. {
  315. addConnection ((uint32) e->getIntAttribute ("srcFilter"),
  316. e->getIntAttribute ("srcChannel"),
  317. (uint32) e->getIntAttribute ("dstFilter"),
  318. e->getIntAttribute ("dstChannel"));
  319. }
  320. graph.removeIllegalConnections();
  321. }