buffer.hpp (3256B)
1 #pragma once 2 3 #include "assert.h" 4 #include "math.h" 5 #include <algorithm> 6 7 namespace bogaudio { 8 namespace dsp { 9 10 template<typename T> 11 struct OverlappingBuffer { 12 const int _size; 13 const int _overlap; 14 const bool _autoProcess; 15 const int _overlapN; 16 const int _samplesN; 17 T* _samples; 18 int _sample; 19 20 OverlappingBuffer(int size, int o, bool autoProcess = true) 21 : _size(size) 22 , _overlap(o) 23 , _autoProcess(autoProcess) 24 , _overlapN(_size / _overlap) 25 , _samplesN(2*_size - _overlapN) 26 , _samples(new T[_samplesN]) 27 , _sample(0) 28 { 29 assert(_size > 0); 30 assert(_overlap > 0 && _overlap <= _size && _size % _overlap == 0); 31 } 32 virtual ~OverlappingBuffer() { 33 delete[] _samples; 34 } 35 36 inline void process() { processBuffer(_samples + _sample - _size); } 37 virtual void processBuffer(T* samples) = 0; 38 void postProcess() { 39 if (_overlap == 1) { 40 _sample = 0; 41 } 42 else if (_sample == _samplesN) { 43 std::copy(_samples + _size, _samples + _samplesN, _samples); 44 _sample = _samplesN - _size; 45 } 46 } 47 48 virtual bool step(T sample) { 49 _samples[_sample++] = sample; 50 assert(_sample <= _samplesN); 51 52 if (_sample >= _size && _sample % _overlapN == 0) { 53 if (_autoProcess) { 54 process(); 55 postProcess(); 56 } 57 return true; 58 } 59 return false; 60 } 61 }; 62 63 64 template<typename T> 65 struct AveragingBuffer { 66 const int _size; 67 const int _framesN; 68 const float _inverseFramesN; 69 T* _sums; 70 T* _averages; 71 T* _frames; 72 int _currentFrame; 73 const int _resetsPerCommit; 74 int _currentReset; 75 76 AveragingBuffer( 77 int size, 78 int framesToAverage 79 ) 80 : _size(size) 81 , _framesN(framesToAverage) 82 , _inverseFramesN(1.0 / (float)_framesN) 83 , _sums(new T[_size] {}) 84 , _averages(new T[_size] {}) 85 , _frames(new T[_size * _framesN] {}) 86 , _currentFrame(0) 87 , _resetsPerCommit(std::max(_size / 100, 10)) 88 , _currentReset(0) 89 { 90 assert(framesToAverage > 0); 91 } 92 ~AveragingBuffer() { 93 delete[] _sums; 94 delete[] _averages; 95 delete[] _frames; 96 } 97 98 T* getInputFrame() { 99 float* frame = _frames + _currentFrame*_size; 100 for (int i = 0; i < _size; ++i) { 101 _sums[i] -= frame[i]; 102 } 103 return frame; 104 } 105 106 void commitInputFrame() { 107 float* frame = _frames + _currentFrame*_size; 108 for (int i = 0; i < _size; ++i) { 109 _sums[i] += frame[i]; 110 _averages[i] = _sums[i] * _inverseFramesN; 111 } 112 113 // Reset the average for some bins, such that reset overhead is even between calls -- avoids buildup of floating point error. 114 for (int i = 0; i < _resetsPerCommit; ++i) { 115 _sums[_currentReset] = 0.0; 116 for (int j = 0; j < _framesN; ++j) { 117 _sums[_currentReset] += _frames[j*_size + _currentReset]; 118 } 119 _currentReset = (_currentReset + 1) % _size; 120 } 121 122 _currentFrame = (_currentFrame + 1) % _framesN; 123 } 124 125 const T* getAverages() { 126 return _averages; 127 } 128 }; 129 130 template<typename T> 131 struct HistoryBuffer { 132 int _size, _i; 133 T* _buf; 134 135 HistoryBuffer(int size, T initialValue) 136 : _size(size) 137 , _i(0) 138 { 139 assert(size > 0); 140 _buf = new T[size]; 141 std::fill(_buf, _buf + size, initialValue); 142 } 143 ~HistoryBuffer() { 144 delete[] _buf; 145 } 146 147 inline void push(T s) { 148 ++_i; 149 _i %= _size; 150 _buf[_i] = s; 151 } 152 153 inline T value(int i) { 154 assert(i >= 0 && i < _size); 155 int j = _i - i; 156 if (j < 0) { 157 j += _size; 158 } 159 return _buf[j]; 160 } 161 }; 162 163 } // namespace dsp 164 } // namespace bogaudio