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