aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/midi/DELPHMCB.PAS
blob: ef0d54513c4a6e16abfb5d23fe79730d074f262f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
{ $Header: /MidiComp/DELPHMCB.PAS 2     10/06/97 7:33 Davec $ }

{MIDI callback for Delphi, was DLL for Delphi 1}

unit Delphmcb;

{ These segment options required for the MIDI callback functions }
{$IFNDEF FPC}
{$C PRELOAD FIXED PERMANENT}
{$ENDIF}

interface

{$IFDEF FPC}
  {$MODE Delphi}
  {$H+} // use long strings
{$ENDIF}

uses
  Windows,
  MMsystem,
  Circbuf,
  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;

implementation

{ Add an event to the circular input buffer. }
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;
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
  on the Windows functions that can be called in this interrupt. }
procedure midiHandler(
		  hMidiIn: HMidiIn;
		  wMsg: UINT;
		  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 }
end;

end.