Audio Library

Status
Not open for further replies.
Is the best way to do this by creating my own audio object in the library and using the following format?:

Yes, exactly.

It doesn't have to be inside Audio.h and Audio.cpp. Just use #include "AudioStream.h" and you can put it anywhere.

Code:
	} else {
		//What should/can I do in here?

Usually you would just return without doing anything. You're not required to transmit audio. Other objects that receive are supposed to treat a lack of data as if it were incoming silence. The 3 objects that actually move output data off-chip actually do substitute a block of silent output for any update() when data doesn't arrive.
 
In Audio.h, a comment explaining the magic numerical value would be welcome
Code:
phase_increment = (freq / AUDIO_SAMPLE_RATE_EXACT) * 4294967296.0f;
or, if it is used in multiple places, perhaps define it as a named constant and put the comment there.
 
Paul, if you ever respin the PCBs for the Audio board and the WIZ820io & Micro SD board, it might be helpful to some to have the pin numbers on the bottom of the shield like you do on the bottom of the Teensy 3.0's and 3.1's. While I need to reorganize things, my current soldering station is on a different floor than the computer, so I will have to be careful to solder my audio board in the correct orientation when I get enough time to solder it up.

Also, in posting this, I wonder if the SD card slots on the Audio and WIZ820io boards would interfere with each other if you decided to mount both boards on the same Teensy.
 
Last edited:
Hi Paul and everyone
I just got the Teensy 3.1 and the audioShield and was able to do a full roundtrip (mic->device->headphone), :eek:
This thread talk allot about SD read but what about SD write?
Do you think that the Teensy+audioShield is capable of writing 44.1khz mono wav/mp3 file from the analog input?
 
I've added an AudioFilterBiquad object to the library. The only documentation at this point is a new Filter example, from File > Examples > Audio > Filter.

https://github.com/PaulStoffregen/Audio

if you want to give it a try with a different filter response that the 800 Hz low pass in the example, here's the part you edit:

Code:
// each filter requires a set up parameters
int myFilterParameters[] = {  // lowpass, Fc=800 Hz, Q=0.707
  3224322, 6448644, 3224322, 1974735214, -913890679, 0, 0, 0};

These first five numbers define the filter response. This website has the easiest calculator for the numbers:

http://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/

Take the 5 numbers from that web page and multiply by 1073741824 (which happens to be 2^30). On the last 2 numbers, also multiply by -1 (negative becomes positive and vise-versa).
 
In Audio.h, a comment explaining the magic numerical value would be welcome
Code:
phase_increment = (freq / AUDIO_SAMPLE_RATE_EXACT) * 4294967296.0f;
or, if it is used in multiple places, perhaps define it as a named constant and put the comment there.



Nantonos, the magic number is (2<<31). This would make sense if the phase depth is 32 bit.
 
Last edited:
Clipping with a notch filter

Trying to implement a notch filter using the BiQuad filter. The notch works but clips badly, suspect because the coefficients are large. I need about a 30db notch and I believe the Q was about 3. Any thought on getting more dynamic range out of the filter?


Code:
#include <Audio.h>
#include <Wire.h>
#include <SD.h>

//const int myInput = AUDIO_INPUT_LINEIN;
const int myInput = AUDIO_INPUT_MIC;

// each filter requires a set up parameters
int myFilterParameters[] = {  // notch, Fc=2175 Hz
  896456695, -1707514503, 896456695, 1707514503, -719171567, 0, 0, 0};

// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputI2S       audioInput;         // audio shield: mic or line-in
AudioFilterBiquad   myFilter(myFilterParameters);
AudioOutputI2S      audioOutput;        // audio shield: headphones & line-out

// Create Audio connections between the components
//
AudioConnection c1(audioInput, 0, audioOutput, 0);
AudioConnection c2(audioInput, 0, myFilter, 0);
AudioConnection c3(myFilter, 0, audioOutput, 1);

// Create an object to control the audio shield.
// 
AudioControlSGTL5000 audioShield;


void setup() {
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(12);

  // Enable the audio shield and set the output volume.
  audioShield.enable();
  audioShield.inputSelect(myInput);
  audioShield.volume(60);
}

elapsedMillis volmsec=0;

void loop() {
  // every 50 ms, adjust the volume
  if (volmsec > 50) {
    float vol = analogRead(15);
    vol = vol / 10.24;
    audioShield.volume(vol);
    volmsec = 0;
  }
}

}
 
I pulled the request on the Github repository to add the objects needed to use the Audio library with the Mikroe Audio Codec PROTO board (WM8731 in master mode, I2S module in slave mode).
I followed Paul's guidelines :
Perhaps the cleanest way to do this might be to have those 2 new classes inherit from the 2 existing ones? You'd probably only need to implement a different begin() and config_i2s(), and let the C++ inheritance reuse everything else. It's fine to change any of the I2S private members to protected, if necessary.

I added two objects, AudioInputI2Sslave and AudioOutputI2Sslave that inherit from the existing Audio*putI2S classes; to avoid configuring twice the DMA and the I2S module (which will lead to bugs, I assure that :D ), I overloaded the constructor in both superclasses adding a protected one that bypasses the modules initialization and lets the subclasses do their own initialization.

I also added the AudioControlWM8731master object, to set the WM8731 codec in master mode, and an example that plays a sinewave on the codec's output.

As I stated in some previous comment, the sinewave frequency is slightly higher than it should be, and as Paul said:
PaulStoffregen said:
The trouble with MCLK as an input is the timing won't necessarily be synchronous with the CPU. It's probably not a big deal if you don't use another other input or output objects that move audio on/off chip. But if you do, things can drift out of sync. I'm not even sure what will happen... if the result might be as benign as infrequent 3ms dropouts, or if the whole thing might crash hard?
I still gotta try these objects with the I2S input, will let you know of the effects.

In the meanwhile, you can check the pull request summary here: https://github.com/PaulStoffregen/Audio/pull/1 (I avoided to repeat these informations on the pull request's summary because the discussion about the library is here)
 
Trying to implement a notch filter using the BiQuad filter. The notch works but clips badly, suspect because the coefficients are large.

I tried it just now, but couldn't reproduce the problem. Well, at least not with the filter part. It's easy to get clipping by feeding in a waveform larger than the input range, or by setting the output volume over about 83 (if your digital signal is full scale).

Here's the code I used for testing. Instead of taking I2S input, I fed a full scale sine wave from AudioSynthWaveform into the filter. With the output volume at 82, I'm seeing a 3 Vp-p sine wave output. I tried several frequencies. Sure enough, around 2200 the output is filtered to almost nothing. I got large sine waves without clipping when testing low and high frequencies.

Code:
#include <Audio.h>
#include <Wire.h>
#include <SD.h>

int myFilterParameters[] = {  // notch, approx 2.2 kHz
  896456695, -1707514503, 896456695, 1707514503, -719171567, 0, 0, 0};

// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioSynthWaveform  sine(AudioWaveformSine);
AudioFilterBiquad   myFilter(myFilterParameters);
AudioOutputI2S      audioOutput;

// Create Audio connections between the components
//
AudioConnection c1(sine, 0, myFilter, 0);
AudioConnection c2(myFilter, 0, audioOutput, 1);

// Create an object to control the audio shield.
// 
AudioControlSGTL5000 audioShield;


void setup() {
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(12);

  // Enable the audio shield and set the output volume.
  audioShield.enable();
  audioShield.volume(82);
  
  sine.frequency(150);
  sine.amplitude(1.0);
}

void loop() {
}
 
WOW! About 20Hz bandwidth and good notch depth. I will have to dig and find out where the clipping is coming from. I have a mic hooked up to the mic input that sounds good in the pass through demo but is clipped to the point of non intelligibility when I put the filter in the path.
 
Looks like the problem was a (in my head/perception ) issue, with the volume around 80 I was unconsciously backing off the mic, when the level was around 60 I found myself talking much closer to the mic and louder resulting in clipping................go figure :)
 
Paul,
I have been trying to figure out what myFFT.outputin the FFTexample actually represents. Is it real^2+imag^2 or has the sqrt been taken? I am trying to come up with a db meter.
 
The audio adaptor is described as sampling at 44.1kHz. The audio chip, SGTL5000, can do several sampling rates including 48000Hz. Can the adaptor do 48000Hz?

Pete
 
Correct, so far there's absolutely no support for the W25Q128FV chip (other than a location to solder it).

The FFT object is magnitude only. Even then, it's currently buggy. There seems to be some sort of strange numerical range or precision problem. So far every attempt I've made (admittedly only a couple) has led back to the ARM math library. I don't want to claim there's definitely a bug in that library. At least not yet. This still needs more investigation. It's one of the many reasons the library is still considered "beta".

Code:
Can the adaptor do 48000Hz?

No, not really.

The main issue is the MK20 chip can't create a low-jitter MCLK needed for 48 kHz mode. If I2S_MDR_FRACT is set to anything other than 0 or 1, the MCLK output is terrible. Here's an old post from a few months ago where I tested this:

http://forum.pjrc.com/threads/24078...s-Would-You-Want?p=34652&viewfull=1#post34652

Luckily, the MK20's PLL runs at 96 MHz. MCLK is created with 96 * 2 / 17 = 11.294 MHz. When divided by 256, the audio sample rate is 44117.647 Hz.

However, if you use an external MCLK, and configure the codec chip in master mode, you can use a different sample rate. MickMad submitted a patch that's now in the library for I2S slave mode. In that mode, the codec provides the clocks and the audio library runs at whatever speed the external hardware wants. Normally the library lets you use any combination of objects, but if you're using the I2S slave objects, you must not use the other input or output objects.
 
Can the adaptor do 48000Hz?
[/code]

No, not really.

The main issue is the MK20 chip can't create a low-jitter MCLK needed for 48 kHz mode. If I2S_MDR_FRACT is set to anything other than 0 or 1, the MCLK output is terrible. Here's an old post from a few months ago where I tested this:

http://forum.pjrc.com/threads/24078...s-Would-You-Want?p=34652&viewfull=1#post34652

Luckily, the MK20's PLL runs at 96 MHz. MCLK is created with 96 * 2 / 17 = 11.294 MHz. When divided by 256, the audio sample rate is 44117.647 Hz.

Maybe this is a dumb comment but isn't 96 * 1/2 = 48 MHz. When divided by 1024, the audio sample rate is 48kHz. What am I missing here?
 
MCLK needs to be 256 times the sample rate, or 12.288 MHz for 48 kHz audio. For low jitter, the hardware can do integer division of 192 MHz.

Also, 48e6 / 1024 = 46875, which isn't 48000. But if 46875 were used, the hardware could create a 12 MHz MCLK with 192 MHz / 16.
 
Paul I am confused with the DTMF demo. How does the output of the audio synth objects get to the input of the tone decoder objects? I only see a connection between sine1, sine2 and the mixer and from the mixer to the output.
 
Paul I am confused with the DTMF demo. How does the output of the audio synth objects get to the input of the tone decoder objects?

It doesn't. The decoding is done on a real audio input.

For testing, I connected an actual telephone, using a 12V supply, resistor, capacitor and opamp to couple the signal to the audio input.


I only see a connection between sine1, sine2 and the mixer and from the mixer to the output.

Yup, that's for generating DTMF output, which is sent to the audio out.
 
I've started looking at the existing stuff, in Paul's audio library, for SGTL5000. This post is primarily to subscribe to this thread but I may as well announce my intentions at least a bit.

I'm interested in fleshing out the AudioControlSGTL5000 object as much as I can, based on having learned a fair deal about the SGTL5000 for my employer's purposes, I think I can offer it a fair bit.

My focus will be on things the codec can do without using I2S, I will post a list of what I propose to add or change in the next couple/few days and see where who points what from there I guess.
 
Status
Not open for further replies.
Back
Top