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.

252 lines
4.4KB

  1. #include "Analyzer.h"
  2. struct Analyzer::Data
  3. {
  4. Data(int size_);
  5. void clear();
  6. void copyFrom (const Data& other);
  7. const juce::CriticalSection& getLock() const;
  8. const int size;
  9. juce::HeapBlock<float> mags;
  10. juce::HeapBlock<float> angles;
  11. private:
  12. juce::CriticalSection lock;
  13. JUCE_DECLARE_NON_COPYABLE(Data)
  14. };
  15. Analyzer::Data::Data (int size_)
  16. : size (size_),
  17. mags (size),
  18. angles (size)
  19. {
  20. clear();
  21. }
  22. void Analyzer::Data::clear()
  23. {
  24. juce::zeromem(mags, sizeof(float) * size);
  25. juce::zeromem(angles, sizeof(float) * size);
  26. }
  27. void Analyzer::Data::copyFrom (const Data& other)
  28. {
  29. if (other.size == size)
  30. {
  31. memcpy(mags, other.mags, sizeof(float) * size);
  32. memcpy(angles, other.angles, sizeof(float) * size);
  33. }
  34. }
  35. const juce::CriticalSection& Analyzer::Data::getLock() const
  36. {
  37. return lock;
  38. }
  39. RmsEnvelope::RmsEnvelope (int envsize, double rmsLength, double updatetime)
  40. : rms (rmsLength), rmsVals (envsize+1), updateTime (updatetime), sampleRate (44100)
  41. {
  42. clear();
  43. }
  44. void RmsEnvelope::setSampleRate (double newSampleRate)
  45. {
  46. sampleRate = newSampleRate;
  47. rms.setSampleRate(sampleRate);
  48. clear();
  49. }
  50. void RmsEnvelope::clear()
  51. {
  52. rms.clear();
  53. rmsVals.clear();
  54. updateIndex = 0;
  55. }
  56. bool RmsEnvelope::process (const float inL, const float inR)
  57. {
  58. rms.process(inL, inR);
  59. const int ovSize = int(updateTime * sampleRate);
  60. jassert(ovSize > 100);
  61. if (++updateIndex >= ovSize)
  62. {
  63. updateIndex = 0;
  64. const float rmsVal = rms.getRms();
  65. rmsVals.push(rmsVal);
  66. return true;
  67. }
  68. return false;
  69. }
  70. void RmsEnvelope::processBlock (const float* inL, const float* inR, int numSamples)
  71. {
  72. ScopedLock lock(processLock);
  73. const int ovSize = int(updateTime * sampleRate);
  74. jassert(ovSize > 100);
  75. int idx = 0;
  76. while (numSamples > 0)
  77. {
  78. const int curNumSamples = jmin(ovSize-updateIndex, numSamples);
  79. rms.processBlock(&inL[idx], &inR[idx], curNumSamples);
  80. numSamples -= curNumSamples;
  81. idx += curNumSamples;
  82. updateIndex += curNumSamples;
  83. if (updateIndex >= ovSize)
  84. {
  85. updateIndex = 0;
  86. const float rmsVal = rms.getRms();
  87. rmsVals.push(rmsVal);
  88. }
  89. }
  90. }
  91. bool RmsEnvelope::getData (Array<float>& data) const
  92. {
  93. const int dataLength = getDataLength();
  94. if (data.size() < dataLength)
  95. {
  96. ScopedTryLock lock(processLock);
  97. if (! lock.isLocked())
  98. return false;
  99. for (int i=0; i<data.size(); ++i)
  100. data.getReference(i) = rmsVals[i];
  101. return true;
  102. }
  103. return false;
  104. }
  105. int RmsEnvelope::getDataLength() const
  106. {
  107. return rmsVals.getSize() - 1;
  108. }
  109. Analyzer::Analyzer()
  110. : sampleRate (0)
  111. {
  112. setSampleRate(44100);
  113. }
  114. void Analyzer::clear()
  115. {
  116. fftIndex = 0;
  117. data->clear();
  118. }
  119. void Analyzer::processBlock (const float* inL, const float* inR, int numSamples)
  120. {
  121. for (int i=0; i<numSamples; ++i)
  122. {
  123. x[fftIndex] = 0.5f * (inL[i] + inR[i]) * window[fftIndex];
  124. ++fftIndex;
  125. if (fftIndex >= fftBlockSize)
  126. {
  127. processFFT();
  128. fftIndex = 0;
  129. }
  130. }
  131. }
  132. int Analyzer::getFFTSize() const
  133. {
  134. return fftBlockSize;
  135. }
  136. int Analyzer::getNumBins() const
  137. {
  138. return numBins;
  139. }
  140. bool Analyzer::getData (Data& d) const
  141. {
  142. ScopedTryLock lock(data->getLock());
  143. if (lock.isLocked())
  144. {
  145. d.copyFrom(*data);
  146. return true;
  147. }
  148. return false;
  149. }
  150. void Analyzer::setSampleRate (double newSampleRate)
  151. {
  152. if (sampleRate != newSampleRate)
  153. {
  154. sampleRate = newSampleRate;
  155. fftBlockSize = 512 * jmax(1, int(sampleRate / 44100));
  156. numBins = fftBlockSize / 2 + 1;
  157. fft = new ffft::FFTReal<float> (fftBlockSize);
  158. x.realloc(fftBlockSize);
  159. f.realloc(fftBlockSize);
  160. window.realloc(fftBlockSize);
  161. data = new Data(numBins);
  162. {
  163. const float alpha = 0.16f;
  164. const float a0 = 0.5f * (1-alpha);
  165. const float a1 = 0.5f;
  166. const float a2 = alpha*0.5f;
  167. for (int i=0; i<fftBlockSize; ++i)
  168. window[i] = a0 - a1*cos(2*float_Pi*i/(fftBlockSize-1)) + a2*cos(4*float_Pi*i/(fftBlockSize-1));
  169. }
  170. clear();
  171. }
  172. }
  173. double Analyzer::getSampleRate() const
  174. {
  175. return sampleRate;
  176. }
  177. void Analyzer::processFFT()
  178. {
  179. fft->do_fft(f, x);
  180. const int imagOffset = fftBlockSize / 2;
  181. const float weight = 1.f / fftBlockSize;
  182. {
  183. ScopedLock lock(data->getLock());
  184. data->mags[0] = f[0]*f[0] * weight;
  185. data->mags[imagOffset] = f[imagOffset]*f[imagOffset] * weight;
  186. data->angles[0] = 0;
  187. data->angles[numBins-1] = 0;
  188. for (int i=1; i<numBins-1; ++i)
  189. {
  190. const float re = f[i];
  191. const float im = f[imagOffset + i];
  192. data->mags[i] = (re*re + im*im) * weight;
  193. data->angles[i] = atan2(im, re);
  194. }
  195. }
  196. }