COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 12-13-2017, 05:35 PM   #1
Guod3
Human being with feelings
 
Guod3's Avatar
 
Join Date: Jan 2008
Posts: 506
Default Generating a midi clock

I'm looking for code to produce a midi clock to be sent out a HW midi port from within an IPlug plugin.

Some sort of timer driven process that sends 0xF8 regularly onto the midi port based on host tempo is what is required, I gather.

This is a common requirement for controlling hardware synths (e.g syncing LFO, arpeggiators, delay times, etc) so I'm hoping I don't have to reinvent this wheel.
Guod3 is offline   Reply With Quote
Old 12-27-2017, 09:47 PM   #2
Mimo
Human being with feelings
 
Join Date: Apr 2015
Posts: 68
Default

__________________________________________________ _________ +1
Mimo is offline   Reply With Quote
Old 12-29-2017, 04:51 PM   #3
Guod3
Human being with feelings
 
Guod3's Avatar
 
Join Date: Jan 2008
Posts: 506
Default

The plugin I'm working on sends CCs to external fx including tempo by way of midi beat clock (0xf8 @ 24ppqn). So for tempo of 120bpm a quarter note goes for 500ms. That means midi clock gets sent around every 20.8ms.
So I plan to generate and queue clock bytes at the rate of 24ppqn and send them at the start of processreplacing.
For an LFO or arpeggiator or delay time it is the average rate which keeps them in sync and the jitter shouldn't matter so much. At the moment I'm using the host controlled midi port rather than a port opened by the plugin.
I'll see how well this works.
Guod3 is offline   Reply With Quote
Old 12-30-2017, 12:18 AM   #4
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

Does not this already exist...?
https://forum.cockos.com/showthread....046#post538046
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 12-31-2017, 01:58 AM   #5
Guod3
Human being with feelings
 
Guod3's Avatar
 
Join Date: Jan 2008
Posts: 506
Default

The task is a clock generator within an Iplug. The jsfx code may provide some guidance but I don't think I'll be executing lines of code every sample to make it happen. Afaik sample accurate generation of midi events in processreplacing does not result in real-time accurate midi to an external HW midi port.
Guod3 is offline   Reply With Quote
Old 01-10-2018, 06:35 AM   #6
Mimo
Human being with feelings
 
Join Date: Apr 2015
Posts: 68
Default

Quote:
Originally Posted by Guod3 View Post
The task is a clock generator within an Iplug. The jsfx code may provide some guidance but I don't think I'll be executing lines of code every sample to make it happen. Afaik sample accurate generation of midi events in processreplacing does not result in real-time accurate midi to an external HW midi port.
Because?

Midi: Bandwidth (Max 1.5 KHz updates)

MIDI Transmission Standard:
MIDI is transmitted as asynchronous bytes at 31250 bits per second.
One start bit, eight data bits, and one stop bit result in a maximum transmission rate of 3125 bytes per second.
If first bit = 1, the following byte is a "status" byte.
If first bit = 0, the following byte is a "data" byte.
The status byte determines the length of most messages, which are usually one, two, or three bytes in length.
System exclusive messages are of variable length and have a start and ending status byte.
Mimo is offline   Reply With Quote
Old 01-10-2018, 12:07 PM   #7
Guod3
Human being with feelings
 
Guod3's Avatar
 
Join Date: Jan 2008
Posts: 506
Default

Again, the task I'm undertaking is a midi beat clock functionality within an IPlug plugin. The port may be: DAW host internal or HW (uart or USB, etc) which all work the same as far as my plugin is concerned.
Guod3 is offline   Reply With Quote
Old 01-10-2018, 05:58 PM   #8
Mimo
Human being with feelings
 
Join Date: Apr 2015
Posts: 68
Default

I refer to this phrase: "Afaik sample accurate generation of midi events in processreplacing does not result in real-time accurate midi to an external HW midi port."

on the other hand:

In my case,when i using SendMidiMsg send the notes that are generated, and an inexplicable realtime midi, whose value is not 248 (0xF8), 250, 252, but a: 127.
Mimo is offline   Reply With Quote
Old 01-14-2018, 11:36 AM   #9
Ad0
Human being with feelings
 
Join Date: Mar 2008
Posts: 89
Default

I have generated a MIDI clock from scratch. It is simple since you just need to send some data periodically.

You need to create a thread running a loop with a variable sleep and a wall clock to have a precise enough clock. Look into C++ threads http://www.cplusplus.com/reference/thread/thread
Ad0 is offline   Reply With Quote
Old 01-14-2018, 05:54 PM   #10
Guod3
Human being with feelings
 
Guod3's Avatar
 
Join Date: Jan 2008
Posts: 506
Default

Feel free to post some code fragments.

What I've implemented so far has the granularity of block_size/SR. This is the time between calls to ProcessReplacing. For a buffer of 128 this is around 2 to 3 ms @48kHz. If a midi clock happens every 20.8ms (i.e.120BPM) there will be some jitter in the clock but it doesn't seem to matter. However if the buffer size is set to 1024 or some other large number and the clock receiver is an outboard delay, then you hear glitches.

Does the sleep function go down to millisecond resolution? Does this determine the accuracy (jitter)?
Guod3 is offline   Reply With Quote
Old 01-15-2018, 06:04 AM   #11
Ad0
Human being with feelings
 
Join Date: Mar 2008
Posts: 89
Default

Quote:
Originally Posted by Guod3 View Post
Feel free to post some code fragments.

What I've implemented so far has the granularity of block_size/SR. This is the time between calls to ProcessReplacing. For a buffer of 128 this is around 2 to 3 ms @48kHz. If a midi clock happens every 20.8ms (i.e.120BPM) there will be some jitter in the clock but it doesn't seem to matter. However if the buffer size is set to 1024 or some other large number and the clock receiver is an outboard delay, then you hear glitches.

Does the sleep function go down to millisecond resolution? Does this determine the accuracy (jitter)?
Don't have the code right here but:
The precision matter at high BPMs. Also - as you say you can't really trust the ProcessReplacing() because it's variable. You could use it as first priority whenever possible, and then switch over to a timer thread if the interval is too low.

1) thread::sleep for the full time - 2 ms. http://en.cppreference.com/w/cpp/thread/sleep_for

Then use the std::chrono::high_resolution_clock to measure the time actually slept and subtract the full sleep time by this elapsed time. What you then get is the remainder to sleep.

But when it closes down to 1-2 ms you should just do an "busy wait", which is basically a for loop checking the remaining elapsed time to be slept and break when it has reached it. That way you get the most stable clock possible. It will use some CPU but at least it's better than for example Reason's MIDI clock.

I anyone knows a better way to make a MIDI clock let me know. I have tried everything from multimedia timers etc to have stable timing on sub ms precision, but it's impossible unless you have a dedicated CPU core for realtime processing.
Ad0 is offline   Reply With Quote
Old 01-15-2018, 06:57 AM   #12
Guod3
Human being with feelings
 
Guod3's Avatar
 
Join Date: Jan 2008
Posts: 506
Default

Thanks for the detailed info.
In my mind (at least) having the correct number of beat clocks transmitted over a period of time (say seconds) is more important than whether the clocks themselves fall right on the 24ppqn instant(s). Here I'm thinking about a beat sync LFO or arpeggiator riff staying "in phase" with a groove, for example. The other example I'm encountering is with a tempo sync digital delay (Lexicon MX400) where the DSP engine interprets midi clock jitter as a change in tempo causing it to alter the delay time with audible artefacts. This happens with fairly gross jitter (~50% of clock period).
If the absolute jitter can be limited to around +/-1ms or so and the total number of pulses per measure can be correctly monitored/maintained using the chrono clock without wait loops I think this will be excellent.
I'm a bit unclear of the argument type for sleep_for(..)
Guod3 is offline   Reply With Quote
Old 01-15-2018, 07:01 AM   #13
Ad0
Human being with feelings
 
Join Date: Mar 2008
Posts: 89
Default

Quote:
Originally Posted by Guod3 View Post
Thanks for the detailed info.
In my mind (at least) having the correct number of beat clocks transmitted over a period of time (say seconds) is more important than whether the clocks themselves fall right on the 24ppqn instant(s). Here I'm thinking about a beat sync LFO or arpeggiator riff staying "in phase" with a groove, for example. The other example I'm encountering is with a tempo sync digital delay (Lexicon MX400) where the DSP engine interprets midi clock jitter as a change in tempo causing it to alter the delay time with audible artefacts. This happens with fairly gross jitter (~50% of clock period).
If the absolute jitter can be limited to around +/-1ms or so and the total number of pulses per measure can be correctly monitored/maintained using the chrono clock without wait loops I think this will be excellent.
You can try without the busy wait first and then introduce it if you run into problems. I advice you to run this in it's own thread so you don't freeze up the plugin processing of the DAW. Remember - if you sleep inside you plug you will disrupt everything I guess and introduce crackles etc.

I wrote my own MIDI clock in a standalone app that generated clock from ableton link so Reason could provide a stable MIDI clock instead of it's internal crappy one.

Jitter was affecting my Eventide Orville just like your Lexicon, and that was what prompted me to write this in the first place.
Ad0 is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 05:40 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.