Audio plugin host https://kx.studio/carla
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.

380 lines
11KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the GPL.txt file
  16. */
  17. // for UINT32_MAX
  18. #define __STDC_LIMIT_MACROS
  19. #include <cstdint>
  20. #include "CarlaNative.hpp"
  21. #include "CarlaMIDI.h"
  22. #include "CarlaString.hpp"
  23. #include "zynaddsubfx/Misc/Master.h"
  24. #include "zynaddsubfx/Misc/Util.h"
  25. #include <ctime>
  26. // Dummy variables and functions for linking purposes
  27. class WavFile;
  28. namespace Nio {
  29. bool start(void){return 1;}
  30. void stop(void){}
  31. void waveNew(WavFile*){}
  32. void waveStart(void){}
  33. void waveStop(void){}
  34. void waveEnd(void){}
  35. }
  36. SYNTH_T* synth = nullptr;
  37. class ZynAddSubFxPlugin : public PluginDescriptorClass
  38. {
  39. public:
  40. enum Parameters {
  41. PARAMETER_COUNT = 0
  42. };
  43. ZynAddSubFxPlugin(const HostDescriptor* const host)
  44. : PluginDescriptorClass(host),
  45. m_master(new Master)
  46. {
  47. // refresh banks
  48. m_master->bank.rescanforbanks();
  49. for (uint32_t i=0, size = m_master->bank.banks.size(); i < size; i++)
  50. {
  51. if (m_master->bank.banks[i].dir.empty())
  52. continue;
  53. m_master->bank.loadbank(m_master->bank.banks[i].dir);
  54. for (unsigned int instrument = 0; instrument < BANK_SIZE; instrument++)
  55. {
  56. const std::string insName(m_master->bank.getname(instrument));
  57. if (insName.empty() || insName[0] == '\0' || insName[0] == ' ')
  58. continue;
  59. ProgramInfo pInfo(i, instrument, insName.c_str());
  60. m_programs.push_back(pInfo);
  61. }
  62. }
  63. }
  64. ~ZynAddSubFxPlugin()
  65. {
  66. //ensure that everything has stopped with the mutex wait
  67. pthread_mutex_lock(&m_master->mutex);
  68. pthread_mutex_unlock(&m_master->mutex);
  69. m_programs.clear();
  70. delete m_master;
  71. }
  72. protected:
  73. // -------------------------------------------------------------------
  74. // Plugin parameter calls
  75. uint32_t getParameterCount()
  76. {
  77. return PARAMETER_COUNT;
  78. }
  79. const Parameter* getParameterInfo(const uint32_t index)
  80. {
  81. CARLA_ASSERT(index < getParameterCount());
  82. //if (index >= PARAMETER_COUNT)
  83. return nullptr;
  84. static Parameter param;
  85. param.ranges.step = PARAMETER_RANGES_DEFAULT_STEP;
  86. param.ranges.stepSmall = PARAMETER_RANGES_DEFAULT_STEP_SMALL;
  87. param.ranges.stepLarge = PARAMETER_RANGES_DEFAULT_STEP_LARGE;
  88. param.scalePointCount = 0;
  89. param.scalePoints = nullptr;
  90. switch (index)
  91. {
  92. #if 0
  93. case PARAMETER_MASTER:
  94. param.hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE;
  95. param.name = "Master Volume";
  96. param.unit = nullptr;
  97. param.ranges.min = 0.0f;
  98. param.ranges.max = 100.0f;
  99. param.ranges.def = 100.0f;
  100. break;
  101. #endif
  102. }
  103. return &param;
  104. }
  105. float getParameterValue(const uint32_t index)
  106. {
  107. CARLA_ASSERT(index < getParameterCount());
  108. switch (index)
  109. {
  110. #if 0
  111. case PARAMETER_MASTER:
  112. return m_master->Pvolume;
  113. #endif
  114. default:
  115. return 0.0f;
  116. }
  117. }
  118. // -------------------------------------------------------------------
  119. // Plugin midi-program calls
  120. uint32_t getMidiProgramCount()
  121. {
  122. return m_programs.size();
  123. }
  124. const MidiProgram* getMidiProgramInfo(const uint32_t index)
  125. {
  126. CARLA_ASSERT(index < getMidiProgramCount());
  127. if (index >= m_programs.size())
  128. return nullptr;
  129. const ProgramInfo& pInfo(m_programs[index]);
  130. static MidiProgram midiProgram;
  131. midiProgram.bank = pInfo.bank;
  132. midiProgram.program = pInfo.prog;
  133. midiProgram.name = pInfo.name;
  134. return &midiProgram;
  135. }
  136. // -------------------------------------------------------------------
  137. // Plugin state calls
  138. void setParameterValue(const uint32_t index, const float value)
  139. {
  140. CARLA_ASSERT(index < getParameterCount());
  141. switch (index)
  142. {
  143. }
  144. return;
  145. // unused, TODO
  146. (void)value;
  147. }
  148. void setMidiProgram(const uint32_t bank, const uint32_t program)
  149. {
  150. if (bank >= m_master->bank.banks.size())
  151. return;
  152. if (program >= BANK_SIZE)
  153. return;
  154. const std::string bankdir(m_master->bank.banks[bank].dir);
  155. if (! bankdir.empty())
  156. {
  157. pthread_mutex_lock(&m_master->mutex);
  158. m_master->bank.loadbank(bankdir);
  159. m_master->bank.loadfromslot(program, m_master->part[0]);
  160. pthread_mutex_unlock(&m_master->mutex);
  161. }
  162. }
  163. // -------------------------------------------------------------------
  164. // Plugin process calls
  165. void activate()
  166. {
  167. m_master->setController(0, MIDI_CONTROL_ALL_SOUND_OFF, 0);
  168. }
  169. void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const MidiEvent* const midiEvents)
  170. {
  171. if (pthread_mutex_trylock(&m_master->mutex) != 0)
  172. {
  173. carla_zeroFloat(outBuffer[0], frames);
  174. carla_zeroFloat(outBuffer[1], frames);
  175. return;
  176. }
  177. uint32_t fromFrame = 0;
  178. uint32_t eventIndex = 0;
  179. uint32_t nextEventFrame = 0;
  180. uint32_t toFrame = 0;
  181. do {
  182. // Find the time of the next event, if any
  183. if (eventIndex >= midiEventCount)
  184. nextEventFrame = UINT32_MAX;
  185. else
  186. nextEventFrame = midiEvents[eventIndex].time;
  187. // find the end of the sub-sample to be processed this time round...
  188. // if the next event falls within the desired sample interval...
  189. if ((nextEventFrame < frames) && (nextEventFrame >= toFrame))
  190. // set the end to be at that event
  191. toFrame = nextEventFrame;
  192. else
  193. // ...else go for the whole remaining sample
  194. toFrame = frames;
  195. if (fromFrame < toFrame)
  196. {
  197. // call master to fill from `fromFrame` to `toFrame`:
  198. m_master->GetAudioOutSamples(toFrame - fromFrame, (unsigned)getSampleRate(), &outBuffer[0][fromFrame], &outBuffer[1][fromFrame]);
  199. // next sub-sample please...
  200. fromFrame = toFrame;
  201. }
  202. // Now process any event(s) at the current timing point
  203. while (eventIndex < midiEventCount && midiEvents[eventIndex].time == toFrame)
  204. {
  205. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvents[eventIndex].data);
  206. const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvents[eventIndex].data);
  207. if (MIDI_IS_STATUS_NOTE_OFF(status))
  208. {
  209. const uint8_t note = midiEvents[eventIndex].data[1];
  210. m_master->noteOff(channel, note);
  211. }
  212. else if (MIDI_IS_STATUS_NOTE_ON(status))
  213. {
  214. const uint8_t note = midiEvents[eventIndex].data[1];
  215. const uint8_t velo = midiEvents[eventIndex].data[2];
  216. m_master->noteOn(channel, note, velo);
  217. }
  218. else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
  219. {
  220. const uint8_t note = midiEvents[eventIndex].data[1];
  221. const uint8_t pressure = midiEvents[eventIndex].data[2];
  222. m_master->polyphonicAftertouch(channel, note, pressure);
  223. }
  224. eventIndex++;
  225. }
  226. // Keep going until we have the desired total length of sample...
  227. } while (toFrame < frames);
  228. pthread_mutex_unlock(&m_master->mutex);
  229. }
  230. // -------------------------------------------------------------------
  231. private:
  232. struct ProgramInfo {
  233. uint32_t bank;
  234. uint32_t prog;
  235. CarlaString name;
  236. ProgramInfo(uint32_t bank_, uint32_t prog_, const char* name_)
  237. : bank(bank_),
  238. prog(prog_),
  239. name(name_) {}
  240. ProgramInfo() = delete;
  241. };
  242. std::vector<ProgramInfo> m_programs;
  243. Master* const m_master;
  244. public:
  245. static int s_instanceCount;
  246. static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
  247. {
  248. if (s_instanceCount++ == 0)
  249. {
  250. synth = new SYNTH_T;
  251. synth->buffersize = host->get_buffer_size(host->handle);
  252. synth->samplerate = host->get_sample_rate(host->handle);
  253. synth->alias();
  254. config.init();
  255. config.cfg.SoundBufferSize = synth->buffersize;
  256. config.cfg.SampleRate = synth->samplerate;
  257. config.cfg.GzipCompression = 0;
  258. sprng(std::time(nullptr));
  259. denormalkillbuf = new float[synth->buffersize];
  260. for (int i=0; i < synth->buffersize; i++)
  261. denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
  262. }
  263. return new ZynAddSubFxPlugin(host);
  264. }
  265. static void _cleanup(PluginHandle handle)
  266. {
  267. delete (ZynAddSubFxPlugin*)handle;
  268. if (--s_instanceCount == 0)
  269. {
  270. delete[] denormalkillbuf;
  271. denormalkillbuf = nullptr;
  272. delete synth;
  273. synth = nullptr;
  274. }
  275. }
  276. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin)
  277. };
  278. int ZynAddSubFxPlugin::s_instanceCount = 0;
  279. // -----------------------------------------------------------------------
  280. static const PluginDescriptor zynAddSubFxDesc = {
  281. /* category */ PLUGIN_CATEGORY_SYNTH,
  282. /* hints */ PLUGIN_IS_SYNTH,
  283. /* audioIns */ 2,
  284. /* audioOuts */ 2,
  285. /* midiIns */ 1,
  286. /* midiOuts */ 0,
  287. /* paramIns */ ZynAddSubFxPlugin::PARAMETER_COUNT,
  288. /* paramOuts */ 0,
  289. /* name */ "ZynAddSubFX",
  290. /* label */ "zynaddsubfx",
  291. /* maker */ "falkTX",
  292. /* copyright */ "GNU GPL v2+",
  293. PluginDescriptorFILL(ZynAddSubFxPlugin)
  294. };
  295. // -----------------------------------------------------------------------
  296. void carla_register_native_plugin_zynaddsubfx()
  297. {
  298. carla_register_native_plugin(&zynAddSubFxDesc);
  299. }
  300. // -----------------------------------------------------------------------