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.

423 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 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 GPL.txt file
  17. */
  18. #include "DistrhoPluginNekobi.hpp"
  19. #include "CarlaUtils.hpp"
  20. extern "C" {
  21. #include "nekobee-src/nekobee_synth.c"
  22. #include "nekobee-src/nekobee_voice.c"
  23. #include "nekobee-src/nekobee_voice_render.c"
  24. #include "nekobee-src/minblep_tables.c"
  25. /* ---- mutual exclusion ---- */
  26. bool dssp_voicelist_mutex_trylock(nekobee_synth_t* 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_lock(nekobee_synth_t* synth)
  43. {
  44. return (pthread_mutex_lock(&synth->voicelist_mutex) == 0);
  45. }
  46. bool dssp_voicelist_mutex_unlock(nekobee_synth_t *synth)
  47. {
  48. return (pthread_mutex_unlock(&synth->voicelist_mutex) == 0);
  49. }
  50. /*
  51. * nekobee_handle_raw_event
  52. */
  53. void nekobee_handle_raw_event(nekobee_synth_t* synth, uint8_t size, const uint8_t* data)
  54. {
  55. if (size != 3)
  56. return;
  57. switch (data[0] & 0xf0)
  58. {
  59. case 0x80:
  60. nekobee_synth_note_off(synth, data[1], data[2]);
  61. break;
  62. case 0x90:
  63. if (data[2] > 0)
  64. nekobee_synth_note_on(synth, data[1], data[2]);
  65. else
  66. nekobee_synth_note_off(synth, data[1], 64); /* shouldn't happen, but... */
  67. break;
  68. case 0xB0:
  69. nekobee_synth_control_change(synth, data[1], data[2]);
  70. break;
  71. default:
  72. break;
  73. }
  74. }
  75. } /* extern "C" */
  76. START_NAMESPACE_DISTRHO
  77. // -------------------------------------------------
  78. DistrhoPluginNekobi::DistrhoPluginNekobi()
  79. : Plugin(paramCount, 1, 0) // 1 program, 0 states
  80. {
  81. nekobee_init_tables();
  82. // init synth
  83. fSynth = new nekobee_synth_t;
  84. fSynth->sample_rate = d_sampleRate();
  85. fSynth->deltat = 1.0f / (float)d_sampleRate();
  86. fSynth->nugget_remains = 0;
  87. fSynth->note_id = 0;
  88. fSynth->polyphony = XSYNTH_DEFAULT_POLYPHONY;
  89. fSynth->voices = XSYNTH_DEFAULT_POLYPHONY;
  90. fSynth->monophonic = XSYNTH_MONO_MODE_ONCE;
  91. fSynth->glide = 0;
  92. fSynth->last_noteon_pitch = 0.0f;
  93. fSynth->vcf_accent = 0.0f;
  94. fSynth->vca_accent = 0.0f;
  95. for (int i=0; i<8; ++i)
  96. fSynth->held_keys[i] = -1;
  97. fSynth->voice = nekobee_voice_new();
  98. fSynth->voicelist_mutex_grab_failed = 0;
  99. pthread_mutex_init(&fSynth->voicelist_mutex, NULL);
  100. fSynth->channel_pressure = 0;
  101. fSynth->pitch_wheel_sensitivity = 0;
  102. fSynth->pitch_wheel = 0;
  103. for (int i=0; i<128; ++i)
  104. {
  105. fSynth->key_pressure[i] = 0;
  106. fSynth->cc[i] = 0;
  107. }
  108. fSynth->cc[7] = 127; // full volume
  109. fSynth->mod_wheel = 1.0f;
  110. fSynth->pitch_bend = 1.0f;
  111. fSynth->cc_volume = 1.0f;
  112. // set default values
  113. d_setProgram(0);
  114. // reset
  115. d_deactivate();
  116. }
  117. DistrhoPluginNekobi::~DistrhoPluginNekobi()
  118. {
  119. free(fSynth->voice);
  120. delete fSynth;
  121. }
  122. // -------------------------------------------------
  123. // Init
  124. void DistrhoPluginNekobi::d_initParameter(uint32_t index, Parameter& parameter)
  125. {
  126. switch (index)
  127. {
  128. case paramWaveform:
  129. parameter.hints = PARAMETER_IS_AUTOMABLE|PARAMETER_IS_BOOLEAN;
  130. parameter.name = "Waveform";
  131. parameter.symbol = "waveform";
  132. parameter.ranges.def = 0.0f;
  133. parameter.ranges.min = 0.0f;
  134. parameter.ranges.max = 1.0f;
  135. break;
  136. case paramTuning:
  137. parameter.hints = PARAMETER_IS_AUTOMABLE; // was 0.5 <-> 2.0, log
  138. parameter.name = "Tuning";
  139. parameter.symbol = "tuning";
  140. parameter.ranges.def = 0.0f;
  141. parameter.ranges.min = -12.0f;
  142. parameter.ranges.max = 12.0f;
  143. break;
  144. case paramCutoff:
  145. parameter.hints = PARAMETER_IS_AUTOMABLE; // modified x2.5
  146. parameter.name = "Cutoff";
  147. parameter.symbol = "cutoff";
  148. parameter.unit = "%";
  149. parameter.ranges.def = 25.0f;
  150. parameter.ranges.min = 0.0f;
  151. parameter.ranges.max = 100.0f;
  152. break;
  153. case paramResonance:
  154. parameter.hints = PARAMETER_IS_AUTOMABLE; // modified x100
  155. parameter.name = "VCF Resonance";
  156. parameter.symbol = "resonance";
  157. parameter.unit = "%";
  158. parameter.ranges.def = 25.0f;
  159. parameter.ranges.min = 0.0f;
  160. parameter.ranges.max = 95.0f;
  161. break;
  162. case paramEnvMod:
  163. parameter.hints = PARAMETER_IS_AUTOMABLE; // modified x100
  164. parameter.name = "Env Mod";
  165. parameter.symbol = "env_mod";
  166. parameter.unit = "%";
  167. parameter.ranges.def = 50.0f;
  168. parameter.ranges.min = 0.0f;
  169. parameter.ranges.max = 100.0f;
  170. break;
  171. case paramDecay:
  172. parameter.hints = PARAMETER_IS_AUTOMABLE; // was 0.000009 <-> 0.0005, log
  173. parameter.name = "Decay";
  174. parameter.symbol = "decay";
  175. parameter.unit = "%";
  176. parameter.ranges.def = 75.0f;
  177. parameter.ranges.min = 0.0f;
  178. parameter.ranges.max = 100.0f;
  179. break;
  180. case paramAccent:
  181. parameter.hints = PARAMETER_IS_AUTOMABLE; // modified x100
  182. parameter.name = "Accent";
  183. parameter.symbol = "accent";
  184. parameter.unit = "%";
  185. parameter.ranges.def = 25.0f;
  186. parameter.ranges.min = 0.0f;
  187. parameter.ranges.max = 100.0f;
  188. break;
  189. case paramVolume:
  190. parameter.hints = PARAMETER_IS_AUTOMABLE; // modified x100
  191. parameter.name = "Volume";
  192. parameter.symbol = "volume";
  193. parameter.unit = "%";
  194. parameter.ranges.def = 75.0f;
  195. parameter.ranges.min = 0.0f;
  196. parameter.ranges.max = 100.0f;
  197. break;
  198. }
  199. }
  200. void DistrhoPluginNekobi::d_initProgramName(uint32_t index, d_string& programName)
  201. {
  202. if (index != 0)
  203. return;
  204. programName = "Default";
  205. }
  206. // -------------------------------------------------
  207. // Internal data
  208. float DistrhoPluginNekobi::d_parameterValue(uint32_t index)
  209. {
  210. switch (index)
  211. {
  212. case paramWaveform:
  213. return fParams.waveform;
  214. case paramTuning:
  215. return fParams.tuning;
  216. case paramCutoff:
  217. return fParams.cutoff;
  218. case paramResonance:
  219. return fParams.resonance;
  220. case paramEnvMod:
  221. return fParams.envMod;
  222. case paramDecay:
  223. return fParams.decay;
  224. case paramAccent:
  225. return fParams.accent;
  226. case paramVolume:
  227. return fParams.volume;
  228. }
  229. return 0.0f;
  230. }
  231. void DistrhoPluginNekobi::d_setParameterValue(uint32_t index, float value)
  232. {
  233. switch (index)
  234. {
  235. case paramWaveform:
  236. fParams.waveform = value;
  237. fSynth->waveform = value;
  238. CARLA_SAFE_ASSERT_INT2(fSynth->waveform == 0.0f || fSynth->waveform == 1.0f, fSynth->waveform, value);
  239. break;
  240. case paramTuning:
  241. fParams.tuning = value;
  242. fSynth->tuning = (value+12.0f)/24.0f * 1.5 + 0.5f; // FIXME: log?
  243. CARLA_SAFE_ASSERT_INT2(fSynth->tuning >= 0.5f && fSynth->tuning <= 2.0f, fSynth->tuning, value);
  244. break;
  245. case paramCutoff:
  246. fParams.cutoff = value;
  247. fSynth->cutoff = value/2.5f;
  248. CARLA_SAFE_ASSERT_INT2(fSynth->cutoff >= 0.0f && fSynth->cutoff <= 40.0f, fSynth->cutoff, value);
  249. break;
  250. case paramResonance:
  251. fParams.resonance = value;
  252. fSynth->resonance = value/100.0f;
  253. CARLA_SAFE_ASSERT_INT2(fSynth->resonance >= 0.0f && fSynth->resonance <= 0.95f, fSynth->resonance, value);
  254. break;
  255. case paramEnvMod:
  256. fParams.envMod = value;
  257. fSynth->envmod = value/100.0f;
  258. CARLA_SAFE_ASSERT_INT2(fSynth->envmod >= 0.0f && fSynth->envmod <= 1.0f, fSynth->envmod, value);
  259. break;
  260. case paramDecay:
  261. fParams.decay = value;
  262. fSynth->decay = value/100.0f * 0.000491f + 0.000009f; // FIXME: log?
  263. CARLA_SAFE_ASSERT_INT2(fSynth->decay >= 0.000009f && fSynth->decay <= 0.0005f, fSynth->decay, value);
  264. break;
  265. case paramAccent:
  266. fParams.accent = value;
  267. fSynth->accent = value/100.0f;
  268. CARLA_SAFE_ASSERT_INT2(fSynth->accent >= 0.0f && fSynth->accent <= 1.0f, fSynth->accent, value);
  269. break;
  270. case paramVolume:
  271. fParams.volume = value;
  272. fSynth->volume = value/100.0f;
  273. CARLA_SAFE_ASSERT_INT2(fSynth->volume >= 0.0f && fSynth->volume <= 1.0f, fSynth->volume, value);
  274. break;
  275. }
  276. }
  277. void DistrhoPluginNekobi::d_setProgram(uint32_t index)
  278. {
  279. if (index != 0)
  280. return;
  281. // Default values
  282. fParams.waveform = 0.0f;
  283. fParams.tuning = 0.0f;
  284. fParams.cutoff = 25.0f;
  285. fParams.resonance = 25.0f;
  286. fParams.envMod = 50.0f;
  287. fParams.decay = 75.0f;
  288. fParams.accent = 25.0f;
  289. fParams.volume = 75.0f;
  290. // Internal stuff
  291. fSynth->waveform = 0.0f;
  292. fSynth->tuning = 1.0f;
  293. fSynth->cutoff = 5.0f;
  294. fSynth->resonance = 0.8f;
  295. fSynth->envmod = 0.3f;
  296. fSynth->decay = 0.0002f;
  297. fSynth->accent = 0.3f;
  298. fSynth->volume = 0.75f;
  299. }
  300. // -------------------------------------------------
  301. // Process
  302. void DistrhoPluginNekobi::d_activate()
  303. {
  304. fSynth->nugget_remains = 0;
  305. fSynth->note_id = 0;
  306. if (fSynth->voice != nullptr)
  307. nekobee_synth_all_voices_off(fSynth);
  308. }
  309. void DistrhoPluginNekobi::d_deactivate()
  310. {
  311. if (fSynth->voice != nullptr)
  312. nekobee_synth_all_voices_off(fSynth);
  313. }
  314. void DistrhoPluginNekobi::d_run(float**, float** outputs, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents)
  315. {
  316. uint32_t framesDone = 0;
  317. uint32_t curEventIndex = 0;
  318. uint32_t burstSize;
  319. float* out = outputs[0];
  320. if (fSynth->voice == nullptr || ! dssp_voicelist_mutex_trylock(fSynth))
  321. {
  322. for (uint32_t i=0; i < frames; ++i)
  323. *out++ = 0.0f;
  324. return;
  325. }
  326. while (framesDone < frames)
  327. {
  328. if (fSynth->nugget_remains == 0)
  329. fSynth->nugget_remains = XSYNTH_NUGGET_SIZE;
  330. /* process any ready events */
  331. while (curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame)
  332. {
  333. nekobee_handle_raw_event(fSynth, midiEvents[curEventIndex].size, midiEvents[curEventIndex].buf);
  334. curEventIndex++;
  335. }
  336. /* calculate the sample count (burstSize) for the next nekobee_voice_render() call to be the smallest of:
  337. * - control calculation quantization size (XSYNTH_NUGGET_SIZE, in samples)
  338. * - the number of samples remaining in an already-begun nugget (synth->nugget_remains)
  339. * - the number of samples until the next event is ready
  340. * - the number of samples left in this run
  341. */
  342. burstSize = XSYNTH_NUGGET_SIZE;
  343. /* we're still in the middle of a nugget, so reduce the burst size
  344. * to end when the nugget ends */
  345. if (fSynth->nugget_remains < burstSize)
  346. burstSize = fSynth->nugget_remains;
  347. /* reduce burst size to end when next event is ready */
  348. if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame - framesDone < burstSize)
  349. burstSize = midiEvents[curEventIndex].frame - framesDone;
  350. /* reduce burst size to end at end of this run */
  351. if (frames - framesDone < burstSize)
  352. burstSize = frames - framesDone;
  353. /* render the burst */
  354. nekobee_synth_render_voices(fSynth, out + framesDone, burstSize, (burstSize == fSynth->nugget_remains));
  355. framesDone += burstSize;
  356. fSynth->nugget_remains -= burstSize;
  357. }
  358. dssp_voicelist_mutex_unlock(fSynth);
  359. }
  360. // -------------------------------------------------
  361. Plugin* createPlugin()
  362. {
  363. return new DistrhoPluginNekobi();
  364. }
  365. // -------------------------------------------------
  366. END_NAMESPACE_DISTRHO