Conversion of mci midi sequencer. Originals on \\sysuk1\data\win31mm\src\sonic\mciseq List utility ------------ LIST H 1238 - List management definitions LIST C 5648 - Memory management SUPPORT C ** NEW FOR NT ** (replace .asm etc). Common header file ------------------ MMSYS H 7810 - Common definitions for MCI and SEQ MCI processing -------------- MCISEQ H 5410 - Definitions for MCI part of driver MCICMDS C 23354 - Commands from mciDriverEntry - msXxx MCISEQ C 36751 - DriverProc -> mciDriverEntry CALLBACK C 2147 - Sequencer callback FORMATS C 10845 - Time formats -- Convert to passing around MMTIME structures ? Sequencer --------- MMSEQI H 13524 - Definitions local to mmseq.c (internal sequencer) MMSEQ C 63220 - midiSeqMessage - the sequencer MMSEQ D 3116 - Doc UTIL C 21200 - callback, track and timer helpers for sequencer Other bits (not reqd for NT) ---------------------------- TASK ASM 2856 - interface to mmTask (why ?) CRIT ASM 1895 - critical sections MCISEQ DEF 304 - def file DATA FLOW ================================================================== MCI (MMSYS.H) SEQ midiSeqMessage (SEQ_...) ---------------------> MIDISEQINFO MIDISEQOPEN MIDISEQHDR MIDISEQCALLBACK (MIDISEQ_...) DONE -> TaskSignal - TO stream task DONEPLAY -> TaskSignal - TO stream task RESET -> StreamTrackReset -> TaskSignal <--------------------- MIDISEQERR_... <--------------------- ================================================================== Notes : mciGetDriverData returns a pointer to the stream - SeqStreamType so the stream is equated to a logical device. GETMOTWORD = 'Get Motorola word' (!) Within the timer interrupt routine use the critical section to get the other side of the mutual exclusion. SERIALIZATION : A critical section is used which is held over calls to mciDriverEntry and in the sequencer tasks but released when getting messages (blocking) or temporarily while yielding. STRUCTURE ========= DRV_... + MCI_... messages (mciseq.c!DriverEntry) | V MCI messages : (mciseq.c!mciDriverEntry) MCI_OPEN_DRIVER mcicmds.c!msOpen MCI_CLOSE_DRIVER mcicmds.c!msClose MCI_PLAY mcicmds.c!msPlay MCI_PAUSE MCI_STOP mmseq.c!midiSeqMessage SEQ_SETPORTOFF MCI_SEEK mcicmds.c!msSeek MCI_STATUS mcicmds.c!msStatus MCI_GETDEVCAPS mcicmds.c!msGetDevCaps MCI_INFO mcicmds.c!msInfo MCI_SET mcicmds.c!msSet Rest unsupported MMSEQ messages : (mmseq.c!midiSeqMessage) SEQ_OPEN .................................................................... Tasking structure : ------------------- Application task : mcicmds.c!msOpen | V mciseq.c!msOpenStream -> mmTaskCreate with routine mciStreamCycle | V TaskSignal PostAppMessage . . WTM_QUITTASK, WTM_DONEPLAY, WTM_FILLBUFFER . Sequencer task : GetMessage TaskBlock | V mciseq.c!mciStreamCycle | V mmseq.c!midiSeqMessage - SEQ_TRACKDATA, SEQ_SETPORTOFF | SEQ_GETINFO V NewTrackData mciStreamCycle just keeps the buffers for the current stream stoked up. Thus : there is 1 (extra) task PER LOGICAL DEVICE. There is 1 SEQ structure per task and 1 stream structure per task (which contains an HMIDISEQ handle hSeq to the SEQ structure). The SEQ structure remembers the HTASK. The SeqStreamType structure is the per-stream data on the MCI side. This is unfortunately shared between application and stream tasks. There is no need to inhibit threading between sequencer tasks, only between the main task and associated sequencer tasks. Use of Yield etc : mciseq.c!msOpenStream - appears to have a spurious yield near the start mcicmds.c!msOpen - calls Yield to allow the stream task to start properly. We need to force this to happen now. Note that this is subtle because multiple people might be running - so we probably need a special event per task. mcicmds.c!msPlay - sits in a loop at the moment ! Need the event again. mmseq NEVER yields or blocks mciseq.c!mciStreamCycle : TaskBlock near start when finished init - other side of Yield in msOpen. Also later Blocks again for more work. This is the other side of msPlay ? mmTaskYeild - probably unnecessary since nothing was kicked off ? ...................................................................... MIDISEQ_DONE Timers : ======== util.c!OneShotTimer has pointer to NPSEQ structure passed to it. | --> mmseq.c!TimerIntRoutine | | util.c!MIDICallback Conversion Issues tasking File format Seems OK because : 1. mmio... is used to get at the chunks 2. The data is in big-endian format and macros are used which will work for either format (GETMODWORD, GETMOTDWORD etc). file access OK - via MMIO parameter sizes api build globals list.c - arrayOfLists window messages alignment / structure packing / structure overlays Comments : ========== 1. This code is essentially uncommented. On the positive side the structure is reasonably clean (though overcomplex and relying on 'messages' (untyped calls) rather than subroutine calls which means many bugs will get by the compiler into runtime code. BUGS ==== Pointer to MMIOPROC in mcicmds.c should be pointer to pointer to.