Skip to content

Instantly share code, notes, and snippets.

@raphox
Created February 11, 2023 15:08
Show Gist options
  • Save raphox/4605a8756516f14e2c8ea371eda908ec to your computer and use it in GitHub Desktop.
Save raphox/4605a8756516f14e2c8ea371eda908ec to your computer and use it in GitHub Desktop.
#include <Arduino.h>
#include <SPI.h>
#include <SD.h>
#include "AutoAnalogAudio.h"
/******** User Config ************************************/
#define SD_CS_PIN 5
#define AUDIO_DEBUG
//Number of ADC readings to sample in a single request. Set to MAX_BUFFER_SIZE or a number < 512
uint32_t adcReadings = MAX_BUFFER_SIZE;
/*********************************************************/
AutoAnalog aaAudio;
File myFile;
#include "myWAV.h"
bool doADC = false;
bool firstADC = false;
void setup() {
Serial.begin(57600);
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD init failed!");
return;
}
Serial.println("SD ok\nAnalog Audio Begin");
aaAudio.begin(1, 1); // Start AAAudio with only the DAC (ADC,DAC,External ADC)
aaAudio.autoAdjust = 0; // Disable automatic timer adjustment
aaAudio.setSampleRate(80000);
aaAudio.dacBitsPerSample = 8;
}
void loop() {
if (Serial.available()) {
char input = Serial.read();
switch (input) {
case '1': playAudio("/M8b24kM.wav"); break; //Play a *.wav file by name - 16bit, 32khz, Mono
case '2': playAudio("/M8b24kS.wav"); break; //Play 16bit, 32khz, Stereo
case '3': playAudio("/M8b44kST.wav"); break; //Play 16bit, 44khz, Mono
case '4': playAudio("/M16b24kS.wav"); break; //Play 16bit, 44khz, Stereo
}
}
}
uint8_t channelSelection = 2;
uint32_t loadBuffer();
void DACC_Handler(void) {
aaAudio.dacHandler(); //Link the DAC ISR/IRQ to the library. Called by the MCU when DAC is ready for data
uint32_t samples = loadBuffer();
if (samples) {
aaAudio.feedDAC(channelSelection, samples);
}
}
float volumeVar = 1.00;
/* Function to open the audio file, seek to starting position and enable the DAC */
uint32_t endPosition = 0;
void playAudio(const char *audioFile) {
uint32_t sampleRate = 16000;
uint16_t numChannels = 1;
uint16_t bitsPerSample = 8;
uint32_t dataSize = 0;
uint32_t startPosition = 44;
Serial.println("Play");
if (myFile) {
Serial.println("Close Current");
//Ramp in and ramp out functions prevent popping and clicking when starting/stopping playback
aaAudio.rampOut(0);
aaAudio.disableDAC();
myFile.close();
}
//Open the designated file
myFile = SD.open(audioFile);
if (myFile) {
myFile.seek(22);
myFile.read((byte*)&numChannels, 2);
myFile.read((byte*)&sampleRate, 4);
myFile.seek(34);
myFile.read((byte*)&bitsPerSample, 2);
myFile.seek(40);
myFile.read((byte*)&dataSize, 4);
endPosition = dataSize + 44;
if (myFile.size() > endPosition) {
//startPosition = myFile.size() - dataSize;
endPosition = dataSize + 44;
myFile.seek(endPosition);
uint8_t buf[myFile.size() - (endPosition)];
myFile.read(buf, myFile.size() - (endPosition));
Serial.println("Metadata:");
Serial.println(myFile.size() - (endPosition));
for (int i = 0; i < myFile.size() - (endPosition); i++) {
Serial.print((char)buf[i]);
}
Serial.println();
}
if (bitsPerSample > 12) {
bitsPerSample = 16;
} else if (bitsPerSample > 10 ) {
bitsPerSample = 12;
} else if (bitsPerSample > 8) {
bitsPerSample = 10;
} else {
bitsPerSample = 8;
}
sampleRate *= numChannels;
Serial.print("SampleRate ");
Serial.println(sampleRate);
Serial.println("Set smp rate");
bool stereo = numChannels > 1 ? true : false;
aaAudio.setSampleRate(sampleRate, stereo);
aaAudio.dacBitsPerSample = bitsPerSample;
//Skip past the WAV header
myFile.seek(startPosition);
//Load one buffer
loadBuffer();
//Feed the DAC to start playback
if (aaAudio.dacBitsPerSample == 8) {
aaAudio.rampIn(aaAudio.dacBuffer[0]);
} else {
aaAudio.rampIn((uint8_t)aaAudio.dacBuffer16[0]);
}
aaAudio.feedDAC(channelSelection, MAX_BUFFER_SIZE, true);
} else {
Serial.print("Failed to open ");
Serial.println(audioFile);
}
}
/* Function called from DAC interrupt after dacHandler(). Loads data into the dacBuffer */
uint32_t loadBuffer() {
uint32_t samplesToRead = 0;
uint32_t metaDataSize = myFile.size() - endPosition;
if (myFile) {
if (myFile.available() > metaDataSize + 1 ) {
samplesToRead = MAX_BUFFER_SIZE;
size_t availableBytes = 0;
if (aaAudio.dacBitsPerSample == 8) {
//Load 32 samples into the 8-bit dacBuffer
if ( (availableBytes = (myFile.available() - metaDataSize)) <= samplesToRead) {
samplesToRead = availableBytes;
Serial.print("File Size ");
Serial.print(myFile.size());
Serial.print(" Bytes Read ");
Serial.println(myFile.position() + samplesToRead);
}
myFile.read(aaAudio.dacBuffer, samplesToRead);
for (int i = 0; i < samplesToRead; i++) {
int16_t tmpVar = (uint16_t)aaAudio.dacBuffer[i] - 0x80;
tmpVar = (tmpVar / volumeVar) + 0x80;
aaAudio.dacBuffer[i] = tmpVar;
}
} else {
if ( (availableBytes = (myFile.available() - metaDataSize)) <= (samplesToRead * 2) ) {
samplesToRead = availableBytes / 2;
Serial.print("File Size16 ");
Serial.print(myFile.size());
Serial.print(" Bytes Read ");
Serial.println(myFile.position() + availableBytes);
}
//Load 32 samples (64 bytes) into the 16-bit dacBuffer
int16_t tmpBuffer[samplesToRead];
myFile.read((byte*)tmpBuffer, samplesToRead * 2);
//Convert the 16-bit samples to 12-bit
for (int i = 0; i < samplesToRead; i++) {
tmpBuffer[i] /= volumeVar;
aaAudio.dacBuffer16[i] = (tmpBuffer[i] + 0x8000) >> 8;
}
}
} else {
Serial.println("File close");
myFile.close();
Serial.print("Dis DAC, ");
aaAudio.rampOut(0);
//If using tasks, disabling the active task and DAC will be done from within the task itself
//Need to let aaAudio know by setting the parameter to 'true'. Using useTasks variable
aaAudio.disableDAC(true);
}
}
return samplesToRead;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment