Hello, I'm using a teensy 4.0 with Rev 4 Audio Shield. I have audio coming in(linein from a piezo).
I want to build a looper pedal.
- record music (working)
- play back music(working)
and 3) record while playing back so that the next time it loops, the added sounds are also there.
For instance:
start playing and recording music, hit a button to tell the teensy the point where it stops, have it loop all the music up to that point. If i hit again, it'll toggle between recording (not replacing, but adding sound onto the loop) and not having any recording and only playing.
My question:
How do I continuously update the sdcard to that as I write the new total audio information is written? Is there example code for doing this that you could provide/link to? The code that I have attached can record and playback, but if I try to record in the middle of playback it glitches. Eventually I want to scale this to have multiple pedals/loops that are independent, but first step is playing the audio in a loop and adding recording to the sound.
Thanks!
You can't write in multiple locations, as you can only retrieve one at a time. How do you take the sd card data, modify it, rewrite, and send back? Can you maybe take a chunk of a few seconds, store it not in the sd card and edit it with the new audio + old audio, and restore that chunk, then retrieve the next? What would be the maximum size of this audio chunk if I want up to 6 layers? I would prefer more, but 6 should be enough for most cases.
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
//write wav
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRate*numChannels*(bitsPerSample/8);// samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels*bitsPerSample/8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;
int count = 1;
// GUItool: begin automatically generated code
AudioInputI2S audioInput; //xy=62.5,192.0000057220459
AudioPlaySdWav audioSD; //xy=204,377.00000381469727
AudioRecordQueue queue1; //xy=268,205.00000381469727
AudioOutputI2S audioOutput; //xy=475,373.00000381469727
AudioConnection patchCord1(audioInput, 0, queue1, 0);
AudioConnection patchCord2(audioSD, 0, audioOutput, 0);
AudioConnection patchCord3(audioSD, 0, audioOutput, 1);
AudioControlSGTL5000 audioShield; //xy=450,251.00000381469727
// GUItool: end automatically generated code
File frec;
elapsedMillis msecs;
int recTime = 0;
bool firstRec = true;
// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
void setup() {
Serial.begin(9600);
AudioMemory(60);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.micGain(40); //0-63
audioShield.volume(0.5); //0-1
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
// stop here, but print a message repetitively
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
Serial.println("1 is record, 2 is stop, 3 is playback");
}
void startRecording() {
Serial.println("startRecording");
if (SD.exists("RECORD.WAV")) {
SD.remove("RECORD.WAV");
}
frec = SD.open("RECORD.WAV", FILE_WRITE);
if (frec) {
queue1.begin();
recByteSaved = 0L;
}
}
void continueRecording() {
if (queue1.available() >= 2) {
byte buffer[512];
memcpy(buffer, queue1.readBuffer(), 256);
queue1.freeBuffer();
memcpy(buffer + 256, queue1.readBuffer(), 256);
queue1.freeBuffer();
// write all 512 bytes to the SD card
frec.write(buffer, 512);
recByteSaved += 512;
// elapsedMicros usec = 0;
// Serial.print("SD write, us=");
// Serial.println(usec);
}
}
void writeOutHeader() { // update WAV header with final filesize/datasize
// NumSamples = (recByteSaved*8)/bitsPerSample/numChannels;
// Subchunk2Size = NumSamples*numChannels*bitsPerSample/8; // number of samples x number of channels x number of bytes per sample
Subchunk2Size = recByteSaved;
ChunkSize = Subchunk2Size + 36;
frec.seek(0);
frec.write("RIFF");
byte1 = ChunkSize & 0xff;
byte2 = (ChunkSize >> 8) & 0xff;
byte3 = (ChunkSize >> 16) & 0xff;
byte4 = (ChunkSize >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.write("WAVE");
frec.write("fmt ");
byte1 = Subchunk1Size & 0xff;
byte2 = (Subchunk1Size >> 8) & 0xff;
byte3 = (Subchunk1Size >> 16) & 0xff;
byte4 = (Subchunk1Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = AudioFormat & 0xff;
byte2 = (AudioFormat >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = numChannels & 0xff;
byte2 = (numChannels >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = sampleRate & 0xff;
byte2 = (sampleRate >> 8) & 0xff;
byte3 = (sampleRate >> 16) & 0xff;
byte4 = (sampleRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = byteRate & 0xff;
byte2 = (byteRate >> 8) & 0xff;
byte3 = (byteRate >> 16) & 0xff;
byte4 = (byteRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = blockAlign & 0xff;
byte2 = (blockAlign >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = bitsPerSample & 0xff;
byte2 = (bitsPerSample >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
frec.write("data");
byte1 = Subchunk2Size & 0xff;
byte2 = (Subchunk2Size >> 8) & 0xff;
byte3 = (Subchunk2Size >> 16) & 0xff;
byte4 = (Subchunk2Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.close();
Serial.println("header written");
Serial.print("Subchunk2: ");
Serial.println(Subchunk2Size);
}
void stopRecording() {
Serial.println("stopRecording");
queue1.end();
while (queue1.available() > 0) {
frec.write((byte*)queue1.readBuffer(), 256);
queue1.freeBuffer();
recByteSaved += 256;
}
writeOutHeader();
frec.close();
}
void startPlaying() {
Serial.println("startPlaying");
audioSD.play("RECORD.WAV");
}
void stopPlaying() {
Serial.println("stopPlaying");
audioSD.stop();
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
if(count == 1){count = -1;}
count++;
//count is either 1 2 or 3, first time it is 0. On the first time, clicking stops recording and starts playing. on all subsequent clicks, it toggles
// read the incoming byte:
byte incomingByte = Serial.read();
Serial.println(count);
// Respond to button presses
if (count == 0){
startRecording();
}
if ( count == 1 ) {
if(firstRec == true){
recTime = millis();
}
Serial.println("stop");
//if (mode == 2) stopPlaying();
stopRecording();
startPlaying();
}
Serial.println("_____");
}
if(count == 0){
continueRecording();
}
}