#include <Audio.h>
#include <Wire.h>
// This is required even if it isn't used
#include <SD.h>
// undefine this if you haven't got the audio board connected
//#define GENERATE_AUDIO
/*
ce
Modify to use two tone generation
cd
Strip the LCD and audio output from previous versions so that
this outputs only to the Serial monitor.
But note that AudioOutputI2S must be defined even though it isn't
used directly
*/
// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
// myFFT averages a specified number of consecutive 'frames'
// before outputting a spectrum. The default is 20.
int num_avg = 16;
// specify the window type. If none is specified (the argument is
// absent) then the default is the Hann(ing) window.
// Specifying NULL means no window is used
const int16_t *window = AudioWindowHanning256;
AudioAnalyzeFFT256 myFFT(num_avg,window);
// This table allows the program to map the window address back into its name
// for debugging output
struct map_window_name {
const char *name;
const int16_t *array;
}
map_win_name[] = {
// The first entry MUST be the default
{ "Hanning", AudioWindowHanning256 },
{ "Bartlett", AudioWindowBartlett256 },
{ "Blackman", AudioWindowBlackman256 },
{ "Flattop", AudioWindowFlattop256 },
{ "BlackmanHarris", AudioWindowBlackmanHarris256 },
{ "Nuttall", AudioWindowNuttall256 },
{ "BlackmanNuttall", AudioWindowBlackmanNuttall256 },
{ "Welch", AudioWindowWelch256 },
{ "Hamming", AudioWindowHamming256 },
{ "Cosine", AudioWindowCosine256 },
{ "Tukey", AudioWindowTukey256 },
{ "Unknown", NULL },
};
// Map a window array address into its name
const char *window_name(const int16_t *ar)
{
int i;
if(ar == NULL)return("NONE");
for(i=0;map_win_name[i].array != NULL;i++) {
if(ar == map_win_name[i].array)return(map_win_name[i].name);
}
return(map_win_name[i].name);
}
// Type of tone. SINE, SAWTOOTH, SQUARE or TRIANGLE
short type1 = TONE_TYPE_TRIANGLE;
short type2 = TONE_TYPE_SINE;
// The width of each FFT bin is 44100/256 = 172.265625Hz
// If you set the frequency as a multiple of 172.266 you
// can make the frequency fall in the middle or on the edge
// of a bin.
#define TONE_FREQ_1 ((15 * 172.265625) + 0.5)
#define TONE_FREQ_2 ((7 * 172.265625) + 0.5)
// If you are playing the audio through the line-out to a PC
// you may have to reduce the amplitudes to about .1 so that
// you don't overdrive the PC's line-input.
#define TONE_AMP_1 .9
#define TONE_AMP_2 .9
// Length of the tones
#define TONE_LENGTH_MS 2000
// Spacing between tones
#define SILENCE_LENGTH_MS 200
// Number of DAHs to send
// When sending to the serial monitor it isn't worth setting this
// to anything other than 1
int tone_count = 1;
// state of tone generator
int tone_state = 0;
char *wave_names[4] = {
"sine",
"sawtooth",
"square",
"triangle"
};
AudioSynthWaveform myEffect1;
AudioSynthWaveform myEffect2;
AudioMixer4 mixer1;
// This must be defined even if it isn't used
AudioOutputI2S audioOutput;
// Connect tone1 to one input on the mixer
// and tone2 to another input
AudioConnection c1(myEffect1, 0, mixer1, 0);
AudioConnection c2(myEffect2, 0, mixer1, 1);
// Connect the output of the mixer to the FFT analyzer
AudioConnection c3(mixer1, 0, myFFT, 0);
#ifdef GENERATE_AUDIO
// Send the mixer output to the left and right audio channels
AudioConnection c4(mixer1, 0, audioOutput, 0);
AudioConnection c5(mixer1, 0, audioOutput, 1);
// Create an object to control the audio shield.
AudioControlSGTL5000 audioShield;
#endif
void setup() {
Serial.begin(115200);
while(!Serial);
delay(2000);
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(12);
#ifdef GENERATE_AUDIO
// Enable the audio shield and set the output volume.
audioShield.enable();
// audioShield.inputSelect(myInput);
audioShield.volume(60);
// I want output on the line out too
audioShield.unmuteLineout();
// audioShield.muteHeadphone();
#endif
// Print out the current settings
Serial.print("tone_1_freq/amp/type = ");
Serial.print(TONE_FREQ_1);
Serial.print("/");
Serial.print(TONE_AMP_1,4);
Serial.print("/");
Serial.print(wave_names[type1]);
Serial.print(", tone_2_freq/amp/type = ");
Serial.print(TONE_FREQ_2);
Serial.print("/");
Serial.print(TONE_AMP_2,4);
Serial.print("/");
Serial.print(wave_names[type2]);
Serial.print(", FFT = ");
Serial.print(num_avg);
Serial.print(", ");
Serial.println(window_name(window));
// Start the tone generators
myEffect1.set_ramp_length(44);
myEffect1.begin(TONE_AMP_1,TONE_FREQ_1,type1);
myEffect2.set_ramp_length(44);
myEffect2.begin(TONE_AMP_2,TONE_FREQ_2,type2);
}
unsigned long last_time;
void loop() {
if(tone_count) {
switch(tone_state) {
case 0: // Start the tone generator and timer
myEffect1.amplitude(TONE_AMP_1);
myEffect2.amplitude(TONE_AMP_2);
last_time = millis();
// Wait for timer to expire
tone_state = 1;
break;
case 1: // Wait for timer to expire
if(millis() - last_time < TONE_LENGTH_MS)break;
myEffect1.amplitude(0);
myEffect2.amplitude(0);
// Now "send" silence
tone_state = 2;
last_time = millis();
break;
case 2:
if(millis() - last_time < SILENCE_LENGTH_MS)break;
// count this tone and then reset for next one
tone_count--;
tone_state = 0;
break;
}
}
if(tone_count) {
if (myFFT.available()) {
for(int i=0;i < 128;i++) {
Serial.print(myFFT.output[i]);
Serial.print(", ");
}
Serial.println("");
}
}
}