Main Site Documentation

Calculating and handling PPQ for a MIDI Sequencer


#1

I hope I’m not flooding this forum with silly questions. But someone once told me that I should always ask things first, so I don’t re-invent the wheel. :wink:

Ok, I’m doing a MIDI Sequencer. So I want to know how I will handle the actual PPQ Loop.

If you don’t know what’s PPQ, check this out:

I want to make it variable, so the user can change this when creating a new song. From 48 to 960 PPQ.

Now I need to know how I will calculate the time from one PPQ to the next one. Of course, this will be done in its own THREAD, so the rest of the LCD, Knobs, etc … doesn’t affect this loop.

One idea is to make the thread idle until the next PPQ, but that’s not exactly ideal. Still, I need to know how I will calculate the TEMPO x PPQ so I know how many MS (micro seconds) each PPQ takes.

I will use the Emulator to run some tests, while my FEZ doesn’t arrive here. 8)

Thanks in advance for any help. Wk


#2

Humm, actually I don’t need a midi clock. All I need is the time of when the sequence started, and I use it to check for events. The same for recording. The only clock I need is to blink a led or display the time on the LCD, and it doesn’t need to be PPQ based, but just BPM based.

Here’s a code example from the FEZ MIDI Player. I just need to check if its time-perfect. Its not polyphonic, but I can change it to be. Once I have something more concrete, I will post here.

                // Determine the time to wait
                TimeSpan timeToWait = new TimeSpan(parser.note.DeltaTime * parser.Tempo * TimeSpan.TicksPerMillisecond / 1000 / parser.TicksPerBeat);
                Debug.Print("Time To Wait: " + timeToWait.ToString());
                Thread.Sleep((int)(timeToWait.Ticks / TimeSpan.TicksPerMillisecond));

Instead of delaying it for the note, I would just delay for the next note instead.

Wk


#3

Why are you calculating milliseconds instead of just using TimeSpan.Milliseconds property:


// Determine the time to wait
TimeSpan timeToWait = new TimeSpan(parser.note.DeltaTime * parser.Tempo * TimeSpan.TicksPerMillisecond / 1000 / parser.TicksPerBeat);
Debug.Print("Time To Wait: " + timeToWait.ToString());
Thread.Sleep(timeToWait.Milliseconds);


#4

That’s not my code, I’m still learning. :wink:

Also, is there any sort of extended Sleep method on the NETMF? I saw something that used Ticks instead of MS, but in the Emulator it didn’t work out.

Wk


#5

I don’t know if there is one.
I think it is not very practical to use ticks.


#6

But I need something that is fractional ms (micro seconds) and from what I can tell Sleep won’t take it, right?

For example: 120 beats per minute (BPM) will get you 2 beats per second. So each beat is 500ms, which is easy to do with Thread.Sleep(500), no problem there.

But now, at 96 PPQ - Pulses Per Quarter, each beat has 96 sub-events. Each event will be: 500ms / 96 = 5.208 ms per PPQ which Thread.Sleep won’t take it.

So, how can I resolve this problem up with NETMF? Assembly? Another thing?

Does NETMF has StopWatch? I could them make my own loop and check for timing. I did try this with the Time check, but on the Emulator it failed.

Unless this is not possible to do with FEZ?? :frowning: :wall: (I know what it is with XMOS, as I read XC and they have a 10ns timer)

For regular stuff it would work with 1 to 1000ms for Thread.Sleep() But as soon as you have tons of events on the sequence, it would lose track of tempo and get out of sync pretty quickly. Specially when using PPQ 960, which would be nuts, as 500 ms / 960 PPQ = 0.5208 ms

I will check more examples of interfacing with other hardware, but from what I’m seeing, this doesn’t look good…

Wk


#7

I guess what’s missing is some sort of delayMicroseconds() like the Arduino has…

Wk


#8

Netmf is great in every task but it is not realtime. The only thing to try is use timer to delay for microseconds. This will definatly not work on emulator so try it on hardware


#9

Ah, indeed, I did try that, but the Emulator failed badly. :wink: Thanks. I will wait for my Panda to arrive, them I will start playing with Timers instead.

Another thing, can you confirm that there’s a delay of 20ms on the I/O Interrupts? (I read about this somewhere on the NET, that NETMF has a 20ms delay on interrupts if other threads are running, which is my case)

Wk


#10

No there is no fixed delay of any number


#11

Hummm, please, read this them:

http://www.ghielectronics.com/forum/index.php?action=printpage;topic=2627.0

As this is confusing me. Since I want to use Interrupts for a Rotatory Encoder, and also MIDI-Input, a 20ms delay is going to kill my project. :think:

[quote]If you care for details…Interrupts in NETMF are not really interrupts! What happens is that every 20ms the system will check for thread swapping and will also check for interrupt flags. If there is an interrupt flag then the interrupt handler is called. So latencies are in the 20ms range.
Now, if your system is completely idle (Thread.Sleep(-1):wink: then the system is not running any threads and all it is doing is checking for events. In this case, the latency is under one ms.
Finally, if the system has few running thread, open sockets, have few events, using file system, GC is activating often…etc. then latency to your interrupt can be much more than 20ms and it is impossible to determine how long it will take.[/quote]

Wk


#12

It checks every 20 ms if the system is not idle. On idle system, this becomes almost immediate.

You can’t rely on 20ms in any calculations. It maybe less or maybe more.