arduino-audio-tools
Loading...
Searching...
No Matches
VolumeStream.h
Go to the documentation of this file.
1
2#pragma once
8
9namespace audio_tools {
10
21 bool allow_boost = false;
22 float volume=1.0; // start_volume
23};
24
25
36 public:
38 VolumeStream() = default;
39
42 setOutput(out);
43 }
44
47 setStream(in);
48 }
49
52 Print *p_print = &out;
53 setOutput(*p_print);
55 }
56
59 Stream *p_stream = &io;
60 setStream(*p_stream);
62 }
63
65 void setStream(Stream &in) override {
66 p_in = ∈
67 p_out = p_in;
68 }
69
71 void setOutput(Print &out) override {
72 p_out = &out;
73 }
74
76 void setOutput(Stream &in){
77 p_in = ∈
78 p_out = p_in;
79 }
80
82 void setStream(Print &out){
83 p_out = &out;
84 }
85
90
91 bool begin() override {
92 return begin(info);
93 }
94
95 bool begin(AudioInfo cfg) {
97 return begin(cfg1);
98 }
99
102 TRACED();
104 // usually we use a exponential volume control - except if we allow values > 1.0
105 if (cfg.allow_boost){
107 } else {
109 }
110
111 // set start volume
112 setVolume(cfg.volume);
113 is_started = true;
114 return true;
115 }
116
117 void end() override {
118 is_started = false;
119 }
120
121
126
131
133 virtual size_t readBytes(uint8_t *data, size_t len) override {
134 TRACED();
135 if (data==nullptr || p_in==nullptr){
136 LOGE("NPE");
137 return 0;
138 }
139 size_t result = p_in->readBytes(data, len);
140 if (isVolumeUpdate()) applyVolume(data, result);
141 return result;
142 }
143
145 virtual size_t write(const uint8_t *data, size_t len) override {
146 LOGD("VolumeStream::write: %zu", len);
147 if (data==nullptr || p_out==nullptr){
148 LOGE("NPE");
149 return 0;
150 }
151 if (isVolumeUpdate()) applyVolume(data,len);
152 return p_out->write(data, len);
153 }
154
156 virtual int availableForWrite() override {
157 return p_out==nullptr? 0 : p_out->availableForWrite();
158 }
159
161 virtual int available() override {
162 return p_in==nullptr? 0 : p_in->available();
163 }
164
165 virtual void flush() override {
166 if (p_out != nullptr) p_out->flush();
167 }
168
170 void setAudioInfo(AudioInfo cfg) override {
171 TRACED();
172 // pass on notification
174
175 if (is_started){
176 int old_n = volume_values.size();;
178 // update config and max values
181 // Only set default volume for new channels if channel count increased
182 int new_n = info.channels;
183 for (int j = old_n; j < new_n; ++j) {
185 }
186 } else {
187 begin(cfg);
188 }
189 }
190
192 bool setVolume(float vol) override {
193 LOGI("setVolume: %f", vol);
194 bool result = true;
195 // just to make sure that we have a valid start volume before begin
196 info.volume = vol;
197 for (int j=0; j<info.channels; j++){
198 result = setVolume(vol, j);
199 }
200 return result;
201 }
202
204 bool setVolume(float vol, int channel){
205 if ((vol > 1.0f && !info.allow_boost) || vol < 0.0f) {
206 LOGE("Invalid volume: %f", vol);
207 return false;
208 }
209 if (channel < info.channels){
211 float volume_value = volumeValue(vol);
212 if (volume_values[channel] != volume_value){
213 LOGI("setVolume: %f at %d", volume_value, channel);
216 #if PREFER_FIXEDPOINT
217 // q1_14_t saturates at ~1.99994 (its Q1.14 range), so boost
218 // is capped there (factor can only be >1 if allow_boost==true)
219 factor_for_channel[channel] = q1_14_t(factor);
220 #else
221 factor_for_channel[channel]=factor;
222 #endif
223 }
224 return true;
225 } else {
226 LOGE("Invalid channel %d - max: %d", channel, info.channels-1);
227 return false;
228 }
229 }
230
232 float volume() override {
233 // prevent npe
234 if (volume_values.size()==0) return info.volume;
235 // calculate avg
236 float total = 0;
237 int cnt = volume_values.size();
238 for (int j=0; j<cnt; j++){
239 total += volume_values[j];
240 }
241 return total / static_cast<float>(cnt);
242 }
243
245 float volume(int channel) {
246 return channel>=info.channels? 0 : volume_values[channel];
247 }
248
249 protected:
250 Print *p_out=nullptr;
251 Stream *p_in=nullptr;
257 #if PREFER_FIXEDPOINT
258 Vector<q1_14_t> factor_for_channel; // Q1.14 fixed point
259 #else
261 #endif
262 bool is_started = false;
263 // max value for clipping: integer on the fixed-point path, so the
264 // per-sample clip in applyVolume16/24/32 stays pure-integer instead
265 // of promoting the int32_t/int64_t result to float on every sample.
266 #if PREFER_FIXEDPOINT
267 int64_t max_value = 32767;
268 #else
269 float max_value = 32767;
270 #endif
271
272 // checks if volume needs to be updated
274 if (!is_started) return false;
275 if (isAllChannelsFullVolume()) return false;
276 return true;
277 }
278
280 int channels = min((int)info.channels, volume_values.size());
281 for (int ch=0;ch < channels;ch++){
282 if (volume_values[ch]!=1.0) return false;
283 }
284 return true;
285 }
286
288 void resizeVectors(int channels) {
289 factor_for_channel.resize(channels);
290 volume_values.resize(channels);
291 }
292
296 cfg1.channels = cfg.channels;
297 cfg1.sample_rate = cfg.sample_rate;
299 // keep volume which might habe been defined befor calling begin
300 cfg1.volume = info.volume;
302 return cfg1;
303 }
304
310
311 float volumeValue(float vol){
312 if (!info.allow_boost && vol>1.0f) vol = 1.0;
313 if (vol<0.0f) vol = 0.0;
314
315 // round to 2 digits
316 float value = (int)(vol * 100 + .5f);
317 float volume_value = (float)value / 100;
318 return volume_value;
319 }
320
324
325 #if PREFER_FIXEDPOINT
326 q1_14_t factorForChannel(int channel){
327 #else
328 float factorForChannel(int channel){
329 #endif
330 if (factor_for_channel.size()==0) return 1.0;
331 if (channel >= factor_for_channel.size()) return 1.0;
332 return factor_for_channel[channel];
333 }
334
335 void applyVolume(const uint8_t *buffer, size_t size){
336 switch(info.bits_per_sample){
337 case 16:
338 applyVolume16((int16_t*)buffer, size/2);
339 break;
340 case 24:
341 applyVolume24((int24_t*)buffer, size/sizeof(int24_t));
342 break;
343 case 32:
344 applyVolume32((int32_t*)buffer, size/4);
345 break;
346 default:
347 LOGE("Unsupported bits_per_sample: %d", info.bits_per_sample);
348 }
349 }
350
351 void applyVolume16(int16_t* data, size_t size){
352 for (size_t j=0;j<size;j++){
353 #if PREFER_FIXEDPOINT
354 int32_t result = factorForChannel(j%info.channels).scale(data[j]);
355 #else
356 float result = factorForChannel(j%info.channels) * data[j];
357 #endif
358 if (!info.allow_boost){
359 if (result>max_value) result = max_value;
360 if (result<-max_value) result = -max_value;
361 }
362 data[j]= static_cast<int16_t>(result);
363 }
364 }
365
366 void applyVolume24(int24_t* data, size_t size) {
367 for (size_t j=0;j<size;j++){
368 #if PREFER_FIXEDPOINT
369 int32_t result = factorForChannel(j%info.channels).scale(data[j]);
370 #else
371 float result = factorForChannel(j%info.channels) * data[j];
372 #endif
373 if (!info.allow_boost){
374 if (result>max_value) result = max_value;
375 if (result<-max_value) result = -max_value;
376 }
377 int32_t result1 = result;
378 data[j]= static_cast<int24_t>(result1);
379 }
380 }
381
382 void applyVolume32(int32_t* data, size_t size) {
383 for (size_t j=0;j<size;j++){
384 #if PREFER_FIXEDPOINT
385 int64_t result = factorForChannel(j%info.channels).scale(data[j]);
386 #else
387 float result = factorForChannel(j%info.channels) * data[j];
388 #endif
389 if (!info.allow_boost){
390 if (result>max_value) result = max_value;
391 if (result<-max_value) result = -max_value;
392 }
393 data[j]= static_cast<int32_t>(result);
394 }
395 }
396};
397
398}
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Definition Arduino.h:56
virtual int availableForWrite()
Definition Arduino.h:128
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
virtual void flush()
Definition Arduino.h:130
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
virtual int available()
Definition Arduino.h:139
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:155
virtual void setAudioInfo(AudioInfo info)=0
Defines the input AudioInfo.
Abstract Audio Ouptut class.
Definition AudioOutput.h:25
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
In order to optimize the processing time we cache the last input & factor and recalculate the new fac...
Definition VolumeControl.h:42
void setVolumeControl(VolumeControl &vc)
Definition VolumeControl.h:52
The simplest possible implementation of a VolumeControl: The input = output which describes a linear ...
Definition VolumeControl.h:150
Abstract class: Objects can be put into a pipleline.
Definition AudioStreams.h:68
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition AudioTypes.h:303
Simple simulated audio pot volume control inspired by https://eepower.com/resistor-guide/resistor-typ...
Definition VolumeControl.h:124
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
int size()
Definition Vector.h:178
Abstract class for handling of the linear input volume to determine the multiplication factor which s...
Definition VolumeControl.h:19
virtual float getVolumeFactor(float volume)=0
determines a multiplication factor (0.0 to 1.0) from an input value (0.0 to 1.0).
Adjust the volume of the related input or output: To work properly the class needs to know the bits p...
Definition VolumeStream.h:35
float factorForChannel(int channel)
Definition VolumeStream.h:328
void setVolumeStreamConfig(VolumeStreamConfig cfg)
Stores the local variable and calculates some max values.
Definition VolumeStream.h:306
virtual size_t write(const uint8_t *data, size_t len) override
Writes raw PCM audio data, which will be the input for the volume control.
Definition VolumeStream.h:145
void setOutput(Print &out) override
Defines/Changes the output target.
Definition VolumeStream.h:71
VolumeControl & volumeControl()
Definition VolumeStream.h:321
Vector< float > volume_values
Definition VolumeStream.h:256
void resizeVectors(int channels)
Resizes the vectors.
Definition VolumeStream.h:288
void setOutput(Stream &in)
same as setStream
Definition VolumeStream.h:76
VolumeStreamConfig defaultConfig()
Definition VolumeStream.h:86
VolumeStreamConfig toVolumeStreamConfig(AudioInfo cfg)
Provides a VolumeStreamConfig based on a AudioInfo.
Definition VolumeStream.h:294
Stream * p_in
Definition VolumeStream.h:251
bool isVolumeUpdate()
Definition VolumeStream.h:273
bool isAllChannelsFullVolume()
Definition VolumeStream.h:279
bool is_started
Definition VolumeStream.h:262
void applyVolume16(int16_t *data, size_t size)
Definition VolumeStream.h:351
virtual size_t readBytes(uint8_t *data, size_t len) override
Read raw PCM audio data, which will be the input for the volume control.
Definition VolumeStream.h:133
void end() override
Definition VolumeStream.h:117
void applyVolume(const uint8_t *buffer, size_t size)
Definition VolumeStream.h:335
void setStream(Print &out)
same as set Output
Definition VolumeStream.h:82
virtual int availableForWrite() override
Provides the nubmer of bytes we can write.
Definition VolumeStream.h:156
float volume() override
Provides the current (avg) volume accross all channels.
Definition VolumeStream.h:232
bool begin(VolumeStreamConfig cfg)
starts the processing
Definition VolumeStream.h:101
VolumeStream()=default
Default Constructor.
VolumeStream(AudioStream &io)
Constructor which assigns Stream input or output.
Definition VolumeStream.h:58
void applyVolume24(int24_t *data, size_t size)
Definition VolumeStream.h:366
LinearVolumeControl linear_vc
Definition VolumeStream.h:253
CachedVolumeControl cached_volume
Definition VolumeStream.h:255
Print * p_out
Definition VolumeStream.h:250
float volumeValue(float vol)
Definition VolumeStream.h:311
Vector< float > factor_for_channel
Definition VolumeStream.h:260
float max_value
Definition VolumeStream.h:269
VolumeStreamConfig info
Definition VolumeStream.h:252
bool begin() override
Definition VolumeStream.h:91
VolumeStream(AudioOutput &out)
Constructor which assigns Print output.
Definition VolumeStream.h:51
void resetVolumeControl()
Resets the volume control to use the standard logic.
Definition VolumeStream.h:128
bool setVolume(float vol) override
Defines the volume for all channels: needs to be in the range of 0 to 1.0 (if allow boost has not bee...
Definition VolumeStream.h:192
VolumeStream(Stream &in)
Constructor which assigns Stream input or output.
Definition VolumeStream.h:46
void applyVolume32(int32_t *data, size_t size)
Definition VolumeStream.h:382
void setStream(Stream &in) override
Defines/Changes the input & output.
Definition VolumeStream.h:65
void setAudioInfo(AudioInfo cfg) override
Detines the Audio info - The bits_per_sample are critical to work properly!
Definition VolumeStream.h:170
SimulatedAudioPot pot_vc
Definition VolumeStream.h:254
VolumeStream(Print &out)
Constructor which assigns Print output.
Definition VolumeStream.h:41
bool setVolume(float vol, int channel)
Sets the volume for one channel.
Definition VolumeStream.h:204
void setVolumeControl(VolumeControl &vc)
Defines the volume control logic.
Definition VolumeStream.h:123
virtual void flush() override
Definition VolumeStream.h:165
float volume(int channel)
Provides the current volume setting for the indicated channel.
Definition VolumeStream.h:245
bool begin(AudioInfo cfg)
Definition VolumeStream.h:95
virtual int available() override
Provides the nubmer of bytes we can write.
Definition VolumeStream.h:161
Supports the setting and getting of the volume.
Definition AudioTypes.h:193
float volume_value
Definition AudioTypes.h:204
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition int24_4bytes_t.h:22
Fixed-point Q1.14 number: a plain 16-bit signed integer holding 1 integer bit and 14 fractional bits ...
Definition q1_14_t.h:16
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:56
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:58
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:60
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:62
Config for VolumeStream.
Definition VolumeStream.h:16
float volume
Definition VolumeStream.h:22
bool allow_boost
Definition VolumeStream.h:21
VolumeStreamConfig()
Definition VolumeStream.h:17