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.

323 lines
9.3KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2014 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 "CarlaNative.hpp"
  18. #include "CarlaMutex.hpp"
  19. #include "CarlaString.hpp"
  20. #include "juce_audio_formats.h"
  21. using juce::AudioFormat;
  22. using juce::AudioFormatManager;
  23. using juce::AudioFormatReader;
  24. using juce::AudioFormatReaderSource;
  25. using juce::AudioSampleBuffer;
  26. using juce::BufferingAudioReader;
  27. using juce::File;
  28. using juce::FloatVectorOperations;
  29. using juce::MemoryMappedAudioFormatReader;
  30. using juce::ScopedPointer;
  31. using juce::TimeSliceThread;
  32. // -----------------------------------------------------------------------
  33. static AudioFormatManager& getAudioFormatManagerInstance()
  34. {
  35. static AudioFormatManager afm;
  36. afm.registerBasicFormats();
  37. return afm;
  38. }
  39. // -----------------------------------------------------------------------
  40. class AudioFilePlugin : public NativePluginClass
  41. {
  42. public:
  43. AudioFilePlugin(const NativeHostDescriptor* const host)
  44. : NativePluginClass(host),
  45. fLoopMode(false),
  46. fDoProcess(false),
  47. fLength(0),
  48. //fThread("AudioFilePluginThread"),
  49. fReaderBuffer(),
  50. fReaderMutex(),
  51. fReader(),
  52. fReaderSource(),
  53. leakDetector_AudioFilePlugin()
  54. {
  55. fReaderBuffer.setSize(2, static_cast<int>(getBufferSize()));
  56. }
  57. ~AudioFilePlugin() override
  58. {
  59. //fThread.stopThread(-1);
  60. fReader = nullptr;
  61. fReaderSource = nullptr;
  62. }
  63. protected:
  64. // -------------------------------------------------------------------
  65. // Plugin parameter calls
  66. uint32_t getParameterCount() const override
  67. {
  68. return 1;
  69. }
  70. const NativeParameter* getParameterInfo(const uint32_t index) const override
  71. {
  72. if (index != 0)
  73. return nullptr;
  74. static NativeParameter param;
  75. param.name = "Loop Mode";
  76. param.unit = nullptr;
  77. param.hints = static_cast<NativeParameterHints>(PARAMETER_IS_ENABLED|PARAMETER_IS_BOOLEAN);
  78. param.ranges.def = 1.0f;
  79. param.ranges.min = 0.0f;
  80. param.ranges.max = 1.0f;
  81. param.ranges.step = 1.0f;
  82. param.ranges.stepSmall = 1.0f;
  83. param.ranges.stepLarge = 1.0f;
  84. param.scalePointCount = 0;
  85. param.scalePoints = nullptr;
  86. return &param;
  87. }
  88. float getParameterValue(const uint32_t index) const override
  89. {
  90. if (index != 0)
  91. return 0.0f;
  92. return fLoopMode ? 1.0f : 0.0f;
  93. }
  94. // -------------------------------------------------------------------
  95. // Plugin state calls
  96. void setParameterValue(const uint32_t index, const float value) override
  97. {
  98. if (index != 0)
  99. return;
  100. const bool loopMode(value > 0.5f);
  101. if (fLoopMode == loopMode)
  102. return;
  103. fLoopMode = loopMode;
  104. const CarlaMutexLocker cml(fReaderMutex);
  105. if (fReaderSource != nullptr)
  106. fReaderSource->setLooping(loopMode);
  107. }
  108. void setCustomData(const char* const key, const char* const value) override
  109. {
  110. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  111. CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',);
  112. if (std::strcmp(key, "file") != 0)
  113. return;
  114. _loadAudioFile(value);
  115. }
  116. // -------------------------------------------------------------------
  117. // Plugin process calls
  118. void process(float**, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const, const uint32_t) override
  119. {
  120. const NativeTimeInfo* const timePos(getTimeInfo());
  121. const int iframes(static_cast<int>(frames));
  122. float* const out1(outBuffer[0]);
  123. float* const out2(outBuffer[1]);
  124. if (fLength == 0 || ! fDoProcess)
  125. {
  126. //carla_stderr("P: no process");
  127. FloatVectorOperations::clear(out1, iframes);
  128. FloatVectorOperations::clear(out2, iframes);
  129. return;
  130. }
  131. const int64_t nextReadPos(fLoopMode ? (static_cast<int64_t>(timePos->frame) % fLength) : static_cast<int64_t>(timePos->frame));
  132. // not playing
  133. if (! timePos->playing)
  134. {
  135. //carla_stderr("P: not playing");
  136. FloatVectorOperations::clear(out1, iframes);
  137. FloatVectorOperations::clear(out2, iframes);
  138. const CarlaMutexLocker cml(fReaderMutex);
  139. if (fReaderSource != nullptr)
  140. fReaderSource->setNextReadPosition(nextReadPos);
  141. return;
  142. }
  143. const CarlaMutexLocker cml(fReaderMutex);
  144. if (fReaderSource != nullptr)
  145. fReaderSource->setNextReadPosition(nextReadPos);
  146. if (fReader == nullptr)
  147. return;
  148. fReader->read(&fReaderBuffer, 0, iframes, nextReadPos, true, true);
  149. FloatVectorOperations::copy(out1, fReaderBuffer.getReadPointer(0), iframes);
  150. FloatVectorOperations::copy(out2, fReaderBuffer.getReadPointer(1), iframes);
  151. }
  152. // -------------------------------------------------------------------
  153. // Plugin UI calls
  154. void uiShow(const bool show) override
  155. {
  156. if (! show)
  157. return;
  158. if (const char* const filename = uiOpenFile(false, "Open Audio File", ""))
  159. uiCustomDataChanged("file", filename);
  160. uiClosed();
  161. }
  162. // -------------------------------------------------------------------
  163. // Plugin dispatcher calls
  164. void bufferSizeChanged(const uint32_t bufferSize) override
  165. {
  166. fReaderBuffer.setSize(2, static_cast<int>(bufferSize));
  167. }
  168. private:
  169. bool fLoopMode;
  170. bool fDoProcess;
  171. int64_t fLength;
  172. //TimeSliceThread fThread;
  173. AudioSampleBuffer fReaderBuffer;
  174. CarlaMutex fReaderMutex;
  175. ScopedPointer<AudioFormatReader> fReader;
  176. ScopedPointer<AudioFormatReaderSource> fReaderSource;
  177. void _loadAudioFile(const char* const filename)
  178. {
  179. carla_stdout("AudioFilePlugin::loadFilename(\"%s\")", filename);
  180. fDoProcess = false;
  181. fLength = 0;
  182. //fThread.stopThread(-1);
  183. {
  184. fReaderMutex.lock();
  185. AudioFormatReader* const reader(fReader.release());
  186. AudioFormatReaderSource* const readerSource(fReaderSource.release());
  187. fReaderMutex.unlock();
  188. delete readerSource;
  189. delete reader;
  190. }
  191. File file(filename);
  192. if (! file.existsAsFile())
  193. return;
  194. AudioFormatManager& afm(getAudioFormatManagerInstance());
  195. AudioFormat* const format(afm.findFormatForFileExtension(file.getFileExtension()));
  196. CARLA_SAFE_ASSERT_RETURN(format != nullptr,);
  197. if (MemoryMappedAudioFormatReader* const memReader = format->createMemoryMappedReader(file))
  198. {
  199. memReader->mapEntireFile();
  200. fReader = memReader;
  201. carla_stdout("Using memory mapped read file");
  202. }
  203. else
  204. {
  205. AudioFormatReader* const reader(afm.createReaderFor(file));
  206. CARLA_SAFE_ASSERT_RETURN(reader != nullptr,);
  207. // this code can be used for very large files
  208. //fThread.startThread();
  209. //BufferingAudioReader* const bufferingReader(new BufferingAudioReader(reader, fThread, getSampleRate()*2));
  210. //bufferingReader->setReadTimeout(50);
  211. AudioFormatReaderSource* const readerSource(new AudioFormatReaderSource(/*bufferingReader*/reader, false));
  212. readerSource->setLooping(fLoopMode);
  213. fReaderSource = readerSource;
  214. fReader = reader;
  215. carla_stdout("Using regular read file");
  216. }
  217. fLength = fReader->lengthInSamples;
  218. fDoProcess = true;
  219. }
  220. PluginClassEND(AudioFilePlugin)
  221. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioFilePlugin)
  222. };
  223. // -----------------------------------------------------------------------
  224. static const NativePluginDescriptor audiofileDesc = {
  225. /* category */ PLUGIN_CATEGORY_UTILITY,
  226. /* hints */ static_cast<NativePluginHints>(PLUGIN_HAS_UI|PLUGIN_NEEDS_UI_OPEN_SAVE),
  227. /* supports */ static_cast<NativePluginSupports>(0x0),
  228. /* audioIns */ 0,
  229. /* audioOuts */ 2,
  230. /* midiIns */ 0,
  231. /* midiOuts */ 0,
  232. /* paramIns */ 1,
  233. /* paramOuts */ 0,
  234. /* name */ "Audio File",
  235. /* label */ "audiofile",
  236. /* maker */ "falkTX",
  237. /* copyright */ "GNU GPL v2+",
  238. PluginDescriptorFILL(AudioFilePlugin)
  239. };
  240. // -----------------------------------------------------------------------
  241. CARLA_EXPORT
  242. void carla_register_native_plugin_audiofile();
  243. CARLA_EXPORT
  244. void carla_register_native_plugin_audiofile()
  245. {
  246. carla_register_native_plugin(&audiofileDesc);
  247. }
  248. // -----------------------------------------------------------------------