External plugins for 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.

428 lines
13KB

  1. /*
  2. * DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others.
  3. * Copyright (C) 2004 Sean Bolton and others
  4. * Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * For a full copy of the GNU General Public License see the LICENSE file.
  17. */
  18. #include "DistrhoPluginNekobi.hpp"
  19. extern "C" {
  20. #include "nekobee-src/nekobee_synth.c"
  21. #include "nekobee-src/nekobee_voice.c"
  22. #include "nekobee-src/nekobee_voice_render.c"
  23. #include "nekobee-src/minblep_tables.c"
  24. // -----------------------------------------------------------------------
  25. // mutual exclusion
  26. bool dssp_voicelist_mutex_trylock(nekobee_synth_t* const synth)
  27. {
  28. /* Attempt the mutex lock */
  29. if (pthread_mutex_trylock(&synth->voicelist_mutex) != 0)
  30. {
  31. synth->voicelist_mutex_grab_failed = 1;
  32. return false;
  33. }
  34. /* Clean up if a previous mutex grab failed */
  35. if (synth->voicelist_mutex_grab_failed)
  36. {
  37. nekobee_synth_all_voices_off(synth);
  38. synth->voicelist_mutex_grab_failed = 0;
  39. }
  40. return true;
  41. }
  42. bool dssp_voicelist_mutex_unlock(nekobee_synth_t* const synth)
  43. {
  44. return (pthread_mutex_unlock(&synth->voicelist_mutex) == 0);
  45. }
  46. // -----------------------------------------------------------------------
  47. // nekobee_handle_raw_event
  48. void nekobee_handle_raw_event(nekobee_synth_t* const synth, const uint8_t size, const uint8_t* const data)
  49. {
  50. if (size != 3)
  51. return;
  52. switch (data[0] & 0xf0)
  53. {
  54. case 0x80:
  55. nekobee_synth_note_off(synth, data[1], data[2]);
  56. break;
  57. case 0x90:
  58. if (data[2] > 0)
  59. nekobee_synth_note_on(synth, data[1], data[2]);
  60. else
  61. nekobee_synth_note_off(synth, data[1], 64); /* shouldn't happen, but... */
  62. break;
  63. case 0xB0:
  64. nekobee_synth_control_change(synth, data[1], data[2]);
  65. break;
  66. default:
  67. break;
  68. }
  69. }
  70. } /* extern "C" */
  71. START_NAMESPACE_DISTRHO
  72. // -----------------------------------------------------------------------
  73. DistrhoPluginNekobi::DistrhoPluginNekobi()
  74. : Plugin(paramCount, 0, 0) // 0 programs, 0 states
  75. {
  76. nekobee_init_tables();
  77. // init synth
  78. fSynth.sample_rate = getSampleRate();
  79. fSynth.deltat = 1.0f / (float)getSampleRate();
  80. fSynth.nugget_remains = 0;
  81. fSynth.note_id = 0;
  82. fSynth.polyphony = XSYNTH_DEFAULT_POLYPHONY;
  83. fSynth.voices = XSYNTH_DEFAULT_POLYPHONY;
  84. fSynth.monophonic = XSYNTH_MONO_MODE_ONCE;
  85. fSynth.glide = 0;
  86. fSynth.last_noteon_pitch = 0.0f;
  87. fSynth.vcf_accent = 0.0f;
  88. fSynth.vca_accent = 0.0f;
  89. for (int i=0; i<8; ++i)
  90. fSynth.held_keys[i] = -1;
  91. fSynth.voice = nekobee_voice_new();
  92. fSynth.voicelist_mutex_grab_failed = 0;
  93. pthread_mutex_init(&fSynth.voicelist_mutex, nullptr);
  94. fSynth.channel_pressure = 0;
  95. fSynth.pitch_wheel_sensitivity = 0;
  96. fSynth.pitch_wheel = 0;
  97. for (int i=0; i<128; ++i)
  98. {
  99. fSynth.key_pressure[i] = 0;
  100. fSynth.cc[i] = 0;
  101. }
  102. fSynth.cc[7] = 127; // full volume
  103. fSynth.mod_wheel = 1.0f;
  104. fSynth.pitch_bend = 1.0f;
  105. fSynth.cc_volume = 1.0f;
  106. // Default values
  107. fParams.waveform = 0.0f;
  108. fParams.tuning = 0.0f;
  109. fParams.cutoff = 25.0f;
  110. fParams.resonance = 25.0f;
  111. fParams.envMod = 50.0f;
  112. fParams.decay = 75.0f;
  113. fParams.accent = 25.0f;
  114. fParams.volume = 75.0f;
  115. fParams.bypass = false;
  116. // Internal stuff
  117. fSynth.waveform = 0.0f;
  118. fSynth.tuning = 1.0f;
  119. fSynth.cutoff = 5.0f;
  120. fSynth.resonance = 0.8f;
  121. fSynth.envmod = 0.3f;
  122. fSynth.decay = 0.0002f;
  123. fSynth.accent = 0.3f;
  124. fSynth.volume = 0.75f;
  125. // reset
  126. deactivate();
  127. }
  128. DistrhoPluginNekobi::~DistrhoPluginNekobi()
  129. {
  130. std::free(fSynth.voice);
  131. }
  132. // -----------------------------------------------------------------------
  133. // Init
  134. void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter)
  135. {
  136. switch (index)
  137. {
  138. case paramWaveform:
  139. parameter.hints = kParameterIsAutomatable|kParameterIsInteger;
  140. parameter.name = "Waveform";
  141. parameter.symbol = "waveform";
  142. parameter.ranges.def = 0.0f;
  143. parameter.ranges.min = 0.0f;
  144. parameter.ranges.max = 1.0f;
  145. parameter.enumValues.count = 2;
  146. parameter.enumValues.restrictedMode = true;
  147. {
  148. ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[2];
  149. enumValues[0].value = 0.0f;
  150. enumValues[0].label = "Square";
  151. enumValues[1].value = 1.0f;
  152. enumValues[1].label = "Triangle";
  153. parameter.enumValues.values = enumValues;
  154. }
  155. break;
  156. case paramTuning:
  157. parameter.hints = kParameterIsAutomatable; // was 0.5 <-> 2.0, log
  158. parameter.name = "Tuning";
  159. parameter.symbol = "tuning";
  160. parameter.ranges.def = 0.0f;
  161. parameter.ranges.min = -12.0f;
  162. parameter.ranges.max = 12.0f;
  163. break;
  164. case paramCutoff:
  165. parameter.hints = kParameterIsAutomatable; // modified x2.5
  166. parameter.name = "Cutoff";
  167. parameter.symbol = "cutoff";
  168. parameter.unit = "%";
  169. parameter.ranges.def = 25.0f;
  170. parameter.ranges.min = 0.0f;
  171. parameter.ranges.max = 100.0f;
  172. break;
  173. case paramResonance:
  174. parameter.hints = kParameterIsAutomatable; // modified x100
  175. parameter.name = "VCF Resonance";
  176. parameter.symbol = "resonance";
  177. parameter.unit = "%";
  178. parameter.ranges.def = 25.0f;
  179. parameter.ranges.min = 0.0f;
  180. parameter.ranges.max = 95.0f;
  181. break;
  182. case paramEnvMod:
  183. parameter.hints = kParameterIsAutomatable; // modified x100
  184. parameter.name = "Env Mod";
  185. parameter.symbol = "env_mod";
  186. parameter.unit = "%";
  187. parameter.ranges.def = 50.0f;
  188. parameter.ranges.min = 0.0f;
  189. parameter.ranges.max = 100.0f;
  190. break;
  191. case paramDecay:
  192. parameter.hints = kParameterIsAutomatable; // was 0.000009 <-> 0.0005, log
  193. parameter.name = "Decay";
  194. parameter.symbol = "decay";
  195. parameter.unit = "%";
  196. parameter.ranges.def = 75.0f;
  197. parameter.ranges.min = 0.0f;
  198. parameter.ranges.max = 100.0f;
  199. break;
  200. case paramAccent:
  201. parameter.hints = kParameterIsAutomatable; // modified x100
  202. parameter.name = "Accent";
  203. parameter.symbol = "accent";
  204. parameter.unit = "%";
  205. parameter.ranges.def = 25.0f;
  206. parameter.ranges.min = 0.0f;
  207. parameter.ranges.max = 100.0f;
  208. break;
  209. case paramVolume:
  210. parameter.hints = kParameterIsAutomatable; // modified x100
  211. parameter.name = "Volume";
  212. parameter.symbol = "volume";
  213. parameter.unit = "%";
  214. parameter.ranges.def = 75.0f;
  215. parameter.ranges.min = 0.0f;
  216. parameter.ranges.max = 100.0f;
  217. break;
  218. case paramBypass:
  219. parameter.initDesignation(kParameterDesignationBypass);
  220. break;
  221. }
  222. }
  223. // -----------------------------------------------------------------------
  224. // Internal data
  225. float DistrhoPluginNekobi::getParameterValue(uint32_t index) const
  226. {
  227. switch (index)
  228. {
  229. case paramWaveform:
  230. return fParams.waveform;
  231. case paramTuning:
  232. return fParams.tuning;
  233. case paramCutoff:
  234. return fParams.cutoff;
  235. case paramResonance:
  236. return fParams.resonance;
  237. case paramEnvMod:
  238. return fParams.envMod;
  239. case paramDecay:
  240. return fParams.decay;
  241. case paramAccent:
  242. return fParams.accent;
  243. case paramVolume:
  244. return fParams.volume;
  245. case paramBypass:
  246. return fParams.bypass ? 1.0f : 0.0f;
  247. }
  248. return 0.0f;
  249. }
  250. void DistrhoPluginNekobi::setParameterValue(uint32_t index, float value)
  251. {
  252. switch (index)
  253. {
  254. case paramWaveform:
  255. fParams.waveform = value;
  256. fSynth.waveform = value;
  257. DISTRHO_SAFE_ASSERT(fSynth.waveform == 0.0f || fSynth.waveform == 1.0f);
  258. break;
  259. case paramTuning:
  260. fParams.tuning = value;
  261. fSynth.tuning = (value+12.0f)/24.0f * 1.5 + 0.5f; // FIXME: log?
  262. DISTRHO_SAFE_ASSERT(fSynth.tuning >= 0.5f && fSynth.tuning <= 2.0f);
  263. break;
  264. case paramCutoff:
  265. fParams.cutoff = value;
  266. fSynth.cutoff = value/2.5f;
  267. DISTRHO_SAFE_ASSERT(fSynth.cutoff >= 0.0f && fSynth.cutoff <= 40.0f);
  268. break;
  269. case paramResonance:
  270. fParams.resonance = value;
  271. fSynth.resonance = value/100.0f;
  272. DISTRHO_SAFE_ASSERT(fSynth.resonance >= 0.0f && fSynth.resonance <= 0.95f);
  273. break;
  274. case paramEnvMod:
  275. fParams.envMod = value;
  276. fSynth.envmod = value/100.0f;
  277. DISTRHO_SAFE_ASSERT(fSynth.envmod >= 0.0f && fSynth.envmod <= 1.0f);
  278. break;
  279. case paramDecay:
  280. fParams.decay = value;
  281. fSynth.decay = value/100.0f * 0.000491f + 0.000009f; // FIXME: log?
  282. DISTRHO_SAFE_ASSERT(fSynth.decay >= 0.000009f && fSynth.decay <= 0.0005f);
  283. break;
  284. case paramAccent:
  285. fParams.accent = value;
  286. fSynth.accent = value/100.0f;
  287. DISTRHO_SAFE_ASSERT(fSynth.accent >= 0.0f && fSynth.accent <= 1.0f);
  288. break;
  289. case paramVolume:
  290. fParams.volume = value;
  291. fSynth.volume = value/100.0f;
  292. DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f);
  293. break;
  294. case paramBypass: {
  295. const bool bypass = (value > 0.5f);
  296. if (fParams.bypass != bypass)
  297. {
  298. fParams.bypass = bypass;
  299. nekobee_synth_all_voices_off(&fSynth);
  300. }
  301. } break;
  302. }
  303. }
  304. // -----------------------------------------------------------------------
  305. // Process
  306. void DistrhoPluginNekobi::activate()
  307. {
  308. fSynth.nugget_remains = 0;
  309. fSynth.note_id = 0;
  310. if (fSynth.voice != nullptr)
  311. nekobee_synth_all_voices_off(&fSynth);
  312. }
  313. void DistrhoPluginNekobi::deactivate()
  314. {
  315. if (fSynth.voice != nullptr)
  316. nekobee_synth_all_voices_off(&fSynth);
  317. }
  318. void DistrhoPluginNekobi::run(const float* const*, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
  319. {
  320. uint32_t framesDone = 0;
  321. uint32_t curEventIndex = 0;
  322. uint32_t burstSize;
  323. float* out = outputs[0];
  324. if (fSynth.voice == nullptr || ! dssp_voicelist_mutex_trylock(&fSynth))
  325. {
  326. std::memset(out, 0, sizeof(float)*frames);
  327. return;
  328. }
  329. // ignore midi input if bypassed
  330. if (fParams.bypass)
  331. midiEventCount = 0;
  332. while (framesDone < frames)
  333. {
  334. if (fSynth.nugget_remains == 0)
  335. fSynth.nugget_remains = XSYNTH_NUGGET_SIZE;
  336. /* process any ready events */
  337. while (curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame)
  338. {
  339. if (midiEvents[curEventIndex].size > MidiEvent::kDataSize)
  340. continue;
  341. nekobee_handle_raw_event(&fSynth, midiEvents[curEventIndex].size, midiEvents[curEventIndex].data);
  342. curEventIndex++;
  343. }
  344. /* calculate the sample count (burstSize) for the next nekobee_voice_render() call to be the smallest of:
  345. * - control calculation quantization size (XSYNTH_NUGGET_SIZE, in samples)
  346. * - the number of samples remaining in an already-begun nugget (synth->nugget_remains)
  347. * - the number of samples until the next event is ready
  348. * - the number of samples left in this run
  349. */
  350. burstSize = XSYNTH_NUGGET_SIZE;
  351. /* we're still in the middle of a nugget, so reduce the burst size
  352. * to end when the nugget ends */
  353. if (fSynth.nugget_remains < burstSize)
  354. burstSize = fSynth.nugget_remains;
  355. /* reduce burst size to end when next event is ready */
  356. if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame - framesDone < burstSize)
  357. burstSize = midiEvents[curEventIndex].frame - framesDone;
  358. /* reduce burst size to end at end of this run */
  359. if (frames - framesDone < burstSize)
  360. burstSize = frames - framesDone;
  361. /* render the burst */
  362. nekobee_synth_render_voices(&fSynth, out + framesDone, burstSize, (burstSize == fSynth.nugget_remains));
  363. framesDone += burstSize;
  364. fSynth.nugget_remains -= burstSize;
  365. }
  366. dssp_voicelist_mutex_unlock(&fSynth);
  367. }
  368. // -----------------------------------------------------------------------
  369. Plugin* createPlugin()
  370. {
  371. return new DistrhoPluginNekobi();
  372. }
  373. // -----------------------------------------------------------------------
  374. END_NAMESPACE_DISTRHO