PT8211 latency (MIDI note-on to sound)

alfa66

Well-known member
We have chosen the pt8211 for a project (ALFASoniQ Mirage II Emulator). We are making great progress, but we ran into what appears to be a latency issue.

When a note is triggered by MIDI, it takes almost 0.5 second for the sound to be produced.
Interestingly, once the note is triggered, the latency is gone for subsequent notes.
Until there is a pause of a few seconds.
When the next note is triggered, the latency is again very high.

Here is a video (Teensy 4.1 with PT8211) of a test case that reproduces the issue:
https://www.youtube.com/watch?v=8G2UPIfnT0E


Does the PT8211 have a undocumented low-power mode? That would explain why it takes a second note to wake up.
The other option could be that the PT8211 has some synchronization issues when using the library?

We tested the same code against teensy 4.0 with Teensy Audio Board SGTL5000:
https://www.youtube.com/watch?v=eoRDheKFKzg

Here is the code:

#include <Audio.h>
#include <MIDI.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

MIDI_CREATE_DEFAULT_INSTANCE();

//#define PT8211

AudioSynthWaveform waveform1;

#ifdef PT8211
AudioOutputPT8211 pt8211_1;
AudioConnection patchCord1(waveform1, 0, pt8211_1, 0);
AudioConnection patchCord2(waveform1, 0, pt8211_1, 1);
#else
AudioOutputI2S i2s1;
AudioConnection patchCord1(waveform1, 0, i2s1, 0);
AudioConnection patchCord2(waveform1, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1;
#endif

void setup() {
AudioMemory(15);
Serial.begin(9600);

#ifdef PT8211
#else
sgtl5000_1.enable();
sgtl5000_1.volume(0.5);
#endif

waveform1.begin(WAVEFORM_SINE);
waveform1.frequency(440);
// waveform1.amplitude(0.99);

Serial.println("getting ready....");
pinMode(LED_BUILTIN, OUTPUT);
MIDI.begin(0);
}

void loop()
{
int note, velocity, channel, d1, d2;

if (MIDI.read()) // If we have received a message
{
byte type = MIDI.getType();
switch (type) {
case midi::NoteOn:
digitalWrite(LED_BUILTIN, HIGH);
waveform1.amplitude(0.99);
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
if (velocity > 0) {
Serial.println(String("Note On: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
} else {
Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
}
break;
case midi::NoteOff:
digitalWrite(LED_BUILTIN, LOW);
waveform1.amplitude(0.0);
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
break;
default:
d1 = MIDI.getData1();
d2 = MIDI.getData2();
Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
}
}
}


Any ideas on what might be happening here?
(we will fire up the scope and logic analyzer sometime during the week...)
 
Can't reproduce this, though I've not quite got the same setup as you (no MIDI keyboard). Doesn't look relevant, as your video clearly shows a lack of sync between the LED and the audio, but ... full disclosure.

Using an official PJRC kit, I tried both the PT8211 objects - if you wire your PT8211 to the I2S2 pins you can use it at the same time as the PJRC Audio Adaptor. Here's my version of your code, in CODE tags (use the # button above the edit box - much better for all!):
Code:
#include <Audio.h>
#include <MIDI.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

MIDI_CREATE_DEFAULT_INSTANCE();

//#define PT8211

AudioSynthWaveform waveform1;

#ifdef PT8211
AudioOutputPT8211 pt8211_1;
AudioConnection patchCord1(waveform1, 0, pt8211_1, 0);
AudioConnection patchCord2(waveform1, 0, pt8211_1, 1);
#else
AudioOutputI2S i2s1;

[COLOR="#FF0000"]AudioOutputPT8211_2 pt8211_1;
AudioConnection patchCord1b(waveform1, 0, pt8211_1, 0);
AudioConnection patchCord2b(waveform1, 0, pt8211_1, 1);[/COLOR]

AudioConnection patchCord1(waveform1, 0, i2s1, 0);
AudioConnection patchCord2(waveform1, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1;
#endif

void setup() {
  AudioMemory(15);
  Serial.begin(9600);

#ifdef PT8211
#else
/*******************/  sgtl5000_1.setAddress(HIGH);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
#endif

  waveform1.begin(WAVEFORM_SINE);
  waveform1.frequency(440);
  // waveform1.amplitude(0.99);

  Serial.println("getting ready....");
  pinMode(LED_BUILTIN, OUTPUT);
  MIDI.begin(0);
}

void loop()
{
  int note, velocity, channel, d1, d2;

  if (MIDI.read()) // If we have received a message
  {
    byte type = MIDI.getType();
    switch (type) {
      case midi::NoteOn:
        digitalWrite(LED_BUILTIN, HIGH);
        waveform1.amplitude(0.99);
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        if (velocity > 0) {
          Serial.println(String("Note On: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        } else {
          Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
        }
        break;
      case midi::NoteOff:
        digitalWrite(LED_BUILTIN, LOW);
        waveform1.amplitude(0.0);
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        break;
      default:
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
        Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
    }
  }

[COLOR="#FF0000"]#define COUNT_OF(a) (sizeof a / sizeof a[0])
  static int state = 0;
  static elapsedMillis next = 0;
  static uint32_t idx = 0;
  static uint32_t limits[] = {100,250,500,1000,2000,3000,5000,10000};
  if (millis() > next)
  {
    switch (state)
    {
      default:
      case 0:
          Serial.printf("bip %d!\n",limits[idx]);
          waveform1.amplitude(0.99);
          digitalWrite(LED_BUILTIN, HIGH);
          next = 0;
          state++;
          break;

      case 1:
        if (next > 100)
        {
          waveform1.amplitude(0.0);
          digitalWrite(LED_BUILTIN, LOW);
          next = 0;
          state++;
        }
        break;
        
      case 2:
        if (next > limits[idx])
        {
          idx++;
          if (idx >= COUNT_OF(limits))
            idx = 0;
          state = 0;
        }
        break;        
    }
  }[/COLOR]
}

It's hard to see how the MIDI library code could affect the timing, but if you can reproduce the issue without it we might have a clearer picture of what the problem is, and perhaps a few more folk could have a stab at investigating.
 
It's hard to see how the MIDI library code could affect the timing, but if you can reproduce the issue without it we might have a clearer picture of what the problem is, and perhaps a few more folk could have a stab at investigating.

In the real code we're using Serial1 to read the MIDI data instead of using the MIDI library.
 
In the real code we're using Serial1 to read the MIDI data instead of using the MIDI library.
But the MIDI library will probably be using Serial under the hood … so, it’s still worth trying to confirm or deny that MIDI/Serial use is part of the issue, by removing it from the problem demo.
 
I've been using pt8211_2 in a development project more than a year now, never encountered any such delay with or without midi. BTW it's not a bad little chip, but it is pretty noisy for a professional product, especially given that a "real" stereo dac can be had for about 3 bucks. Heck, a PCM1680 has EIGHT outputs (just think what you could do with 8 outputs!) and it's less than three-fitty even in low quantities. https://www.mouser.com/ProductDetail/595-PCM1681PWPR
 
I ran the code here and measured the response time with my oscilloscope. I'm seeing approx 3 to 5 ms from the end of the MIDI message until the PT8211 starts the sine wave output.

To test, I used a Teensy 4.0 running this code to send the MIDI messages.

Code:
#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  pinMode(13, OUTPUT);
  MIDI.begin(0);
}

void loop() {
  digitalWrite(13, HIGH);
  MIDI.sendNoteOn(64, 64, 1);
  delay(500);
  digitalWrite(13, LOW);
  MIDI.sendNoteOff(64, 64, 1);
  delay(1500);
}

I ran the code from msg #1 on a Teensy 4.1. Only edit was to uncomment the #define PT8211 line.

Here is the hardware on my workbench, so you can see how I tested.

pt8211_latency.jpg

I connected the oscilloscope to pin 13 on both boards, and to the serial data line, and of course the PT8211 output.

file.png

This scope setting is 2 ms/division. You can see the blue trace (LED on Teensy 4.1) goes high very quickly after the end of the MIDI message (green trace), and then just under 2 divisions later the PT8211 starts creating the sine wave.
 
In the demo video, the sound is much more pleasing than the plain and somewhat shrill tone of a pure sine wave.

Is the PT8211 output going through some sort of reverb or echo effect pedal or other processing?
 
In the demo video, the sound is much more pleasing than the plain and somewhat shrill tone of a pure sine wave.

Is the PT8211 output going through some sort of reverb or echo effect pedal or other processing?

Hi Paul,
thank you for checking this.
The sound - just a sine wave - is going through a Creative Labs speaker (and then reflected around my living room, there is a piano and some guitars there).
I just started my work day and I cannot verify it right now, but my colleague in the project suggests that, given your measurements, it is possible that the speaker I am using goes in shut-down while not connected to a power source.
If that's the case, this would be liberating and confirm once again that using teensy and your audio lib are great choices for the project.
I will report later.
 
... my colleague in the project suggests that, given your measurements, it is possible that the speaker I am using goes in shut-down while not connected to a power souuce.

I think it's actually more like a noise gate which seems to cut out the background hiss a second or two after the sound source goes quiet, but also is perhaps combined with that speaker's auto-gain feature which may be attempting to prevent loud initial transients and so cuts off the start of the sound.
 
I think it's actually more like a noise gate which seems to cut out the background hiss a second or two after the sound source goes quiet, but also is perhaps combined with that speaker's auto-gain feature which may be attempting to prevent loud initial transients and so cuts off the start of the sound.

Closing this thread, the particular speaker (Creative Labs iRoar Go) was the culprit.
The same behavior occurs when powered via the DC power supply, so I will move to another speaker.

I am super-thankful for the support received.
 
Back
Top