Audio Library

Status
Not open for further replies.
By the way - when using the Adafruit_Neopixel library, plus the teensy Audio library, the audio I hear throw the audio board's output jack is terribly distorted.

Can you post some details about how you've connected things? How many NeoPixels are you lighting up? Are they powered from USB, or another power supply? Maybe a photo of the wiring would help?
 
Help -- need an example

I'm trying to get started with the Audio Library, but I can't figure out where to start.

I imported the Audio Library from Github into my Arduino setup and can compile and run the FFT example. I don't have my audio board hooked up to my Teensy, but I'm not sure it is necessary for what I want to do.

I'd like to understand the AudioAnalyzeFFT256 function, so I thought I could create a sinewave signal (or two and add them), and print out its FFT; so I copied the
Code:
AudioSynthWaveform       sine1(AudioWaveformSine);  // 2 sine wave
line from the DTMF example and added it the the FFT example -- it doesn't compile.

What am I doing wrong ? Could someone post a short example showing a self-contained FFT example (i.e. that doesn't use the audio board) where I can set the input data and print the output ?

Is there any documentation on the Audio Library other then browsing the code itself ?

Thanks
 
I changed the way the recent version of AudioSynthWaveform works. I should probably change it back.
In the meantime here's a sketch which uses only the wave synthesis and FFT and outputs the results to the serial monitor (@115200 baud).
You do not need to have an audio card attached.

Pete

Code:
#include <Audio.h>
#include <Wire.h>
// This is required even if it isn't used
#include <SD.h>

/*
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 = NULL;
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 type = TONE_TYPE_SINE;
// The width of each FFT bin is 44100/256 = 172.265625Hz
// 861Hz falls in the middle of a bin: 861 = 5*172.265625
#define TONE_FREQ 861
// Length of the tone
#define TONE_LENGTH_MS 1000
// 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;
// tone amplitude
float t_amp = 0.9;
char *wave_names[4] = {
  "sine",
  "sawtooth",
  "square",
  "triangle"
};
AudioSynthWaveform     myEffect;

// This must be defined even if it isn't used
AudioOutputI2S      audioOutput;

// Connect the tone generator to the FFT analysis
AudioConnection c2(myEffect, 0, myFFT, 0);


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);

  // Start the tone generator with zero amplitude
  myEffect.begin(t_amp,TONE_FREQ,type);
  
  // Print out the current settings
  Serial.print("tone_freq = ");
  Serial.print(TONE_FREQ);
  Serial.print(", ");
  Serial.print(wave_names[type]);
  Serial.print(", amplitude = ");
  Serial.print(t_amp,4);
  Serial.print(", FFT = ");
  Serial.print(num_avg);
  Serial.print(", ");
  Serial.println(window_name(window));
}


unsigned long last_time;

void loop() {

  if(tone_count) {
    if(0) {
      Serial.print("tone_count = ");
      Serial.print(tone_count);
      Serial.print("tone_state  = ");
      Serial.println(tone_state);
    }
    
    // This generates the tone on-the-fly so that the FFT
    // analyser can 'see' it
    switch(tone_state) {
    case 0:  // Start the tone generator and timer
      myEffect.amplitude(t_amp);
      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;
      myEffect.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("");
    }
  }
}
 
@el_supremo: Your FFT demo code works fine for me, on a T3.1 without the audio card. I'd like to try some different FFT windowing functions but not sure how to specify them, can you show me a non-NULL example?

Code:
// 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 = NULL;

Contrary to my understanding of the comment, if I do not initialize *window at all, the code Serial.println(window_name(window)); still prints out "NONE" instead of "Hanning" as I expected.

UPDATE: nevermind, I found out what I wanted to do:
Code:
const int16_t *window = AudioWindowHanning256;
 
Last edited:
still prints out "NONE" instead of "Hanning" as I expected.
That's because the code which determines the name of the window uses the 'window' variable which is set to NULL (whether you explicitly set it or not).
If you specify the FFT like this:
Code:
AudioAnalyzeFFT256  myFFT(num_avg);
it can't detect that you are using the default in this case either.
If you are going to be relying on the window name in the debugging output, it is best to explicitly set 'window' to whichever window you want to use.

Pete
 
Here's another sketch to play with. This one generates two tones, mixes them together and then analyzes them with the FFT. The wave shape, frequency and amplitude of the two tones can be independently varied.

Pete

Code:
#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("");
    }
  }
}
 
Here's another sketch to play with. This one generates two tones, mixes them together and then analyzes them with the FFT. The wave shape, frequency and amplitude of the two tones can be independently varied.

Pete

Thanks -- the 1st worked great and I was starting to try to figure out the 2nd on my own.
 
Thanks for 2nd FFT example, very good!

Separate question: based on the setting of CHIP_CLK_CTRL in C:\Program Files\Arduino\libraries\Audio\control_sgtl5000.cpp it looks like I can set the chip's sample rate as slow as 32kHz / 6 = 5.33 kHz, is that correct? With that setting, presumably the 256-bin FFT would have a frequency resolution of 5.33 kHz / 256 = 21 Hz (of course with the tradeoff in maximum frequency).

UPDATE: Well, I edited the control_sgtl5000.cpp file as below, thinking that the sample clock would be slower and the spectrum spread out 6x, but it seems to have made no difference at all (at least, just looking at a FFT of 60 Hz noise coming into the MIC input).
Code:
// write(CHIP_CLK_CTRL, 0x0004);  // 44.1 kHz, 256*Fs
   write(CHIP_CLK_CTRL, 0x0034);  // 44.1 kHz and 1/6 rate  (JPB 25 MARCH 2014)
 
Last edited:
@Paul:

- Is there a problem with my pull request which fixes a problem in AudioSynthToneSweep?

- I have another addition to the Audio library almost ready to go - recording to the uSD card (but at the moment it can record only mono synthesized audio, NOT audio from the DACs). I see in SD2Card.cpp that the SPI speed is initialized to its lowest value - spiInit(6) on line 430. Is that required because of some interaction in the audio library? Can it be increased without blowing something up?

Pete
 
Last edited:
Hi! this is my situation. I'm having a little problem reading an analog signal with my teensy 3.1 + Audio Adaptor Board. I'm using it to measure a DC voltaje from a potentiometer connected between 3.3 V and AGND, the code is exactly like the one in the example "AnalogImput". It is really simple! but when I see the values in the serial port it just shows 1023, 1023, 1023,..., the value of the DC is 0.8 V at the input of A0...I did this before without the Audio Adaptor Board connected to the Teensy 3.1 and it worked! the value was changing with the rotation of the potentiometer. I tried with A1, A2, and nothing changed the problem persists...I don't know what is happening, anyone ever had this problem before?, please I need some help to solve this.

Thanks
 
Hi, no it didn't worked. I've tried all analog pins, without result. this is the code that i´m using. I dont think thats the problem

void setup()
{
Serial.begin(38400);
}

int val;

void loop()
{
val = analogRead(10);
Serial.print("analog 10 is: ");
Serial.println(val);
delay(100);
}
 
Your sketch works for me on pin A2. I used a 10k resistor to pull it high or low and the output on the serial monitor changes properly.

Pete
 
I used a 5k potentiometer between 3.3 V , A2 , AGND connected in that order, but the serial monitor keeps showing 1023. When I put the A2 pin to AGND it should be in 0 but it remain in 1023. That confuse me!
Sometimes when I hold the pin with my hand the value in the serial monitor changes and goes down to 0 and then it goes back to 1023 when I release the pin, sometimes.
I really don't know what is happening...
 
I used a 5k potentiometer between 3.3 V , A2 , AGND connected in that order, but the serial monitor keeps showing 1023. When I put the A2 pin to AGND it should be in 0 but it remain in 1023.

If you're running the code in reply #462, it's reading the wrong pin. You need analogRead(A2), not analogRead(10).

If the code is correct, perhaps there's a physical wiring problem? Maybe a photo would help us to see what's wrong?
 
I believe his use of analogRead(10) was due to me...I suggested the pin in a post I deleted after Pete posted complete information. I didn't have the reference handy to the pins in use by the audio shield and suggested the "standalone" analog pins.
 
Hi Paul,
is it possible to read form an analog input of teensy while using the AudioAnalogInput of the Audio Library?
I would like to acquire an analog signal (ecg) while the mic is getting audio signals.

It would be great to have two AudioAnalogInput object running in parallel (one for audio, and one at lower sample rate for the other analog signal). In this why I could make some processing on the analog signal seamlessly as for the audio stream (just with different blocks).
Or in alternative, can I just use the analogRead in the maim loop with an IntervalTimer?

Thank you,
Enrico
 
is it possible to read form an analog input of teensy while using the AudioAnalogInput of the Audio Library?

No. Or at least not with analogRead.

On Teensy 3.1 there are 2 ADCs. Perhaps Pedvide's ADC library can use the other one? I have not tried this, so I do now know if it works.

But I do know if you try to use ADC0 while the audio library is using it with DMA and interrupts, things will not work and your program will very likely crash.
 
No. Or at least not with analogRead.

On Teensy 3.1 there are 2 ADCs. Perhaps Pedvide's ADC library can use the other one? I have not tried this, so I do now know if it works.

But I do know if you try to use ADC0 while the audio library is using it with DMA and interrupts, things will not work and your program will very likely crash.

Thanks, Paul.
I'm gonna have a look to Pedvide's ADC library.
I was thinking, would it be possible to create another object like AudioInputAnalog1, that uses instead ADC1?

Enrico
 
Thanks, Paul.
I'm gonna have a look to Pedvide's ADC library.
I was thinking, would it be possible to create another object like AudioInputAnalog1, that uses instead ADC1?
Enrico

It looks like that ADC library is currently limited to ADC0 and register A, but it should be relatively straightforward to extend it to ADC1.
I'd think it would be easier to work on that library than the Audio library, since you wouldn't have to worry about the DMA or PDB configurations there.
Mostly just find all the registers prefixed with ADC0_ and replace them with ADC1_
 
@Paul:

- Is there a problem with my pull request which fixes a problem in AudioSynthToneSweep?

- I have another addition to the Audio library almost ready to go - recording to the uSD card (but at the moment it can record only mono synthesized audio, NOT audio from the DACs). I see in SD2Card.cpp that the SPI speed is initialized to its lowest value - spiInit(6) on line 430. Is that required because of some interaction in the audio library? Can it be increased without blowing something up?

Pete

+1 + Don't spare my feelings.
 
By the way - when using the Adafruit_Neopixel library, plus the teensy Audio library, the audio I hear throw the audio board's output jack is terribly distorted.
If I comment out strip.show() in my code though, it sounds fine.
I wonder if that has something to do with my audio FFT problems? :(

Sorry for the delay in getting back to this.

I discovered that by changing my code to use the FastLED (ver 2.1) library to control the LEDs, the problem of distorted audio went away.

My guess is that the Adafruit_Neopixel library was halting interrupts and causing the problem that way? (I think the FastLED library uses some of the Teensy's abilities to offload the work, like the Octows2811.
 
foto.pngIMG_1628.jpgIMG_1629.jpg
Hi Paul,
This is the way that i am wiring the teensy to the Pot. I am showing in a picture what is the value of the A6 in the DVM and the values with Serial Monitor.

Thanks,

juan.
 
Last edited:
Hi,
I have a question about teensy 3.1 + Audio Adaptor. I need to reproduce a short sound like a beep with some frecuency (beep....beep....beep) during this reproduction the teensy has to evualuate other parameters and depending of this, the sound will change. I need something like multitask, where while teensy are in task1, the task2 are running also. The task2 for me is to reproduce a sound again and again......, until I change the new sound and reproduce like the previos one. And task 1 is the mensure of different parameters that change the sound in task2. Is this possible on teensy 3.1?

thanks,

Juan.
 
You can use AudioSynthWaveform to generate a beep and you can turn it on and off by changing its amplitude at regular intervals. You can also change the frequency and even the wave type (sine, square, triangle, sawtooth).
The timing will just be a variation of the BlinkWithoutDelay example.

Pete
 
Status
Not open for further replies.
Back
Top