Moved reading of SD card data into a dedicated class DataSource.

This commit is contained in:
Fabian Schlenz 2019-11-20 05:04:27 +01:00
parent 82d8f07eea
commit 94489618ca
4 changed files with 80 additions and 34 deletions

34
include/data_sources.h Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <Arduino.h>
#include <SD.h>
#include "config.h"
class DataSource {
private:
public:
DataSource() {};
~DataSource() {};
virtual size_t read(uint8_t* buf, size_t len) = 0;
virtual uint8_t read() = 0;
virtual size_t position() = 0;
virtual void seek(size_t position) = 0;
virtual size_t size() = 0;
virtual void close() = 0;
virtual void skip_id3_tag();
};
class SDDataSource : public DataSource {
private:
File _file;
public:
SDDataSource(String file);
~SDDataSource();
size_t read(uint8_t* buf, size_t len);
uint8_t read();
size_t position();
void seek(size_t position);
size_t size();
void close();
void skip_id3_tag();
};

View File

@ -4,6 +4,7 @@
#include <SD.h>
#include "spi_master.h"
#include "playlist.h"
#include "data_sources.h"
class Player;
@ -55,7 +56,6 @@ private:
void _flush_and_cancel();
int8_t _get_endbyte();
void _flush(uint count, int8_t fill_byte);
uint32_t _id3_tag_offset(File f);
void _play_file(String filename, uint32_t offset);
void _finish_playing();
void _finish_stopping(bool turn_speaker_off);
@ -72,7 +72,7 @@ private:
SPISettings _spi_settings_fast = SPISettings(4000000, MSBFIRST, SPI_MODE0);
SPISettings* _spi_settings = &_spi_settings_slow;
File _file;
DataSource* _file;
uint32_t _file_size = 0;
uint8_t _buffer[32];
uint32_t _current_play_position = 0;

35
src/data_sources.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "data_sources.h"
////////////// SDDataSource //////////////
SDDataSource::SDDataSource(String file) { _file = SD.open(file, "r"); }
SDDataSource::~SDDataSource() { if (_file) _file.close(); }
size_t SDDataSource::read(uint8_t* buf, size_t len) { return _file.read(buf, len); }
uint8_t SDDataSource::read() { return _file.read(); }
size_t SDDataSource::position() { return _file.position(); }
void SDDataSource::seek(size_t position) { _file.seek(position); }
size_t SDDataSource::size() { return _file.size(); }
void SDDataSource::close() { _file.close(); }
void SDDataSource::skip_id3_tag() {
uint32_t original_position = _file.position();
uint32_t offset = 0;
if (_file.read()=='I' && _file.read()=='D' && _file.read()=='3') {
DEBUG("ID3 tag found\n");
// Skip ID3 tag version
_file.read(); _file.read();
byte tags = _file.read();
bool footer_present = tags & 0x10;
DEBUG("ID3 footer found: %d\n", footer_present);
for (byte i=0; i<4; i++) {
offset <<= 7;
offset |= (0x7F & _file.read());
}
offset += 10;
if (footer_present) offset += 10;
DEBUG("ID3 tag length is %d bytes.\n", offset);
_file.seek(offset);
} else {
DEBUG("No ID3 tag found\n");
_file.seek(original_position);
}
}

View File

@ -545,8 +545,8 @@ bool Player::play() {
void Player::_play_file(String file, uint32_t file_offset) {
INFO("play_file('%s', %d)\n", file.c_str(), file_offset);
_spi->select_sd();
_file = SD.open(file);
_file_size = _file.size();
_file = new SDDataSource(file);
_file_size = _file->size();
_spi->select_sd(false);
if (!_file) {
DEBUG("Could not open file %s", file.c_str());
@ -561,10 +561,10 @@ void Player::_play_file(String file, uint32_t file_offset) {
_spi->select_sd();
if (file_offset == 0) {
_file.seek(_id3_tag_offset(_file));
_file->skip_id3_tag();
}
_refills = 0;
_current_play_position = _file.position();
_current_play_position = _file->position();
_spi->select_sd(false);
_skip_to = file_offset;
if (_skip_to>0) _mute();
@ -573,30 +573,6 @@ void Player::_play_file(String file, uint32_t file_offset) {
_controller->send_player_status();
}
uint32_t Player::_id3_tag_offset(File f) {
uint32_t original_position = f.position();
uint32_t offset = 0;
if (f.read()=='I' && f.read()=='D' && f.read()=='3') {
DEBUG("ID3 tag found\n");
// Skip ID3 tag version
f.read(); f.read();
byte tags = f.read();
bool footer_present = tags & 0x10;
DEBUG("ID3 footer found: %d\n", footer_present);
for (byte i=0; i<4; i++) {
offset <<= 7;
offset |= (0x7F & f.read());
}
offset += 10;
if (footer_present) offset += 10;
DEBUG("ID3 tag length is %d bytes.\n", offset);
} else {
DEBUG("No ID3 tag found\n");
}
f.seek(original_position);
return offset;
}
void Player::_flush(uint count, int8_t byte) {
_spi->select_vs1053_xdcs();
SPI.beginTransaction(*_spi_settings);
@ -652,7 +628,8 @@ void Player::_finish_stopping(bool turn_speaker_off) {
_state = idle;
_stopped_at = millis();
if (_file) {
_file.close();
_file->close();
delete _file;
}
_current_play_position = 0;
_file_size = 0;
@ -664,7 +641,7 @@ void Player::_refill() {
_spi->select_sd();
_refills++;
if (_refills % 1000 == 0) DEBUG(".");
uint8_t result = _file.read(_buffer, sizeof(_buffer));
uint8_t result = _file->read(_buffer, sizeof(_buffer));
_spi->select_sd(false);
if (result == 0) {
// File is over.
@ -686,13 +663,13 @@ void Player::_refill() {
_write_data(_buffer);
if (_skip_to > 0) {
if (_skip_to > _file.position()) {
if (_skip_to > _file->position()) {
uint16_t status = _read_control_register(SCI_STATUS);
if ((status & SS_DO_NOT_JUMP) == 0) {
DEBUG("Skipping to %d.\n", _skip_to);
_flush(2048, _get_endbyte());
_spi->select_sd();
_file.seek(_skip_to);
_file->seek(_skip_to);
_spi->select_sd(false);
_skip_to = 0;
_unmute();