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.

411 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 doc/GPL.txt file.
  17. */
  18. #include "DistrhoPluginNekobi.hpp"
  19. #ifdef CARLA_EXPORT
  20. # include "CarlaUtils.hpp"
  21. #else
  22. # define CARLA_SAFE_ASSERT_INT2(...)
  23. #endif
  24. extern "C" {
  25. #include "nekobee-src/nekobee_synth.c"
  26. #include "nekobee-src/nekobee_voice.c"
  27. #include "nekobee-src/nekobee_voice_render.c"
  28. #include "nekobee-src/minblep_tables.c"
  29. // -----------------------------------------------------------------------
  30. // mutual exclusion
  31. bool dssp_voicelist_mutex_trylock(nekobee_synth_t* synth)
  32. {
  33. /* Attempt the mutex lock */
  34. if (pthread_mutex_trylock(&synth->voicelist_mutex) != 0)
  35. {
  36. synth->voicelist_mutex_grab_failed = 1;
  37. return false;
  38. }
  39. /* Clean up if a previous mutex grab failed */
  40. if (synth->voicelist_mutex_grab_failed)
  41. {
  42. nekobee_synth_all_voices_off(synth);
  43. synth->voicelist_mutex_grab_failed = 0;
  44. }
  45. return true;
  46. }
  47. bool dssp_voicelist_mutex_lock(nekobee_synth_t* synth)
  48. {
  49. return (pthread_mutex_lock(&synth->voicelist_mutex) == 0);
  50. }
  51. bool dssp_voicelist_mutex_unlock(nekobee_synth_t *synth)
  52. {
  53. return (pthread_mutex_unlock(&synth->voicelist_mutex) == 0);
  54. }
  55. // -----------------------------------------------------------------------
  56. // nekobee_handle_raw_event
  57. void nekobee_handle_raw_event(nekobee_synth_t* synth, uint8_t size, const uint8_t* data)
  58. {
  59. if (size != 3)
  60. return;
  61. switch (data[0] & 0xf0)
  62. {
  63. case 0x80:
  64. nekobee_synth_note_off(synth, data[1], data[2]);
  65. break;
  66. case 0x90:
  67. if (data[2] > 0)
  68. nekobee_synth_note_on(synth, data[1], data[2]);
  69. else
  70. nekobee_synth_note_off(synth, data[1], 64); /* shouldn't happen, but... */
  71. break;
  72. case 0xB0:
  73. nekobee_synth_control_change(synth, data[1], data[2]);
  74. break;
  75. default:
  76. break;
  77. }
  78. }
  79. } /* extern "C" */
  80. START_NAMESPACE_DISTRHO
  81. // -----------------------------------------------------------------------
  82. DistrhoPluginNekobi::DistrhoPluginNekobi()
  83. : Plugin(paramCount, 0, 0) // 0 programs, 0 states
  84. {
  85. nekobee_init_tables();
  86. // init synth
  87. fSynth = new nekobee_synth_t;
  88. fSynth->sample_rate = d_getSampleRate();
  89. fSynth->deltat = 1.0f / (float)d_getSampleRate();
  90. fSynth->nugget_remains = 0;
  91. fSynth->note_id = 0;
  92. fSynth->polyphony = XSYNTH_DEFAULT_POLYPHONY;
  93. fSynth->voices = XSYNTH_DEFAULT_POLYPHONY;
  94. fSynth->monophonic = XSYNTH_MONO_MODE_ONCE;
  95. fSynth->glide = 0;
  96. fSynth->last_noteon_pitch = 0.0f;
  97. fSynth->vcf_accent = 0.0f;
  98. fSynth->vca_accent = 0.0f;
  99. for (int i=0; i<8; ++i)
  100. fSynth->held_keys[i] = -1;
  101. fSynth->voice = nekobee_voice_new();
  102. fSynth->voicelist_mutex_grab_failed = 0;
  103. pthread_mutex_init(&fSynth->voicelist_mutex, NULL);
  104. fSynth->channel_pressure = 0;
  105. fSynth->pitch_wheel_sensitivity = 0;
  106. fSynth->pitch_wheel = 0;
  107. for (int i=0; i<128; ++i)
  108. {
  109. fSynth->key_pressure[i] = 0;
  110. fSynth->cc[i] = 0;
  111. }
  112. fSynth->cc[7] = 127; // full volume
  113. fSynth->mod_wheel = 1.0f;
  114. fSynth->pitch_bend = 1.0f;
  115. fSynth->cc_volume = 1.0f;
  116. // Default values
  117. fParams.waveform = 0.0f;
  118. fParams.tuning = 0.0f;
  119. fParams.cutoff = 25.0f;
  120. fParams.resonance = 25.0f;
  121. fParams.envMod = 50.0f;
  122. fParams.decay = 75.0f;
  123. fParams.accent = 25.0f;
  124. fParams.volume = 75.0f;
  125. // Internal stuff
  126. fSynth->waveform = 0.0f;
  127. fSynth->tuning = 1.0f;
  128. fSynth->cutoff = 5.0f;
  129. fSynth->resonance = 0.8f;
  130. fSynth->envmod = 0.3f;
  131. fSynth->decay = 0.0002f;
  132. fSynth->accent = 0.3f;
  133. fSynth->volume = 0.75f;
  134. // reset
  135. d_deactivate();
  136. }
  137. DistrhoPluginNekobi::~DistrhoPluginNekobi()
  138. {
  139. std::free(fSynth->voice);
  140. delete fSynth;
  141. }
  142. // -----------------------------------------------------------------------
  143. // Init
  144. void DistrhoPluginNekobi::d_initParameter(uint32_t index, Parameter& parameter)
  145. {
  146. switch (index)
  147. {
  148. case paramWaveform:
  149. parameter.hints = PARAMETER_IS_AUTOMABLE|PARAMETER_IS_BOOLEAN;
  150. parameter.name = "Waveform";
  151. parameter.symbol = "waveform";
  152. parameter.ranges.def = 0.0f;
  153. parameter.ranges.min = 0.0f;
  154. parameter.ranges.max = 1.0f;
  155. break;
  156. case paramTuning:
  157. parameter.hints = PARAMETER_IS_AUTOMABLE; // 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 = PARAMETER_IS_AUTOMABLE; // 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 = PARAMETER_IS_AUTOMABLE; // 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 = PARAMETER_IS_AUTOMABLE; // 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 = PARAMETER_IS_AUTOMABLE; // 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 = PARAMETER_IS_AUTOMABLE; // 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 = PARAMETER_IS_AUTOMABLE; // 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. }
  219. }
  220. // -----------------------------------------------------------------------
  221. // Internal data
  222. float DistrhoPluginNekobi::d_getParameterValue(uint32_t index) const
  223. {
  224. switch (index)
  225. {
  226. case paramWaveform:
  227. return fParams.waveform;
  228. case paramTuning:
  229. return fParams.tuning;
  230. case paramCutoff:
  231. return fParams.cutoff;
  232. case paramResonance:
  233. return fParams.resonance;
  234. case paramEnvMod:
  235. return fParams.envMod;
  236. case paramDecay:
  237. return fParams.decay;
  238. case paramAccent:
  239. return fParams.accent;
  240. case paramVolume:
  241. return fParams.volume;
  242. }
  243. return 0.0f;
  244. }
  245. void DistrhoPluginNekobi::d_setParameterValue(uint32_t index, float value)
  246. {
  247. switch (index)
  248. {
  249. case paramWaveform:
  250. fParams.waveform = value;
  251. fSynth->waveform = value;
  252. CARLA_SAFE_ASSERT_INT2(fSynth->waveform == 0.0f || fSynth->waveform == 1.0f, fSynth->waveform, value);
  253. break;
  254. case paramTuning:
  255. fParams.tuning = value;
  256. fSynth->tuning = (value+12.0f)/24.0f * 1.5 + 0.5f; // FIXME: log?
  257. CARLA_SAFE_ASSERT_INT2(fSynth->tuning >= 0.5f && fSynth->tuning <= 2.0f, fSynth->tuning, value);
  258. break;
  259. case paramCutoff:
  260. fParams.cutoff = value;
  261. fSynth->cutoff = value/2.5f;
  262. CARLA_SAFE_ASSERT_INT2(fSynth->cutoff >= 0.0f && fSynth->cutoff <= 40.0f, fSynth->cutoff, value);
  263. break;
  264. case paramResonance:
  265. fParams.resonance = value;
  266. fSynth->resonance = value/100.0f;
  267. CARLA_SAFE_ASSERT_INT2(fSynth->resonance >= 0.0f && fSynth->resonance <= 0.95f, fSynth->resonance, value);
  268. break;
  269. case paramEnvMod:
  270. fParams.envMod = value;
  271. fSynth->envmod = value/100.0f;
  272. CARLA_SAFE_ASSERT_INT2(fSynth->envmod >= 0.0f && fSynth->envmod <= 1.0f, fSynth->envmod, value);
  273. break;
  274. case paramDecay:
  275. fParams.decay = value;
  276. fSynth->decay = value/100.0f * 0.000491f + 0.000009f; // FIXME: log?
  277. CARLA_SAFE_ASSERT_INT2(fSynth->decay >= 0.000009f && fSynth->decay <= 0.0005f, fSynth->decay, value);
  278. break;
  279. case paramAccent:
  280. fParams.accent = value;
  281. fSynth->accent = value/100.0f;
  282. CARLA_SAFE_ASSERT_INT2(fSynth->accent >= 0.0f && fSynth->accent <= 1.0f, fSynth->accent, value);
  283. break;
  284. case paramVolume:
  285. fParams.volume = value;
  286. fSynth->volume = value/100.0f;
  287. CARLA_SAFE_ASSERT_INT2(fSynth->volume >= 0.0f && fSynth->volume <= 1.0f, fSynth->volume, value);
  288. break;
  289. }
  290. }
  291. // -----------------------------------------------------------------------
  292. // Process
  293. void DistrhoPluginNekobi::d_activate()
  294. {
  295. fSynth->nugget_remains = 0;
  296. fSynth->note_id = 0;
  297. if (fSynth->voice != nullptr)
  298. nekobee_synth_all_voices_off(fSynth);
  299. }
  300. void DistrhoPluginNekobi::d_deactivate()
  301. {
  302. if (fSynth->voice != nullptr)
  303. nekobee_synth_all_voices_off(fSynth);
  304. }
  305. void DistrhoPluginNekobi::d_run(float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
  306. {
  307. uint32_t framesDone = 0;
  308. uint32_t curEventIndex = 0;
  309. uint32_t burstSize;
  310. float* out = outputs[0];
  311. if (fSynth->voice == nullptr || ! dssp_voicelist_mutex_trylock(fSynth))
  312. {
  313. for (uint32_t i=0; i < frames; ++i)
  314. *out++ = 0.0f;
  315. return;
  316. }
  317. while (framesDone < frames)
  318. {
  319. if (fSynth->nugget_remains == 0)
  320. fSynth->nugget_remains = XSYNTH_NUGGET_SIZE;
  321. /* process any ready events */
  322. while (curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame)
  323. {
  324. nekobee_handle_raw_event(fSynth, midiEvents[curEventIndex].size, midiEvents[curEventIndex].buf);
  325. curEventIndex++;
  326. }
  327. /* calculate the sample count (burstSize) for the next nekobee_voice_render() call to be the smallest of:
  328. * - control calculation quantization size (XSYNTH_NUGGET_SIZE, in samples)
  329. * - the number of samples remaining in an already-begun nugget (synth->nugget_remains)
  330. * - the number of samples until the next event is ready
  331. * - the number of samples left in this run
  332. */
  333. burstSize = XSYNTH_NUGGET_SIZE;
  334. /* we're still in the middle of a nugget, so reduce the burst size
  335. * to end when the nugget ends */
  336. if (fSynth->nugget_remains < burstSize)
  337. burstSize = fSynth->nugget_remains;
  338. /* reduce burst size to end when next event is ready */
  339. if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame - framesDone < burstSize)
  340. burstSize = midiEvents[curEventIndex].frame - framesDone;
  341. /* reduce burst size to end at end of this run */
  342. if (frames - framesDone < burstSize)
  343. burstSize = frames - framesDone;
  344. /* render the burst */
  345. nekobee_synth_render_voices(fSynth, out + framesDone, burstSize, (burstSize == fSynth->nugget_remains));
  346. framesDone += burstSize;
  347. fSynth->nugget_remains -= burstSize;
  348. }
  349. dssp_voicelist_mutex_unlock(fSynth);
  350. }
  351. // -----------------------------------------------------------------------
  352. Plugin* createPlugin()
  353. {
  354. return new DistrhoPluginNekobi();
  355. }
  356. // -----------------------------------------------------------------------
  357. END_NAMESPACE_DISTRHO