#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#define RECORD_PIN 0
#define TESTLINEIN
#define DEBUG
#define BUG
AudioOutputI2S i2s2;
AudioRecordQueue queue1;
#ifdef TESTLINEIN
AudioInputI2S i2s1;
AudioConnection patchCord1(i2s1, 0, i2s2, 0);
AudioConnection patchCord2(i2s1, 0, queue1, 0);
AudioConnection patchCord3(i2s1, 1, i2s2, 1);
#else
AsyncAudioInputSPDIF3 spdifIn(false, false, 100, 20, 80); //dither = false, noiseshaping = false, anti-aliasing attenuation=100dB, minimum half resampling filter length=20, maximum half resampling filter length=80
AudioConnection patchCord1(spdifIn, 0, i2s2, 0);
AudioConnection patchCord2(spdifIn, 0, queue1, 0);
AudioConnection patchCord3(spdifIn, 1, i2s2, 1);
#endif
AudioControlSGTL5000 sgtl5000_1;
// Bounce objects to easily and reliably read the buttons
Bounce buttonRecord = Bounce(RECORD_PIN, 8);
#ifdef TESTLINEIN
// which input on the audio shield will be used?
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;
#endif
// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
// Remember which mode we're doing
int mode = 0; // 0=stopped, 1=recording, 2=stopRecording
// The file where data is recorded
File frec;
int nbiter=0;
#ifdef DEBUG
unsigned long last_time = millis();
#endif
void setup() {
// Configure the pushbutton pins
pinMode(RECORD_PIN, INPUT_PULLUP);
AudioMemory(12);
// Enable the audio shield, enable output
sgtl5000_1.enable();
sgtl5000_1.volume(0.5);
#ifdef TESTLINEIN
sgtl5000_1.inputSelect(myInput); //choose line-in or mic-in
#endif
#ifdef DEBUG
Serial.begin(115200);
#endif
// Initialize the SD card
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
// stop here if no SD card, but print a message
while (1) {
#ifdef DEBUG
Serial.println("Unable to access the SD card");
#endif
delay(500);
}
}
}
void loop() {
#if !defined TESTLINEIN && defined DEBUG
double bufferedTime=spdifIn.getBufferedTime();
#endif
// First, read the button
buttonRecord.update();
// Respond to button presses
if (buttonRecord.fallingEdge())
{
#ifdef DEBUG
Serial.println("-------------------");
Serial.println("Record Button Press");
Serial.println("-------------------");
#endif
if (mode == 0) startRecording();
}
else
{
if (mode == 1)
{
// If we'rerecording, carry on...
#ifdef BUG
continueRecording1();
#else
continueRecording();
#endif
}
else
{
if (mode==2)
{
// Stop Recording
stopRecording();
}
}
}
#if !defined TESTLINEIN && defined DEBUG
if (millis() - last_time >= 2500)
{
Serial.print("buffered time [micro seconds]: ");
Serial.println(bufferedTime*1e6,2);
Serial.print("locked: ");
Serial.println(spdifIn.isLocked());
Serial.print("input frequency: ");
double inputFrequency=spdifIn.getInputFrequency();
Serial.println(inputFrequency);
Serial.print("anti-aliasing attenuation: ");
Serial.println(spdifIn.getAttenuation());
Serial.print("resampling goup delay [milli seconds]: ");
Serial.println(spdifIn.getHalfFilterLength()/inputFrequency*1e3,2);
Serial.print("half filter length: ");
Serial.println(spdifIn.getHalfFilterLength());
double pUsageIn=spdifIn.processorUsage();
Serial.print("processor usage [%]: ");
Serial.println(pUsageIn);
Serial.print("max number of used blocks: ");
Serial.println(AudioMemoryUsageMax());
last_time=millis();
}
#endif
}
void startRecording()
{
#ifdef DEBUG
Serial.println("--------------");
Serial.println("startRecording");
Serial.println("--------------");
#endif
// 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.
#ifdef TESTLINEIN
if (SD.exists("linein.raw"))
{
SD.remove("linein.raw");
}
frec = SD.open("linein.raw", FILE_WRITE);
#else
if (SD.exists("spdif.raw"))
{
SD.remove("spdif.raw");
}
frec = SD.open("spdif.raw", FILE_WRITE);
#endif
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
#ifdef DEBUG
elapsedMicros usec = 0;
#endif
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 queue 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.
#ifdef DEBUG
Serial.print("SD write, us=");
Serial.println(usec);
#endif
if (nbiter<1722) nbiter++; //440832 samples (approx. 10sec) stored in SDCARD before stopRecording
else mode=2; //stopRecording
}
}
void continueRecording1()
{
int i,m=12; //12 corresponds to 35 ms of 44100Hz samples, not 301.7 ms as announced
if (queue1.available() >= m)
{
for (i=0;i<m;i++)
{
queue1.freeBuffer();
}
elapsedMicros usec = 0;
Serial.print("SD write, us=");
Serial.println(usec);
mode=2; //stopRecording
}
}
void stopRecording()
{
#ifdef DEBUG
Serial.println("-------------");
Serial.println("stopRecording");
Serial.println("-------------");
#endif
queue1.end();
while (queue1.available() > 0)
{
frec.write((byte*)queue1.readBuffer(), 256);
queue1.freeBuffer();
}
frec.close();
nbiter=0;
mode = 0;
}