A library which allows the playing of Wav files using the TLV320
Dependents: RSALB_hbridge_helloworld RSALB_lobster WavPlayer_test AudioCODEC_HelloWorld
WavPlayer.cpp
- Committer:
- p07gbar
- Date:
- 2012-09-21
- Revision:
- 3:a7380cfc1987
- Parent:
- 2:d54e6966fa2b
File content as of revision 3:a7380cfc1987:
// TODO: Add licence and stop start remembering and fill buffer functions
#include "WavPlayer.h"
#define DEBUG 0
#define debug_printf(args ...) if (DEBUG) printf(args)
#define WAVPLAYER_PLAYER_BUF 1000
#define WAVPLAYER_OUTPUT_RATE 48000
#define WAVPLAYER_READ_MARGIN 0.9
#define WAVLPAYER_SLOW_MARGIN 5
#define WAVPLAYER_GEN_TEST 0
#define WAVPLAYER_GEN_FREQ 440
#if WAVPLAYER_GEN_TEST == 1
#include "sinelookup.h"
#else
#define SINE16LENGTH 2
#define SINE32LENGTH 2
const int16_t sine16lookup[] = {0,10000};
#endif
WavPlayer* WavPlayer::instance;
//void WavPlayer::i2sisr();
WavPlayer::WavPlayer() :
flag_play(true), i2s(I2S_TRANSMIT, p5, p6, p7), codec(p9, p10)//, ext_flag(p22), //run_flag(p23)
{
instance = this;
codec.power(true); //power up TLV apart from analogue input
codec.stop();
codec.frequency(WAVPLAYER_OUTPUT_RATE); //set sample frequency
codec.wordsize(16); //set transfer protocol
codec.master(false);
codec.headphone_volume(0.6);
//interrupt come from the I2STXFIFO only
i2s.masterslave(I2S_MASTER);
i2s.attach(&WavPlayer::i2sisr);
i2s.wordsize(16);
i2s.stereomono(I2S_MONO);
i2s.frequency(WAVPLAYER_OUTPUT_RATE);
//ext_flag = false;
flag_vol = false;
volume = 1;
}
WavPlayer::WavPlayer(FILE **fpp):flag_play(true), i2s(I2S_TRANSMIT, p5, p6, p7), codec(p9, p10)//, ext_flag(p22), //run_flag(p23)
{
instance = this;
codec.power(true); //power up TLV apart from analogue input
codec.stop();
codec.frequency(WAVPLAYER_OUTPUT_RATE); //set sample frequency
codec.wordsize(16); //set transfer protocol
codec.master(false);
codec.headphone_volume(0.6);
//interrupt come from the I2STXFIFO only
i2s.masterslave(I2S_MASTER);
i2s.attach(&WavPlayer::i2sisr);
i2s.wordsize(16);
i2s.stereomono(I2S_MONO);
i2s.frequency(WAVPLAYER_OUTPUT_RATE);
//ext_flag = false;
flag_vol = false;
volume = 1;
open(fpp);
}
void WavPlayer::i2sisr()
{
instance->i2sisr_();
}
void WavPlayer::i2sisr_()
{
int to_write = i2s.max_fifo_points() - i2s.fifo_points();
int temp[32];
/*for(int i = 0; i < 32; i++)
{
temp[i] = 0;
}*/
int destore[2];
if (rbuf.numberStored() > to_write + 8 && flag_play)
{
for (int i = 0; i < to_write; i += 2)
{
rbuf.readFirst(destore);
rbuf.usedFirst();
temp[i] = destore[0];
temp[i+1] = destore[1];
}
i2s.write(temp, to_write);
}
else
{
for (int i = 0; i < to_write; i++)
{
temp[i] = 0;
}
i2s.write(temp, to_write);
isr_underrun++;
}
}
void WavPlayer::open(FILE **fpp)
{
filepp = fpp;
if (*filepp == NULL)
printf(
"Please open a file before passing the file pointer pointer...\n\r");
char temp[4];
fgets_m(temp, 4, *filepp);
debug_printf("%s\n\r", temp);
if (strcmp(temp, "RIFF") != 0)
printf("This is not a RIFF file\n\r");
fseekread(*filepp, temp, 8, 4);
if (strcmp(temp, "WAVE") != 0)
printf("This is not a WAVE file\n\r");
current_time = 0;
getConfig();
}
int WavPlayer::getConfig()
{
char temp[4];
clear(temp, 4);
fseekread(*filepp, temp, 4, 4);
config.file_size = getu32(temp, 4);
debug_printf("FileSize = %i\n\r", config.file_size);
int chunkstart = findChunk(*filepp, "fmt ", 4, config.file_size, 12);
if (chunkstart != -1)
{
config.format_tag = fsru16(*filepp, chunkstart + 8);
debug_printf("Format_tag: %i\n\r", config.format_tag);
config.channels = fsru16(*filepp, chunkstart + 10);
debug_printf("nChannels: %i\n\r", config.channels);
config.samples_per_sec = fsru32(*filepp, chunkstart + 12);
debug_printf("nSamplesPerSec: %i\n\r", config.samples_per_sec);
config.avg_bytes_per_sec = fsru32(*filepp, chunkstart + 16);
debug_printf("avg_bytes_per_sec: %i\n\r", config.avg_bytes_per_sec);
config.block_align = fsru16(*filepp, chunkstart + 20);
debug_printf("block_align: %i\n\r", config.block_align);
config.bits_per_sample = fsru16(*filepp, chunkstart + 22);
debug_printf(
"bits per sample: %i\n\r", config.bits_per_sample);
}
chunkstart = findChunk(*filepp, "data", 4, config.file_size, 12);
if (chunkstart != -1)
{
config.data_length = fsru32(*filepp, chunkstart + 4);
debug_printf("Data Length: %i\n\r", config.data_length);
}
return 0;
}
float WavPlayer::play()
{
return play(float(config.data_length) / float(config.samples_per_sec));
}
float WavPlayer::play(float time)
{
return play(current_time, time);
}
float WavPlayer::play(float start, float timefor)
{
#if WAVPLAYER_GEN_TEST == 1
config.channels = 1;
config.samples_per_sec = 48000;
#endif
float timeElapsed = 0;
int endPoint = int((start + timefor) * float(config.samples_per_sec));
if (endPoint * config.block_align >= config.data_length)
endPoint = config.data_length / config.block_align;
//printf("Will end after: %i samples \n\r", endPoint);
int point = int(start * float(config.samples_per_sec));
bool valid = true;
flag_play = false;
int dataOffset = findChunk(*filepp, "data", 4, config.file_size, 12) + 8 + (point * config.block_align);
double timeComp = 0;
double out_rate_t_p = 1 / double(WAVPLAYER_OUTPUT_RATE);
//printf("out_rate_t_p = %f\n\r", out_rate_t_p);
double out_rate_t_n = -1 / double(WAVPLAYER_OUTPUT_RATE);
double in_rate = 1 / double(config.samples_per_sec); //0.0000125
//printf("in_rate = %f\n\r", in_rate);
float phase = 0;
if (dataOffset != -1)
{
fseek(*filepp, dataOffset, SEEK_SET);
int16_t buffer[WAVPLAYER_PLAYER_BUF];
codec.start();
//debug_printf("Expecting isr\n\r");
i2s.frequency(WAVPLAYER_OUTPUT_RATE);
if (config.channels == 1)
{
stereo = false;
i2s.stereomono(I2S_MONO);
}
else
{
stereo =true;
i2s.stereomono(I2S_STEREO);
}
i2s.attach(&WavPlayer::i2sisr);
i2s.start();
flag_play = true;
while (valid && point < endPoint)
{
if (rbuf.numberStored() < RBLENGTH - 10)
{
//timer.reset();
//timer.start();
int numToread = WAVPLAYER_PLAYER_BUF;
if (numToread > (RBLENGTH - 10) - rbuf.numberStored())
{
numToread = (RBLENGTH - 10) - rbuf.numberStored();
}
if (numToread + (point * (config.block_align/config.channels)) > config.data_length)
{
numToread = config.data_length - point * config.block_align;
valid = false;
debug_printf("EOF detected\n\r");
}
if(numToread % 2 == 1) numToread--;
//printf("Generating\n\r");
//run_flag = true;
//phase = sine_gen(buffer,numToread,float(config.samples_per_sec)/120,phase);
timer.reset();
timer.start();
//fread(buffer, config.block_align/config.channels, numToread, *filepp);
#if WAVPLAYER_GEN_TEST == 1
phase = sine_gen(buffer,numToread,float(config.samples_per_sec)/WAVPLAYER_GEN_FREQ,phase);
#else
fread(buffer, config.block_align/config.channels, numToread, *filepp);
#endif
timer.stop();
//printf("numToread:%f\n\r",float(numToread));
if(numToread>=10)
{
read_time += (timer.read()/float(numToread));
read_time_div += 1;
}
if(read_time/float(read_time_div) >= WAVPLAYER_READ_MARGIN / float(config.samples_per_sec*config.channels))
{
slow_count++;
if(slow_count > WAVLPAYER_SLOW_MARGIN)
{
printf("Data rates not high enough to sustain read...%f seconds per read\n\r", read_time/float(read_time_div));
valid = false;
break;
}
}
//run_flag = false;
int storer[2];
for (int i = 0; i < numToread; i += 2)
{
//run_flag = true;
if (timeComp < out_rate_t_p && timeComp > out_rate_t_n)
{
storer[0] = (int) buffer[i];
storer[1] = (int) buffer[i + 1];
//storer[0] = blip;
//storer[1] = blip;
timeComp += in_rate;
while (rbuf.numberStored() > RBLENGTH - 10)
{
//run_flag = true;
//run_flag = false;
}
rbuf.addToBuffer(storer);
timeComp -= out_rate_t_p;
//printf(",",timeComp);
point++;
//printf("straight %f\n\r",timeComp);
}
else if (timeComp >= out_rate_t_p)
{
storer[0] = (int) buffer[i];
storer[1] = (int) buffer[i + 1];
//storer[0] = blip;
//storer[1] = blip;
timeComp += in_rate;
/*const float ct = 5;
float c = 0;
float bufi = float(buffer[i]);
float bufip = float((i+1 >= numToread) ? buffer[i+1] : bufi);*/
while (timeComp >= out_rate_t_p)
{
//storer[0] = int((((ct-c)/ct)*bufi)+((c/ct)*bufip));
while (rbuf.numberStored() > RBLENGTH - 10)
{
//run_flag = true;
//run_flag = false;
}
rbuf.addToBuffer(storer);
timeComp -= out_rate_t_p;
//printf(";");
//if(c < ct) c++;
}
point++;
}
else if (timeComp <= out_rate_t_n)
{
timeComp += in_rate;
//printf("-");
}
//storer[1] = 0;
//if(i%1 == 0) printf("%i\n",int(storer[0]),int(storer[1]));
//run_flag = false;
}
flag_play = true;
//timer.stop();
//printf("point: %i\n\r",isr_underrun);
//read_time += timer;
//read_time_div =numToread;
}
}
}
flag_play = false;
current_time = float(point)/float(config.samples_per_sec);
return current_time;
}
int WavPlayer::fseekread(FILE *fp, char* str, int offset, int len)
{
fseek(fp, offset, SEEK_SET);
fgets_m(str, len, fp);
return len;
}
uint32_t WavPlayer::getu32(char str[], int len)
{
uint32_t temp = 0;
for (int i = 0; i < len; i++)
{
temp += str[i] << (i * 8);
}
return temp;
}
uint16_t WavPlayer::getu16(char str[], int len)
{
uint16_t temp = 0;
for (int i = 0; i < len; i++)
{
temp += str[i] << (i * 8);
}
return temp;
}
int32_t WavPlayer::get32(char str[], int len)
{
uint32_t temp = 0;
for (int i = 0; i < len; i++)
{
temp += str[i] << (i * 8);
}
return temp;
}
int16_t WavPlayer::get16(char str[], int len)
{
uint16_t temp = 0;
for (int i = 0; i < len; i++)
{
temp += str[i] << (i * 8);
}
return temp;
}
uint32_t WavPlayer::fsru32(FILE *fp, int offset, int len)
{
char temp[4];
fseekread(fp, temp, offset, len);
return getu32(temp, len);
}
uint16_t WavPlayer::fsru16(FILE *fp, int offset, int len)
{
char temp[2];
fseekread(fp, temp, offset, len);
return getu16(temp, len);
}
void WavPlayer::clear(char* str, int len)
{
for (int i = 0; i < len; i++)
{
str[i] = 0;
}
}
int WavPlayer::findChunk(FILE *fp, char* match, int len, int fileSize,
int startOffset)
{
char temp[5];
int count = startOffset;
while ((count + 8) < fileSize)
{
clear(temp, 5);
fseekread(fp, temp, count, 4);
int chunksize = fsru32(fp, count + 4) + 8;
//debug_printf("@ %i Chunk Name: %s Size: %i\n\r", count, temp, chunksize);
if (strcmp(temp, match) == 0)
{
return count;
}
count += chunksize;
}
return -1;
}
int WavPlayer::findChunk(FILE *fp, char* match, int len, int startOffset)
{
return findChunk(fp, match, len, config.file_size, startOffset);
}
void WavPlayer::fgets_m(char* str, int num, FILE* fp)
{
for (int i = 0; i < num; i++)
{
str[i] = fgetc(fp);
//printf("%c",str[i]);
}
}
float WavPlayer::sine_gen(int16_t* buf, int len, float div, float phase)
{
#if WAVPLAYER_GEN_TEST == 1
float t = SINE16LENGTH / div;
for (int i = 0; i < len; i++)
{
buf[i] = sine16lookup[int(phase)];
//printf("%i\n\r",buf[i]);
phase += t;
while (phase >= SINE16LENGTH)
phase -= SINE16LENGTH;
}
#endif
return phase;
}