Audio Library

Status
Not open for further replies.
If I leave the CHIP_ANA_ADC_CTRL register at 0x0000, can I somehow measure the p-p volts of my line-in values. I realize the ADC makes them 2-byte integers, but does that mean 0x7fff represents 3.3 volts? 1.65 volts?
 
hey daperl, full scale on the inputs of the Audio Adapter is 3.3V and using signed (short) integers to represent that gives DEC values -32768 to 32767, where 32767 should represent +1.65V and -32767 should likewise represent -1.65V

If you use the AudioPeak object I added to the library it should be so that you can get a (not too unreasonably inaccurate) measure of Vp-p in by
Code:
float vpp=(3.3/65535)*AudPk.Dpp();


Before posting I tried experiment: Sig gen outputting 440Hz @ 1.76Vpp (according to reasonable scope, Tektronix TDS2022) and use of that simple formula above returned (average of) 1.76656, to do the experiment I used a simple addition to the StereoPeakMeter example in the library, I've set bold the line I added
Code:
/* Stereo peak meter example, assumes Audio adapter but just uses terminal so no more parts required.

This example code is in the public domain
*/

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

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

AudioInputI2S        audioInput;         // audio shield: mic or line-in
AudioPeak            peak_L;
AudioPeak            peak_R;
AudioOutputI2S       audioOutput;        // audio shield: headphones & line-out

AudioConnection c1(audioInput,0,peak_L,0);
AudioConnection c2(audioInput,1,peak_R,0);
AudioConnection c3(audioInput,0,audioOutput,0);
AudioConnection c4(audioInput,1,audioOutput,1);

AudioControlSGTL5000 audioShield;


void setup() {
  AudioMemory(6);
  audioShield.enable();
  audioShield.inputSelect(myInput);
  audioShield.volume(0.75);
  audioShield.unmuteLineout();
  Serial.begin(Serial.baud());
}

elapsedMillis fps;
uint8_t cnt=0;

void loop() {
  
  if(fps>24) { // for best effect make your terminal/monitor a minimum of 62 chars wide and as high as you can.
    Serial.println();
    fps=0;
    uint8_t leftPeak=peak_L.Dpp()/2184.5321; // 65536 / 2184.5321 ~ 30.
    for(cnt=0;cnt<30-leftPeak;cnt++) Serial.print(" ");
    while(cnt++<30) Serial.print("<");
    Serial.print("||");
    uint8_t rightPeak=peak_R.Dpp()/2184.5321;
    for(cnt=0;cnt<rightPeak;cnt++) Serial.print(">");
    while(cnt++<30) Serial.print(" ");
    [B]Serial.printf(" Vpp=%f",(float)(3.3/65535)*peak_L.Dpp());[/B]

    peak_L.begin(); // no need to call .stop if all you want
    peak_R.begin(); // is to zero it.
  }
}
 
Has anybody implemented any "overlap and add" type of algorithm with this audio library? I'd like to understand how to use the library data structure to implement filtering algorithms via FFT, vocoder, etc.
Thanks
 
I2S Data Frame size

Plan to use a DAC in Master mode (Teensy in I2S Slave Mode). I know playing WAV files is restricted to 44.2K and 16bit DATA. The requirement from the DAC is that the frame size be 32 bit (or 64*fs for the bitclock). Is this supported by the audio library? Thanks in advance...
 
@alfa66: hopefully someone else will chime in with a better answer but for now I'd recommend looking at a few objects in the library to see if the data structure becomes apparent enough to you to just proceed - if it doesn't become apparent quickly enough looking at it might arm you with more direct questions about it which are easier to answer 'piecemeal', as it were. I don't think there is anything that exactly qualifies as 'overlap and add' in there yet but there are FFT objects and others which show how the data is stored and fairly efficient ways to manipulate it - I haven't looked too closely at the FFT objects and maybe there is some form of 'overlap and add' there.

@glt: Your apparent desires aren't yet catered by the Audio Library. It is sampling awfully close to "CD quality", being 44.1K, not quite precise because actually sampling at (pretty sure) 44118 stereo samples per second when using the SGTL5000 as slave like the current version of the library does. I posted a way to start the SGTL5000 as master @ 96K a few posts back on this thread and a few posts before that Paul describes a method to implement 24 bit sampling which should be able to manage 32 bit sampling as well when it is written.
 
I'd like to understand how to use the library data structure to implement filtering algorithms via FFT, vocoder, etc.
Thanks

This page, and looking at some of the existing code, would be the best place to start.

http://www.pjrc.com/teensy/td_libs_AudioNewObjects.html

Technically, the library just moves blocks of 128 samples around between objects (actually, data is in shared copy-on-write buffers, not actually moved). Most objects work on a single 128 sample block. The 256 point FFT uses 2 blocks as a queue and does 50% overlap and applies a window before running the FFT. If you're going to implement new objects, it's up to you how you wish to handle the samples. The library tries to offer a lot of flexibility, while also making the simple "just operate on a single block" case relatively easy.
 
The requirement from the DAC is that the frame size be 32 bit (or 64*fs for the bitclock). Is this supported by the audio library?

No, but it might be possible to edit the code. Supposedly the I2S port can do this.

.... a few posts before that Paul describes a method to implement 24 bit sampling which should be able to manage 32 bit sampling as well when it is written.

If you do edit the I2S object and submit a pull request, I'd like to see this done one of a few ways....

For an initial attempt, a #define and #ifdef checks for the new way is probably a good starting point.

Long-term, I'd like to see this as either a related I2S object that inherits from the original, like the slave mode object does today.

Another possibility would involve using 32 bit I2S word sizes for everything, even if only 16 bits are used normally. I believe this mode works with the SGTL5000 and pretty much all other chips. But it would need to be tested carefully.

I'm not personally planning to work on this anytime soon. This is only in the unlikely case someone else does so, and wishes to submit a pull request (that I'll actually accept).
 
Thanks for the quick reply. I was aware that the sample frequency was "awfully close to CD quality". Thus as a slave device, it would be driven by the DAC in master mode with an accurate sample rate. The DAC I am interested in using will have a local clock of 45.1584MHz and the DAC can generate a bitclock of /16 which is 2.8224MHz. The frame clock is fixed as /64.
Regarding treating everything 32bit I2S, I think this will have wider appeal as it seems universally accepted by all DACs. Actually, it is the frame rate at 64*fs that is supported (and some requires it) by all DACs, the data can be 16 bit, 20 bit, 24 bit or 32 bit.
Can you hint me as to where to look for the 64*fs support?
Thanks.
 
... restricted to 44.2K and 16bit DATA. ...
You wrote 44.2K before so I thought it pertinent to point out that it is much closer to 44.1K

Thanks for the quick reply. I was aware that the sample frequency was "awfully close to CD quality". Thus as a slave device, it would be driven by the DAC in master mode with an accurate sample rate. The DAC I am interested in using will have a local clock of 45.1584MHz and the DAC can generate a bitclock of /16 which is 2.8224MHz. The frame clock is fixed as /64.
Regarding treating everything 32bit I2S, I think this will have wider appeal as it seems universally accepted by all DACs. Actually, it is the frame rate at 64*fs that is supported (and some requires it) by all DACs, the data can be 16 bit, 20 bit, 24 bit or 32 bit.
Can you hint me as to where to look for the 64*fs support?
Thanks.

Even if you specify which audio codec you intend to use the answer to where you could look for 64*fs support may just have to be "elsewhere"; to use a codec at all means having specific controlling code for that codec. Paul has put the SGTL5000 on PJRC's Audio Adapter so that one is clearly to be supported. Others may become supported but equally they may not.



@Paul: I spent a lot of yesterday poring over https://www.pjrc.com/teensy/K20P64M72SF1RM and I am going to spend a lot hours reading (more of) it and pondering the less well defined items they have in there.

I read enough to become fairly confident that the 'split buffer' idea may be more work (for both author(s) and processor) than really ideal - I cannot currently see a way to do it other than to collect the data from the codec in an array of int32_t and then split each of those blocks into the two int16_t buffers currently in use, which gives rise to a question of sign in the LSB set too. Maybe that won't be as intensive an operation in the processor as I think but as the sampling rate increases it probably is.

I think conditional compiling where the data member of audio_block_struct is made int32_t when AUDIO_LIBRARY_BIT_DEPTH > 16 might be a better way to go - 24 bit samples can be processed by the same code that processes 32 bits and I think that it will be less work ultimately to write/modify objects which conditionally compile regarding bit depth as well instead of what would be necessary to deal with the split buffer method.

Where I think the bit depth should be library wide, even though the ADC is 16 bit (just shift << by (AUDIO_LIBRARY_BIT_DEPTH-16)) and the DAC is only 12 bit (similar shift, opposite direction), I've an idea that supporting multiple simultaneous sample rates could be cool enough to (perhaps, at least) be worth dealing with the trickier aspects of doing so - I can see reasons tho that I am probably wrong about this and perhaps a library wide AUDIO_LIBRARY_SAMPLE_RATE is called for too.

If audio_block_struct was re-written like this;
Code:
typedef struct audio_block_struct {
	unsigned char ref_count;
	unsigned char memory_pool_index;
#if AUDIO_LIBRARY_BIT_DEPTH>16
	int32_t data[AUDIO_BLOCK_SAMPLES];
#else
	int16_t data[AUDIO_BLOCK_SAMPLES];
#endif
	uint32_t sample_rate;
} audio_block_t;

Source objects fill the sample_rate field, manipulation and destination objects check that field and act appropriately. Then, for example, the end user could run ADC->[manipulation]->DAC at 44.117'K and codec_in->[manipulation]->codec_out at another rate if for whatever reason they wanted to. I see problems with trying to modify sample rates using an 'object in the middle' approach so perhaps the sample_rate member I suggest isn't a workable approach and source objects would have to up/down sample to the destination object's rate as they go - maybe that isn't economically feasible, in terms of having enough compute-power/time to manipulate as much as desired, either.


On the other hand making the sample rate fixed library wide setting PDB_PERIOD to 1000 or 500 (or even 250) can be used to match 48K and 96K (I wonder if it would manage 192K ?) for ADC & DAC, better still if we could get them to operate from BCLK(in or out) using LRCLK as enable or trigger perhaps) to align more precisely with less effort but I haven't found the part of the manual for MK20DX256VLH7 which shows me how to make it so yet - if it is possible.


For others reading and thinking how brilliant it would be to do 96K at 24-32 bits it should probably be pointed out that the time available to process and manipulate samples is decreased by the raised sample rate and the time required to process or manipulate the samples is increased by the larger bit depth - all leaving less processor time for other activities. IMHO 44.1-48K @ 16 bits is pretty good audio and leaves plenty of time to apply more processing/manipulation to samples and other activities.
 
You wrote 44.2K before so I thought it pertinent to point out that it is much closer to 44.1K



Even if you specify which audio codec you intend to use the answer to where you could look for 64*fs support may just have to be "elsewhere"; to use a codec at all means having specific controlling code for that codec. Paul has put the SGTL5000 on PJRC's Audio Adapter so that one is clearly to be supported. Others may become supported but equally they may not.



....

Oh, I meant 44.1K...
Regarding support for a specific codec, I've already written code for it and can control it independently of the Teensy. I believe all I need is for AudioOutputI2Sslave to support 64*fs frame rate even for 16 bit data
 
Sorry glt, 64*fs must be supported for 24 & 32 bit sampling but I don't think anybody is going to rush into causing I2S objects in the Audio Library to support 64*fs for 16 bit sampling, I am fairly sure most people won't see a value add for such behaviour - if your codec requires it to be so (only allowing 64*fs for instance) then in your case it is just necessary and if that is the case then telling us which codec you are trying to employ and going so far as to share your controller code for it will get you a better chance of somebody else modifying the I2S objects to your requirements; chances are you'd still beat any of us to it if you try very much while waiting for somebody to pick up the challenge.
 
Last edited:
...

Another possibility would involve using 32 bit I2S word sizes for everything, even if only 16 bits are used normally. I believe this mode works with the SGTL5000 and pretty much all other chips. But it would need to be tested carefully.

... .

If it was modified like that we could use right-justify for 24 & 16 bits, least significant 16 bits can be catered or discarded as desired without further bit shifting - ie., just treat upper 16 bits as 16 bit sample or treat as 32 bits regardless of LSB relevancy - this should make it just work for glt's purposes with only the work of making their codec 'play ball' for these settings, at worst I'm sure they could set 32 bit samples and for now the library can trash the lower 16 bits at the AudioInputI2S* objects and dummy the same bits for the AudioOutputI2S* objects; just while waiting for people who can to make the rest of the modifications required in other parts of the library to support the extended bit depth.

I might beat everybody to a submission but it could be up to three weeks before I can make a reasonably tested submission due my workload and circumstances - encouragement (anybody expressing positive interest) may spur me along to be quicker, discouragement may slow me down ;)
 
I'm about 36 hours from heading to Maker Faire, so please understand I won't be really looking at any of this stuff until next week.

This audio library is first and foremost designed for 16 bits and 44100 Hz (or 48e6/1088) sample rate. 16 bits makes a lot of sense on ARM Cortex-M4, since the DSP instructions are primarily designed to optimized 16 bit operations.

I understand we'll continue to see "audiophile" people who really want more bits and higher sample rates, for whatever reasons they believe they need such capability. I'm not opposed to supporting 24 or 32 bits. I planning to put my own programming time into making awesome and really useful 16 bit objects, like reverb, wavetable synth, etc. I'm willing to merge pull requests, if they follow the basic approach I've outlined (and even that is flexible).

But please understand I'll be traveling for the next several days. When I get back, Teensyduino 1.19 (bug fixes only) is going to be my top priority.
 
Is forum time here your local time? I hope you are getting enough rest Paul!

Forgive me if you felt like I was asking you to re-prioritise or prompting you to do something sooner than I will try to, not my intent at all.

I doubt you need it (due planning, diligence and hard work) but just in case: Good luck at Maker Faire, I wish I could attend.
 
All you need to do is get it working, then submit a github pull request. See my comments in #582 before you start.

Thanks for the encouragement. Unfortunately right now it is beyond my capability.
I am "one of those audiophiles" but my request is mainly for hardware compatibility. Hope you will keep this in mind when you get the time to work on the audio code.
The DAC I am working on is the ESS9018K2M.
 
Sorry glt, 64*fs must be supported for 24 & 32 bit sampling but I don't think anybody is going to rush into causing I2S objects in the Audio Library to support 64*fs for 16 bit sampling, I am fairly sure most people won't see a value add for such behaviour - if your codec requires it to be so (only allowing 64*fs for instance) then in your case it is just necessary and if that is the case then telling us which codec you are trying to employ and going so far as to share your controller code for it will get you a better chance of somebody else modifying the I2S objects to your requirements; chances are you'd still beat any of us to it if you try very much while waiting for somebody to pick up the challenge.

The DAC is the ESS9018K2M. I've also worked with the ESS9018S and the code is available here: http://hifiduino.wordpress.com/code/
The K2M model supports 32*fs and 64*fs in slave mode, but only 64*fs in master mode. After I test the code I'll put it up too.
 
Requests for 24 bits and fast sample rates are something I've expected to start hearing more and more as this library becomes more widely known and used.

For I2S master mode, or any use involving the on-chip DAC, ADC and PWM, we're very tightly locked into 44.1 kHz. Or 48 MHz divided by 1088 to be precise. Any other sample rate will need to use I2S slave mode, and will be incompatible with the on-chip I/O objects.

So I was thinking a little bit about the alternative sample rate issue and the first thing that came to mind was to use the I2S clock to feed an external trigger back into the PDB. For example, following robsoles' post #573, if we set the SGTL500 to 96kHz in I2S master mode, then it should be responsible for generating a 96kHz signal on the I2S_LRCLK pin. Would it be possible to use this to drive the PDB counter in external-trigger enabled one-shot mode?

Is this a bad idea?
 
I've the impression that when I can sit to focus on expanding available sampling rates for SGTL5000 to the lower rates I expect to find it somewhere between easy and only moderately difficult. Working by memory right now (see excuse next paragraph) the way appears to be to set one of the 'obvious' sample rates (32K or 44.1K) and then use the RATE_MODE bits of CHIP_CLK_CTRL(?) to tamper that down to the lower sample rates.

I've been dragged off to a holiday for the next few days (returning next thursday) and allowed only a 10" netbook and my (android based) phone; I just don't want to look at technical documents or programming environment(s) (not even notepad++) on either of these.

So I was thinking a little bit about the alternative sample rate issue and the first thing that came to mind was to use the I2S clock to feed an external trigger back into the PDB. For example, following robsoles' post #573, if we set the SGTL500 to 96kHz in I2S master mode, then it should be responsible for generating a 96kHz signal on the I2S_LRCLK pin. Would it be possible to use this to drive the PDB counter in external-trigger enabled one-shot mode?

Is this a bad idea?

It is a brilliant idea and my intention to pursue it to whichever conclusion (success or understanding why it can't succeed) as soon as I can spare it the time - I've read the most relevant parts of the MK20DX manual once now and it is not easy reading, I've the impression I will be re-reading various sections and referring to other relevant documentation a fair bit before I become certain either way. It seems probable to me that the answer may not involve the PDB but instead triggering ADC/DMA via pin driven interrupt instead. I've a degree of certainty that one or two people haunting this forum have read (and understood) enough of the relevant documents to either easily do it or explain why it isn't possible but I don't mean to call them out or anything, everybody has a right to be too busy and also to take holidays etc etc.

Funnily enough, I have to learn how to do all the higher sample rates and bit depths for the purposes my employer has decided on for these and related/similar parts but I actually see greater value in providing lower sample rates at 16 bits so I won't be ignoring the low end in favour of the top end.
 
Last edited:
Hmm... Thanks for the quick reply. I was thinking the PDB because that's what triggers both of the teensy's onboard ADCs and its DAC, but I admit I know nothing of the PWM stuff. I'm pretty new at all this.

Personally I'm currently looking into some projects that could involve frequencies in the 100Hz - 80kHz range, so getting 96kHz samples at 16 bits is not quite ideal, but it's enough to get into the frequency ranges significantly higher than I can hear, and higher than what most of the standard audio stuff is designed for, so it would certainly be good enough to keep me busy with all the design problems that I'll need to deal with when I decide to go up a notch (or junk the project).

Oh, and in case it's not implied: thanks a bunch to everyone contributing here -- this is a ton of fun!
 
For I2S master mode, or any use involving the on-chip DAC, ADC and PWM, we're very tightly locked into 44.1 kHz. Or 48 MHz divided by 1088 to be precise. Any other sample rate will need to use I2S slave mode, and will be incompatible with the on-chip I/O objects. If any audiophiles are reading this, designing a PCB (shared at OSH Park) with a high-end DAC and 24.576 crystal oscillator (no PLL, direct from a crystal+amplifier) for MCLK would a necessary step if we're ever going to even try to support such sample rates. A DAC with 120 dB SINAD would also be encouraging, so at least 4 of those extra bits might mean something....

I've been toying around with the idea of designing a board like this. I don't actually need that kind of quality, but it sounds like it would be a fun project to dust off my rusty PC design skills.

The biggest problem with this type of board is the increased cost. The SGTL5000 is a pretty cheap IC (freescale.com shows a budgetary price of only $1.25), and the audio board costs $15 (addt'l costs for PCB, connectors, and passives).

There are some slightly better single chip solutions (Analog Devices ADAU1772 or TI TLV320AIC3268) that have similar functionality to the SGTL5000 (integrated ADC/DAC/etc) with budgetary prices of ~$5, which would increase the board cost to somewhere around $25-30 (increased chip cost, and add crystal, similar part count and board area). These ICs can handle 192kHz sample rates and 24 bit resolution, but the SNR of the ADC/DACs are only slightly better than the SGTL5000 (both between 100-110dB).

If you move to high quality separate DAC and ADC ICs, you can achieve really good performance (>120dB SNR), but the part count and cost increase dramatically. Even for a board with just a high quality DAC and no ADC, you'd be looking at a total cost of at least $40-50. The increased cost is mainly due to the increased cost of the DAC itself, the need for a good quality output interface (multiple good quality opamps), the addition of a dedicated clock generator IC for the crystal, increased power supply filtering (these DACs generally run off of a 5V analog supply, so the 5V from the USB would need to be filtered a lot to get a good power supply rail), and a bunch of extra high quality passives.

Would there be that many people that would actually be interested in such a board? I'm somewhat skeptical that the increased cost is really worth the increased quality (which is probably only marginally audible), but if people are really interested in it, then I'd be willing to give it a shot.

If there's much interest, I'll start a new thread to see what sort of requirements people have (ie DAC only vs DAC and ADC, quality vs price, etc).
 
I've been considering having PJRC make a second audio shield for audiophile applications. Or it might be an unassembled or partially assembled (SMT parts soldered) kit.

I recently just built up a big demo that we're showing at Maker Faire (I'm writing from my laptop... killing a little extra time before it opens up again today). One very minor issue, which I don't think anyone has noticed except me, is a very tiny amount of noise due to ground loops. It's small, but well above the STGL5000 noise floor and/or the noise of the amp chips I've using. In a quiet room, without attenuation feeding right into the amps and your ear up to the speaker, it's noticeable.

Perhaps all audiophiles will instinctively know to use 2 separate, isolated power supplies for the Teensy and the DAC, with their grounds joined at a single location close to the DAC?

Still, I worry about ground loop problems as people build more complex projects. Afterall, if you only want to just play uncompressed 24 bit WAV files to a single output, without connections to anything else other than some buttons and display, there's already lots of products. Why bother building something so simple with a Teensy?

Perhaps an optical S/PDIF shield would be a better product that a DAC shield?

Then again, maybe isolation isn't an issue for audiophiles? Perhaps they'll all use Teensy in ways where it doesn't connect to anything else ground referenced? That seems like a pretty big "if" to me, so I'd really like to hear some input from anyone interested in this high end audio, about what sorts of ways they'd actually use Teesny and such a shield. What types of connections to other stuff than the DAC shield are the most important part.

Price is also going to be an issue. Anything "audiophile" is going to need expensive parts. My gut feeling it to try to keep the shield under $100 retail price. With a high end DAC, optical or transformer isolation, jitter-free clock generation, and expensive opamps for top quality output filtering, $100 might not be very realistic?
 
One very minor issue, which I don't think anyone has noticed except me, is a very tiny amount of noise due to ground loops. It's small, but well above the STGL5000 noise floor and/or the noise of the amp chips I've using. In a quiet room, without attenuation feeding right into the amps and your ear up to the speaker, it's noticeable.

Perhaps all audiophiles will instinctively know to use 2 separate, isolated power supplies for the Teensy and the DAC, with their grounds joined at a single location close to the DAC?
They won't all know, but that is a well known solution and will certainly help to some extent.

Still, I worry about ground loop problems as people build more complex projects. Afterall, if you only want to just play uncompressed 24 bit WAV files to a single output, without connections to anything else other than some buttons and display, there's already lots of products. Why bother building something so simple with a Teensy?

Perhaps an optical S/PDIF shield would be a better product that a DAC shield?

Then again, maybe isolation isn't an issue for audiophiles? Perhaps they'll all use Teensy in ways where it doesn't connect to anything else ground referenced?

Using optical isolation is certainly a proven way to break ground loops.

The problem of ground currents and differning ground potentials in connected circuitry is well known and is why professional audio (and some audiophile compnents) use balanced audio connections between equipment. High performance single-chip solutions for balancing and unbalancing are widely available at moderate cost.
THAT 1606 Balanced Line Driver IC
THAT 124x Balanced Line Receiver ICs, TI INA 137 Audio Differential Line Receiver

This has also historically been addressed by transformer coupling. However, this is significantly more expensive and offers little benefit in terms of measured specification. Transformer coupling (especially on microphone preamps) mainly seems to be used to get a characteristic and desired (by some) colouration from transformer saturation for a "vintage" feel. Because the people who want that will be very picky on the exact make and model of transformer (plus those parts are large and costly) I would suggest not addressing the transformer coupled area. Its easy enough for someone who wants that to add their own transformer stage. There are also a fair number of transformer coupled mic preamp DIY designs.
 
Would using an external voltage regulator between the USB +5v the the STGL5000 Vin, plus a small isolated ground connection make a bit of difference on the current audioshield?

I'm experiencing a lot of ground issues having it plugged into my laptop. Goes away when I touch both laptop and teensy at the same time...
 
Status
Not open for further replies.
Back
Top