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.

249 lines
5.9KB

  1. /*
  2. * dRowAudio_TappedDelayLine.cpp
  3. *
  4. * Created by David Rowland on 13/04/2009.
  5. * Copyright 2009 dRowAudio. All rights reserved.
  6. *
  7. */
  8. #include "dRowAudio_TappedDelayLine.h"
  9. TappedDelayLine::TappedDelayLine(int initialBufferSize)
  10. : pfDelayBuffer(0)
  11. {
  12. initialiseBuffer(initialBufferSize);
  13. }
  14. TappedDelayLine::TappedDelayLine(float bufferLengthMs, double sampleRate)
  15. : pfDelayBuffer(0)
  16. {
  17. int initialBufferSize = (int)((bufferLengthMs * 0.001) * sampleRate);
  18. initialiseBuffer(initialBufferSize);
  19. }
  20. void TappedDelayLine::initialiseBuffer(int bufferSize_)
  21. {
  22. bufferSize = bufferSize_;
  23. bufferWritePos = 0;
  24. inputGain = 1.0f;
  25. feedbackGain = 0.99f;
  26. spacingCoefficient = 1.0f;
  27. feedbackCoefficient = 1.0f;
  28. delete[] pfDelayBuffer;
  29. pfDelayBuffer = new float[bufferSize];
  30. for (int i = 0; i < bufferSize; i++)
  31. pfDelayBuffer[i] = 0;
  32. }
  33. TappedDelayLine::~TappedDelayLine()
  34. {
  35. readTaps.clear();
  36. delete[] pfDelayBuffer;
  37. pfDelayBuffer = 0;
  38. }
  39. void TappedDelayLine::addTap(int noDelaySamples, int sampleRate)
  40. {
  41. jassert(noDelaySamples < bufferSize);
  42. Tap newTap;
  43. newTap.originalDelaySamples = noDelaySamples;
  44. newTap.delaySamples = newTap.originalDelaySamples;
  45. newTap.originalTapFeedback = feedbackCoefficient;
  46. newTap.tapFeedback = newTap.originalTapFeedback;
  47. newTap.sampleRateWhenCreated = sampleRate;
  48. newTap.tapGain = 0.15f;
  49. readTaps.add(newTap);
  50. noTaps = readTaps.size();
  51. }
  52. void TappedDelayLine::addTapAtTime(int newTapPosMs, double sampleRate)
  53. {
  54. int newTapPosSamples = (int)((newTapPosMs * 0.001) * sampleRate);
  55. addTap(newTapPosSamples, sampleRate);
  56. }
  57. bool TappedDelayLine::setTapDelayTime(int tapIndex, int newTapPosMs, double sampleRate)
  58. {
  59. return setTapDelaySamples(tapIndex, msToSamples(newTapPosMs, sampleRate));
  60. }
  61. bool TappedDelayLine::setTapDelaySamples(int tapIndex, int newDelaySamples)
  62. {
  63. if ( tapIndex < readTaps.size() )
  64. {
  65. readTaps.getReference(tapIndex).delaySamples = newDelaySamples;
  66. return true;
  67. }
  68. return false;
  69. }
  70. void TappedDelayLine::setTapSpacing(float newSpacingCoefficient)
  71. {
  72. if ( !almostEqual<float>(spacingCoefficient, newSpacingCoefficient) )
  73. {
  74. spacingCoefficient = fabsf(newSpacingCoefficient);
  75. for (int i = 0; i < readTaps.size(); i++)
  76. {
  77. int newDelaySamples = (readTaps[i].originalDelaySamples * spacingCoefficient);
  78. jlimit(0, bufferSize, newDelaySamples);
  79. readTaps.getReference(i).delaySamples = newDelaySamples;
  80. }
  81. }
  82. }
  83. void TappedDelayLine::setTapSpacingExplicitly(float newSpacingCoefficient)
  84. {
  85. spacingCoefficient = fabsf(newSpacingCoefficient);
  86. for (int i = 0; i < readTaps.size(); i++)
  87. {
  88. int newDelaySamples = (readTaps[i].originalDelaySamples * spacingCoefficient);
  89. jlimit(0, bufferSize, newDelaySamples);
  90. readTaps.getReference(i).delaySamples = newDelaySamples;
  91. }
  92. }
  93. void TappedDelayLine::scaleFeedbacks(float newFeedbackCoefficient)
  94. {
  95. if ( !almostEqual<float>(feedbackCoefficient, newFeedbackCoefficient) )
  96. {
  97. feedbackCoefficient = newFeedbackCoefficient;
  98. for (int i = 0; i < readTaps.size(); i++)
  99. readTaps.getReference(i).tapFeedback = readTaps.getReference(i).originalTapFeedback * feedbackCoefficient;
  100. }
  101. }
  102. Array<int> TappedDelayLine::getTapSamplePositions()
  103. {
  104. Array<int> tapSamplePositions;
  105. for (int i = 0; i < readTaps.size(); i++)
  106. tapSamplePositions.add(readTaps[i].delaySamples);
  107. return tapSamplePositions;
  108. }
  109. bool TappedDelayLine::removeTapAtIndex(int tapIndex)
  110. {
  111. readTaps.remove(tapIndex);
  112. if (readTaps.size() < noTaps) {
  113. noTaps = readTaps.size();
  114. return true;
  115. }
  116. return false;
  117. }
  118. bool TappedDelayLine::removeTapAtSample(int sampleForRemovedTap)
  119. {
  120. for (int i = 0; i < readTaps.size(); i++)
  121. if (readTaps[i].delaySamples == sampleForRemovedTap) {
  122. readTaps.remove(i);
  123. noTaps = readTaps.size();
  124. return true;
  125. }
  126. return false;
  127. }
  128. bool TappedDelayLine::removeTapAtMs(int timeMsForRemovedTap, int sampleRate)
  129. {
  130. int tapsample = timeMsForRemovedTap * 0.001 * sampleRate;
  131. return removeTapAtSample(tapsample);
  132. }
  133. void TappedDelayLine::removeAllTaps()
  134. {
  135. readTaps.clear();
  136. noTaps = readTaps.size();
  137. }
  138. void TappedDelayLine::updateDelayTimes(double newSampleRate)
  139. {
  140. for (int i = 0; i < readTaps.size(); i++)
  141. {
  142. if ( (int)readTaps[i].sampleRateWhenCreated != 0
  143. && !almostEqual<double>(newSampleRate, readTaps.getReference(i).sampleRateWhenCreated) )
  144. {
  145. double scale = (newSampleRate / readTaps.getReference(i).sampleRateWhenCreated);
  146. readTaps.getReference(i).delaySamples *= scale;
  147. readTaps.getReference(i).sampleRateWhenCreated = newSampleRate;
  148. }
  149. }
  150. }
  151. float TappedDelayLine::processSingleSample(float newSample) throw()
  152. {
  153. // incriment buffer position and store new sample
  154. if(++bufferWritePos > bufferSize)
  155. bufferWritePos = 0;
  156. float *bufferInput = &pfDelayBuffer[bufferWritePos];
  157. *bufferInput = 0;
  158. float fOut = (inputGain * newSample);
  159. for (int i = 0; i < noTaps; ++i)
  160. {
  161. const Tap currentTap = readTaps.getReference(i);
  162. int tapReadPos = bufferWritePos - currentTap.delaySamples;
  163. if (tapReadPos < 0)
  164. tapReadPos += bufferSize;
  165. float tapOutput = currentTap.tapGain * pfDelayBuffer[tapReadPos];
  166. fOut += tapOutput;
  167. *bufferInput += currentTap.tapFeedback * tapOutput;
  168. }
  169. *bufferInput += newSample;
  170. return fOut;
  171. }
  172. void TappedDelayLine::processSamples (float* const samples,
  173. const int numSamples) throw()
  174. {
  175. const ScopedLock sl (processLock);
  176. for (int i = 0; i < numSamples; ++i)
  177. {
  178. const float in = samples[i];
  179. // incriment buffer position and store new sample
  180. if(++bufferWritePos >= bufferSize)
  181. bufferWritePos = 0;
  182. float *bufferInput = &pfDelayBuffer[bufferWritePos];
  183. *bufferInput = 0;
  184. float fOut = (inputGain * in);
  185. for (int t = 0; t < noTaps; ++t)
  186. {
  187. const Tap currentTap = readTaps.getReference(t);
  188. int tapReadPos = bufferWritePos - currentTap.delaySamples;
  189. if (tapReadPos < 0)
  190. tapReadPos += bufferSize;
  191. float tapOutput = currentTap.tapGain * pfDelayBuffer[tapReadPos];
  192. fOut += tapOutput;
  193. *bufferInput += currentTap.tapFeedback * tapOutput;
  194. }
  195. *bufferInput += in;
  196. samples[i] = fOut;
  197. }
  198. }