amazingrolo
Member
I'm currently building a two-buffer audio sampler using a Teensy 3.1 and the audio shield. Messy code below...I recognize that it's very poorly constructed!
My design uses four buttons, two for each buffer. Each buffer has a play/stop button, and a record button.
The current problem is very specific, but I can't figure out a solution. Essentially: if I'm holding the "play" button on one channel, and press the "record" button on the other channel, then everything stops and I have to restart the Teensy.
A few other clues:
- Recording into both buffers simultaneously works fine
- Playing both buffers simultaneously works fine
- Holding the play button and then pressing the record button on the same buffer works fine
- If I look at the files on a computer after an error, the file from the buffer where I pressed record is a zero byte file. e.g. if I was holding "play2" and pressed "record1" then the record1.raw file is zero bytes, while the record2.raw file is still intact
Any ideas? Many thanks!
-yann
My design uses four buttons, two for each buffer. Each buffer has a play/stop button, and a record button.
The current problem is very specific, but I can't figure out a solution. Essentially: if I'm holding the "play" button on one channel, and press the "record" button on the other channel, then everything stops and I have to restart the Teensy.
A few other clues:
- Recording into both buffers simultaneously works fine
- Playing both buffers simultaneously works fine
- Holding the play button and then pressing the record button on the same buffer works fine
- If I look at the files on a computer after an error, the file from the buffer where I pressed record is a zero byte file. e.g. if I was holding "play2" and pressed "record1" then the record1.raw file is zero bytes, while the record2.raw file is still intact
Any ideas? Many thanks!
-yann
Code:
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
// GUItool: begin automatically generated code
AudioPlaySdRaw playRaw2; //xy=189,349
AudioPlaySdRaw playRaw1; //xy=190,295
AudioInputI2S i2s1; //xy=226,112
AudioSynthWaveformSine sine1; //xy=261,453
AudioMixer4 mixer1; //xy=395,309
AudioRecordQueue queue2; //xy=450,219
AudioRecordQueue queue1; //xy=453,89
AudioFilterStateVariable filter1; //xy=461,421
AudioOutputI2S i2s2; //xy=609,428
AudioConnection patchCord1(playRaw2, 0, mixer1, 1);
AudioConnection patchCord2(playRaw1, 0, mixer1, 0);
AudioConnection patchCord3(i2s1, 0, queue2, 0);
AudioConnection patchCord4(i2s1, 0, queue1, 0);
AudioConnection patchCord5(sine1, 0, filter1, 1);
AudioConnection patchCord6(mixer1, 0, filter1, 0);
AudioConnection patchCord7(filter1, 0, i2s2, 0);
AudioConnection patchCord8(filter1, 0, i2s2, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=281,607
// GUItool: end automatically generated code
const int numReadings = 20;
int readings[numReadings]; // the readings from the analog input
int avgindex = 0; // the avgindex of the current reading
int total = 0; // the running total
int average = 0; // the average
int inputPin = A10;
// Bounce objects to easily and reliably read the buttons
Bounce buttonRecord = Bounce(0, 8);
Bounce buttonPlay = Bounce(1, 8); // 8 = 8 ms debounce time
Bounce buttonRecord2 = Bounce(2, 8);
Bounce buttonPlay2 = Bounce(3, 8);
float filtercontrol;
float filterfreqcal = 15000;
// which input on the audio shield will be used?
// Remember which mode we're doing
int mode = 0;
int mode2 = 0;
// 0=stopped, 1=recording, 2=playing
int loopMode = 0;
// The file where data is recorded
File frec;
File frec2;
void setup() {
// Configure the pushbutton pins
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(16, OUTPUT);
pinMode(17, OUTPUT);
pinMode(20, OUTPUT);
pinMode(21, OUTPUT);
mixer1.gain(0,1);
mixer1.gain(1,1);
filter1.frequency(15000);
filter1.resonance(1.5);
sine1.frequency(5);
// Audio connections require memory, and the record queue
// uses this memory to buffer incoming audio.
AudioMemory(120);
const int myInput = AUDIO_INPUT_LINEIN;
// Enable the audio shield, select input, and enable output
sgtl5000_1.enable();
sgtl5000_1.inputSelect(myInput);
sgtl5000_1.volume(0.8);
// Initialize the SD card
SPI.setMOSI(7);
SPI.setSCK(14);
if (!(SD.begin(10))) {
// stop here if no SD card, but print a message
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}
void loop() {
// First, read the buttons
if (digitalRead(5) == 1) {
loopMode = 1;
Serial.println("Loop On");
} else {
loopMode = 0;
// Serial.println("Loop Off");
}
buttonRecord.update();
buttonPlay.update();
buttonRecord2.update();
buttonPlay2.update();
setFilter();
if (mode == 1) {
digitalWrite(16, HIGH);
} else {
digitalWrite(16, LOW);
}
if (mode == 2) {
digitalWrite(17, HIGH);
} else {
digitalWrite(17, LOW);
}
if (mode2 == 1) {
digitalWrite(20, HIGH);
} else {
digitalWrite(20, LOW);
}
if (mode2 == 2) {
digitalWrite(21, HIGH);
} else {
digitalWrite(21, LOW);
}
// Respond to button presses
if (buttonRecord.fallingEdge()) {
Serial.println("Record Button Press");
if (mode == 2) stopPlaying();
if (mode == 0) startRecording();
else if (mode == 1) stopRecording();
}
if (loopMode == 1) {
if (buttonPlay.fallingEdge()) {
Serial.println("Play Button Press");
if (mode == 1) stopRecording();
if (mode == 0) startPlaying();
if (mode == 2) startPlaying();
}
}
if (loopMode == 0) {
if (buttonPlay.fallingEdge()) {
Serial.println("Play Button Press OneShot");
if (mode == 0) startPlaying();
if (mode == 1) {
stopRecording();
startPlaying();
}
}
if (buttonPlay.risingEdge() && mode != 1) {
stopPlaying();
}
}
// If we're playing or recording, carry on...
if (mode == 1) {
continueRecording();
}
if (mode == 2) {
continuePlaying();
}
// second channel
// Respond to button presses
if (buttonRecord2.fallingEdge()) {
Serial.println("Record Button Press 2");
if (mode2 == 2) stopPlaying2();
if (mode2 == 0) startRecording2();
else if (mode2 == 1) stopRecording2();
}
if (loopMode == 1) {
if (buttonPlay2.fallingEdge()) {
Serial.println("Play Button Press 2");
if (mode2 == 1) stopRecording2();
if (mode2 == 0) startPlaying2();
if (mode2 == 2) startPlaying2();
}
}
if (loopMode == 0) {
if (buttonPlay2.fallingEdge()) {
Serial.println("Play Button Press OneShot 2");
if (mode2 == 0) startPlaying2();
if (mode2 == 1) {
stopRecording2();
startPlaying2();
}
}
if (buttonPlay2.risingEdge() && mode2 != 1) {
stopPlaying2();
}
}
// If we're playing or recording, carry on...
if (mode2 == 1) {
continueRecording2();
}
if (mode2 == 2) {
continuePlaying2();
}
}
void startRecording() {
Serial.println("startRecording");
if (SD.exists("RECORD.RAW")) {
// The SD library writes new data to the end of the
// file, so to start a new recording, the old file
// must be deleted before new data is written.
SD.remove("RECORD.RAW");
}
frec = SD.open("RECORD.RAW", FILE_WRITE);
if (frec) {
queue1.begin();
mode = 1;
}
}
void continueRecording() {
if (queue1.available() >= 2) {
byte buffer[512];
// Fetch 2 blocks from the audio library and copy
// into a 512 byte buffer. The Arduino SD library
// is most efficient when full 512 byte sector size
// writes are used.
memcpy(buffer, queue1.readBuffer(), 256);
queue1.freeBuffer();
memcpy(buffer+256, queue1.readBuffer(), 256);
queue1.freeBuffer();
// write all 512 bytes to the SD card
elapsedMicros usec = 0;
frec.write(buffer, 512);
// Uncomment these lines to see how long SD writes
// are taking. A pair of audio blocks arrives every
// 5802 microseconds, so hopefully most of the writes
// take well under 5802 us. Some will take more, as
// the SD library also must write to the FAT tables
// and the SD card controller manages media erase and
// wear leveling. The queue1 object can buffer
// approximately 301700 us of audio, to allow time
// for occasional high SD card latency, as long as
// the average write time is under 5802 us.
Serial.print("SD write, us=");
Serial.println(usec);
}
}
void stopRecording() {
Serial.println("stopRecording");
queue1.end();
if (mode == 1) {
while (queue1.available() > 0) {
frec.write((byte*)queue1.readBuffer(), 256);
queue1.freeBuffer();
}
frec.close();
}
mode = 0;
}
void startPlaying() {
Serial.println("startPlaying");
playRaw1.play("RECORD.RAW");
mode = 2;
}
void continuePlaying() {
if (!playRaw1.isPlaying()) {
playRaw1.play("RECORD.RAW");
// mode = 0;
}
}
void stopPlaying() {
if (mode != 0) {
Serial.println("stopPlaying");
playRaw1.stop();
mode = 0;
}
}
// second channel
void startRecording2() {
Serial.println("startRecording2");
if (SD.exists("RECORD2.RAW")) {
// The SD library writes new data to the end of the
// file, so to start a new recording, the old file
// must be deleted before new data is written.
SD.remove("RECORD2.RAW");
}
frec2 = SD.open("RECORD2.RAW", FILE_WRITE);
if (frec2) {
queue2.begin();
mode2 = 1;
Serial.println("made it this far");
}
}
void continueRecording2() {
if (queue2.available() >= 2) {
byte buffer2[512];
// Fetch 2 blocks from the audio library and copy
// into a 512 byte buffer. The Arduino SD library
// is most efficient when full 512 byte sector size
// writes are used.
memcpy(buffer2, queue2.readBuffer(), 256);
queue2.freeBuffer();
memcpy(buffer2+256, queue2.readBuffer(), 256);
queue2.freeBuffer();
// write all 512 bytes to the SD card
elapsedMicros usec = 0;
frec2.write(buffer2, 512);
// Uncomment these lines to see how long SD writes
// are taking. A pair of audio blocks arrives every
// 5802 microseconds, so hopefully most of the writes
// take well under 5802 us. Some will take more, as
// the SD library also must write to the FAT tables
// and the SD card controller manages media erase and
// wear leveling. The queue1 object can buffer
// approximately 301700 us of audio, to allow time
// for occasional high SD card latency, as long as
// the average write time is under 5802 us.
//Serial.print("SD write, us=");
//Serial.println(usec);
}
}
void stopRecording2() {
Serial.println("stopRecording2");
queue2.end();
if (mode2 == 1) {
while (queue2.available() > 0) {
frec2.write((byte*)queue2.readBuffer(), 256);
queue2.freeBuffer();
}
frec2.close();
}
mode2 = 0;
}
void startPlaying2() {
Serial.println("startPlaying2");
playRaw2.play("RECORD2.RAW");
mode2 = 2;
}
void continuePlaying2() {
if (!playRaw2.isPlaying()) {
playRaw2.play("RECORD2.RAW");
// mode = 0;
}
}
void stopPlaying2() {
Serial.println("stopPlaying2");
if (mode2 == 2) playRaw2.stop();
mode2 = 0;
}
void setFilter() {
// subtract the last reading:
total= total - readings[avgindex];
// read from the sensor:
readings[avgindex] = analogRead(inputPin);
// add the reading to the total:
total= total + readings[avgindex];
// advance to the next position in the array:
avgindex = avgindex + 1;
// if we're at the end of the array...
if (avgindex >= numReadings)
// ...wrap around to the beginning:
avgindex = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
delay(1); // delay in between reads for stability
filtercontrol = map(average,0,1023,100,12000);
filter1.frequency(filtercontrol);
// Serial.println(filtercontrol);
}