#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#define DEBUG
#define PASSTHRU
#define USE_SD
//#define USE_FIR
#ifdef USE_SD
AudioPlaySdWav playSdWav1;
AudioOutputUSB audioOutput; //Puts digital samples to Audacity input (MME, digital audio interface) for recording to wav file
#else
AudioInputI2S i2s1;
#endif
#ifdef USE_FIR
AudioFilterFIR fir1;
AudioFilterFIR fir2;
#endif
AudioRecordQueue queue3;
AudioRecordQueue queue1;
AudioPlayQueue queue2;
AudioPlayQueue queue4;
AudioOutputI2S i2s2;
#ifdef USE_FIR
#ifdef USE_SD
AudioConnection patchCord1(playSdWav1, 0, fir1, 0);
AudioConnection patchCord2(playSdWav1, 1, fir2, 0);
#else
AudioConnection patchCord1(i2s1, 0, fir1, 0);
AudioConnection patchCord2(i2s1, 1, fir2, 0);
#endif
AudioConnection patchCord3(fir1, queue1);
AudioConnection patchCord4(fir2, queue3);
#else //#ifdef USE_FIR
#ifdef USE_SD
AudioConnection patchCord1(playSdWav1, 0, queue1, 0);
AudioConnection patchCord2(playSdWav1, 1, queue3, 0);
#else
AudioConnection patchCord1(i2s1, 0, queue1, 0);
AudioConnection patchCord2(i2s1, 1, queue3, 0);
#endif
#endif //#ifdef USE_FIR
AudioConnection patchCord5(queue2, 0, i2s2, 0);
AudioConnection patchCord6(queue4, 0, i2s2, 1);
#ifdef USE_SD
AudioConnection patchCord7(queue2, 0, audioOutput,0);
AudioConnection patchCord8(queue4, 0, audioOutput,1);
#endif
AudioControlSGTL5000 sgtl5000_1;
#ifdef USE_SD
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
#else
//const int myInput = AUDIO_INPUT_MIC;
const int myInput = AUDIO_INPUT_LINEIN;
#endif
#ifdef USE_FIR
//---------------------------------------------FIR parameters ---------------------
#define NUM_COEFFS 50
//Arbitrary xfer function using fft for hpf fc=4000 fir filter design - (choice no. 13 of calcfilt.m)
double coefs1[] =
{
#include "num.h"
};
double coefs2[] =
{
#include "num.h"
};
short int COEFS1[NUM_COEFFS];
short int COEFS2[NUM_COEFFS];
//---------------------------------------------------------------------------------
#endif //#ifdef USE_FIR
int32_t agcGain1=0x08000000;//.5 in Q3.29 format
int32_t agcGain2=0x08000000;//.5 in Q3.29 format
int32_t ref=293504;//.07*AUDIO_BLOCK_SAMPLES in Q15 format(2293*128)
void setup() {
Serial.begin(9600);
delay(300);
// allocate memory for the audio library
AudioMemory(32);
sgtl5000_1.enable();
sgtl5000_1.volume(0.5);
#ifdef USE_SD
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
delay(1000);
#else
sgtl5000_1.inputSelect(myInput);
#endif
#ifdef USE_FIR
// Initialize the filter
transformCoeffs( COEFS1, coefs1, NUM_COEFFS );
transformCoeffs( COEFS2, coefs2, NUM_COEFFS );
fir1.begin(COEFS1,NUM_COEFFS);
fir2.begin(COEFS2,NUM_COEFFS);
#endif
// Start the record queue
queue1.begin();
queue3.begin();
#ifdef DEBUG
Serial.println("setup done");
#endif
}
// audio volume
int volume = 0;
unsigned long last_time = millis();
void loop()
{
#ifdef USE_SD
if (playSdWav1.isPlaying() == false)
{
Serial.println("Start playing");
playSdWav1.play("Tower.wav");
// playSdWav1.play("multisin.wav");
// playSdWav1.play("noise.wav");
delay(10);
}
#endif
//--------------------------- Left channel -----------------------------
if (queue1.available() >= 1) //Left Channel
{
agcCalc(queue1.readBuffer(),queue2.getBuffer(),&agcGain1);
// Free the input audio buffer
queue1.freeBuffer();
// and play it back into the audio queue
queue2.playBuffer();
} //if (queue1.available() >= 1)
//--------------------------- Right channel -----------------------------
if (queue3.available() >= 1)
{
agcCalc(queue3.readBuffer(),queue4.getBuffer(),&agcGain2);
// Free the input audio buffer
queue3.freeBuffer();
// and play it back into the audio queue
queue4.playBuffer();
} //if (queue3.available() >= 1)
//--------------------------- Volume control -----------------------------
int n = analogRead(0);
if (n != volume)
{
volume = n;
sgtl5000_1.volume((float)n / 1023.);
//uncomment this line if your audio shield has the volume pot
//audioShield.volume((float)n / 1023);
}
//----------------------------- done --------------------------------------
#ifdef DEBUG
// print information about resource usage
// Proc = 18 (18), Mem = 4 (5)
if (millis() - last_time >= 2500)
{
Serial.print("Proc = ");
Serial.print(AudioProcessorUsage());
Serial.print(" % ");
Serial.print(" (");
Serial.print(AudioProcessorUsageMax());
Serial.print(" %), Mem = ");
Serial.print(AudioMemoryUsage());
Serial.print(" (");
Serial.print(AudioMemoryUsageMax());
Serial.println(")");
Serial.print(" agcGain1: ");
Serial.print((float)agcGain1/(float)0x10000000);
Serial.print(" agcGain2: ");
Serial.println((float)agcGain2/(float)0x10000000);
last_time = millis();
}
#endif
}
void transformCoeffs( short int out[], double in[], int k )
{
for ( int i = 0 ; i < k ; i++ )
out[i] = 32767 * in[i];
}
void agcCalc(int16_t *inbuf,int16_t *outbuf,int32_t *agcGain)
{
int16_t *bp1=inbuf,*bp2=outbuf;
#ifdef PASSTHRU
// Copy from input to output buffer
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++)
{
*bp2++ = *bp1++;
}
#else
// Apply agcGain on input with saturation to output buffer
int32_t sum=0,sum1=0,sum2=0,sum3=0,res,res1,res2,res3,err;
for(int i = 0;i < AUDIO_BLOCK_SAMPLES>>2;i++)
{
//ref. dspinst.h in Teensy audio library
res=signed_multiply_32x16b(*agcGain>>12,*bp1++);
res1=signed_multiply_32x16b(*agcGain>>12,*bp1++);
res2=signed_multiply_32x16b(*agcGain>>12,*bp1++);
res3=signed_multiply_32x16b(*agcGain>>12,*bp1++);
*bp2++=saturate16(res);
*bp2++=saturate16(res1);
*bp2++=saturate16(res2);
*bp2++=saturate16(res3);
sum+=abs(res);
sum1+=abs(res1);
sum2+=abs(res2);
sum3+=abs(res3);
}
sum+=(sum1+sum2+sum3);
// Calculate new agcGain for next input buffer
err=ref-sum;
*agcGain+=err>>3; //update gain
*agcGain=min(*agcGain,0x7ff80000); //keep agcGain < 8.0
*agcGain=max(*agcGain,0); //keep agcGain >= 0
#endif
}