Freq (22) [Avatar] Offline
#1
I'm having trouble with MIDI clock messages. Internal sync seems rock solid on my Celeron 500 but the machines I have connected to it slowly fall out of sync. I use a Midiman 2x4 (2 in, 4 outs) and send clock messages to 3 of the 4 out ports. I'm worried this might be a performance problem. Has anyone tried this before? Anyone have any ideas of how I can tackle fixing this? MaxSeq won't let me sync more than 1 device at a time so I can't really tell whether this is a problem with maxmidi or with my app. Any pointers/help appreciated.
Freq (22) [Avatar] Offline
#2
Re: MIDI clock problems
A little update:

I've run a few tests and I'm getting MIDIERR_NOTREADY on some calls to:

midiOutShortMsg(lpMO->hMidiOut, (DWORD)MIDI_CLOCK);

Seems to happen when I flush the buffer (I have to do that every so often because my app is loop based).

Any ideas? Why is it telling me the driver is busy? Shouldn't it be buffering the midi_clock message instead?
KUMA (56) [Avatar] Offline
#3
Re: MIDI clock problems
Hi, Freq!

As a simple flushing with FlushMidiOut() may cause endless notes, you must have coped with it with some gimmic.
Isn't it possible that it causes the problem?

By the way, now we know that we can attach mutiple output structures to a single sync structure and no merging is needed. So I have realized that output buffers are not necessary, or rather I can utilize them instead of tracks. So far, that goes well.
Freq (22) [Avatar] Offline
#4
Re: MIDI clock problems
Hi Kuma!

Yeah, you're right. The Flush does cause a lot of note off messages and it was jamming up the MIDI port. But I actually found an elegant solution that really works well for this and I can still call the flush without worrying about a NOTREADY error. What I've done is if I get an error when trying to send a clock message, I'll wait for the next sync() before sending it. I store the number of missed clock messages in the MidiOut struct (I added nClocks to the structure) so that the next sync() call can send them instead. It works wonderfully. I'm so happy. My software is now fully functional and I managed to jam with a live drummer (on an electronic drum set), two keyboards, 3 beatboxes and a few pre sequenced melodies without any noticeable lag at all. And I'm running this off a Celeron 500 laptop on Win98SE. Time to start making music!!!

FYI, this is what the new code looks like:

lpMO->nclocks += nclocks;

if((lpMO->dwFlags & SYNC_OUTPUT) && (lpSync->wSyncMode != S_MIDI))
while((lpMO->nclocks > 0)
&& (midiOutShortMsg(lpMO->hMidiOut, (DWORD)MIDI_CLOCK) == MMSYSERR_NOERROR))
lpMO->nclocks--;


So, my modified MaxMidi DLLs (v.1.57):
- uses absolute time
- doesn't miss midi clock messages (no drift)
- allows for multiple opens on a same device

I can send you a copy of the code Kuma if you want or a list of the modifications to the code.

a.
Freq (22) [Avatar] Offline
#5
Re: MIDI clock problems
>> So I have realized that output buffers are not necessary, or rather I can utilize them instead of tracks.

I think you'll still need to maintain your own buffers/tracks because if a user changes a note, you'll need to flush the midiout buffer and recreate it. I handle my own tracks and when a note changes, I have an updateBuffer() function that reads through the notes in a track, sorts them by time and sends it to he midiout. It isn't a big job for me because all my tracks are loops so I'm typically only sorting 4 bars worth of notes. I create an array based on that and just loop through the array until the MidiOut buffer is full. I can't recall what kind of app your building. Is it loop based?
KUMA (56) [Avatar] Offline
#6
Re: MIDI clock problems
Slightly modifying sync(), I can loop specified series of events specified times in output buffers. Though I can't change events on the fly for now, the flushing seems not to be necessary. (I'm going to modify and make use of CMaxMidiTrack functions to maintain the buffers/tracks.)