From: Tim E. R. <ter...@ro...> - 2011-01-17 19:18:51
|
On January 17, 2011 11:33:33 am you wrote: > Hi Tim, > > hope all is well with you! > > I did a checkin just now that I thought I would mention, it was simple > but as I don't grokk all of muse's internals, especially not the midi > stuff I thought you might want to chime in. > As Alex noted some weeks ago the panic button didn't do anything. As I > understand the code this is due to an optimization, if the hardware > state is unchanged we don't send anything. > So I added a 'forceSend' flag, which makes the routine always send the > note. > > If that doesn't sound like the right fix do point me in the right direction > :) > > The code: > ::panic() > > http://lmuse.svn.sourceforge.net/viewvc/lmuse/trunk/muse2/muse/midi.cpp?r1= >755&r2=754&pathrev=755 > > ::sendEvent > > http://lmuse.svn.sourceforge.net/viewvc/lmuse/trunk/muse2/muse/midiport.cpp >?r1=755&r2=754&pathrev=755 > > -- > Also, I told you earlier that I sometimes get no sound from MESS > synths and was going to send you a printout. This happened now again, > several times actually, so I managed to copy the trace: > frame > endPos!! frame = 578923641 >= endPos 128, i->time() 122, > frameOffset -578923519 curPos=0 > frame > endPos!! frame = 578922890 >= endPos 128, i->time() 11, > frameOffset -578922879 curPos=0 > frame > endPos!! frame = 578908676 >= endPos 128, i->time() 5, > frameOffset -578908671 curPos=0 > frame > endPos!! frame = 578896199 >= endPos 128, i->time() 72, > frameOffset -578896127 curPos=0 > frame > endPos!! frame = 578896037 >= endPos 128, i->time() 38, > frameOffset -578895999 curPos=0 > frame > endPos!! frame = 578894445 >= endPos 128, i->time() 110, > frameOffset -578894335 curPos=0 > frame > endPos!! frame = 578892323 >= endPos 128, i->time() 36, > frameOffset -578892287 curPos=0 > frame > endPos!! frame = 578888135 >= endPos 128, i->time() 72, > frameOffset -578888063 curPos=0 > frame > endPos!! frame = 578886113 >= endPos 128, i->time() 98, > frameOffset -578886015 curPos=0 > frame > endPos!! frame = 578885994 >= endPos 128, i->time() 107, > frameOffset -578885887 curPos=0 > frame > endPos!! frame = 578882048 >= endPos 128, i->time() 1, > frameOffset -578882047 curPos=0 > frame > endPos!! frame = 578882174 >= endPos 128, i->time() 127, > frameOffset -578882047 curPos=0 > > I was tempted to try without this test since the DSSI synths seems to > do well without them but didn't yet... > > Regards, > Robert Howdy! I should have committed what I've got so far, but things are much improved. First, I got rid of the MidiDevice::nextPlayEvent iterator. This iterator was not pointing to the right places sometimes, and was causing problems. Now, instead of Audio::processMidi erasing 'already-played' notes at the top, each midi device is responsible for erasing the notes, immediately after playing them. This also allowed me to re-write MidiInstrument::reset (called by clicking "Midi -> Reset Instr.") to place all 2048 note-off events into the device's play events list, rather than the FIFOs, which are much too small for that. I will also do the same for the controller initializations, which can also number in the thousands of events. I also re-wrote the Jack midi, (and ALSA midi and Synth midi) processors so that there are no more 'lost' events due to buffer overflow. Now, Jack midi properly stops processing events until the next cycle. It works! Also, I finally fixed DSSI timing. Did it properly. No notes are missed now. A test song with a scary sub-tick timing, which misses notes in muse-1, now plays properly in muse-2. Lastly, OSC messages are now time-stamped, and I will try to fix slow OSC event processing, splitting up DSSI process into sections (as PD agreed when I asked him - he said Ardour does that). Hang in there - please try not to fix too much in these areas, I'm on it! Will commit soon. I will update to, and review, your changes now... Thanks Tim. |
From: Tim E. R. <ter...@ro...> - 2011-01-18 23:11:44
|
On January 17, 2011 02:09:49 pm Tim E. Real wrote: > First, I got rid of the MidiDevice::nextPlayEvent iterator. > This iterator was not pointing to the right places sometimes, and > was causing problems. > Now, instead of Audio::processMidi erasing 'already-played' notes at the > top, each midi device is responsible for erasing the notes, immediately > after playing them. > > This also allowed me to re-write MidiInstrument::reset (called by clicking > "Midi -> Reset Instr.") to place all 2048 note-off events into the > device's play events list, rather than the FIFOs, which are much too small > for that. I will also do the same for the controller initializations, which > can also number in the thousands of events. Just a technical footnote: Looking at MidiSeq::msgSetMidiDevice (which eventually sends out the bunch of controller initializations), it runs in the GUI thread to avoid time-outs in the RT thread. My plan there is to keep the current structure of using putEvent, but modify it by having it wait until all the events are processed. If after a few seconds, the events could not be processed, it will give up. It is the GUI thread after all, and we can afford to make it wait around for a few seconds while things are processed. Here, we can't go the other option and put the events into the device's play events list because it is not synchronized with the audio thread, and the list might be altered while processing it in the audio thread - not good. (That's the reason why we have both Jack midi FIFOs and play event lists). So, I think I will revert MidiInstrument::reset to use putEvent, but I will change it to run in the GUI thread, just like MidiSeq::msgSetMidiDevice, and make it wait around for a few seconds until done. MidiInstrument::reset is run in, and synchronized with, the audio thread, which made using the play events list OK. But with 2048 events being allocated into the play events lists, this might cause a time-out in the RT audio thread. So I think running it in the GUI thread might be a better solution, where we can have it wait around for a few seconds. This would go for anything which wants to dump a whole bunch of events at once, depending on whether or not it is synchronized with the audio. Ironically, Audio::processMidi does just that - allocates a bunch of events to be played, into the play events lists, and that's from the RT audio thread! But usually nowhere near as many as the 2048 events which reset wants to put there - just simply the next group of song play events. Well, hopefully I'll figure it out and find the best solutions for sending such 'large event blocks'. Tim. |
From: Luis G. <lui...@us...> - 2011-01-19 08:08:08
|
On Wed, Jan 19, 2011 at 12:02 AM, Tim E. Real <ter...@ro...> wrote: > Well, hopefully I'll figure it out and find the best solutions for sending such > 'large event blocks'. May be I am missing something obvious, but, what about a third thread? Then you don't block the GUI. Luis |
From: Tim E. R. <ter...@ro...> - 2011-01-19 19:17:26
|
On January 19, 2011 03:08:01 am Luis Garrido wrote: > On Wed, Jan 19, 2011 at 12:02 AM, Tim E. Real <ter...@ro...> wrote: > > Well, hopefully I'll figure it out and find the best solutions for > > sending such 'large event blocks'. > > May be I am missing something obvious, but, what about a third thread? > Then you don't block the GUI. > > Luis Yes good point. A worker thread. It occurred to me yesterday. But I figured, might as well block the user from making any more GUI choices for a few seconds after selecting for ex. 'Init Instr.' to avoid potential mess-ups, like if they hit 'play' and we've not yet finished sending out all the init events. I figured, GUI thread seems like a good place to do it, but still, a worker thread could probably be made to co-exist somehow if we can avoid problems. Tim. |
From: Geoff B. <ge...@la...> - 2011-01-17 22:48:53
|
whew! sounds fantastic!! can't wait for the commits ;) g. |