1 /*
2 * Copyright 2006, Haiku.
3 *
4 * Copyright (c) 2002-2003 Matthijs Hollemans
5 * Copyright (c) 2002 Jerome Leveque
6 * Distributed under the terms of the MIT License.
7 *
8 * Authors:
9 * Matthijs Hollemans
10 * Jérôme Leveque
11 */
12
13 #include <MidiPort.h>
14 #include <MidiProducer.h>
15 #include <MidiRoster.h>
16 #include <stdlib.h>
17
18 #include "debug.h"
19 #include "MidiGlue.h"
20
21 using namespace BPrivate;
22
23
BMidiPort(const char * name)24 BMidiPort::BMidiPort(const char* name)
25 {
26 fPortName = NULL;
27 fDevices = new BList;
28 fStatus = B_ERROR;
29
30 fLocalSource = new BMidiLocalProducer("MidiPortGlue(out)");
31 fLocalSink = new BMidiPortGlue(this, "MidiPortGlue(in)");
32 fLocalSource->Register();
33 fLocalSink->Register();
34
35 fRemoteSource = NULL;
36 fRemoteSink = NULL;
37
38 ScanDevices();
39
40 if (name != NULL)
41 Open(name);
42 }
43
44
~BMidiPort()45 BMidiPort::~BMidiPort()
46 {
47 Close();
48
49 EmptyDeviceList();
50 delete fDevices;
51
52 fLocalSource->Unregister();
53 fLocalSink->Unregister();
54 fLocalSource->Release();
55 fLocalSink->Release();
56 }
57
58
59 status_t
InitCheck() const60 BMidiPort::InitCheck() const
61 {
62 return fStatus;
63 }
64
65
66 status_t
Open(const char * name)67 BMidiPort::Open(const char* name)
68 {
69 fStatus = B_ERROR;
70
71 if (name != NULL) {
72 Close();
73
74 for (int32 t = 0; t < fDevices->CountItems(); ++t) {
75 BMidiEndpoint* endp = (BMidiEndpoint*)fDevices->ItemAt(t);
76 if (strcmp(name, endp->Name()) != 0)
77 continue;
78 if (!endp->IsValid()) // still exists?
79 continue;
80 if (endp->IsProducer()) {
81 if (fRemoteSource == NULL)
82 fRemoteSource = (BMidiProducer*)endp;
83 } else {
84 if (fRemoteSink == NULL) {
85 fRemoteSink = (BMidiConsumer*)endp;
86 fLocalSource->Connect(fRemoteSink);
87 }
88 }
89 }
90
91 if (fRemoteSource != NULL) {
92 fPortName = strdup(fRemoteSource->Name());
93 fStatus = B_OK;
94 } else if (fRemoteSink != NULL) {
95 fPortName = strdup(fRemoteSink->Name());
96 fStatus = B_OK;
97 }
98 }
99
100 return fStatus;
101 }
102
103
104 void
Close()105 BMidiPort::Close()
106 {
107 if (fRemoteSource != NULL) {
108 fRemoteSource->Disconnect(fLocalSink);
109 fRemoteSource = NULL;
110 }
111
112 if (fRemoteSink != NULL) {
113 fLocalSource->Disconnect(fRemoteSink);
114 fRemoteSink = NULL;
115 }
116
117 if (fPortName != NULL) {
118 free(fPortName);
119 fPortName = NULL;
120 }
121 }
122
123
124 const char*
PortName() const125 BMidiPort::PortName() const
126 {
127 return fPortName;
128 }
129
130
131 void
NoteOff(uchar channel,uchar note,uchar velocity,uint32 time)132 BMidiPort::NoteOff(
133 uchar channel, uchar note, uchar velocity, uint32 time)
134 {
135 fLocalSource->SprayNoteOff(channel - 1, note, velocity, MAKE_BIGTIME(time));
136 }
137
138
139 void
NoteOn(uchar channel,uchar note,uchar velocity,uint32 time)140 BMidiPort::NoteOn(
141 uchar channel, uchar note, uchar velocity, uint32 time)
142 {
143 fLocalSource->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time));
144 }
145
146
147 void
KeyPressure(uchar channel,uchar note,uchar pressure,uint32 time)148 BMidiPort::KeyPressure(
149 uchar channel, uchar note, uchar pressure, uint32 time)
150 {
151 fLocalSource->SprayKeyPressure(
152 channel - 1, note, pressure, MAKE_BIGTIME(time));
153 }
154
155
156 void
ControlChange(uchar channel,uchar controlNumber,uchar controlValue,uint32 time)157 BMidiPort::ControlChange(
158 uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
159 {
160 fLocalSource->SprayControlChange(
161 channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time));
162 }
163
164
165 void
ProgramChange(uchar channel,uchar programNumber,uint32 time)166 BMidiPort::ProgramChange(
167 uchar channel, uchar programNumber, uint32 time)
168 {
169 fLocalSource->SprayProgramChange(
170 channel - 1, programNumber, MAKE_BIGTIME(time));
171 }
172
173
174 void
ChannelPressure(uchar channel,uchar pressure,uint32 time)175 BMidiPort::ChannelPressure(uchar channel, uchar pressure, uint32 time)
176 {
177 fLocalSource->SprayChannelPressure(
178 channel - 1, pressure, MAKE_BIGTIME(time));
179 }
180
181
182 void
PitchBend(uchar channel,uchar lsb,uchar msb,uint32 time)183 BMidiPort::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
184 {
185 fLocalSource->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time));
186 }
187
188
189 void
SystemExclusive(void * data,size_t length,uint32 time)190 BMidiPort::SystemExclusive(void* data, size_t length, uint32 time)
191 {
192 fLocalSource->SpraySystemExclusive(data, length, MAKE_BIGTIME(time));
193 }
194
195
196 void
SystemCommon(uchar status,uchar data1,uchar data2,uint32 time)197 BMidiPort::SystemCommon(
198 uchar status, uchar data1, uchar data2, uint32 time)
199 {
200 fLocalSource->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time));
201 }
202
203
204 void
SystemRealTime(uchar status,uint32 time)205 BMidiPort::SystemRealTime(uchar status, uint32 time)
206 {
207 fLocalSource->SpraySystemRealTime(status, MAKE_BIGTIME(time));
208 }
209
210
211 status_t
Start()212 BMidiPort::Start()
213 {
214 status_t err = super::Start();
215
216 if ((err == B_OK) && (fRemoteSource != NULL)) {
217 return fRemoteSource->Connect(fLocalSink);
218 }
219
220 return err;
221 }
222
223
224 void
Stop()225 BMidiPort::Stop()
226 {
227 if (fRemoteSource != NULL) {
228 fRemoteSource->Disconnect(fLocalSink);
229 }
230
231 super::Stop();
232 }
233
234
235 int32
CountDevices()236 BMidiPort::CountDevices()
237 {
238 return fDevices->CountItems();
239 }
240
241
242 status_t
GetDeviceName(int32 n,char * name,size_t bufSize)243 BMidiPort::GetDeviceName(int32 n, char* name, size_t bufSize)
244 {
245 BMidiEndpoint* endp = (BMidiEndpoint*)fDevices->ItemAt(n);
246 if (endp == NULL)
247 return B_BAD_VALUE;
248
249 size_t size = strlen(endp->Name());
250 if (size >= bufSize)
251 return B_NAME_TOO_LONG;
252
253 strcpy(name, endp->Name());
254 return B_OK;
255 }
256
257
_ReservedMidiPort1()258 void BMidiPort::_ReservedMidiPort1() { }
_ReservedMidiPort2()259 void BMidiPort::_ReservedMidiPort2() { }
_ReservedMidiPort3()260 void BMidiPort::_ReservedMidiPort3() { }
261
262
263 void
Run()264 BMidiPort::Run()
265 {
266 while (KeepRunning())
267 snooze(50000);
268 }
269
270
271 void
ScanDevices()272 BMidiPort::ScanDevices()
273 {
274 EmptyDeviceList();
275
276 int32 id = 0;
277 BMidiEndpoint* endp;
278
279 while ((endp = BMidiRoster::NextEndpoint(&id)) != NULL) {
280 // Each hardware port has two endpoints associated with it, a consumer
281 // and a producer. Both have the same name, so we add only one of them.
282
283 bool addItem = true;
284 for (int32 t = 0; t < fDevices->CountItems(); ++t) {
285 BMidiEndpoint* other = (BMidiEndpoint*)fDevices->ItemAt(t);
286 if (strcmp(endp->Name(), other->Name()) == 0) {
287 addItem = false;
288 break;
289 }
290 }
291
292 if (addItem) {
293 fDevices->AddItem(endp);
294 } else {
295 endp->Release();
296 }
297 }
298 }
299
300
301 void
EmptyDeviceList()302 BMidiPort::EmptyDeviceList()
303 {
304 for (int32 t = 0; t < fDevices->CountItems(); ++t)
305 ((BMidiEndpoint*)fDevices->ItemAt(t))->Release();
306
307 fDevices->MakeEmpty();
308 }
309
310