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.

835 lines
27KB

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