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-file.cpp 28KB

9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2013-2022 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. #include "CarlaNativePrograms.hpp"
  18. #include "CarlaString.hpp"
  19. #include "audio-base.hpp"
  20. static const char* const audiofilesWildcard =
  21. #ifdef HAVE_SNDFILE
  22. "*.aif;*.aifc;*.aiff;*.au;*.bwf;*.flac;*.htk;*.iff;*.mat4;*.mat5;*.oga;*.ogg;*.opus;"
  23. "*.paf;*.pvf;*.pvf5;*.sd2;*.sf;*.snd;*.svx;*.vcc;*.w64;*.wav;*.xi;"
  24. #endif
  25. #ifdef HAVE_FFMPEG
  26. "*.3g2;*.3gp;*.aac;*.ac3;*.amr;*.ape;*.mp2;*.mp3;*.mpc;*.wma;"
  27. # ifndef HAVE_SNDFILE
  28. "*.flac;*.oga;*.ogg;*.w64;*.wav;"
  29. # endif
  30. #else
  31. "*.mp3;"
  32. #endif
  33. ;
  34. // -----------------------------------------------------------------------
  35. class AudioFilePlugin : public NativePluginWithMidiPrograms<FileAudio>
  36. {
  37. public:
  38. #ifndef __MOD_DEVICES__
  39. typedef enum _PendingInlineDisplay
  40. # ifdef CARLA_PROPER_CPP11_SUPPORT
  41. : uint8_t
  42. # endif
  43. {
  44. InlineDisplayNotPending,
  45. InlineDisplayNeedRequest,
  46. InlineDisplayRequesting
  47. } PendingInlineDisplay;
  48. #endif
  49. enum Parameters {
  50. kParameterLooping,
  51. kParameterHostSync,
  52. kParameterVolume,
  53. kParameterEnabled,
  54. kParameterInfoChannels,
  55. kParameterInfoBitRate,
  56. kParameterInfoBitDepth,
  57. kParameterInfoSampleRate,
  58. kParameterInfoLength,
  59. kParameterInfoPosition,
  60. kParameterInfoPoolFill,
  61. kParameterCount
  62. };
  63. AudioFilePlugin(const NativeHostDescriptor* const host)
  64. : NativePluginWithMidiPrograms<FileAudio>(host, fPrograms, 2),
  65. fLoopMode(true),
  66. #ifdef __MOD_DEVICES__
  67. fHostSync(false),
  68. #else
  69. fHostSync(true),
  70. #endif
  71. fEnabled(true),
  72. fDoProcess(false),
  73. fWasPlayingBefore(false),
  74. fNeedsFileRead(false),
  75. fEntireFileLoaded(false),
  76. fMaxFrame(0),
  77. fInternalTransportFrame(0),
  78. fLastPosition(0.0f),
  79. fLastPoolFill(0.0f),
  80. fVolume(1.0f),
  81. fPool(),
  82. fReader(),
  83. fFilename(),
  84. fPrograms(hostGetFilePath("audio"), audiofilesWildcard),
  85. fPreviewData()
  86. #ifndef __MOD_DEVICES__
  87. , fInlineDisplay()
  88. #endif
  89. {
  90. }
  91. ~AudioFilePlugin() override
  92. {
  93. fReader.destroy();
  94. fPool.destroy();
  95. }
  96. protected:
  97. // -------------------------------------------------------------------
  98. // Plugin parameter calls
  99. uint32_t getParameterCount() const override
  100. {
  101. return kParameterCount;
  102. }
  103. const NativeParameter* getParameterInfo(const uint32_t index) const override
  104. {
  105. static NativeParameter param;
  106. param.scalePointCount = 0;
  107. param.scalePoints = nullptr;
  108. param.unit = nullptr;
  109. param.ranges.step = 1.0f;
  110. param.ranges.stepSmall = 1.0f;
  111. param.ranges.stepLarge = 1.0f;
  112. param.designation = NATIVE_PARAMETER_DESIGNATION_NONE;
  113. switch (index)
  114. {
  115. case kParameterLooping:
  116. param.name = "Loop Mode";
  117. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  118. NATIVE_PARAMETER_IS_ENABLED|
  119. NATIVE_PARAMETER_IS_BOOLEAN);
  120. param.ranges.def = 1.0f;
  121. param.ranges.min = 0.0f;
  122. param.ranges.max = 1.0f;
  123. break;
  124. case kParameterHostSync:
  125. param.name = "Host Sync";
  126. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  127. NATIVE_PARAMETER_IS_ENABLED|
  128. NATIVE_PARAMETER_IS_BOOLEAN);
  129. #ifdef __MOD_DEVICES__
  130. param.ranges.def = 0.0f;
  131. #else
  132. param.ranges.def = 1.0f;
  133. #endif
  134. param.ranges.min = 0.0f;
  135. param.ranges.max = 1.0f;
  136. break;
  137. case kParameterVolume:
  138. param.name = "Volume";
  139. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  140. NATIVE_PARAMETER_IS_ENABLED);
  141. param.ranges.def = 100.0f;
  142. param.ranges.min = 0.0f;
  143. param.ranges.max = 127.0f;
  144. param.ranges.stepSmall = 0.5f;
  145. param.ranges.stepLarge = 10.0f;
  146. param.unit = "%";
  147. break;
  148. case kParameterEnabled:
  149. param.name = "Enabled";
  150. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  151. NATIVE_PARAMETER_IS_ENABLED|
  152. NATIVE_PARAMETER_IS_BOOLEAN|
  153. NATIVE_PARAMETER_USES_DESIGNATION);
  154. param.ranges.def = 1.0f;
  155. param.ranges.min = 0.0f;
  156. param.ranges.max = 1.0f;
  157. param.designation = NATIVE_PARAMETER_DESIGNATION_ENABLED;
  158. break;
  159. case kParameterInfoChannels:
  160. param.name = "Num Channels";
  161. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  162. NATIVE_PARAMETER_IS_ENABLED|
  163. NATIVE_PARAMETER_IS_INTEGER|
  164. NATIVE_PARAMETER_IS_OUTPUT);
  165. param.ranges.def = 0.0f;
  166. param.ranges.min = 0.0f;
  167. param.ranges.max = 2.0f;
  168. break;
  169. case kParameterInfoBitRate:
  170. param.name = "Bit Rate";
  171. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  172. NATIVE_PARAMETER_IS_ENABLED|
  173. NATIVE_PARAMETER_IS_INTEGER|
  174. NATIVE_PARAMETER_IS_OUTPUT);
  175. param.ranges.def = 0.0f;
  176. param.ranges.min = -1.0f;
  177. param.ranges.max = 384000.0f * 64.0f * 2.0f;
  178. break;
  179. case kParameterInfoBitDepth:
  180. param.name = "Bit Depth";
  181. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  182. NATIVE_PARAMETER_IS_ENABLED|
  183. NATIVE_PARAMETER_IS_INTEGER|
  184. NATIVE_PARAMETER_IS_OUTPUT);
  185. param.ranges.def = 0.0f;
  186. param.ranges.min = 0.0f;
  187. param.ranges.max = 64.0f;
  188. break;
  189. case kParameterInfoSampleRate:
  190. param.name = "Sample Rate";
  191. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  192. NATIVE_PARAMETER_IS_ENABLED|
  193. NATIVE_PARAMETER_IS_INTEGER|
  194. NATIVE_PARAMETER_IS_OUTPUT);
  195. param.ranges.def = 0.0f;
  196. param.ranges.min = 0.0f;
  197. param.ranges.max = 384000.0f;
  198. break;
  199. case kParameterInfoLength:
  200. param.name = "Length";
  201. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  202. NATIVE_PARAMETER_IS_ENABLED|
  203. NATIVE_PARAMETER_IS_OUTPUT);
  204. param.ranges.def = 0.0f;
  205. param.ranges.min = 0.0f;
  206. param.ranges.max = (float)INT64_MAX;
  207. param.unit = "s";
  208. break;
  209. case kParameterInfoPosition:
  210. param.name = "Position";
  211. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  212. NATIVE_PARAMETER_IS_ENABLED|
  213. NATIVE_PARAMETER_IS_OUTPUT);
  214. param.ranges.def = 0.0f;
  215. param.ranges.min = 0.0f;
  216. param.ranges.max = 100.0f;
  217. param.unit = "%";
  218. break;
  219. case kParameterInfoPoolFill:
  220. param.name = "Pool Fill";
  221. param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE|
  222. NATIVE_PARAMETER_IS_ENABLED|
  223. NATIVE_PARAMETER_IS_OUTPUT);
  224. param.ranges.def = 0.0f;
  225. param.ranges.min = 0.0f;
  226. param.ranges.max = 100.0f;
  227. param.unit = "%";
  228. break;
  229. default:
  230. return nullptr;
  231. }
  232. return &param;
  233. }
  234. float getParameterValue(const uint32_t index) const override
  235. {
  236. switch (index)
  237. {
  238. case kParameterLooping:
  239. return fLoopMode ? 1.0f : 0.0f;
  240. case kParameterHostSync:
  241. return fHostSync ? 1.0f : 0.0f;
  242. case kParameterEnabled:
  243. return fEnabled ? 1.0f : 0.0f;
  244. case kParameterVolume:
  245. return fVolume * 100.0f;
  246. case kParameterInfoPosition:
  247. return fLastPosition;
  248. case kParameterInfoPoolFill:
  249. return fLastPoolFill;
  250. case kParameterInfoBitRate:
  251. return static_cast<float>(fReader.getCurrentBitRate());
  252. }
  253. const ADInfo nfo = fReader.getFileInfo();
  254. switch (index)
  255. {
  256. case kParameterInfoChannels:
  257. return static_cast<float>(nfo.channels);
  258. case kParameterInfoBitDepth:
  259. return static_cast<float>(nfo.bit_depth);
  260. case kParameterInfoSampleRate:
  261. return static_cast<float>(nfo.sample_rate);
  262. case kParameterInfoLength:
  263. return static_cast<float>(nfo.length)/1000.0f;
  264. default:
  265. return 0.0f;
  266. }
  267. }
  268. // -------------------------------------------------------------------
  269. // Plugin state calls
  270. void setParameterValue(const uint32_t index, const float value) override
  271. {
  272. if (index == kParameterVolume)
  273. {
  274. fVolume = value / 100.0f;
  275. return;
  276. }
  277. const bool b = (value > 0.5f);
  278. switch (index)
  279. {
  280. case kParameterLooping:
  281. if (fLoopMode != b)
  282. {
  283. fLoopMode = b;
  284. fReader.setLoopingMode(b);
  285. }
  286. break;
  287. case kParameterHostSync:
  288. if (fHostSync != b)
  289. {
  290. fInternalTransportFrame = 0;
  291. fHostSync = b;
  292. }
  293. break;
  294. case kParameterEnabled:
  295. if (fEnabled != b)
  296. {
  297. fInternalTransportFrame = 0;
  298. fEnabled = b;
  299. }
  300. break;
  301. default:
  302. break;
  303. }
  304. }
  305. void setCustomData(const char* const key, const char* const value) override
  306. {
  307. if (std::strcmp(key, "file") != 0)
  308. return;
  309. invalidateNextFilename();
  310. loadFilename(value);
  311. }
  312. // -------------------------------------------------------------------
  313. // Plugin process calls
  314. void process2(const float* const*, float** const outBuffer, const uint32_t frames,
  315. const NativeMidiEvent*, uint32_t) override
  316. {
  317. float* const out1 = outBuffer[0];
  318. float* const out2 = outBuffer[1];
  319. const water::GenericScopedLock<water::SpinLock> gsl(fPool.mutex);
  320. if (! fDoProcess)
  321. {
  322. // carla_stderr("P: no process");
  323. carla_zeroFloats(out1, frames);
  324. carla_zeroFloats(out2, frames);
  325. fLastPosition = 0.0f;
  326. return;
  327. }
  328. const bool loopMode = fLoopMode;
  329. const float volume = fVolume;
  330. bool needsIdleRequest = false;
  331. bool playing;
  332. uint64_t frame;
  333. if (fHostSync)
  334. {
  335. const NativeTimeInfo* const timePos = getTimeInfo();
  336. playing = fEnabled && timePos->playing;
  337. frame = timePos->frame;
  338. }
  339. else
  340. {
  341. playing = fEnabled;
  342. frame = fInternalTransportFrame;
  343. if (playing)
  344. fInternalTransportFrame += frames;
  345. }
  346. // not playing
  347. if (! playing)
  348. {
  349. // carla_stderr("P: not playing");
  350. if (frame == 0 && fWasPlayingBefore)
  351. fReader.setNeedsRead(frame);
  352. carla_zeroFloats(out1, frames);
  353. carla_zeroFloats(out2, frames);
  354. fWasPlayingBefore = false;
  355. return;
  356. }
  357. else
  358. {
  359. fWasPlayingBefore = true;
  360. }
  361. // out of reach
  362. if ((frame < fPool.startFrame || frame >= fMaxFrame) && !loopMode)
  363. {
  364. if (frame < fPool.startFrame)
  365. {
  366. needsIdleRequest = true;
  367. fNeedsFileRead = true;
  368. fReader.setNeedsRead(frame);
  369. }
  370. carla_zeroFloats(out1, frames);
  371. carla_zeroFloats(out2, frames);
  372. #ifndef __MOD_DEVICES__
  373. if (fInlineDisplay.writtenValues < 32)
  374. {
  375. fInlineDisplay.lastValuesL[fInlineDisplay.writtenValues] = 0.0f;
  376. fInlineDisplay.lastValuesR[fInlineDisplay.writtenValues] = 0.0f;
  377. ++fInlineDisplay.writtenValues;
  378. }
  379. if (fInlineDisplay.pending == InlineDisplayNotPending)
  380. {
  381. needsIdleRequest = true;
  382. fInlineDisplay.pending = InlineDisplayNeedRequest;
  383. }
  384. #endif
  385. if (needsIdleRequest)
  386. hostRequestIdle();
  387. if (frame == 0)
  388. fLastPosition = 0.0f;
  389. else if (frame >= fMaxFrame)
  390. fLastPosition = 100.0f;
  391. else
  392. fLastPosition = static_cast<float>(frame) / static_cast<float>(fMaxFrame) * 100.0f;
  393. return;
  394. }
  395. if (fEntireFileLoaded)
  396. {
  397. // NOTE: frame is always < fMaxFrame (or looping)
  398. uint32_t targetStartFrame = static_cast<uint32_t>(loopMode ? frame % fMaxFrame : frame);
  399. for (uint32_t framesDone=0, framesToDo=frames, remainingFrames; framesDone < frames;)
  400. {
  401. if (targetStartFrame + framesToDo <= fMaxFrame)
  402. {
  403. // everything fits together
  404. carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, framesToDo);
  405. carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, framesToDo);
  406. break;
  407. }
  408. remainingFrames = std::min(fMaxFrame - targetStartFrame, framesToDo);
  409. carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, remainingFrames);
  410. carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, remainingFrames);
  411. framesDone += remainingFrames;
  412. framesToDo -= remainingFrames;
  413. if (! loopMode)
  414. {
  415. // not looping, stop here
  416. if (framesToDo != 0)
  417. {
  418. carla_zeroFloats(out1+framesDone, framesToDo);
  419. carla_zeroFloats(out2+framesDone, framesToDo);
  420. }
  421. break;
  422. }
  423. // reset for next loop
  424. targetStartFrame = 0;
  425. }
  426. fLastPosition = static_cast<float>(targetStartFrame) / static_cast<float>(fMaxFrame) * 100.0f;
  427. }
  428. else
  429. {
  430. const bool offline = isOffline();
  431. if (! fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest))
  432. {
  433. carla_zeroFloats(out1, frames);
  434. carla_zeroFloats(out2, frames);
  435. }
  436. if (needsIdleRequest)
  437. {
  438. fNeedsFileRead = true;
  439. if (isOffline())
  440. {
  441. needsIdleRequest = false;
  442. fReader.readPoll();
  443. if (! fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest))
  444. {
  445. carla_zeroFloats(out1, frames);
  446. carla_zeroFloats(out2, frames);
  447. }
  448. if (needsIdleRequest)
  449. fNeedsFileRead = true;
  450. }
  451. }
  452. const uint32_t modframe = static_cast<uint32_t>(frame % fMaxFrame);
  453. fLastPosition = static_cast<float>(modframe) / static_cast<float>(fMaxFrame) * 100.0f;
  454. if (modframe > fPool.startFrame)
  455. fLastPoolFill = static_cast<float>(modframe - fPool.startFrame) / static_cast<float>(fPool.numFrames) * 100.0f;
  456. else
  457. fLastPoolFill = 100.0f;
  458. }
  459. if (carla_isNotZero(volume-1.0f))
  460. {
  461. carla_multiply(out1, volume, frames);
  462. carla_multiply(out2, volume, frames);
  463. }
  464. #ifndef __MOD_DEVICES__
  465. if (fInlineDisplay.writtenValues < 32)
  466. {
  467. fInlineDisplay.lastValuesL[fInlineDisplay.writtenValues] = carla_findMaxNormalizedFloat(out1, frames);
  468. fInlineDisplay.lastValuesR[fInlineDisplay.writtenValues] = carla_findMaxNormalizedFloat(out2, frames);
  469. ++fInlineDisplay.writtenValues;
  470. }
  471. if (fInlineDisplay.pending == InlineDisplayNotPending)
  472. {
  473. needsIdleRequest = true;
  474. fInlineDisplay.pending = InlineDisplayNeedRequest;
  475. }
  476. #endif
  477. if (needsIdleRequest)
  478. hostRequestIdle();
  479. }
  480. // -------------------------------------------------------------------
  481. // Plugin UI calls
  482. void uiShow(const bool show) override
  483. {
  484. if (! show)
  485. return;
  486. if (const char* const filename = uiOpenFile(false, "Open Audio File", ""))
  487. uiCustomDataChanged("file", filename);
  488. uiClosed();
  489. }
  490. // -------------------------------------------------------------------
  491. // Plugin state calls
  492. void setStateFromFile(const char* const filename) override
  493. {
  494. loadFilename(filename);
  495. }
  496. // -------------------------------------------------------------------
  497. // Plugin dispatcher calls
  498. void idle() override
  499. {
  500. NativePluginWithMidiPrograms<FileAudio>::idle();
  501. if (fNeedsFileRead)
  502. {
  503. fReader.readPoll();
  504. fNeedsFileRead = false;
  505. }
  506. #ifndef __MOD_DEVICES__
  507. if (fInlineDisplay.pending == InlineDisplayNeedRequest)
  508. {
  509. fInlineDisplay.pending = InlineDisplayRequesting;
  510. hostQueueDrawInlineDisplay();
  511. }
  512. #endif
  513. }
  514. #ifndef __MOD_DEVICES__
  515. const NativeInlineDisplayImageSurface* renderInlineDisplay(const uint32_t rwidth, const uint32_t height) override
  516. {
  517. CARLA_SAFE_ASSERT_RETURN(height > 4, nullptr);
  518. const uint32_t width = rwidth == height ? height * 4 : rwidth;
  519. /* NOTE the code is this function is not optimized, still learning my way through pixels...
  520. */
  521. const size_t stride = width * 4;
  522. const size_t dataSize = stride * height;
  523. const uint pxToMove = fDoProcess ? fInlineDisplay.writtenValues : 0;
  524. uchar* data = fInlineDisplay.data;
  525. if (fInlineDisplay.dataSize != dataSize || data == nullptr)
  526. {
  527. delete[] data;
  528. data = new uchar[dataSize];
  529. std::memset(data, 0, dataSize);
  530. fInlineDisplay.data = data;
  531. fInlineDisplay.dataSize = dataSize;
  532. }
  533. else if (pxToMove != 0)
  534. {
  535. // shift all previous values to the left
  536. for (uint w=0; w < width - pxToMove; ++w)
  537. for (uint h=0; h < height; ++h)
  538. std::memmove(&data[h * stride + w * 4], &data[h * stride + (w+pxToMove) * 4], 4);
  539. }
  540. fInlineDisplay.width = static_cast<int>(width);
  541. fInlineDisplay.height = static_cast<int>(height);
  542. fInlineDisplay.stride = static_cast<int>(stride);
  543. if (pxToMove != 0)
  544. {
  545. const uint h2 = height / 2;
  546. // clear current line
  547. for (uint w=width-pxToMove; w < width; ++w)
  548. for (uint h=0; h < height; ++h)
  549. memset(&data[h * stride + w * 4], 0, 4);
  550. // draw upper/left
  551. for (uint i=0; i < pxToMove && i < 32; ++i)
  552. {
  553. const float valueL = fInlineDisplay.lastValuesL[i];
  554. const float valueR = fInlineDisplay.lastValuesR[i];
  555. const uint h2L = static_cast<uint>(valueL * (float)h2);
  556. const uint h2R = static_cast<uint>(valueR * (float)h2);
  557. const uint w = width - pxToMove + i;
  558. for (uint h=0; h < h2L; ++h)
  559. {
  560. // -30dB
  561. //if (valueL < 0.032f)
  562. // continue;
  563. data[(h2 - h) * stride + w * 4 + 3] = 160;
  564. // -12dB
  565. if (valueL < 0.25f)
  566. {
  567. data[(h2 - h) * stride + w * 4 + 1] = 255;
  568. }
  569. // -3dB
  570. else if (valueL < 0.70f)
  571. {
  572. data[(h2 - h) * stride + w * 4 + 2] = 255;
  573. data[(h2 - h) * stride + w * 4 + 1] = 255;
  574. }
  575. else
  576. {
  577. data[(h2 - h) * stride + w * 4 + 2] = 255;
  578. }
  579. }
  580. for (uint h=0; h < h2R; ++h)
  581. {
  582. // -30dB
  583. //if (valueR < 0.032f)
  584. // continue;
  585. data[(h2 + h) * stride + w * 4 + 3] = 160;
  586. // -12dB
  587. if (valueR < 0.25f)
  588. {
  589. data[(h2 + h) * stride + w * 4 + 1] = 255;
  590. }
  591. // -3dB
  592. else if (valueR < 0.70f)
  593. {
  594. data[(h2 + h) * stride + w * 4 + 2] = 255;
  595. data[(h2 + h) * stride + w * 4 + 1] = 255;
  596. }
  597. else
  598. {
  599. data[(h2 + h) * stride + w * 4 + 2] = 255;
  600. }
  601. }
  602. }
  603. }
  604. fInlineDisplay.writtenValues = 0;
  605. fInlineDisplay.pending = InlineDisplayNotPending;
  606. return (NativeInlineDisplayImageSurface*)(NativeInlineDisplayImageSurfaceCompat*)&fInlineDisplay;
  607. }
  608. #endif
  609. void sampleRateChanged(double) override
  610. {
  611. if (char* const filename = fFilename.releaseBufferPointer())
  612. {
  613. loadFilename(filename);
  614. std::free(filename);
  615. }
  616. }
  617. // -------------------------------------------------------------------
  618. private:
  619. bool fLoopMode;
  620. bool fHostSync;
  621. bool fEnabled;
  622. bool fDoProcess;
  623. bool fWasPlayingBefore;
  624. volatile bool fNeedsFileRead;
  625. bool fEntireFileLoaded;
  626. uint32_t fMaxFrame;
  627. uint32_t fInternalTransportFrame;
  628. float fLastPosition;
  629. float fLastPoolFill;
  630. float fVolume;
  631. AudioFilePool fPool;
  632. AudioFileReader fReader;
  633. CarlaString fFilename;
  634. NativeMidiPrograms fPrograms;
  635. float fPreviewData[108];
  636. #ifndef __MOD_DEVICES__
  637. struct InlineDisplay : NativeInlineDisplayImageSurfaceCompat {
  638. float lastValuesL[32];
  639. float lastValuesR[32];
  640. volatile PendingInlineDisplay pending;
  641. volatile uint8_t writtenValues;
  642. InlineDisplay()
  643. : NativeInlineDisplayImageSurfaceCompat(),
  644. # ifdef CARLA_PROPER_CPP11_SUPPORT
  645. lastValuesL{0.0f},
  646. lastValuesR{0.0f},
  647. # endif
  648. pending(InlineDisplayNotPending),
  649. writtenValues(0)
  650. {
  651. # ifndef CARLA_PROPER_CPP11_SUPPORT
  652. carla_zeroFloats(lastValuesL, 32);
  653. carla_zeroFloats(lastValuesR, 32);
  654. # endif
  655. }
  656. ~InlineDisplay()
  657. {
  658. if (data != nullptr)
  659. {
  660. delete[] data;
  661. data = nullptr;
  662. }
  663. }
  664. CARLA_DECLARE_NON_COPYABLE(InlineDisplay)
  665. CARLA_PREVENT_HEAP_ALLOCATION
  666. } fInlineDisplay;
  667. #endif
  668. void loadFilename(const char* const filename)
  669. {
  670. CARLA_ASSERT(filename != nullptr);
  671. carla_debug("AudioFilePlugin::loadFilename(\"%s\")", filename);
  672. fDoProcess = false;
  673. fLastPoolFill = 0.0f;
  674. fInternalTransportFrame = 0;
  675. fPool.destroy();
  676. fReader.destroy();
  677. fFilename.clear();
  678. if (filename == nullptr || *filename == '\0')
  679. {
  680. fMaxFrame = 0;
  681. return;
  682. }
  683. const uint32_t previewDataSize = sizeof(fPreviewData)/sizeof(float);
  684. if (fReader.loadFilename(filename, static_cast<uint32_t>(getSampleRate()), previewDataSize, fPreviewData))
  685. {
  686. fEntireFileLoaded = fReader.isEntireFileLoaded();
  687. fMaxFrame = fReader.getMaxFrame();
  688. if (fEntireFileLoaded)
  689. {
  690. fReader.putAndSwapAllData(fPool);
  691. fLastPoolFill = 100.0f;
  692. }
  693. else
  694. {
  695. fReader.createSwapablePool(fPool);
  696. fReader.readPoll();
  697. }
  698. fDoProcess = true;
  699. fFilename = filename;
  700. hostSendPreviewBufferData('f', previewDataSize, fPreviewData);
  701. }
  702. else
  703. {
  704. fEntireFileLoaded = false;
  705. fMaxFrame = 0;
  706. }
  707. }
  708. PluginClassEND(AudioFilePlugin)
  709. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioFilePlugin)
  710. };
  711. // -----------------------------------------------------------------------
  712. static const NativePluginDescriptor audiofileDesc = {
  713. /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
  714. /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
  715. |NATIVE_PLUGIN_HAS_UI
  716. #ifndef __MOD_DEVICES__
  717. |NATIVE_PLUGIN_HAS_INLINE_DISPLAY
  718. #endif
  719. |NATIVE_PLUGIN_REQUESTS_IDLE
  720. |NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE
  721. |NATIVE_PLUGIN_USES_TIME),
  722. /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
  723. /* audioIns */ 0,
  724. /* audioOuts */ 2,
  725. /* midiIns */ 0,
  726. /* midiOuts */ 0,
  727. /* paramIns */ 1,
  728. /* paramOuts */ 0,
  729. /* name */ "Audio File",
  730. /* label */ "audiofile",
  731. /* maker */ "falkTX",
  732. /* copyright */ "GNU GPL v2+",
  733. PluginDescriptorFILL(AudioFilePlugin)
  734. };
  735. // -----------------------------------------------------------------------
  736. CARLA_API_EXPORT
  737. void carla_register_native_plugin_audiofile();
  738. CARLA_API_EXPORT
  739. void carla_register_native_plugin_audiofile()
  740. {
  741. carla_register_native_plugin(&audiofileDesc);
  742. }
  743. // -----------------------------------------------------------------------