Skip to content

Commit

Permalink
Some I2S scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
pschatzmann committed May 1, 2021
1 parent bcef45b commit b3891a8
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 18 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ Some basic C++ classes that can be used for Audio Processing privided as Arduino
- AudioOutputWithCallback class to provide callback integration with ESP8266Audio

This functionality provides the glue which makes different audio processing components and libraries work together.
We also provide plenty of examples that demonstrate how to implement the different scenarios.
We also provide plenty of examples that demonstrate how to implement the different scenarios.

The design philosophy is based on the Arduino conventions: we use the ```begin()``` and ```end()``` methods to start and stop the processing and we propagate the use of Streams.


## Optional Libraries

Expand Down
2 changes: 1 addition & 1 deletion examples/file_mp3-a2dp/file_mp3-a2dp.ino
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <SD.h>
#include "AudioFileSourceSD.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputWithCallback.h"
#include "ESP8266AudioSupport.h"
#include "BluetoothA2DPSource.h"
#include "AudioTools.h"

Expand Down
40 changes: 40 additions & 0 deletions sandbox/file_raw-I2S_external_dac/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Stream SD File to I2S external DAC

We are reading a raw audio file from the SD card and write the data to the I2S interface. The audio file must be available using 16 bit integers with 2 channels.

[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/arduino-audio-tools/resources/audio.raw).

### SD Pins:

The SD module is connected with the help of the SPI bus

![sd](https://pschatzmann.github.io/arduino-audio-tools/resources/sd-module.jpeg)

We connect the SD to the ESP32:

| SD | ESP32
|---------|---------------
| VCC | 5V
| GND | GND
| CS | CS GP5
| SCK | SCK GP18
| MOSI | MOSI GP23
| MISO | MISO GP19


### External DAC:

| DAC | ESP32
| --------| ---------------
| VDD | 5V
| GND | GND
| SD | OUT (GPIO22)
| L/R | GND
| WS | WS (GPIO15)
| SCK | BCK (GPIO14)






46 changes: 46 additions & 0 deletions sandbox/file_raw-I2S_external_dac/file_raw-I2S_external_dac.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @file file_raw-external_dac.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/file_raw-external_dac/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/

#include "AudioTools.h"
#include <SPI.h>
#include <SD.h>

using namespace audio_tools;

File sound_file;
I2S<int16_t> i2s;
I2SStream i2s_stream(i2s);
StreamCopy streamCopy(i2s_stream, sound_file, 1024);
const char* file_name = "/audio.raw";
const int sd_ss_pin = 5;


// Arduino Setup
void setup(void) {
Serial.begin(115200);

// Setup SD and open file
SD.begin(sd_ss_pin);
sound_file = SD.open(file_name, FILE_READ);

// start I2S with external DAC
Serial.println("starting I2S...");
i2s.begin(i2s.defaultConfig(TX_MODE));
}

// Arduino loop - repeated processing
void loop() {
if (streamCopy.copy()){
Serial.print(".");
} else {
Serial.println();
Serial.println("Copy ended");
delay(10000);
}
}
41 changes: 41 additions & 0 deletions sandbox/file_raw-I2S_internal_dac/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Stream SD File to I2S internal DAC

We are reading a raw audio file from the SD card and write the data to the analog pins of the ESP32 using the I2S interface. The audio file must be available using 16 bit integers with 2 channels.

[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/arduino-audio-tools/resources/audio.raw).

### SD Pins:

The SD module is connected with the help of the SPI bus

![sd](https://pschatzmann.github.io/arduino-audio-tools/resources/sd-module.jpeg)

We connect the SD to the ESP32:

| SD | ESP32
|---------|---------------
| VCC | 5V
| GND | GND
| CS | CS GP5
| SCK | SCK GP18
| MOSI | MOSI GP23
| MISO | MISO GP19


### Amplifier Pins:

To hear the sound we connect the ESP32 to an amplifier module: The analog output is available on GPIO25 & GPIO26. You could also use some earphones.


| Amp | ESP32
|---------|---------------
| + | 5V
| - | GND
| L | GPIO25
| R | GPIO26
| T | GND





48 changes: 48 additions & 0 deletions sandbox/file_raw-I2S_internal_dac/file_raw-I2S_internal_dac.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @file file_raw-internal_dac.ino
* @author Phil Schatzmann
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/file_raw-internal_dac/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*/

#include "AudioTools.h"
#include <SPI.h>
#include <SD.h>

using namespace audio_tools;

File sound_file;
I2S<int16_t> i2s;
I2SStream i2s_stream(i2s);
StreamCopy streamCopy(i2s_stream, sound_file, 1024);
const char* file_name = "/audio.raw";
const int sd_ss_pin = 5;


// Arduino Setup
void setup(void) {
Serial.begin(115200);

// Setup SD and open file
SD.begin(sd_ss_pin);
sound_file = SD.open(file_name, FILE_READ);

// start I2S with internal DAC -> GPIO25 & GPIO26
Serial.println("starting I2S...");
I2SConfig<int16_t> config = i2s.defaultConfig(TX_MODE);
config.i2s.mode = static_cast<i2s_mode_t>( I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN);
i2s.begin(config);
}

// Arduino loop - repeated processing
void loop() {
if (streamCopy.copy()){
Serial.print(".");
} else {
Serial.println();
Serial.println("Copy ended");
delay(10000);
}
}
2 changes: 1 addition & 1 deletion sandbox/flash_midi-a2dp/flash_midi-a2dp.ino
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include <AudioFileSourcePROGMEM.h>
#include "AudioGeneratorMIDI.h"
#include "AudioOutputWithCallback.h"
#include "ESP8266AudioSupport.h"
#include "BluetoothA2DPSource.h"
#include "AudioTools.h"
#include "Undertale_Megalovania.h" // midi
Expand Down
13 changes: 10 additions & 3 deletions src/AudioTools/AudioLogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ class AudioLogger {
void begin(Stream& out, LogLevel level=SOUND_LOG_LEVEL) {
this->log_stream_ptr = &out;
this->log_level = level;
this->active = true;
}

/// stops the logger
void end(){
this->active = false;
}

/// checks if the logging is active
Expand Down Expand Up @@ -66,7 +72,7 @@ class AudioLogger {
/// printf support
int printf(LogLevel current_level, const char* fmt, ...) const {
int len = 0;
if (log_stream_ptr!=nullptr && current_level >= log_level){
if (this->active && log_stream_ptr!=nullptr && current_level >= log_level){
char serial_printf_buffer[PRINTF_BUFFER_SIZE] = {0};
va_list args;
va_start(args,fmt);
Expand All @@ -80,7 +86,7 @@ class AudioLogger {

/// write an message to the log
void log(LogLevel current_level, const char *str, const char* str1=nullptr, const char* str2=nullptr) const {
if (log_stream_ptr!=nullptr){
if (this->active && log_stream_ptr!=nullptr){
if (current_level >= log_level){
log_stream_ptr->print((char*)str);
if (str1!=nullptr){
Expand Down Expand Up @@ -109,7 +115,8 @@ class AudioLogger {

protected:
Stream *log_stream_ptr;
LogLevel log_level;
LogLevel log_level;
bool active;

AudioLogger(){

Expand Down
4 changes: 3 additions & 1 deletion src/AudioTools/Streams.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class MemoryStream : public Stream {
*/
class StreamCopy {
public:
StreamCopy(Stream &from, Stream &to, int buffer_size){
StreamCopy(Stream &to, Stream &from, int buffer_size){
this->from = &from;
this->to = &to;
this->buffer_size = buffer_size;
Expand Down Expand Up @@ -129,6 +129,8 @@ class StreamCopy {

};



#ifdef ESP32
/**
* @brief Represents the content of a URL as Stream. We use the ESP32 ESP HTTP Client API
Expand Down
17 changes: 9 additions & 8 deletions src/AudioWAV.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,6 @@ class WAVHeader {
size_t data_pos = 0;
size_t sound_pos = 0;

void logInfo(){
WAVLogger.printf(AudioLogger::Info,"WAVHeader sound_pos: ", sound_pos);
WAVLogger.printf(AudioLogger::Info,"WAVHeader channels: ", headerInfo.channels);
WAVLogger.printf(AudioLogger::Info,"WAVHeader bits_per_sample: ", headerInfo.bits_per_sample);
WAVLogger.printf(AudioLogger::Info,"WAVHeader sample_rate: ", headerInfo.sample_rate);
WAVLogger.printf(AudioLogger::Info,"WAVHeader format: ", headerInfo.format);
}

uint32_t read_tag() {
uint32_t tag = 0;
tag = (tag << 8) | getChar();
Expand Down Expand Up @@ -210,6 +202,15 @@ class WAVHeader {
bool eof() {
return data_pos>=len-1;
}

void logInfo(){
WAVLogger.printf(AudioLogger::Info,"WAVHeader sound_pos: ", sound_pos);
WAVLogger.printf(AudioLogger::Info,"WAVHeader channels: ", headerInfo.channels);
WAVLogger.printf(AudioLogger::Info,"WAVHeader bits_per_sample: ", headerInfo.bits_per_sample);
WAVLogger.printf(AudioLogger::Info,"WAVHeader sample_rate: ", headerInfo.sample_rate);
WAVLogger.printf(AudioLogger::Info,"WAVHeader format: ", headerInfo.format);
}

};

AudioBaseInfoDependent AudioBaseInfoDependentNone;
Expand Down
33 changes: 30 additions & 3 deletions src/AudioOutputWithCallback.h → src/ESP8266AudioSupport.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#pragma once

#include "AudioOutput.h"
Expand All @@ -13,9 +12,9 @@ namespace audio_tools {
* @author Phil Schatzmann
* @copyright GPLv3
*/
class AudioOutputWithCallback : public AudioOutput
{
class AudioOutputWithCallback : public AudioOutput {
public:
// Default constructor
AudioOutputWithCallback(int bufferSize, int bufferCount ){
buffer_ptr = new NBuffer<Channels>(bufferSize, bufferCount);
}
Expand Down Expand Up @@ -54,4 +53,32 @@ class AudioOutputWithCallback : public AudioOutput
bool active;
};

/**
* @brief ESP8266Audio Output to Stream
*
*/
class SerialOutputStream(): public AudioOutput {
public:
SerialOutputStream(Stream &out){
this->out = out;
}

virtual bool begin() {
active = start;
}

virtual bool ConsumeSample(int16_t sample[2]){
if (active) out.write((uint8_t*)sample, const_exptr(2*sizeof(int16_t)));
}

virtual bool stop() {
active = false;
}

protected:
const Stream &out;
bool active;
};

}

0 comments on commit b3891a8

Please sign in to comment.