Hello! For my project, I am trying to build a cube that records audio while a user is holding it (and then plays it back later). I'm using the Teensy 4.1 with Rev D audio shield, Adafruit's SPH0645 microphone (https://www.adafruit.com/product/3421), and the Max98306 amplifier breakout board (https://www.adafruit.com/product/987) to boost line out audio from the audio shield to a pair of speakers. Pictures of the current setup:
Currently the microphone records fine, saves to the SD card fine, and plays audio back fine (though there is a little noise and it is a little quiet).
For capacitive sensing I'm using the Capacitive Sensor library to run wires on pins 19 and 16 to create a capacitive sensing circuit, which also works fine on its own. (https://playground.arduino.cc/Main/CapacitiveSensor/)
The problem is that if I try and read a capacitive touch with capacitiveSensor during recording of audio, the audio can't record at the same time. I'm not that great at physical computing, and I can only imagine it's a problem of the microcontroller not being able to do both things at once, but I thought maybe someone else would have an idea of how to skirt around the problem. I tried only reading capacitive touch every two seconds, but even that resulted in an audible break in the recording. This is a problem because I need to know when the user has let go of the cube.
Current code is below -- some of the experimentation I was doing with averaging to smooth the signal is commented out. Thank you in advance for any advice!
Currently the microphone records fine, saves to the SD card fine, and plays audio back fine (though there is a little noise and it is a little quiet).
For capacitive sensing I'm using the Capacitive Sensor library to run wires on pins 19 and 16 to create a capacitive sensing circuit, which also works fine on its own. (https://playground.arduino.cc/Main/CapacitiveSensor/)
The problem is that if I try and read a capacitive touch with capacitiveSensor during recording of audio, the audio can't record at the same time. I'm not that great at physical computing, and I can only imagine it's a problem of the microcontroller not being able to do both things at once, but I thought maybe someone else would have an idea of how to skirt around the problem. I tried only reading capacitive touch every two seconds, but even that resulted in an audible break in the recording. This is a problem because I need to know when the user has let go of the cube.
Current code is below -- some of the experimentation I was doing with averaging to smooth the signal is commented out. Thank you in advance for any advice!
Code:
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Metro.h> // Include the Metro library
// GUItool: begin automatically generated code
AudioInputI2S2 i2s2_1; //xy=264.00000381469727,191.00000286102295
AudioAnalyzePeak peak1; //xy=766,134
AudioRecordQueue queue1; //xy=780,200
AudioFilterStateVariable filter1; //xy=422.00000762939453,191.00000190734863
AudioAmplifier amp1; //xy=545.0000076293945,192.00000286102295
AudioAnalyzeFFT1024 fft1024_1; //xy=829.0000114440918,297.00000190734863
AudioPlaySdRaw playSdRaw1; //xy=347.00000762939453,290.00000381469727
AudioOutputI2S i2s1; //xy=594,291
AudioConnection patchCord1(i2s2_1, 0, filter1, 0);
AudioConnection patchCord2(playSdRaw1, 0, i2s1, 0);
AudioConnection patchCord3(playSdRaw1, 0, i2s1, 1);
AudioConnection patchCord4(filter1, 2, amp1, 0);
AudioConnection patchCord5(amp1, fft1024_1);
AudioConnection patchCord6(amp1, queue1);
AudioConnection patchCord7(amp1, peak1);
AudioControlSGTL5000 sgtl5000_1; //xy=510.00000762939453,403.0000057220459
// GUItool: end automatically generated code
// 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=playing, 3=stopped
long int currentFile = 0;
// The file where data is recorded
File frec;
//CAPSENSE STUFF
#include <CapacitiveSensor.h>
CapacitiveSensor cs_19_16 = CapacitiveSensor(19,16); // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired
//currently using 1M resistor
//int capTotalOld;
//int capTotal;
Metro capSenseMetro = Metro(2000); // Instantiate an instance
void setup() {
cs_19_16.set_CS_AutocaL_Millis(0xFFFFFFFF); // turn off autocalibrate on channel 1 - just as an example
// 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.7);
sgtl5000_1.lineOutLevel(15);
//for microphone
filter1.frequency(30); // filter out DC & extremely low frequencies
amp1.gain(8.5); // amplify sign to useful range
// 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) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
}
void loop() {
//CAPSENSE AVERAGING
//---------------------------------
long start = millis();
//average = 0;
//check if 2 seconds have passed
if (capSenseMetro.check() == 1) {
long total1 = cs_19_16.capacitiveSensor(30);
}
/*//long total1 = cs_19_16.capacitiveSensor(30);
for (int i = 0; i < 30; i++) {
long total1 = cs_19_16.capacitiveSensor(30);
average += total1;
}
average /= 30;*/
/*if((average - oldAverage) > 500 && touchState == 0 && oldAverage != 0) {
Serial.println("touch started");
storedValue = oldAverage;
touchState = 1;
//Serial.println(storedValue);
}
if(touchState == 1 && (average < storedValue)) {
touchState = 0;
Serial.println("stopped touching");
}*/
//--------------------------------
//RECORDING STUFF
if (millis() > 7000 && mode == 1) {
stopRecording();
delay(1000);
startPlaying();
} else if (mode == 1) {
continueRecording();
}
if (millis() > 2000 && mode == 0) {
startRecording();
}
// If we're playing or recording, carry on...
if (mode == 1) {
continueRecording();
}
if (mode == 3) {
continuePlaying();
}
//oldAverage = average;
}
void startRecording() {
Serial.println("startRecording");
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");
}
frec = SD.open("RECORD2.RAW", FILE_WRITE);
if (frec) {
queue1.begin();
mode = 1;
}
}
void continueRecording() {
//Serial.println("Recording....");
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);
}
if (fft1024_1.available()) {
// each time new FFT data is available
// print 20 bins to the Arduino Serial Monitor
Serial.print("FFT: ");
for (int i = 0; i < 20; i++) {
float n = fft1024_1.read(i);
if (n >= 0.001) {
Serial.print(n, 3);
Serial.print(" ");
} else {
Serial.print(" -- "); // don't print "0.000"
}
}
Serial.println();
}
}
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 = 3;
}
void startPlaying() {
Serial.println("startPlaying");
playSdRaw1.play("RECORD2.RAW");
mode = 2;
}
void continuePlaying() {
if (!playSdRaw1.isPlaying()) {
playSdRaw1.stop();
mode = 4;
}
}
void stopPlaying() {
Serial.println("stopPlaying");
if (mode == 2) playSdRaw1.stop();
mode = 3;
}