Audio and MIDI file render through 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.

429 lines
12KB

  1. /*
  2. * kuriborosu
  3. * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) 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.
  13. * See the GNU Affero General Public License for more details.
  14. *
  15. * For a full copy of the GNU Affero General Public License see LICENSE file.
  16. */
  17. #include "host.h"
  18. #include <float.h>
  19. #include <math.h>
  20. #include <stdarg.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <sndfile.h>
  25. typedef struct _Kuriborosu {
  26. uint32_t buffer_size;
  27. uint32_t sample_rate;
  28. const NativePluginDescriptor* plugin_descriptor;
  29. NativePluginHandle plugin_handle;
  30. NativeHostDescriptor host_descriptor;
  31. CarlaHostHandle carla_handle;
  32. NativeTimeInfo time;
  33. bool plugin_needs_idle;
  34. } Kuriborosu;
  35. #define kuriborosu ((Kuriborosu*)handle)
  36. static uint32_t get_buffer_size(const NativeHostHandle handle)
  37. {
  38. return kuriborosu->buffer_size;
  39. }
  40. static double get_sample_rate(const NativeHostHandle handle)
  41. {
  42. return kuriborosu->sample_rate;
  43. }
  44. static bool is_offline(const NativeHostHandle handle)
  45. {
  46. return true;
  47. // unused
  48. (void)handle;
  49. }
  50. static const NativeTimeInfo* get_time_info(const NativeHostHandle handle)
  51. {
  52. return &kuriborosu->time;
  53. }
  54. static bool write_midi_event(const NativeHostHandle handle, const NativeMidiEvent* const event)
  55. {
  56. return false;
  57. // unused
  58. (void)handle;
  59. (void)event;
  60. }
  61. static void ui_parameter_changed(const NativeHostHandle handle, const uint32_t index, const float value)
  62. {
  63. return;
  64. // unused
  65. (void)handle;
  66. (void)index;
  67. (void)value;
  68. }
  69. static void ui_midi_program_changed(const NativeHostHandle handle, const uint8_t channel, const uint32_t bank, const uint32_t program)
  70. {
  71. return;
  72. // unused
  73. (void)handle;
  74. (void)channel;
  75. (void)bank;
  76. (void)program;
  77. }
  78. static void ui_custom_data_changed(const NativeHostHandle handle, const char* const key, const char* const value)
  79. {
  80. return;
  81. // unused
  82. (void)handle;
  83. (void)key;
  84. (void)value;
  85. }
  86. static void ui_closed(const NativeHostHandle handle)
  87. {
  88. return;
  89. // unused
  90. (void)handle;
  91. }
  92. static const char* ui_open_file(const NativeHostHandle handle, const bool isDir, const char* const title, const char* const filter)
  93. {
  94. // not supported
  95. return NULL;
  96. // unused
  97. (void)handle;
  98. (void)isDir;
  99. (void)title;
  100. (void)filter;
  101. }
  102. static const char* ui_save_file(const NativeHostHandle handle, const bool isDir, const char* const title, const char* const filter)
  103. {
  104. // not supported
  105. return NULL;
  106. // unused
  107. (void)handle;
  108. (void)isDir;
  109. (void)title;
  110. (void)filter;
  111. }
  112. static intptr_t dispatcher(const NativeHostHandle handle,
  113. const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  114. {
  115. switch (opcode)
  116. {
  117. case NATIVE_HOST_OPCODE_REQUEST_IDLE:
  118. kuriborosu->plugin_needs_idle = true;
  119. return 1;
  120. default:
  121. break;
  122. }
  123. return 0;
  124. // unused
  125. (void)index;
  126. (void)value;
  127. (void)ptr;
  128. (void)opt;
  129. }
  130. #undef kuriborosu
  131. static void carla_stderr2(const char* const fmt, ...)
  132. {
  133. va_list args;
  134. va_start(args, fmt);
  135. fprintf(stderr, "\x1b[31m");
  136. vfprintf(stderr, fmt, args);
  137. fprintf(stderr, "\x1b[0m\n");
  138. fflush(stderr);
  139. va_end(args);
  140. }
  141. static void carla_safe_assert(const char* const assertion, const char* const file, const int line)
  142. {
  143. carla_stderr2("Kuriborosu assertion failure: \"%s\" in file %s, line %i", assertion, file, line);
  144. }
  145. Kuriborosu* kuriborosu_host_init(const uint32_t buffer_size, const uint32_t sample_rate)
  146. {
  147. Kuriborosu* const kuri = (Kuriborosu*)malloc(sizeof(Kuriborosu));
  148. if (kuri == NULL)
  149. return NULL;
  150. memset(kuri, 0, sizeof(Kuriborosu));
  151. kuri->buffer_size = buffer_size;
  152. kuri->sample_rate = sample_rate;
  153. kuri->host_descriptor.handle = kuri;
  154. kuri->host_descriptor.resourceDir = carla_get_library_folder();
  155. kuri->host_descriptor.get_buffer_size = get_buffer_size;
  156. kuri->host_descriptor.get_sample_rate = get_sample_rate;
  157. kuri->host_descriptor.is_offline = is_offline;
  158. kuri->host_descriptor.get_time_info = get_time_info;
  159. kuri->host_descriptor.write_midi_event = write_midi_event;
  160. kuri->host_descriptor.ui_parameter_changed = ui_parameter_changed;
  161. kuri->host_descriptor.ui_midi_program_changed = ui_midi_program_changed;
  162. kuri->host_descriptor.ui_custom_data_changed = ui_custom_data_changed;
  163. kuri->host_descriptor.ui_closed = ui_closed;
  164. kuri->host_descriptor.ui_open_file = ui_open_file;
  165. kuri->host_descriptor.ui_save_file = ui_save_file;
  166. kuri->host_descriptor.dispatcher = dispatcher;
  167. kuri->plugin_descriptor = carla_get_native_rack_plugin();
  168. if (kuri->plugin_descriptor == NULL)
  169. {
  170. fprintf(stderr, "Failed to load Carla-Rack plugin\n");
  171. goto error;
  172. }
  173. kuri->plugin_handle = kuri->plugin_descriptor->instantiate(&kuri->host_descriptor);
  174. if (kuri->plugin_handle == NULL)
  175. {
  176. fprintf(stderr, "Failed to instantiate Carla-Rack plugin\n");
  177. goto error;
  178. }
  179. kuri->carla_handle = carla_create_native_plugin_host_handle(kuri->plugin_descriptor,
  180. kuri->plugin_handle);
  181. if (kuri->carla_handle == NULL)
  182. {
  183. fprintf(stderr, "Failed to create Carla-Rack host handle\n");
  184. goto cleanup;
  185. }
  186. kuri->plugin_descriptor->activate(kuri->plugin_handle);
  187. return kuri;
  188. cleanup:
  189. kuri->plugin_descriptor->cleanup(kuri->plugin_handle);
  190. error:
  191. free(kuri);
  192. return NULL;
  193. }
  194. void kuriborosu_host_destroy(Kuriborosu* const kuri)
  195. {
  196. CARLA_SAFE_ASSERT_RETURN(kuri != NULL,);
  197. kuri->plugin_descriptor->deactivate(kuri->plugin_handle);
  198. kuri->plugin_descriptor->cleanup(kuri->plugin_handle);
  199. carla_host_handle_free(kuri->carla_handle);
  200. }
  201. bool kuriborosu_host_load_file(Kuriborosu* const kuri, const char* const filename)
  202. {
  203. CARLA_SAFE_ASSERT_RETURN(kuri != NULL, false);
  204. CARLA_SAFE_ASSERT_RETURN(filename != NULL, false);
  205. const uint32_t plugin_id = carla_get_current_plugin_count(kuri->carla_handle);
  206. if (carla_load_file(kuri->carla_handle, filename))
  207. {
  208. // Disable audiofile looping
  209. if (strcmp(carla_get_real_plugin_name(kuri->carla_handle, plugin_id), "Audio File") == 0)
  210. {
  211. const uint32_t parameter_count = carla_get_parameter_count(kuri->carla_handle, plugin_id);
  212. for (uint32_t i=0; i<parameter_count; ++i)
  213. {
  214. const CarlaParameterInfo* const info = carla_get_parameter_info(kuri->carla_handle, plugin_id, i);
  215. if (strcmp(info->name, "Loop Mode") == 0)
  216. {
  217. carla_set_parameter_value(kuri->carla_handle, plugin_id, i, 0.0f);
  218. break;
  219. }
  220. }
  221. }
  222. return true;
  223. }
  224. fprintf(stderr, "Failed to load file %s, error was: %s\n",
  225. filename, carla_get_last_error(kuri->carla_handle));
  226. return false;
  227. }
  228. bool kuriborosu_host_load_plugin(Kuriborosu* kuri, const char* filenameOrUID)
  229. {
  230. CARLA_SAFE_ASSERT_RETURN(kuri != NULL, false);
  231. CARLA_SAFE_ASSERT_RETURN(filenameOrUID != NULL, false);
  232. if (carla_add_plugin(kuri->carla_handle, BINARY_NATIVE, PLUGIN_LV2, "", "", filenameOrUID, 0, NULL, 0x0))
  233. return true;
  234. fprintf(stderr, "Failed to load plugin %s, error was: %s\n",
  235. filenameOrUID, carla_get_last_error(kuri->carla_handle));
  236. return false;
  237. }
  238. bool kuriborosu_host_render_to_file(Kuriborosu* const kuri, const file_render_options_t* const options)
  239. {
  240. CARLA_SAFE_ASSERT_RETURN(kuri != NULL, false);
  241. CARLA_SAFE_ASSERT_RETURN(options != NULL, false);
  242. const uint32_t buffer_size = kuri->buffer_size;
  243. const uint32_t sample_rate = kuri->sample_rate;
  244. float* const bufN = malloc(sizeof(float)*buffer_size*2);
  245. float* const bufL = malloc(sizeof(float)*buffer_size);
  246. float* const bufR = malloc(sizeof(float)*buffer_size);
  247. if (bufN == NULL || bufL == NULL || bufR == NULL)
  248. {
  249. fprintf(stderr, "Out of memory\n");
  250. return false;
  251. }
  252. SF_INFO sf_fmt = {
  253. .frames = 0,
  254. .samplerate = sample_rate,
  255. .channels = 2,
  256. .format = SF_FORMAT_WAV|SF_FORMAT_PCM_16,
  257. .sections = 0,
  258. .seekable = 0,
  259. };
  260. SNDFILE* const file = sf_open(options->filename, SFM_WRITE, &sf_fmt);
  261. // TODO check file NULL or error
  262. if (file == NULL)
  263. {
  264. goto free;
  265. }
  266. // Turn on clipping and normalization of floats (-1.0 - 1.0)
  267. sf_command(file, SFC_SET_CLIPPING, NULL, SF_TRUE);
  268. sf_command(file, SFC_SET_NORM_FLOAT, NULL, SF_TRUE);
  269. float* inbuf[2] = { bufN, bufN + buffer_size };
  270. float* outbuf[2] = { bufL, bufR };
  271. kuri->time.playing = true;
  272. for (uint32_t i = 0; i < options->frames; i += buffer_size)
  273. {
  274. kuri->time.frame = i;
  275. memset(bufN, 0, sizeof(float)*buffer_size*2);
  276. kuri->plugin_descriptor->process(kuri->plugin_handle, inbuf, outbuf, buffer_size, NULL, 0);
  277. // interleave
  278. for (uint32_t j = 0, k = 0; k < buffer_size; j += 2, ++k)
  279. {
  280. bufN[j+0] = bufL[k];
  281. bufN[j+1] = bufR[k];
  282. }
  283. sf_writef_float(file, bufN, buffer_size);
  284. if (kuri->plugin_needs_idle)
  285. {
  286. kuri->plugin_needs_idle = false;
  287. kuri->plugin_descriptor->dispatcher(kuri->plugin_handle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, NULL, 0.0f);
  288. }
  289. }
  290. if (options->tail_mode == tail_mode_continue_until_silence)
  291. {
  292. // keep going a bit until silence, maximum 5 seconds
  293. const uint32_t until_silence = 5 * sample_rate;
  294. kuri->time.playing = false;
  295. for (uint32_t i = 0; i < until_silence; i += buffer_size)
  296. {
  297. memset(bufN, 0, sizeof(float)*buffer_size*2);
  298. kuri->plugin_descriptor->process(kuri->plugin_handle, inbuf, outbuf, buffer_size, NULL, 0);
  299. // interleave
  300. for (uint32_t j = 0, k = 0; k < buffer_size; j += 2, ++k)
  301. {
  302. bufN[j+0] = bufL[k];
  303. bufN[j+1] = bufR[k];
  304. }
  305. sf_writef_float(file, bufN, buffer_size);
  306. if (kuri->plugin_needs_idle)
  307. {
  308. kuri->plugin_needs_idle = false;
  309. kuri->plugin_descriptor->dispatcher(kuri->plugin_handle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, NULL, 0.0f);
  310. }
  311. if (fabsf(bufN[buffer_size-1]) < __FLT_EPSILON__)
  312. break;
  313. }
  314. }
  315. free:
  316. free(bufN);
  317. free(bufL);
  318. free(bufR);
  319. sf_close(file);
  320. return true;
  321. }
  322. double get_file_length_from_last_plugin(Kuriborosu* const kuri)
  323. {
  324. static const double fallback = 60.0;
  325. CARLA_SAFE_ASSERT_RETURN(kuri != NULL, fallback);
  326. const uint32_t next_plugin_id = carla_get_current_plugin_count(kuri->carla_handle);
  327. CARLA_SAFE_ASSERT_RETURN(next_plugin_id != 0, fallback);
  328. const uint32_t plugin_id = next_plugin_id - 1;
  329. const char* const plugin_name = carla_get_real_plugin_name(kuri->carla_handle, plugin_id);
  330. CARLA_SAFE_ASSERT_RETURN(plugin_name != NULL, fallback);
  331. if (strcmp(plugin_name, "Audio File") == 0 || strcmp(plugin_name, "MIDI File") == 0)
  332. {
  333. const uint32_t parameter_count = carla_get_parameter_count(kuri->carla_handle, plugin_id);
  334. for (uint32_t i=0; i<parameter_count; ++i)
  335. {
  336. const CarlaParameterInfo* const info = carla_get_parameter_info(kuri->carla_handle, plugin_id, i);
  337. if (strcmp(info->name, "Length") == 0)
  338. return carla_get_current_parameter_value(kuri->carla_handle, plugin_id, i);
  339. }
  340. }
  341. return fallback;
  342. }