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.

424 lines
11KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2013 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 GPL.txt file
  16. */
  17. #include "CarlaNative.h"
  18. #include "audio_decoder/ad.h"
  19. #include <pthread.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24. typedef struct adinfo ADInfo;
  25. typedef pthread_mutex_t Mutex;
  26. typedef pthread_t Thread;
  27. typedef struct _AudioFilePool {
  28. float* buffer[2];
  29. uint32_t startFrame;
  30. uint32_t size;
  31. } AudioFilePool;
  32. typedef struct _AudioFileInstance {
  33. HostDescriptor* host;
  34. void* filePtr;
  35. ADInfo fileNfo;
  36. uint32_t lastFrame;
  37. uint32_t maxFrame;
  38. AudioFilePool pool;
  39. bool needsRead;
  40. bool doProcess;
  41. bool doQuit;
  42. Mutex mutex;
  43. Thread thread;
  44. } AudioFileInstance;
  45. // ------------------------------------------------------------------------------------------
  46. static bool gADInitiated = false;
  47. // ------------------------------------------------------------------------------------------
  48. void zeroFloat(float* data, unsigned size)
  49. {
  50. for (unsigned i=0; i < size; ++i)
  51. *data++ = 0.0f;
  52. }
  53. void audiofile_read_poll(AudioFileInstance* const handlePtr)
  54. {
  55. if (handlePtr->fileNfo.frames == 0)
  56. {
  57. //fprintf(stderr, "R: no song loaded\n");
  58. handlePtr->needsRead = false;
  59. return;
  60. }
  61. int64_t lastFrame = handlePtr->lastFrame;
  62. if (lastFrame >= handlePtr->maxFrame)
  63. {
  64. //fprintf(stderr, "R: transport out of bounds\n");
  65. handlePtr->needsRead = false;
  66. return;
  67. }
  68. // temp data buffer
  69. const uint32_t tmpSize = handlePtr->pool.size * handlePtr->fileNfo.channels;
  70. float tmpData[tmpSize];
  71. zeroFloat(tmpData, tmpSize);
  72. {
  73. fprintf(stderr, "R: poll data - reading at %li:%02li\n", lastFrame/44100/60, (lastFrame/44100) % 60);
  74. ad_seek(handlePtr->filePtr, lastFrame);
  75. ssize_t i, j, rv = ad_read(handlePtr->filePtr, tmpData, tmpSize);
  76. {
  77. // lock, and put data asap
  78. pthread_mutex_lock(&handlePtr->mutex);
  79. //zeroFloat(handlePtr->pool.buffer[0], handlePtr->pool.size);
  80. //zeroFloat(handlePtr->pool.buffer[1], handlePtr->pool.size);
  81. for (i=0, j=0; i < handlePtr->pool.size && j < rv; j++)
  82. {
  83. if (handlePtr->fileNfo.channels == 1)
  84. {
  85. handlePtr->pool.buffer[0][i] = tmpData[j];
  86. handlePtr->pool.buffer[1][i] = tmpData[j];
  87. i++;
  88. }
  89. else
  90. {
  91. if (j % 2 == 0)
  92. {
  93. handlePtr->pool.buffer[0][i] = tmpData[j];
  94. }
  95. else
  96. {
  97. handlePtr->pool.buffer[1][i] = tmpData[j];
  98. i++;
  99. }
  100. }
  101. }
  102. for (; i < handlePtr->pool.size; i++)
  103. {
  104. handlePtr->pool.buffer[0][i] = 0.0f;
  105. handlePtr->pool.buffer[1][i] = 0.0f;
  106. }
  107. handlePtr->pool.startFrame = lastFrame;
  108. // done
  109. pthread_mutex_unlock(&handlePtr->mutex);
  110. }
  111. }
  112. handlePtr->needsRead = false;
  113. }
  114. void audiofile_load_filename(AudioFileInstance* const handlePtr, const char* const filename)
  115. {
  116. // wait for jack processing to end
  117. handlePtr->doProcess = false;
  118. pthread_mutex_lock(&handlePtr->mutex);
  119. pthread_mutex_unlock(&handlePtr->mutex);
  120. // clear old data
  121. if (handlePtr->filePtr != NULL)
  122. {
  123. ad_close(handlePtr->filePtr);
  124. handlePtr->filePtr = NULL;
  125. }
  126. ad_clear_nfo(&handlePtr->fileNfo);
  127. // open new
  128. handlePtr->filePtr = ad_open(filename, &handlePtr->fileNfo);
  129. if (handlePtr->filePtr != NULL)
  130. {
  131. ad_dump_nfo(1, &handlePtr->fileNfo);
  132. if (handlePtr->fileNfo.channels == 1 || handlePtr->fileNfo.channels == 2)
  133. {
  134. handlePtr->maxFrame = handlePtr->fileNfo.frames;
  135. audiofile_read_poll(handlePtr);
  136. handlePtr->doProcess = true;
  137. }
  138. else
  139. {
  140. ad_close(handlePtr->filePtr);
  141. handlePtr->filePtr = NULL;
  142. ad_clear_nfo(&handlePtr->fileNfo);
  143. }
  144. }
  145. }
  146. static void audiofile_thread_idle(void* ptr)
  147. {
  148. AudioFileInstance* const handlePtr = (AudioFileInstance*)ptr;
  149. while (! handlePtr->doQuit)
  150. {
  151. if (handlePtr->needsRead || handlePtr->lastFrame - handlePtr->pool.startFrame >= handlePtr->pool.size*3/4)
  152. audiofile_read_poll(handlePtr);
  153. else
  154. usleep(50*1000);
  155. }
  156. pthread_exit(0);
  157. }
  158. // ------------------------------------------------------------------------------------------
  159. static PluginHandle audiofile_instantiate(const PluginDescriptor* _this_, HostDescriptor* host)
  160. {
  161. AudioFileInstance* const handlePtr = (AudioFileInstance*)malloc(sizeof(AudioFileInstance));
  162. if (handlePtr == NULL)
  163. return NULL;
  164. if (! gADInitiated)
  165. {
  166. ad_init();
  167. gADInitiated = true;
  168. }
  169. // init
  170. handlePtr->host = host;
  171. handlePtr->filePtr = NULL;
  172. handlePtr->lastFrame = 0;
  173. handlePtr->maxFrame = 0;
  174. handlePtr->pool.buffer[0] = NULL;
  175. handlePtr->pool.buffer[1] = NULL;
  176. handlePtr->pool.startFrame = 0;
  177. handlePtr->pool.size = 0;
  178. handlePtr->needsRead = false;
  179. handlePtr->doProcess = false;
  180. handlePtr->doQuit = false;
  181. ad_clear_nfo(&handlePtr->fileNfo);
  182. pthread_mutex_init(&handlePtr->mutex, NULL);
  183. // create audio pool
  184. handlePtr->pool.size = host->get_sample_rate(host->handle) * 6; // 6 secs
  185. handlePtr->pool.buffer[0] = (float*)malloc(sizeof(float) * handlePtr->pool.size);
  186. handlePtr->pool.buffer[1] = (float*)malloc(sizeof(float) * handlePtr->pool.size);
  187. if (handlePtr->pool.buffer[0] == NULL || handlePtr->pool.buffer[1] == NULL)
  188. {
  189. free(handlePtr);
  190. return NULL;
  191. }
  192. zeroFloat(handlePtr->pool.buffer[0], handlePtr->pool.size);
  193. zeroFloat(handlePtr->pool.buffer[1], handlePtr->pool.size);
  194. pthread_create(&handlePtr->thread, NULL, (void*)&audiofile_thread_idle, handlePtr);
  195. // load file, TESTING
  196. // wait for jack processing to end
  197. handlePtr->doProcess = false;
  198. pthread_mutex_lock(&handlePtr->mutex);
  199. pthread_mutex_unlock(&handlePtr->mutex);
  200. return handlePtr;
  201. // unused
  202. (void)_this_;
  203. }
  204. static void audiofile_cleanup(PluginHandle handle)
  205. {
  206. AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;
  207. // wait for processing to end
  208. handlePtr->doProcess = false;
  209. handlePtr->doQuit = true;
  210. pthread_mutex_lock(&handlePtr->mutex);
  211. pthread_join(handlePtr->thread, NULL);
  212. pthread_mutex_unlock(&handlePtr->mutex);
  213. pthread_mutex_destroy(&handlePtr->mutex);
  214. if (handlePtr->filePtr != NULL)
  215. ad_close(handlePtr->filePtr);
  216. if (handlePtr->pool.buffer[0] != NULL)
  217. free(handlePtr->pool.buffer[0]);
  218. if (handlePtr->pool.buffer[1] != NULL)
  219. free(handlePtr->pool.buffer[1]);
  220. free(handlePtr);
  221. }
  222. static void audiofile_set_custom_data(PluginHandle handle, const char* key, const char* value)
  223. {
  224. AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;
  225. if (strcmp(key, "file") == 0)
  226. audiofile_load_filename(handlePtr, value);
  227. }
  228. static void audiofile_process(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents)
  229. {
  230. AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;
  231. float* out1 = outBuffer[0];
  232. float* out2 = outBuffer[1];
  233. if (! handlePtr->doProcess)
  234. {
  235. //fprintf(stderr, "P: no process\n");
  236. zeroFloat(out1, frames);
  237. zeroFloat(out2, frames);
  238. return;
  239. }
  240. const TimeInfo* const timePos = handlePtr->host->get_time_info(handlePtr->host->handle);
  241. // not playing
  242. if (! timePos->playing)
  243. {
  244. //fprintf(stderr, "P: not rolling\n");
  245. handlePtr->lastFrame = timePos->frame;
  246. zeroFloat(out1, frames);
  247. zeroFloat(out2, frames);
  248. return;
  249. }
  250. pthread_mutex_lock(&handlePtr->mutex);
  251. // out of reach
  252. if (timePos->frame + frames < handlePtr->pool.startFrame || timePos->frame >= handlePtr->maxFrame)
  253. {
  254. //fprintf(stderr, "P: non-continuous playback, out of reach %u vs %u\n", timePos->frame + frames, handlePtr->maxFrame);
  255. handlePtr->lastFrame = timePos->frame;
  256. handlePtr->needsRead = true;
  257. pthread_mutex_unlock(&handlePtr->mutex);
  258. zeroFloat(out1, frames);
  259. zeroFloat(out2, frames);
  260. return;
  261. }
  262. int64_t poolFrame = (int64_t)timePos->frame - handlePtr->pool.startFrame;
  263. int64_t poolSize = handlePtr->pool.size;
  264. for (uint32_t i=0; i < frames; i++, poolFrame++)
  265. {
  266. if (poolFrame >= 0 && poolFrame < poolSize)
  267. {
  268. out1[i] = handlePtr->pool.buffer[0][poolFrame];
  269. out2[i] = handlePtr->pool.buffer[1][poolFrame];
  270. // reset
  271. handlePtr->pool.buffer[0][poolFrame] = 0.0f;
  272. handlePtr->pool.buffer[1][poolFrame] = 0.0f;
  273. }
  274. else
  275. {
  276. out1[i] = 0.0f;
  277. out2[i] = 0.0f;
  278. }
  279. }
  280. handlePtr->lastFrame = timePos->frame;
  281. pthread_mutex_unlock(&handlePtr->mutex);
  282. return;
  283. // unused
  284. (void)inBuffer;
  285. (void)midiEventCount;
  286. (void)midiEvents;
  287. }
  288. // -----------------------------------------------------------------------
  289. static const PluginDescriptor audiofileDesc = {
  290. .category = PLUGIN_CATEGORY_UTILITY,
  291. .hints = PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI,
  292. .audioIns = 0,
  293. .audioOuts = 2,
  294. .midiIns = 0,
  295. .midiOuts = 0,
  296. .parameterIns = 0,
  297. .parameterOuts = 0,
  298. .name = "Audio File",
  299. .label = "audiofile",
  300. .maker = "falkTX",
  301. .copyright = "GNU GPL v2+",
  302. .instantiate = audiofile_instantiate,
  303. .cleanup = audiofile_cleanup,
  304. .get_parameter_count = NULL,
  305. .get_parameter_info = NULL,
  306. .get_parameter_value = NULL,
  307. .get_parameter_text = NULL,
  308. .get_midi_program_count = NULL,
  309. .get_midi_program_info = NULL,
  310. .set_parameter_value = NULL,
  311. .set_midi_program = NULL,
  312. .set_custom_data = audiofile_set_custom_data,
  313. .ui_show = NULL,
  314. .ui_idle = NULL,
  315. .ui_set_parameter_value = NULL,
  316. .ui_set_midi_program = NULL,
  317. .ui_set_custom_data = NULL,
  318. .activate = NULL,
  319. .deactivate = NULL,
  320. .process = audiofile_process
  321. };
  322. // -----------------------------------------------------------------------
  323. void carla_register_native_plugin_audiofile()
  324. {
  325. carla_register_native_plugin(&audiofileDesc);
  326. }
  327. // -----------------------------------------------------------------------
  328. // amagamated build
  329. #include "audio_decoder/ad_ffmpeg.c"
  330. #include "audio_decoder/ad_plugin.c"
  331. #include "audio_decoder/ad_soundfile.c"
  332. // -----------------------------------------------------------------------