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 8.9KB

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