xref: /haiku/src/kits/midi/MidiPort.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
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 
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
60 BMidiPort::InitCheck() const
61 {
62 	return fStatus;
63 }
64 
65 
66 status_t
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
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*
125 BMidiPort::PortName() const
126 {
127 	return fPortName;
128 }
129 
130 
131 void
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
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
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
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
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
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
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
190 BMidiPort::SystemExclusive(void* data, size_t length, uint32 time)
191 {
192 	fLocalSource->SpraySystemExclusive(data, length, MAKE_BIGTIME(time));
193 }
194 
195 
196 void
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
205 BMidiPort::SystemRealTime(uchar status, uint32 time)
206 {
207 	fLocalSource->SpraySystemRealTime(status, MAKE_BIGTIME(time));
208 }
209 
210 
211 status_t
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
225 BMidiPort::Stop()
226 {
227 	if (fRemoteSource != NULL) {
228 		fRemoteSource->Disconnect(fLocalSink);
229 	}
230 
231 	super::Stop();
232 }
233 
234 
235 int32
236 BMidiPort::CountDevices()
237 {
238 	return fDevices->CountItems();
239 }
240 
241 
242 status_t
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 
258 void BMidiPort::_ReservedMidiPort1() { }
259 void BMidiPort::_ReservedMidiPort2() { }
260 void BMidiPort::_ReservedMidiPort3() { }
261 
262 
263 void
264 BMidiPort::Run()
265 {
266 	while (KeepRunning())
267 		snooze(50000);
268 }
269 
270 
271 void
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
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