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.

audio-base.hpp 9.5KB

11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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 doc/GPL.txt file.
  16. */
  17. #ifndef AUDIO_BASE_HPP_INCLUDED
  18. #define AUDIO_BASE_HPP_INCLUDED
  19. #include "CarlaThread.hpp"
  20. #ifdef HAVE_JUCE
  21. # include "juce_audio_basics.h"
  22. using juce::FloatVectorOperations;
  23. #endif
  24. extern "C" {
  25. #include "audio_decoder/ad.h"
  26. }
  27. typedef struct adinfo ADInfo;
  28. struct AudioFilePool {
  29. float* buffer[2];
  30. uint64_t startFrame;
  31. uint32_t size;
  32. AudioFilePool()
  33. : startFrame(0),
  34. size(0)
  35. {
  36. buffer[0] = buffer[1] = nullptr;
  37. }
  38. ~AudioFilePool()
  39. {
  40. CARLA_ASSERT(buffer[0] == nullptr);
  41. CARLA_ASSERT(buffer[1] == nullptr);
  42. CARLA_ASSERT(startFrame == 0);
  43. CARLA_ASSERT(size == 0);
  44. }
  45. void create(const uint32_t sampleRate)
  46. {
  47. CARLA_ASSERT(buffer[0] == nullptr);
  48. CARLA_ASSERT(buffer[1] == nullptr);
  49. CARLA_ASSERT(startFrame == 0);
  50. CARLA_ASSERT(size == 0);
  51. size = sampleRate * 2;
  52. buffer[0] = new float[size];
  53. buffer[1] = new float[size];
  54. reset();
  55. }
  56. void destroy()
  57. {
  58. CARLA_ASSERT(buffer[0] != nullptr);
  59. CARLA_ASSERT(buffer[1] != nullptr);
  60. CARLA_ASSERT(size != 0);
  61. if (buffer[0] != nullptr)
  62. {
  63. delete[] buffer[0];
  64. buffer[0] = nullptr;
  65. }
  66. if (buffer[1] != nullptr)
  67. {
  68. delete[] buffer[1];
  69. buffer[1] = nullptr;
  70. }
  71. startFrame = 0;
  72. size = 0;
  73. }
  74. void reset()
  75. {
  76. CARLA_ASSERT(size != 0);
  77. startFrame = 0;
  78. #ifdef HAVE_JUCE
  79. FloatVectorOperations::clear(buffer[0], size);
  80. FloatVectorOperations::clear(buffer[1], size);
  81. #else
  82. carla_zeroFloat(buffer[0], size);
  83. carla_zeroFloat(buffer[1], size);
  84. #endif
  85. }
  86. };
  87. class AbstractAudioPlayer
  88. {
  89. public:
  90. virtual ~AbstractAudioPlayer() {}
  91. virtual uint64_t getLastFrame() const = 0;
  92. };
  93. class AudioFileThread : public CarlaThread
  94. {
  95. public:
  96. AudioFileThread(AbstractAudioPlayer* const player, const double sampleRate)
  97. : CarlaThread("AudioFileThread"),
  98. kPlayer(player),
  99. fNeedsRead(false),
  100. fFilePtr(nullptr)
  101. {
  102. CARLA_ASSERT(kPlayer != nullptr);
  103. static bool adInitiated = false;
  104. if (! adInitiated)
  105. {
  106. ad_init();
  107. adInitiated = true;
  108. }
  109. ad_clear_nfo(&fFileNfo);
  110. fPool.create((uint32_t)sampleRate);
  111. }
  112. ~AudioFileThread() override
  113. {
  114. CARLA_ASSERT(! isRunning());
  115. if (fFilePtr != nullptr)
  116. ad_close(fFilePtr);
  117. fPool.destroy();
  118. }
  119. void startNow()
  120. {
  121. fNeedsRead = true;
  122. start();
  123. }
  124. void stopNow()
  125. {
  126. fNeedsRead = false;
  127. stop(1000);
  128. const CarlaMutex::ScopedLocker sl(fMutex);
  129. fPool.reset();
  130. }
  131. uint32_t getMaxFrame() const
  132. {
  133. return fFileNfo.frames > 0 ? (uint32_t)fFileNfo.frames : 0;
  134. }
  135. void setNeedsRead()
  136. {
  137. fNeedsRead = true;
  138. }
  139. bool loadFilename(const char* const filename)
  140. {
  141. CARLA_ASSERT(! isRunning());
  142. CARLA_ASSERT(filename != nullptr);
  143. fPool.startFrame = 0;
  144. // clear old data
  145. if (fFilePtr != nullptr)
  146. {
  147. ad_close(fFilePtr);
  148. fFilePtr = nullptr;
  149. }
  150. ad_clear_nfo(&fFileNfo);
  151. // open new
  152. fFilePtr = ad_open(filename, &fFileNfo);
  153. if (fFilePtr == nullptr)
  154. return false;
  155. ad_dump_nfo(99, &fFileNfo);
  156. if (fFileNfo.frames == 0)
  157. carla_stderr("L: filename \"%s\" has 0 frames", filename);
  158. if ((fFileNfo.channels == 1 || fFileNfo.channels == 2) && fFileNfo.frames > 0)
  159. {
  160. // valid
  161. readPoll();
  162. return true;
  163. }
  164. else
  165. {
  166. // invalid
  167. ad_clear_nfo(&fFileNfo);
  168. ad_close(fFilePtr);
  169. fFilePtr = nullptr;
  170. return false;
  171. }
  172. }
  173. void tryPutData(AudioFilePool& pool)
  174. {
  175. CARLA_ASSERT(pool.size == fPool.size);
  176. if (pool.size != fPool.size)
  177. return;
  178. if (! fMutex.tryLock())
  179. return;
  180. //if (pool.startFrame != fPool.startFrame || pool.buffer[0] != fPool.buffer[0] || pool.buffer[1] != fPool.buffer[1])
  181. {
  182. pool.startFrame = fPool.startFrame;
  183. #ifdef HAVE_JUCE
  184. FloatVectorOperations::copy(pool.buffer[0], fPool.buffer[0], fPool.size);
  185. FloatVectorOperations::copy(pool.buffer[1], fPool.buffer[1], fPool.size);
  186. #else
  187. carla_copyFloat(pool.buffer[0], fPool.buffer[0], fPool.size);
  188. carla_copyFloat(pool.buffer[1], fPool.buffer[1], fPool.size);
  189. #endif
  190. }
  191. fMutex.unlock();
  192. }
  193. void readPoll()
  194. {
  195. if (fFileNfo.frames <= 0 || fFilePtr == nullptr)
  196. {
  197. carla_stderr("R: no song loaded");
  198. fNeedsRead = false;
  199. return;
  200. }
  201. int64_t lastFrame = kPlayer->getLastFrame();
  202. int64_t readFrame = lastFrame;
  203. int64_t maxFrame = fFileNfo.frames;
  204. if (lastFrame >= maxFrame)
  205. {
  206. #if 0
  207. if (false)
  208. //if (handlePtr->loopMode)
  209. {
  210. carla_stderr("R: DEBUG read loop, lastFrame:%i, maxFrame:%i", lastFrame, maxFrame);
  211. if (maxFrame >= static_cast<int64_t>(fPool.size))
  212. {
  213. readFrame %= maxFrame;
  214. }
  215. else
  216. {
  217. readFrame = 0;
  218. lastFrame -= lastFrame % maxFrame;
  219. }
  220. }
  221. else
  222. #endif
  223. {
  224. carla_stderr("R: transport out of bounds");
  225. fNeedsRead = false;
  226. return;
  227. }
  228. }
  229. // temp data buffer
  230. const size_t tmpSize = fPool.size * fFileNfo.channels;
  231. float tmpData[tmpSize];
  232. #ifdef HAVE_JUCE
  233. FloatVectorOperations::clear(tmpData, int(tmpSize));
  234. #else
  235. carla_zeroFloat(tmpData, tmpSize);
  236. #endif
  237. {
  238. carla_stderr("R: poll data - reading at %li:%02li", readFrame/44100/60, (readFrame/44100) % 60);
  239. ad_seek(fFilePtr, readFrame);
  240. ssize_t i, j, rv = ad_read(fFilePtr, tmpData, tmpSize);
  241. i = j = 0;
  242. // lock, and put data asap
  243. const CarlaMutex::ScopedLocker sl(fMutex);
  244. for (ssize_t size = (ssize_t)fPool.size; i < size && j < rv; ++j)
  245. {
  246. if (fFileNfo.channels == 1)
  247. {
  248. fPool.buffer[0][i] = tmpData[j];
  249. fPool.buffer[1][i] = tmpData[j];
  250. i++;
  251. }
  252. else
  253. {
  254. if (j % 2 == 0)
  255. {
  256. fPool.buffer[0][i] = tmpData[j];
  257. }
  258. else
  259. {
  260. fPool.buffer[1][i] = tmpData[j];
  261. i++;
  262. }
  263. }
  264. }
  265. #if 0
  266. if (false)
  267. //if (handlePtr->loopMode && i < fPool.size)
  268. {
  269. while (i < fPool.size)
  270. {
  271. for (j=0; i < fPool.size && j < rv; ++j)
  272. {
  273. if (fFileNfo.channels == 1)
  274. {
  275. fPool.buffer[0][i] = tmpData[j];
  276. fPool.buffer[1][i] = tmpData[j];
  277. i++;
  278. }
  279. else
  280. {
  281. if (j % 2 == 0)
  282. {
  283. fPool.buffer[0][i] = tmpData[j];
  284. }
  285. else
  286. {
  287. fPool.buffer[1][i] = tmpData[j];
  288. i++;
  289. }
  290. }
  291. }
  292. }
  293. }
  294. else
  295. #endif
  296. {
  297. for (ssize_t size = (ssize_t)fPool.size; i < size; ++i)
  298. {
  299. fPool.buffer[0][i] = 0.0f;
  300. fPool.buffer[1][i] = 0.0f;
  301. }
  302. }
  303. fPool.startFrame = lastFrame;
  304. }
  305. fNeedsRead = false;
  306. }
  307. protected:
  308. void run() override
  309. {
  310. while (! shouldExit())
  311. {
  312. const uint64_t lastFrame(kPlayer->getLastFrame());
  313. if (fNeedsRead || lastFrame < fPool.startFrame || (lastFrame - fPool.startFrame >= fPool.size*3/4 && lastFrame < (uint64_t)fFileNfo.frames))
  314. readPoll();
  315. else
  316. carla_msleep(50);
  317. }
  318. }
  319. private:
  320. AbstractAudioPlayer* const kPlayer;
  321. volatile bool fNeedsRead;
  322. void* fFilePtr;
  323. ADInfo fFileNfo;
  324. AudioFilePool fPool;
  325. CarlaMutex fMutex;
  326. };
  327. #endif // AUDIO_BASE_HPP_INCLUDED