amazingrolo
Member
I'm just getting started with the audio shield and audio library, it's great fun.
I'm working on a little test sampler which records a single channel of audio. That part works great.
I'd also like to use a potentiometer to control a filter on the playback. It's just about working in the sense that I can hear the filter, however there is also loads of crackly noise. I'm nearly certain that this is a result of the filter frequency value being updated hundreds of times a second from the analogRead() reading from the potentiometer.
What's the best way to avoid this? I'd like to have the potentiometer readings update as fast as possible, to get nice smooth control of the filter.
Thanks
(code below, though it's a total mess!)
I'm working on a little test sampler which records a single channel of audio. That part works great.
I'd also like to use a potentiometer to control a filter on the playback. It's just about working in the sense that I can hear the filter, however there is also loads of crackly noise. I'm nearly certain that this is a result of the filter frequency value being updated hundreds of times a second from the analogRead() reading from the potentiometer.
What's the best way to avoid this? I'd like to have the potentiometer readings update as fast as possible, to get nice smooth control of the filter.
Thanks
(code below, though it's a total mess!)
Code:
// 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
AudioPlaySdRaw playRaw1; //xy=190,295
AudioInputI2S i2s1; //xy=226,112
AudioFilterBiquad biquad1; //xy=399,354
AudioRecordQueue queue1; //xy=431,191
AudioOutputI2S i2s2; //xy=768,436
AudioConnection patchCord1(playRaw1, biquad1);
AudioConnection patchCord2(i2s1, 0, queue1, 0);
AudioConnection patchCord3(i2s1, 1, queue1, 0);
AudioConnection patchCord4(biquad1, 0, i2s2, 0);
AudioConnection patchCord5(biquad1, 0, i2s2, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=281,607
// GUItool: end automatically generated code
const int numReadings = 400;
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 = 20;
// 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);
float filtercontrol;
float filterfreqcal = 15000;
// 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);
pinMode(3, INPUT_PULLUP);
biquad1.setLowpass(0, 15000, 0.707);
// 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.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
buttonRecord.update();
buttonStop.update();
buttonPlay.update();
setFilter();
// 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 (mode == 2) 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.play("RECORD.RAW");
// mode = 0;
}
}
void stopPlaying() {
Serial.println("stopPlaying");
if (mode == 2) playRaw1.stop();
mode = 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,15000);
biquad1.setLowpass(0, filtercontrol, 0.707);
Serial.println(average);
}
void adjustMicLevel() {
// TODO: read the peak1 object and adjust sgtl5000_1.micGain()
// if anyone gets this working, please submit a github pull request :-)
}