xref: /haiku/src/kits/midi/MidiPort.cpp (revision 81f5654c124bf46fba0fd251f208e2d88d81e1ce)
1 /*
2  * Copyright (c) 2002-2003 Matthijs Hollemans
3  * Copyright (c) 2002 Jerome Leveque
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <MidiProducer.h>
25 #include <MidiRoster.h>
26 #include <stdlib.h>
27 
28 #include "debug.h"
29 #include "MidiPort.h"
30 #include "MidiGlue.h"
31 
32 using namespace BPrivate;
33 
34 //------------------------------------------------------------------------------
35 
36 BMidiPort::BMidiPort(const char* name)
37 {
38 	portName = NULL;
39 	devices  = new BList;
40 	status   = B_ERROR;
41 
42 	localSource = new BMidiLocalProducer("MidiPortGlue(out)");
43 	localSink   = new BMidiPortGlue(this, "MidiPortGlue(in)");
44 
45 	remoteSource = NULL;
46 	remoteSink   = NULL;
47 
48 	ScanDevices();
49 
50 	if (name != NULL)
51 	{
52 		Open(name);
53 	}
54 }
55 
56 //------------------------------------------------------------------------------
57 
58 BMidiPort::~BMidiPort()
59 {
60 	Close();
61 
62 	EmptyDeviceList();
63 	delete devices;
64 
65 	localSource->Release();
66 	localSink->Release();
67 }
68 
69 //------------------------------------------------------------------------------
70 
71 status_t BMidiPort::InitCheck() const
72 {
73 	return status;
74 }
75 
76 //------------------------------------------------------------------------------
77 
78 status_t BMidiPort::Open(const char* name)
79 {
80 	status = B_ERROR;
81 
82 	if (name != NULL)
83 	{
84 		Close();
85 
86 		for (int32 t = 0; t < devices->CountItems(); ++t)
87 		{
88 			BMidiEndpoint* endp = (BMidiEndpoint*) devices->ItemAt(t);
89 			if (strcmp(name, endp->Name()) == 0)
90 			{
91 				if (endp->IsValid())  // still exists?
92 				{
93 					if (endp->IsProducer())
94 					{
95 						if (remoteSource == NULL)
96 						{
97 							remoteSource = (BMidiProducer*) endp;
98 						}
99 					}
100 					else if (endp->IsConsumer())
101 					{
102 						if (remoteSink == NULL)
103 						{
104 							remoteSink = (BMidiConsumer*) endp;
105 							localSource->Connect(remoteSink);
106 						}
107 					}
108 				}
109 			}
110 		}
111 
112 		if (remoteSource != NULL)
113 		{
114 			portName = strdup(remoteSource->Name());
115 			status = B_OK;
116 		}
117 		else if (remoteSink != NULL)
118 		{
119 			portName = strdup(remoteSink->Name());
120 			status = B_OK;
121 		}
122 	}
123 
124 	return status;
125 }
126 
127 //------------------------------------------------------------------------------
128 
129 void BMidiPort::Close()
130 {
131 	if (remoteSource != NULL)
132 	{
133 		remoteSource->Disconnect(localSink);
134 		remoteSource = NULL;
135 	}
136 
137 	if (remoteSink != NULL)
138 	{
139 		localSource->Disconnect(remoteSink);
140 		remoteSink = NULL;
141 	}
142 
143 	if (portName != NULL)
144 	{
145 		free(portName);
146 		portName = NULL;
147 	}
148 }
149 
150 //------------------------------------------------------------------------------
151 
152 const char* BMidiPort::PortName() const
153 {
154 	return portName;
155 }
156 
157 //------------------------------------------------------------------------------
158 
159 void BMidiPort::NoteOff(
160 	uchar channel, uchar note, uchar velocity, uint32 time)
161 {
162 	localSource->SprayNoteOff(channel - 1, note, velocity, MAKE_BIGTIME(time));
163 }
164 
165 //------------------------------------------------------------------------------
166 
167 void BMidiPort::NoteOn(
168 	uchar channel, uchar note, uchar velocity, uint32 time)
169 {
170 	localSource->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time));
171 }
172 
173 //------------------------------------------------------------------------------
174 
175 void BMidiPort::KeyPressure(
176 	uchar channel, uchar note, uchar pressure, uint32 time)
177 {
178 	localSource->SprayKeyPressure(
179 		channel - 1, note, pressure, MAKE_BIGTIME(time));
180 }
181 
182 //------------------------------------------------------------------------------
183 
184 void BMidiPort::ControlChange(
185 	uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
186 {
187 	localSource->SprayControlChange(
188 		channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time));
189 }
190 
191 //------------------------------------------------------------------------------
192 
193 void BMidiPort::ProgramChange(
194 	uchar channel, uchar programNumber, uint32 time)
195 {
196 	localSource->SprayProgramChange(
197 		channel - 1, programNumber, MAKE_BIGTIME(time));
198 }
199 
200 //------------------------------------------------------------------------------
201 
202 void BMidiPort::ChannelPressure(uchar channel, uchar pressure, uint32 time)
203 {
204 	localSource->SprayChannelPressure(
205 		channel - 1, pressure, MAKE_BIGTIME(time));
206 }
207 
208 //------------------------------------------------------------------------------
209 
210 void BMidiPort::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
211 {
212 	localSource->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time));
213 }
214 
215 //------------------------------------------------------------------------------
216 
217 void BMidiPort::SystemExclusive(void* data, size_t length, uint32 time)
218 {
219 	localSource->SpraySystemExclusive(data, length, MAKE_BIGTIME(time));
220 }
221 
222 //------------------------------------------------------------------------------
223 
224 void BMidiPort::SystemCommon(
225 	uchar status, uchar data1, uchar data2, uint32 time)
226 {
227 	localSource->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time));
228 }
229 
230 //------------------------------------------------------------------------------
231 
232 void BMidiPort::SystemRealTime(uchar status, uint32 time)
233 {
234 	localSource->SpraySystemRealTime(status, MAKE_BIGTIME(time));
235 }
236 
237 //------------------------------------------------------------------------------
238 
239 status_t BMidiPort::Start()
240 {
241 	status_t err = super::Start();
242 
243 	if ((err == B_OK) && (remoteSource != NULL))
244 	{
245 		return remoteSource->Connect(localSink);
246 	}
247 
248 	return err;
249 }
250 
251 //------------------------------------------------------------------------------
252 
253 void BMidiPort::Stop()
254 {
255 	if (remoteSource != NULL)
256 	{
257 		remoteSource->Disconnect(localSink);
258 	}
259 
260 	super::Stop();
261 }
262 
263 //------------------------------------------------------------------------------
264 
265 int32 BMidiPort::CountDevices()
266 {
267 	return devices->CountItems();
268 }
269 
270 //------------------------------------------------------------------------------
271 
272 status_t BMidiPort::GetDeviceName(int32 n, char* name, size_t bufSize)
273 {
274 	BMidiEndpoint* endp = (BMidiEndpoint*) devices->ItemAt(n);
275 	if (endp == NULL)
276 	{
277 		return B_BAD_VALUE;
278 	}
279 
280 	size_t size = strlen(endp->Name());
281 	if (size >= bufSize)
282 	{
283 		return B_NAME_TOO_LONG;
284 	}
285 
286 	strcpy(name, endp->Name());
287 	return B_OK;
288 }
289 
290 //------------------------------------------------------------------------------
291 
292 void BMidiPort::_ReservedMidiPort1() { }
293 void BMidiPort::_ReservedMidiPort2() { }
294 void BMidiPort::_ReservedMidiPort3() { }
295 
296 //------------------------------------------------------------------------------
297 
298 void BMidiPort::Run()
299 {
300 	while (KeepRunning())
301 	{
302 		snooze(50000);
303 	}
304 }
305 
306 //------------------------------------------------------------------------------
307 
308 void BMidiPort::ScanDevices()
309 {
310 	EmptyDeviceList();
311 
312 	int32 id = 0;
313 	BMidiEndpoint* endp;
314 
315 	while ((endp = BMidiRoster::NextEndpoint(&id)) != NULL)
316 	{
317 		// Each hardware port has two endpoints associated with it, a consumer
318 		// and a producer. Both have the same name, so we add only one of them.
319 
320 		bool addItem = true;
321 		for (int32 t = 0; t < devices->CountItems(); ++t)
322 		{
323 			BMidiEndpoint* other = (BMidiEndpoint*) devices->ItemAt(t);
324 			if (strcmp(endp->Name(), other->Name()) == 0)
325 			{
326 				addItem = false;
327 				break;
328 			}
329 		}
330 
331 		if (addItem)
332 		{
333 			devices->AddItem(endp);
334 		}
335 		else
336 		{
337 			endp->Release();
338 		}
339 	}
340 }
341 
342 //------------------------------------------------------------------------------
343 
344 void BMidiPort::EmptyDeviceList()
345 {
346 	for (int32 t = 0; t < devices->CountItems(); ++t)
347 	{
348 		((BMidiEndpoint*) devices->ItemAt(t))->Release();
349 	}
350 
351 	devices->MakeEmpty();
352 }
353 
354 //------------------------------------------------------------------------------
355