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.

356 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 > (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_AUTOMABLE;
  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. static void audiogain_process(NativePluginHandle handle,
  171. const float** inBuffer, float** outBuffer, uint32_t frames,
  172. const NativeMidiEvent* midiEvents, uint32_t midiEventCount)
  173. {
  174. const float gain = handlePtr->gain;
  175. const bool applyLeft = handlePtr->applyLeft;
  176. const bool applyRight = handlePtr->applyRight;
  177. const bool isMono = handlePtr->isMono;
  178. handle_audio_buffers(inBuffer[0], outBuffer[0], &handlePtr->lowpass[0], (isMono || applyLeft) ? gain : 1.0f, frames);
  179. if (! isMono)
  180. handle_audio_buffers(inBuffer[1], outBuffer[1], &handlePtr->lowpass[1], applyRight ? gain : 1.0f, frames);
  181. return;
  182. // unused
  183. (void)midiEvents;
  184. (void)midiEventCount;
  185. }
  186. static intptr_t audiogain_dispatcher(NativePluginHandle handle, NativePluginDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
  187. {
  188. switch (opcode)
  189. {
  190. case NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED:
  191. for (unsigned i = 0; i < MAX_CHANNELS; ++i)
  192. set_filter_sample_rate(&handlePtr->lowpass[i], opt);
  193. break;
  194. default:
  195. break;
  196. }
  197. return 0;
  198. // unused
  199. (void)index;
  200. (void)value;
  201. (void)ptr;
  202. }
  203. // -----------------------------------------------------------------------
  204. static const NativePluginDescriptor audiogainMonoDesc = {
  205. .category = NATIVE_PLUGIN_CATEGORY_UTILITY,
  206. .hints = NATIVE_PLUGIN_IS_RTSAFE,
  207. .supports = NATIVE_PLUGIN_SUPPORTS_NOTHING,
  208. .audioIns = 1,
  209. .audioOuts = 1,
  210. .midiIns = 0,
  211. .midiOuts = 0,
  212. .paramIns = PARAM_COUNT_MONO,
  213. .paramOuts = 0,
  214. .name = "Audio Gain (Mono)",
  215. .label = "audiogain",
  216. .maker = "falkTX",
  217. .copyright = "GNU GPL v2+",
  218. .instantiate = audiogain_instantiate_mono,
  219. .cleanup = audiogain_cleanup,
  220. .get_parameter_count = audiogain_get_parameter_count,
  221. .get_parameter_info = audiogain_get_parameter_info,
  222. .get_parameter_value = audiogain_get_parameter_value,
  223. .get_midi_program_count = NULL,
  224. .get_midi_program_info = NULL,
  225. .set_parameter_value = audiogain_set_parameter_value,
  226. .set_midi_program = NULL,
  227. .set_custom_data = NULL,
  228. .ui_show = NULL,
  229. .ui_idle = NULL,
  230. .ui_set_parameter_value = NULL,
  231. .ui_set_midi_program = NULL,
  232. .ui_set_custom_data = NULL,
  233. .activate = NULL,
  234. .deactivate = NULL,
  235. .process = audiogain_process,
  236. .get_state = NULL,
  237. .set_state = NULL,
  238. .dispatcher = audiogain_dispatcher,
  239. .render_inline_display = NULL
  240. };
  241. static const NativePluginDescriptor audiogainStereoDesc = {
  242. .category = NATIVE_PLUGIN_CATEGORY_UTILITY,
  243. .hints = NATIVE_PLUGIN_IS_RTSAFE,
  244. .supports = NATIVE_PLUGIN_SUPPORTS_NOTHING,
  245. .audioIns = 2,
  246. .audioOuts = 2,
  247. .cvIns = 0,
  248. .cvOuts = 0,
  249. .midiIns = 0,
  250. .midiOuts = 0,
  251. .paramIns = PARAM_COUNT_STEREO,
  252. .paramOuts = 0,
  253. .name = "Audio Gain (Stereo)",
  254. .label = "audiogain_s",
  255. .maker = "falkTX",
  256. .copyright = "GNU GPL v2+",
  257. .instantiate = audiogain_instantiate_stereo,
  258. .cleanup = audiogain_cleanup,
  259. .get_parameter_count = audiogain_get_parameter_count,
  260. .get_parameter_info = audiogain_get_parameter_info,
  261. .get_parameter_value = audiogain_get_parameter_value,
  262. .get_midi_program_count = NULL,
  263. .get_midi_program_info = NULL,
  264. .set_parameter_value = audiogain_set_parameter_value,
  265. .set_midi_program = NULL,
  266. .set_custom_data = NULL,
  267. .ui_show = NULL,
  268. .ui_idle = NULL,
  269. .ui_set_parameter_value = NULL,
  270. .ui_set_midi_program = NULL,
  271. .ui_set_custom_data = NULL,
  272. .activate = NULL,
  273. .deactivate = NULL,
  274. .process = audiogain_process,
  275. .get_state = NULL,
  276. .set_state = NULL,
  277. .dispatcher = audiogain_dispatcher,
  278. .render_inline_display = NULL
  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. // -----------------------------------------------------------------------