Arduino A2DP

Loading...
Searching...
No Matches
A2DPVolumeControl.h
1#pragma once
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Copyright 2020 Phil Schatzmann
16// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
17
18#include "esp_log.h"
19
26 struct __attribute__((packed)) Frame {
27 int16_t channel1;
28 int16_t channel2;
29
34 Frame(int v = 0) { channel1 = channel2 = v; }
35
41 Frame(int ch1, int ch2) {
42 channel1 = ch1;
43 channel2 = ch2;
44 }
45};
46
54 class A2DPVolumeControl {
55 public:
59 A2DPVolumeControl() = default;
60
66 virtual void update_audio_data(uint8_t* data, uint16_t byteCount) {
67 update_audio_data((Frame*)data, byteCount / 4);
68 }
69
75 virtual void update_audio_data(Frame* data, uint16_t frameCount) {
76 if (data != nullptr && frameCount > 0 && (mono_downmix || is_volume_used)) {
77 ESP_LOGD("VolumeControl", "update_audio_data");
78 for (int i = 0; i < frameCount; i++) {
79 int32_t pcmLeft = data[i].channel1;
80 int32_t pcmRight = data[i].channel2;
81 // if mono -> we provide the same output on both channels
82 if (mono_downmix) {
83 pcmRight = pcmLeft = (pcmLeft + pcmRight) / 2;
84 }
85 // adjust the volume
86 if (is_volume_used) {
87 pcmLeft = clip(pcmLeft * volumeFactor / volumeFactorMax);
88 pcmRight = clip(pcmRight * volumeFactor / volumeFactorMax);
89 }
90 data[i].channel1 = pcmLeft;
91 data[i].channel2 = pcmRight;
92 }
93 }
94 }
95
100 int32_t get_volume_factor() { return volumeFactor; }
101
106 int32_t get_volume_factor_max() { return volumeFactorMax; }
107
112 void set_enabled(bool enabled) { is_volume_used = enabled; }
113
118 void set_mono_downmix(bool enabled) { mono_downmix = enabled; }
119
124 virtual void set_volume(uint8_t volume) = 0;
125
126 protected:
127 bool is_volume_used = false;
128 bool mono_downmix = false;
129 int32_t volumeFactor = 1;
130 int32_t volumeFactorMax = 0x1000;
131 int32_t volumeFactorClippingLimit = 0xfff;
132
138 int32_t clip(int32_t value) {
139 int32_t result = value;
140 if (value < -32768) result = -32768;
141 if (value > 32767) result = 32767;
142 return result;
143 }
144};
145
151 class A2DPDefaultVolumeControl : public A2DPVolumeControl {
152 public:
156 A2DPDefaultVolumeControl() = default;
157
163 A2DPDefaultVolumeControl(int32_t limit) {
164 assert(limit < volumeFactorMax);
165 volumeFactorClippingLimit = limit;
166 };
167
168 protected:
173 void set_volume(uint8_t volume) override {
174 constexpr float base = 1.4f;
175 constexpr float bits = 12.0f;
176 constexpr float zero_ofs = pow(base, -bits);
177 constexpr float scale = pow(2.0f, bits);
178 float volumeFactorFloat =
179 (pow(base, volume * bits / 127.0f - bits) - zero_ofs) * scale /
180 (1.0f - zero_ofs);
181 volumeFactor = volumeFactorFloat;
182 if (volumeFactor > volumeFactorClippingLimit) {
183 volumeFactor = volumeFactorClippingLimit;
184 }
185 }
186};
187
193 class A2DPSimpleExponentialVolumeControl : public A2DPVolumeControl {
194 public:
198 A2DPSimpleExponentialVolumeControl() = default;
199
205 A2DPSimpleExponentialVolumeControl(int32_t limit) {
206 assert(limit < volumeFactorMax);
207 volumeFactorClippingLimit = limit;
208 };
209
210 protected:
215 void set_volume(uint8_t volume) override {
216 float volumeFactorFloat = volume;
217 volumeFactorFloat = pow(2.0f, volumeFactorFloat * 12.0f / 127.0f);
218 volumeFactor = volumeFactorFloat - 1.0f;
219 if (volumeFactor > volumeFactorClippingLimit) {
220 volumeFactor = volumeFactorClippingLimit;
221 }
222 }
223};
224
230 class A2DPLinearVolumeControl : public A2DPVolumeControl {
231 public:
235 A2DPLinearVolumeControl() { volumeFactorMax = 128; }
236
237 protected:
242 void set_volume(uint8_t volume) override { volumeFactor = volume; }
243};
244
250 class A2DPNoVolumeControl : public A2DPVolumeControl {
251 public:
257 A2DPNoVolumeControl(int32_t fixedVolume = 0x1000) {
258 is_volume_used = fixedVolume != 0x1000;
259 mono_downmix = false;
260 volumeFactor = fixedVolume; // fixed volume
261 volumeFactorMax = 0x1000; // no change
262 }
263
269 void update_audio_data(Frame* data, uint16_t frameCount) override {}
270
275 void set_volume(uint8_t volume) override {}
276};
A2DPDefaultVolumeControl
Default implementation for handling of the volume of the audio data.
Definition A2DPVolumeControl.h:151
A2DPDefaultVolumeControl::A2DPDefaultVolumeControl
A2DPDefaultVolumeControl(int32_t limit)
Constructor with custom volume factor clipping limit.
Definition A2DPVolumeControl.h:163
A2DPDefaultVolumeControl::set_volume
void set_volume(uint8_t volume) override
Sets the volume using exponential curve calculation.
Definition A2DPVolumeControl.h:173
A2DPDefaultVolumeControl::A2DPDefaultVolumeControl
A2DPDefaultVolumeControl()=default
Default constructor.
A2DPLinearVolumeControl
The simplest possible implementation of a VolumeControl.
Definition A2DPVolumeControl.h:230
A2DPLinearVolumeControl::A2DPLinearVolumeControl
A2DPLinearVolumeControl()
Constructor that sets volumeFactorMax to 128 for linear scaling.
Definition A2DPVolumeControl.h:235
A2DPLinearVolumeControl::set_volume
void set_volume(uint8_t volume) override
Sets the volume using direct linear mapping.
Definition A2DPVolumeControl.h:242
A2DPNoVolumeControl
Keeps the audio data as is -> no volume control!
Definition A2DPVolumeControl.h:250
A2DPNoVolumeControl::set_volume
void set_volume(uint8_t volume) override
Override that does nothing - no volume setting.
Definition A2DPVolumeControl.h:275
A2DPNoVolumeControl::A2DPNoVolumeControl
A2DPNoVolumeControl(int32_t fixedVolume=0x1000)
Constructor with optional fixed volume setting.
Definition A2DPVolumeControl.h:257
A2DPNoVolumeControl::update_audio_data
void update_audio_data(Frame *data, uint16_t frameCount) override
Override that does nothing - no audio data modification.
Definition A2DPVolumeControl.h:269
A2DPSimpleExponentialVolumeControl
Exponential volume control.
Definition A2DPVolumeControl.h:193
A2DPSimpleExponentialVolumeControl::set_volume
void set_volume(uint8_t volume) override
Sets the volume using simple exponential calculation.
Definition A2DPVolumeControl.h:215
A2DPSimpleExponentialVolumeControl::A2DPSimpleExponentialVolumeControl
A2DPSimpleExponentialVolumeControl()=default
Default constructor.
A2DPSimpleExponentialVolumeControl::A2DPSimpleExponentialVolumeControl
A2DPSimpleExponentialVolumeControl(int32_t limit)
Constructor with custom volume factor clipping limit.
Definition A2DPVolumeControl.h:205
A2DPVolumeControl
Abstract class for handling of the volume of the audio data.
Definition A2DPVolumeControl.h:54
A2DPVolumeControl::clip
int32_t clip(int32_t value)
Clips audio sample value to prevent overflow.
Definition A2DPVolumeControl.h:138
A2DPVolumeControl::set_volume
virtual void set_volume(uint8_t volume)=0
Sets the volume level (pure virtual function)
A2DPVolumeControl::set_mono_downmix
void set_mono_downmix(bool enabled)
Enables or disables mono downmix.
Definition A2DPVolumeControl.h:118
A2DPVolumeControl::get_volume_factor
int32_t get_volume_factor()
Gets the current volume factor.
Definition A2DPVolumeControl.h:100
A2DPVolumeControl::update_audio_data
virtual void update_audio_data(Frame *data, uint16_t frameCount)
Updates audio data with volume control and optional mono downmix.
Definition A2DPVolumeControl.h:75
A2DPVolumeControl::is_volume_used
bool is_volume_used
Flag indicating if volume control is enabled.
Definition A2DPVolumeControl.h:127
A2DPVolumeControl::volumeFactorClippingLimit
int32_t volumeFactorClippingLimit
Volume factor clipping limit (4095)
Definition A2DPVolumeControl.h:131
A2DPVolumeControl::mono_downmix
bool mono_downmix
Flag indicating if mono downmix is enabled.
Definition A2DPVolumeControl.h:128
A2DPVolumeControl::update_audio_data
virtual void update_audio_data(uint8_t *data, uint16_t byteCount)
Updates audio data with volume control and optional mono downmix.
Definition A2DPVolumeControl.h:66
A2DPVolumeControl::A2DPVolumeControl
A2DPVolumeControl()=default
Default constructor.
A2DPVolumeControl::set_enabled
void set_enabled(bool enabled)
Enables or disables volume control.
Definition A2DPVolumeControl.h:112
A2DPVolumeControl::volumeFactor
int32_t volumeFactor
Current volume factor.
Definition A2DPVolumeControl.h:129
A2DPVolumeControl::volumeFactorMax
int32_t volumeFactorMax
Maximum volume factor (4096)
Definition A2DPVolumeControl.h:130
A2DPVolumeControl::get_volume_factor_max
int32_t get_volume_factor_max()
Gets the maximum volume factor value.
Definition A2DPVolumeControl.h:106