This commit is contained in:
2026-02-12 21:00:02 -08:00
parent cb1f2b0efd
commit 40714a3a68
1141 changed files with 1010880 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
# Communication Examples
You can transmit audio information over a wire or (e.g. if you have an ESP32) wirelessly. It is important that you make sure that the transmitted amount of audio data is below the transmission capacity of the medium (e.g. by limiting the channels, the sample rate or the bits per sample).
You can also use [one of the many supported CODECs](https://github.com/pschatzmann/arduino-audio-tools/wiki/Encoding-and-Decoding-of-Audio) to decrease the transmitted amount of data!

View File

@@ -0,0 +1,17 @@
## Using the AI Thinker ESP32 Audio Kit as A2DP Receiver
I found some cheap [AI Thinker ESP32 Audio Kit V2.2](https://docs.ai-thinker.com/en/esp32-audio-kit) on AliExpress.
<img src="https://pschatzmann.github.io/Resources/img/audio-toolkit.png" alt="Audio Kit" />
I am using the data callback of the A2DP library to feed the AudioBoardStream
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies:
## Dependencies
You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/ESP32-A2DP
- https://github.com/pschatzmann/arduino-audio-driver

View File

@@ -0,0 +1,37 @@
/**
* @file basic-a2dp-audiokit.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-audiokit/basic-a2dp-audiokit/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h" // install https://github.com/pschatzmann/ESP32-A2DP
#include "AudioTools/AudioLibs/AudioBoardStream.h" // install https://github.com/pschatzmann/arduino-audio-driver
BluetoothA2DPSink a2dp_sink;
AudioBoardStream kit(AudioKitEs8388V1);
// Write data to AudioKit in callback
void read_data_stream(const uint8_t *data, uint32_t length) {
kit.write(data, length);
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
cfg.sd_active = false;
kit.begin(cfg);
// register callback
a2dp_sink.set_stream_reader(read_data_stream, false);
a2dp_sink.start("AudioKit");
}
void loop() {
}

View File

@@ -0,0 +1,17 @@
## Using the AI Thinker ESP32 Audio Kit as A2DP Receiver with Equalizer
I found some cheap [AI Thinker ESP32 Audio Kit V2.2](https://docs.ai-thinker.com/en/esp32-audio-kit) on AliExpress.
<img src="https://pschatzmann.github.io/Resources/img/audio-toolkit.png" alt="Audio Kit" />
I am using the data callback of the A2DP library to feed the AudioBoardStream that will be controlled by an Equalizer
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies:
## Dependencies
You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/ESP32-A2DP
- https://github.com/pschatzmann/arduino-audio-driver

View File

@@ -0,0 +1,51 @@
/**
* @file basic-a2dp-audiokit.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-audiokit/basic-a2dp-audiokit/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h" // install https://github.com/pschatzmann/ESP32-A2DP
#include "AudioTools/AudioLibs/AudioBoardStream.h" // install https://github.com/pschatzmann/arduino-audio-driver
BluetoothA2DPSink a2dp_sink;
AudioBoardStream kit(AudioKitEs8388V1);
Equalizer3Bands eq(kit);
ConfigEqualizer3Bands cfg_eq;
// Write data to AudioKit in callback
void read_data_stream(const uint8_t *data, uint32_t length) {
eq.write(data, length);
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
cfg.sd_active = false;
kit.begin(cfg);
// max volume
kit.setVolume(1.0);
// setup equilizer
cfg_eq = eq.defaultConfig();
cfg_eq.setAudioInfo(cfg); // use channels, bits_per_sample and sample_rate from kit
cfg_eq.gain_low = 0.5;
cfg_eq.gain_medium = 0.5;
cfg_eq.gain_high = 1.0;
eq.begin(cfg_eq);
// register callback
a2dp_sink.set_stream_reader(read_data_stream, false);
a2dp_sink.start("AudioKit");
}
void loop() {
}

View File

@@ -0,0 +1,68 @@
/**
* @file basic-a2dp-fft-led.ino
* @brief A2DP Sink with output of the FFT result to the LED matrix
* For details see the FFT Wiki: https://github.com/pschatzmann/arduino-audio-tools/wiki/FFT
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include <FastLED.h> // to prevent conflicts introduced with 3.9
#include "AudioTools.h"
#include "AudioTools/AudioLibs/AudioRealFFT.h" // or any other supported inplementation
#include "AudioTools/AudioLibs/LEDOutput.h"
#include "BluetoothA2DPSink.h"
#define PIN_LEDS 22
#define LED_X 32
#define LED_Y 8
BluetoothA2DPSink a2dp_sink;
AudioRealFFT fft; // or any other supported inplementation
FFTDisplay fft_dis(fft);
LEDOutput led(fft_dis); // output to LED matrix
// Provide data to FFT
void writeDataStream(const uint8_t *data, uint32_t length) {
fft.write(data, length);
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// Setup FFT
auto tcfg = fft.defaultConfig();
tcfg.length = 1024;
tcfg.channels = 2;
tcfg.sample_rate = a2dp_sink.sample_rate();;
tcfg.bits_per_sample = 16;
fft.begin(tcfg);
// Setup LED matrix output
auto lcfg = led.defaultConfig();
lcfg.x = LED_X;
lcfg.y = LED_Y;
led.begin(lcfg);
fft_dis.fft_group_bin = 3;
fft_dis.fft_start_bin = 0;
fft_dis.fft_max_magnitude = 40000;
fft_dis.begin();
// add LEDs
FastLED.addLeds<WS2812B, PIN_LEDS, GRB>(led.ledData(), led.ledCount());
// register A2DP callback
a2dp_sink.set_stream_reader(writeDataStream, false);
// Start Bluetooth Audio Receiver
Serial.print("starting a2dp-fft...");
a2dp_sink.set_auto_reconnect(false);
a2dp_sink.start("a2dp-fft");
}
void loop() {
led.update();
delay(50);
}

View File

@@ -0,0 +1,59 @@
/**
* @file basic-a2dp-fft.ino
* @brief A2DP Sink with output to FFT.
* For details see the FFT Wiki: https://github.com/pschatzmann/arduino-audio-tools/wiki/FFT
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioLibs/AudioRealFFT.h" // or any other supported inplementation
#include "BluetoothA2DPSink.h"
BluetoothA2DPSink a2dp_sink;
AudioRealFFT fft; // or any other supported inplementation
// Provide data to FFT
void writeDataStream(const uint8_t *data, uint32_t length) {
fft.write(data, length);
}
// display fft result
void fftResult(AudioFFTBase &fft){
float diff;
auto result = fft.result();
if (result.magnitude>100){
Serial.print(result.frequency);
Serial.print(" ");
Serial.print(result.magnitude);
Serial.print(" => ");
Serial.print(result.frequencyAsNote(diff));
Serial.print( " diff: ");
Serial.println(diff);
}
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// Setup FFT
auto tcfg = fft.defaultConfig();
tcfg.length = 4096;
tcfg.channels = 2;
tcfg.sample_rate = a2dp_sink.sample_rate();;
tcfg.bits_per_sample = 16;
tcfg.callback = &fftResult;
fft.begin(tcfg);
// register callback
a2dp_sink.set_stream_reader(writeDataStream, false);
// Start Bluetooth Audio Receiver
Serial.print("starting a2dp-fft...");
a2dp_sink.set_auto_reconnect(false);
a2dp_sink.start("a2dp-fft");
}
void loop() { delay(100); }

View File

@@ -0,0 +1,43 @@
/**
* @file basic-a2dp-audioi2s.ino
* @brief A2DP Sink with output to I2SStream. This example is of small value
* since my Bluetooth Library already provides I2S output out of the box.
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "BluetoothA2DPSink.h"
BluetoothA2DPSink a2dp_sink;
I2SStream i2s;
// Write data to I2S
void read_data_stream(const uint8_t *data, uint32_t length) {
i2s.write(data, length);
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// register callback
a2dp_sink.set_stream_reader(read_data_stream, false);
// Start Bluetooth Audio Receiver
a2dp_sink.set_auto_reconnect(false);
a2dp_sink.start("a2dp-i2s");
// setup output
auto cfg = i2s.defaultConfig();
cfg.pin_data = 23;
cfg.sample_rate = a2dp_sink.sample_rate();
cfg.channels = 2;
cfg.bits_per_sample = 16;
cfg.buffer_count = 8;
cfg.buffer_size = 256;
i2s.begin(cfg);
}
void loop() { delay(100); }

View File

@@ -0,0 +1,73 @@
/**
* @file basic-a2dp-mixer-i2s.ino
* @brief A2DP Sink with output to mixer: I think this is the most efficient way
* of mixing a signal that is coming from A2DP which requires only 160 byte of additional RAM.
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "BluetoothA2DPSink.h"
AudioInfo info(44100, 2, 16);
BluetoothA2DPSink a2dp_sink;
I2SStream i2s;
SineWaveGenerator<int16_t> sineWave(10000); // subclass of SoundGenerator with max amplitude of 10000
GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave
OutputMixer<int16_t> mixer(i2s, 2); // output mixer with 2 outputs
const int buffer_size = 80; // split up the output into small chunks
uint8_t sound_buffer[buffer_size];
// Write data to mixer
void read_data_stream(const uint8_t *data, uint32_t length) {
// To keep the mixing buffer small we split up the output into small chunks
int count = length / buffer_size + 1;
for (int j = 0; j < count; j++) {
const uint8_t *start = data + (j * buffer_size);
const uint8_t *end = min(data + length, start + buffer_size);
int len = end - start;
if (len > 0) {
// write a2dp
mixer.write(start, len);
// write sine tone with identical length
sound.readBytes(sound_buffer, len);
mixer.write(sound_buffer, len);
// We could flush to force the output but this is not necessary because we
// were already writing all 2 streams mixer.flushMixer();
}
}
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// setup Output mixer with min necessary memory
mixer.begin(buffer_size);
// Register data callback
a2dp_sink.set_stream_reader(read_data_stream, false);
// Start Bluetooth Audio Receiver
a2dp_sink.set_auto_reconnect(false);
a2dp_sink.start("a2dp-i2s");
// Update sample rate
info.sample_rate = a2dp_sink.sample_rate();
// start sine wave
sineWave.begin(info, N_B4);
// setup output
auto cfg = i2s.defaultConfig();
cfg.copyFrom(info);
// cfg.pin_data = 23;
cfg.buffer_count = 8;
cfg.buffer_size = 256;
i2s.begin(cfg);
}
void loop() { delay(100); }

View File

@@ -0,0 +1,23 @@
# Stream Analog input to A2DP Bluetooth
We can read an analog signal from a microphone and and send it to a Bluetooth A2DP device. To test the functionality I am using a MCP6022 microphone module.
![MCP6022](https://pschatzmann.github.io/Resources/img/mcp6022.jpeg)
![MCP6022](https://pschatzmann.github.io/Resources/img/mcp6022-1.jpeg)
The MCP6022 is a anlog microphone which operates at 3.3 V
We sample the sound signal with the help of the ESP32 I2S ADC input functionality.
### Pins:
| MCP6022 | ESP32
|---------|---------------
| VCC | 3.3
| GND | GND
| OUT | GPIO34
### Dependencies
- https://github.com/pschatzmann/ESP32-A2DP.git

View File

@@ -0,0 +1,47 @@
/**
* @file basic-adc-a2dp.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-communication/a2dp/basic-adc-a2dp/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "BluetoothA2DPSource.h"
/**
* @brief We use a mcp6022 analog microphone as input and send the data to A2DP
*/
AnalogAudioStream adc;
BluetoothA2DPSource a2dp_source;
// callback used by A2DP to provide the sound data
int32_t get_sound_data(Frame* frames, int32_t frameCount) {
uint8_t *data = (uint8_t*)frames;
int frameSize = 4;
size_t resultBytes = adc.readBytes(data, frameCount*frameSize);
return resultBytes/frameSize;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
// start i2s input with default configuration
Serial.println("starting I2S-ADC...");
adc.begin(adc.defaultConfig(RX_MODE));
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(false);
a2dp_source.set_data_callback_in_frames(get_sound_data);
a2dp_source.start("MyMusic");
}
// Arduino loop - repeated processing
void loop() {
delay(1000);
}

View File

@@ -0,0 +1,44 @@
/**
* @file base-audiokit-a2dp.ino
* @author Phil Schatzmann
* @brief We play the input from the ADC to an A2DP speaker
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Communication/A2DPStream.h"
AudioInfo info(44100, 2, 16);
BluetoothA2DPSource a2dp_source;
AudioBoardStream i2s(AudioKitEs8388V1);
const int16_t BYTES_PER_FRAME = 4;
// callback used by A2DP to provide the sound data - usually len is 128 2 channel int16 frames
int32_t get_sound_data(Frame* data, int32_t frameCount) {
return i2s.readBytes((uint8_t*)data, frameCount*BYTES_PER_FRAME)/BYTES_PER_FRAME;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// start i2s input with default configuration
Serial.println("starting I2S...");
auto cfg = i2s.defaultConfig(RX_MODE);
cfg.i2s_format = I2S_STD_FORMAT; // or try with I2S_LSB_FORMAT
cfg.copyFrom(info);
cfg.input_device = ADC_INPUT_LINE2; // microphone
i2s.begin(cfg);
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_data_callback_in_frames(get_sound_data);
a2dp_source.start("LEXON MINO L");
}
// Arduino loop - repeated processing
void loop() {
delay(1000);
}

View File

@@ -0,0 +1,53 @@
// We use the decoding on the input side to provid pcm data
#include "SPI.h"
#include "SD.h"
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
//#include "AudioTools/AudioLibs/AudioBoardStream.h" // for SPI pins
File file;
MP3DecoderHelix mp3; // or change to MP3DecoderMAD
EncodedAudioStream decoder(&file, &mp3);
BluetoothA2DPSource a2dp_source;
const int chipSelect = SS; //PIN_AUDIO_KIT_SD_CARD_CS;
// callback used by A2DP to provide the sound data - usually len is 128 2 channel int16 frames
int32_t get_sound_data(uint8_t* data, int32_t size) {
int32_t result = decoder.readBytes((uint8_t*)data, size);
delay(1); // feed the dog
return result;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// open file
//SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
SD.begin(chipSelect);
file = SD.open("/test.mp3", FILE_READ);
if (!file) {
Serial.println("file failed");
stop();
}
// make sure we have enough space for the pcm data
decoder.transformationReader().resizeResultQueue(1024 * 8);
if (!decoder.begin()) {
Serial.println("decoder failed");
stop();
}
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_data_callback(get_sound_data);
a2dp_source.start("LEXON MINO L");
}
// Arduino loop - repeated processing
void loop() {
delay(1000);
}

View File

@@ -0,0 +1,45 @@
/**
* @file basic-generator-a2dp.ino
* @author Phil Schatzmann
* @brief We send a test sine signal to a bluetooth speaker
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
const char* name = "LEXON MINO L"; // Replace with your bluetooth speaker name
SineWaveGenerator<int16_t> sineWave(15000); // subclass of SoundGenerator, set max amplitude (=volume)
GeneratedSoundStream<int16_t> in_stream(sineWave); // Stream generated from sine wave
BluetoothA2DPSource a2dp_source; // A2DP Sender
// callback used by A2DP to provide the sound data - usually len is 128 * 2 channel int16 frames
int32_t get_sound_data(uint8_t * data, int32_t len) {
return in_stream.readBytes((uint8_t*)data, len);
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// start input
auto cfg = in_stream.defaultConfig();
cfg.bits_per_sample = 16;
cfg.channels = 2;
cfg.sample_rate = 44100;
in_stream.begin(cfg);
sineWave.begin(cfg, N_B4);
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(false);
a2dp_source.set_data_callback(get_sound_data);
a2dp_source.start(name);
}
// Arduino loop - repeated processing
void loop() {
delay(1000);
}

View File

@@ -0,0 +1,35 @@
# Stream I2S Input to A2DP Bluetooth
## General Description:
We implement a A2DP source: We stream the sound input which we read in from the I2S interface to a A2DP sink. We can use any device which provides the sound data via I2S. In order to test the functionality we use the INMP441 microphone.
![INMP441](https://pschatzmann.github.io/Resources/img/inmp441.jpeg)
The INMP441 is a high-performance, low power, digital-output, omnidirectional MEMS microphone with a bottom port. The complete INMP441 solution consists of a MEMS sensor, signal conditioning, an analog-to-digital converter, anti-aliasing filters, power management, and an industry-standard 24-bit I²S interface. The I²S interface allows the INMP441 to connect directly to digital processors, such as DSPs and microcontrollers, without the need for an audio codec in the system.
## Pins
| INMP441 | ESP32
| --------| ---------------
| VDD | 3.3
| GND | GND
| SD | IN (GPIO32)
| L/R | GND
| WS | WS (GPIO15)
| SCK | BCK (GPIO14)
SCK: Serial data clock for I²S interface
WS: Select serial data words for the I²S interface
L/R: Left / right channel selection
When set to low, the microphone emits signals on one channel of the I²S frame.
When the high level is set, the microphone will send signals on the other channel.
ExSD: Serial data output of the I²S interface
VCC: input power 1.8V to 3.3V
GND: Power groundHigh PSR: -75 dBFS.
### Dependencies
- https://github.com/pschatzmann/ESP32-A2DP.git

View File

@@ -0,0 +1,51 @@
/**
* @file basic-i2s-a2dp.ino
* @author Phil Schatzmann
* @brief We use a INMP441 I2S microphone as input and send the data to A2DP
* Unfortunatly the data type from the microphone (int32_t) does not match with
* the required data type by A2DP (int16_t), so we need to convert.
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
AudioInfo info32(44100, 2, 32);
AudioInfo info16(44100, 2, 16);
BluetoothA2DPSource a2dp_source;
I2SStream i2s;
FormatConverterStream conv(i2s);
const int BYTES_PER_FRAME = 4;
int32_t get_sound_data(Frame* data, int32_t frameCount) {
return conv.readBytes((uint8_t*)data, frameCount*BYTES_PER_FRAME)/BYTES_PER_FRAME;
}
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup conversion
conv.begin(info32, info16);
// start i2s input with default configuration
Serial.println("starting I2S...");
auto cfg = i2s.defaultConfig(RX_MODE);
cfg.i2s_format = I2S_STD_FORMAT; // or try with I2S_LSB_FORMAT
cfg.copyFrom(info32);
cfg.is_master = true;
i2s.begin(cfg);
// start the bluetooth
Serial.println("starting A2DP...");
// a2dp_source.set_auto_reconnect(false);
a2dp_source.set_data_callback_in_frames(get_sound_data);
a2dp_source.start("LEXON MINO L");
Serial.println("A2DP started");
}
// Arduino loop - repeated processing
void loop() { delay(1000); }

View File

@@ -0,0 +1,66 @@
/**
* @file basic-player-a2dp.ino
* @author Phil Schatzmann
* @brief Sketch which uses the A2DP callback to provide data from the AudioPlayer via a Queue
* The queue is filled by the Arduino loop.
* @version 0.1
* @date 2022-12-04
*
* @copyright Copyright (c) 2022
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
#include "AudioTools/Disk/AudioSourceSDFAT.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
//#include "AudioTools/AudioLibs/AudioBoardStream.h" // for SD Pins
const int cs = 33; //PIN_AUDIO_KIT_SD_CARD_CS;
const int buffer_size = 15*1024;
const char *startFilePath = "/";
const char *ext = "mp3";
AudioSourceSDFAT source(startFilePath, ext, cs);
MP3DecoderHelix decoder;
//Setup of synchronized buffer
BufferRTOS<uint8_t> buffer(0);
QueueStream<uint8_t> out(buffer); // convert Buffer to Stream
AudioPlayer player(source, out, decoder);
BluetoothA2DPSource a2dp;
// Provide data to A2DP
int32_t get_data(uint8_t *data, int32_t bytes) {
size_t result_bytes = buffer.readArray(data, bytes);
//LOGI("get_data_channels %d -> %d of (%d)", bytes, result_bytes , buffer.available());
return result_bytes;
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// allocate in PSRAM only possible in setup or loop
buffer.resize(buffer_size);
// sd_active is setting up SPI with the right SD pins by calling
// SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
// start QueueStream when 95% full
out.begin(95);
// setup player
player.setDelayIfOutputFull(0);
player.setVolume(0.1);
player.begin();
// start a2dp source
Serial.println("starting A2DP...");
a2dp.set_data_callback(get_data);
a2dp.start("LEXON MINO L");
Serial.println("Started!");
}
void loop() {
// decode data to buffer
player.copy();
}

View File

@@ -0,0 +1,87 @@
/**
* @file player-sdfat_a2dp-audiokit.ino
* @author Phil Schatzmann
* @brief Swithcing between Player and A2DP
* @version 0.1
* @date 2022-04-21
*
* @copyright Copyright (c) 2022
*
*/
// install https://github.com/greiman/SdFat.git
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Disk/AudioSourceSDFAT.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
const char *startFilePath="/";
const char* ext="mp3";
AudioBoardStream kit(AudioKitEs8388V1);
SdSpiConfig sdcfg(PIN_AUDIO_KIT_SD_CARD_CS, DEDICATED_SPI, SD_SCK_MHZ(10) , &SPI);
AudioSourceSDFAT source(startFilePath, ext, sdcfg);
MP3DecoderHelix decoder;
AudioPlayer player(source, kit, decoder);
BluetoothA2DPSink a2dp_sink;
bool player_active = true;
// Write data to AudioKit in callback
void read_data_stream(const uint8_t *data, uint32_t length) {
kit.write(data, length);
}
// switch between a2dp and sd player
void mode(bool, int, void*) {
player_active = !player_active;
if (player_active){
Serial.println("Stopping A2DP");
a2dp_sink.end();
// setup player
player.setVolume(0.7);
player.begin();
Serial.println("Player started");
} else {
Serial.println("Stopping player..");
player.end();
// start sink
a2dp_sink.start("AudioKit");
// update sample rate
auto cfg = kit.defaultConfig();
cfg.sample_rate = a2dp_sink.sample_rate();
kit.setAudioInfo(cfg);
Serial.println("A2DP started");
}
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// provide a2dp data
a2dp_sink.set_stream_reader(read_data_stream, false);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
kit.setVolume(40);
kit.begin(cfg);
// setup additional buttons
kit.addDefaultActions();
kit.addAction(kit.getKey(4), mode);
// setup player
player.setVolume(0.7);
player.begin();
}
void loop() {
if (player) {
player.copy();
} else {
// feed watchdog
delay(10);
}
kit.processActions();
}

View File

@@ -0,0 +1,28 @@
# A Simple SdFat Audio Player
The example demonstrates how to implement an __MP3 Player__: which provides the data from a SD drive and provides the audio via A2DP (e.g. to a Bluetooth Speaker): The __AudioSourceSdFat class__ builds on the [SdFat Library](https://github.com/greiman/SdFat) from Bill Greiman which provides FAT16/FAT32 and exFAT support.
## SD Card
Here is the information how to wire the SD card to the ESP32
| SD | ESP32
|-------|-----------------------
| CS | VSPI-CS0 (GPIO 05)
| SCK | VSPI-CLK (GPIO 18)
| MOSI | VSPI-MOSI (GPIO 23)
| MISO | VSPI-MISO (GPIO 19)
| VCC | VIN (5V)
| GND | GND
![SD](https://www.pschatzmann.ch/wp-content/uploads/2021/04/sd-module.jpeg)
## Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix
- https://github.com/greiman/SdFat
- https://github.com/pschatzmann/ESP32-A2DP

View File

@@ -0,0 +1,46 @@
/**
* @file player-sdfat-a2dp.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-sdfat-a2dp/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
//remove this, to find issues regarding mp3 decoding
#define HELIX_LOGGING_ACTIVE false
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
#include "AudioTools/Disk/AudioSourceSDFAT.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSDFAT source(startFilePath, ext); // , PIN_AUDIO_KIT_SD_CARD_CS);
A2DPStream out;
MP3DecoderHelix decoder;
AudioPlayer player(source, out, decoder);
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// setup player
// Setting up SPI if necessary with the right SD pins by calling
// SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
player.setVolume(0.1);
player.begin();
// setup output - We send the test signal via A2DP - so we conect to a Bluetooth Speaker
auto cfg = out.defaultConfig(TX_MODE);
cfg.silence_on_nodata = true; // prevent disconnect when there is no audio data
cfg.name = "LEXON MINO L"; // set the device here. Otherwise the first available device is used for output
//cfg.auto_reconnect = true; // if this is use we just quickly connect to the last device ignoring cfg.name
out.begin(cfg);
}
void loop() {
player.copy();
}

View File

@@ -0,0 +1,41 @@
/**
* @file streams-a2dp-serial.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-stream/streams-a2dp-serial/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
A2DPStream in;
AudioBoardStream kit(AudioKitEs8388V1);
StreamCopy copier(kit, in); // copy in to out
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// start the bluetooth audio receiver
Serial.println("starting A2DP...");
auto cfg = in.defaultConfig(RX_MODE);
cfg.name = "AudioKit";
in.begin(cfg);
// setup the audioKit
auto cfgk = kit.defaultConfig(TX_MODE);
cfgk.copyFrom(in.audioInfo());
kit.begin(cfgk);
}
// Arduino loop
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,3 @@
# Receive Sound Data from Bluetooth A2DP
We receive some music via Bluetooth e.g. from your mobile phone and display it as CSV

View File

@@ -0,0 +1,33 @@
/**
* @file streams-a2dp-serial.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-stream/streams-a2dp-serial/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
A2DPStream in;
CsvOutput<int16_t> out(Serial, 2); // ASCII stream as csv
StreamCopy copier(out, in); // copy in to out
// Arduino Setup
void setup(void) {
Serial.begin(115200);
// start the bluetooth audio receiver
Serial.println("starting A2DP...");
auto cfg = in.defaultConfig(RX_MODE);
cfg.name = "MyReceiver";
in.begin(cfg);
}
// Arduino loop
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,35 @@
/**
* @file basic-a2dp-audiospdif.ino
* @brief A2DP Sink with output to SPDIFOutput
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioLibs/SPDIFOutput.h"
#include "BluetoothA2DPSink.h"
AudioInfo info(44100, 2, 16);
SPDIFOutput spdif;
BluetoothA2DPSink a2dp_sink(spdif);
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// setup output
auto cfg = spdif.defaultConfig();
cfg.copyFrom(info);
cfg.buffer_size = 384;
cfg.buffer_count = 30;
cfg.pin_data = 23;
spdif.begin(cfg);
// Start Bluetooth Audio Receiver
a2dp_sink.start("a2dp-spdif");
}
void loop() {
delay(100);
}

View File

@@ -0,0 +1,10 @@
# Test Signal to Bluetooth Speaker
Sometimes it is quite useful to be able to generate a test tone.
We can use the GeneratedSoundStream class together with a SoundGenerator class. In my example I use a SineWaveGenerator.
To test the output I'm using this generated signal and write it to A2DP (e.g. a Bluetooth Speaker).
### Dependencies
- https://github.com/pschatzmann/ESP32-A2DP.git

View File

@@ -0,0 +1,48 @@
/**
* @file streams-generator-a2dp.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-stream/streams-generator-a2dp/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
const char* name = "LEXON MINO L"; // Replace with your device name
AudioInfo info(44100, 2, 16);
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
A2DPStream out; // A2DP output
StreamCopy copier(out, in); // copy in to out
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// set the frequency
sineWave.setFrequency(N_B4);
// Setup sine wave
auto cfg = in.defaultConfig();
cfg.copyFrom(info);
in.addNotifyAudioChange(out);
in.begin(cfg);
// We send the test signal via A2DP - so we conect to the MyMusic Bluetooth Speaker
auto cfgA2DP = out.defaultConfig(TX_MODE);
cfgA2DP.name = name;
//cfgA2DP.auto_reconnect = false;
out.begin(cfgA2DP);
out.setVolume(0.3);
Serial.println("A2DP is connected now...");
}
// Arduino loop
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,34 @@
# Stream I2S Input to A2DP Bluetooth
## General Description:
We implement a A2DP source: We stream the sound input which we read in from the I2S interface to a A2DP sink. We can use any device which provides the sound data via I2S. In order to test the functionality we use the INMP441 microphone. Because the Microphone only provides data on one channel, we the ConverterFillLeftAndRight class to copy the data to the other channel as well.
In this Sketch we are using Streams!
![INMP441](https://pschatzmann.github.io/Resources/img/inmp441.jpeg)
The INMP441 is a high-performance, low power, digital-output, omnidirectional MEMS microphone with a bottom port. The complete INMP441 solution consists of a MEMS sensor, signal conditioning, an analog-to-digital converter, anti-aliasing filters, power management, and an industry-standard 24-bit I²S interface. The I²S interface allows the INMP441 to connect directly to digital processors, such as DSPs and microcontrollers, without the need for an audio codec in the system.
## Pins
| INMP441 | ESP32
| --------| ---------------
| VDD | 3.3
| GND | GND
| SD | IN (GPIO32)
| L/R | GND
| WS | WS (GPIO15)
| SCK | BCK (GPIO14)
- SCK: Serial data clock for I²S interface
- WS: Select serial data words for the I²S interface
- L/R: Left / right channel selection
When set to low, the microphone emits signals on the left channel of the I²S frame.
When the high level is set, the microphone will send signals on the right channel.
- ExSD: Serial data output of the I²S interface
- VCC: input power 1.8V to 3.3V
- GND: Power groundHigh PSR: -75 dBFS.

View File

@@ -0,0 +1,43 @@
/**
* @file streams-i2s-a2dp.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-stream/streams-i2s-a2dp/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/A2DPStream.h"
I2SStream i2sStream; // Access I2S as stream
A2DPStream a2dpStream; // access A2DP as stream
StreamCopy copier(a2dpStream, i2sStream); // copy i2sStream to a2dpStream
ConverterFillLeftAndRight<int16_t> filler(LeftIsEmpty); // fill both channels
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// start bluetooth
Serial.println("starting A2DP...");
auto cfgA2DP = a2dpStream.defaultConfig(TX_MODE);
cfgA2DP.name = "LEXON MINO L";
a2dpStream.begin(cfgA2DP);
// set intial volume
a2dpStream.setVolume(0.3);
// start i2s input with default configuration
Serial.println("starting I2S...");
a2dpStream.addNotifyAudioChange(i2sStream); // i2s is using the info from a2dp
i2sStream.begin(i2sStream.defaultConfig(RX_MODE));
}
// Arduino loop - copy data
void loop() {
// copier.copy(filler);
copier.copy();
}

View File

@@ -0,0 +1,15 @@
# A Simple Synthesizer for the AI Thinker AudioKit to A2DP Bluetooth Speaker
I was taking the streams-synth-audiokit example and converted the output to go to A2DP. In order to minimize the lag
I am not using the Stream API but directly the A2DP Callbacks - which avoids any buffers.
The delay howver is still too big to be really useful...
### Dependencies
You need to install the following libraries:
- [Arduino Audio Tools](https://github.com/pschatzmann/arduino-audio-tools)
- [Midi](https://github.com/pschatzmann/arduino-midi)
- [ESP32-A2DP](https://github.com/pschatzmann/ESP32-A2DP)

View File

@@ -0,0 +1,52 @@
/**
* @file streams-synth-audiokit.ino
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#define USE_MIDI
#include "AudioTools.h" // must be first
#include "AudioTools/AudioLibs/AudioBoardStream.h" // https://github.com/pschatzmann/arduino-audio-driver
#include "BluetoothA2DPSource.h" // https://github.com/pschatzmann/ESP32-A2DP
BluetoothA2DPSource a2dp_source;
int channels = 2;
AudioBoardStream kit(AudioKitEs8388V1);
Synthesizer synthesizer;
GeneratedSoundStream<int16_t> in(synthesizer);
SynthesizerKey keys[] = {{kit.getKey(1), N_C3},{kit.getKey(2), N_D3},{kit.getKey(3), N_E3},{kit.getKey(4), N_F3},{kit.getKey(5), N_G3},{kit.getKey(6), N_A3},{0,0}};
int32_t get_sound_data(Frame *data, int32_t frameCount) {
int frame_size = sizeof(int16_t)*channels;
int16_t samples = synthesizer.readBytes((uint8_t*)data,frameCount*frame_size);
//esp_task_wdt_reset();
delay(1);
return samples/frame_size;
}
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial,AudioLogger::Info);
// setup synthezizer keys
synthesizer.setKeys(kit.audioActions(), keys, AudioActions::ActiveLow);
// define synthesizer keys for AudioKit
synthesizer.setKeys(kit.audioActions(), keys, AudioActions::ActiveLow);
synthesizer.setMidiName("AudioKit Synthesizer");
auto cfg = in.defaultConfig();
cfg.channels = channels;
cfg.sample_rate = 44100;
in.begin(cfg);
a2dp_source.set_data_callback_in_frames(get_sound_data);
a2dp_source.start("LEXON MINO L");
a2dp_source.set_volume(20);
}
void loop() {
kit.processActions();
delay(1);
}

View File

@@ -0,0 +1,47 @@
/**
* @file example-serial-receive.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow and decoding data to I2S
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
#include "AudioTools/AudioCodecs/CodecSBC.h"
// #include "AudioTools/AudioLibs/AudioBoardStream.h"
ESPNowStream now;
I2SStream out; // or AudioBoardStream
EncodedAudioStream decoder(&out, new SBCDecoder(256)); // decode and write to I2S - ESP Now is limited to 256 bytes
StreamCopy copier(decoder, now);
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// setup esp-now
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
now.begin(cfg);
now.addPeers(peers);
// start I2S
Serial.println("starting I2S...");
auto config = out.defaultConfig(TX_MODE);
out.begin(config);
// start decoder
decoder.begin();
Serial.println("Receiver started...");
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,41 @@
/**
* @file example-serial-receive_measure.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow with max speed to measure thruput
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
#include "AudioTools/AudioCodecs/CodecSBC.h"
ESPNowStream now;
MeasuringStream out(1000, &Serial);
EncodedAudioStream decoder(&out, new SBCDecoder()); // decode and write to I2S
StreamCopy copier(decoder, now);
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// start esp-now
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
now.begin(cfg);
now.addPeers(peers);
// start output
decoder.begin();
out.begin();
Serial.println("Receiver started...");
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,44 @@
/**
* @file example-serial-send.ino
* @author Phil Schatzmann
* @brief Sending encoded audio over ESPNow
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
#include "AudioTools/AudioCodecs/CodecSBC.h"
AudioInfo info(32000,1,16);
SineWaveGenerator<int16_t> sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound( sineWave); // Stream generated from sine wave
ESPNowStream now;
SBCEncoder sbc;
EncodedAudioStream encoder(&now, &sbc); // encode and write to ESP-now
StreamCopy copier(encoder, sound); // copies sound into i2s
const char *peers[] = {"A8:48:FA:0B:93:01"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:02";
now.begin(cfg);
now.addPeers(peers);
// Setup sine wave
sineWave.begin(info, N_B4);
// start encoder
encoder.begin(info);
Serial.println("Sender started...");
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,42 @@
/**
* @file example-espnow-receive.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
AudioInfo info(8000, 1, 16);
ESPNowStream now;
MeasuringStream now1(now);
I2SStream out;
StreamCopy copier(out, now1);
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
now.begin(cfg);
now.addPeers(peers);
// start I2S
Serial.println("starting I2S...");
auto config = out.defaultConfig(TX_MODE);
config.copyFrom(info);
out.begin(config);
Serial.println("Receiver started...");
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,34 @@
/**
* @file example-espnow-receive_csv.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
ESPNowStream now;
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
now.begin(cfg);
now.addPeers(peers);
Serial.println("Receiver started...");
}
void loop() {
int16_t sample;
if (now.readBytes((uint8_t*)&sample,2)){
Serial.println(sample);
}
}

View File

@@ -0,0 +1,38 @@
/**
* @file example-espnow-receive_measure.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow with max speed to measure thruput
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
ESPNowStream now;
MeasuringStream out;
StreamCopy copier(out, now);
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
now.begin(cfg);
now.addPeers(peers);
// start I2S
Serial.println("starting Out...");
out.begin();
Serial.println("Receiver started...");
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,37 @@
/**
* @file example-espnow-send.ino
* @author Phil Schatzmann
* @brief Sending audio over ESPNow
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
AudioInfo info(8000, 1, 16);
SineWaveGenerator<int16_t> sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound( sineWave); // Stream generated from sine wave
ESPNowStream now;
StreamCopy copier(now, sound); // copies sound into i2s
const char *peers[] = {"A8:48:FA:0B:93:01"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:02";
now.begin(cfg);
now.addPeers(peers);
// Setup sine wave
sineWave.begin(info, N_B4);
Serial.println("Sender started...");
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,39 @@
/**
* @file example-serial-receive_measure.ino
* @author Phil Schatzmann
* @brief Receiving data via ESPNow with max speed to measure thruput. We define a specific esp-now rate
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
ESPNowStream now;
MeasuringStream out;
StreamCopy copier(out, now);
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
cfg.rate = WIFI_PHY_RATE_24M;
now.begin(cfg);
now.addPeers(peers);
// start I2S
Serial.println("starting Out...");
out.begin();
Serial.println("Receiver started...");
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,33 @@
/**
* @file example-serial-send.ino
* @author Phil Schatzmann
* @brief Sending data over ESPNow. We define a specific esp-now rate
* @version 0.1
* @date 2022-03-09
*
* @copyright Copyright (c) 2022
*/
#include "AudioTools.h"
#include "AudioTools/Communication/ESPNowStream.h"
ESPNowStream now;
const char *peers[] = {"A8:48:FA:0B:93:01"};
uint8_t buffer[1024] = {0};
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:02";
cfg.rate = WIFI_PHY_RATE_24M;
now.begin(cfg);
now.addPeers(peers);
Serial.println("Sender started...");
}
void loop() {
now.write(buffer, 1024);
}

View File

@@ -0,0 +1,52 @@
/**
* @file ftp-client.ino
* @author Phil Schatzmann
* @brief Receiving audio via FTP and writing to I2S of the AudioKit.
* Replace the userids, passwords and ip adresses with your own!
* And don't forget to read the Wiki of the imported projects
* @version 0.1
* @date 2023-11-09
*
* @copyright Copyright (c) 2023
*/
#include "WiFi.h"
#include "FTPClient.h" // install https://github.com/pschatzmann/TinyFTPClient
#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools
#include "AudioTools/AudioCodecs/CodecMP3Helix.h" // https://github.com/pschatzmann/arduino-libhelix
#include "AudioTools/AudioLibs/AudioBoardStream.h" // https://github.com/pschatzmann/arduino-audio-driver
FTPClient<WiFiClient> client;
FTPFile file;
AudioBoardStream kit(AudioKitEs8388V1); // or replace with e.g. I2SStream
MP3DecoderHelix mp3;
EncodedAudioStream decoder(&kit, &mp3);
StreamCopy copier(decoder, file);
void setup() {
Serial.begin(115200);
// connect to WIFI
WiFi.begin("network name", "password");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// optional logging
FTPLogger::setOutput(Serial);
// FTPLogger::setLogLevel(LOG_DEBUG);
// open connection
client.begin(IPAddress(192, 168, 1, 10), "user", "password");
// copy data from file
file = client.open("/data/music/Neil Young/After the Gold Rush/08 Birds.mp3");
// open output device
kit.begin();
decoder.begin();
}
void loop() { copier.copy(); }

View File

@@ -0,0 +1,64 @@
/**
* @file hls-buffer-i2s.ino
* @brief Buffered playback of HLSStream: activate PSRAM!
* We use a MultiDecoder to handle different formats.
* For MPEG-TS (MTS) you need to set the log level to Warning or higher.
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecHelix.h"
#include "AudioTools/AudioCodecs/CodecMTS.h"
#include "AudioTools/Communication/HLSStream.h"
#include "AudioTools/Concurrency/RTOS.h"
// #include "AudioTools/AudioLibs/AudioBoardStream.h"
// AudioBoardStream out(AudioKitEs8388V1); // final output of decoded stream
I2SStream out; // audio output
BufferRTOS<uint8_t> buffer(0);
QueueStream<uint8_t> queue(buffer);
HLSStream hls_stream("ssid", "password"); // audio data source
// decoder
MP3DecoderHelix mp3;
AACDecoderHelix aac;
MTSDecoder mts(aac); // MPEG-TS (MTS) decoder
MultiDecoder multi(hls_stream); // MultiDecoder using mime from hls_stream
EncodedAudioOutput dec(&out, &multi);
// 2 separate copy processes
StreamCopy copier_play(dec, queue);
StreamCopy copier_write_queue(queue, hls_stream);
Task writeTask("write", 1024 * 8, 10, 0);
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8
// https://streams.radiomast.io/ref-128k-aaclc-stereo/hls.m3u8
// https://streams.radiomast.io/ref-64k-heaacv1-stereo/hls.m3u8
if (!hls_stream.begin(
"https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8"))
stop();
// register decoders with mime types
multi.addDecoder(mp3, "audio/mpeg");
multi.addDecoder(aac, "audio/aac");
multi.addDecoder(mts, "video/MP2T"); // MPEG-TS
// start output
auto cfg = out.defaultConfig(TX_MODE);
// add optional configuration here: e.g. pins
out.begin(cfg);
buffer.resize(10 * 1024); // increase to 50k psram
dec.begin(); // start decoder
queue.begin(100); // activate read when 100% full
writeTask.begin([]() { copier_write_queue.copy(); });
}
// Arduino loop
void loop() { copier_play.copy(); }

View File

@@ -0,0 +1,48 @@
/**
* @file hls-i2s.ino
* @brief Copy hls stream to decoder: the re-loading of data is causig pauses
* We use a MultiDecoder to handle different formats.
* For MPEG-TS (MTS) you need to set the log level to Warning or higher.
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/HLSStream.h"
#include "AudioTools/AudioCodecs/CodecHelix.h"
//#include "AudioTools/AudioLibs/AudioBoardStream.h"
//AudioBoardStream out(AudioKitEs8388V1);
I2SStream out;
HLSStream hls_stream("ssid", "password");
MP3DecoderHelix mp3;
AACDecoderHelix aac;
MultiDecoder multi(hls_stream); // MultiDecoder using mime from hls_stream
EncodedAudioOutput dec(&out, &multi);
StreamCopy copier(dec, hls_stream);
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8
// https://streams.radiomast.io/ref-128k-aaclc-stereo/hls.m3u8
// https://streams.radiomast.io/ref-64k-heaacv1-stereo/hls.m3u8
if (!hls_stream.begin("https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8"))
stop();
multi.addDecoder(mp3, "audio/mpeg");
multi.addDecoder(aac, "audio/aac");
auto cfg = out.defaultConfig(TX_MODE);
out.begin(cfg);
dec.begin(); // start decoder
}
// Arduino loop
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,68 @@
# A Simple Streaming Audio Player
It was pretty simple to build a simple audio player with the help of the Stream API.
The AudioPlayer supports
- __multiple processor architectures__
- __multiple audio data sources__ (SD, URL, callbacks)
- __different Output__ Scenarios (I2S, PWM, A2DP etc). Just pass the desired output stream object to the constructor.
- __different Decoders__ for MP3, AAC, WAV. Just pass the desired decoder object to the constructor.
- __Volume Control__ (by calling player.setVolume())
- __Stopping and Resuming__ the processing (by calling player.stop() and player.play())
- You can __move to the next file__ by calling player.next();
- support for __Metadata__
The example demonstrates how to implement an __MP3 Player__ which provides the data via the Internet (with the help of the AudioSourceURL class) and sends the audio via I2S to an external DAC using an ESP32.
### The External DAC
For my tests I am using the 24-bit PCM5102 PCM5102A Stereo DAC Digital-to-analog Converter PLL Voice Module pHAT
![DAC](https://pschatzmann.github.io/Resources/img/dac.jpeg)
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
DAC | ESP32
-----|----------------
VCC | 5V
GND | GND
BCK | BCK (GPIO14)
DIN | OUT (GPIO22)
LCK | BCK (GPIO15)
FMT | GND
XMT | 3V (or another GPIO PIN which is set to high)
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
- FLT - Filter select : Normal latency (Low) / Low latency (High)
- SCL - System clock input (probably SCL on your board).
- FMT - Audio format selection : I2S (Low) / Left justified (High)
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)
### Wiring the Volume Potentiometer
![DAC](https://www.pschatzmann.ch/wp-content/uploads/2021/10/Pot.jpg)
| Pot | ESP32 | ESP8266
| --------| ---------|---------
| POW | 3V | 3V
| GND | GND | GND
| VOUT | A0 | A0
### Moving to the next song
We use a button to move to the next url.
| Button | ESP32 | ESP8266
|------------|----------|---------
| Button | GPIO13 | GPIO13
| Out 3V
### Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix

View File

@@ -0,0 +1,73 @@
/**
* @file player-url-i2s.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-url-i2s/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Disk/AudioSourceURL.h"
#include "AudioTools/Communication/AudioHttp.h"
const char *urls[] = {
"http://stream.srg-ssr.ch/m/rsj/mp3_128",
"http://stream.srg-ssr.ch/m/drs3/mp3_128",
"http://stream.srg-ssr.ch/m/rr/mp3_128",
"http://sunshineradio.ice.infomaniak.ch/sunshineradio-128.mp3",
"http://streaming.swisstxt.ch/m/drsvirus/mp3_128"
};
const char *wifi = "wifi";
const char *password = "password";
URLStream urlStream(wifi, password);
AudioSourceURL source(urlStream, urls, "audio/mp3");
I2SStream i2s;
MP3DecoderHelix decoder;
AudioPlayer player(source, i2s, decoder);
// additional controls
const int volumePin = A0;
Debouncer nextButtonDebouncer(2000);
const int nextButtonPin = 13;
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup output
auto cfg = i2s.defaultConfig(TX_MODE);
i2s.begin(cfg);
// setup player
player.begin();
}
// Sets the volume control from a linear potentiometer input
void updateVolume() {
// Reading potentiometer value (range is 0 - 4095)
float vol = static_cast<float>(analogRead(volumePin));
// min in 0 - max is 1.0
player.setVolume(vol/4095.0);
}
// Moves to the next url when we touch the pin
void updatePosition() {
if (digitalRead(nextButtonPin)) {
Serial.println("Moving to next url");
if (nextButtonDebouncer.debounce()){
player.next();
}
}
}
void loop() {
//updateVolume(); // remove comments to activate volume control
//updatePosition(); // remove comments to activate position control
player.copy();
}

View File

@@ -0,0 +1,21 @@
# A Simple Icecast Streaming Audio Player
Compared to the regular URLStream, and ICYStream provides audio Metadata.
<img src="https://pschatzmann.github.io/Resources/img/audio-toolkit.png" alt="Audio Kit" />
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies:
I also demonstrate how to assign your own actions to the buttons of the audio kit.
### Notes
- Do not forget to set the wifi name and password.
- The log level has been set to Info to help you to identify any problems. Please change it to AudioLogger::Warning to get the best sound quality!
### Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix
- https://github.com/pschatzmann/arduino-audio-driver

View File

@@ -0,0 +1,70 @@
/**
* @file player-url-kit.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-audiokit/player-url-audiokit/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Disk/AudioSourceURL.h"
#include "AudioTools/Communication/AudioHttp.h"
const char *urls[] = {
"http://stream.srg-ssr.ch/m/rsj/mp3_128",
"http://stream.srg-ssr.ch/m/drs3/mp3_128",
"http://stream.srg-ssr.ch/m/rr/mp3_128",
"http://sunshineradio.ice.infomaniak.ch/sunshineradio-128.mp3",
"http://streaming.swisstxt.ch/m/drsvirus/mp3_128"
};
const char *wifi = "wifi";
const char *password = "password";
ICYStream urlStream(wifi, password);
AudioSourceURL source(urlStream, urls, "audio/mp3");
AudioBoardStream kit(AudioKitEs8388V1);
MP3DecoderHelix decoder;
AudioPlayer player(source, kit, decoder);
void next(bool, int, void*) {
player.next();
}
void previous(bool, int, void*) {
player.previous();
}
void stopResume(bool, int, void*){
if (player.isActive()){
player.stop();
} else{
player.play();
}
}
// Arduino setup
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
cfg.sd_active = false;
kit.begin(cfg);
// setup navigation
kit.addAction(kit.getKey(4), next);
kit.addAction(kit.getKey(3), previous);
// setup player
player.setVolume(0.7);
player.begin();
}
// Arduino loop
void loop() {
player.copy();
kit.processActions();
}

View File

@@ -0,0 +1,54 @@
# A Simple Icecast Streaming Audio Player
Compared to the regular URLStream, and ICYStream provides audio Metadata.
### The External DAC
For my tests I am using the 24-bit PCM5102 PCM5102A Stereo DAC Digital-to-analog Converter PLL Voice Module pHAT
![DAC](https://pschatzmann.github.io/Resources/img/dac.jpeg)
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
DAC | ESP32
-----|----------------
VCC | 5V
GND | GND
BCK | BCK (GPIO14)
DIN | OUT (GPIO22)
LCK | BCK (GPIO15)
FMT | GND
XMT | 3V (or another GPIO PIN which is set to high)
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
- FLT - Filter select : Normal latency (Low) / Low latency (High)
- SCL - System clock input (probably SCL on your board).
- FMT - Audio format selection : I2S (Low) / Left justified (High)
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)
### Wiring the Volume Potentiometer
![DAC](https://www.pschatzmann.ch/wp-content/uploads/2021/10/Pot.jpg)
| Pot | ESP32 | ESP8266
| --------| ---------|---------
| POW | 3V | 3V
| GND | GND | GND
| VOUT | A0 | A0
### Moving to the next song
We use a button to move to the next url.
| Button | ESP32 | ESP8266
|------------|----------|---------
| Button | GPIO13 | GPIO13
| Out 3V
### Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix

View File

@@ -0,0 +1,84 @@
/**
* @file player-url-i2s.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-url-i2s/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Disk/AudioSourceURL.h"
#include "AudioTools/Communication/AudioHttp.h"
const char *urls[] = {
"http://stream.srg-ssr.ch/m/rsj/mp3_128",
"http://stream.srg-ssr.ch/m/drs3/mp3_128",
"http://stream.srg-ssr.ch/m/rr/mp3_128",
"http://sunshineradio.ice.infomaniak.ch/sunshineradio-128.mp3",
"http://streaming.swisstxt.ch/m/drsvirus/mp3_128"
};
const char *wifi = "wifi";
const char *password = "password";
ICYStream urlStream(wifi, password);
AudioSourceURL source(urlStream, urls, "audio/mp3");
I2SStream i2s;
MP3DecoderHelix decoder;
AudioPlayer player(source, i2s, decoder);
// additional controls
const int volumePin = A0;
Debouncer nextButtonDebouncer(2000);
const int nextButtonPin = 13;
// Print Audio Metadata
void printMetaData(MetaDataType type, const char* str, int len){
Serial.print("==> ");
Serial.print(toStr(type));
Serial.print(": ");
Serial.println(str);
}
// Arduino setup
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup output
auto cfg = i2s.defaultConfig(TX_MODE);
i2s.begin(cfg);
// setup player
player.setMetadataCallback(printMetaData);
player.begin();
}
// Sets the volume control from a linear potentiometer input
void updateVolume() {
// Reading potentiometer value (range is 0 - 4095)
float vol = static_cast<float>(analogRead(volumePin));
// min in 0 - max is 1.0
player.setVolume(vol/4095.0);
}
// Moves to the next url when we touch the pin
void updatePosition() {
if (digitalRead(nextButtonPin)) {
Serial.println("Moving to next url");
if (nextButtonDebouncer.debounce()){
player.next();
}
}
}
// Arduino loop
void loop() {
//updateVolume(); // remove comments to activate volume control
//updatePosition(); // remove comments to activate position control
player.copy();
}

View File

@@ -0,0 +1,53 @@
#pragma once
#include "AudioTools.h"
#include "AudioTools/Communication/HTTP/URLStream.h"
#include "AudioTools/Disk/AudioSourceURL.h"
namespace audio_tools {
/**
* @brief URLStream which provides the ICY Http Parameters
*
*/
class AudioSourceIcyUrl : public AudioSourceURL {
public:
template<typename T, size_t N>
AudioSourceIcyUrl(URLStream& urlStream, T(&urlArray)[N], const char* mime, int start=0)
: AudioSourceURL(urlStream, urlArray, mime,start) {
}
const char *icyValue(const char* name) {
return actual_stream->httpRequest().reply().get(name);
}
const char *icyName() {
return icyValue("icy-name");
}
const char *icyDescription() {
return icyValue("icy-description");
}
const char *icyGenre() {
return icyValue("icy-genre");
}
/// Returns the last section of a url: https://22323.live.streamtheworld.com/TOPRETRO.mp3 gives TOPRETRO.mp3
const char *urlName(){
const char* result = "";
StrView tmpStr(toStr());
int pos = tmpStr.lastIndexOf("/");
if (pos>0){
result = toStr()+pos+1;
}
return result;
}
/// Returns the icy name if available otherwise we use our custom logic
const char* name() {
StrView result(icyName());
if (result.isEmpty()){
result.set(urlName());
}
return result.c_str();
}
};
}

View File

@@ -0,0 +1,10 @@
# A Simple Streaming Audio Player
This is just a simple example which demonstrates how to use your own subclasses to add additional functionality.
We provide the URL ICY parameters in our own AudioSourceIcyUrl subclass!
### Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix

View File

@@ -0,0 +1,83 @@
/**
* @file player-url-i2s.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-url_subclass-i2s/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioSourceIcyUrl.h"
#include "AudioTools/Communication/AudioHttp.h"
const char *urls[] = {
"http://stream.srg-ssr.ch/m/rsj/mp3_128",
"http://stream.srg-ssr.ch/m/drs3/mp3_128",
"http://stream.srg-ssr.ch/m/rr/mp3_128",
"http://sunshineradio.ice.infomaniak.ch/sunshineradio-128.mp3",
"http://streaming.swisstxt.ch/m/drsvirus/mp3_128"
};
const char *wifi = "wifi";
const char *password = "password";
URLStream urlStream(wifi, password);
AudioSourceIcyUrl source(urlStream, urls, "audio/mp3");
I2SStream i2s;
MP3DecoderHelix decoder;
AudioPlayer player(source, i2s, decoder);
// additional controls
const int volumePin = A0;
Debouncer nextButtonDebouncer(2000);
const int nextButtonPin = 13;
void printName() {
Serial.print("icy name: ");
Serial.println(source.icyName());
Serial.print("Url name: ");
Serial.println(source.urlName());
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup output
auto cfg = i2s.defaultConfig(TX_MODE);
i2s.begin(cfg);
// setup player
player.begin();
printName();
}
// Sets the volume control from a linear potentiometer input
void updateVolume() {
// Reading potentiometer value (range is 0 - 4095)
float vol = static_cast<float>(analogRead(volumePin));
// min in 0 - max is 1.0
player.setVolume(vol/4095.0);
}
// Moves to the next url when we touch the pin
void updatePosition() {
if (digitalRead(nextButtonPin)) {
Serial.println("Moving to next url");
if (nextButtonDebouncer.debounce()){
player.next();
printName();
}
}
}
void loop() {
//updateVolume(); // remove comments to activate volume control
//updatePosition(); // remove comments to activate position control
player.copy();
}

View File

@@ -0,0 +1,69 @@
/**
* @file streams-url_mp3-i2s.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const int CS = SS;
EthernetClient eth;
URLStream url(eth);
I2SStream i2s; // final output of decoded stream
EncodedAudioStream dec(&i2s, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setupEthernet() {
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(CS);
// start the Ethernet connection:
Serial.println("Initialize Ethernet with DHCP:");
if (Ethernet.begin(mac)) {
Serial.print(" DHCP assigned IP ");
Serial.println(Ethernet.localIP());
} else {
Serial.println("Failed to configure Ethernet using DHCP");
stop();
}
}
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
setupEthernet();
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
// you could define e.g your pins and change other settings
//config.pin_ws = 10;
//config.pin_bck = 11;
//config.pin_data = 12;
//config.mode = I2S_STD_FORMAT;
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,67 @@
/**
* @file streams-url-post.ino
* @author Phil Schatzmann
* @brief example how to http post data from an input stream using the
* HttpRequest class.
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
const char *ssid = "your SSID";
const char *password = "your PASSWORD";
const char *url_str = "http://192.168.1.44:9988";
AudioInfo info(44100, 2, 16);
SineWaveGenerator<int16_t> sineWave(32000);
GeneratedSoundStream<int16_t> sound(sineWave);
TimedStream timed(sound);
WiFiClient client;
HttpRequest http(client);
StreamCopy copier(http, timed);
void startWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println();
Serial.println(WiFi.localIP());
}
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
startWiFi();
// Setup sine wave
sineWave.begin(info, N_B4);
// limit the size of the input stream to 60 seconds
timed.setEndSec(60);
timed.begin();
// start post
Url url(url_str);
http.header().put(TRANSFER_ENCODING, CHUNKED); // uncomment if chunked
if (!http.processBegin(POST, url, "audio/pcm")){
Serial.println("post failed");
stop();
}
}
// Arduino loop - copy sound to out
void loop() {
// posting the data
if (copier.copy() == 0) {
// closing the post
http.processEnd();
}
}

View File

@@ -0,0 +1,59 @@
/**
* @file streams-url-file.ino
* @author Phil Schatzmann
* @brief Demo how to download a file from the internet and store it to a file. The test was done with an AudioKit which requires
* some specific pin settings
* @version 0.1
* @date 2022-09-09
*
* @copyright Copyright (c) 2022
*
*/
#include "SD.h"
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
#define PIN_AUDIO_KIT_SD_CARD_CS 13
#define PIN_AUDIO_KIT_SD_CARD_MISO 2
#define PIN_AUDIO_KIT_SD_CARD_MOSI 15
#define PIN_AUDIO_KIT_SD_CARD_CLK 14
const char *ssid = "SSID";
const char *password = "password";
URLStream url(ssid, password); // Music Stream
StreamCopy copier; //(i2s, music, 1024); // copy music to i2s
File file; // final output stream
int retryCount = 5;
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// define custom SPI pins
SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
// intialize SD
if(!SD.begin(PIN_AUDIO_KIT_SD_CARD_CS)){
LOGE("SD failed");
return;
}
// open music stream
url.begin("https://pschatzmann.github.io/Resources/audio/audio-8000.raw");
// copy file
file = SD.open("/audio-8000.raw", FILE_WRITE);
// overwirte from beginning
file.seek(0);
copier.begin(file, url);
copier.copyAll();
file.close();
file = SD.open("/audio-8000.raw");
LOGI("file size: %d", file.size());
}
void loop() {
}

View File

@@ -0,0 +1,35 @@
/**
* @file streams-url_mp3-measuring.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and measure bytes per second of decoded data
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password"); // or replace with ICYStream to get metadata
MeasuringStream out(50, &Serial); // final output of decoded stream
EncodedAudioStream dec(&out, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
dec.begin();
// mp3 radio
url.begin("http://direct.fipradio.fr/live/fip-midfi.mp3","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,4 @@
# Streaming Radio Player
We just play a streamed radio station which provides the audio as aac and output the result via I2S to an external DAC

View File

@@ -0,0 +1,43 @@
/**
* @file streams-url_aac-audiokit.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S on audiokit
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecAACHelix.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password"); // or replace with ICYStream to get metadata
AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
EncodedAudioStream dec(&i2s, new AACDecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// aac radio
url.begin("http://peacefulpiano.stream.publicradio.org/peacefulpiano.aac","audio/aac");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,30 @@
# Streaming Radio Player
We just play a streamed radio station which provides the audio as mp3 and output the result via I2S to an external DAC
An ESP32 was used to test this sketch.
### External DAC:
![DAC](https://pschatzmann.github.io/Resources/img/dac.jpeg)
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
DAC | ESP32
-----|----------------
VCC | 5V
GND | GND
BCK | BCK (GPIO14)
DIN | OUT (GPIO22)
LCK | BCK (GPIO15)
FMT | GND
XMT | 3V (or another GPIO PIN which is set to high)
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
- FLT - Filter select : Normal latency (Low) / Low latency (High)
- SCL - System clock input (probably SCL on your board).
- FMT - Audio format selection : I2S (Low) / Left justified (High)
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)

View File

@@ -0,0 +1,47 @@
/**
* @file streams-url_aac-i2s.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecAACHelix.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password");
I2SStream i2s; // final output of decoded stream
EncodedAudioStream dec(&i2s, new AACDecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
// you could define e.g your pins and change other settings
//config.pin_ws = 10;
//config.pin_bck = 11;
//config.pin_data = 12;
//config.mode = I2S_STD_FORMAT;
i2s.begin(config);
// aac radio
url.begin("http://peacefulpiano.stream.publicradio.org/peacefulpiano.aac","audio/aac");
// initialize decoder
dec.begin();
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,35 @@
/**
* @file streams-url_flac-i2s.ino
* @author Phil Schatzmann
* @brief The FLAC decoder supports a streaming interface where we can directly assign a source stream
* @version 0.1
* @date 2022-05-13
*
* @copyright Copyright (c) 2022
*
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecFLAC.h"
#include "AudioTools/Communication/AudioHttp.h"
const char* ssid = "ssid";
const char* pwd = "password";
URLStream url(ssid, pwd);
FLACDecoder dec;
I2SStream i2s;
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
i2s.begin(i2s.defaultConfig(TX_MODE));
url.begin("http://www.lindberg.no/hires/test/2L-145_01_stereo_01.cd.flac");
dec.setInput(url);
dec.setOutput(i2s);
dec.begin();
}
void loop() {
dec.copy();
}

View File

@@ -0,0 +1,54 @@
/**
* @file streams-url_flac_foxen-i2s.ino
* @author Phil Schatzmann
* @brief Demo using the Foxen FLAC decoder
* @version 0.1
* @date 2025-01-09
*
* @copyright Copyright (c) 2022
*
* Warning: The WIFI speed is quite limited and the FLAC files are quite big. So there
* is a big chance that the WIFI is just not fast enough. For my test I was downsampling
* the file to 8000 samples per second!
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecFLACFoxen.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Communication/AudioHttp.h"
const char* ssid = "ssid";
const char* pwd = "password";
URLStream url(ssid, pwd);
AudioBoardStream i2s(AudioKitEs8388V1); // or replace with e.g. I2SStream i2s;
FLACDecoderFoxen flac(5*1024, 2);
EncodedAudioStream dec(&i2s, &flac); // Decoding to i2s
StreamCopy copier(dec, url, 1024); // copy url to decoder
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
while(!Serial);
Serial.println("starting...");
// Open I2S: if the buffer is too slow audio is breaking up
auto cfg =i2s.defaultConfig(TX_MODE);
cfg.buffer_size= 1024;
cfg.buffer_count = 20;
if (!i2s.begin(cfg)){
Serial.println("i2s error");
stop();
}
// Open url
url.begin("https://pschatzmann.github.io/Resources/audio/audio.flac", "audio/flac");
// Start decoder
if (!dec.begin()){
Serial.println("Decoder failed");
}
}
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,23 @@
# Streaming Radio Player
We just play a streamed radio station which provides the audio as mp3 and output the result via I2S via the built in DAC
An ESP32 was used to test this sketch.
### Output Device: Piezo Electric Element
To test the output I am using a piezo electric element
![DAC](https://pschatzmann.github.io/Resources/img/piezo.jpeg)
It should also be possible to connect a headphone to the output pins...
On the ESP32 the output is on the Pins GPIO26 and GPIO27
| PIEZO | ESP32
| --------| ---------------
| + | GPIO25 / GPIO26
| - | GND

View File

@@ -0,0 +1,42 @@
/**
* @file streams-url_mp3-out.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password");
AnalogAudioStream out; // final output of decoded stream
EncodedAudioStream dec(&out, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup out
auto config = out.defaultConfig(TX_MODE);
out.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,4 @@
# Streaming Radio Player
We just play a streamed radio station which provides the audio as mp3 and output the result via I2S to an external DAC

View File

@@ -0,0 +1,43 @@
/**
* @file streams-url_mp3-audiokit.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S on audiokit
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password"); // or replace with ICYStream to get metadata
AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
EncodedAudioStream dec(&i2s, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,43 @@
/**
* @file streams-url_mp3-out.ino
* @author Phil Schatzmann
* @brief read MP3 stream from url and output of metadata only: There is no audio output!
* @date 2021-11-07
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
ICYStream url("ssid","password");
MetaDataOutput out; // final output of decoded stream
StreamCopy copier(out, url); // copy url to decoder
// callback for meta data
void printMetaData(MetaDataType type, const char* str, int len){
Serial.print("==> ");
Serial.print(toStr(type));
Serial.print(": ");
Serial.println(str);
}
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// mp3 radio
url.httpRequest().header().put("Icy-MetaData","1");
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
out.setCallback(printMetaData);
out.begin(url.httpRequest());
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,62 @@
/**
* @file streams-url_mp3-metadata2.ino
* @author Phil Schatzmann
* @brief read MP3 stream from url and output metadata and audio!
* The used mp3 file contains ID3 Metadata!
* @date 2021-11-07
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
// -> EncodedAudioStream -> I2SStream
// URLStream -> MultiOutput -|
// -> MetaDataOutput
URLStream url("ssid","password");
MetaDataOutput out1; // final output of metadata
I2SStream i2s; // I2S output
EncodedAudioStream out2dec(&i2s, new MP3DecoderHelix()); // Decoding stream
MultiOutput out;
StreamCopy copier(out, url); // copy url to decoder
// callback for meta data
void printMetaData(MetaDataType type, const char* str, int len){
Serial.print("==> ");
Serial.print(toStr(type));
Serial.print(": ");
Serial.println(str);
}
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup multi output
out.add(out1);
out.add(out2dec);
// setup input
url.begin("https://pschatzmann.github.io/Resources/audio/audio.mp3","audio/mp3");
// setup metadata
out1.setCallback(printMetaData);
out1.begin(url.httpRequest());
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
out2dec.begin();
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,50 @@
/**
* @file streams-url_mp3-out.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it with the help of PWM
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password");
PWMAudioOutput out; // final output of decoded stream
EncodedAudioStream dec(&out, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup out
auto config = out.defaultConfig(TX_MODE);
//config.resolution = 8; // must be between 8 and 11 -> drives pwm frequency (8 is default)
// alternative 1
//config.start_pin = 3;
// alternative 2
int pins[] = {22, 23};
// alternative 3
//Pins pins = {3};
//config.setPins(pins);
out.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,34 @@
# Streaming Radio Player
We just play a streamed radio station which provides the audio as mp3 and output the result via I2S to an external DAC
To decode the data we use the libhelix library.
An ESP32 was used to test this sketch.
### External DAC:
![DAC](https://pschatzmann.github.io/Resources/img/dac.jpeg)
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
DAC | ESP32
-----|----------------
VCC | 5V
GND | GND
BCK | BCK (GPIO14)
DIN | OUT (GPIO22)
LCK | BCK (GPIO15)
FMT | GND
XMT | 3V (or another GPIO PIN which is set to high)
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
- FLT - Filter select : Normal latency (Low) / Low latency (High)
- SCL - System clock input (probably SCL on your board).
- FMT - Audio format selection : I2S (Low) / Left justified (High)
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)
### Dependencies
- https://github.com/pschatzmann/arduino-libhelix

View File

@@ -0,0 +1,47 @@
/**
* @file streams-url_mp3-i2s.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password");
I2SStream i2s; // final output of decoded stream
EncodedAudioStream dec(&i2s, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
// you could define e.g your pins and change other settings
//config.pin_ws = 10;
//config.pin_bck = 11;
//config.pin_data = 12;
//config.mode = I2S_STD_FORMAT;
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,53 @@
/**
* @file streams-url_mp3-i2s_24bit.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S. The data is converted from
* 16 to 32 bit
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password");
I2SStream i2s; // final output of decoded stream
NumberFormatConverterStream nfc(i2s);
EncodedAudioStream dec(&nfc, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// convert 16 bits to 32, you could also change the gain
nfc.begin(16, 32);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
// you could define e.g your pins and change other settings
//config.pin_ws = 10;
//config.pin_bck = 11;
//config.pin_data = 12;
//config.mode = I2S_STD_FORMAT;
//config.bits_per_sample = 32; // we coult do this explicitly
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,35 @@
# Streaming Radio Player
We just play a streamed radio station which provides the audio as mp3 and output the result via I2S to an external DAC
To decode the data we use the libmad library.
An ESP32 was used to test this sketch.
### External DAC:
![DAC](https://pschatzmann.github.io/Resources/img/dac.jpeg)
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
DAC | ESP32
-----|----------------
VCC | 5V
GND | GND
BCK | BCK (GPIO14)
DIN | OUT (GPIO22)
LCK | BCK (GPIO15)
FMT | GND
XMT | 3V (or another GPIO PIN which is set to high)
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
- FLT - Filter select : Normal latency (Low) / Low latency (High)
- SCL - System clock input (probably SCL on your board).
- FMT - Audio format selection : I2S (Low) / Left justified (High)
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)
### Dependencies
- https://github.com/pschatzmann/arduino-libmad

View File

@@ -0,0 +1,47 @@
/**
* @file streams-url_mp3-i2s.ino
* @author Phil Schatzmann
* @brief decode MP3 stream from url and output it on I2S
* @version 0.1
* @date 2021-96-25
*
* @copyright Copyright (c) 2021
*/
// install https://github.com/pschatzmann/arduino-libmad.git
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3MAD.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream url("ssid","password");
I2SStream i2s; // final output of decoded stream
EncodedAudioStream dec(&i2s, new MP3DecoderMAD()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
// you could define e.g your pins and change other settings
//config.pin_ws = 10;
//config.pin_bck = 11;
//config.pin_data = 12;
//config.mode = I2S_STD_FORMAT;
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
dec.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
}
void loop(){
copier.copy();
}

View File

@@ -0,0 +1,32 @@
/**
* @file url_mts-hex.ino
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMTS.h"
#include "AudioTools/Communication/HLSStream.h"
HexDumpOutput out(Serial);
HLSStream hls_stream("SSID", "password");
MTSDecoder mts;
EncodedAudioStream mts_stream(&out, &mts);
StreamCopy copier(mts_stream, hls_stream);
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
mts_stream.begin();
hls_stream.begin("http://a.files.bbci.co.uk/media/live/manifesto/audio/simulcast/hls/nonuk/sbr_vlow/ak/bbc_world_service.m3u8");
}
// Arduino loop
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,36 @@
/**
* @file streams-url-post.ino
* @author Phil Schatzmann
* @brief example how to http post data from an input stream
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
AudioInfo info(44100, 2, 16);
SineWaveGenerator<int16_t> sineWave(32000);
GeneratedSoundStream<int16_t> sound(sineWave);
TimedStream timed(sound);
URLStream url("ssid", "password");
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// Setup sine wave
sineWave.begin(info, N_B4);
// limit the size of the input stream
timed.setEndSec(60);
timed.begin();
// post the data
url.begin("http://192.168.1.35:8000", "audio/bin", POST, "text/html", timed);
}
// Arduino loop - copy sound to out
void loop() {}

View File

@@ -0,0 +1,29 @@
# Stream URL to I2S external DAC
We are reading a raw audio file from the Intenet and write the data to the I2S interface. The audio file must be available using 16 bit integers with 2 channels. I used a sampling rate of 8000.
[Audacity](https://www.audacityteam.org/) might help you out here: export with the file name audio.raw as RAW signed 16 bit PCM and copy it to the SD card. In my example I was using the file [audio.raw](https://pschatzmann.github.io/Resources/audio/audio.raw).
### External DAC:
![DAC](https://pschatzmann.github.io/Resources/img/dac.jpeg)
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
DAC | ESP32
-----|----------------
VCC | 5V
GND | GND
BCK | BCK (GPIO14)
DIN | OUT (GPIO22)
LCK | BCK (GPIO15)
FMT | GND
XMT | 3V (or another GPIO PIN which is set to high)
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
- FLT - Filter select : Normal latency (Low) / Low latency (High)
- SCL - System clock input (probably SCL on your board).
- FMT - Audio format selection : I2S (Low) / Left justified (High)
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)

View File

@@ -0,0 +1,51 @@
/**
* @file url_raw-I2S_external_dac.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/url_raw-I2S_externel_dac/README.md
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "WiFi.h"
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream music; // Music Stream
I2SStream i2s;// I2S as Stream
StreamCopy copier(i2s, music, 1024); // copy music to i2s
// Arduino Setup
void setup(void) {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// connect to WIFI
WiFi.begin("network", "pwd");
while (WiFi.status() != WL_CONNECTED){
Serial.print(".");
delay(500);
}
// open music stream
music.begin("https://pschatzmann.github.io/Resources/audio/audio-8000.raw");
// start I2S with external DAC
Serial.println("\nstarting I2S...");
auto cfg = i2s.defaultConfig(TX_MODE);
cfg.sample_rate = 8000;
i2s.begin(cfg);
}
// Arduino loop - repeated processing: copy input stream to output stream
void loop() {
int len = copier.copy();
if (len){
Serial.print(".");
} else {
delay(5000);
i2s.end();
Serial.println("\nCopy ended");
stop();
}
}

View File

@@ -0,0 +1,8 @@
# Display RAW Stream
Sometimes it is handy to check out the data on the screen with the help of the Arduino Serial Monitor and Serial Plotter.
We read the raw binary data from an URLStream.
As output stream we use a CsvOutput: this class transforms the data into CSV and prints the result to Serial. Finally we can use the Arduino Serial Plotter to view the result as chart:
![serial-plotter](https://pschatzmann.github.io/Resources/img/serial-plotter-01.png)

View File

@@ -0,0 +1,41 @@
/**
* @file streams-url_raw-serial.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-stream/streams-url_raw-serial/README.md
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "WiFi.h"
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
URLStream music; // Music Stream
int channels = 2; // The stream has 2 channels
CsvOutput<int16_t> printer(Serial, channels); // ASCII stream
StreamCopy copier(printer, music); // copies music into printer
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// connect to WIFI
WiFi.begin("network-name", "password");
while (WiFi.status() != WL_CONNECTED){
Serial.print(".");
delay(500);
}
// open music stream - it contains 2 channels of int16_t data
music.begin("https://pschatzmann.github.io/Resources/audio/audio.raw");
}
// Arduino loop - repeated processing
void loop() {
copier.copy();
}

View File

@@ -0,0 +1,35 @@
/**
* @file streams-url_flac-i2s.ino
* @author Phil Schatzmann
* @brief The FLAC decoder supports a streaming interface where we can directly assign a source stream
* @version 0.1
* @date 2022-05-13
*
* @copyright Copyright (c) 2022
*
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecVorbis.h"
#include "AudioTools/Communication/AudioHttp.h"
const char* ssid = "ssid";
const char* pwd = "password";
URLStream url(ssid, pwd);
VorbisDecoder dec;
I2SStream i2s;
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
i2s.begin(i2s.defaultConfig(TX_MODE));
url.begin("http://marmalade.scenesat.com:8086/bitjam.ogg","application/ogg");
dec.setInput(url);
dec.setOutput(i2s);
dec.begin();
}
void loop() {
dec.copy();
}

View File

@@ -0,0 +1,3 @@
# Examples for the WebServer
I created the Server as a simple way to test the audio w/o any need of soldering or connecting any wires. Just use the Wifi to listen to your audio...

View File

@@ -0,0 +1,25 @@
# A Simple SdFat Audio Player
The example demonstrates how to implement an __MP3 Player__: which provides the data from a SD drive and provides the audio via a Webserver!
## SD Card
Here is the information how to wire the SD card to the ESP32
| SD | ESP32
|-------|-----------------------
| CS | VSPI-CS0 (GPIO 05)
| SCK | VSPI-CLK (GPIO 18)
| MOSI | VSPI-MOSI (GPIO 23)
| MISO | VSPI-MISO (GPIO 19)
| VCC | VIN (5V)
| GND | GND
![SD](https://www.pschatzmann.ch/wp-content/uploads/2021/04/sd-module.jpeg)
## Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/TinyHttp.git
- Arduino SD library

View File

@@ -0,0 +1,54 @@
/**
* @file player-sdfat-a2dp.ino
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-sdfat-a2dp/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/Disk/AudioSourceSD.h"
#include "AudioTools/Communication/AudioServerEx.h"
#include "AudioTools/AudioCodecs/CodecCopy.h"
#define PIN_AUDIO_KIT_SD_CARD_CS 13
#define PIN_AUDIO_KIT_SD_CARD_MISO 2
#define PIN_AUDIO_KIT_SD_CARD_MOSI 15
#define PIN_AUDIO_KIT_SD_CARD_CLK 14
const char *ssid = "SSID";
const char *password = "PWD";
const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSD source(startFilePath, ext, PIN_AUDIO_KIT_SD_CARD_CS);
AudioServerEx out;
AudioPlayer player(source, out, *new CopyDecoder());
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
HttpLogger.setLevel(tinyhttp::Warning);
// setup SPI for SD card
SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
// setup output - We need to login and serve the data as audio/mp3
auto cfg = out.defaultConfig();
cfg.password = password;
cfg.ssid = ssid;
cfg.mime = "audio/mp3";
out.begin(cfg);
// setup player
player.setVolume(1.0);
player.begin();
}
void loop() {
player.copy();
out.copy();
}

View File

@@ -0,0 +1,5 @@
This directory contains a server in Python that was used to test the [Arduino
post sketch](https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-communication/http-client/streams-http_post/streams-http_post.ino) using chunged writes.
The server logs each written line and writes the data to a file.

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env python3
from http.server import HTTPServer, SimpleHTTPRequestHandler
HOST = ""
PORT = 9988
path = "./audio.pcm"
class TestHTTPRequestHandler(SimpleHTTPRequestHandler):
def do_POST(self):
self.send_response(200)
self.end_headers()
if "Content-Length" in self.headers:
content_length = int(self.headers["Content-Length"])
body = self.rfile.read(content_length)
with open(path, "wb") as out_file:
print("writing:", content_length)
out_file.write(body)
elif "chunked" in self.headers.get("Transfer-Encoding", ""):
with open(path, "wb") as out_file:
while True:
line = self.rfile.readline().strip()
print(line)
chunk_length = int(line, 16)
if chunk_length != 0:
print("writing chunk:", chunk_length)
chunk = self.rfile.read(chunk_length)
out_file.write(chunk)
# Each chunk is followed by an additional empty newline
# that we have to consume.
self.rfile.readline()
# Finally, a chunk size of 0 is an end indication
if chunk_length == 0:
break
def main():
httpd = HTTPServer((HOST, PORT), TestHTTPRequestHandler)
print("Serving at port:", httpd.server_port)
httpd.serve_forever()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,56 @@
/**
* @file streams-audiokit-webserver_aac.ino
*
* This sketch reads sound data from the AudioKit. The result is provided as AAC stream which can be listened to in a Web Browser
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/AudioCodecs/CodecAACFDK.h"
#include "AudioTools/Communication/AudioHttp.h"
// WIFI
const char *ssid = "ssid";
const char *password = "password";
AudioInfo info(16000,1,16);
AACEncoderFDK fdk;
AudioEncoderServer server(&fdk, ssid, password);
AudioBoardStream kit(AudioKitEs8388V1);
// Arduino setup
void setup(){
Serial.begin(115200);
// Defining Loglevels for the different libraries
//AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
//LOGLEVEL_FDK = FDKInfo;
//LOGLEVEL_AUDIOKIT = AudioKitInfo;
// setup and configure fdk (not necessary if you activate PSRAM)
fdk.setAudioObjectType(2); // AAC low complexity
fdk.setOutputBufferSize(1024); // decrease output buffer size
fdk.setVariableBitrateMode(2); // low variable bitrate
// start i2s input with default configuration
Serial.println("starting AudioKit...");
auto config = kit.defaultConfig(RX_MODE);
config.input_device = ADC_INPUT_LINE2;
config.copyFrom(info);
config.sd_active = false;
kit.begin(config);
Serial.println("AudioKit started");
// start data sink
server.begin(kit, info);
Serial.println("Server started");
}
// Arduino loop
void loop() {
// Handle new connections
server.doLoop();
}

View File

@@ -0,0 +1,63 @@
/**
* @file streams-audiokit-webserver_mp3.ino
*
* This sketch reads sound data from the AudioKit. The result is provided as MP3 stream which can be listened to in a Web Browser
*
* @author Phil Schatzmann, Thorsten Godau (changed AAC example to MP3, added optional static IP)
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/AudioCodecs/CodecMP3LAME.h"
#include "AudioTools/Communication/AudioHttp.h"
// Set static IP address and stuff (optional)
IPAddress IPA_address(192, 168, 0, 222);
IPAddress IPA_gateway(192, 168, 0, 1);
IPAddress IPA_subnet(255, 255, 0, 0);
IPAddress IPA_primaryDNS(192, 168, 0, 1); //optional
IPAddress IPA_secondaryDNS(8, 8, 8, 8); //optional
// WIFI
const char *ssid = "ssid";
const char *password = "password";
AudioInfo info(16000,1,16);
MP3EncoderLAME mp3;
AudioEncoderServer server(&mp3, ssid, password);
AudioBoardStream kit(AudioKitEs8388V1);
// Arduino setup
void setup(){
Serial.begin(115200);
// Defining Loglevels for the different libraries
//AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
//LOGLEVEL_AUDIOKIT = AudioKitInfo;
// Configures static IP address (optional)
if (!WiFi.config(IPA_address, IPA_gateway, IPA_subnet, IPA_primaryDNS, IPA_secondaryDNS))
{
Serial.println("WiFi.config: Failed to configure static IPv4...");
}
// start i2s input with default configuration
Serial.println("starting AudioKit...");
auto config = kit.defaultConfig(RX_MODE);
config.input_device = ADC_INPUT_LINE2;
config.copyFrom(info);
config.sd_active = false;
kit.begin(config);
Serial.println("AudioKit started");
// start data sink
server.begin(kit, config);
Serial.println("Server started");
}
// Arduino loop
void loop() {
// Handle new connections
server.doLoop();
}

View File

@@ -0,0 +1,39 @@
/**
* @file streams-audiokit-webserver_wav.ino
*
* This sketch reads sound data from the AudioKit. The result is provided as WAV stream which can be listened to in a Web Browser
*
* @author Phil Schatzmann
* @copyright GPLv3
*/
#include "AudioTools.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Communication/AudioHttp.h"
AudioEncoderServer server(new WAVEncoder(),"ssid","password");
AudioBoardStream kit(AudioKitEs8388V1);
// Arduino setup
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
// start i2s input with default configuration
Serial.println("starting AudioKit...");
auto config = kit.defaultConfig(RX_MODE);
config.input_device = ADC_INPUT_LINE1;
config.sample_rate = 44100;
config.sd_active = false;
kit.begin(config);
Serial.println("AudioKit started");
// start data sink
server.begin(kit, config);
}
// Arduino loop
void loop() {
// Handle new connections
server.doLoop();
}

View File

@@ -0,0 +1,61 @@
/**
* @file streams-effect-server_wav.ino
*
* This sketch uses sound effects applied to a sine wav. The result is provided as WAV stream which can be listened to in a Web Browser
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
// WIFI
const char *ssid = "ssid";
const char *password = "password";
AudioWAVServer server(ssid, password);
// Contorl input
float volumeControl = 1.0;
int16_t clipThreashold = 4990;
float fuzzEffectValue = 6.5;
int16_t distortionControl = 4990;
int16_t tremoloDuration = 200;
float tremoloDepth = 0.5;
// Audio
SineWaveGenerator<int16_t> sine;
GeneratedSoundStream<int16_t> stream(sine);
AudioEffectStream effects(stream);
// Audio Format
const int sample_rate = 10000;
const int channels = 1;
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial,AudioLogger::Info);
// setup effects
effects.addEffect(new Boost(volumeControl));
effects.addEffect(new Distortion(clipThreashold));
effects.addEffect(new Fuzz(fuzzEffectValue));
effects.addEffect(new Tremolo(tremoloDuration, tremoloDepth, sample_rate));
// start server
auto config = stream.defaultConfig();
config.channels = channels;
config.sample_rate = sample_rate;
server.begin(effects, config);
sine.begin(config, N_B4);
stream.begin(config);
effects.begin(config);
}
// copy the data
void loop() {
server.copy();
}

View File

@@ -0,0 +1,7 @@
# Using FLITE Speach to Text
I am providing a simple sketch which generates sound data with the Flite text to speach engine.
You need to install https://github.com/pschatzmann/arduino-flite
In this demo we provide the result as WAV stream which can be listened to in a Web Browser

View File

@@ -0,0 +1,37 @@
/**
* @file streams-flite-webserver_wav.ino
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "flite_arduino.h"
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
AudioWAVServer server("ssid","password");
// Callback which provides the audio data
void outputData(Print *out){
Serial.print("providing data...");
Flite flite(*out);
// Setup Audio Info
FliteOutputBase *o = flite.getOutput();
flite.say("Hallo, my name is Alice");
Serial.printf("info %d, %d, %d", o->sampleRate(), o->channels(), o->bitsPerSample());
}
void setup(){
Serial.begin(115200);
server.begin(outputData, 8000,1,16);
}
// Arduino loop
void loop() {
// Handle new connections
server.copy();
}

View File

@@ -0,0 +1,45 @@
/**
* @file streams-generator-server_aac.ino
*
* This sketch generates a test sine wave. The result is provided as AAC stream which can be listened to in a Web Browser
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecAACFDK.h"
#include "AudioTools/Communication/AudioHttp.h"
// WIFI
const char *ssid = "ssid";
const char *password = "password";
AudioInfo info(16000,1,16);
AACEncoderFDK fdk;
AudioEncoderServer server(&fdk, ssid, password);
SineWaveGenerator<int16_t> sineWave; // Subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial,AudioLogger::Info);
// configure FDK to use less RAM (not necessary if you activate PSRAM)
fdk.setAudioObjectType(2); // AAC low complexity
fdk.setOutputBufferSize(1024); // decrease output buffer size
fdk.setVariableBitrateMode(2); // low variable bitrate
// start server
server.begin(in, info);
// start generation of sound
sineWave.begin(info, N_B4);
}
// copy the data
void loop() {
server.copy();
}

View File

@@ -0,0 +1,41 @@
/**
* @file streams-generator-webserver_mp3.ino
*
* This sketch generates a test sine wave. The result is provided as mp3 stream which can be listened to in a Web Browser
* Please note that MP3EncoderLAME needs a processor with PSRAM !
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3LAME.h"
#include "AudioTools/Communication/AudioHttp.h"
// WIFI
const char *ssid = "ssid";
const char *password = "password";
AudioInfo info(24000, 1, 16);
MP3EncoderLAME mp3;
AudioEncoderServer server(&mp3, ssid, password);
SineWaveGenerator<int16_t> sineWave; // Subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial,AudioLogger::Info);
// start server
server.begin(in, info);
// start generation of sound
sineWave.begin(info, N_B4);
}
// copy the data
void loop() {
server.copy();
}

View File

@@ -0,0 +1,43 @@
/**
* @file streams-generator-server_ogg.ino
*
* This sketch generates a test sine wave. The result is provided as opus ogg
* stream which can be listened to in a Web Browser This seems to be quite
* unreliable in the browser and with ffplay -i http://address it is breaking
* up.
*
* Only saving it to a file for playback seems to help: ffmpeg -i
* http://address test.ogg
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecOpusOgg.h"
#include "AudioTools/Communication/AudioHttp.h"
// WIFI
const char *ssid = "ssid";
const char *password = "password";
AudioInfo info(16000, 1, 16);
OpusOggEncoder ogg;
AudioEncoderServer server(&ogg, ssid, password);
SineWaveGenerator<int16_t> sineWave;
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// start server
server.begin(in, info);
// start generation of sound
sineWave.begin(info, N_B4);
}
// copy the data
void loop() { server.copy(); }

View File

@@ -0,0 +1,6 @@
# Webserver
With the help of the ESP32 WIFI functionality we can implement a simple web server.
In the example we use a Sine Wave generator as sound source and return the result as an WAV file
It would have been more elegent to use a proper __server library__ - but I did not want to introduce another dependency. So I leave this excercise up to you to implement it with less code by using your preferred library!

View File

@@ -0,0 +1,44 @@
/**
* @file streams-generator-server_wav.ino
*
* This sketch generates a test sine wave. The result is provided as WAV stream which can be listened to in a Web Browser
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/AudioHttp.h"
// WIFI
const char *ssid = "ssid";
const char *password = "password";
AudioWAVServer server(ssid, password);
// Sound Generation
const int sample_rate = 10000;
const int channels = 1;
SineWaveGenerator<int16_t> sineWave; // Subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial,AudioLogger::Info);
// start server
server.begin(in, sample_rate, channels);
// start generation of sound
sineWave.begin(channels, sample_rate, N_B4);
in.begin();
}
// copy the data
void loop() {
server.copy();
}

View File

@@ -0,0 +1,13 @@
# Webserver
With the help of the ESP32 WIFI functionality we can implement a simple web server.
In the example we use a Sine Wave generator as sound source and return the result as an WAV file
The server can be used like any other output stream and we can use a StreamCopy to provide it with data.
Multiple users can connect to the server!
## Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/TinyHttp.git

View File

@@ -0,0 +1,50 @@
/**
* @file streams-generator-server_wav.ino
*
* This sketch generates a test sine wave. The result is provided as WAV stream which can be listened to in a Web Browser
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/AudioServerEx.h"
// WIFI
const char *ssid = "SSID";
const char *password = "password";
AudioInfo info(10000, 1, 16);
SineWaveGenerator<int16_t> sineWave; // Subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
AudioWAVServerEx server;
StreamCopy copier(server, in); // copy mic to tfl
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial,AudioLogger::Info);
HttpLogger.setLevel(tinyhttp::Info);
// activate additional checks
copier.setCheckAvailableForWrite(true);
// start server
auto cfg = server.defaultConfig();
cfg.copyFrom(info);
cfg.ssid = ssid;
cfg.password = password;
server.begin(cfg);
// start generation of sound
sineWave.begin(info, N_B4);
in.begin();
}
// copy the data
void loop() {
copier.copy(); // copy data to server
server.copy(); // from server to client
}

View File

@@ -0,0 +1,13 @@
# Webserver
With the help of the ESP32 WIFI functionality we can implement a simple web server.
In the example we use a Sine Wave generator as sound source and return the result as an WAV file
The input is defied as part of the configuration
Multiple users can connect to the server!
## Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/TinyHttp.git

View File

@@ -0,0 +1,46 @@
/**
* @file streams-generator-server_wav.ino
*
* This sketch generates a test sine wave. The result is provided as WAV stream which can be listened to in a Web Browser
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
#include "AudioTools.h"
#include "AudioTools/Communication/AudioServerEx.h"
// WIFI
const char *ssid = "SSID";
const char *password = "password";
AudioInfo info(10000, 1, 16);
SineWaveGenerator<int16_t> sineWave; // Subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
AudioWAVServerEx server;
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial,AudioLogger::Info);
HttpLogger.setLevel(tinyhttp::Info);
// start server
auto cfg = server.defaultConfig();
cfg.copyFrom(info);
cfg.ssid = ssid;
cfg.password = password;
cfg.input = &in; // Define input
server.begin(cfg);
// start generation of sound
sineWave.begin(info, N_B4);
in.begin();
}
// copy the data
void loop() {
server.copy();
}

Some files were not shown because too many files have changed in this diff Show More