-
-
Notifications
You must be signed in to change notification settings - Fork 237
Volume Control
Sound is propagating in the form of waves. The amplitude of a wave is the distance from the centre line (or the still position) to the top of a crest or to the bottom.
When talking about sound waves, the volume is the perception of loudness from the intensity of a sound wave. The higher the intensity of a sound, the louder it is perceived in our ears, and the higher volume and the amplitude it has.
If you represent the sound with an int16_t then at maximum volume the values as oscillating between +-32767. To decrease the volume you can just decrease the amplitude e.g. by multiplying it with a value < 1.0. If you multiply with 0.0 you have no sound - if you multiply by 0.5 you have halve the volume.
In order to be able to handle the volume for encoded data properly, I have created the VolumeOutput class. You can just wrap your final PCM output class that should be controlled:
// set this in AudioConfig.h or here after installing https://github.com/pschatzmann/arduino-libhelix.git
#define USE_HELIX
#include "AudioTools.h"
#include "AudioCodecs/CodecMP3Helix.h"
using namespace audio_tools;
URLStream url("ssid","password");
I2SStream i2s; // final output of decoded stream
VolumeStream volume(i2s);
EncodedAudioStream dec(&volume, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.setNotifyAudioChange(i2s);
dec.begin();
// set initial volume
volume.begin(config);
volume.setVolume(0.3);
// mp3 radio
url.begin("https://centralcharts.ice.infomaniak.ch/centralcharts-128.mp3","audio/mp3");
}
void loop(){
copier.copy();
}
You can adjust the volume now dynamically by calling volume.setVolume(0.0)
to mute the output or volume.setVolume(0.5)
to halve the volume...
Sound is not perceived in a linear way. Therefore the potentiometers that are used in audio are approximating a logarithmic curve. I am providing different VolumeControl implementations which try to represent different yield curves, so that you can still use a linear potentiometer to control the volume.
The x axis represents the provided input value and the y axis the resulting multiplication factor.
By default the VolumeStream class is using the SimulatedAudioPot implementation, but you can select a different implementation or a Simulated Pot with different parameter values:
VolumeStream volume(i2s);
LogarithmicVolumeControl lvc(0.1);
void setup(){
...
volume.setVolumeControl(lvc);
...
}
Last, but not least: if you already use an physical audio potentiometer as input device, you would select the LinearVolumeControl class!
If the input is simple PCM data you can also use the ConverterScaler class to set the volume. Here is an example sketch which just sends some generated output to the serial monitor :
#include "AudioTools.h"
using namespace audio_tools;
uint16_t sample_rate=44100;
uint8_t channels = 2; // The stream will have 2 channels
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave
CsvStream<sound_t> printer(Serial, channels); // ASCII stream
StreamCopy copier(printer, sound); // copies sound into printer
ConverterScaler<int16_t> volume(1.0, 0, 32767); // volume control
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
// Setup sine wave
sineWave.begin(channels, sample_rate, N_B4);
}
// Arduino loop - repeated processing
void loop() {
copier.copy(volume);
}
You can adjust the volume now dynamically by calling volume.setFactor(0.0)
to mute the output or volume.setFactor(0.5)
to halve the volume...