arduino-audio-tools
Loading...
Searching...
No Matches
VolumeStream.h
Go to the documentation of this file.
1
2#pragma once
7
8namespace audio_tools {
9
20 bool allow_boost = false;
21 float volume=1.0; // start_volume
22};
23
24
35 public:
37 VolumeStream() = default;
38
41 setOutput(out);
42 }
43
46 setStream(in);
47 }
48
51 Print *p_print = &out;
52 setOutput(*p_print);
54 }
55
58 Stream *p_stream = &io;
59 setStream(*p_stream);
61 }
62
64 void setStream(Stream &in) override {
65 p_in = ∈
66 p_out = p_in;
67 }
68
70 void setOutput(Print &out) override {
71 p_out = &out;
72 }
73
75 void setOutput(Stream &in){
76 p_in = ∈
77 p_out = p_in;
78 }
79
81 void setStream(Print &out){
82 p_out = &out;
83 }
84
89
90 bool begin() override {
91 return begin(info);
92 }
93
94 bool begin(AudioInfo cfg) {
96 return begin(cfg1);
97 }
98
101 TRACED();
103 // usually we use a exponential volume control - except if we allow values > 1.0
104 if (cfg.allow_boost){
106 } else {
108 }
109
110 // set start volume
111 setVolume(cfg.volume);
112 is_started = true;
113 return true;
114 }
115
116 void end() override {
117 is_started = false;
118 }
119
120
125
130
132 virtual size_t readBytes(uint8_t *data, size_t len) override {
133 TRACED();
134 if (data==nullptr || p_in==nullptr){
135 LOGE("NPE");
136 return 0;
137 }
138 size_t result = p_in->readBytes(data, len);
139 if (isVolumeUpdate()) applyVolume(data, result);
140 return result;
141 }
142
144 virtual size_t write(const uint8_t *data, size_t len) override {
145 LOGD("VolumeStream::write: %zu", len);
146 if (data==nullptr || p_out==nullptr){
147 LOGE("NPE");
148 return 0;
149 }
150 if (isVolumeUpdate()) applyVolume(data,len);
151 return p_out->write(data, len);
152 }
153
155 virtual int availableForWrite() override {
156 return p_out==nullptr? 0 : p_out->availableForWrite();
157 }
158
160 virtual int available() override {
161 return p_in==nullptr? 0 : p_in->available();
162 }
163
165 void setAudioInfo(AudioInfo cfg) override {
166 TRACED();
167 // pass on notification
169
170 if (is_started){
171 int old_n = volume_values.size();;
173 // update config and max values
176 // Only set default volume for new channels if channel count increased
177 int new_n = info.channels;
178 for (int j = old_n; j < new_n; ++j) {
180 }
181 } else {
182 begin(cfg);
183 }
184 }
185
187 bool setVolume(float vol) override {
188 LOGI("setVolume: %f", vol);
189 bool result = true;
190 // just to make sure that we have a valid start volume before begin
191 info.volume = vol;
192 for (int j=0; j<info.channels; j++){
193 result = setVolume(vol, j);
194 }
195 return result;
196 }
197
199 bool setVolume(float vol, int channel){
200 if ((vol > 1.0f && !info.allow_boost) || vol < 0.0f) {
201 LOGE("Invalid volume: %f", vol);
202 return false;
203 }
204 if (channel < info.channels){
207 if (volume_values[channel] != volume_value){
208 LOGI("setVolume: %f at %d", volume_value, channel);
211 #if PREFER_FIXEDPOINT
212 //convert float to fixed point 2.6
213 //Fixedpoint-Math from https://github.com/earlephilhower/ESP8266Audio/blob/0abcf71012f6128d52a6bcd155ed1404d6cc6dcd/src/AudioOutput.h#L67
214 if(factor > 4.0) factor = 4.0;//factor can only be >1 if allow_boost == true TODO: should we update volume_values[channel] if factor got clipped to 4.0?
215 uint8_t factorF2P6 = (uint8_t) (factor*(1<<6));
217 #else
218 factor_for_channel[channel]=factor;
219 #endif
220 }
221 return true;
222 } else {
223 LOGE("Invalid channel %d - max: %d", channel, info.channels-1);
224 return false;
225 }
226 }
227
229 float volume() override {
230 // prevent npe
231 if (volume_values.size()==0) return info.volume;
232 // calculate avg
233 float total = 0;
234 int cnt = volume_values.size();
235 for (int j=0; j<cnt; j++){
236 total += volume_values[j];
237 }
238 return total / static_cast<float>(cnt);
239 }
240
242 float volume(int channel) {
243 return channel>=info.channels? 0 : volume_values[channel];
244 }
245
246 protected:
247 Print *p_out=nullptr;
248 Stream *p_in=nullptr;
254 #if PREFER_FIXEDPOINT
255 Vector<uint8_t> factor_for_channel; //Fixed point 2.6
256 #else
258 #endif
259 bool is_started = false;
260 float max_value = 32767; // max value for clipping
261
262 // checks if volume needs to be updated
264 if (!is_started) return false;
265 if (isAllChannelsFullVolume()) return false;
266 return true;
267 }
268
270 int channels = MIN(info.channels, volume_values.size());
271 for (int ch=0;ch < channels;ch++){
272 if (volume_values[ch]!=1.0) return false;
273 }
274 return true;
275 }
276
278 void resizeVectors(int channels) {
279 factor_for_channel.resize(channels);
280 volume_values.resize(channels);
281 }
282
286 cfg1.channels = cfg.channels;
287 cfg1.sample_rate = cfg.sample_rate;
288 cfg1.bits_per_sample = cfg.bits_per_sample;
289 // keep volume which might habe been defined befor calling begin
290 cfg1.volume = info.volume;
291 cfg1.allow_boost = info.allow_boost;
292 return cfg1;
293 }
294
300
301 float volumeValue(float vol){
302 if (!info.allow_boost && vol>1.0f) vol = 1.0;
303 if (vol<0.0f) vol = 0.0;
304
305 // round to 2 digits
306 float value = (int)(vol * 100 + .5f);
307 float volume_value = (float)value / 100;
308 return volume_value;
309 }
310
314
315 #if PREFER_FIXEDPOINT
316 uint8_t factorForChannel(int channel){
317 #else
318 float factorForChannel(int channel){
319 #endif
320 if (factor_for_channel.size()==0) return 1.0;
321 if (channel >= factor_for_channel.size()) return 1.0;
322 return factor_for_channel[channel];
323 }
324
325 void applyVolume(const uint8_t *buffer, size_t size){
326 switch(info.bits_per_sample){
327 case 16:
328 applyVolume16((int16_t*)buffer, size/2);
329 break;
330 case 24:
331 applyVolume24((int24_t*)buffer, size/sizeof(int24_t));
332 break;
333 case 32:
334 applyVolume32((int32_t*)buffer, size/4);
335 break;
336 default:
337 LOGE("Unsupported bits_per_sample: %d", info.bits_per_sample);
338 }
339 }
340
341 void applyVolume16(int16_t* data, size_t size){
342 for (size_t j=0;j<size;j++){
343 #if PREFER_FIXEDPOINT
344 int32_t result = (data[j] * factorForChannel(j%info.channels)) >> 6; //Fixedpoint-Math from https://github.com/earlephilhower/ESP8266Audio/blob/0abcf71012f6128d52a6bcd155ed1404d6cc6dcd/src/AudioOutput.h#L67
345 #else
346 float result = factorForChannel(j%info.channels) * data[j];
347 #endif
348 if (!info.allow_boost){
349 if (result>max_value) result = max_value;
350 if (result<-max_value) result = -max_value;
351 }
352 data[j]= static_cast<int16_t>(result);
353 }
354 }
355
356 void applyVolume24(int24_t* data, size_t size) {
357 for (size_t j=0;j<size;j++){
358 #if PREFER_FIXEDPOINT
359 int32_t result = (data[j] * factorForChannel(j%info.channels)) >> 6; //8bits * 24bits = fits into 32
360 #else
361 float result = factorForChannel(j%info.channels) * data[j];
362 #endif
363 if (!info.allow_boost){
364 if (result>max_value) result = max_value;
365 if (result<-max_value) result = -max_value;
366 }
367 int32_t result1 = result;
368 data[j]= static_cast<int24_t>(result1);
369 }
370 }
371
372 void applyVolume32(int32_t* data, size_t size) {
373 for (size_t j=0;j<size;j++){
374 #if PREFER_FIXEDPOINT
375 int64_t result = (static_cast<int64_t>(data[j]) * static_cast<int64_t>(factorForChannel(j%info.channels))) >> 6;
376 #else
377 float result = factorForChannel(j%info.channels) * data[j];
378 #endif
379 if (!info.allow_boost){
380 if (result>max_value) result = max_value;
381 if (result<-max_value) result = -max_value;
382 }
383 data[j]= static_cast<int32_t>(result);
384 }
385 }
386};
387
388}
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define MIN(A, B)
Definition AudioTypes.h:17
void notifyAudioChange(AudioInfo info)
Definition AudioTypes.h:178
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:153
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:123
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:301
Definition NoArduino.h:62
virtual int availableForWrite()
Definition NoArduino.h:134
virtual size_t write(const uint8_t *data, size_t len)
Definition NoArduino.h:126
Simple simulated audio pot volume control inspired by https://eepower.com/resistor-guide/resistor-typ...
Definition VolumeControl.h:124
Definition NoArduino.h:142
virtual size_t readBytes(uint8_t *data, size_t len)
Definition NoArduino.h:147
virtual int available()
Definition NoArduino.h:146
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(int 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:34
float factorForChannel(int channel)
Definition VolumeStream.h:318
void setVolumeStreamConfig(VolumeStreamConfig cfg)
Stores the local variable and calculates some max values.
Definition VolumeStream.h:296
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:144
void setOutput(Print &out) override
Defines/Changes the output target.
Definition VolumeStream.h:70
VolumeControl & volumeControl()
Definition VolumeStream.h:311
Vector< float > volume_values
Definition VolumeStream.h:253
void resizeVectors(int channels)
Resizes the vectors.
Definition VolumeStream.h:278
void setOutput(Stream &in)
same as setStream
Definition VolumeStream.h:75
VolumeStreamConfig defaultConfig()
Definition VolumeStream.h:85
VolumeStreamConfig toVolumeStreamConfig(AudioInfo cfg)
Provides a VolumeStreamConfig based on a AudioInfo.
Definition VolumeStream.h:284
Stream * p_in
Definition VolumeStream.h:248
bool isVolumeUpdate()
Definition VolumeStream.h:263
bool isAllChannelsFullVolume()
Definition VolumeStream.h:269
bool is_started
Definition VolumeStream.h:259
void applyVolume16(int16_t *data, size_t size)
Definition VolumeStream.h:341
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:132
void end() override
Definition VolumeStream.h:116
void applyVolume(const uint8_t *buffer, size_t size)
Definition VolumeStream.h:325
void setStream(Print &out)
same as set Output
Definition VolumeStream.h:81
virtual int availableForWrite() override
Provides the nubmer of bytes we can write.
Definition VolumeStream.h:155
float volume() override
Provides the current (avg) volume accross all channels.
Definition VolumeStream.h:229
bool begin(VolumeStreamConfig cfg)
starts the processing
Definition VolumeStream.h:100
VolumeStream()=default
Default Constructor.
VolumeStream(AudioStream &io)
Constructor which assigns Stream input or output.
Definition VolumeStream.h:57
void applyVolume24(int24_t *data, size_t size)
Definition VolumeStream.h:356
LinearVolumeControl linear_vc
Definition VolumeStream.h:250
CachedVolumeControl cached_volume
Definition VolumeStream.h:252
Print * p_out
Definition VolumeStream.h:247
float volumeValue(float vol)
Definition VolumeStream.h:301
Vector< float > factor_for_channel
Definition VolumeStream.h:257
float max_value
Definition VolumeStream.h:260
VolumeStreamConfig info
Definition VolumeStream.h:249
bool begin() override
Definition VolumeStream.h:90
VolumeStream(AudioOutput &out)
Constructor which assigns Print output.
Definition VolumeStream.h:50
void resetVolumeControl()
Resets the volume control to use the standard logic.
Definition VolumeStream.h:127
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:187
VolumeStream(Stream &in)
Constructor which assigns Stream input or output.
Definition VolumeStream.h:45
void applyVolume32(int32_t *data, size_t size)
Definition VolumeStream.h:372
void setStream(Stream &in) override
Defines/Changes the input & output.
Definition VolumeStream.h:64
void setAudioInfo(AudioInfo cfg) override
Detines the Audio info - The bits_per_sample are critical to work properly!
Definition VolumeStream.h:165
SimulatedAudioPot pot_vc
Definition VolumeStream.h:251
VolumeStream(Print &out)
Constructor which assigns Print output.
Definition VolumeStream.h:40
bool setVolume(float vol, int channel)
Sets the volume for one channel.
Definition VolumeStream.h:199
void setVolumeControl(VolumeControl &vc)
Defines the volume control logic.
Definition VolumeStream.h:122
float volume(int channel)
Provides the current volume setting for the indicated channel.
Definition VolumeStream.h:242
bool begin(AudioInfo cfg)
Definition VolumeStream.h:94
virtual int available() override
Provides the nubmer of bytes we can write.
Definition VolumeStream.h:160
Supports the setting and getting of the volume.
Definition AudioTypes.h:191
float volume_value
Definition AudioTypes.h:202
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition Int24_4bytes_t.h:16
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:55
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:57
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:59
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:61
Config for VolumeStream.
Definition VolumeStream.h:15
float volume
Definition VolumeStream.h:21
bool allow_boost
Definition VolumeStream.h:20
VolumeStreamConfig()
Definition VolumeStream.h:16