diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/midi/CircBuf.pas | 248 | ||||
-rw-r--r-- | src/lib/midi/DelphiMcb.pas | 210 | ||||
-rw-r--r-- | src/lib/midi/MidiComp.dpk | 16 | ||||
-rw-r--r-- | src/lib/midi/MidiCons.pas | 52 | ||||
-rw-r--r-- | src/lib/midi/MidiDefs.pas | 53 | ||||
-rw-r--r-- | src/lib/midi/MidiFile.pas | 174 | ||||
-rw-r--r-- | src/lib/midi/MidiIn.pas | 129 | ||||
-rw-r--r-- | src/lib/midi/MidiOut.pas | 143 | ||||
-rw-r--r-- | src/lib/midi/MidiScope.pas | 142 | ||||
-rw-r--r-- | src/lib/midi/MidiType.pas | 87 | ||||
-rw-r--r-- | src/lib/midi/demo/MidiTest.pas | 56 | ||||
-rw-r--r-- | src/lib/midi/readme.txt | 12 |
12 files changed, 651 insertions, 671 deletions
diff --git a/src/lib/midi/CircBuf.pas b/src/lib/midi/CircBuf.pas index 571d1ee4..995b82ac 100644 --- a/src/lib/midi/CircBuf.pas +++ b/src/lib/midi/CircBuf.pas @@ -5,19 +5,19 @@ { A First-In First-Out circular buffer. - Port of circbuf.c from Microsoft's Windows MIDI monitor example. + Port of circbuf.c from Microsoft's Windows Midi monitor example. I did do a version of this as an object (see Rev 1.1) but it was getting too complicated and I couldn't see any real benefits to it so I dumped it for an ordinary memory buffer with pointers. This unit is a bit C-like, everything is done with pointers and extensive - use is made of the undocumented feature of the Inc() function that + use is made of the undocumented feature of the inc() function that increments pointers by the size of the object pointed to. All of this could probably be done using Pascal array notation with range-checking turned off, but I'm not sure it's worth it. } -Unit CircBuf; +unit CircBuf; interface @@ -26,158 +26,158 @@ interface {$H+} // use long strings {$ENDIF} -Uses +uses Windows, MMSystem; type - { MIDI input event } - TMidiBufferItem = record - timestamp: DWORD; { Timestamp in milliseconds after midiInStart } - data: DWORD; { MIDI message received } - sysex: PMidiHdr; { Pointer to sysex MIDIHDR, nil if not sysex } - end; - PMidiBufferItem = ^TMidiBufferItem; - - { MIDI input buffer } - TCircularBuffer = record - RecordHandle: HGLOBAL; { Windows memory handle for this record } - BufferHandle: HGLOBAL; { Windows memory handle for the buffer } - pStart: PMidiBufferItem; { ptr to start of buffer } - pEnd: PMidiBufferItem; { ptr to end of buffer } - pNextPut: PMidiBufferItem; { next location to fill } - pNextGet: PMidiBufferItem; { next location to empty } - Error: Word; { error code from MMSYSTEM functions } - Capacity: Word; { buffer size (in TMidiBufferItems) } - EventCount: Word; { Number of events in buffer } - end; - - PCircularBuffer = ^TCircularBuffer; - -function GlobalSharedLockedAlloc( Capacity: Word; var hMem: HGLOBAL ): Pointer; -procedure GlobalSharedLockedFree( hMem: HGLOBAL; ptr: Pointer ); - -function CircbufAlloc( Capacity: Word ): PCircularBuffer; -procedure CircbufFree( PBuffer: PCircularBuffer ); -function CircbufRemoveEvent( PBuffer: PCircularBuffer ): Boolean; -function CircbufReadEvent( PBuffer: PCircularBuffer; PEvent: PMidiBufferItem ): Boolean; + { Midi input event } + TMidiBufferItem = record + timestamp: dword; { Timestamp in milliseconds after midiInStart } + data: dword; { Midi message received } + sysex: PMidiHdr; { Pointer to sysex MIDIHDR, nil if not sysex } + end; + PMidiBufferItem = ^TMidiBufferItem; + + { Midi input buffer } + TCircularBuffer = record + RecordHandle: HGLOBAL; { Windows memory handle for this record } + BufferHandle: HGLOBAL; { Windows memory handle for the buffer } + pStart: PMidiBufferItem; { ptr to start of buffer } + pEnd: PMidiBufferItem; { ptr to end of buffer } + pNextPut: PMidiBufferItem; { next location to fill } + pNextGet: PMidiBufferItem; { next location to empty } + Error: word; { error code from MMSYSTEM functions } + Capacity: word; { buffer size (in TMidiBufferItems) } + EventCount: word; { Number of events in buffer } + end; + + PCircularBuffer = ^TCircularBuffer; + +function GlobalSharedLockedAlloc(Capacity: word; var hMem: HGLOBAL): pointer; +procedure GlobalSharedLockedFree(hMem: HGLOBAL; ptr: pointer); + +function CircbufAlloc(Capacity: word): PCircularBuffer; +procedure CircbufFree(PBuffer: PCircularBuffer); +function CircbufRemoveEvent(PBuffer: PCircularBuffer): boolean; +function CircbufReadEvent(PBuffer: PCircularBuffer; PEvent: PMidiBufferItem): boolean; { Note: The PutEvent function is in the DLL } implementation { Allocates in global shared memory, returns pointer and handle } -function GlobalSharedLockedAlloc( Capacity: Word; var hMem: HGLOBAL ): Pointer; +function GlobalSharedLockedAlloc(Capacity: word; var hMem: HGLOBAL): pointer; var - ptr: Pointer; + ptr: pointer; begin - { Allocate the buffer memory } - hMem := GlobalAlloc(GMEM_SHARE Or GMEM_MOVEABLE Or GMEM_ZEROINIT, Capacity ); - - if (hMem = 0) then - ptr := Nil - else - begin - ptr := GlobalLock(hMem); - if (ptr = Nil) then - GlobalFree(hMem); - end; - - GlobalSharedLockedAlloc := Ptr; + { Allocate the buffer memory } + hMem := GlobalAlloc(GMEM_SHARE Or GMEM_MOVEABLE Or GMEM_ZEROINIT, Capacity); + + if hMem = 0 then + ptr := nil + else + begin + ptr := GlobalLock(hMem); + if ptr = nil then + GlobalFree(hMem); + end; + + GlobalSharedLockedAlloc := Ptr; end; -procedure GlobalSharedLockedFree( hMem: HGLOBAL; ptr: Pointer ); +procedure GlobalSharedLockedFree(hMem: HGLOBAL; ptr: pointer); begin - if (hMem <> 0) then - begin - GlobalUnlock(hMem); - GlobalFree(hMem); - end; + if hMem <> 0 then + begin + GlobalUnlock(hMem); + GlobalFree(hMem); + end; end; -function CircbufAlloc( Capacity: Word ): PCircularBuffer; +function CircbufAlloc(Capacity: word): PCircularBuffer; var - NewCircularBuffer: PCircularBuffer; - NewMIDIBuffer: PMidiBufferItem; - hMem: HGLOBAL; + NewCircularBuffer: PCircularBuffer; + NewMidiBuffer: PMidiBufferItem; + hMem: HGLOBAL; begin - { TODO: Validate circbuf size, <64K } - NewCircularBuffer := - GlobalSharedLockedAlloc( Sizeof(TCircularBuffer), hMem ); - if (NewCircularBuffer <> Nil) then - begin - NewCircularBuffer^.RecordHandle := hMem; - NewMIDIBuffer := - GlobalSharedLockedAlloc( Capacity * Sizeof(TMidiBufferItem), hMem ); - if (NewMIDIBuffer = Nil) then - begin - { TODO: Exception here? } - GlobalSharedLockedFree( NewCircularBuffer^.RecordHandle, - NewCircularBuffer ); - NewCircularBuffer := Nil; - end - else - begin - NewCircularBuffer^.pStart := NewMidiBuffer; - { Point to item at end of buffer } - NewCircularBuffer^.pEnd := NewMidiBuffer; - Inc(NewCircularBuffer^.pEnd, Capacity); - { Start off the get and put pointers in the same position. These - will get out of sync as the interrupts start rolling in } - NewCircularBuffer^.pNextPut := NewMidiBuffer; - NewCircularBuffer^.pNextGet := NewMidiBuffer; - NewCircularBuffer^.Error := 0; - NewCircularBuffer^.Capacity := Capacity; - NewCircularBuffer^.EventCount := 0; - end; - end; - CircbufAlloc := NewCircularBuffer; + { TODO: Validate circbuf size, <64K } + NewCircularBuffer := + GlobalSharedLockedAlloc(Sizeof(TCircularBuffer), hMem); + if NewCircularBuffer <> nil then + begin + NewCircularBuffer^.RecordHandle := hMem; + NewMidiBuffer := + GlobalSharedLockedAlloc(Capacity * Sizeof(TMidiBufferItem), hMem); + if NewMidiBuffer = nil then + begin + { TODO: Exception here? } + GlobalSharedLockedFree(NewCircularBuffer^.RecordHandle, + NewCircularBuffer); + NewCircularBuffer := nil; + end + else + begin + NewCircularBuffer^.pStart := NewMidiBuffer; + { Point to item at end of buffer } + NewCircularBuffer^.pEnd := NewMidiBuffer; + inc(NewCircularBuffer^.pEnd, Capacity); + { Start off the get and put pointers in the same position. These + will get out of sync as the interrupts start rolling in } + NewCircularBuffer^.pNextPut := NewMidiBuffer; + NewCircularBuffer^.pNextGet := NewMidiBuffer; + NewCircularBuffer^.Error := 0; + NewCircularBuffer^.Capacity := Capacity; + NewCircularBuffer^.EventCount := 0; + end; + end; + CircbufAlloc := NewCircularBuffer; end; -procedure CircbufFree( pBuffer: PCircularBuffer ); +procedure CircbufFree(pBuffer: PCircularBuffer); begin - if (pBuffer <> Nil) then - begin - GlobalSharedLockedFree(pBuffer^.BufferHandle, pBuffer^.pStart); - GlobalSharedLockedFree(pBuffer^.RecordHandle, pBuffer); - end; + if pBuffer <> nil then + begin + GlobalSharedLockedFree(pBuffer^.BufferHandle, pBuffer^.pStart); + GlobalSharedLockedFree(pBuffer^.RecordHandle, pBuffer); + end; end; { Reads first event in queue without removing it. Returns true if successful, False if no events in queue } -function CircbufReadEvent( PBuffer: PCircularBuffer; PEvent: PMidiBufferItem ): Boolean; +function CircbufReadEvent(PBuffer: PCircularBuffer; PEvent: PMidiBufferItem): boolean; var - PCurrentEvent: PMidiBufferItem; + PCurrentEvent: PMidiBufferItem; begin - if (PBuffer^.EventCount <= 0) then - CircbufReadEvent := False - else - begin - PCurrentEvent := PBuffer^.PNextget; - - { Copy the object from the "tail" of the buffer to the caller's object } - PEvent^.Timestamp := PCurrentEvent^.Timestamp; - PEvent^.Data := PCurrentEvent^.Data; - PEvent^.Sysex := PCurrentEvent^.Sysex; - CircbufReadEvent := True; - end; + if PBuffer^.EventCount <= 0 then + CircbufReadEvent := false + else + begin + PCurrentEvent := PBuffer^.PNextget; + + { Copy the object from the "tail" of the buffer to the caller's object } + PEvent^.Timestamp := PCurrentEvent^.Timestamp; + PEvent^.Data := PCurrentEvent^.Data; + PEvent^.Sysex := PCurrentEvent^.Sysex; + CircbufReadEvent := true; + end; end; { Remove current event from the queue } -function CircbufRemoveEvent(PBuffer: PCircularBuffer): Boolean; +function CircbufRemoveEvent(PBuffer: PCircularBuffer): boolean; begin - if (PBuffer^.EventCount > 0) then - begin - Dec( Pbuffer^.EventCount); - - { Advance the buffer pointer, with wrap } - Inc( Pbuffer^.PNextGet ); - If (PBuffer^.PNextGet = PBuffer^.PEnd) then - PBuffer^.PNextGet := PBuffer^.PStart; - - CircbufRemoveEvent := True; - end - else - CircbufRemoveEvent := False; + if PBuffer^.EventCount > 0 then + begin + dec(Pbuffer^.EventCount); + + { Advance the buffer pointer, with wrap } + inc(Pbuffer^.PNextGet); + if PBuffer^.PNextGet = PBuffer^.PEnd then + PBuffer^.PNextGet := PBuffer^.PStart; + + CircbufRemoveEvent := true; + end + else + CircbufRemoveEvent := false; end; end. diff --git a/src/lib/midi/DelphiMcb.pas b/src/lib/midi/DelphiMcb.pas index 39b1c61f..5686e227 100644 --- a/src/lib/midi/DelphiMcb.pas +++ b/src/lib/midi/DelphiMcb.pas @@ -1,10 +1,10 @@ { $Header: /MidiComp/DelphiMcb.pas 2 10/06/97 7:33 Davec $ } -{MIDI callback for Delphi, was DLL for Delphi 1} +{Midi callback for Delphi, was DLL for Delphi 1} unit DelphiMcb; -{ These segment options required for the MIDI callback functions } +{ These segment options required for the Midi callback functions } {$IFNDEF FPC} {$C PRELOAD FIXED PERMANENT} {$ENDIF} @@ -23,118 +23,118 @@ uses MidiDefs, MidiCons; -procedure midiHandler( - hMidiIn: HMidiIn; - wMsg: UINT; - dwInstance: DWORD; - dwParam1: DWORD; - dwParam2: DWORD); stdcall; export; -function CircbufPutEvent(PBuffer: PCircularBuffer; PTheEvent: PMidiBufferItem): Boolean; stdcall; export; +procedure MidiHandler( + hMidiIn: HMidiIn; + wMsg: uint; + dwInstance: dword; + dwParam1: dword; + dwParam2: dword); stdcall; export; + +function CircbufPutEvent(PBuffer: PCircularBuffer; PTheEvent: PMidiBufferItem): boolean; stdcall; export; implementation { Add an event to the circular input buffer. } -function CircbufPutEvent(PBuffer: PCircularBuffer; PTheEvent: PMidiBufferItem): Boolean; stdcall; +function CircbufPutEvent(PBuffer: PCircularBuffer; PTheEvent: PMidiBufferItem): boolean; stdcall; begin - If (PBuffer^.EventCount < PBuffer^.Capacity) Then - begin - Inc(Pbuffer^.EventCount); - - { Todo: better way of copying this record } - with PBuffer^.PNextput^ do - begin - Timestamp := PTheEvent^.Timestamp; - Data := PTheEvent^.Data; - Sysex := PTheEvent^.Sysex; - end; - - { Move to next put location, with wrap } - Inc(Pbuffer^.PNextPut); - If (PBuffer^.PNextPut = PBuffer^.PEnd) then - PBuffer^.PNextPut := PBuffer^.PStart; - - CircbufPutEvent := True; - end - else - CircbufPutEvent := False; + if PBuffer^.EventCount < PBuffer^.Capacity then + begin + inc(Pbuffer^.EventCount); + + { Todo: better way of copying this record } + with PBuffer^.PNextput^ do + begin + Timestamp := PTheEvent^.Timestamp; + Data := PTheEvent^.Data; + Sysex := PTheEvent^.Sysex; + end; + + { Move to next put location, with wrap } + inc(Pbuffer^.PNextPut); + if PBuffer^.PNextPut = PBuffer^.PEnd then + PBuffer^.PNextPut := PBuffer^.PStart; + + CircbufPutEvent := true; + end + else + CircbufPutEvent := false; end; -{ This is the callback function specified when the MIDI device was opened - by midiInOpen. It's called at interrupt time when MIDI input is seen - by the MIDI device driver(s). See the docs for midiInOpen for restrictions +{ This is the callback function specified when the Midi device was opened + by MidiInOpen. It's called at interrupt time when Midi input is seen + by the Midi device driver(s). See the docs for MidiInOpen for restrictions on the Windows functions that can be called in this interrupt. } -procedure midiHandler( - hMidiIn: HMidiIn; - wMsg: UINT; - dwInstance: DWORD; - dwParam1: DWORD; - dwParam2: DWORD); stdcall; +procedure MidiHandler( + hMidiIn: HMidiIn; + wMsg: dword; + dwInstance: dword; + dwParam1: dword; + dwParam2: dword); stdcall; var - thisEvent: TMidiBufferItem; - thisCtlInfo: PMidiCtlInfo; - thisBuffer: PCircularBuffer; -Begin - case wMsg of - - mim_Open: {nothing}; - - mim_Error: {TODO: handle (message to trigger exception?) }; - - mim_Data, mim_Longdata, mim_Longerror: - { Note: mim_Longerror included because there's a bug in the Maui - input driver that sends MIM_LONGERROR for subsequent buffers when - the input buffer is smaller than the sysex block being received } - - begin - { TODO: Make filtered messages customisable, I'm sure someone wants to - do something with MTC! } - if (dwParam1 <> MIDI_ACTIVESENSING) and - (dwParam1 <> MIDI_TIMINGCLOCK) then - begin - - { The device driver passes us the instance data pointer we - specified for midiInOpen. Use this to get the buffer address - and window handle for the MIDI control } - thisCtlInfo := PMidiCtlInfo(dwInstance); - thisBuffer := thisCtlInfo^.PBuffer; - - { Screen out short messages if we've been asked to } - if ((wMsg <> mim_Data) or (thisCtlInfo^.SysexOnly = False)) - and (thisCtlInfo <> Nil) and (thisBuffer <> Nil) then - begin - with thisEvent do - begin - timestamp := dwParam2; - if (wMsg = mim_Longdata) or - (wMsg = mim_Longerror) then - begin - data := 0; - sysex := PMidiHdr(dwParam1); - end - else - begin - data := dwParam1; - sysex := Nil; - end; - end; - if CircbufPutEvent( thisBuffer, @thisEvent ) then - { Send a message to the control to say input's arrived } - PostMessage(thisCtlInfo^.hWindow, mim_Data, 0, 0) - else - { Buffer overflow } - PostMessage(thisCtlInfo^.hWindow, mim_Overflow, 0, 0); - end; - end; - end; - - mom_Done: { Sysex output complete, dwParam1 is pointer to MIDIHDR } - begin - { Notify the control that its sysex output is finished. - The control should call midiOutUnprepareHeader before freeing the buffer } - PostMessage(PMidiCtlInfo(dwInstance)^.hWindow, mom_Done, 0, dwParam1); - end; - - end; { Case } + thisEvent: TMidiBufferItem; + thisCtlInfo: PMidiCtlInfo; + thisBuffer: PCircularBuffer; +begin + case wMsg of + + mim_Open: {nothing}; + + mim_Error: {TODO: handle (message to trigger exception?) }; + + mim_Data, mim_Longdata, mim_Longerror: + { Note: mim_Longerror included because there's a bug in the Maui + input driver that sends MIM_LONGERROR for subsequent buffers when + the input buffer is smaller than the sysex block being received } + + begin + { TODO: Make filtered messages customisable, I'm sure someone wants to + do something with MTC! } + if (dwParam1 <> MIDI_ACTIVESENSING) and + (dwParam1 <> MIDI_TIMINGCLOCK) then + begin + + { The device driver passes us the instance data pointer we + specified for MidiInOpen. Use this to get the buffer address + and window handle for the Midi control } + thisCtlInfo := PMidiCtlInfo(dwInstance); + thisBuffer := thisCtlInfo^.PBuffer; + + { Screen out short messages if we've been asked to } + if ((wMsg <> mim_Data) or (thisCtlInfo^.SysexOnly = false)) + and (thisCtlInfo <> nil) and (thisBuffer <> nil) then + begin + with thisEvent do + begin + timestamp := dwParam2; + if (wMsg = mim_Longdata) or (wMsg = mim_Longerror) then + begin + data := 0; + sysex := PMidiHdr(dwParam1); + end + else + begin + data := dwParam1; + sysex := nil; + end; + end; + if CircbufPutEvent(thisBuffer, @thisEvent) then + { Send a message to the control to say input's arrived } + PostMessage(thisCtlInfo^.hWindow, mim_Data, 0, 0) + else + { Buffer overflow } + PostMessage(thisCtlInfo^.hWindow, mim_Overflow, 0, 0); + end; + end; + end; + + mom_Done: { Sysex output complete, dwParam1 is pointer to MIDIHDR } + begin + { Notify the control that its sysex output is finished. + The control should call MidiOutUnprepareHeader before freeing the buffer } + PostMessage(PMidiCtlInfo(dwInstance)^.hWindow, mom_Done, 0, dwParam1); + end; + + end; { Case } end; end. diff --git a/src/lib/midi/MidiComp.dpk b/src/lib/midi/MidiComp.dpk index 7c403eae..cf99a3ea 100644 --- a/src/lib/midi/MidiComp.dpk +++ b/src/lib/midi/MidiComp.dpk @@ -1,9 +1,9 @@ -package midiComp;
+package MidiComp;
{$R *.RES}
{$R 'MidiFile.dcr'}
-{$R 'Midiin.dcr'}
-{$R 'Midiout.dcr'}
+{$R 'MidiIn.dcr'}
+{$R 'MidiOut.dcr'}
{$R 'MidiScope.dcr'}
{$ALIGN ON}
{$ASSERTIONS ON}
@@ -34,12 +34,12 @@ requires vcl50;
contains
- Miditype in 'Miditype.pas',
- Mididefs in 'Mididefs.pas',
+ MidiType in 'MidiType.pas',
+ MidiDefs in 'MidiDefs.pas',
MidiFile in 'MidiFile.pas',
- Midiin in 'Midiin.pas',
- Midiout in 'Midiout.pas',
+ MidiIn in 'MidiIn.pas',
+ MidiOut in 'MidiOut.pas',
MidiScope in 'MidiScope.pas',
- Midicons in 'Midicons.pas';
+ MidiCons in 'MidiCons.pas';
end.
diff --git a/src/lib/midi/MidiCons.pas b/src/lib/midi/MidiCons.pas index dbd3c5b7..aa8462c3 100644 --- a/src/lib/midi/MidiCons.pas +++ b/src/lib/midi/MidiCons.pas @@ -4,7 +4,7 @@ released to the public domain. } -{ MIDI Constants } +{ Midi Constants } unit MidiCons; interface @@ -14,33 +14,33 @@ interface {$H+} // use long strings {$ENDIF} -uses Messages; +uses + Messages; const - MIDI_ALLNOTESOFF = $7B; - MIDI_NOTEON = $90; - MIDI_NOTEOFF = $80; - MIDI_KEYAFTERTOUCH = $a0; - MIDI_CONTROLCHANGE = $b0; - MIDI_PROGRAMCHANGE = $c0; - MIDI_CHANAFTERTOUCH = $d0; - MIDI_PITCHBEND = $e0; - MIDI_SYSTEMMESSAGE = $f0; - MIDI_BEGINSYSEX = $f0; - MIDI_MTCQUARTERFRAME = $f1; - MIDI_SONGPOSPTR = $f2; - MIDI_SONGSELECT = $f3; - MIDI_ENDSYSEX = $F7; - MIDI_TIMINGCLOCK = $F8; - MIDI_START = $FA; - MIDI_CONTINUE = $FB; - MIDI_STOP = $FC; - MIDI_ACTIVESENSING = $FE; - MIDI_SYSTEMRESET = $FF; - - MIM_OVERFLOW = WM_USER; { Input buffer overflow } - MOM_PLAYBACK_DONE = WM_USER+1; { Timed playback complete } - + MIDI_ALLNOTESOFF = $7B; + MIDI_NOTEON = $90; + MIDI_NOTEOFF = $80; + MIDI_KEYAFTERTOUCH = $a0; + MIDI_CONTROLCHANGE = $b0; + MIDI_PROGRAMCHANGE = $c0; + MIDI_CHANAFTERTOUCH = $d0; + MIDI_PITCHBEND = $e0; + MIDI_SYSTEMMESSAGE = $f0; + MIDI_BEGINSYSEX = $f0; + MIDI_MTCQUARTERFRAME = $f1; + MIDI_SONGPOSPTR = $f2; + MIDI_SONGSELECT = $f3; + MIDI_ENDSYSEX = $F7; + MIDI_TIMINGCLOCK = $F8; + MIDI_START = $FA; + MIDI_CONTINUE = $FB; + MIDI_STOP = $FC; + MIDI_ACTIVESENSING = $FE; + MIDI_SYSTEMRESET = $FF; + + MIM_OVERFLOW = WM_USER; { Input buffer overflow } + MOM_PLAYBACK_DONE = WM_USER + 1; { Timed playback complete } implementation diff --git a/src/lib/midi/MidiDefs.pas b/src/lib/midi/MidiDefs.pas index f14b5e77..8ec7626e 100644 --- a/src/lib/midi/MidiDefs.pas +++ b/src/lib/midi/MidiDefs.pas @@ -4,7 +4,7 @@ released to the public domain. } -{ Common definitions used by DELPHMID.DPR and the MIDI components. +{ Common definitions used by DELPHMID.DPR and the Midi components. This must be a separate unit to prevent large chunks of the VCL being linked into the DLL. } unit Mididefs; @@ -23,33 +23,32 @@ uses type - {-------------------------------------------------------------------} - { This is the information about the control that must be accessed by - the MIDI input callback function in the DLL at interrupt time } - PMidiCtlInfo = ^TMidiCtlInfo; - TMidiCtlInfo = record - hMem: THandle; { Memory handle for this record } - PBuffer: PCircularBuffer; { Pointer to the MIDI input data buffer } - hWindow: HWnd; { Control's window handle } - SysexOnly: Boolean; { Only process System Exclusive input } - end; - - { Information for the output timer callback function, also required at - interrupt time. } - PMidiOutTimerInfo = ^TMidiOutTimerInfo; - TMidiOutTimerInfo = record - hMem: THandle; { Memory handle for this record } - PBuffer: PCircularBuffer; { Pointer to MIDI output data buffer } - hWindow: HWnd; { Control's window handle } - TimeToNextEvent: DWORD; { Delay to next event after timer set } - MIDIHandle: HMidiOut; { MIDI handle to send output to - (copy of component's FMidiHandle property) } - PeriodMin: Word; { Multimedia timer minimum period supported } - PeriodMax: Word; { Multimedia timer maximum period supported } - TimerId: Word; { Multimedia timer ID of current event } - end; + {-------------------------------------------------------------------} + { This is the information about the control that must be accessed by + the Midi input callback function in the DLL at interrupt time } + PMidiCtlInfo = ^TMidiCtlInfo; + TMidiCtlInfo = record + hMem: THandle; { Memory handle for this record } + PBuffer: PCircularBuffer; { Pointer to the Midi input data buffer } + hWindow: HWnd; { Control's window handle } + SysexOnly: boolean; { Only process System Exclusive input } + end; + + { Information for the output timer callback function, also required at + interrupt time. } + PMidiOutTimerInfo = ^TMidiOutTimerInfo; + TMidiOutTimerInfo = record + hMem: THandle; { Memory handle for this record } + PBuffer: PCircularBuffer; { Pointer to Midi output data buffer } + hWindow: HWnd; { Control's window handle } + TimeToNextEvent: dword; { Delay to next event after timer set } + MidiHandle: HMidiOut; { Midi handle to send output to + (copy of component's FMidiHandle property) } + PeriodMin: word; { Multimedia timer minimum period supported } + PeriodMax: word; { Multimedia timer maximum period supported } + TimerId: word; { Multimedia timer ID of current event } + end; implementation - end. diff --git a/src/lib/midi/MidiFile.pas b/src/lib/midi/MidiFile.pas index acf44c04..c0271521 100644 --- a/src/lib/midi/MidiFile.pas +++ b/src/lib/midi/MidiFile.pas @@ -128,7 +128,7 @@ type TMidiTrack = class(TObject) protected events: TList; - name: string; + name: string; instrument: string; currentTime: integer; currentPos: integer; @@ -162,13 +162,13 @@ type procedure WndProc(var Msg : TMessage); protected { Protected declarations } - midiFile: TBinaryFileStream; + MidiFile: TBinaryFileStream; chunkType: TChunkType; chunkLength: integer; chunkData: PByte; chunkIndex: PByte; chunkEnd: PByte; - FPriority: DWORD; + FPriority: dword; // midi file attributes FFileFormat: TFileFormat; @@ -236,7 +236,8 @@ procedure Register; implementation -uses mmsystem; +uses + mmsystem; type {$IFDEF FPC} @@ -246,40 +247,43 @@ type TTimerProc = TFNTimeCallBack; {$ENDIF} -const TIMER_RESOLUTION=10; -const WM_MULTIMEDIA_TIMER=WM_USER+127; +const + TIMER_RESOLUTION = 10; + WM_MULTIMEDIA_TIMER = WM_USER + 127; -var MIDIFileHandle : HWND; - TimerProc : TTimerProc; - MIDITimerID : Integer; - TimerPeriod : Integer; +var + MidiFileHandle: HWND; + TimerProc: TTimerProc; + MidiTimerID: integer; + TimerPeriod: integer; -procedure TimerCallBackProc(uTimerID,uMsg: Cardinal; dwUser,dwParam1,dwParam2:DWORD);stdcall; +procedure TimerCallBackProc(uTimerID, uMsg: Cardinal; dwUser, dwParam1, dwParam2:dword);stdcall; begin - PostMessage(HWND(dwUser),WM_MULTIMEDIA_TIMER,0,0); + PostMessage(HWND(dwUser), WM_MULTIMEDIA_TIMER, 0, 0); end; -procedure SetMIDITimer; - var TimeCaps : TTimeCaps; +procedure SetMidiTimer; +var + TimeCaps: TTimeCaps; begin - timeGetDevCaps(@TimeCaps,SizeOf(TimeCaps)); + timeGetDevCaps(@TimeCaps, SizeOf(TimeCaps)); if TIMER_RESOLUTION < TimeCaps.wPeriodMin then - TimerPeriod:=TimeCaps.wPeriodMin + TimerPeriod := TimeCaps.wPeriodMin else if TIMER_RESOLUTION > TimeCaps.wPeriodMax then - TimerPeriod:=TimeCaps.wPeriodMax + TimerPeriod := TimeCaps.wPeriodMax else - TimerPeriod:=TIMER_RESOLUTION; + TimerPeriod := TIMER_RESOLUTION; timeBeginPeriod(TimerPeriod); - MIDITimerID:=timeSetEvent(TimerPeriod,TimerPeriod,TimerProc, - DWORD(MIDIFileHandle),TIME_PERIODIC); - if MIDITimerID=0 then + MidiTimerID := timeSetEvent(TimerPeriod, TimerPeriod, TimerProc, + dword(MidiFileHandle), TIME_PERIODIC); + if MidiTimerID=0 then timeEndPeriod(TimerPeriod); end; -procedure KillMIDITimer; +procedure KillMidiTimer; begin - timeKillEvent(MIDITimerID); + timeKillEvent(MidiTimerID); timeEndPeriod(TimerPeriod); end; @@ -307,11 +311,11 @@ var i: integer; pevent: PMidiEvent; begin - if (event.event = $FF) then + if event.event = $FF then begin - if (event.data1 = 3) then + if event.data1 = 3 then name := event.str; - if (event.data1 = 4) then + if event.data1 = 4 then instrument := event.str; end; currentTime := currentTime + event.dticks; @@ -320,8 +324,8 @@ begin events.add(TObject(event)); command := event.event and $F0; - if ((command = $80) // note off - or ((command = $90) and (event.data2 = 0))) //note on with speed 0 + if (command = $80) // note off + or ((command = $90) and (event.data2 = 0)) //note on with speed 0 then begin // this is a note off, try to find the accompanion note on @@ -331,8 +335,7 @@ begin begin pevent := PMidiEvent(events[i]); if (pevent.event = command) and - (pevent.data1 = event.data1) - then + (pevent.data1 = event.data1) then begin pevent.len := currentTIme - pevent.time; i := 0; @@ -360,7 +363,7 @@ end; function TMiditrack.getEvent(index: integer): PMidiEvent; begin - if ((index < events.count) and (index >= 0)) then + if (index < events.count) and (index >= 0) then result := events[index] else result := nil; @@ -375,36 +378,29 @@ procedure TMiditrack.Rewind(pos: integer); begin if currentPos = events.count then dec(currentPos); - while ((currentPos > 0) and - (PMidiEvent(events[currentPos]).time > pos)) - do - begin + while (currentPos > 0) and + (PMidiEvent(events[currentPos]).time > pos) do dec(currentPos); - end; checkReady; end; procedure TMiditrack.PlayUntil(pos: integer); begin if assigned(OnMidiEvent) then - begin while ((currentPos < events.count) and (PMidiEvent(events[currentPos]).time < pos)) do begin OnMidiEvent(PMidiEvent(events[currentPos])); inc(currentPos); end; - end; checkReady; end; procedure TMidiTrack.GoUntil(pos: integer); begin - while ((currentPos < events.count) and - (PMidiEvent(events[currentPos]).time < pos)) do - begin + while (currentPos < events.count) and + (PMidiEvent(events[currentPos]).time < pos) do inc(currentPos); - end; checkReady; end; @@ -433,27 +429,29 @@ end; constructor TMidifile.Create(AOwner: TComponent); begin inherited Create(AOWner); - MIDIFileHandle:=AllocateHWnd(WndProc); + MidiFileHandle := AllocateHWnd(WndProc); chunkData := nil; chunkType := illegal; Tracks := TList.Create; - TimerProc:=@TimerCallBackProc; - FPriority:=GetPriorityClass(MIDIFileHandle); + TimerProc := @TimerCallBackProc; + FPriority := GetPriorityClass(MidiFileHandle); end; destructor TMidifile.Destroy; var i: integer; begin - if not (chunkData = nil) then FreeMem(chunkData); + if not (chunkData = nil) then + FreeMem(chunkData); for i := 0 to Tracks.Count - 1 do TMidiTrack(Tracks.Items[i]).Free; Tracks.Free; - SetPriorityClass(MIDIFileHandle,FPriority); + SetPriorityClass(MidiFileHandle, FPriority); - if MIDITimerID<>0 then KillMIDITimer; + if MidiTimerID <> 0 then + KillMidiTimer; - DeallocateHWnd(MIDIFileHandle); + DeallocateHWnd(MidiFileHandle); inherited Destroy; end; @@ -501,9 +499,9 @@ begin playStartTime := getTickCount; playing := true; - SetPriorityClass(MIDIFileHandle,REALTIME_PRIORITY_CLASS); + SetPriorityClass(MidiFileHandle, REALTIME_PRIORITY_CLASS); - SetMIDITimer; + SetMidiTimer; currentPos := 0.0; currentTime := 0; end; @@ -514,17 +512,17 @@ begin PlayStartTime := GetTickCount - currentTime; playing := true; - SetPriorityClass(MIDIFileHandle,REALTIME_PRIORITY_CLASS); + SetPriorityClass(MidiFileHandle, REALTIME_PRIORITY_CLASS); - SetMIDITimer; + SetMidiTimer; end; {$WARNINGS ON} procedure TMidifile.StopPlaying; begin playing := false; - KillMIDITimer; - SetPriorityClass(MIDIFileHandle,FPriority); + KillMidiTimer; + SetPriorityClass(MidiFileHandle, FPriority); end; function TMidiFile.GetCurrentTime: integer; @@ -586,7 +584,7 @@ procedure TMidifile.ReadChunkHeader; var theByte: array[0..7] of byte; begin - midiFile.Read(theByte[0], 8); + MidiFile.Read(theByte[0], 8); if (theByte[0] = $4D) and (theByte[1] = $54) then begin if (theByte[2] = $68) and (theByte[3] = $64) then @@ -597,9 +595,7 @@ begin chunkType := illegal; end else - begin chunkType := illegal; - end; chunkLength := theByte[7] + theByte[6] * $100 + theByte[5] * $10000 + theByte[4] * $1000000; end; @@ -608,7 +604,7 @@ begin if not (chunkData = nil) then FreeMem(chunkData); GetMem(chunkData, chunkLength + 10); - midiFile.Read(chunkData^, chunkLength); + MidiFile.Read(chunkData^, chunkLength); chunkIndex := chunkData; chunkEnd := PByte(integer(chunkIndex) + integer(chunkLength) - 1); end; @@ -693,7 +689,7 @@ begin inc(chunkIndex); len := ReadVarLength; - midiEvent.str := ReadString(len); + midiEvent.str := ReadString(len); currentTrack.putEvent(midiEvent); end; @@ -826,7 +822,7 @@ end; function TMidifile.ReadString(l: integer): string; var - s: PChar; + s: Pchar; i: integer; begin GetMem(s, l + 1); ; @@ -848,10 +844,10 @@ begin Tracks.Clear; chunkType := illegal; - midiFile := TBinaryFileStream.Create(FFilename, fmOpenRead); - while (midiFile.Position < midiFile.Size) do + MidiFile := TBinaryFileStream.Create(FFilename, fmOpenRead); + while (MidiFile.Position < MidiFile.Size) do ReadChunk; - FreeAndNil(midiFile); + FreeAndNil(MidiFile); numberTracks := Tracks.Count; end; @@ -862,16 +858,16 @@ var begin n := key mod 12; case n of - 0: str := 'C'; - 1: str := 'C#'; - 2: str := 'D'; - 3: str := 'D#'; - 4: str := 'E'; - 5: str := 'F'; - 6: str := 'F#'; - 7: str := 'G'; - 8: str := 'G#'; - 9: str := 'A'; + 0: str := 'C'; + 1: str := 'C#'; + 2: str := 'D'; + 3: str := 'D#'; + 4: str := 'E'; + 5: str := 'F'; + 6: str := 'F#'; + 7: str := 'G'; + 8: str := 'G#'; + 9: str := 'A'; 10: str := 'A#'; 11: str := 'B'; end; @@ -889,18 +885,18 @@ begin end; function MyTimeToStr(val: integer): string; - var +var hour: integer; - min: integer; - sec: integer; + min: integer; + sec: integer; msec: integer; begin msec := val mod 1000; - sec := val div 1000; - min := sec div 60; - sec := sec mod 60; + sec := val div 1000; + min := sec div 60; + sec := sec mod 60; hour := min div 60; - min := min mod 60; + min := min mod 60; Result := IntToStr(hour) + ':' + IntToLenStr(min, 2) + ':' + IntToLenStr(sec, 2) + '.' + IntToLenStr(msec, 3); end; @@ -910,8 +906,9 @@ begin end; function TMidiFIle.GetTrackLength:integer; -var i,length : integer; - time : extended; +var + i, length: integer; + time: extended; begin length := 0; for i := 0 to Tracks.Count - 1 do @@ -923,7 +920,8 @@ begin end; function TMidiFIle.Ready: boolean; -var i : integer; +var + i : integer; begin result := true; for i := 0 to Tracks.Count - 1 do @@ -934,12 +932,13 @@ end; procedure TMidiFile.OnTrackReady; begin if ready then - if assigned(FOnUpdateEvent) then FOnUpdateEvent(self); + if assigned(FOnUpdateEvent) then + FOnUpdateEvent(self); end; procedure TMidiFile.WndProc(var Msg : TMessage); begin - with MSG do + with Msg do begin case Msg of WM_MULTIMEDIA_TIMER: @@ -953,7 +952,7 @@ begin end; else begin - Result := DefWindowProc(MIDIFileHandle, Msg, wParam, lParam); + Result := DefWindowProc(MidiFileHandle, Msg, wParam, lParam); end; end; end; @@ -965,4 +964,3 @@ begin end; end. - diff --git a/src/lib/midi/MidiIn.pas b/src/lib/midi/MidiIn.pas index 5ff17ae8..7587a3eb 100644 --- a/src/lib/midi/MidiIn.pas +++ b/src/lib/midi/MidiIn.pas @@ -7,26 +7,26 @@ unit MidiIn; { Properties: - DeviceID: Windows numeric device ID for the MIDI input device. + DeviceID: Windows numeric device ID for the MIDI input device. Between 0 and NumDevs-1. Read-only while device is open, exception when changed while open - MIDIHandle: The input handle to the MIDI device. + MIDIHandle: The input handle to the MIDI device. 0 when device is not open Read-only, runtime-only - MessageCount: Number of input messages waiting in input buffer + MessageCount: Number of input messages waiting in input buffer - Capacity: Number of messages input buffer can hold + Capacity: Number of messages input buffer can hold Defaults to 1024 Limited to (64K/event size) Read-only when device is open (exception when changed while open) - SysexBufferSize: Size in bytes of each sysex buffer + SysexBufferSize: Size in bytes of each sysex buffer Defaults to 10K Minimum 0K (no buffers), Maximum 64K-1 - SysexBufferCount: Number of sysex buffers + SysexBufferCount: Number of sysex buffers Defaults to 16 Minimum 0 (no buffers), Maximum (avail mem/SysexBufferSize) Check where these buffers are allocated? @@ -83,7 +83,7 @@ unit MidiIn; are removed from the circular buffer by the GetMidiEvent method the buffers are put back on the input. If all the buffers are used up there will be no more sysex input until at least one sysex event is removed from the input buffer. - In other words if you're expecting lots of sysex input you need to set the + In other words if you're expecting lots of sysex input you need to set the SysexBufferCount property high enough so that you won't run out of input buffers before you get a chance to read them with GetMidiEvent. @@ -129,23 +129,23 @@ type TMidiInput = class(TComponent) private Handle: THandle; { Window handle used for callback notification } - FDeviceID: Word; { MIDI device ID } + FDeviceID: word; { MIDI device ID } FMIDIHandle: HMIDIIn; { Handle to input device } FState: MidiInputState; { Current device state } - FError: Word; - FSysexOnly: Boolean; + FError: word; + FSysexOnly: boolean; { Stuff from MIDIINCAPS } FDriverVersion: MMVERSION; FProductName: string; - FMID: Word; { Manufacturer ID } - FPID: Word; { Product ID } + FMID: word; { Manufacturer ID } + FPID: word; { Product ID } { Queue } - FCapacity: Word; { Buffer capacity } + FCapacity: word; { Buffer capacity } PBuffer: PCircularBuffer; { Low-level MIDI input buffer created by Open method } - FNumdevs: Word; { Number of input devices on system } + FNumdevs: word; { Number of input devices on system } { Events } FOnMIDIInput: TNotifyEvent; { MIDI Input arrived } @@ -153,8 +153,8 @@ type { TODO: Some sort of error handling event for MIM_ERROR } { Sysex } - FSysexBufferSize: Word; - FSysexBufferCount: Word; + FSysexBufferSize: word; + FSysexBufferCount: word; MidiHdrs: Tlist; PCtlInfo: PMidiCtlInfo; { Pointer to control info for DLL } @@ -163,13 +163,13 @@ type procedure Prepareheaders; procedure UnprepareHeaders; procedure AddBuffers; - procedure SetDeviceID(DeviceID: Word); + procedure SetDeviceID(DeviceID: word); procedure SetProductName(NewProductName: string); - function GetEventCount: Word; - procedure SetSysexBufferSize(BufferSize: Word); - procedure SetSysexBufferCount(BufferCount: Word); - procedure SetSysexOnly(bSysexOnly: Boolean); - function MidiInErrorString(WError: Word): string; + function GetEventCount: word; + procedure SetSysexBufferSize(BufferSize: word); + procedure SetSysexBufferCount(BufferCount: word); + procedure SetSysexOnly(bSysexOnly: boolean); + function MidiInErrorString(WError: word): string; public constructor Create(AOwner: TComponent); override; @@ -178,12 +178,12 @@ type property MIDIHandle: HMIDIIn read FMIDIHandle; property DriverVersion: MMVERSION read FDriverVersion; - property MID: Word read FMID; { Manufacturer ID } - property PID: Word read FPID; { Product ID } + property MID: word read FMID; { Manufacturer ID } + property PID: word read FPID; { Product ID } - property Numdevs: Word read FNumdevs; + property Numdevs: word read FNumdevs; - property MessageCount: Word read GetEventCount; + property MessageCount: word read GetEventCount; { TODO: property to select which incoming messages get filtered out } procedure Open; @@ -201,21 +201,21 @@ type { TODO: Property editor with dropdown list of product names } property ProductName: string read FProductName write SetProductName; - property DeviceID: Word read FDeviceID write SetDeviceID default 0; - property Capacity: Word read FCapacity write FCapacity default 1024; - property Error: Word read FError; - property SysexBufferSize: Word + property DeviceID: word read FDeviceID write SetDeviceID default 0; + property Capacity: word read FCapacity write FCapacity default 1024; + property Error: word read FError; + property SysexBufferSize: word read FSysexBufferSize write SetSysexBufferSize default 10000; - property SysexBufferCount: Word + property SysexBufferCount: word read FSysexBufferCount write SetSysexBufferCount default 16; - property SysexOnly: Boolean + property SysexOnly: boolean read FSysexOnly write SetSysexOnly - default False; + default false; { Events } property OnMidiInput: TNotifyEvent read FOnMidiInput write FOnMidiInput; @@ -228,8 +228,9 @@ procedure Register; {====================================================================} implementation -uses Controls, - Graphics; +uses + Controls, + Graphics; (* Not used in Delphi 3 { This is the callback procedure in the external DLL. @@ -241,9 +242,9 @@ uses Controls, function midiHandler( hMidiIn: HMidiIn; wMsg: UINT; - dwInstance: DWORD; - dwParam1: DWORD; - dwParam2: DWORD): Boolean; stdcall; external 'DELMID32.DLL'; + dwInstance: dword; + dwParam1: dword; + dwParam2: dword): boolean; stdcall; external 'DELMID32.DLL'; {$ENDIF} *) {-------------------------------------------------------------------} @@ -253,7 +254,7 @@ begin inherited Create(AOwner); FState := misCreating; - FSysexOnly := False; + FSysexOnly := false; FNumDevs := midiInGetNumDevs; MidiHdrs := nil; @@ -279,13 +280,13 @@ end; destructor TMidiInput.Destroy; begin - if (FMidiHandle <> 0) then + if FMidiHandle <> 0 then begin Close; FMidiHandle := 0; end; - if (PCtlInfo <> nil) then + if PCtlInfo <> nil then GlobalSharedLockedFree(PCtlinfo^.hMem, PCtlInfo); DeallocateHwnd(Handle); @@ -298,9 +299,9 @@ end; (e.g. "an invalid parameter was passed to a system function") so sort out some proper error strings. } -function TMidiInput.MidiInErrorString(WError: Word): string; +function TMidiInput.MidiInErrorString(WError: word): string; var - errorDesc: PChar; + errorDesc: Pchar; begin errorDesc := nil; try @@ -317,7 +318,7 @@ end; {-------------------------------------------------------------------} { Set the sysex buffer size, fail if device is already open } -procedure TMidiInput.SetSysexBufferSize(BufferSize: Word); +procedure TMidiInput.SetSysexBufferSize(BufferSize: word); begin if FState = misOpen then raise EMidiInputError.Create('Change to SysexBufferSize while device was open') @@ -329,7 +330,7 @@ end; {-------------------------------------------------------------------} { Set the sysex buffer count, fail if device is already open } -procedure TMidiInput.SetSysexBuffercount(Buffercount: Word); +procedure TMidiInput.SetSysexBuffercount(Buffercount: word); begin if FState = misOpen then raise EMidiInputError.Create('Change to SysexBuffercount while device was open') @@ -341,7 +342,7 @@ end; {-------------------------------------------------------------------} { Set the Sysex Only flag to eliminate unwanted short MIDI input messages } -procedure TMidiInput.SetSysexOnly(bSysexOnly: Boolean); +procedure TMidiInput.SetSysexOnly(bSysexOnly: boolean); begin FSysexOnly := bSysexOnly; { Update the interrupt handler's copy of this property } @@ -353,14 +354,14 @@ end; { Set the Device ID to select a new MIDI input device Note: If no MIDI devices are installed, throws an 'Invalid Device ID' exception } -procedure TMidiInput.SetDeviceID(DeviceID: Word); +procedure TMidiInput.SetDeviceID(DeviceID: word); var MidiInCaps: TMidiInCaps; begin if FState = misOpen then raise EMidiInputError.Create('Change to DeviceID while device was open') else - if (DeviceID >= midiInGetNumDevs) then + if DeviceID >= midiInGetNumDevs then raise EMidiInputError.Create('Invalid device ID') else begin @@ -391,7 +392,7 @@ end; procedure TMidiInput.SetProductName(NewProductName: string); var MidiInCaps: TMidiInCaps; - testDeviceID: Word; + testDeviceID: word; testProductName: string; begin if FState = misOpen then @@ -414,7 +415,7 @@ begin if testProductName = NewProductName then begin FProductName := NewProductName; - Break; + break; end; end; if FProductName <> NewProductName then @@ -432,7 +433,7 @@ end; procedure TMidiInput.PrepareHeaders; var - ctr: Word; + ctr: word; MyMidiHdr: TMyMidiHdr; begin if (FSysexBufferCount > 0) and (FSysexBufferSize > 0) @@ -448,7 +449,7 @@ begin structure so we can get back to the object when a pointer to the MIDIHDR is received. E.g. see TMidiOutput.Output method } - MyMidiHdr.hdrPointer^.dwUser := DWORD(MyMidiHdr); + MyMidiHdr.hdrPointer^.dwUser := dword(MyMidiHdr); { Get MMSYSTEM's blessing for this header } FError := midiInPrepareHeader(FMidiHandle, MyMidiHdr.hdrPointer, @@ -468,9 +469,9 @@ end; procedure TMidiInput.UnprepareHeaders; var - ctr: Word; + ctr: word; begin - if (MidiHdrs <> nil) then { will be Nil if 0 sysex buffers } + if MidiHdrs <> nil then { will be nil if 0 sysex buffers } begin for ctr := 0 to MidiHdrs.Count - 1 do begin @@ -491,9 +492,9 @@ end; procedure TMidiInput.AddBuffers; var - ctr: Word; + ctr: word; begin - if MidiHdrs <> nil then { will be Nil if 0 sysex buffers } + if MidiHdrs <> nil then { will be nil if 0 sysex buffers } begin if MidiHdrs.Count > 0 then begin @@ -517,11 +518,11 @@ var begin try { Create the buffer for the MIDI input messages } - if (PBuffer = nil) then + if PBuffer = nil then PBuffer := CircBufAlloc(FCapacity); { Create the control info for the DLL } - if (PCtlInfo = nil) then + if PCtlInfo = nil then begin PCtlInfo := GlobalSharedLockedAlloc(Sizeof(TMidiCtlInfo), hMem); PctlInfo^.hMem := hMem; @@ -530,11 +531,11 @@ begin Pctlinfo^.hWindow := Handle; { Control's window handle } PCtlInfo^.SysexOnly := FSysexOnly; FError := midiInOpen(@FMidiHandle, FDeviceId, - DWORD(@midiHandler), - DWORD(PCtlInfo), + dword(@midiHandler), + dword(PCtlInfo), CALLBACK_FUNCTION); - if (FError <> MMSYSERR_NOERROR) then + if FError <> MMSYSERR_NOERROR then { TODO: use CreateFmtHelp to add MIDI device name/ID to message } raise EMidiInputError.Create(MidiInErrorString(FError)); @@ -576,7 +577,7 @@ begin with thisItem do begin Result.Time := Timestamp; - if (Sysex = nil) then + if Sysex = nil then begin { Short message } Result.MidiMessage := LoByte(LoWord(Data)); @@ -618,7 +619,7 @@ end; {-------------------------------------------------------------------} -function TMidiInput.GetEventCount: Word; +function TMidiInput.GetEventCount: word; begin if FState = misOpen then Result := PBuffer^.EventCount @@ -654,7 +655,7 @@ begin FMidiHandle := 0; - if (PBuffer <> nil) then + if PBuffer <> nil then begin CircBufFree(PBuffer); PBuffer := nil; diff --git a/src/lib/midi/MidiOut.pas b/src/lib/midi/MidiOut.pas index 60538a08..6d675013 100644 --- a/src/lib/midi/MidiOut.pas +++ b/src/lib/midi/MidiOut.pas @@ -11,12 +11,12 @@ unit MidiOut; MIDI Output component. Properties: - DeviceID: Windows numeric device ID for the MIDI output device. + DeviceID: Windows numeric device ID for the MIDI output device. Between 0 and (midioutGetNumDevs-1), or MIDI_MAPPER (-1). Special value MIDI_MAPPER specifies output to the Windows MIDI mapper Read-only while device is open, exception if changed while open - MIDIHandle: The output handle to the MIDI device. + MIDIHandle: The output handle to the MIDI device. 0 when device is not open Read-only, runtime-only @@ -67,16 +67,16 @@ unit MidiOut; transmission so you can free the TMyMidiEvent immediately after calling PutMidiEvent, even if output has not yet finished. - PutShort(MidiMessage: Byte; Data1: Byte; Data2: Byte): Output a short + PutShort(MidiMessage: byte; Data1: byte; Data2: byte): Output a short MIDI message. Handy when you can't be bothered to build a TMyMidiEvent. If the message you're sending doesn't use Data1 or Data2, set them to 0. - PutLong(TheSysex: Pointer; msgLength: Word): Output sysex data. + PutLong(TheSysex: pointer; msgLength: word): Output sysex data. SysexPointer: Pointer to sysex data to send msgLength: Length of sysex data. This is handy when you don't have a TMyMidiEvent. - SetVolume(Left: Word, Right: Word): Set the volume of the + SetVolume(Left: word, Right: word): Set the volume of the left and right channels on the output device (only on internal devices?). 0xFFFF is maximum volume. If the device doesn't support separate left/right volume control, the value of the Left parameter will be used. @@ -126,12 +126,12 @@ type { These are the equivalent of constants prefixed with mod_ as defined in MMSystem. See SetTechnology } OutPortTech = ( - opt_None, { none } + opt_None, { none } opt_MidiPort, { output port } - opt_Synth, { generic internal synth } - opt_SQSynth, { square wave internal synth } - opt_FMSynth, { FM internal synth } - opt_Mapper); { MIDI mapper } + opt_Synth, { generic internal synth } + opt_SQSynth, { square wave internal synth } + opt_FMSynth, { FM internal synth } + opt_Mapper); { Midi mapper } TechNameMap = array[OutPortTech] of string[18]; @@ -145,35 +145,35 @@ type TMidiOutput = class(TComponent) protected Handle: THandle; { Window handle used for callback notification } - FDeviceID: Cardinal; { MIDI device ID } - FMIDIHandle: Hmidiout; { Handle to output device } + FDeviceID: cardinal; { MIDI device ID } + FMIDIHandle: HMidiOut; { Handle to output device } FState: midioutputState; { Current device state } PCtlInfo: PMidiCtlInfo; { Pointer to control info for DLL } PBuffer: PCircularBuffer; { Output queue for PutTimedEvent, set by Open } - FError: Word; { Last MMSYSTEM error } + FError: word; { Last MMSYSTEM error } { Stuff from midioutCAPS } FDriverVersion: MMVERSION; { Driver version from midioutGetDevCaps } FProductName: string; { product name } FTechnology: OutPortTech; { Type of MIDI output device } - FVoices: Word; { Number of voices (internal synth) } - FNotes: Word; { Number of notes (internal synth) } - FChannelMask: Word; { Bit set for each MIDI channels that the + FVoices: word; { Number of voices (internal synth) } + FNotes: word; { Number of notes (internal synth) } + FChannelMask: word; { Bit set for each MIDI channels that the device responds to (internal synth) } - FSupport: DWORD; { Technology supported (volume control, + FSupport: dword; { Technology supported (volume control, patch caching etc. } - FNumdevs: Word; { Number of MIDI output devices on system } + FNumdevs: word; { Number of MIDI output devices on system } FOnMIDIOutput: TNotifyEvent; { Sysex output finished } procedure MidiOutput(var Message: TMessage); - procedure SetDeviceID(DeviceID: Cardinal); + procedure SetDeviceID(DeviceID: cardinal); procedure SetProductName(NewProductName: string); procedure SetTechnology(NewTechnology: OutPortTech); - function midioutErrorString(WError: Word): string; + function midioutErrorString(WError: word): string; public { Properties } @@ -184,24 +184,24 @@ type read FTechnology write SetTechnology default opt_Synth; - property Voices: Word { Number of voices (internal synth) } + property Voices: word { Number of voices (internal synth) } read FVoices; - property Notes: Word { Number of notes (internal synth) } + property Notes: word { Number of notes (internal synth) } read FNotes; - property ChannelMask: Word { Bit set for each MIDI channels that the } + property ChannelMask: word { Bit set for each MIDI channels that the } read FChannelMask; { device responds to (internal synth) } - property Support: DWORD { Technology supported (volume control, } + property Support: dword { Technology supported (volume control, } read FSupport; { patch caching etc. } - property Error: Word read FError; - property Numdevs: Word read FNumdevs; + property Error: word read FError; + property Numdevs: word read FNumdevs; { Methods } - function Open: Boolean; virtual; - function Close: Boolean; virtual; + function Open: boolean; virtual; + function Close: boolean; virtual; procedure PutMidiEvent(theEvent: TMyMidiEvent); virtual; - procedure PutShort(MidiMessage: Byte; Data1: Byte; Data2: Byte); virtual; - procedure PutLong(TheSysex: Pointer; msgLength: Word); virtual; - procedure SetVolume(Left: Word; Right: Word); + procedure PutShort(MidiMessage: byte; Data1: byte; Data2: byte); virtual; + procedure PutLong(TheSysex: pointer; msgLength: word); virtual; + procedure SetVolume(Left: word; Right: word); constructor Create(AOwner: TComponent); override; destructor Destroy; override; @@ -211,7 +211,7 @@ type { TODO: Property editor with dropdown list of product names } property ProductName: string read FProductName write SetProductName; - property DeviceID: Cardinal read FDeviceID write SetDeviceID default 0; + property DeviceID: cardinal read FDeviceID write SetDeviceID default 0; { TODO: midiOutGetVolume? Or two properties for Left and Right volume? Is it worth it?? midiOutMessage?? Does anyone use this? } @@ -238,9 +238,9 @@ implementation function midiHandler( hMidiIn: HMidiIn; wMsg: UINT; - dwInstance: DWORD; - dwParam1: DWORD; - dwParam2: DWORD): Boolean; stdcall; external 'DELMID32.DLL'; + dwInstance: dword; + dwParam1: dword; + dwParam2: dword): boolean; stdcall; external 'DELMID32.DLL'; {$ENDIF} *) @@ -254,9 +254,7 @@ begin { Create the window for callback notification } if not (csDesigning in ComponentState) then - begin Handle := AllocateHwnd(MidiOutput); - end; end; @@ -266,7 +264,7 @@ destructor Tmidioutput.Destroy; begin if FState = mosOpen then Close; - if (PCtlInfo <> nil) then + if PCtlInfo <> nil then GlobalSharedLockedFree(PCtlinfo^.hMem, PCtlInfo); DeallocateHwnd(Handle); inherited Destroy; @@ -279,9 +277,9 @@ end; some proper error strings would be nice. } -function Tmidioutput.midioutErrorString(WError: Word): string; +function Tmidioutput.midioutErrorString(WError: word): string; var - errorDesc: PChar; + errorDesc: Pchar; begin errorDesc := nil; try @@ -291,14 +289,15 @@ begin else result := 'Specified error number is out of range'; finally - if errorDesc <> nil then StrDispose(errorDesc); + if errorDesc <> nil then + StrDispose(errorDesc); end; end; {-------------------------------------------------------------------} { Set the output device ID and change the other properties to match } -procedure Tmidioutput.SetDeviceID(DeviceID: Cardinal); +procedure Tmidioutput.SetDeviceID(DeviceID: cardinal); var midioutCaps: TmidioutCaps; begin @@ -343,7 +342,7 @@ end; procedure Tmidioutput.SetProductName(NewProductName: string); var midioutCaps: TmidioutCaps; - testDeviceID: Integer; + testDeviceID: integer; testProductName: string; begin if FState = mosOpen then @@ -366,7 +365,7 @@ begin if testProductName = NewProductName then begin FProductName := NewProductName; - Break; + break; end; end; if FProductName <> NewProductName then @@ -386,7 +385,7 @@ end; procedure TMidiOutput.SetTechnology(NewTechnology: OutPortTech); var midiOutCaps: TMidiOutCaps; - testDeviceID: Integer; + testDeviceID: integer; testTechnology: OutPortTech; begin if FState = mosOpen then @@ -406,7 +405,7 @@ begin if testTechnology = NewTechnology then begin FTechnology := NewTechnology; - Break; + break; end; end; if FTechnology <> NewTechnology then @@ -419,14 +418,14 @@ end; {-------------------------------------------------------------------} -function Tmidioutput.Open: Boolean; +function Tmidioutput.Open: boolean; var hMem: THandle; begin - Result := False; + Result := false; try { Create the control info for the DLL } - if (PCtlInfo = nil) then + if PCtlInfo = nil then begin PCtlInfo := GlobalSharedLockedAlloc(Sizeof(TMidiCtlInfo), hMem); PctlInfo^.hMem := hMem; @@ -435,19 +434,19 @@ begin Pctlinfo^.hWindow := Handle; { Control's window handle } FError := midioutOpen(@FMidiHandle, FDeviceId, - DWORD(@midiHandler), - DWORD(PCtlInfo), + dword(@midiHandler), + dword(PCtlInfo), CALLBACK_FUNCTION); -{ FError := midioutOpen(@FMidiHandle, FDeviceId, +{ FError := midioutOpen(@FMidiHandle, FDeviceId, Handle, - DWORD(PCtlInfo), + dword(PCtlInfo), CALLBACK_WINDOW); } - if (FError <> 0) then + if FError <> 0 then { TODO: use CreateFmtHelp to add MIDI device name/ID to message } raise EmidioutputError.Create(midioutErrorString(FError)) else begin - Result := True; + Result := true; FState := mosOpen; end; @@ -463,13 +462,13 @@ end; {-------------------------------------------------------------------} -procedure TMidiOutput.PutShort(MidiMessage: Byte; Data1: Byte; Data2: Byte); +procedure TMidiOutput.PutShort(MidiMessage: byte; Data1: byte; Data2: byte); var - thisMsg: DWORD; + thisMsg: dword; begin - thisMsg := DWORD(MidiMessage) or - (DWORD(Data1) shl 8) or - (DWORD(Data2) shl 16); + thisMsg := dword(MidiMessage) or + (dword(Data1) shl 8) or + (dword(Data2) shl 16); FError := midiOutShortMsg(FMidiHandle, thisMsg); if Ferror > 0 then @@ -478,7 +477,7 @@ end; {-------------------------------------------------------------------} -procedure TMidiOutput.PutLong(TheSysex: Pointer; msgLength: Word); +procedure TMidiOutput.PutLong(TheSysex: pointer; msgLength: word); { Notes: This works asynchronously; you send your sysex output by calling this function, which returns immediately. When the MIDI device driver has finished sending the data the MidiOutPut function in this @@ -493,13 +492,13 @@ begin MyMidiHdr := TMyMidiHdr.Create(msgLength); { Copy the data over to the MidiHdr buffer - We can't just use the caller's PChar because the buffer memory + We can't just use the caller's Pchar because the buffer memory has to be global, shareable, and locked. } StrMove(MyMidiHdr.SysexPointer, TheSysex, msgLength); { Store the MyMidiHdr address in the header so we can find it again quickly (see the MidiOutput proc) } - MyMidiHdr.hdrPointer^.dwUser := DWORD(MyMidiHdr); + MyMidiHdr.hdrPointer^.dwUser := dword(MyMidiHdr); { Get MMSYSTEM's blessing for this header } FError := midiOutPrepareHeader(FMidiHandle, MyMidiHdr.hdrPointer, @@ -525,9 +524,7 @@ begin with theEvent do begin if Sysex = nil then - begin PutShort(MidiMessage, Data1, Data2) - end else PutLong(Sysex, SysexLength); end; @@ -535,15 +532,15 @@ end; {-------------------------------------------------------------------} -function Tmidioutput.Close: Boolean; +function Tmidioutput.Close: boolean; begin - Result := False; + Result := false; if FState = mosOpen then begin - { Note this sends a lot of fast control change messages which some synths can't handle. +{ Note this sends a lot of fast control change messages which some synths can't handle. TODO: Make this optional. } -{ FError := midioutReset(FMidiHandle); +{ FError := midioutReset(FMidiHandle); if Ferror <> 0 then raise EMidiOutputError.Create(MidiOutErrorString(FError)); } @@ -551,7 +548,7 @@ begin if Ferror <> 0 then raise EMidiOutputError.Create(MidiOutErrorString(FError)) else - Result := True; + Result := true; end; FMidiHandle := 0; @@ -561,11 +558,11 @@ end; {-------------------------------------------------------------------} -procedure TMidiOutput.SetVolume(Left: Word; Right: Word); +procedure TMidiOutput.SetVolume(Left: word; Right: word); var - dwVolume: DWORD; + dwVolume: dword; begin - dwVolume := (DWORD(Left) shl 16) or Right; + dwVolume := (dword(Left) shl 16) or Right; FError := midiOutSetVolume(DeviceID, dwVolume); if Ferror <> 0 then raise EMidiOutputError.Create(MidiOutErrorString(FError)); diff --git a/src/lib/midi/MidiScope.pas b/src/lib/midi/MidiScope.pas index afc20b0f..3eb51054 100644 --- a/src/lib/midi/MidiScope.pas +++ b/src/lib/midi/MidiScope.pas @@ -24,7 +24,14 @@ interface {$ENDIF} uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; + Windows, + Messages, + SysUtils, + Classes, + Graphics, + Controls, + Forms, + Dialogs; type TMidiScope = class(TGraphicControl) @@ -32,40 +39,40 @@ type { Private declarations } protected { Protected declarations } - notes : array[0..15,0..127] of integer; - controllers : array[0..15,0..17] of integer; - aftertouch : array[0..15,0..127] of integer; + notes: array[0..15,0..127] of integer; + controllers: array[0..15,0..17] of integer; + aftertouch: array[0..15,0..127] of integer; - selectedChannel : integer; + selectedChannel: integer; - procedure PaintSlide(ch,pos,val: integer); + procedure PaintSlide(ch, pos, val: integer); - procedure NoteOn(channel, note, speed : integer); - procedure Controller(channel,number,value : integer); - procedure AfterTch(channel, note, value : integer); + procedure NoteOn(channel, note, speed: integer); + procedure Controller(channel, number, value: integer); + procedure AfterTch(channel, note, value: integer); public { Public declarations } constructor Create(AOwner: TComponent); override; - procedure MidiEvent(event,data1,data2 : integer); + procedure MidiEvent(event, data1, data2: integer); procedure Paint; override; published { Published declarations } end; - procedure Register; const - BarHeight = 16; - BarHeightInc = BarHeight+2; + BarHeight = 16; + BarHeightInc = BarHeight + 2; BarWidth = 3; - BarWidthInc = BarWidth+1; + BarWidthInc = BarWidth + 1; HeightDiv = 128 div BarHeight; implementation -uses Midicons; +uses + MidiCons; procedure Register; begin @@ -74,125 +81,100 @@ end; constructor TMidiScope.Create(AOwner: TComponent); var - i,j : integer; + i, j: integer; begin inherited Create(AOwner); Height := BarHeightinc * 16 + 4; - Width := 147*BarWidthInc + 4 + 20; // for channel number + Width := 147 * BarWidthInc + 4 + 20; // for channel number for i := 0 to 15 do - begin for j := 0 to 127 do begin notes[i,j] := 0; aftertouch[i,j] := 0; end; - end; for i := 0 to 17 do - begin for j := 0 to 15 do controllers[i,j] := 0; - end; end; -procedure TMidiScope.PaintSlide(ch,pos,val: integer); -var x,y:integer; +procedure TMidiScope.PaintSlide(ch, pos, val: integer); +var + x, y:integer; begin Canvas.Brush.Color := clBlack; Canvas.Pen.color := clBlack; x := pos * BarWidthInc + 2; y := 2 + ch * BarHeightInc; - Canvas.Rectangle(x, y, x+BarWidthInc, y+BarHeightInc); + Canvas.Rectangle(x, y, x + BarWidthInc, y + BarHeightInc); Canvas.Brush.Color := clGreen; Canvas.Pen.Color := clGreen; - Canvas.Rectangle(x, y + (BarHeight - (val div HeightDiv )), x + BarWidth, y + BarHeight) + Canvas.Rectangle(x, y + (BarHeight - (val div HeightDiv)), x + BarWidth, y + BarHeight) end; procedure TMidiScope.Paint; -var i,j : integer; -x : integer; +var + i, j: integer; + x: integer; begin Canvas.Brush.color := clBlack; - Canvas.Rectangle(0,0,Width,Height); + Canvas.Rectangle(0, 0, Width, Height); Canvas.Pen.Color := clGreen; - x := 128*BarWidthInc+2; - Canvas.MoveTo(x,0); - Canvas.LineTo(x,Height); - x := 148*BarWIdthInc+2; + x := 128 * BarWidthInc + 2; + Canvas.MoveTo(x, 0); + Canvas.LineTo(x, Height); + x := 148 * BarWIdthInc + 2; canvas.Font.Color := clGreen; for i := 0 to 15 do - Canvas.TextOut(x,((i+1)*BarHeightInc) - Canvas.font.size-3,IntToStr(i+1)); + Canvas.TextOut(x, ((i + 1) * BarHeightInc) - Canvas.font.size - 3, IntToStr(i + 1)); canvas.Pen.color := clBlack; - begin - for j := 0 to 127 do - begin - PaintSlide(i,j,notes[i,j]); - end; - for j := 0 to 17 do - begin - PaintSlide(i,j+129,controllers[i,j]); - end; - end; + for j := 0 to 127 do + PaintSlide(i, j, notes[i,j]); + for j := 0 to 17 do + PaintSlide(i, j + 129, controllers[i,j]); end; -procedure TMidiScope.NoteOn(channel, note, speed : integer); + +procedure TMidiScope.NoteOn(channel, note, speed: integer); begin notes[channel,note] := speed; - PaintSlide(channel,note,notes[channel,note]); + PaintSlide(channel, note, notes[channel,note]); end; -procedure TMidiScope.AfterTch(channel, note, value : integer); + +procedure TMidiScope.AfterTch(channel, note, value: integer); begin aftertouch[channel,note] := value; end; -procedure TMidiScope.Controller(channel,number,value : integer); -var i : integer; +procedure TMidiScope.Controller(channel, number, value: integer); +var + i: integer; begin if number < 18 then begin - controllers[channel,number] := value; - PaintSlide(channel,number+129,value); + controllers[channel,number] := value; + PaintSlide(channel, number + 129, value); end else if number >= $7B then begin // all notes of for channel for i := 0 to 127 do - begin if notes[channel,i] > 0 then begin notes[channel,i] := 0; - PaintSlide(channel,i,0); + PaintSlide(channel, i, 0); end; - end; end; end; -procedure TMidiScope.MidiEvent(event,data1,data2 : integer); +procedure TMidiScope.MidiEvent(event, data1, data2: integer); begin - case (event AND $F0) of - MIDI_NOTEON : - begin - NoteOn((event AND $F),data1,data2); - end; - MIDI_NOTEOFF: - begin - NoteOn((event AND $F),data1,0); - end; - MIDI_CONTROLCHANGE : - begin - Controller((event AND $F),data1,data2); - end; - MIDI_CHANAFTERTOUCH: - begin - Controller((Event AND $F),16,Data1); - end; - MIDI_PITCHBEND: - begin - begin - Controller((Event AND $F),17,data2); - end; - end; - MIDI_KEYAFTERTOUCH: - begin - end; + case (event and $F0) of + MIDI_NOTEON : NoteOn ((event and $F), data1, data2); + MIDI_NOTEOFF: NoteOn ((event and $F), data1, 0 ); + MIDI_CONTROLCHANGE: Controller((event and $F), data1, data2); + MIDI_CHANAFTERTOUCH: Controller((Event and $F), 16, data1); + MIDI_PITCHBEND: Controller((Event and $F), 17, data2); + MIDI_KEYAFTERTOUCH: ; end; end; + end. diff --git a/src/lib/midi/MidiType.pas b/src/lib/midi/MidiType.pas index 14157dbe..30e043ab 100644 --- a/src/lib/midi/MidiType.pas +++ b/src/lib/midi/MidiType.pas @@ -1,9 +1,8 @@ -{ $Header: /MidiComp/MidiType.pas 2 10/06/97 7:33 Davec $ } +{ $Header: /MidiComp/MidiType.pas 2 10/06/97 7:33 Davec $ } { Written by David Churcher <dchurcher@cix.compulink.co.uk>, released to the public domain. } - unit MidiType; interface @@ -22,32 +21,32 @@ uses CircBuf; type - {-------------------------------------------------------------------} - { A MIDI input/output event } - TMyMidiEvent = class(TPersistent) - public - MidiMessage: Byte; { MIDI message status byte } - Data1: Byte; { MIDI message data 1 byte } - Data2: Byte; { MIDI message data 2 byte } - Time: DWORD; { Time in ms since midiInOpen } - SysexLength: Word; { Length of sysex data (0 if none) } - Sysex: PChar; { Pointer to sysex data buffer } - destructor Destroy; override; { Frees sysex data buffer if nec. } - end; - PMyMidiEvent = ^TMyMidiEvent; - - {-------------------------------------------------------------------} - { Encapsulates the MIDIHDR with its memory handle and sysex buffer } - PMyMidiHdr = ^TMyMidiHdr; - TMyMidiHdr = class(TObject) - public - hdrHandle: THandle; - hdrPointer: PMIDIHDR; - sysexHandle: THandle; - sysexPointer: Pointer; - constructor Create(BufferSize: Word); - destructor Destroy; override; - end; + {-------------------------------------------------------------------} + { A MIDI input/output event } + TMyMidiEvent = class(TPersistent) + public + MidiMessage: byte; { MIDI message status byte } + Data1: byte; { MIDI message data 1 byte } + Data2: byte; { MIDI message data 2 byte } + Time: dword; { Time in ms since midiInOpen } + SysexLength: word; { Length of sysex data (0 if none) } + Sysex: Pchar; { Pointer to sysex data buffer } + destructor Destroy; override; { Frees sysex data buffer if nec. } + end; + PMyMidiEvent = ^TMyMidiEvent; + + {-------------------------------------------------------------------} + { Encapsulates the MIDIHDR with its memory handle and sysex buffer } + PMyMidiHdr = ^TMyMidiHdr; + TMyMidiHdr = class(TObject) + public + hdrHandle: THandle; + hdrPointer: PMIDIHDR; + sysexHandle: THandle; + sysexPointer: pointer; + constructor Create(BufferSize: word); + destructor Destroy; override; + end; implementation @@ -55,36 +54,34 @@ implementation { Free any sysex buffer associated with the event } destructor TMyMidiEvent.Destroy; begin - if (Sysex <> Nil) then - Freemem(Sysex, SysexLength); + if (Sysex <> nil) then + Freemem(Sysex, SysexLength); - inherited Destroy; + inherited Destroy; end; {-------------------------------------------------------------------} { Allocate memory for the sysex header and buffer } -constructor TMyMidiHdr.Create(BufferSize:Word); +constructor TMyMidiHdr.Create(BufferSize: word); begin - inherited Create; + inherited Create; - if BufferSize > 0 then - begin - hdrPointer := GlobalSharedLockedAlloc(sizeof(TMIDIHDR), hdrHandle); - sysexPointer := GlobalSharedLockedAlloc(BufferSize, sysexHandle); + if BufferSize > 0 then + begin + hdrPointer := GlobalSharedLockedAlloc(sizeof(TMIDIHDR), hdrHandle); + sysexPointer := GlobalSharedLockedAlloc(BufferSize, sysexHandle); - hdrPointer^.lpData := sysexPointer; - hdrPointer^.dwBufferLength := BufferSize; - end; + hdrPointer^.lpData := sysexPointer; + hdrPointer^.dwBufferLength := BufferSize; + end; end; {-------------------------------------------------------------------} destructor TMyMidiHdr.Destroy; begin - GlobalSharedLockedFree( hdrHandle, hdrPointer ); - GlobalSharedLockedFree( sysexHandle, sysexPointer ); - inherited Destroy; + GlobalSharedLockedFree(hdrHandle, hdrPointer); + GlobalSharedLockedFree(sysexHandle, sysexPointer); + inherited Destroy; end; - - end. diff --git a/src/lib/midi/demo/MidiTest.pas b/src/lib/midi/demo/MidiTest.pas index 793db730..4ded35fd 100644 --- a/src/lib/midi/demo/MidiTest.pas +++ b/src/lib/midi/demo/MidiTest.pas @@ -5,8 +5,22 @@ unit MidiTest; interface uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, MidiFile, ExtCtrls, MidiOut, MidiType, MidiScope, Grids; + Windows, + Messages, + SysUtils, + Classes, + Graphics, + Controls, + Forms, + Dialogs, + StdCtrls, + ExtCtrls, + Grids, + MidiFile, + MidiOut, + MidiType, + MidiScope; + type TMidiPlayer = class(TForm) OpenDialog1: TOpenDialog; @@ -33,9 +47,9 @@ type procedure cmbInputChange(Sender: TObject); procedure MidiFile1UpdateEvent(Sender: TObject); procedure Button2Click(Sender: TObject); - procedure edtBpmKeyPress(Sender: TObject; var Key: Char); - procedure TracksGridSelectCell(Sender: TObject; Col, Row: Integer; - var CanSelect: Boolean); + procedure edtBpmKeyPress(Sender: TObject; var Key: char); + procedure TracksGridSelectCell(Sender: TObject; Col, Row: integer; + var CanSelect: boolean); procedure FormShow(Sender: TObject); private { Private declarations } @@ -58,9 +72,9 @@ implementation procedure TMidiPlayer.Button1Click(Sender: TObject); var - i,j: integer; - track : TMidiTrack; - event : PMidiEvent; + i, j: integer; + track: TMidiTrack; + event: PMidiEvent; begin if opendialog1.execute then begin @@ -79,7 +93,8 @@ begin end; procedure TMidiPlayer.MidiFile1MidiEvent(event: PMidiEvent); -var mEvent : TMyMidiEvent; +var + mEvent: TMyMidiEvent; begin mEvent := TMyMidiEvent.Create; if not (event.event = $FF) then @@ -90,19 +105,16 @@ begin midioutput1.PutMidiEvent(mEvent); end else - begin if (event.data1 >= 1) and (event.data1 < 15) then - begin memo2.Lines.add(IntToStr(event.data1) + ' '+ event.str); - end - end; midiScope1.MidiEvent(event.event,event.data1,event.data2); mEvent.Destroy; end; procedure TMidiPlayer.SentAllNotesOff; -var mEvent : TMyMidiEvent; -channel : integer; +var + mEvent: TMyMidiEvent; + channel: integer; begin mEvent := TMyMidiEvent.Create; for channel:= 0 to 15 do @@ -149,7 +161,8 @@ end; procedure TMidiPlayer.FormCreate(Sender: TObject); -var thisDevice : integer; +var + thisDevice: integer; begin for thisDevice := 0 to MidiOutput1.NumDevs - 1 do begin @@ -183,7 +196,7 @@ begin MidiFile1.ContinuePlaying; end; -procedure TMidiPlayer.edtBpmKeyPress(Sender: TObject; var Key: Char); +procedure TMidiPlayer.edtBpmKeyPress(Sender: TObject; var Key: char); begin if Key = char(13) then begin @@ -195,12 +208,11 @@ begin end; procedure TMidiPlayer.TracksGridSelectCell(Sender: TObject; Col, - Row: Integer; var CanSelect: Boolean); + Row: integer; var CanSelect: boolean); var - MidiTrack : TMidiTrack; - i : integer; - j : integer; - event : PMidiEvent; + MidiTrack: TMidiTrack; + i, j: integer; + event: PMidiEvent; begin CanSelect := false; if Row < MidiFile1.NumberOfTracks then diff --git a/src/lib/midi/readme.txt b/src/lib/midi/readme.txt index 7112aecf..e412c23e 100644 --- a/src/lib/midi/readme.txt +++ b/src/lib/midi/readme.txt @@ -1,7 +1,6 @@ - Midi components TMidiFile, TMidiScope - TMidiIn and TMidiOut of david Churcher are included because they are used in + TMidiIn and TMidiOut of David Churcher are included because they are used in the demo application Freeware. @@ -16,15 +15,12 @@ TMidiFile, read a midifile and have the contents available in memory TMidiScope, show all activity on a midi device -TMidiIn and TMidiOut of David Churcher are included because they are used -in the demo application - Midiplayer is a demo application which plays a midifile on a midi output it is build fairly simple with the included components. The timer is used to time the midievents. The timing is therefor as good as the windows timer. - The header of midifile,midiscope contains help information on the properties/functions + The header of midifile, midiscope contains help information on the properties/functions The example Midiplayer gives a good idea how to use the components Installation @@ -36,8 +32,6 @@ Installation to run the demo open project1.dpr in the demo directory and press run. - - history 1.0 18-1-1999 first release @@ -55,6 +49,6 @@ Frans Bouwmans fbouwmans@spiditel.nl I'm busy building a software music synthesizer, which will be available in source -to the public. If you are interrested in helping me with certain soundmodules +to the public. If you are interested in helping me with certain soundmodules (effects, filters, sound generators) just sent me an email. |