2 * Copyright 2006, Haiku.
4 * Copyright (c) 2002-2003 Matthijs Hollemans
5 * Distributed under the terms of the MIT License.
14 #include <MidiConsumer.h>
15 #include <MidiRoster.h>
20 _midi_event_thread(void* data
)
22 return ((BMidiLocalConsumer
*) data
)->EventThread();
26 BMidiLocalConsumer::BMidiLocalConsumer(const char* name
)
29 TRACE(("BMidiLocalConsumer::BMidiLocalConsumer"))
33 fTimeout
= (bigtime_t
) -1;
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);
54 wait_for_thread(fThread
, &result
);
59 BMidiLocalConsumer::SetLatency(bigtime_t latency_
)
62 WARN("SetLatency() does not accept negative values");
64 } else if (!IsValid()) {
66 } else if (fLatency
!= latency_
) {
68 msg
.AddInt64("midi:latency", latency_
);
70 if (SendChangeRequest(&msg
) == B_OK
) {
81 BMidiLocalConsumer::GetProducerID()
83 return fCurrentProducer
;
88 BMidiLocalConsumer::SetTimeout(bigtime_t when
, void* data
)
96 BMidiLocalConsumer::Timeout(void* data
)
103 BMidiLocalConsumer::Data(uchar
* data
, size_t length
, bool atomic
, bigtime_t time
)
106 switch (data
[0] & 0xF0) {
110 NoteOff(data
[0] & 0x0F, data
[1], data
[2], time
);
117 NoteOn(data
[0] & 0x0F, data
[1], data
[2], time
);
124 KeyPressure(data
[0] & 0x0F, data
[1], data
[2], time
);
128 case B_CONTROL_CHANGE
:
131 ControlChange(data
[0] & 0x0F, data
[1], data
[2], time
);
135 case B_PROGRAM_CHANGE
:
138 ProgramChange(data
[0] & 0x0F, data
[1], time
);
142 case B_CHANNEL_PRESSURE
:
145 ChannelPressure(data
[0] & 0x0F, data
[1], time
);
152 PitchBend(data
[0] & 0x0F, data
[1], data
[2], time
);
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
);
173 SystemCommon(data
[0], 0, 0, time
);
178 case B_CABLE_MESSAGE
:
179 case B_MIDI_TIME_CODE
:
183 SystemCommon(data
[0], data
[1], 0, time
);
188 case B_SONG_POSITION
:
191 SystemCommon(data
[0], data
[1], data
[2], time
);
200 case B_ACTIVE_SENSING
:
203 SystemRealTime(data
[0], time
);
211 SystemRealTime(data
[0], time
);
212 } else if ((length
== 6) && (data
[1] == 0x51)
213 && (data
[2] == 0x03)) {
215 (data
[3] << 16) | (data
[4] << 8) | data
[5];
217 TempoChange(60000000/tempo
, time
);
229 BMidiLocalConsumer::NoteOff(uchar channel
, uchar note
, uchar velocity
, bigtime_t time
)
236 BMidiLocalConsumer::NoteOn(uchar channel
, uchar note
, uchar velocity
, bigtime_t time
)
243 BMidiLocalConsumer::KeyPressure(uchar channel
, uchar note
, uchar pressure
, bigtime_t time
)
250 BMidiLocalConsumer::ControlChange(uchar channel
, uchar controlNumber
, uchar controlValue
, bigtime_t time
)
257 BMidiLocalConsumer::ProgramChange(uchar channel
, uchar programNumber
, bigtime_t time
)
263 void BMidiLocalConsumer::ChannelPressure(uchar channel
, uchar pressure
, bigtime_t time
)
270 BMidiLocalConsumer::PitchBend(uchar channel
, uchar lsb
, uchar msb
, bigtime_t time
)
277 BMidiLocalConsumer::SystemExclusive(
278 void* data
, size_t length
, bigtime_t time
)
285 BMidiLocalConsumer::SystemCommon(
286 uchar statusByte
, uchar data1
, uchar data2
, bigtime_t time
)
293 BMidiLocalConsumer::SystemRealTime(uchar statusByte
, bigtime_t time
)
300 BMidiLocalConsumer::TempoChange(int32 beatsPerMinute
, bigtime_t time
)
307 BMidiLocalConsumer::AllNotesOff(bool justChannel
, bigtime_t time
)
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() { }
324 BMidiLocalConsumer::EventThread()
328 ssize_t buf_size
= 100;
329 uint8
* buffer
= (uint8
*) malloc(buf_size
);
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;
345 break; // error reading port
347 if (msg_size
> buf_size
) {
348 buffer
= (uint8
*) realloc(buffer
, msg_size
);
352 read_port(fPort
, &msg_code
, buffer
, msg_size
);
354 if (msg_size
> 20) { // minimum valid size
356 printf("*** received: ");
357 for (int32 t
= 0; t
< msg_size
; ++t
) {
358 printf("%02X, ", ((uint8
*) buffer
)[t
]);
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
);