1 |
/*************************************************************************** |
2 |
* * |
3 |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2004 Grame * |
7 |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
10 |
* the Free Software Foundation; either version 2 of the License, or * |
11 |
* (at your option) any later version. * |
12 |
* * |
13 |
* This program is distributed in the hope that it will be useful, * |
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
16 |
* GNU General Public License for more details. * |
17 |
* * |
18 |
* You should have received a copy of the GNU General Public License * |
19 |
* along with this program; if not, write to the Free Software * |
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, * |
21 |
* MA 02111-1307 USA * |
22 |
***************************************************************************/ |
23 |
|
24 |
#include "MidiInputDeviceMidiShare.h" |
25 |
|
26 |
namespace LinuxSampler { |
27 |
|
28 |
#define MSHSlotName "LinuxSampler" |
29 |
#define MSHDriverName "LinuxSampler" |
30 |
|
31 |
#define MidiShareDrvRef 127 |
32 |
|
33 |
/** |
34 |
* Create MidiShare input device for LinuxSampler. |
35 |
* |
36 |
* @param AutoConnectPortID - (optional) Alsa client and port ID of a |
37 |
* MIDI source we should auto connect to |
38 |
* (e.g. "64:0") |
39 |
* @throws MidiInputException if initialization failed |
40 |
*/ |
41 |
MidiInputDeviceMidiShare::MidiInputDeviceMidiShare(char* AutoConnectPortID) : MidiInputDevice(MidiInputDevice::type_midishare) |
42 |
{ |
43 |
if (!MidiShare()) |
44 |
throw MidiInputException("MidiShare not installed"); |
45 |
|
46 |
#if defined(MIDISHARE_DRIVER) |
47 |
OpenDriver(); |
48 |
#else |
49 |
OpenAppl(); |
50 |
#endif |
51 |
|
52 |
hMidiFilter = MidiNewFilter(); |
53 |
|
54 |
if (hMidiFilter == 0) { |
55 |
MidiClose(hRefnum); |
56 |
throw MidiInputException("MidiShare filter can not be allocated"); |
57 |
} |
58 |
|
59 |
for (int i = 0 ; i < 256; i++) { |
60 |
MidiAcceptPort(hMidiFilter, i, 1); /* accept all ports */ |
61 |
MidiAcceptType(hMidiFilter, i, 0); /* reject all types */ |
62 |
} |
63 |
|
64 |
for (int i = 0 ; i < 16; i++) { |
65 |
MidiAcceptChan(hMidiFilter, i, 1); /* accept all chan */ |
66 |
} |
67 |
/* accept only the following types */ |
68 |
MidiAcceptType(hMidiFilter, typeNote, 1); |
69 |
MidiAcceptType(hMidiFilter, typeKeyOn, 1); |
70 |
MidiAcceptType(hMidiFilter, typeKeyOff, 1); |
71 |
MidiAcceptType(hMidiFilter, typeCtrlChange, 1); |
72 |
//MidiAcceptType(hMidiFilter, typeProgChange, 1); |
73 |
MidiAcceptType(hMidiFilter, typePitchWheel, 1); |
74 |
|
75 |
/* set the filter */ |
76 |
MidiSetFilter(hRefnum, hMidiFilter); |
77 |
|
78 |
MidiSetRcvAlarm(hRefnum,ReceiveEvents); |
79 |
MidiSetApplAlarm(hRefnum,ApplAlarm); |
80 |
MidiSetInfo(hRefnum,this); |
81 |
MidiConnect(0,hRefnum,true); |
82 |
} |
83 |
|
84 |
|
85 |
MidiInputDeviceMidiShare::~MidiInputDeviceMidiShare() |
86 |
{ |
87 |
#if defined(MIDISHARE_DRIVER) |
88 |
CloseDriver(); |
89 |
#else |
90 |
CloseAppl(); |
91 |
#endif |
92 |
MidiFreeFilter(hMidiFilter); |
93 |
} |
94 |
|
95 |
void MidiInputDeviceMidiShare::OpenAppl() |
96 |
{ |
97 |
hRefnum = MidiOpen(MSHDriverName); |
98 |
if (hRefnum < 0) { |
99 |
throw MidiInputException("MidiShare client can not be opened"); |
100 |
} |
101 |
MidiSetRcvAlarm(hRefnum,ReceiveEvents); |
102 |
MidiSetApplAlarm(hRefnum,ApplAlarm); |
103 |
} |
104 |
|
105 |
void MidiInputDeviceMidiShare::CloseAppl() |
106 |
{ |
107 |
MidiClose(hRefnum); |
108 |
} |
109 |
|
110 |
void MidiInputDeviceMidiShare::OpenDriver() |
111 |
{ |
112 |
/* gcc wanted me to use {0,0} to initialize the reserved[2] fields */ |
113 |
TDriverInfos infos = { MSHDriverName, 100, 0, { 0, 0 } }; |
114 |
TDriverOperation op = { WakeUp, Sleep, { 0, 0, 0 } }; |
115 |
hRefnum = MidiRegisterDriver(&infos, &op); |
116 |
if (hRefnum < 0) { |
117 |
throw MidiInputException("MidiShare driver can not be opened"); |
118 |
} |
119 |
hSlotRef = MidiAddSlot(hRefnum,MSHSlotName,MidiOutputSlot); |
120 |
MidiSetRcvAlarm(hRefnum,ReceiveEvents); |
121 |
} |
122 |
|
123 |
void MidiInputDeviceMidiShare::CloseDriver() |
124 |
{ |
125 |
MidiUnregisterDriver(hRefnum); |
126 |
} |
127 |
|
128 |
void MidiInputDeviceMidiShare::WakeUp(short r) |
129 |
{ |
130 |
MidiConnect(MidiShareDrvRef, r, true); |
131 |
MidiConnect(r, MidiShareDrvRef, true); |
132 |
} |
133 |
|
134 |
void MidiInputDeviceMidiShare::Sleep(short r){} |
135 |
|
136 |
|
137 |
void MidiInputDeviceMidiShare::SetInputPort(const char * MidiSource) |
138 |
{ |
139 |
|
140 |
} |
141 |
|
142 |
void MidiInputDeviceMidiShare::ApplAlarm(short ref, long code) |
143 |
{ |
144 |
|
145 |
} |
146 |
|
147 |
void MidiInputDeviceMidiShare::KeyOffTask(long date, short ref, long a1, long a2, long a3) |
148 |
{ |
149 |
MidiInputDeviceMidiShare* driver = (MidiInputDeviceMidiShare*)MidiGetInfo(ref); |
150 |
MidiEvPtr ev =(MidiEvPtr)a1; |
151 |
driver->DispatchNoteOn(Pitch(ev),Vel(ev),Chan(ev)); |
152 |
MidiFreeEv(ev); |
153 |
} |
154 |
|
155 |
void MidiInputDeviceMidiShare::ReceiveEvents(short ref) |
156 |
{ |
157 |
MidiInputDeviceMidiShare* driver = (MidiInputDeviceMidiShare*)MidiGetInfo(ref); |
158 |
MidiEvPtr ev; |
159 |
|
160 |
while ((ev = MidiGetEv(ref))) |
161 |
|
162 |
switch(EvType(ev)) { |
163 |
|
164 |
case typeCtrlChange: |
165 |
if (MidiGetField(ev,0) == 0) |
166 |
driver->DispatchBankSelectMsb(MidiGetField(ev,0),Chan(ev)); |
167 |
else if (MidiGetField(ev,0) == 32) |
168 |
driver->DispatchBankSelectLsb(MidiGetField(ev,0),Chan(ev)); |
169 |
else |
170 |
driver->DispatchControlChange(MidiGetField(ev,0),MidiGetField(ev,0),Chan(ev)); |
171 |
MidiFreeEv(ev); |
172 |
break; |
173 |
|
174 |
case typePitchWheel: |
175 |
driver->DispatchPitchbend(((MidiGetField(ev,0)+(MidiGetField(ev,1) << 7)) - 8192),Chan(ev)); |
176 |
MidiFreeEv(ev); |
177 |
break; |
178 |
|
179 |
case typeNote: |
180 |
driver->DispatchNoteOn(Pitch(ev),Vel(ev),Chan(ev)); |
181 |
MidiTask(KeyOffTask,Date(ev)+Dur(ev),ref,(long)ev,0,0); |
182 |
break; |
183 |
|
184 |
case typeKeyOn: |
185 |
if (Vel(ev) > 0) |
186 |
driver->DispatchNoteOn(Pitch(ev),Vel(ev),Chan(ev)); |
187 |
else |
188 |
driver->DispatchNoteOff(Pitch(ev),Vel(ev),Chan(ev)); |
189 |
MidiFreeEv(ev); |
190 |
break; |
191 |
|
192 |
case typeKeyOff: |
193 |
driver->DispatchNoteOff(Pitch(ev),Vel(ev),Chan(ev)); |
194 |
MidiFreeEv(ev); |
195 |
break; |
196 |
} |
197 |
} |
198 |
|
199 |
|
200 |
} // namespace LinuxSampler |