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.2KB

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