xref: /haiku/src/kits/midi/MidiPort.cpp (revision e5430a086c769ea76c3944046b1f07cf049c1ae0)
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 //------------------------------------------------------------------------------
33 
34 BMidiPort::BMidiPort(const char* name)
35 {
36 	portName = NULL;
37 	devices  = new BList;
38 	status   = B_ERROR;
39 
40 	localSource = new BMidiLocalProducer("MidiPortGlue(out)");
41 	localSink   = new BMidiPortGlue(this, "MidiPortGlue(in)");
42 
43 	remoteSource = NULL;
44 	remoteSink   = NULL;
45 
46 	ScanDevices();
47 
48 	if (name != NULL)
49 	{
50 		Open(name);
51 	}
52 }
53 
54 //------------------------------------------------------------------------------
55 
56 BMidiPort::~BMidiPort()
57 {
58 	Close();
59 
60 	EmptyDeviceList();
61 	delete devices;
62 
63 	localSource->Release();
64 	localSink->Release();
65 }
66 
67 //------------------------------------------------------------------------------
68 
69 status_t BMidiPort::InitCheck() const
70 {
71 	return status;
72 }
73 
74 //------------------------------------------------------------------------------
75 
76 status_t BMidiPort::Open(const char* name)
77 {
78 	status = B_ERROR;
79 
80 	if (name != NULL)
81 	{
82 		Close();
83 
84 		for (int32 t = 0; t < devices->CountItems(); ++t)
85 		{
86 			BMidiEndpoint* endp = (BMidiEndpoint*) devices->ItemAt(t);
87 			if (strcmp(name, endp->Name()) == 0)
88 			{
89 				if (endp->IsValid())  // still exists?
90 				{
91 					if (endp->IsProducer())
92 					{
93 						if (remoteSource == NULL)
94 						{
95 							remoteSource = (BMidiProducer*) endp;
96 						}
97 					}
98 					else if (endp->IsConsumer())
99 					{
100 						if (remoteSink == NULL)
101 						{
102 							remoteSink = (BMidiConsumer*) endp;
103 							localSource->Connect(remoteSink);
104 						}
105 					}
106 				}
107 			}
108 		}
109 
110 		if (remoteSource != NULL)
111 		{
112 			portName = strdup(remoteSource->Name());
113 			status = B_OK;
114 		}
115 		else if (remoteSink != NULL)
116 		{
117 			portName = strdup(remoteSink->Name());
118 			status = B_OK;
119 		}
120 	}
121 
122 	return status;
123 }
124 
125 //------------------------------------------------------------------------------
126 
127 void BMidiPort::Close()
128 {
129 	if (remoteSource != NULL)
130 	{
131 		remoteSource->Disconnect(localSink);
132 		remoteSource = NULL;
133 	}
134 
135 	if (remoteSink != NULL)
136 	{
137 		localSource->Disconnect(remoteSink);
138 		remoteSink = NULL;
139 	}
140 
141 	if (portName != NULL)
142 	{
143 		free(portName);
144 		portName = NULL;
145 	}
146 }
147 
148 //------------------------------------------------------------------------------
149 
150 const char* BMidiPort::PortName() const
151 {
152 	return portName;
153 }
154 
155 //------------------------------------------------------------------------------
156 
157 void BMidiPort::NoteOff(
158 	uchar channel, uchar note, uchar velocity, uint32 time)
159 {
160 	localSource->SprayNoteOff(channel - 1, note, velocity, MAKE_BIGTIME(time));
161 }
162 
163 //------------------------------------------------------------------------------
164 
165 void BMidiPort::NoteOn(
166 	uchar channel, uchar note, uchar velocity, uint32 time)
167 {
168 	localSource->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time));
169 }
170 
171 //------------------------------------------------------------------------------
172 
173 void BMidiPort::KeyPressure(
174 	uchar channel, uchar note, uchar pressure, uint32 time)
175 {
176 	localSource->SprayKeyPressure(
177 		channel - 1, note, pressure, MAKE_BIGTIME(time));
178 }
179 
180 //------------------------------------------------------------------------------
181 
182 void BMidiPort::ControlChange(
183 	uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
184 {
185 	localSource->SprayControlChange(
186 		channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time));
187 }
188 
189 //------------------------------------------------------------------------------
190 
191 void BMidiPort::ProgramChange(
192 	uchar channel, uchar programNumber, uint32 time)
193 {
194 	localSource->SprayProgramChange(
195 		channel - 1, programNumber, MAKE_BIGTIME(time));
196 }
197 
198 //------------------------------------------------------------------------------
199 
200 void BMidiPort::ChannelPressure(uchar channel, uchar pressure, uint32 time)
201 {
202 	localSource->SprayChannelPressure(
203 		channel - 1, pressure, MAKE_BIGTIME(time));
204 }
205 
206 //------------------------------------------------------------------------------
207 
208 void BMidiPort::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
209 {
210 	localSource->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time));
211 }
212 
213 //------------------------------------------------------------------------------
214 
215 void BMidiPort::SystemExclusive(void* data, size_t length, uint32 time)
216 {
217 	localSource->SpraySystemExclusive(data, length, MAKE_BIGTIME(time));
218 }
219 
220 //------------------------------------------------------------------------------
221 
222 void BMidiPort::SystemCommon(
223 	uchar status, uchar data1, uchar data2, uint32 time)
224 {
225 	localSource->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time));
226 }
227 
228 //------------------------------------------------------------------------------
229 
230 void BMidiPort::SystemRealTime(uchar status, uint32 time)
231 {
232 	localSource->SpraySystemRealTime(status, MAKE_BIGTIME(time));
233 }
234 
235 //------------------------------------------------------------------------------
236 
237 status_t BMidiPort::Start()
238 {
239 	status_t err = super::Start();
240 
241 	if ((err == B_OK) && (remoteSource != NULL))
242 	{
243 		return remoteSource->Connect(localSink);
244 	}
245 
246 	return err;
247 }
248 
249 //------------------------------------------------------------------------------
250 
251 void BMidiPort::Stop()
252 {
253 	if (remoteSource != NULL)
254 	{
255 		remoteSource->Disconnect(localSink);
256 	}
257 
258 	super::Stop();
259 }
260 
261 //------------------------------------------------------------------------------
262 
263 int32 BMidiPort::CountDevices()
264 {
265 	return devices->CountItems();
266 }
267 
268 //------------------------------------------------------------------------------
269 
270 status_t BMidiPort::GetDeviceName(int32 n, char* name, size_t bufSize)
271 {
272 	BMidiEndpoint* endp = (BMidiEndpoint*) devices->ItemAt(n);
273 	if (endp == NULL)
274 	{
275 		return B_BAD_VALUE;
276 	}
277 
278 	size_t size = strlen(endp->Name());
279 	if (size >= bufSize)
280 	{
281 		return B_NAME_TOO_LONG;
282 	}
283 
284 	strcpy(name, endp->Name());
285 	return B_OK;
286 }
287 
288 //------------------------------------------------------------------------------
289 
290 void BMidiPort::_ReservedMidiPort1() { }
291 void BMidiPort::_ReservedMidiPort2() { }
292 void BMidiPort::_ReservedMidiPort3() { }
293 
294 //------------------------------------------------------------------------------
295 
296 void BMidiPort::Run()
297 {
298 	while (KeepRunning())
299 	{
300 		snooze(50000);
301 	}
302 }
303 
304 //------------------------------------------------------------------------------
305 
306 void BMidiPort::ScanDevices()
307 {
308 	EmptyDeviceList();
309 
310 	int32 id = 0;
311 	BMidiEndpoint* endp;
312 
313 	while ((endp = BMidiRoster::NextEndpoint(&id)) != NULL)
314 	{
315 		// Each hardware port has two endpoints associated with it, a consumer
316 		// and a producer. Both have the same name, so we add only one of them.
317 
318 		bool addItem = true;
319 		for (int32 t = 0; t < devices->CountItems(); ++t)
320 		{
321 			BMidiEndpoint* other = (BMidiEndpoint*) devices->ItemAt(t);
322 			if (strcmp(endp->Name(), other->Name()) == 0)
323 			{
324 				addItem = false;
325 				break;
326 			}
327 		}
328 
329 		if (addItem)
330 		{
331 			devices->AddItem(endp);
332 		}
333 		else
334 		{
335 			endp->Release();
336 		}
337 	}
338 }
339 
340 //------------------------------------------------------------------------------
341 
342 void BMidiPort::EmptyDeviceList()
343 {
344 	for (int32 t = 0; t < devices->CountItems(); ++t)
345 	{
346 		((BMidiEndpoint*) devices->ItemAt(t))->Release();
347 	}
348 
349 	devices->MakeEmpty();
350 }
351 
352 //------------------------------------------------------------------------------
353