headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / midi2 / MidiLocalConsumer.cpp
blob1ab05a5c1c0f900e98cd0399ffdc925ec109ccfc
1 /*
2 * Copyright 2006, Haiku.
3 *
4 * Copyright (c) 2002-2003 Matthijs Hollemans
5 * Distributed under the terms of the MIT License.
7 * Authors:
8 * Matthijs Hollemans
9 */
11 #include <stdlib.h>
13 #include "debug.h"
14 #include <MidiConsumer.h>
15 #include <MidiRoster.h>
16 #include "protocol.h"
19 int32
20 _midi_event_thread(void* data)
22 return ((BMidiLocalConsumer*) data)->EventThread();
26 BMidiLocalConsumer::BMidiLocalConsumer(const char* name)
27 : BMidiConsumer(name)
29 TRACE(("BMidiLocalConsumer::BMidiLocalConsumer"))
31 fIsLocal = true;
32 fRefCount = 1;
33 fTimeout = (bigtime_t) -1;
34 fTimeoutData = NULL;
36 fPort = create_port(1, "MidiEventPort");
37 fThread = spawn_thread(
38 _midi_event_thread, "MidiEventThread", B_REAL_TIME_PRIORITY, this);
39 resume_thread(fThread);
41 BMidiRoster::MidiRoster()->CreateLocal(this);
45 BMidiLocalConsumer::~BMidiLocalConsumer()
47 TRACE(("BMidiLocalConsumer::~BMidiLocalConsumer"))
49 BMidiRoster::MidiRoster()->DeleteLocal(this);
51 delete_port(fPort);
53 status_t result;
54 wait_for_thread(fThread, &result);
58 void
59 BMidiLocalConsumer::SetLatency(bigtime_t latency_)
61 if (latency_ < 0) {
62 WARN("SetLatency() does not accept negative values");
63 return;
64 } else if (!IsValid()) {
65 return;
66 } else if (fLatency != latency_) {
67 BMessage msg;
68 msg.AddInt64("midi:latency", latency_);
70 if (SendChangeRequest(&msg) == B_OK) {
71 if (LockLooper()) {
72 fLatency = latency_;
73 UnlockLooper();
80 int32
81 BMidiLocalConsumer::GetProducerID()
83 return fCurrentProducer;
87 void
88 BMidiLocalConsumer::SetTimeout(bigtime_t when, void* data)
90 fTimeout = when;
91 fTimeoutData = data;
95 void
96 BMidiLocalConsumer::Timeout(void* data)
98 // Do nothing.
102 void
103 BMidiLocalConsumer::Data(uchar* data, size_t length, bool atomic, bigtime_t time)
105 if (atomic) {
106 switch (data[0] & 0xF0) {
107 case B_NOTE_OFF:
109 if (length == 3)
110 NoteOff(data[0] & 0x0F, data[1], data[2], time);
111 break;
114 case B_NOTE_ON:
116 if (length == 3)
117 NoteOn(data[0] & 0x0F, data[1], data[2], time);
118 break;
121 case B_KEY_PRESSURE:
123 if (length == 3)
124 KeyPressure(data[0] & 0x0F, data[1], data[2], time);
125 break;
128 case B_CONTROL_CHANGE:
130 if (length == 3)
131 ControlChange(data[0] & 0x0F, data[1], data[2], time);
132 break;
135 case B_PROGRAM_CHANGE:
137 if (length == 2)
138 ProgramChange(data[0] & 0x0F, data[1], time);
139 break;
142 case B_CHANNEL_PRESSURE:
144 if (length == 2)
145 ChannelPressure(data[0] & 0x0F, data[1], time);
146 break;
149 case B_PITCH_BEND:
151 if (length == 3)
152 PitchBend(data[0] & 0x0F, data[1], data[2], time);
153 break;
156 case 0xF0:
158 switch (data[0]) {
159 case B_SYS_EX_START:
161 if (data[length - 1] == B_SYS_EX_END) {
162 SystemExclusive(data + 1, length - 2, time);
163 } else { // sysex-end is not required
164 SystemExclusive(data + 1, length - 1, time);
166 break;
169 case B_TUNE_REQUEST:
170 case B_SYS_EX_END:
172 if (length == 1) {
173 SystemCommon(data[0], 0, 0, time);
175 break;
178 case B_CABLE_MESSAGE:
179 case B_MIDI_TIME_CODE:
180 case B_SONG_SELECT:
182 if (length == 2) {
183 SystemCommon(data[0], data[1], 0, time);
185 break;
188 case B_SONG_POSITION:
190 if (length == 3) {
191 SystemCommon(data[0], data[1], data[2], time);
193 break;
196 case B_TIMING_CLOCK:
197 case B_START:
198 case B_CONTINUE:
199 case B_STOP:
200 case B_ACTIVE_SENSING:
202 if (length == 1) {
203 SystemRealTime(data[0], time);
205 break;
208 case B_SYSTEM_RESET:
210 if (length == 1) {
211 SystemRealTime(data[0], time);
212 } else if ((length == 6) && (data[1] == 0x51)
213 && (data[2] == 0x03)) {
214 int32 tempo =
215 (data[3] << 16) | (data[4] << 8) | data[5];
217 TempoChange(60000000/tempo, time);
221 break;
228 void
229 BMidiLocalConsumer::NoteOff(uchar channel, uchar note, uchar velocity, bigtime_t time)
231 // Do nothing.
235 void
236 BMidiLocalConsumer::NoteOn(uchar channel, uchar note, uchar velocity, bigtime_t time)
238 // Do nothing.
242 void
243 BMidiLocalConsumer::KeyPressure(uchar channel, uchar note, uchar pressure, bigtime_t time)
245 // Do nothing.
249 void
250 BMidiLocalConsumer::ControlChange(uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time)
252 // Do nothing.
256 void
257 BMidiLocalConsumer::ProgramChange(uchar channel, uchar programNumber, bigtime_t time)
259 // Do nothing.
263 void BMidiLocalConsumer::ChannelPressure(uchar channel, uchar pressure, bigtime_t time)
265 // Do nothing.
269 void
270 BMidiLocalConsumer::PitchBend(uchar channel, uchar lsb, uchar msb, bigtime_t time)
272 // Do nothing.
276 void
277 BMidiLocalConsumer::SystemExclusive(
278 void* data, size_t length, bigtime_t time)
280 // Do nothing.
284 void
285 BMidiLocalConsumer::SystemCommon(
286 uchar statusByte, uchar data1, uchar data2, bigtime_t time)
288 // Do nothing.
292 void
293 BMidiLocalConsumer::SystemRealTime(uchar statusByte, bigtime_t time)
295 // Do nothing.
299 void
300 BMidiLocalConsumer::TempoChange(int32 beatsPerMinute, bigtime_t time)
302 // Do nothing.
306 void
307 BMidiLocalConsumer::AllNotesOff(bool justChannel, bigtime_t time)
309 // Do nothing.
313 void BMidiLocalConsumer::_Reserved1() { }
314 void BMidiLocalConsumer::_Reserved2() { }
315 void BMidiLocalConsumer::_Reserved3() { }
316 void BMidiLocalConsumer::_Reserved4() { }
317 void BMidiLocalConsumer::_Reserved5() { }
318 void BMidiLocalConsumer::_Reserved6() { }
319 void BMidiLocalConsumer::_Reserved7() { }
320 void BMidiLocalConsumer::_Reserved8() { }
323 int32
324 BMidiLocalConsumer::EventThread()
326 int32 msg_code;
327 ssize_t msg_size;
328 ssize_t buf_size = 100;
329 uint8* buffer = (uint8*) malloc(buf_size);
331 while (true) {
332 if (fTimeout == (bigtime_t) -1) {
333 msg_size = port_buffer_size(fPort);
334 } else { // have timeout
335 msg_size = port_buffer_size_etc(fPort, B_ABSOLUTE_TIMEOUT, fTimeout);
336 if (msg_size == B_TIMED_OUT) {
337 Timeout(fTimeoutData);
338 fTimeout = (bigtime_t) -1;
339 fTimeoutData = NULL;
340 continue;
344 if (msg_size < 0)
345 break; // error reading port
347 if (msg_size > buf_size) {
348 buffer = (uint8*) realloc(buffer, msg_size);
349 buf_size = msg_size;
352 read_port(fPort, &msg_code, buffer, msg_size);
354 if (msg_size > 20) { // minimum valid size
355 #ifdef DEBUG
356 printf("*** received: ");
357 for (int32 t = 0; t < msg_size; ++t) {
358 printf("%02X, ", ((uint8*) buffer)[t]);
360 printf("\n");
361 #endif
363 fCurrentProducer = *((uint32*) (buffer + 0));
364 int32 targetId = *((uint32*) (buffer + 4));
365 bigtime_t time = *((bigtime_t*) (buffer + 8));
366 bool atomic = *((bool*) (buffer + 16));
368 if (targetId == fId) { // only if we are the destination
369 Data((uchar*) (buffer + 20), msg_size - 20, atomic, time);
374 free(buffer);
375 return 0;