Audio with a Teensy 3.2 & Prop LC

I am working with a Teensy 3.2 and a Prop shield (LC, no motion sensors).

I am hoping to use the on board memory on the Prop Shield as well as the DAC to eventually get code similar to:

if (Pin X = HIGH) {
   // Play File X.wav from Prop Shield Memory

} else if (Pin Y = HIGH) {
   // Play File Y.wav from Prop Shield Memory
}
.
.
.

I have been able to use Frank Boesing’s Transfer utility to get files onto the flash: GitHub - FrankBoesing/TeensyTransfer: Teensy HID Transfer Tool

Next would be the actual pulling/playing code aspect. I have an example file to draw from:

Which is something that Paul Stoffregen has created for laymens like me, but I cant for the life of me decypher how this could work:

#include <Arduino.h>
#include "play_serialflash_raw.h"
#include "spi_interrupt.h"


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


bool AudioPlaySerialflashRaw::play(const char *filename)
{
	stop();
	AudioStartUsingSPI();
	rawfile = SerialFlash.open(filename);
	if (!rawfile) {
		//Serial.println("unable to open file");
		AudioStopUsingSPI();
		return false;
	}
	file_size = rawfile.size();
	file_offset = 0;
	//Serial.println("able to open file");
	playing = true;
	return true;
}

void AudioPlaySerialflashRaw::stop(void)
{
	__disable_irq();
	if (playing) {
		playing = false;
		__enable_irq();
		rawfile.close();
		AudioStopUsingSPI();
	} else {
		__enable_irq();
	}
}


void AudioPlaySerialflashRaw::update(void)
{
	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 (rawfile.available()) {
		// we can read more data from the file...
		n = rawfile.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 {
		rawfile.close();
		AudioStopUsingSPI();
		playing = false;
		//Serial.println("Finished playing sample");		//TODO
	}
	release(block);
}

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

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

uint32_t AudioPlaySerialflashRaw::lengthMillis(void)
{
	return ((uint64_t)file_size * B2M) >> 32;
}

From what I understand, would i basically pull that code into my project and then call

bool AudioPlaySerialflashRaw::play(const char *filename.wav)

but I am not 100% on this. Does anyone know if there is a way that I can get these files pulled and playing from the LC shield?

Any help is greatly appreciated!
Jon

Does anyone know if there is a way that I can get these files pulled and playing from the LC shield?

If your name was Paul Stoffregen, then I'd guess you could. Since it's not, I'd have to say no.

Paul's code plays wave files from the flash memory on the Teensy. Playing them from some other memory location is theoretically possible.

PaulS:
If your name was Paul Stoffregen, then I’d guess you could. Since it’s not, I’d have to say no.

Paul’s code plays wave files from the flash memory on the Teensy. Playing them from some other memory location is theoretically possible.

Thanks for the support…?

After a few weeks grinding away, and lot of help from others, here it is working:

// Simple MP3 file player example
//
// https://forum.pjrc.com/threads/27059-MP3-Player-Lib-with-example?p=101537&viewfull=1#post101537
//
// Requires the prop-shield and Teensy 3.2 or 3.1
// This example code is in the public domain.

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <play_sd_mp3.h> // https://github.com/FrankBoesing/Arduino-Teensy-Codec-lib
#include <Bounce2.h>
#include <Snooze.h>
#include <SnoozeBlock.h>

#define PINTER_DELAY 2000
#define HIBERNATE_DELAY  300000

#define PROP_AMP_ENABLE    5
#define FLASH_CHIP_SELECT  6
//#define FLASH_CHIP_SELECT 21  // Arduino 101 built-in SPI Flash

// GUItool: begin automatically generated code
//AudioPlaySdWav           playSdWav1;     //xy=154,422
AudioPlaySdMp3           playMp31; //xy=154,422
AudioMixer4              mixer1;         //xy=327,432
AudioOutputAnalog        dac1;           //xy=502,412
AudioConnection          patchCord1(playMp31, 0, mixer1, 0);
AudioConnection          patchCord2(playMp31, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, dac1);
// GUItool: end automatically generated code

const char *sounds[] = {
  "achest.mp3",
  "afoot.mp3",
  "ear.mp3",
  "lfoot.mp3",
  "rhand.mp3",
  "hand.mp3"
  };

bool buttons[33];    // create a symbol for every button
Bounce buttonsB[33]; // debounce handler for each button not excluded.
//
uint8_t exclude_buttons[] = { 6, 7, 10, 11, 12, 13 };   // exclude pins that may be required for communication or other
uint8_t switch_buttons[] = { 23, 24 };

// button 0 -> 33
void initButtonStates() {
  for ( uint8_t i = 0; i < 33; i++ ) {
    buttons[i] = false;
  }
}

bool isSwitch(uint8_t b) {
  uint8_t n = sizeof(switch_buttons);
  for ( uint8_t i = 0; i < n; i++ ) {
      if ( b == switch_buttons[i] ) {
        return(true);
      }
  }
  return(false);
}

bool excludedButton(uint8_t b) {
  uint8_t n = sizeof(exclude_buttons);
  for ( uint8_t i = 0; i < n; i++ ) {
      if ( b == exclude_buttons[i] ) {
        return(true);
      }
  }
  return(false);
}

void setupBouncers(void) {
  for ( uint8_t i = 0; i < 33; i++ ) {
    if ( !excludedButton(i) ) {
      buttonsB[i].attach( i , INPUT_PULLUP  );  //setup the bounce instance for the current button
      buttonsB[i].interval(10);                 // interval in ms
    }
  }
}

void buttonUpdates(void) {
  // Update all the button objects
  for ( uint8_t i = 0; i < 33; i++ ) {
    if ( !excludedButton(i) ) {
      buttonsB[i].update();
    }
  }
}

bool buttonSense(void) {
  //
  buttonUpdates();
  //
  bool hasActivity = false;
  for ( uint8_t i = 0; i < 33; i++ ) {
    if ( !excludedButton(i) ) {
      bool bstate = ( buttonsB[i].read() == 0 );
      bool bfell = buttonsB[i].fell();
      if ( isSwitch(i) ) {
        buttons[i] = bstate;
      } else {
        buttons[i] = bstate && bfell;
      }
      hasActivity = hasActivity || bstate;
    }
  }
  //
  return(hasActivity);
}

SnoozeDigital digital;
// install drivers to a SnoozeBlock
SnoozeBlock config(digital);

uint8_t wakeupPins[] = { 2, 4, 6, 7, 9, 10, 11, 13, 16, 21, 22, 26, 30, 33 };

void initWakeupPins(void) {
  uint8_t n = sizeof(wakeupPins);
  for ( uint8_t i = 0; i < n; i++ ) {
    if ( !excludedButton(wakeupPins[i]) ) {
      pinMode(wakeupPins[i], INPUT_PULLUP);
      digital.pinMode(wakeupPins[i], INPUT_PULLUP, FALLING);  // pin, mode, type
    }
  }
}

void setAmpliferState(bool ampEnableState) {
  if ( ampEnableState ) {
    digitalWrite(PROP_AMP_ENABLE, HIGH);    // Enable Amplifier
  } else {
    digitalWrite(PROP_AMP_ENABLE, LOW);    // Disable Amplifier
  }
}

void init_amplifier(void) {
  //Start Amplifier
  pinMode(PROP_AMP_ENABLE, OUTPUT);
  setAmpliferState(true);
}

void setup() {
  //
  // Configure the pushbutton pins for pullups.
  // Each button should connect from the pin to GND.
  initButtonStates();
  setupBouncers();
  //
  initWakeupPins();
  //
  pinMode(LED_BUILTIN, OUTPUT);
  //Serial.begin(9600);
  while (!Serial);
  AudioMemory(8); //4
  delay(2000);
  Serial.println("start...");

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1) {
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
    }
  }

  //Set Volume
  mixer1.gain(0, 0.5);
  mixer1.gain(1, 0.5);

  init_amplifier();

  Serial.println("ready...");
}

void playFile(const char *filename)
{
  SerialFlashFile ff = SerialFlash.open(filename);
  Serial.print("Playing file: ");
  Serial.println(filename);

  uint32_t sz = ff.size();
  uint32_t pos = ff.getFlashAddress();

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playMp31.play(pos,sz);

  // Simply wait for the file to finish playing.
  /*
  while (playMp31.isPlaying()) {
    yield();
  }
  */
}



// JUST A LITTLE CHANGE:  Just put in the buttons on this one. But. It looks like the whole thing will delay until the file is done playing.
// That means the buttons should be useless until the sound is done.
// One way to fix that is to quit using the call to yield() above. Eliminate the loop.
// Again, the stops might have to be uncommented.

elapsedMillis gt_activityTimeout = 0;

bool activityTimeout(void) {
  if ( gt_activityTimeout > HIBERNATE_DELAY ) {
    return(true);
  }
  return(false);
}

void actvityRefreshTimer(void) {
  gt_activityTimeout = 0;
}

void actvityWakeup() {
  delay(PINTER_DELAY);
  actvityRefreshTimer();
}


void triggerAwake(void) {

  if ( !playMp31.isPlaying() ) {
    if ( activityTimeout() ) {
      digitalWrite(LED_BUILTIN, LOW);
      Serial.println("going to sleep...");
      setAmpliferState(false);
      delay(100);
      //Snooze.sleep( config );

      Serial.print(gt_activityTimeout);
      Serial.print(" ");

      elapsedMillis timeout = 0;

      Serial.println(gt_activityTimeout);
      // bounce needs to call update longer than the debounce time = 5ms,
      // which is set in constructor.
      while (timeout < 10)  buttonUpdates();
      //
      Snooze.hibernate( config );
      //Snooze.sleep( config );
      //
      actvityWakeup();
      setAmpliferState(true);
      Serial.println("Woke up");
      digitalWrite(LED_BUILTIN, HIGH);
    }
    // actually never really returns.
  } else {
    actvityRefreshTimer();
  }
}




void loop() {
  //
  triggerAwake(); // block on sleeping so does not have to be boolean
  if (  buttonSense() ) {
    actvityRefreshTimer();

    if ( buttons[0]) {
      playFile(sounds[0]);

    } else if ( buttons[1]) {
      playFile(sounds[1]);

    } else if ( buttons[2]) {
      playFile(sounds[2]);

    } else if ( buttons[3]) {
      playFile(sounds[3]);

    } else if ( buttons[4]) {
      playFile(sounds[4]);

    } else if ( buttons[5]) {
      playFile(sounds[5]);

    } else {
      // no selections
    }
  }
  //
}

Now I am trying to get it to run off of 3xAA batteries. I have reached out for help here, but any help to get it running off of 3xAA batteries would be greatly appreciated!