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.

354 lines
9.6KB

  1. //-----------------------------------------------------------------------------
  2. // Project : VST SDK
  3. //
  4. // Category : Helpers
  5. // Filename : public.sdk/source/vst/vstbypassprocessor.cpp
  6. // Created by : Steinberg, 04/2015
  7. // Description : Example of bypass support Implementation
  8. //
  9. //-----------------------------------------------------------------------------
  10. // LICENSE
  11. // (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
  12. //-----------------------------------------------------------------------------
  13. // Redistribution and use in source and binary forms, with or without modification,
  14. // are permitted provided that the following conditions are met:
  15. //
  16. // * Redistributions of source code must retain the above copyright notice,
  17. // this list of conditions and the following disclaimer.
  18. // * Redistributions in binary form must reproduce the above copyright notice,
  19. // this list of conditions and the following disclaimer in the documentation
  20. // and/or other materials provided with the distribution.
  21. // * Neither the name of the Steinberg Media Technologies nor the names of its
  22. // contributors may be used to endorse or promote products derived from this
  23. // software without specific prior written permission.
  24. //
  25. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  26. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  27. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  28. // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  29. // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  30. // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  31. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  32. // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  33. // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  34. // OF THE POSSIBILITY OF SUCH DAMAGE.
  35. //-----------------------------------------------------------------------------
  36. #include "vstbypassprocessor.h"
  37. #include "vstspeakerarray.h"
  38. #include <cstdlib>
  39. namespace Steinberg {
  40. namespace Vst {
  41. //------------------------------------------------------------------------
  42. static bool delay (int32 sampleFrames, float* inStream, float* outStream, float* delayBuffer,
  43. int32 bufferSize, int32 bufferInPos, int32 bufferOutPos)
  44. {
  45. // delay inStream
  46. int32 remain, inFrames, outFrames;
  47. float* bufIn;
  48. float* bufOut;
  49. remain = sampleFrames;
  50. while (remain > 0)
  51. {
  52. bufIn = delayBuffer + bufferInPos;
  53. bufOut = delayBuffer + bufferOutPos;
  54. if (bufferInPos > bufferOutPos)
  55. inFrames = bufferSize - bufferInPos;
  56. else
  57. inFrames = bufferOutPos - bufferInPos;
  58. outFrames = bufferSize - bufferOutPos;
  59. if (inFrames > remain)
  60. inFrames = remain;
  61. if (outFrames > inFrames)
  62. outFrames = inFrames;
  63. // order important for in-place processing!
  64. memcpy (bufIn, inStream, inFrames * sizeof (float)); // copy to buffer
  65. memcpy (outStream, bufOut, outFrames * sizeof (float)); // copy from buffer
  66. inStream += inFrames;
  67. outStream += outFrames;
  68. bufferInPos += inFrames;
  69. if (bufferInPos >= bufferSize)
  70. bufferInPos -= bufferSize;
  71. bufferOutPos += outFrames;
  72. if (bufferOutPos >= bufferSize)
  73. bufferOutPos -= bufferSize;
  74. if (inFrames > outFrames)
  75. {
  76. // still some output to copy
  77. bufOut = delayBuffer + bufferOutPos;
  78. outFrames = inFrames - outFrames;
  79. memcpy (outStream, bufOut, outFrames * sizeof (float)); // copy from buffer
  80. outStream += outFrames;
  81. bufferOutPos += outFrames;
  82. if (bufferOutPos >= bufferSize)
  83. bufferOutPos -= bufferSize;
  84. }
  85. remain -= inFrames;
  86. }
  87. return true;
  88. }
  89. //------------------------------------------------------------------------
  90. // AudioBuffer Implementation
  91. //------------------------------------------------------------------------
  92. AudioBuffer::AudioBuffer ()
  93. : mBuffer (nullptr)
  94. , mMaxSamples (0)
  95. {}
  96. //------------------------------------------------------------------------
  97. AudioBuffer::~AudioBuffer ()
  98. {
  99. resize (0);
  100. }
  101. //------------------------------------------------------------------------
  102. void AudioBuffer::resize (int32 _maxSamples)
  103. {
  104. if (mMaxSamples != _maxSamples)
  105. {
  106. mMaxSamples = _maxSamples;
  107. if (mMaxSamples <= 0)
  108. {
  109. if (mBuffer)
  110. free (mBuffer),
  111. mBuffer = nullptr;
  112. }
  113. else
  114. {
  115. if (mBuffer)
  116. mBuffer = (float*)realloc (mBuffer, mMaxSamples * sizeof (float));
  117. else
  118. mBuffer = (float*)malloc (mMaxSamples * sizeof (float));
  119. }
  120. }
  121. }
  122. //------------------------------------------------------------------------
  123. void AudioBuffer::clear (int32 numSamples)
  124. {
  125. if (mBuffer)
  126. {
  127. int32 count = numSamples < mMaxSamples ? numSamples : mMaxSamples;
  128. memset (mBuffer, 0, count * sizeof (float));
  129. }
  130. }
  131. //------------------------------------------------------------------------
  132. //------------------------------------------------------------------------
  133. // BypassProcessor Implementation
  134. //------------------------------------------------------------------------
  135. BypassProcessor::BypassProcessor () : mActive (false), mMainIOBypass (false)
  136. {
  137. for (int32 i = 0; i < kMaxChannelsSupported; i++)
  138. {
  139. mInputPinLookup[i] = -1;
  140. mDelays[i] = nullptr;
  141. }
  142. }
  143. //------------------------------------------------------------------------
  144. BypassProcessor::~BypassProcessor () { reset (); }
  145. //------------------------------------------------------------------------
  146. void BypassProcessor::setup (IAudioProcessor& audioProcessor, ProcessSetup& processSetup,
  147. int32 delaySamples)
  148. {
  149. reset ();
  150. SpeakerArrangement inputArr = 0;
  151. bool hasInput = audioProcessor.getBusArrangement (kInput, 0, inputArr) == kResultOk;
  152. SpeakerArrangement outputArr = 0;
  153. bool hasOutput = audioProcessor.getBusArrangement (kOutput, 0, outputArr) == kResultOk;
  154. mMainIOBypass = hasInput && hasOutput;
  155. if (!mMainIOBypass)
  156. return;
  157. // create lookup table (in <- out) and delays...
  158. SpeakerArray inArray (inputArr);
  159. SpeakerArray outArray (outputArr);
  160. // security check (todo)
  161. if (outArray.total () >= kMaxChannelsSupported)
  162. return;
  163. for (int32 i = 0; i < outArray.total (); i++)
  164. {
  165. if (outArray.at (i) == Vst::kSpeakerL)
  166. {
  167. if (inArray.total () == 1 && inArray.at (0) == Vst::kSpeakerM)
  168. {
  169. mInputPinLookup[i] = 0;
  170. }
  171. else
  172. mInputPinLookup[i] = inArray.getSpeakerIndex (outArray.at (i));
  173. }
  174. else
  175. mInputPinLookup[i] = inArray.getSpeakerIndex (outArray.at (i));
  176. mDelays[i] = new Delay (processSetup.maxSamplesPerBlock, delaySamples);
  177. mDelays[i]->flush ();
  178. }
  179. }
  180. //------------------------------------------------------------------------
  181. void BypassProcessor::reset ()
  182. {
  183. mMainIOBypass = false;
  184. for (int32 i = 0; i < kMaxChannelsSupported; i++)
  185. {
  186. mInputPinLookup[i] = -1;
  187. if (mDelays[i])
  188. {
  189. delete mDelays[i];
  190. mDelays[i] = nullptr;
  191. }
  192. }
  193. }
  194. //------------------------------------------------------------------------
  195. void BypassProcessor::setActive (bool state)
  196. {
  197. if (mActive == state)
  198. return;
  199. mActive = state;
  200. // flush delays when turning on
  201. if (state && mMainIOBypass)
  202. for (int32 i = 0; i < kMaxChannelsSupported; i++)
  203. {
  204. if (!mDelays[i])
  205. break;
  206. mDelays[i]->flush ();
  207. }
  208. }
  209. //------------------------------------------------------------------------
  210. void BypassProcessor::process (ProcessData& data)
  211. {
  212. if (mMainIOBypass)
  213. {
  214. AudioBusBuffers& inBus = data.inputs[0];
  215. AudioBusBuffers& outBus = data.outputs[0];
  216. for (int32 channel = 0; channel < outBus.numChannels; channel++)
  217. {
  218. float* src = nullptr;
  219. bool silent = true;
  220. float* dst = outBus.channelBuffers32[channel];
  221. if (!dst)
  222. continue;
  223. int inputChannel = mInputPinLookup[channel];
  224. if (inputChannel != -1)
  225. {
  226. silent = (inBus.silenceFlags & (1ll << inputChannel)) != 0;
  227. src = inBus.channelBuffers32[inputChannel];
  228. }
  229. if (mDelays[channel]->process (src, dst, data.numSamples, silent))
  230. {
  231. outBus.silenceFlags |= (1ll << channel);
  232. }
  233. else
  234. {
  235. outBus.silenceFlags = 0;
  236. }
  237. }
  238. }
  239. // clear all other outputs
  240. for (int32 outBusIndex = mMainIOBypass ? 1 : 0; outBusIndex < data.numOutputs; outBusIndex++)
  241. {
  242. AudioBusBuffers& outBus = data.outputs[outBusIndex];
  243. if (!outBus.channelBuffers32)
  244. continue;
  245. for (int32 channel = 0; channel < outBus.numChannels; channel++)
  246. {
  247. float* dst = outBus.channelBuffers32[channel];
  248. if (dst)
  249. {
  250. memset (dst, 0, data.numSamples * sizeof (float));
  251. outBus.silenceFlags |= 1ll << channel;
  252. }
  253. }
  254. }
  255. }
  256. //------------------------------------------------------------------------
  257. void BypassProcessor::Delay::flush ()
  258. {
  259. mDelayBuffer.clearAll ();
  260. mInPos = mOutPos = 0;
  261. if (hasDelay ())
  262. mOutPos = getBufferSamples () - mDelaySamples; // must be != inPos
  263. }
  264. //------------------------------------------------------------------------
  265. bool BypassProcessor::Delay::process (float* src, float* dst, int32 numSamples, bool silentIn)
  266. {
  267. bool silentOut = false;
  268. if (hasDelay () && src)
  269. {
  270. int32 bufferSize = getBufferSamples ();
  271. delay (numSamples, src, dst, mDelayBuffer, bufferSize, mInPos, mOutPos);
  272. // update inPos, outPos
  273. mInPos += numSamples;
  274. if (mInPos >= bufferSize)
  275. mInPos -= bufferSize;
  276. mOutPos += numSamples;
  277. if (mOutPos >= bufferSize)
  278. mOutPos -= bufferSize;
  279. }
  280. else
  281. {
  282. if (src != dst)
  283. {
  284. if (src && !silentIn)
  285. {
  286. memcpy (dst, src, numSamples * sizeof (float));
  287. }
  288. else
  289. {
  290. memset (dst, 0, numSamples * sizeof (float));
  291. silentOut = true;
  292. }
  293. }
  294. else
  295. {
  296. silentOut = silentIn;
  297. }
  298. }
  299. return silentOut;
  300. }
  301. //------------------------------------------------------------------------
  302. } // namespace Vst
  303. } // namespace Steinberg