Skip to content

Commit

Permalink
ESP8266Audio library
Browse files Browse the repository at this point in the history
  • Loading branch information
lyusupov committed Sep 18, 2023
1 parent 8bc948f commit 4b92733
Show file tree
Hide file tree
Showing 510 changed files with 140,553 additions and 0 deletions.
674 changes: 674 additions & 0 deletions software/firmware/source/libraries/ESP8266Audio/LICENSE

Large diffs are not rendered by default.

266 changes: 266 additions & 0 deletions software/firmware/source/libraries/ESP8266Audio/README.md

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions software/firmware/source/libraries/ESP8266Audio/keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
AudioFileSource KEYWORD1
AudioFileSourceSPIFFS KEYWORD1
AudioFileSourceLittleFS KEYWORD1
AudioFileSourceFS KEYWORD1
AudioFileSourcePROGMEM KEYWORD1
AudioFileSourceHTTPStream KEYWORD1
AudioFileSourceICYStream KEYWORD1
AudioFileSourceID3 KEYWORD1
AudioFileSourceSD KEYWORD1
AudioFileSourceBuffer KEYWORD1
AudioFileSourceSPIRAMBuffer KEYWORD1
AudioGenerator KEYWORD1
AudioGeneratorAAC KEYWORD1
AudioGeneratorFLAC KEYWORD1
AudioGeneratorMOD KEYWORD1
AudioGeneratorMIDI KEYWORD1
AudioGeneratorMP3 KEYWORD1
AudioGeneratorOpus KEYWORD1
AudioGeneratorRTTTL KEYWORD1
AudioGeneratorTalkie KEYWORD1
AudioGeneratorWAV KEYWORD1
AudioOutput KEYWORD1
AudioOutputI2S KEYWORD1
AudioOutputI2SNoDAC KEYWORD1
AudioOutputI2SClass KEYWORD1
AudioOutputPWM KEYWORD1
AudioOutputNull KEYWORD1
AudioOutputBuffer KEYWORD1
AudioOutputSerialWAV KEYWORD1
AudioOutputSPIFFSWAV KEYWORD1
AudioOutputMixer KEYWORD1
AudioOutputMixerStub KEYWORD1
AudioOutputSPDIF KEYWORD1
26 changes: 26 additions & 0 deletions software/firmware/source/libraries/ESP8266Audio/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "ESP8266Audio",
"description": "Audio file format and I2S DAC library for ESP8266, ESP32, and Raspberry Pi Pico RP2040",
"keywords": "ESP8266, ESP32, MP3, AAC, WAV, MOD, FLAC, RTTTL, MIDI, I2S, DAC, Delta-Sigma, TTS",
"authors": [
{
"name": "Earle F. Philhower, III",
"email": "[email protected]",
"url": "https://github.com/earlephilhower/ESP8266Audio",
"maintainer": true
}
],
"repository": {
"type": "git",
"url": "https://github.com/earlephilhower/ESP8266Audio"
},
"version": "1.9.7",
"homepage": "https://github.com/earlephilhower/ESP8266Audio",
"frameworks": "Arduino",
"examples": [
"examples/*/*.ino"
],
"build": {
"libLDFMode": "deep"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=ESP8266Audio
version=1.9.7
author=Earle F. Philhower, III
maintainer=Earle F. Philhower, III
sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040
paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Talkie, and WAV and play on an I2S DAC or a software-driven delta-sigma DAC and 1-transistor amplifier.
category=Signal Input/Output
url=https://github.com/earlephilhower/ESP8266Audio
architectures=esp8266,esp32,rp2040
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
AudioFileSource
Base class of an input "file" to be used by AudioGenerator
Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _AUDIOFILESOURCE_H
#define _AUDIOFILESOURCE_H

#include <Arduino.h>
#include "AudioStatus.h"

class AudioFileSource
{
public:
AudioFileSource() {};
virtual ~AudioFileSource() {};
virtual bool open(const char *filename) { (void)filename; return false; };
virtual uint32_t read(void *data, uint32_t len) { (void)data; (void)len; return 0; };
virtual uint32_t readNonBlock(void *data, uint32_t len) { return read(data, len); };
virtual bool seek(int32_t pos, int dir) { (void)pos; (void)dir; return false; };
virtual bool close() { return false; };
virtual bool isOpen() { return false; };
virtual uint32_t getSize() { return 0; };
virtual uint32_t getPos() { return 0; };
virtual bool loop() { return true; };

public:
virtual bool RegisterMetadataCB(AudioStatus::metadataCBFn fn, void *data) { return cb.RegisterMetadataCB(fn, data); }
virtual bool RegisterStatusCB(AudioStatus::statusCBFn fn, void *data) { return cb.RegisterStatusCB(fn, data); }

protected:
AudioStatus cb;
};

#endif

Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*
AudioFileSourceBuffer
Double-buffered file source using system RAM
Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <Arduino.h>
#include "AudioFileSourceBuffer.h"

#pragma GCC optimize ("O3")

AudioFileSourceBuffer::AudioFileSourceBuffer(AudioFileSource *source, uint32_t buffSizeBytes)
{
buffSize = buffSizeBytes;
buffer = (uint8_t*)malloc(sizeof(uint8_t) * buffSize);
if (!buffer) audioLogger->printf_P(PSTR("Unable to allocate AudioFileSourceBuffer::buffer[]\n"));
deallocateBuffer = true;
writePtr = 0;
readPtr = 0;
src = source;
length = 0;
filled = false;
}

AudioFileSourceBuffer::AudioFileSourceBuffer(AudioFileSource *source, void *inBuff, uint32_t buffSizeBytes)
{
buffSize = buffSizeBytes;
buffer = (uint8_t*)inBuff;
deallocateBuffer = false;
writePtr = 0;
readPtr = 0;
src = source;
length = 0;
filled = false;
}

AudioFileSourceBuffer::~AudioFileSourceBuffer()
{
if (deallocateBuffer) free(buffer);
buffer = NULL;
}

bool AudioFileSourceBuffer::seek(int32_t pos, int dir)
{
if(dir == SEEK_CUR && (readPtr+pos) < length) {
readPtr += pos;
return true;
} else {
// Invalidate
readPtr = 0;
writePtr = 0;
length = 0;
return src->seek(pos, dir);
}
}

bool AudioFileSourceBuffer::close()
{
if (deallocateBuffer) free(buffer);
buffer = NULL;
return src->close();
}

bool AudioFileSourceBuffer::isOpen()
{
return src->isOpen();
}

uint32_t AudioFileSourceBuffer::getSize()
{
return src->getSize();
}

uint32_t AudioFileSourceBuffer::getPos()
{
return src->getPos();
}

uint32_t AudioFileSourceBuffer::getFillLevel()
{
return length;
}

uint32_t AudioFileSourceBuffer::read(void *data, uint32_t len)
{
if (!buffer) return src->read(data, len);

uint32_t bytes = 0;
if (!filled) {
// Fill up completely before returning any data at all
cb.st(STATUS_FILLING, PSTR("Refilling buffer"));
length = src->read(buffer, buffSize);
writePtr = length % buffSize;
filled = true;
}

// Pull from buffer until we've got none left or we've satisfied the request
uint8_t *ptr = reinterpret_cast<uint8_t*>(data);
uint32_t toReadFromBuffer = (len < length) ? len : length;
if ( (toReadFromBuffer > 0) && (readPtr >= writePtr) ) {
uint32_t toReadToEnd = (toReadFromBuffer < (uint32_t)(buffSize - readPtr)) ? toReadFromBuffer : (buffSize - readPtr);
memcpy(ptr, &buffer[readPtr], toReadToEnd);
readPtr = (readPtr + toReadToEnd) % buffSize;
len -= toReadToEnd;
length -= toReadToEnd;
ptr += toReadToEnd;
bytes += toReadToEnd;
toReadFromBuffer -= toReadToEnd;
}
if (toReadFromBuffer > 0) { // We know RP < WP at this point
memcpy(ptr, &buffer[readPtr], toReadFromBuffer);
readPtr = (readPtr + toReadFromBuffer) % buffSize;
len -= toReadFromBuffer;
length -= toReadFromBuffer;
ptr += toReadFromBuffer;
bytes += toReadFromBuffer;
toReadFromBuffer -= toReadFromBuffer;
}

if (len) {
// Still need more, try direct read from src
bytes += src->read(ptr, len);
// We're out of buffered data, need to force a complete refill. Thanks, @armSeb
readPtr = 0;
writePtr = 0;
length = 0;
filled = false;
cb.st(STATUS_UNDERFLOW, PSTR("Buffer underflow"));
}

fill();

return bytes;
}

void AudioFileSourceBuffer::fill()
{
if (!buffer) return;

if (length < buffSize) {
// Now try and opportunistically fill the buffer
if (readPtr > writePtr) {
if (readPtr == writePtr+1) return;
uint32_t bytesAvailMid = readPtr - writePtr - 1;
int cnt = src->readNonBlock(&buffer[writePtr], bytesAvailMid);
length += cnt;
writePtr = (writePtr + cnt) % buffSize;
return;
}

if (buffSize > writePtr) {
uint32_t bytesAvailEnd = buffSize - writePtr;
int cnt = src->readNonBlock(&buffer[writePtr], bytesAvailEnd);
length += cnt;
writePtr = (writePtr + cnt) % buffSize;
if (cnt != (int)bytesAvailEnd) return;
}

if (readPtr > 1) {
uint32_t bytesAvailStart = readPtr - 1;
int cnt = src->readNonBlock(&buffer[writePtr], bytesAvailStart);
length += cnt;
writePtr = (writePtr + cnt) % buffSize;
}
}
}



bool AudioFileSourceBuffer::loop()
{
if (!src->loop()) return false;
fill();
return true;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
AudioFileSourceBuffer
Double-buffered input file using system RAM
Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _AUDIOFILESOURCEBUFFER_H
#define _AUDIOFILESOURCEBUFFER_H

#include "AudioFileSource.h"


class AudioFileSourceBuffer : public AudioFileSource
{
public:
AudioFileSourceBuffer(AudioFileSource *in, uint32_t bufferBytes);
AudioFileSourceBuffer(AudioFileSource *in, void *buffer, uint32_t bufferBytes); // Pre-allocated buffer by app
virtual ~AudioFileSourceBuffer() override;

virtual uint32_t read(void *data, uint32_t len) override;
virtual bool seek(int32_t pos, int dir) override;
virtual bool close() override;
virtual bool isOpen() override;
virtual uint32_t getSize() override;
virtual uint32_t getPos() override;
virtual bool loop() override;

virtual uint32_t getFillLevel();

enum { STATUS_FILLING=2, STATUS_UNDERFLOW };

private:
virtual void fill();

private:
AudioFileSource *src;
uint32_t buffSize;
uint8_t *buffer;
bool deallocateBuffer;
uint32_t writePtr;
uint32_t readPtr;
uint32_t length;
bool filled;
};


#endif

Loading

0 comments on commit 4b92733

Please sign in to comment.