DISTRHO Plugin Framework
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.

342 lines
11KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "DistrhoPluginInternal.hpp"
  17. #include "CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.h"
  18. // -----------------------------------------------------------------------
  19. START_NAMESPACE_DISTRHO
  20. // #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  21. static const writeMidiFunc writeMidiCallback = nullptr;
  22. // #endif
  23. // -----------------------------------------------------------------------
  24. struct LastValuesInit {
  25. LastValuesInit()
  26. {
  27. if (d_lastBufferSize == 0)
  28. d_lastBufferSize = kAUDefaultMaxFramesPerSlice;
  29. if (d_isZero(d_lastSampleRate))
  30. d_lastSampleRate = kAUDefaultSampleRate;
  31. };
  32. };
  33. // -----------------------------------------------------------------------
  34. // AU Plugin
  35. class PluginAU : public AUEffectBase
  36. {
  37. public:
  38. PluginAU(AudioUnit component)
  39. : AUEffectBase(component),
  40. fLastValuesInit(),
  41. fPlugin(this, writeMidiCallback),
  42. fNumChannels(0),
  43. fLastParameterValues(nullptr)
  44. {
  45. CreateElements();
  46. AUElement* const globals = Globals();
  47. DISTRHO_SAFE_ASSERT_RETURN(globals != nullptr,);
  48. if (const uint32_t paramCount = fPlugin.getParameterCount())
  49. {
  50. fLastParameterValues = new float[paramCount];
  51. globals->UseIndexedParameters(paramCount);
  52. for (uint32_t i=0; i < paramCount; ++i)
  53. {
  54. fLastParameterValues[i] = fPlugin.getParameterValue(i);
  55. globals->SetParameter(i, fLastParameterValues[i]);
  56. }
  57. }
  58. }
  59. ~PluginAU() override
  60. {
  61. if (fLastParameterValues)
  62. {
  63. delete[] fLastParameterValues;
  64. fLastParameterValues = nullptr;
  65. }
  66. }
  67. protected:
  68. OSStatus GetParameterValueStrings(AudioUnitScope inScope,
  69. AudioUnitParameterID inParameterID,
  70. CFArrayRef* outStrings) override
  71. {
  72. // TODO scalepoints support via kAudioUnitParameterFlag_ValuesHaveStrings
  73. return kAudioUnitErr_InvalidProperty;
  74. }
  75. OSStatus GetParameterInfo(AudioUnitScope inScope,
  76. AudioUnitParameterID inParameterID,
  77. AudioUnitParameterInfo& outParameterInfo) override
  78. {
  79. DISTRHO_SAFE_ASSERT_RETURN(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidParameter);
  80. outParameterInfo.flags = kAudioUnitParameterFlag_IsReadable | kAudioUnitParameterFlag_IsWritable;
  81. // Name
  82. {
  83. const String& name = fPlugin.getParameterName(inParameterID);
  84. CFStringRef cfname = CFStringCreateWithCString(kCFAllocatorDefault, name.buffer(), kCFStringEncodingUTF8);
  85. AUBase::FillInParameterName(outParameterInfo, cfname, false);
  86. }
  87. // Hints
  88. {
  89. const uint32_t hints(fPlugin.getParameterHints(inParameterID));
  90. // other interesting bits:
  91. // kAudioUnitParameterFlag_OmitFromPresets for outputs?
  92. // kAudioUnitParameterFlag_MeterReadOnly for outputs?
  93. // kAudioUnitParameterFlag_CanRamp for log?
  94. // kAudioUnitParameterFlag_IsHighResolution ??
  95. if ((hints & kParameterIsAutomable) == 0x0)
  96. outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
  97. /* TODO: there doesn't seem to be a hint for this
  98. if (hints & kParameterIsBoolean)
  99. {}
  100. else if (hints & kParameterIsInteger)
  101. {}
  102. */
  103. if (hints & kParameterIsLogarithmic)
  104. outParameterInfo.flags |= kAudioUnitParameterFlag_DisplayLogarithmic;
  105. }
  106. // Ranges
  107. {
  108. const ParameterRanges& ranges(fPlugin.getParameterRanges(inParameterID));
  109. outParameterInfo.defaultValue = ranges.def;
  110. outParameterInfo.minValue = ranges.min;
  111. outParameterInfo.maxValue = ranges.max;
  112. }
  113. // Unit
  114. {
  115. const String& unit = fPlugin.getParameterUnit(inParameterID);
  116. // TODO: map all AU unit types
  117. if (unit == "dB")
  118. {
  119. outParameterInfo.unit = kAudioUnitParameterUnit_LinearGain;
  120. }
  121. else
  122. {
  123. outParameterInfo.unit = kAudioUnitParameterUnit_CustomUnit;
  124. outParameterInfo.unitName = CFStringCreateWithCString(kCFAllocatorDefault, unit.buffer(), kCFStringEncodingUTF8);
  125. }
  126. }
  127. return noErr;
  128. }
  129. OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
  130. AudioUnitScope inScope,
  131. AudioUnitElement inElement,
  132. UInt32& outDataSize,
  133. Boolean& outWritable) override
  134. {
  135. return AUEffectBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
  136. }
  137. OSStatus GetProperty(AudioUnitPropertyID inID,
  138. AudioUnitScope inScope,
  139. AudioUnitElement inElement,
  140. void* outData) override
  141. {
  142. return AUEffectBase::GetProperty (inID, inScope, inElement, outData);
  143. }
  144. #if 0
  145. void SetParameter(AudioUnitParameterID index,
  146. AudioUnitParameterValue value) override
  147. {
  148. d_stdout("SetParameter %u %f", index, value);
  149. const uint32_t hints(fPlugin.getParameterHints(index));
  150. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  151. if (hints & kParameterIsBoolean)
  152. {
  153. const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f;
  154. value = value > midRange ? ranges.max : ranges.min;
  155. }
  156. else if (hints & kParameterIsInteger)
  157. {
  158. value = std::round(value);
  159. }
  160. fPlugin.setParameterValue(index, value);
  161. //printf("SET: id=%d val=%f\n", index, value);
  162. }
  163. #endif
  164. bool SupportsTail() override
  165. {
  166. return false;
  167. }
  168. OSStatus Version() override
  169. {
  170. return fPlugin.getVersion();
  171. }
  172. OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,
  173. const AudioBufferList& inBuffer,
  174. AudioBufferList& outBuffer,
  175. UInt32 inFramesToProcess) override
  176. {
  177. const float* srcBuffer[fNumChannels];
  178. /* */ float* destBuffer[fNumChannels];
  179. for (uint32_t i = 0; i < fNumChannels; ++i) {
  180. srcBuffer[i] = (const float*)inBuffer.mBuffers[i].mData;
  181. destBuffer[i] = (float *)outBuffer.mBuffers[i].mData;
  182. }
  183. updateParameterInputs();
  184. fPlugin.run(srcBuffer, destBuffer, inFramesToProcess);
  185. updateParameterOutputsAndTriggers();
  186. ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
  187. return noErr;
  188. }
  189. // -------------------------------------------------------------------
  190. ComponentResult Initialize() override
  191. {
  192. ComponentResult err;
  193. if ((err = AUEffectBase::Initialize()) != noErr)
  194. return err;
  195. fPlugin.activate();
  196. // FIXME this does not seem right
  197. fNumChannels = GetNumberOfChannels();
  198. d_stdout("fNumChannels %u", fNumChannels);
  199. DISTRHO_SAFE_ASSERT(fNumChannels == DISTRHO_PLUGIN_NUM_INPUTS);
  200. return noErr;
  201. }
  202. void Cleanup() override
  203. {
  204. AUEffectBase::Cleanup();
  205. fPlugin.deactivate();
  206. }
  207. // -------------------------------------------------------------------
  208. private:
  209. LastValuesInit fLastValuesInit;
  210. PluginExporter fPlugin;
  211. uint32_t fNumChannels;
  212. // Temporary data
  213. float* fLastParameterValues;
  214. void updateParameterInputs()
  215. {
  216. float value;
  217. for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
  218. {
  219. if (! fPlugin.isParameterInput(i))
  220. continue;
  221. value = GetParameter(i);
  222. if (d_isEqual(fLastParameterValues[i], value))
  223. continue;
  224. fLastParameterValues[i] = value;
  225. fPlugin.setParameterValue(i, value);
  226. }
  227. }
  228. void updateParameterOutputsAndTriggers()
  229. {
  230. float value;
  231. for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
  232. {
  233. if (fPlugin.isParameterOutput(i))
  234. {
  235. value = fLastParameterValues[i] = fPlugin.getParameterValue(i);
  236. SetParameter(i, value);
  237. }
  238. else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger)
  239. {
  240. // NOTE: no trigger support in AU, simulate it here
  241. value = fPlugin.getParameterRanges(i).def;
  242. if (d_isEqual(value, fPlugin.getParameterValue(i)))
  243. continue;
  244. fLastParameterValues[i] = value;
  245. fPlugin.setParameterValue(i, value);
  246. SetParameter(i, value);
  247. }
  248. }
  249. }
  250. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginAU)
  251. };
  252. END_NAMESPACE_DISTRHO
  253. // -----------------------------------------------------------------------
  254. COMPONENT_ENTRY(PluginAU)
  255. // -----------------------------------------------------------------------
  256. #include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.cpp"
  257. #include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.cpp"
  258. #include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.cpp"
  259. #include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.cpp"
  260. #include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.cpp"
  261. #include "CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.cpp"
  262. #include "CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp"
  263. #include "CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.cpp"
  264. #include "CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.cpp"
  265. #include "CoreAudio106/PublicUtility/CAAudioChannelLayout.cpp"
  266. #include "CoreAudio106/PublicUtility/CAAUParameter.cpp"
  267. #include "CoreAudio106/PublicUtility/CAMutex.cpp"
  268. #include "CoreAudio106/PublicUtility/CAStreamBasicDescription.cpp"
  269. #include "CoreAudio106/PublicUtility/CAVectorUnit.cpp"
  270. // -----------------------------------------------------------------------