AidanRTaylor
Active member
**{FIXED}** Multiple WAV playback problems
-*-*-*-FIXED-*-*-*-
Hello, I'm working on a prototype for a toy - it's basically a steering wheel with some switches that activate simple things - but included is a fake radio. The hardware is a Teensy 3.2 and the Teensy Audio Adaptor with an SD Card (more on that below) and some basic panel controls around it. I have a sketch mostly together for it - the radio works by buffering two WAVs at any given time. One WAV is always playing which is a 60 second sample of out-of-tune radio static, and as you adjust a "Tuning" potentiometer, several other WAVs of full length songs (I'm using the Teensy demo audio at the moment) are faded in and out. Only one song is active at a time, so WAVs are being buffered and removed from the buffer as the pot is adjusted. In terms of how it works, it is pretty much identical to the "Mixer" example provided with the Teensy Audio examples, with the exception of buffering new files in the loop.
I've also implemented a volume control - I'm using the line output of the audio shield so I use the .dacVolume() function. The toy also includes some LED indicators and a vibration motor which is controlled with PWM to simulate an engine turning.
So here are the problems...
Sometimes the sketch runs absolutely fine, sometimes it starts fine and then becomes unresponsive with audio still playing, sometimes it starts unresponsive with some things running but no audio starting. Sometimes the audio playback is very glitchy, like the sample rate is inconsistent. One of the most annoying things is that the volume control is very selective, it often won't work at all when most other things are working ok - but I imagine all the problems will boil down to the same issue. When the sketch isn't running properly, it tends to be noticeable in the way the vibration motor behaves as well, I think PWM is running fine, but the analogWrite() updating isn't working as intended. - ah yes just from looking over my code, I can't seem to get any noticeable effect using .dacVolumeRamp() either
As a side note - I also have the same problems running the "Mixer" example, although it is a simpler effect. The audio playback is either absolutely fine or very glitchy, using the provided WAV examples.
I started working with a Kingston 16GB MicroSD HC, but this morning I tried a 32GB SanDisk Ultra as recommended on the PJRC site, but the same problems remain.
Code is posted below, any feedback would be most welcome (even unrelated!) - one parameter I am particularly unclear on is "AudioMemory()" - I have set this quite high (I think it is the same as the WavFilePlayer example) but I don't know where I should be setting it. I think it is pretty resonably commented!
-*-*-*-FIXED-*-*-*-
Hello, I'm working on a prototype for a toy - it's basically a steering wheel with some switches that activate simple things - but included is a fake radio. The hardware is a Teensy 3.2 and the Teensy Audio Adaptor with an SD Card (more on that below) and some basic panel controls around it. I have a sketch mostly together for it - the radio works by buffering two WAVs at any given time. One WAV is always playing which is a 60 second sample of out-of-tune radio static, and as you adjust a "Tuning" potentiometer, several other WAVs of full length songs (I'm using the Teensy demo audio at the moment) are faded in and out. Only one song is active at a time, so WAVs are being buffered and removed from the buffer as the pot is adjusted. In terms of how it works, it is pretty much identical to the "Mixer" example provided with the Teensy Audio examples, with the exception of buffering new files in the loop.
I've also implemented a volume control - I'm using the line output of the audio shield so I use the .dacVolume() function. The toy also includes some LED indicators and a vibration motor which is controlled with PWM to simulate an engine turning.
So here are the problems...
Sometimes the sketch runs absolutely fine, sometimes it starts fine and then becomes unresponsive with audio still playing, sometimes it starts unresponsive with some things running but no audio starting. Sometimes the audio playback is very glitchy, like the sample rate is inconsistent. One of the most annoying things is that the volume control is very selective, it often won't work at all when most other things are working ok - but I imagine all the problems will boil down to the same issue. When the sketch isn't running properly, it tends to be noticeable in the way the vibration motor behaves as well, I think PWM is running fine, but the analogWrite() updating isn't working as intended. - ah yes just from looking over my code, I can't seem to get any noticeable effect using .dacVolumeRamp() either
As a side note - I also have the same problems running the "Mixer" example, although it is a simpler effect. The audio playback is either absolutely fine or very glitchy, using the provided WAV examples.
I started working with a Kingston 16GB MicroSD HC, but this morning I tried a 32GB SanDisk Ultra as recommended on the PJRC site, but the same problems remain.
Code is posted below, any feedback would be most welcome (even unrelated!) - one parameter I am particularly unclear on is "AudioMemory()" - I have set this quite high (I think it is the same as the WavFilePlayer example) but I don't know where I should be setting it. I think it is pretty resonably commented!
Code:
/*
* Steering Wheel Haptic Control Sketch for Teensy 3.2 + Audio Adaptor
*
* 2 dials control a pretend radio with tuning and volume. The radio works by
* looping tracks and one control fades between them. Switches activate
* indicator LEDs. A tilt switch activates vibration motors.
*
*/
// Additional libraries are required for Audio on the Teensy and the Audio Adaptor
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// Below is automatically generated code from the Teensy Audio System Design Tool
// https://www.pjrc.com/teensy/gui/index.html
// GUItool: begin automatically generated code
AudioPlaySdWav playSdWav1; //xy=282,264
AudioPlaySdWav playSdWav2; //xy=282,298
AudioPlaySdWav playSdWav3; //xy=282,332
AudioPlaySdWav playSdWav4; //xy=282,366
AudioMixer4 mixer2; //xy=492,341
AudioMixer4 mixer1; //xy=493,277
AudioOutputI2S i2s1; //xy=634,310
AudioConnection patchCord1(playSdWav1, 0, mixer1, 0);
AudioConnection patchCord2(playSdWav1, 1, mixer2, 0);
AudioConnection patchCord3(playSdWav2, 0, mixer1, 1);
AudioConnection patchCord4(playSdWav2, 1, mixer2, 1);
AudioConnection patchCord5(playSdWav3, 0, mixer1, 2);
AudioConnection patchCord6(playSdWav3, 1, mixer2, 2);
AudioConnection patchCord7(playSdWav4, 0, mixer1, 3);
AudioConnection patchCord8(playSdWav4, 1, mixer2, 3);
AudioConnection patchCord9(mixer2, 0, i2s1, 1);
AudioConnection patchCord10(mixer1, 0, i2s1, 0);
AudioControlSGTL5000 sgtl5000_1; //xy=118,436
// GUItool: end automatically generated code
// Teensy Audio Shield connections
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
// IO pins used in the sketch:
const byte tunerPin = A2;
const byte ledLPin = 1;
const byte ledRPin = 2;
const byte indicatorLPin = 4;
const byte indicatorRPin = 5;
const byte vibratePin = 3;
const byte tiltPin = 0;
// control state memory variables:
int tunerVal;
boolean indicatorL, indicatorR, tilt, lastTilt, vibDir, vibEnable, ledL, ledR;
byte vibLevel;
float gain1,gain2,gain3,gain4;
// time management variables:
unsigned long timeMS, ledLMS, ledRMS, tiltMS;
int ledInterval = 500;
int vibInterval = 10000;
void setup() {
Serial.begin(115200);
Serial.println("Starting Setup");
AudioMemory(160); // audio buffer memory - may be higher than necessary
sgtl5000_1.enable(); // sgtl5000 allows for control over audio adaptor
// sgtl5000_1.volume(0.5); // volume for headphone output
sgtl5000_1.dacVolumeRamp(); // exponential volume ramp dac (doesn't seem to work??)
sgtl5000_1.lineOutLevel(21);
//SD Card setup
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
// Virtual Mixer initial levels
mixer1.gain(0, 0.);
mixer1.gain(1, 0.);
mixer1.gain(2, 0.);
mixer1.gain(3, 0.);
mixer2.gain(0, 0.);
mixer2.gain(1, 0.);
mixer2.gain(2, 0.);
mixer2.gain(3, 0.);
// IO setup:
pinMode(ledLPin, OUTPUT);
pinMode(ledRPin, OUTPUT);
pinMode(vibratePin, OUTPUT);
pinMode(indicatorLPin, INPUT_PULLUP);
pinMode(indicatorRPin, INPUT_PULLUP);
pinMode(tiltPin, INPUT_PULLUP);
Serial.println("Sketch starts shortly");
delay(1000);
Serial.println("Setup Complete, running sketch");
}
void loop() {
timeMS = millis(); // sample the current internal timer
tilt = digitalRead(tiltPin); // read from the tilt sensor
indicatorL = digitalRead(indicatorLPin); // read left indicator switch
indicatorR = digitalRead(indicatorRPin); // read right indicator switch
int volPot = analogRead(A3);
float vol = (float)volPot / 1028.0;
sgtl5000_1.dacVolume(vol);
// Serial.print("volume = ");
// Serial.println(vol);
vibration();
indicators();
radio();
}
void radio() {
// The radio static sample plays all the time:
if (playSdWav1.isPlaying() == false) {
Serial.println("Start playing 1");
playSdWav1.play("static.WAV");
delay(100); // wait for library to parse WAV info
}
tunerVal = analogRead(tunerPin); // read from the Tuner knob
/*
* The code below looks complex, but it really isn't! It splits the reading from
* the tuner pot by a number of divisions, then for each division a track will be
* faded in or out (against the static background). I start and stop tracks from
* the SD Card so there is never more than two playing at a time - I am not sure
* how many long tracks can be simultaneously played by the Teensy before it
* reaches the limits of its memory.
*/
if(tunerVal < 170) {
gain1 = 1.0 - ((float)tunerVal / 170.0);
gain2 = (float)tunerVal / 170.0;
if (playSdWav3.isPlaying() == true) {
Serial.println("Stop playing 3");
playSdWav3.stop();
delay(100); // wait for library to parse WAV info
}
if (playSdWav2.isPlaying() == false) {
Serial.println("Start playing 2");
playSdWav2.play("SDTEST1.WAV");
delay(100); // wait for library to parse WAV info
}
}
else if(tunerVal >= 170 && tunerVal < 340) {
gain1 = (float)(tunerVal-170) / 170.0;
gain2 = 1.0 - gain1;
if (playSdWav3.isPlaying() == true) {
Serial.println("Stop playing 3");
playSdWav3.stop();
delay(100); // wait for library to parse WAV info
}
if (playSdWav2.isPlaying() == false) {
Serial.println("Start playing 2");
playSdWav2.play("SDTEST1.WAV");
delay(100); // wait for library to parse WAV info
}
}
else if(tunerVal >= 340 && tunerVal < 510) {
gain1 = 1.0 - ((float)(tunerVal-340) / 170.0);
gain3 = (float)(tunerVal-340) / 170.0;
if (playSdWav2.isPlaying() == true) {
Serial.println("Stop playing 2");
playSdWav2.stop();
delay(100); // wait for library to parse WAV info
}
if (playSdWav3.isPlaying() == false) {
Serial.println("Start playing 3");
playSdWav3.play("SDTEST2.WAV");
delay(100); // wait for library to parse WAV info
}
}
else if(tunerVal >= 510 && tunerVal < 680) {
gain1 = (float)(tunerVal-510) / 170.0;
gain3 = 1.0 - gain1;
if (playSdWav4.isPlaying() == true) {
Serial.println("Stop playing 4");
playSdWav4.stop();
delay(100); // wait for library to parse WAV info
}
if (playSdWav3.isPlaying() == false) {
Serial.println("Start playing 3");
playSdWav3.play("SDTEST2.WAV");
delay(100); // wait for library to parse WAV info
}
}
else if(tunerVal >= 680 && tunerVal < 850) {
gain1 = 1.0 - ((float)(tunerVal-680) / 170.0);
gain4 = (float)(tunerVal-680) / 170.0;
if (playSdWav3.isPlaying() == true) {
Serial.println("Stop playing 3");
playSdWav3.stop();
delay(100); // wait for library to parse WAV info
}
if (playSdWav4.isPlaying() == false) {
Serial.println("Start playing 4");
playSdWav4.play("SDTEST3.WAV");
delay(100); // wait for library to parse WAV info
}
}
else if(tunerVal >= 850 && tunerVal <= 1024) {
gain1 = ((float)(tunerVal-850) / 174.0);
gain4 = 1.0 - gain1;
if (playSdWav3.isPlaying() == true) {
Serial.println("Stop playing 3");
playSdWav3.stop();
delay(100); // wait for library to parse WAV info
}
if (playSdWav4.isPlaying() == false) {
Serial.println("Start playing 4");
playSdWav4.play("SDTEST3.WAV");
delay(100); // wait for library to parse WAV info
}
}
// The code below is useful for debugging, but leave it commented out otherwise
// Serial.print("gain 1= ");
// Serial.print(gain1);
// Serial.print(" gain 2= ");
// Serial.print(gain2);
// Serial.print(" gain 3= ");
// Serial.print(gain3);
// Serial.print(" gain 4= ");
// Serial.println(gain4);
mixer1.gain(0, gain1);
mixer1.gain(1, gain2);
mixer1.gain(2, gain3);
mixer1.gain(3, gain4);
mixer2.gain(0, gain1);
mixer2.gain(1, gain2);
mixer2.gain(2, gain3);
mixer2.gain(3, gain4);
}
void vibration() {
if(tilt != lastTilt) {
lastTilt = tilt;
tiltMS = millis();
Serial.println("Tilt Detected");
}
if(timeMS - tiltMS < 10000) vibEnable = true;
else vibEnable = false;
if(vibEnable) {
if(vibDir && vibLevel < 255) {
vibLevel++;
}
else if(!vibDir && vibLevel >= 0) {
vibLevel--;
if(vibLevel == 0) digitalWrite(vibratePin, LOW);
}
if(vibLevel != 0) analogWrite(vibratePin, vibLevel);
delay(2);
if(vibLevel == 100) vibDir = !vibDir;
if(vibLevel == 255) vibDir = !vibDir;
}
else {
if(vibLevel != 0) {
vibLevel--;
analogWrite(vibratePin, vibLevel);
delay(5);
}
else digitalWrite(vibratePin, LOW);
}
}
void indicators() {
if(!indicatorL) {
if(timeMS - ledLMS > 500) {
ledLMS = millis();
ledL = !ledL;
digitalWrite(ledLPin, ledL);
}
}
else digitalWrite(ledLPin, LOW);
if(!indicatorR) {
if(timeMS - ledRMS > 500) {
ledRMS = millis();
ledR = !ledR;
digitalWrite(ledRPin, ledR);
}
}
else digitalWrite(ledRPin, LOW);
}
Last edited: