|
-
-
- #include <Arduino.h>
- #include "play_sd_wav.h"
- #include "spi_interrupt.h"
-
-
- #define STATE_DIRECT_8BIT_MONO 0
- #define STATE_DIRECT_8BIT_STEREO 1
- #define STATE_DIRECT_16BIT_MONO 2
- #define STATE_DIRECT_16BIT_STEREO 3
- #define STATE_CONVERT_8BIT_MONO 4
- #define STATE_CONVERT_8BIT_STEREO 5
- #define STATE_CONVERT_16BIT_MONO 6
- #define STATE_CONVERT_16BIT_STEREO 7
- #define STATE_PARSE1 8
- #define STATE_PARSE2 9
- #define STATE_PARSE3 10
- #define STATE_PARSE4 11
- #define STATE_PARSE5 12
- #define STATE_STOP 13
-
- void AudioPlaySdWav::begin(void)
- {
- state = STATE_STOP;
- state_play = STATE_STOP;
- data_length = 0;
- if (block_left) {
- release(block_left);
- block_left = NULL;
- }
- if (block_right) {
- release(block_right);
- block_right = NULL;
- }
- }
-
-
- bool AudioPlaySdWav::play(const char *filename)
- {
- stop();
- bool irq = false;
- if (NVIC_IS_ENABLED(IRQ_SOFTWARE)) {
- NVIC_DISABLE_IRQ(IRQ_SOFTWARE);
- irq = true;
- }
- #if defined(HAS_KINETIS_SDHC)
- if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStartUsingSPI();
- #else
- AudioStartUsingSPI();
- #endif
- wavfile = SD.open(filename);
- if (!wavfile) {
- #if defined(HAS_KINETIS_SDHC)
- if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStopUsingSPI();
- #else
- AudioStopUsingSPI();
- #endif
- if (irq) NVIC_ENABLE_IRQ(IRQ_SOFTWARE);
- return false;
- }
- buffer_length = 0;
- buffer_offset = 0;
- state_play = STATE_STOP;
- data_length = 20;
- header_offset = 0;
- state = STATE_PARSE1;
- if (irq) NVIC_ENABLE_IRQ(IRQ_SOFTWARE);
- return true;
- }
-
- void AudioPlaySdWav::stop(void)
- {
- bool irq = false;
- if (NVIC_IS_ENABLED(IRQ_SOFTWARE)) {
- NVIC_DISABLE_IRQ(IRQ_SOFTWARE);
- irq = true;
- }
- if (state != STATE_STOP) {
- audio_block_t *b1 = block_left;
- block_left = NULL;
- audio_block_t *b2 = block_right;
- block_right = NULL;
- state = STATE_STOP;
- if (b1) release(b1);
- if (b2) release(b2);
- wavfile.close();
- #if defined(HAS_KINETIS_SDHC)
- if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStopUsingSPI();
- #else
- AudioStopUsingSPI();
- #endif
- }
- if (irq) NVIC_ENABLE_IRQ(IRQ_SOFTWARE);
- }
-
-
- void AudioPlaySdWav::update(void)
- {
- int32_t n;
-
-
- if (state == STATE_STOP) return;
-
-
- block_left = allocate();
- if (block_left == NULL) return;
- if (state < 8 && (state & 1) == 1) {
-
-
- block_right = allocate();
- if (block_right == NULL) {
- release(block_left);
- return;
- }
- } else {
-
-
- block_right = NULL;
- }
- block_offset = 0;
-
-
-
-
- n = buffer_length - buffer_offset;
- if (n > 0) {
-
- if (consume(n)) return;
- }
-
-
- if (state != STATE_STOP && wavfile.available()) {
-
- readagain:
- buffer_length = wavfile.read(buffer, 512);
- if (buffer_length == 0) goto end;
- buffer_offset = 0;
- bool parsing = (state >= 8);
- bool txok = consume(buffer_length);
- if (txok) {
- if (state != STATE_STOP) return;
- } else {
- if (state != STATE_STOP) {
- if (parsing && state < 8) goto readagain;
- else goto cleanup;
- }
- }
- }
- end:
- wavfile.close();
- #if defined(HAS_KINETIS_SDHC)
- if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStopUsingSPI();
- #else
- AudioStopUsingSPI();
- #endif
- state_play = STATE_STOP;
- state = STATE_STOP;
- cleanup:
- if (block_left) {
- if (block_offset > 0) {
- for (uint32_t i=block_offset; i < AUDIO_BLOCK_SAMPLES; i++) {
- block_left->data[i] = 0;
- }
- transmit(block_left, 0);
- if (state < 8 && (state & 1) == 0) {
- transmit(block_left, 1);
- }
- }
- release(block_left);
- block_left = NULL;
- }
- if (block_right) {
- if (block_offset > 0) {
- for (uint32_t i=block_offset; i < AUDIO_BLOCK_SAMPLES; i++) {
- block_right->data[i] = 0;
- }
- transmit(block_right, 1);
- }
- release(block_right);
- block_right = NULL;
- }
- }
-
-
-
-
-
- bool AudioPlaySdWav::consume(uint32_t size)
- {
- uint32_t len;
- uint8_t lsb, msb;
- const uint8_t *p;
-
- p = buffer + buffer_offset;
- start:
- if (size == 0) return false;
- #if 0
- Serial.print("AudioPlaySdWav consume, ");
- Serial.print("size = ");
- Serial.print(size);
- Serial.print(", buffer_offset = ");
- Serial.print(buffer_offset);
- Serial.print(", data_length = ");
- Serial.print(data_length);
- Serial.print(", space = ");
- Serial.print((AUDIO_BLOCK_SAMPLES - block_offset) * 2);
- Serial.print(", state = ");
- Serial.println(state);
- #endif
- switch (state) {
-
- case STATE_PARSE1:
- len = data_length;
- if (size < len) len = size;
- memcpy((uint8_t *)header + header_offset, p, len);
- header_offset += len;
- buffer_offset += len;
- data_length -= len;
- if (data_length > 0) return false;
-
- if (header[0] == 0x46464952 && header[2] == 0x45564157) {
-
- if (header[3] == 0x20746D66) {
-
- if (header[4] < 16) {
-
- break;
- }
- if (header[4] > sizeof(header)) {
-
-
-
- break;
- }
-
- header_offset = 0;
- state = STATE_PARSE2;
- } else {
-
-
-
-
-
- header_offset = 12;
- state = STATE_PARSE5;
- }
- p += len;
- size -= len;
- data_length = header[4];
- goto start;
- }
-
- break;
-
-
- case STATE_PARSE2:
- len = data_length;
- if (size < len) len = size;
- memcpy((uint8_t *)header + header_offset, p, len);
- header_offset += len;
- buffer_offset += len;
- data_length -= len;
- if (data_length > 0) return false;
- if (parse_format()) {
-
- p += len;
- size -= len;
- data_length = 8;
- header_offset = 0;
- state = STATE_PARSE3;
- goto start;
- }
-
- break;
-
-
- case STATE_PARSE3:
- len = data_length;
- if (size < len) len = size;
- memcpy((uint8_t *)header + header_offset, p, len);
- header_offset += len;
- buffer_offset += len;
- data_length -= len;
- if (data_length > 0) return false;
-
-
-
-
- p += len;
- size -= len;
- data_length = header[1];
- if (header[0] == 0x61746164) {
-
-
-
-
-
- leftover_bytes = 0;
- state = state_play;
- if (state & 1) {
-
-
- block_right = allocate();
- if (!block_right) return false;
- }
- total_length = data_length;
- } else {
- state = STATE_PARSE4;
- }
- goto start;
-
-
- case STATE_PARSE4:
- if (size < data_length) {
- data_length -= size;
- buffer_offset += size;
- return false;
- }
- p += data_length;
- size -= data_length;
- buffer_offset += data_length;
- data_length = 8;
- header_offset = 0;
- state = STATE_PARSE3;
-
- goto start;
-
-
- case STATE_PARSE5:
- len = data_length;
- if (size < len) len = size;
- buffer_offset += len;
- data_length -= len;
- if (data_length > 0) return false;
- p += len;
- size -= len;
- data_length = 8;
- state = STATE_PARSE1;
- goto start;
-
-
- case STATE_DIRECT_8BIT_MONO:
- return false;
-
-
- case STATE_DIRECT_8BIT_STEREO:
- return false;
-
-
- case STATE_DIRECT_16BIT_MONO:
- if (size > data_length) size = data_length;
- data_length -= size;
- while (1) {
- lsb = *p++;
- msb = *p++;
- size -= 2;
- block_left->data[block_offset++] = (msb << 8) | lsb;
- if (block_offset >= AUDIO_BLOCK_SAMPLES) {
- transmit(block_left, 0);
- transmit(block_left, 1);
- release(block_left);
- block_left = NULL;
- data_length += size;
- buffer_offset = p - buffer;
- if (block_right) release(block_right);
- if (data_length == 0) state = STATE_STOP;
- return true;
- }
- if (size == 0) {
- if (data_length == 0) break;
- return false;
- }
- }
-
-
- if (block_offset > 0) {
-
- }
- state = STATE_STOP;
- return false;
-
-
- case STATE_DIRECT_16BIT_STEREO:
- if (size > data_length) size = data_length;
- data_length -= size;
- if (leftover_bytes) {
- block_left->data[block_offset] = header[0];
-
- leftover_bytes = 0;
- goto right16;
- }
- while (1) {
- lsb = *p++;
- msb = *p++;
- size -= 2;
- if (size == 0) {
- if (data_length == 0) break;
- header[0] = (msb << 8) | lsb;
- leftover_bytes = 2;
- return false;
- }
- block_left->data[block_offset] = (msb << 8) | lsb;
- right16:
- lsb = *p++;
- msb = *p++;
- size -= 2;
- block_right->data[block_offset++] = (msb << 8) | lsb;
- if (block_offset >= AUDIO_BLOCK_SAMPLES) {
- transmit(block_left, 0);
- release(block_left);
- block_left = NULL;
- transmit(block_right, 1);
- release(block_right);
- block_right = NULL;
- data_length += size;
- buffer_offset = p - buffer;
- if (data_length == 0) state = STATE_STOP;
- return true;
- }
- if (size == 0) {
- if (data_length == 0) break;
- leftover_bytes = 0;
- return false;
- }
- }
-
- if (block_offset > 0) {
-
- }
- state = STATE_STOP;
- return false;
-
-
- case STATE_CONVERT_8BIT_MONO :
- return false;
-
-
- case STATE_CONVERT_8BIT_STEREO:
- return false;
-
-
- case STATE_CONVERT_16BIT_MONO:
- return false;
-
-
- case STATE_CONVERT_16BIT_STEREO:
- return false;
-
-
-
- case STATE_STOP:
- return false;
-
-
-
-
- }
- state_play = STATE_STOP;
- state = STATE_STOP;
- return false;
- }
-
-
-
-
-
-
-
-
-
-
-
-
- #define B2M_44100 (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT)
- #define B2M_22050 (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT * 2.0)
- #define B2M_11025 (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT * 4.0)
-
- bool AudioPlaySdWav::parse_format(void)
- {
- uint8_t num = 0;
- uint16_t format;
- uint16_t channels;
- uint32_t rate, b2m;
- uint16_t bits;
-
- format = header[0];
-
-
- if (format != 1) return false;
-
- rate = header[1];
-
-
- if (rate == 44100) {
- b2m = B2M_44100;
- } else if (rate == 22050) {
- b2m = B2M_22050;
- num |= 4;
- } else if (rate == 11025) {
- b2m = B2M_11025;
- num |= 4;
- } else {
- return false;
- }
-
- channels = header[0] >> 16;
-
-
- if (channels == 1) {
- } else if (channels == 2) {
- b2m >>= 1;
- num |= 1;
- } else {
- return false;
- }
-
- bits = header[3] >> 16;
-
-
- if (bits == 8) {
- } else if (bits == 16) {
- b2m >>= 1;
- num |= 2;
- } else {
- return false;
- }
-
- bytes2millis = b2m;
-
-
-
-
-
-
-
- state_play = num;
- return true;
- }
-
-
- bool AudioPlaySdWav::isPlaying(void)
- {
- uint8_t s = *(volatile uint8_t *)&state;
- return (s < 8);
- }
-
- uint32_t AudioPlaySdWav::positionMillis(void)
- {
- uint8_t s = *(volatile uint8_t *)&state;
- if (s >= 8) return 0;
- uint32_t tlength = *(volatile uint32_t *)&total_length;
- uint32_t dlength = *(volatile uint32_t *)&data_length;
- uint32_t offset = tlength - dlength;
- uint32_t b2m = *(volatile uint32_t *)&bytes2millis;
- return ((uint64_t)offset * b2m) >> 32;
- }
-
-
- uint32_t AudioPlaySdWav::lengthMillis(void)
- {
- uint8_t s = *(volatile uint8_t *)&state;
- if (s >= 8) return 0;
- uint32_t tlength = *(volatile uint32_t *)&total_length;
- uint32_t b2m = *(volatile uint32_t *)&bytes2millis;
- return ((uint64_t)tlength * b2m) >> 32;
- }
-
-
-
-
-
|