Skip to content
Permalink
Browse files

play .RAW at arb rates

  • Loading branch information...
newdigate committed Feb 11, 2019
1 parent aa5f6be commit fe2f8dace558614d8a48cb00fc47aecc0c7a1960
@@ -112,6 +112,7 @@
#include "play_memory.h"
#include "play_queue.h"
#include "play_sd_raw.h"
#include "play_sd_raw_resampled.h"
#include "play_sd_wav.h"
#include "play_serialflash_raw.h"
#include "record_queue.h"
@@ -0,0 +1,47 @@
// Plays a RAW (16-bit signed) PCM audio file at slower or faster rate
// this example requires an uSD-card inserted to teensy 3.6 with a file called DEMO.raw
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlaySdRawResampled playSdRaw1; //xy=324,457
AudioOutputI2S i2s2; //xy=840.8571472167969,445.5714416503906
AudioConnection patchCord1(playSdRaw1, 0, i2s2, 0);
AudioConnection patchCord2(playSdRaw1, 0, i2s2, 1);
// GUItool: end automatically generated code

AudioControlSGTL5000 audioShield;

void setup() {

Serial.begin(57600);

if (!(SD.begin(BUILTIN_SDCARD))) {
// stop here if no SD card, but print a message
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}

AudioMemory(24);

audioShield.enable();
audioShield.volume(0.5);

playSdRaw1.play("DEMO.RAW");
playSdRaw1.setReadRate(1.5);
Serial.println("playing...");
}

void loop() {

if (!playSdRaw1.isPlaying()) {
//Serial.println("playing...");

playSdRaw1.play("demo2.raw");
}
}
@@ -0,0 +1,69 @@
//
// Created by Nicholas Newdigate on 10/02/2019.
//

#include "play_sd_raw_resampled.h"
#include "spi_interrupt.h"

void AudioPlaySdRawResampled::begin()
{
playing = false;
file_offset = 0;
file_size = 0;
}

bool AudioPlaySdRawResampled::play(const char *filename)
{
stop();
playing = sdReader.play(filename);
return playing;
}

void AudioPlaySdRawResampled::stop()
{
sdReader.stop();
}

void AudioPlaySdRawResampled::update()
{
unsigned int i, n;
audio_block_t *block;

// only update if we're playing
if (!playing) return;

// allocate the audio blocks to transmit
block = allocate();
if (block == NULL) return;

if (sdReader.available()) {
// we can read more data from the file...
n = sdReader.read(block->data, AUDIO_BLOCK_SAMPLES*2);
file_offset += n;
for (i=n/2; i < AUDIO_BLOCK_SAMPLES; i++) {
block->data[i] = 0;
}
transmit(block);
} else {
sdReader.close();
#if defined(HAS_KINETIS_SDHC)
if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStopUsingSPI();
#else
AudioStopUsingSPI();
#endif
playing = false;
}
release(block);
}

#define B2M (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT / 2.0) // 97352592

uint32_t AudioPlaySdRawResampled::positionMillis()
{
return ((uint64_t)file_offset * B2M) >> 32;
}

uint32_t AudioPlaySdRawResampled::lengthMillis()
{
return ((uint64_t)file_size * B2M) >> 32;
}
@@ -0,0 +1,43 @@
//
// Created by Nicholas Newdigate on 10/02/2019.
//

#ifndef TEENSYAUDIOLIBRARY_PLAY_SD_RAW_RESAMPLED_H
#define TEENSYAUDIOLIBRARY_PLAY_SD_RAW_RESAMPLED_H
#include "Arduino.h"
#include "AudioStream.h"
#include "SD.h"
#include "stdint.h"
#include "utility/ResamplingSdReader.h"

class AudioPlaySdRawResampled : public AudioStream
{
public:
AudioPlaySdRawResampled(void) :
AudioStream(0, NULL),
sdReader()
{
begin();
}

void begin(void);
bool play(const char *filename);
void stop(void);
bool isPlaying(void) { return playing; }
uint32_t positionMillis(void);
uint32_t lengthMillis(void);
virtual void update(void);

void setReadRate(float f) {
sdReader.setReadRate(f);
}

private:

uint32_t file_size;
volatile uint32_t file_offset;
volatile bool playing;
ResamplingSdReader sdReader;
};

#endif //TEENSYAUDIOLIBRARY_PLAY_SD_RAW_RESAMPLED_H
@@ -0,0 +1,114 @@
//
// Created by Nicholas Newdigate on 10/02/2019.
//

#include "ResamplingSdReader.h"

int ResamplingSdReader::read(void *buf, uint16_t nbyte) {

unsigned int count = 0;
int16_t *index = (int16_t*)buf;
for (int i=0; i< nbyte/2; i++) {
//Serial.printf("i=%d \n", i);
if (readNextValue(index))
count+=2;
else
return count;

index++;
}
return count;
}

bool ResamplingSdReader::readNextValue(int16_t *value) {
if ( _bufferLength == 0 || _bufferPosition >= _bufferLength) {
// fill buffer from file
unsigned int numRead = 0;
if (_file.available() > 0) {
//Serial.printf("read %d bytes\n", AUDIO_BLOCK_SAMPLES * 2);
numRead = _file.read(_buffer, AUDIO_BLOCK_SAMPLES * 2);
if (numRead == 0)
return false;
_file_offset = _file.position();
//Serial.printf("numread %d\n", numRead);
}
else
return false;

_bufferLength = numRead;
_bufferPosition = 0;
}

//Serial.printf("buf %d/%d \n", _bufferPosition, _bufferLength);
uint16_t result = _buffer[_bufferPosition/2];
//Serial.printf("result %4x \n", result);
_remainder += _readRate;

unsigned int delta = static_cast<unsigned int>(_remainder);
_remainder -= static_cast<float>(delta);

_bufferPosition += 2 * delta;
*value = result;
return true;
}

void ResamplingSdReader::begin(void)
{
_playing = false;
_file_offset = 0;
_file_size = 0;
}

bool ResamplingSdReader::play(const char *filename)
{
stop();
#if defined(HAS_KINETIS_SDHC)
if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStartUsingSPI();
#else
AudioStartUsingSPI();
#endif
__disable_irq();
_file = SD.open(filename);
__enable_irq();
if (!_file) {
//Serial.println("unable to open file");
#if defined(HAS_KINETIS_SDHC)
if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStopUsingSPI();
#else
AudioStopUsingSPI();
#endif
return false;
}
_file_size = _file.size();
_file_offset = 0;
//Serial.println("able to open file");
_playing = true;
return true;
}

void ResamplingSdReader::stop(void)
{
__disable_irq();
if (_playing) {
_playing = false;
__enable_irq();
_file.close();
#if defined(HAS_KINETIS_SDHC)
if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStopUsingSPI();
#else
AudioStopUsingSPI();
#endif
} else {
__enable_irq();
}
}

int ResamplingSdReader::available(void) {
return _file.available() / _readRate;
}

void ResamplingSdReader::close(void) {
if (_playing)
stop();
_file.close();
}
@@ -0,0 +1,49 @@
//
// Created by Nicholas Newdigate on 10/02/2019.
//

#ifndef TEENSYAUDIOLIBRARY_RESAMPLINGSDREADER_H
#define TEENSYAUDIOLIBRARY_RESAMPLINGSDREADER_H

#include "stdint.h"
#include <SD.h>
#include <AudioStream.h>

#include "../spi_interrupt.h"

class ResamplingSdReader {
public:
ResamplingSdReader() {

}
void begin(void);
bool play(const char *filename);
void stop(void);
bool isPlaying(void) { return _playing; }

int read(void *buf, uint16_t nbyte);
bool readNextValue(int16_t *value);

void setReadRate(float f) {
_readRate = f;
}
int available(void);
void close(void);

private:
volatile bool _playing;
volatile uint32_t _file_offset;

uint32_t _file_size;
float _readRate = 0.5;
float _remainder = 0;

unsigned int _bufferPosition = 0;
unsigned int _bufferLength = 0;
int16_t _buffer[AUDIO_BLOCK_SAMPLES];

File _file;
};


#endif //PAULSTOFFREGEN_RESAMPLINGSDREADER_H

0 comments on commit fe2f8da

Please sign in to comment.
You can’t perform that action at this time.