1 // Copyright 2014 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 //
27 // Circular buffer storing audio samples.
28 
29 #ifndef CLOUDS_DSP_AUDIO_BUFFER_H_
30 #define CLOUDS_DSP_AUDIO_BUFFER_H_
31 
32 #include <algorithm>
33 
34 #include "stmlib/stmlib.h"
35 
36 #include "stmlib/dsp/dsp.h"
37 #include "stmlib/utils/dsp.h"
38 
39 #include "clouds/dsp/mu_law.h"
40 
41 const int32_t kCrossFadeSize = 256;
42 const int32_t kInterpolationTail = 8;
43 
44 namespace clouds {
45 
46 enum Resolution {
47   RESOLUTION_16_BIT,
48   RESOLUTION_8_BIT,
49   RESOLUTION_8_BIT_DITHERED,
50   RESOLUTION_8_BIT_MU_LAW,
51 };
52 
53 enum InterpolationMethod {
54   INTERPOLATION_ZOH,
55   INTERPOLATION_LINEAR,
56   INTERPOLATION_HERMITE
57 };
58 
59 template<Resolution resolution>
60 class AudioBuffer {
61  public:
AudioBuffer()62   AudioBuffer() { }
~AudioBuffer()63   ~AudioBuffer() { }
64 
Init(void * buffer,int32_t size,int16_t * tail_buffer)65   void Init(
66       void* buffer,
67       int32_t size,
68       int16_t* tail_buffer) {
69     s16_ = static_cast<int16_t*>(buffer);
70     s8_ = static_cast<int8_t*>(buffer);
71     size_ = size - kInterpolationTail;
72     write_head_ = 0;
73     quantization_error_ = 0.0f;
74     crossfade_counter_ = 0;
75     if (resolution == RESOLUTION_16_BIT) {
76       std::fill(&s16_[0], &s16_[size], 0);
77     } else {
78       std::fill(
79           &s8_[0],
80           &s8_[size],
81           resolution == RESOLUTION_8_BIT_MU_LAW ? 127 : 0);
82     }
83     tail_ = tail_buffer;
84   }
85 
Resync(int32_t head)86   inline void Resync(int32_t head) {
87     write_head_ = head;
88     crossfade_counter_ = 0;
89   }
90 
Write(float in)91   inline void Write(float in) {
92     if (resolution == RESOLUTION_16_BIT) {
93       s16_[write_head_] = stmlib::Clip16(
94             static_cast<int32_t>(in * 32768.0f));
95     } else if (resolution == RESOLUTION_8_BIT_DITHERED) {
96       float sample = in * 127.0f;
97       sample += quantization_error_;
98       int32_t quantized = static_cast<int32_t>(sample);
99       if (quantized < -127) quantized = -127;
100       else if (quantized > 127) quantized = 127;
101       quantization_error_ = sample - static_cast<float>(in);
102       s8_[write_head_] = quantized;
103     } else if (resolution == RESOLUTION_8_BIT_MU_LAW) {
104       int16_t sample = stmlib::Clip16(static_cast<int32_t>(in * 32768.0f));
105       s8_[write_head_] = Lin2MuLaw(sample);
106     } else {
107       s8_[write_head_] = static_cast<int8_t>(
108           stmlib::Clip16(in * 32768.0f) >> 8);
109     }
110 
111     if (resolution == RESOLUTION_16_BIT) {
112       if (write_head_ < kInterpolationTail) {
113         s16_[write_head_ + size_] = s16_[write_head_];
114       }
115     } else {
116       if (write_head_ < kInterpolationTail) {
117         s8_[write_head_ + size_] = s8_[write_head_];
118       }
119     }
120     ++write_head_;
121     if (write_head_ >= size_) {
122       write_head_ = 0;
123     }
124   }
125 
WriteFade(const float * in,int32_t size,int32_t stride,bool write)126   inline void WriteFade(
127       const float* in,
128       int32_t size,
129       int32_t stride,
130       bool write) {
131     if (!write) {
132       // Continue recording samples to have something to crossfade with
133       // when recording resumes.
134       if (crossfade_counter_ < kCrossFadeSize) {
135         while (size--) {
136           if (crossfade_counter_ < kCrossFadeSize) {
137             tail_[crossfade_counter_++] = stmlib::Clip16(
138                 static_cast<int32_t>(*in * 32767.0f));
139             in += stride;
140           }
141         }
142       }
143     } else if (write && !crossfade_counter_ &&
144         resolution == RESOLUTION_16_BIT &&
145         write_head_ >= kInterpolationTail && write_head_ < (size_ - size)) {
146       // Fast write routine for the most common case.
147       while (size--) {
148         s16_[write_head_] = stmlib::Clip16(
149             static_cast<int32_t>(*in * 32767.0f));
150         ++write_head_;
151         in += stride;
152       }
153     } else {
154       while (size--) {
155         float sample = *in;
156         if (crossfade_counter_) {
157           --crossfade_counter_;
158           float tail_sample = tail_[kCrossFadeSize - crossfade_counter_];
159           float gain = crossfade_counter_ * (1.0f / float(kCrossFadeSize));
160           sample += (tail_sample / 32768.0f - sample) * gain;
161         }
162         Write(sample);
163         in += stride;
164       }
165     }
166   }
167 
Write(const float * in,int32_t size,int32_t stride)168   inline void Write(const float* in, int32_t size, int32_t stride) {
169     if (resolution == RESOLUTION_16_BIT
170         && write_head_ >= kInterpolationTail && write_head_ < (size_ - size)) {
171       // Fast write routine for the most common case.
172       while (size--) {
173         s16_[write_head_] = stmlib::Clip16(
174             static_cast<int32_t>(*in * 32768.0f));
175         ++write_head_;
176         in += stride;
177       }
178     } else {
179       while (size--) {
180         Write(*in);
181         in += stride;
182       }
183     }
184   }
185 
186   template<InterpolationMethod method>
Read(int32_t integral,uint16_t fractional)187   inline float Read(int32_t integral, uint16_t fractional) const {
188     if (method == INTERPOLATION_ZOH) {
189       return ReadZOH(integral, fractional);
190     } else if (method == INTERPOLATION_LINEAR) {
191       return ReadLinear(integral, fractional);
192     } else if (method == INTERPOLATION_HERMITE) {
193       return ReadHermite(integral, fractional);
194     }
195   }
196 
ReadZOH(int32_t integral,uint16_t fractional)197   inline float ReadZOH(int32_t integral, uint16_t fractional) const {
198     if (integral >= size_) {
199       integral -= size_;
200     }
201 
202     float x0, scale;
203     if (resolution == RESOLUTION_16_BIT) {
204       x0 = s16_[integral];
205       scale = 1.0f / 32768.0f;
206     } else if (resolution == RESOLUTION_8_BIT_MU_LAW) {
207       x0 = MuLaw2Lin(s8_[integral]);
208       scale = 1.0f / 32768.0f;
209     } else {
210       x0 = s8_[integral];
211       scale = 1.0f / 128.0f;
212     }
213     return x0 * scale;
214   }
215 
ReadLinear(int32_t integral,uint16_t fractional)216   inline float ReadLinear(int32_t integral, uint16_t fractional) const {
217     if (integral >= size_) {
218       integral -= size_;
219     }
220 
221     // assert(integral >= 0 && integral < size_);
222 
223     float x0, x1, scale;
224     float t = static_cast<float>(fractional) / 65536.0f;
225     if (resolution == RESOLUTION_16_BIT) {
226       x0 = s16_[integral];
227       x1 = s16_[integral + 1];
228       scale = 1.0f / 32768.0f;
229     } else if (resolution == RESOLUTION_8_BIT_MU_LAW) {
230       x0 = MuLaw2Lin(s8_[integral]);
231       x1 = MuLaw2Lin(s8_[integral + 1]);
232       scale = 1.0f / 32768.0f;
233     } else {
234       x0 = s8_[integral];
235       x1 = s8_[integral + 1];
236       scale = 1.0f / 128.0f;
237     }
238     return (x0 + (x1 - x0) * t) * scale;
239   }
240 
ReadHermite(int32_t integral,uint16_t fractional)241   inline float ReadHermite(int32_t integral, uint16_t fractional) const {
242     if (integral >= size_) {
243       integral -= size_;
244     }
245 
246     // assert(integral >= 0 && integral < size_);
247 
248     float xm1, x0, x1, x2, scale;
249     float t = static_cast<float>(fractional) / 65536.0f;
250 
251     if (resolution == RESOLUTION_16_BIT) {
252       xm1 = s16_[integral];
253       x0 = s16_[integral + 1];
254       x1 = s16_[integral + 2];
255       x2 = s16_[integral + 3];
256       scale = 1.0f / 32768.0f;
257     } else if (resolution == RESOLUTION_8_BIT_MU_LAW) {
258       xm1 = MuLaw2Lin(s8_[integral]);
259       x0 = MuLaw2Lin(s8_[integral + 1]);
260       x1 = MuLaw2Lin(s8_[integral + 2]);
261       x2 = MuLaw2Lin(s8_[integral + 3]);
262       scale = 1.0f / 32768.0f;
263     } else {
264       xm1 = s8_[integral];
265       x0 = s8_[integral + 1];
266       x1 = s8_[integral + 2];
267       x2 = s8_[integral + 3];
268       scale = 1.0f / 128.0f;
269     }
270 
271     // Laurent de Soras's Hermite interpolator.
272     const float c = (x1 - xm1) * 0.5f;
273     const float v = x0 - x1;
274     const float w = c + v;
275     const float a = w + v + (x2 - x0) * 0.5f;
276     const float b_neg = w + a;
277     return ((((a * t) - b_neg) * t + c) * t + x0) * scale;
278   }
279 
size()280   inline int32_t size() const { return size_; }
head()281   inline int32_t head() const { return write_head_; }
282 
283  private:
284   int16_t* s16_;
285   int8_t* s8_;
286 
287   float quantization_error_;
288 
289   int16_t tail_ptr_;
290 
291   int32_t size_;
292   int32_t write_head_;
293 
294   int16_t* tail_;
295   int32_t crossfade_counter_;
296 
297   DISALLOW_COPY_AND_ASSIGN(AudioBuffer);
298 };
299 
300 }  // namespace clouds
301 
302 #endif  // CLOUDS_DSP_AUDIO_BUFFER_H_
303