SGTL5000 compared to PT8211

Status
Not open for further replies.

C0d3man

Well-known member
Hi!

I used for my project (MicroDexed) a Teensy-Audio-Board (SGTL5000) and it sounds really good (and works for 16 voices with only 2 Blocks of audio memory). But when using the same code (adapted for the PT8211, using the Teensy-Audio-Design-Tool) it seems that I am getting much memory problems. AudioMemoryUsageMax() reports something about 50.000 (!!!). I have seen that four-times-oversampling uses much memory, so I turned it of for a test. But there were also drop outs due to memory problems.

Does the PT8211 "driver" really needs much more memory than the SGTL5000 - or do I have a problem in my code?

Thanks and Regards, Holger
 
Without looking deeper into the audio library’s source code, I’d guess that a simple PT8211 output without oversampling should not be that memory consuming and I’d look for the problem elsewhere.
The oversampling itself, when it is done with a lengthy zero phase FIR, might be extremely resource consuming. I made some tests, just generating a 48ks/s sine wave in real time with a high Q SVF, followed by x8 oversampling on a Teensy 3.2 without audio library, some years ago, and that was enough to saturate the poor little Teensy.

Besides of that, new designs based on the obsolete PT8211 are not recommended.
 
Without looking deeper into the audio library’s source code, I’d guess that a simple PT8211 output without oversampling should not be that memory consuming and I’d look for the problem elsewhere.
The oversampling itself, when it is done with a lengthy zero phase FIR, might be extremely resource consuming. I made some tests, just generating a 48ks/s sine wave in real time with a high Q SVF, followed by x8 oversampling on a Teensy 3.2 without audio library, some years ago, and that was enough to saturate the poor little Teensy.

Ok, thanks for this information. I have an idea where the memory problems may come from.

Besides of that, new designs based on the obsolete PT8211 are not recommended.

Sure, but the PT8211 is currently the easiest and cheapest way to get something like sound out of the Teensy via I2S. The TSOP housing is the only way for me to get an I2S interface soldered on a PCB :-(

Regards, Holger
 
I'm currently experimenting with a cheap (3.14€) chinese PCM5102A breakout module. The PCM5102A has integrated x8 oversampling which makes things much easier.
 
I'm currently experimenting with a cheap (3.14€) chinese PCM5102A breakout module. The PCM5102A has integrated x8 oversampling which makes things much easier.

I successfully used the PCM5102A and it sounds much better than the Audio Shield.
https://forum.pjrc.com/threads/53069-Teensy-with-PCM5102a-Module-via-I2S

Ultimately, though I wish to use the PCM5242. This would give me entry level audiophile quality sound. I just bought the evaluation module and I'll be hooking it up. I'm not a coder though, so I suspect I'll struggle "writing" the firmware to initialize the chip. I'll try...

My goal will be to run the PCM5242 DAC in TDM mode with a Teensy. I'll be looking to hire a good firmware developer to help me along. If anyone is interested in paid work to do this let me know.
 
The pt8211 code does not use that much memory. It does not use more than the SGTL code.
Can you please post an example?
I wrote parts of the code and would like to fix the bug- if there is any. But I need something that helps me to reproduce the problem.
This is the first time I hear about it, and it is unlikely that it has a memory problem.

Also, please give examplecode for dropouts.
 
Last edited:
Hi @Frank B

thanks for replying to my post!

The pt8211 code does not use that much memory. It does not use more than the SGTL code.
Can you please post an example?

I am not really sure what is the problem - maybe I am doing something wrong...
I tested the simple hardware example sketch and the PT8211Sine works without a problem. So I replaced the SGTL code inside my (far more complex code) with the PI8211 driver (currently this is done by a #undef TEENSY_AUDIO_BOARD):

Code:
// GUItool: begin automatically generated code
AudioPlayQueue           queue1;         //xy=494,404
AudioAnalyzePeak         peak1;          //xy=695,491
#ifdef TEENSY_AUDIO_BOARD
AudioOutputI2S           i2s1;           //xy=1072,364
AudioConnection          patchCord1(queue1, peak1);
AudioConnection          patchCord2(queue1, 0, i2s1, 0);
AudioConnection          patchCord3(queue1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=700,536
#else
AudioOutputPT8211        pt8211_1;       //xy=1079,320
AudioAmplifier           volume_master;           //xy=678,393
AudioAmplifier           volume_r;           //xy=818,370
AudioAmplifier           volume_l;           //xy=818,411
AudioConnection          patchCord1(queue1, peak1);
AudioConnection          patchCord2(queue1, volume_master);
AudioConnection          patchCord3(volume_master, volume_r);
AudioConnection          patchCord4(volume_master, volume_l);
AudioConnection          patchCord5(volume_r, 0, pt8211_1, 0);
AudioConnection          patchCord6(volume_l, 0, pt8211_1, 1);
#endif
// GUItool: end automatically generated code

(The complete project is located at https://teahub.io/dcoredump/MicroDexed.git).

Normally I only need to reserve 2 blocks of audio memory for the SGTL5000. I tried with several other values (up to ~500). I can hear something similar of a sound but there are much drops and reports about huge memory usage. I was trying with AUDIO_BLOCK_SAMPLES sizes of 128 (default) and 64 (which I am using for the SGTL5000 based code). The following is the main-loop:

Code:
void loop()
{
  int16_t* audio_buffer; // pointer to AUDIO_BLOCK_SAMPLES * int16_t
  const uint16_t audio_block_time_ms = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES);

  while (42 == 42) // DON'T PANIC!
  {
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
    if (cpu_mem_millis > SHOW_CPU_LOAD_MSEC)
    {
      show_cpu_and_mem_usage();
      cpu_mem_millis = 0;
    }
#endif

    handle_input();

    audio_buffer = queue1.getBuffer();
    if (audio_buffer == NULL)
    {
      Serial.println(F("E: audio_buffer allocation problems!"));
    }

    if (!queue1.available())
      continue;

    elapsedMicros t1;
    dexed->getSamples(AUDIO_BLOCK_SAMPLES, audio_buffer);
    if (t1 > audio_block_time_ms) // everything greater 2.9ms is a buffer underrun!
      xrun++;
    if (t1 > render_time_max)
      render_time_max = t1;
    if (peak1.available())
    {
      if (peak1.read() > 0.99)
        peak++;
    }
#ifndef TEENSY_AUDIO_BOARD
    for (uint8_t i = 0; i <= AUDIO_BLOCK_SAMPLES; i++)
      audio_buffer[i] *= vol;
#endif
    queue1.playBuffer();
  }
}

[ While I am writing this reply I can see that I am declaring "int16_t* audio_buffer; // pointer to AUDIO_BLOCK_SAMPLES * int16_t" outside the endless-while-loop. Is this the problem? ]

What is strange: AudioMemoryUsageMax() is reporting values about 50.000 or 65.000 blocks after a note-on event.

I wrote parts of the code and would like to fix the bug- if there is any. But I need something that helps me to reproduce the problem.
This is the first time I hear about it, and it is unlikely that it has a memory problem.

Also, please give examplecode for dropouts.

I hope those small pieces of code are helping. The whole project is much bigger... perhaps it is a problem of the combination of the queue object with the PT8211 driver? I think I will try to write a smaller program which only generates a sine wave inside a queue...

Regards, Holger
 
I think I will try to write a smaller program which only generates a sine wave inside a queue

Yes, a smaller program would be a huge help.

The queue objects are tough to use and can quickly burn up memory if your code doesn't keep up with the full audio rate. If there really is a bug in the PT8211 code, a test program not using any queues would be really helpful.
 
Yes, a smaller program would be a huge help.

The queue objects are tough to use and can quickly burn up memory if your code doesn't keep up with the full audio rate. If there really is a bug in the PT8211 code, a test program not using any queues would be really helpful.

The example program PT8211Sine is doing fine. I don't think that there is a problem in the PT8211 code. I think I am doing something wrong with the queue. The strange thing is: the SGTL5000 implementation works, and the PT8211 not (same code, only some amps (for panning a mono signal) were added). I'm a little confused at this point:

Code:
audio_buffer = queue1.getBuffer();
    if (audio_buffer == NULL)
    {
      Serial.println(F("E: audio_buffer allocation problems!"));
    }

    if (!queue1.available())
      continue;

I thought that queue1.available() should block if there is no audio buffer free. So, if I use
Code:
AudioMemory(8);
, then there should not be used more than these 8 audio buffers and the function should block or continue() withoud allocating, or am I wrong?

Regards, Holger
 
The PT8211 code does a bunch of extra work to interpolate samples. The I2S code just quickly copies them to a buffer.

Perhaps this extra CPU time consumed by the PT8211 code is impacting the timing of the rest of your program enough that you're using the queue differently?
 
The PT8211 code does a bunch of extra work to interpolate samples. The I2S code just quickly copies them to a buffer.

Perhaps this extra CPU time consumed by the PT8211 code is impacting the timing of the rest of your program enough that you're using the queue differently?

I have seen that there is software oversampling and other stuff implented and I "#undef"-ed them inside the driver with no improvement. I am pretty sure that I am doing something wrong with the queue().

Does queue1.available() block? If not I think I know what I am doing wrong...

Regard, Holger
 
Hm, seeing the code here: https://github.com/PaulStoffregen/Audio/blob/master/play_queue.cpp#L31
I think your code should probably look like this:

Code:
if (queue1.available()) {   
  audio_buffer = queue1.getBuffer();
  ..fill buffer here..
  queue1.playBuffer(); 
  ...
}

The documentation for the queue does not look correct..

Functions

play(int16);
not yet implemented


play(int16[], length);

not yet implemented


getBuffer();

Returns a pointer to an array of 128 int16. This buffer is within the audio library memory pool, providing the most efficient way to input data to the audio system. The buffer is likely to be populated by previously used data, so the entire 128 words should be written before calling playBuffer(). Only a single buffer should be requested at a time. This function may return NULL if no memory is available.


playBuffer();

Transmit the buffer previously obtained from getBuffer().
Apart from the missing available() which allocates the buffer, getBuffer never returns null, but waits for a free buffer.
 
Last edited:
Hm, seeing the code here: https://github.com/PaulStoffregen/Audio/blob/master/play_queue.cpp#L31
I think your code should probably look like this:

Code:
if (queue1.available()) {   
  audio_buffer = queue1.getBuffer();
  ..fill buffer here..
  queue1.playBuffer(); 
  ...
}

The documentation for the queue does not look correct..


Apart from the missing available() which allocates the buffer, getBuffer never returns null, but waits for a free buffer.

Thanks @Frank B! This may be the cause for my (perhaps) faulty implementation. I just have not much time for testing this. Will do this at weekend and report here.

Regards, Holger
 
Last edited:
Problem solved!

I GOT IT!!!

First I tried to rewrite my main loop as @Frank B sugessted. But this changed nothing. But then I recognized a really stupid problem made by myself - the problem is in front of the screen:

...
#ifndef TEENSY_AUDIO_BOARD
for (uint8_t i = 0; i <= AUDIO_BLOCK_SAMPLES; i++)
audio_buffer *= vol;
#endif
queue1.playBuffer();
...

Where is the problem? It is not the driver... It is the erroneous comparison in the for loop that triggers an access outside the allocated memory area! ARGH! And this part of the code is only used when not using the audio-board. The for-loop has to check "i < AUDIO_BLOCK_SAMPLES" instead of "i <= AUDIO_BLOCK_SAMPLES"...

Now Micro-Dexed also works on the PT8211. Thanks so much for helping to all!!!!!!!!!!!

Regards, Holger
 
Status
Not open for further replies.
Back
Top