/* AudioFileSourceSPIRAMBuffer Buffered file source in external SPI RAM Copyright (C) 2017 Sebastien Decourriere Based on AudioFileSourceBuffer class from Earle F. Philhower, III Copyright (C) 2020 Earle F. Philhower, III Rewritten for speed and functionality 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 . */ #include #include "AudioFileSourceSPIRAMBuffer.h" #pragma GCC optimize ("O3") AudioFileSourceSPIRAMBuffer::AudioFileSourceSPIRAMBuffer(AudioFileSource *source, uint8_t csPin, uint32_t buffSizeBytes) { ram.begin(40, csPin); ramSize = buffSizeBytes; writePtr = 0; readPtr = 0; filled = false; src = source; audioLogger->printf_P(PSTR("SPI RAM buffer size: %u Bytes\n"), ramSize); } AudioFileSourceSPIRAMBuffer::~AudioFileSourceSPIRAMBuffer() { ram.end(); } bool AudioFileSourceSPIRAMBuffer::seek(int32_t pos, int dir) { // Invalidate readPtr = 0; writePtr = 0; filled = false; return src->seek(pos, dir); } bool AudioFileSourceSPIRAMBuffer::close() { return src->close(); } bool AudioFileSourceSPIRAMBuffer::isOpen() { return src->isOpen(); } uint32_t AudioFileSourceSPIRAMBuffer::getSize() { return src->getSize(); } uint32_t AudioFileSourceSPIRAMBuffer::getPos() { return src->getPos() - (writePtr - readPtr); } uint32_t AudioFileSourceSPIRAMBuffer::read(void *data, uint32_t len) { uint32_t bytes = 0; // Check if the buffer isn't empty, otherwise we try to fill completely if (!filled) { cb.st(999, PSTR("Filling buffer...")); uint8_t buffer[256]; writePtr = 0; readPtr = 0; // Fill up completely before returning any data at all do { int toRead = std::min(ramSize - (writePtr - readPtr), sizeof(buffer)); int length = src->read(buffer, toRead); if (length > 0) { #ifdef FAKERAM for (size_t i=0; i(data); if (toReadFromBuffer > 0) { #ifdef FAKERAM for (size_t i=0; i0 there is no data left in buffer and we try to read more directly from source. // Then, we trigger a complete buffer refill if (len) { bytes += src->read(data, len); filled = false; } return bytes; } void AudioFileSourceSPIRAMBuffer::fill() { // Make sure the buffer is pre-filled before make partial fill. if (!filled) return; for (auto i=0; i<5; i++) { // Make sure there is at least buffer size free in RAM uint8_t buffer[128]; if ((ramSize - (writePtr - readPtr)) < sizeof(buffer)) { return; } int cnt = src->readNonBlock(buffer, sizeof(buffer)); if (cnt) { #ifdef FAKERAM for (size_t i=0; iloop()) return false; fill(); if ((ESP.getCycleCount() - last) > microsecondsToClockCycles(1000000)) { last = ESP.getCycleCount(); char str[65]; memset(str, '#', 64); str[64] = 0; str[((writePtr - readPtr) * 64)/ramSize] = 0; cb.st(((writePtr - readPtr) * 100)/ramSize, str); } return true; }