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.

340 lines
8.9KB

  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 GPL.txt file
  16. */
  17. #include "CarlaNative.hpp"
  18. #include "CarlaString.hpp"
  19. #include "audio-base.hpp"
  20. #define PROGRAM_COUNT 16
  21. class AudioFilePlugin : public PluginDescriptorClass,
  22. public AbstractAudioPlayer
  23. {
  24. public:
  25. AudioFilePlugin(const HostDescriptor* const host)
  26. : PluginDescriptorClass(host),
  27. AbstractAudioPlayer(),
  28. fLoopMode(false),
  29. fDoProcess(false),
  30. fLastFrame(0),
  31. fMaxFrame(0),
  32. fThread(this, getSampleRate())
  33. {
  34. fPool.create(getSampleRate());
  35. }
  36. ~AudioFilePlugin() override
  37. {
  38. fPool.destroy();
  39. fThread.stopNow();
  40. }
  41. uint32_t getLastFrame() const override
  42. {
  43. return fLastFrame;
  44. }
  45. protected:
  46. // -------------------------------------------------------------------
  47. // Plugin parameter calls
  48. uint32_t getParameterCount() override
  49. {
  50. return 1;
  51. }
  52. const Parameter* getParameterInfo(const uint32_t index) override
  53. {
  54. if (index != 0)
  55. return nullptr;
  56. static Parameter param;
  57. param.name = "Loop Mode";
  58. param.unit = nullptr;
  59. param.hints = static_cast<ParameterHints>(PARAMETER_IS_ENABLED|PARAMETER_IS_BOOLEAN);
  60. param.ranges.def = 1.0f;
  61. param.ranges.min = 0.0f;
  62. param.ranges.max = 1.0f;
  63. param.ranges.step = 1.0f;
  64. param.ranges.stepSmall = 1.0f;
  65. param.ranges.stepLarge = 1.0f;
  66. param.scalePointCount = 0;
  67. param.scalePoints = nullptr;
  68. return &param;
  69. }
  70. float getParameterValue(const uint32_t index) override
  71. {
  72. if (index != 0)
  73. return 0.0f;
  74. return fLoopMode ? 1.0f : 0.0f;
  75. }
  76. // -------------------------------------------------------------------
  77. // Plugin midi-program calls
  78. uint32_t getMidiProgramCount() override
  79. {
  80. return PROGRAM_COUNT;
  81. }
  82. const MidiProgram* getMidiProgramInfo(const uint32_t index) override
  83. {
  84. if (index >= PROGRAM_COUNT)
  85. return NULL;
  86. static MidiProgram midiProgram;
  87. midiProgram.bank = 0;
  88. midiProgram.program = index;
  89. midiProgram.name = (const char*)fPrograms.shortNames[index];
  90. return &midiProgram;
  91. }
  92. // -------------------------------------------------------------------
  93. // Plugin state calls
  94. void setParameterValue(const uint32_t index, const float value) override
  95. {
  96. if (index != 0)
  97. return;
  98. bool b = (value > 0.5f);
  99. if (b == fLoopMode)
  100. return;
  101. fLoopMode = b;
  102. fThread.setNeedsRead();
  103. }
  104. void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  105. {
  106. if (bank != 0 || program >= PROGRAM_COUNT)
  107. return;
  108. if (fPrograms.current != program)
  109. {
  110. loadFilename(fPrograms.fullNames[program]);
  111. fPrograms.current = program;
  112. }
  113. }
  114. void setCustomData(const char* const key, const char* const value) override
  115. {
  116. if (std::strlen(key) != 6)
  117. return;
  118. if (std::strncmp(key, "file", 4) != 0)
  119. return;
  120. if (key[4] < '0' || key[4] > '9')
  121. return;
  122. if (key[5] < '0' || key[5] > '9')
  123. return;
  124. uint8_t tens = key[4]-'0';
  125. uint8_t nums = key[5]-'0';
  126. uint32_t program = tens*10 + nums;
  127. if (program >= PROGRAM_COUNT)
  128. return;
  129. fPrograms.fullNames[program] = value;
  130. if (const char* const shortName = std::strrchr(value, OS_SEP))
  131. fPrograms.shortNames[program] = shortName+1;
  132. else
  133. fPrograms.shortNames[program] = value;
  134. fPrograms.shortNames[program].truncate(fPrograms.shortNames[program].rfind('.'));
  135. if (fPrograms.current == program)
  136. loadFilename(value);
  137. }
  138. // -------------------------------------------------------------------
  139. // Plugin process calls
  140. void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t, const MidiEvent* const) override
  141. {
  142. const TimeInfo* const timePos(getTimeInfo());
  143. float* out1 = outBuffer[0];
  144. float* out2 = outBuffer[1];
  145. if (! fDoProcess)
  146. {
  147. carla_stderr("P: no process");
  148. fLastFrame = timePos->frame;
  149. carla_zeroFloat(out1, frames);
  150. carla_zeroFloat(out2, frames);
  151. return;
  152. }
  153. // not playing
  154. if (! timePos->playing)
  155. {
  156. carla_stderr("P: not playing");
  157. fLastFrame = timePos->frame;
  158. if (timePos->frame == 0 && fLastFrame > 0)
  159. fThread.setNeedsRead();
  160. carla_zeroFloat(out1, frames);
  161. carla_zeroFloat(out2, frames);
  162. return;
  163. }
  164. fThread.tryPutData(fPool);
  165. // out of reach
  166. if (timePos->frame + frames < fPool.startFrame || timePos->frame >= fMaxFrame) /*&& ! loopMode)*/
  167. {
  168. carla_stderr("P: out of reach");
  169. fLastFrame = timePos->frame;
  170. fThread.setNeedsRead();
  171. carla_zeroFloat(out1, frames);
  172. carla_zeroFloat(out2, frames);
  173. return;
  174. }
  175. int64_t poolFrame = (int64_t)timePos->frame - fPool.startFrame;
  176. int64_t poolSize = fPool.size;
  177. for (uint32_t i=0; i < frames; ++i, ++poolFrame)
  178. {
  179. if (poolFrame >= 0 && poolFrame < poolSize)
  180. {
  181. out1[i] = fPool.buffer[0][poolFrame];
  182. out2[i] = fPool.buffer[1][poolFrame];
  183. // reset
  184. fPool.buffer[0][poolFrame] = 0.0f;
  185. fPool.buffer[1][poolFrame] = 0.0f;
  186. }
  187. else
  188. {
  189. out1[i] = 0.0f;
  190. out2[i] = 0.0f;
  191. }
  192. }
  193. fLastFrame = timePos->frame;
  194. }
  195. // -------------------------------------------------------------------
  196. // Plugin UI calls
  197. void uiShow(const bool show) override
  198. {
  199. if (! show)
  200. return;
  201. if (const char* const filename = uiOpenFile(false, "Open Audio File", ""))
  202. {
  203. char fileStr[] = { 'f', 'i', 'l', 'e', '\0', '\0', '\0' };
  204. fileStr[4] = '0' + (fPrograms.current / 10);
  205. fileStr[5] = '0' + (fPrograms.current % 10);
  206. uiCustomDataChanged(fileStr, filename);
  207. }
  208. uiClosed();
  209. }
  210. private:
  211. bool fLoopMode;
  212. bool fDoProcess;
  213. uint32_t fLastFrame;
  214. uint32_t fMaxFrame;
  215. AudioFilePool fPool;
  216. AudioFileThread fThread;
  217. struct Programs {
  218. uint32_t current;
  219. CarlaString fullNames[PROGRAM_COUNT];
  220. CarlaString shortNames[PROGRAM_COUNT];
  221. Programs()
  222. : current(0) {}
  223. } fPrograms;
  224. void loadFilename(const char* const filename)
  225. {
  226. CARLA_ASSERT(filename != nullptr);
  227. carla_debug("AudioFilePlugin::loadFilename(\"%s\")", filename);
  228. if (filename == nullptr)
  229. return;
  230. fThread.stopNow();
  231. if (fThread.loadFilename(filename))
  232. {
  233. carla_stdout("AudioFilePlugin::loadFilename(\"%s\") - sucess", filename);
  234. fThread.startNow();
  235. fMaxFrame = fThread.getMaxFrame();
  236. fDoProcess = true;
  237. }
  238. else
  239. {
  240. carla_stderr("AudioFilePlugin::loadFilename(\"%s\") - failed", filename);
  241. fDoProcess = false;
  242. fMaxFrame = 0;
  243. }
  244. }
  245. PluginDescriptorClassEND(AudioFilePlugin)
  246. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioFilePlugin)
  247. };
  248. // -----------------------------------------------------------------------
  249. static const PluginDescriptor audiofileDesc = {
  250. /* category */ PLUGIN_CATEGORY_UTILITY,
  251. /* hints */ static_cast<PluginHints>(PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI),
  252. /* audioIns */ 0,
  253. /* audioOuts */ 2,
  254. /* midiIns */ 0,
  255. /* midiOuts */ 0,
  256. /* paramIns */ 1,
  257. /* paramOuts */ 0,
  258. /* name */ "Audio File",
  259. /* label */ "audiofile",
  260. /* maker */ "falkTX",
  261. /* copyright */ "GNU GPL v2+",
  262. PluginDescriptorFILL(AudioFilePlugin)
  263. };
  264. // -----------------------------------------------------------------------
  265. void carla_register_native_plugin_audiofile()
  266. {
  267. carla_register_native_plugin(&audiofileDesc);
  268. }
  269. // -----------------------------------------------------------------------