|
|
@@ -0,0 +1,193 @@ |
|
|
|
// Record sound as raw data to a SD card, and play it back. |
|
|
|
// |
|
|
|
// Requires the audio shield: |
|
|
|
// http://www.pjrc.com/store/teensy3_audio.html |
|
|
|
// |
|
|
|
// Three pushbuttons need to be connected: |
|
|
|
// Record Button: pin 0 to GND |
|
|
|
// Stop Button: pin 1 to GND |
|
|
|
// Play Button: pin 2 to GND |
|
|
|
// |
|
|
|
// This example code is in the public domain. |
|
|
|
|
|
|
|
#include <Bounce.h> |
|
|
|
#include <Audio.h> |
|
|
|
#include <Wire.h> |
|
|
|
#include <SPI.h> |
|
|
|
#include <SD.h> |
|
|
|
|
|
|
|
// GUItool: begin automatically generated code |
|
|
|
AudioInputI2S i2s2; //xy=105,63 |
|
|
|
AudioAnalyzePeak peak1; //xy=278,108 |
|
|
|
AudioRecordQueue queue1; //xy=281,63 |
|
|
|
AudioPlaySdRaw playRaw1; //xy=302,157 |
|
|
|
AudioOutputI2S i2s1; //xy=470,120 |
|
|
|
AudioConnection patchCord1(i2s2, 0, queue1, 0); |
|
|
|
AudioConnection patchCord2(i2s2, 0, peak1, 0); |
|
|
|
AudioConnection patchCord3(playRaw1, 0, i2s1, 0); |
|
|
|
AudioConnection patchCord4(playRaw1, 0, i2s1, 1); |
|
|
|
AudioControlSGTL5000 sgtl5000_1; //xy=265,212 |
|
|
|
// GUItool: end automatically generated code |
|
|
|
|
|
|
|
// Bounce objects to easily and reliably read the buttons |
|
|
|
Bounce buttonRecord = Bounce(0, 8); |
|
|
|
Bounce buttonStop = Bounce(1, 8); // 8 = 8 ms debounce time |
|
|
|
Bounce buttonPlay = Bounce(2, 8); |
|
|
|
|
|
|
|
|
|
|
|
// which input on the audio shield will be used? |
|
|
|
const int myInput = AUDIO_INPUT_LINEIN; |
|
|
|
//const int myInput = AUDIO_INPUT_MIC; |
|
|
|
|
|
|
|
// Remember which mode we're doing |
|
|
|
int mode = 0; // 0=stopped, 1=recording, 2=playing |
|
|
|
|
|
|
|
// The file where data is recorded |
|
|
|
File frec; |
|
|
|
|
|
|
|
void setup() { |
|
|
|
// Configure the pushbutton pins |
|
|
|
pinMode(0, INPUT_PULLUP); |
|
|
|
pinMode(1, INPUT_PULLUP); |
|
|
|
pinMode(2, INPUT_PULLUP); |
|
|
|
|
|
|
|
// Audio connections require memory, and the record queue |
|
|
|
// uses this memory to buffer incoming audio. |
|
|
|
AudioMemory(60); |
|
|
|
|
|
|
|
// Enable the audio shield, select input, and enable output |
|
|
|
sgtl5000_1.enable(); |
|
|
|
sgtl5000_1.inputSelect(myInput); |
|
|
|
sgtl5000_1.volume(0.5); |
|
|
|
|
|
|
|
// 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); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void loop() { |
|
|
|
// First, read the buttons |
|
|
|
buttonRecord.update(); |
|
|
|
buttonStop.update(); |
|
|
|
buttonPlay.update(); |
|
|
|
|
|
|
|
// Respond to button presses |
|
|
|
if (buttonRecord.fallingEdge()) { |
|
|
|
Serial.println("Record Button Press"); |
|
|
|
if (mode == 2) stopPlaying(); |
|
|
|
if (mode == 0) startRecording(); |
|
|
|
} |
|
|
|
if (buttonStop.fallingEdge()) { |
|
|
|
Serial.println("Stop Button Press"); |
|
|
|
if (mode == 1) stopRecording(); |
|
|
|
if (mode == 2) stopPlaying(); |
|
|
|
} |
|
|
|
if (buttonPlay.fallingEdge()) { |
|
|
|
Serial.println("Play Button Press"); |
|
|
|
if (mode == 1) stopRecording(); |
|
|
|
if (mode == 0) startPlaying(); |
|
|
|
} |
|
|
|
|
|
|
|
// If we're playing or recording, carry on... |
|
|
|
if (mode == 1) { |
|
|
|
continueRecording(); |
|
|
|
} |
|
|
|
if (mode == 2) { |
|
|
|
continuePlaying(); |
|
|
|
} |
|
|
|
|
|
|
|
// when using a microphone, continuously adjust gain |
|
|
|
if (myInput == AUDIO_INPUT_MIC) adjustMicLevel(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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.stop(); |
|
|
|
mode = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void stopPlaying() { |
|
|
|
Serial.println("stopPlaying"); |
|
|
|
if (mode == 2) playRaw1.stop(); |
|
|
|
mode = 0; |
|
|
|
} |
|
|
|
|
|
|
|
void adjustMicLevel() { |
|
|
|
// TODO: read the peak1 object and adjust sgtl5000_1.micGain() |
|
|
|
// if anyone gets this working, please submit a github pull request :-) |
|
|
|
} |
|
|
|
|