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.

776 lines
26KB

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