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.

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