|
|
|
//
|
|
|
|
// Created by Nicholas Newdigate on 10/02/2019.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef TEENSYAUDIOLIBRARY_RESAMPLINGSDREADER_H
|
|
|
|
#define TEENSYAUDIOLIBRARY_RESAMPLINGSDREADER_H
|
|
|
|
|
|
|
|
#include "SD.h"
|
|
|
|
#include <cstdint>
|
|
|
|
#include "spi_interrupt.h"
|
|
|
|
#include "loop_type.h"
|
|
|
|
#include "interpolation.h"
|
|
|
|
#include "IndexableFile.h"
|
|
|
|
|
|
|
|
#define RESAMPLE_BUFFER_SAMPLE_SIZE 128
|
|
|
|
|
|
|
|
#define B2M (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT / 2.0) // 97352592
|
|
|
|
|
|
|
|
class ResamplingSdReader {
|
|
|
|
public:
|
|
|
|
ResamplingSdReader() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void begin(void);
|
|
|
|
bool playRaw(const char *filename, uint16_t numChannels);
|
|
|
|
bool playWav(const char *filename);
|
|
|
|
|
|
|
|
bool play();
|
|
|
|
void stop(void);
|
|
|
|
bool isPlaying(void) { return _playing; }
|
|
|
|
|
|
|
|
unsigned int read(void **buf, uint16_t nbyte);
|
|
|
|
bool readNextValue(int16_t *value, uint16_t channelNumber);
|
|
|
|
|
|
|
|
void setPlaybackRate(double f) {
|
|
|
|
_playbackRate = f;
|
|
|
|
if (f < 0.0 && _bufferPosition == 0) {
|
|
|
|
//_file.seek(_file_size);
|
|
|
|
_bufferPosition = _file_size / 2 - _numChannels;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double playbackRate() {
|
|
|
|
return _playbackRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setLoopType(loop_type loopType)
|
|
|
|
{
|
|
|
|
_loopType = loopType;
|
|
|
|
}
|
|
|
|
|
|
|
|
loop_type getLoopType(){
|
|
|
|
return _loopType;
|
|
|
|
}
|
|
|
|
|
|
|
|
int available(void);
|
|
|
|
void reset(void);
|
|
|
|
void close(void);
|
|
|
|
|
|
|
|
void setLoopStart(uint32_t loop_start) {
|
|
|
|
_loop_start = _header_offset + (loop_start * _numChannels);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setLoopFinish(uint32_t loop_finish) {
|
|
|
|
// sample number, (NOT byte number)
|
|
|
|
_loop_finish = _header_offset + (loop_finish * _numChannels);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setInterpolationType(ResampleInterpolationType interpolationType) {
|
|
|
|
if (interpolationType != _interpolationType) {
|
|
|
|
_interpolationType = interpolationType;
|
|
|
|
initializeInterpolationPoints();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t getNumChannels() {
|
|
|
|
return _numChannels;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setNumChannels(uint16_t numChannels) {
|
|
|
|
if (numChannels != _numChannels) {
|
|
|
|
_numChannels = numChannels;
|
|
|
|
initializeInterpolationPoints();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setHeaderSize(uint32_t headerSizeInBytes) {
|
|
|
|
_header_offset = headerSizeInBytes / 2;
|
|
|
|
if (_bufferPosition < _header_offset) {
|
|
|
|
if (_playbackRate >= 0) {
|
|
|
|
_bufferPosition = _header_offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t positionMillis(void) {
|
|
|
|
if (_file_size == 0) return 0;
|
|
|
|
|
|
|
|
return (uint32_t) (( (double)_bufferPosition * lengthMillis() ) / (double)(_file_size/2));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t lengthMillis(void) {
|
|
|
|
return ((uint64_t)_file_size * B2M) >> 32;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
volatile bool _playing = false;
|
|
|
|
|
|
|
|
int32_t _file_size;
|
|
|
|
int32_t _header_offset = 0; // == (header size in bytes ) / 2
|
|
|
|
|
|
|
|
double _playbackRate = 1.0;
|
|
|
|
double _remainder = 0.0;
|
|
|
|
loop_type _loopType = looptype_none;
|
|
|
|
int _bufferPosition = 0;
|
|
|
|
int32_t _loop_start = 0;
|
|
|
|
int32_t _loop_finish = 0;
|
|
|
|
int16_t _numChannels = -1;
|
|
|
|
uint16_t _numInterpolationPointsChannels = 0;
|
|
|
|
char *_filename = nullptr;
|
|
|
|
newdigate::IndexableFile<128, 2> *_sourceBuffer = nullptr;
|
|
|
|
|
|
|
|
ResampleInterpolationType _interpolationType = ResampleInterpolationType::resampleinterpolation_none;
|
|
|
|
unsigned int _numInterpolationPoints = 0;
|
|
|
|
InterpolationData **_interpolationPoints = nullptr;
|
|
|
|
|
|
|
|
static bool isUsingSPI;
|
|
|
|
void StartUsingSPI(){
|
|
|
|
if (!isUsingSPI) {
|
|
|
|
isUsingSPI = true;
|
|
|
|
#if defined(HAS_KINETIS_SDHC)
|
|
|
|
if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStartUsingSPI();
|
|
|
|
#else
|
|
|
|
AudioStartUsingSPI();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void StopUsingSPI() {
|
|
|
|
if (isUsingSPI) {
|
|
|
|
isUsingSPI = false;
|
|
|
|
#if defined(HAS_KINETIS_SDHC)
|
|
|
|
if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStopUsingSPI();
|
|
|
|
#else
|
|
|
|
AudioStopUsingSPI();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool play(const char *filename, bool isWave, uint16_t numChannelsIfRaw = 0);
|
|
|
|
void initializeInterpolationPoints(void);
|
|
|
|
void deleteInterpolationPoints(void);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif //TEENSYAUDIOLIBRARY_RESAMPLINGSDREADER_H
|