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.

355 lines
9.6KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2019 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 doc/GPL.txt file.
  16. */
  17. #include "CarlaNative.h"
  18. #include "CarlaMIDI.h"
  19. #include <math.h>
  20. #include <stdbool.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #define MAX_CHANNELS 2
  24. // -----------------------------------------------------------------------
  25. typedef struct {
  26. float a0, b1, z1;
  27. } Filter;
  28. static inline
  29. void set_filter_sample_rate(Filter* const filter, const float sampleRate)
  30. {
  31. static const float M_PIf = (float)M_PI;
  32. const float frequency = 30.0f / sampleRate;
  33. filter->b1 = expf(-2.0f * M_PIf * frequency);
  34. filter->a0 = 1.0f - filter->b1;
  35. filter->z1 = 0.0f;
  36. }
  37. // -----------------------------------------------------------------------
  38. typedef enum {
  39. // all versions
  40. PARAM_GAIN = 0,
  41. PARAM_COUNT_MONO,
  42. // stereo version
  43. PARAM_APPLY_LEFT = PARAM_COUNT_MONO,
  44. PARAM_APPLY_RIGHT,
  45. PARAM_COUNT_STEREO
  46. } AudioGainParams;
  47. typedef struct {
  48. Filter lowpass[MAX_CHANNELS];
  49. float gain;
  50. bool isMono;
  51. bool applyLeft;
  52. bool applyRight;
  53. } AudioGainHandle;
  54. // -----------------------------------------------------------------------
  55. static NativePluginHandle audiogain_instantiate(const NativeHostDescriptor* host, const bool isMono)
  56. {
  57. AudioGainHandle* const handle = (AudioGainHandle*)malloc(sizeof(AudioGainHandle));
  58. if (handle == NULL)
  59. return NULL;
  60. handle->gain = 1.0f;
  61. handle->isMono = isMono;
  62. handle->applyLeft = true;
  63. handle->applyRight = true;
  64. const float sampleRate = (float)host->get_sample_rate(host->handle);
  65. for (unsigned i = 0; i < MAX_CHANNELS; ++i)
  66. set_filter_sample_rate(&handle->lowpass[i], sampleRate);
  67. return handle;
  68. }
  69. static NativePluginHandle audiogain_instantiate_mono(const NativeHostDescriptor* host)
  70. {
  71. return audiogain_instantiate(host, true);
  72. }
  73. static NativePluginHandle audiogain_instantiate_stereo(const NativeHostDescriptor* host)
  74. {
  75. return audiogain_instantiate(host, false);
  76. }
  77. #define handlePtr ((AudioGainHandle*)handle)
  78. static void audiogain_cleanup(NativePluginHandle handle)
  79. {
  80. free(handlePtr);
  81. }
  82. static uint32_t audiogain_get_parameter_count(NativePluginHandle handle)
  83. {
  84. return handlePtr->isMono ? PARAM_COUNT_MONO : PARAM_COUNT_STEREO;
  85. }
  86. static const NativeParameter* audiogain_get_parameter_info(NativePluginHandle handle, uint32_t index)
  87. {
  88. if (index > (uint32_t)(handlePtr->isMono ? PARAM_COUNT_MONO : PARAM_COUNT_STEREO))
  89. return NULL;
  90. static NativeParameter param;
  91. param.hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMATABLE;
  92. param.unit = NULL;
  93. param.scalePointCount = 0;
  94. param.scalePoints = NULL;
  95. switch (index)
  96. {
  97. case PARAM_GAIN:
  98. param.name = "Gain";
  99. param.ranges.def = 1.0f;
  100. param.ranges.min = 0.0f;
  101. param.ranges.max = 4.0f;
  102. param.ranges.step = PARAMETER_RANGES_DEFAULT_STEP;
  103. param.ranges.stepSmall = PARAMETER_RANGES_DEFAULT_STEP_SMALL;
  104. param.ranges.stepLarge = PARAMETER_RANGES_DEFAULT_STEP_LARGE;
  105. break;
  106. case PARAM_APPLY_LEFT:
  107. param.name = "Apply Left";
  108. param.hints |= NATIVE_PARAMETER_IS_BOOLEAN;
  109. param.ranges.def = 1.0f;
  110. param.ranges.min = 0.0f;
  111. param.ranges.max = 1.0f;
  112. param.ranges.step = 1.0f;
  113. param.ranges.stepSmall = 1.0f;
  114. param.ranges.stepLarge = 1.0f;
  115. break;
  116. case PARAM_APPLY_RIGHT:
  117. param.name = "Apply Right";
  118. param.hints |= NATIVE_PARAMETER_IS_BOOLEAN;
  119. param.ranges.def = 1.0f;
  120. param.ranges.min = 0.0f;
  121. param.ranges.max = 1.0f;
  122. param.ranges.step = 1.0f;
  123. param.ranges.stepSmall = 1.0f;
  124. param.ranges.stepLarge = 1.0f;
  125. break;
  126. }
  127. return &param;
  128. }
  129. static float audiogain_get_parameter_value(NativePluginHandle handle, uint32_t index)
  130. {
  131. switch (index)
  132. {
  133. case PARAM_GAIN:
  134. return handlePtr->gain;
  135. case PARAM_APPLY_LEFT:
  136. return handlePtr->applyLeft ? 1.0f : 0.0f;
  137. case PARAM_APPLY_RIGHT:
  138. return handlePtr->applyRight ? 1.0f : 0.0f;
  139. default:
  140. return 0.0f;
  141. }
  142. }
  143. static void audiogain_set_parameter_value(NativePluginHandle handle, uint32_t index, float value)
  144. {
  145. switch (index)
  146. {
  147. case PARAM_GAIN:
  148. handlePtr->gain = value;
  149. break;
  150. case PARAM_APPLY_LEFT:
  151. handlePtr->applyLeft = (value >= 0.5f);
  152. break;
  153. case PARAM_APPLY_RIGHT:
  154. handlePtr->applyRight = (value >= 0.5f);
  155. break;
  156. }
  157. }
  158. static inline
  159. void handle_audio_buffers(const float* inBuffer, float* outBuffer, Filter* const filter, const float gain, const uint32_t frames)
  160. {
  161. const float a0 = filter->a0;
  162. const float b1 = filter->b1;
  163. float z1 = filter->z1;
  164. for (uint32_t i=0; i < frames; ++i) {
  165. z1 = gain * a0 + z1 * b1;
  166. *outBuffer++ = *inBuffer++ * z1;
  167. }
  168. filter->z1 = z1;
  169. }
  170. // FIXME for v3.0, use const for the input buffer
  171. static void audiogain_process(NativePluginHandle handle,
  172. float** inBuffer, float** outBuffer, uint32_t frames,
  173. const NativeMidiEvent* midiEvents, uint32_t midiEventCount)
  174. {
  175. const float gain = handlePtr->gain;
  176. const bool applyLeft = handlePtr->applyLeft;
  177. const bool applyRight = handlePtr->applyRight;
  178. const bool isMono = handlePtr->isMono;
  179. handle_audio_buffers(inBuffer[0], outBuffer[0], &handlePtr->lowpass[0], (isMono || applyLeft) ? gain : 1.0f, frames);
  180. if (! isMono)
  181. handle_audio_buffers(inBuffer[1], outBuffer[1], &handlePtr->lowpass[1], applyRight ? gain : 1.0f, frames);
  182. return;
  183. // unused
  184. (void)midiEvents;
  185. (void)midiEventCount;
  186. }
  187. static intptr_t audiogain_dispatcher(NativePluginHandle handle, NativePluginDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
  188. {
  189. switch (opcode)
  190. {
  191. case NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED:
  192. for (unsigned i = 0; i < MAX_CHANNELS; ++i)
  193. set_filter_sample_rate(&handlePtr->lowpass[i], opt);
  194. break;
  195. default:
  196. break;
  197. }
  198. return 0;
  199. // unused
  200. (void)index;
  201. (void)value;
  202. (void)ptr;
  203. }
  204. // -----------------------------------------------------------------------
  205. static const NativePluginDescriptor audiogainMonoDesc = {
  206. .category = NATIVE_PLUGIN_CATEGORY_UTILITY,
  207. .hints = NATIVE_PLUGIN_IS_RTSAFE,
  208. .supports = NATIVE_PLUGIN_SUPPORTS_NOTHING,
  209. .audioIns = 1,
  210. .audioOuts = 1,
  211. .midiIns = 0,
  212. .midiOuts = 0,
  213. .paramIns = PARAM_COUNT_MONO,
  214. .paramOuts = 0,
  215. .name = "Audio Gain (Mono)",
  216. .label = "audiogain",
  217. .maker = "falkTX",
  218. .copyright = "GNU GPL v2+",
  219. .instantiate = audiogain_instantiate_mono,
  220. .cleanup = audiogain_cleanup,
  221. .get_parameter_count = audiogain_get_parameter_count,
  222. .get_parameter_info = audiogain_get_parameter_info,
  223. .get_parameter_value = audiogain_get_parameter_value,
  224. .get_midi_program_count = NULL,
  225. .get_midi_program_info = NULL,
  226. .set_parameter_value = audiogain_set_parameter_value,
  227. .set_midi_program = NULL,
  228. .set_custom_data = NULL,
  229. .ui_show = NULL,
  230. .ui_idle = NULL,
  231. .ui_set_parameter_value = NULL,
  232. .ui_set_midi_program = NULL,
  233. .ui_set_custom_data = NULL,
  234. .activate = NULL,
  235. .deactivate = NULL,
  236. .process = audiogain_process,
  237. .get_state = NULL,
  238. .set_state = NULL,
  239. .dispatcher = audiogain_dispatcher,
  240. .render_inline_display = NULL
  241. };
  242. static const NativePluginDescriptor audiogainStereoDesc = {
  243. .category = NATIVE_PLUGIN_CATEGORY_UTILITY,
  244. .hints = NATIVE_PLUGIN_IS_RTSAFE,
  245. .supports = NATIVE_PLUGIN_SUPPORTS_NOTHING,
  246. .audioIns = 2,
  247. .audioOuts = 2,
  248. .cvIns = 0,
  249. .cvOuts = 0,
  250. .midiIns = 0,
  251. .midiOuts = 0,
  252. .paramIns = PARAM_COUNT_STEREO,
  253. .paramOuts = 0,
  254. .name = "Audio Gain (Stereo)",
  255. .label = "audiogain_s",
  256. .maker = "falkTX",
  257. .copyright = "GNU GPL v2+",
  258. .instantiate = audiogain_instantiate_stereo,
  259. .cleanup = audiogain_cleanup,
  260. .get_parameter_count = audiogain_get_parameter_count,
  261. .get_parameter_info = audiogain_get_parameter_info,
  262. .get_parameter_value = audiogain_get_parameter_value,
  263. .get_midi_program_count = NULL,
  264. .get_midi_program_info = NULL,
  265. .set_parameter_value = audiogain_set_parameter_value,
  266. .set_midi_program = NULL,
  267. .set_custom_data = NULL,
  268. .ui_show = NULL,
  269. .ui_idle = NULL,
  270. .ui_set_parameter_value = NULL,
  271. .ui_set_midi_program = NULL,
  272. .ui_set_custom_data = NULL,
  273. .activate = NULL,
  274. .deactivate = NULL,
  275. .process = audiogain_process,
  276. .get_state = NULL,
  277. .set_state = NULL,
  278. .dispatcher = audiogain_dispatcher
  279. };
  280. // -----------------------------------------------------------------------
  281. void carla_register_native_plugin_audiogain(void);
  282. void carla_register_native_plugin_audiogain(void)
  283. {
  284. carla_register_native_plugin(&audiogainMonoDesc);
  285. carla_register_native_plugin(&audiogainStereoDesc);
  286. }
  287. // -----------------------------------------------------------------------