1 /* 2 * Copyright 2006, Haiku. 3 * 4 * Copyright (c) 2002-2003 Matthijs Hollemans 5 * Distributed under the terms of the MIT License. 6 * 7 * Authors: 8 * Matthijs Hollemans 9 */ 10 11 #include <stdlib.h> 12 13 #include "debug.h" 14 #include <MidiConsumer.h> 15 #include <MidiRoster.h> 16 #include "protocol.h" 17 18 19 int32 20 _midi_event_thread(void* data) 21 { 22 return ((BMidiLocalConsumer*) data)->EventThread(); 23 } 24 25 26 BMidiLocalConsumer::BMidiLocalConsumer(const char* name) 27 : BMidiConsumer(name) 28 { 29 TRACE(("BMidiLocalConsumer::BMidiLocalConsumer")) 30 31 fIsLocal = true; 32 fRefCount = 1; 33 fTimeout = (bigtime_t) -1; 34 fTimeoutData = NULL; 35 36 fPort = create_port(1, "MidiEventPort"); 37 fThread = spawn_thread( 38 _midi_event_thread, "MidiEventThread", B_REAL_TIME_PRIORITY, this); 39 resume_thread(fThread); 40 41 BMidiRoster::MidiRoster()->CreateLocal(this); 42 } 43 44 45 BMidiLocalConsumer::~BMidiLocalConsumer() 46 { 47 TRACE(("BMidiLocalConsumer::~BMidiLocalConsumer")) 48 49 BMidiRoster::MidiRoster()->DeleteLocal(this); 50 51 delete_port(fPort); 52 53 status_t result; 54 wait_for_thread(fThread, &result); 55 } 56 57 58 void 59 BMidiLocalConsumer::SetLatency(bigtime_t latency_) 60 { 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_); 69 70 if (SendChangeRequest(&msg) == B_OK) { 71 if (LockLooper()) { 72 fLatency = latency_; 73 UnlockLooper(); 74 } 75 } 76 } 77 } 78 79 80 int32 81 BMidiLocalConsumer::GetProducerID() 82 { 83 return fCurrentProducer; 84 } 85 86 87 void 88 BMidiLocalConsumer::SetTimeout(bigtime_t when, void* data) 89 { 90 fTimeout = when; 91 fTimeoutData = data; 92 } 93 94 95 void 96 BMidiLocalConsumer::Timeout(void* data) 97 { 98 // Do nothing. 99 } 100 101 102 void 103 BMidiLocalConsumer::Data(uchar* data, size_t length, bool atomic, bigtime_t time) 104 { 105 if (atomic) { 106 switch (data[0] & 0xF0) { 107 case B_NOTE_OFF: 108 { 109 if (length == 3) 110 NoteOff(data[0] & 0x0F, data[1], data[2], time); 111 break; 112 } 113 114 case B_NOTE_ON: 115 { 116 if (length == 3) 117 NoteOn(data[0] & 0x0F, data[1], data[2], time); 118 break; 119 } 120 121 case B_KEY_PRESSURE: 122 { 123 if (length == 3) 124 KeyPressure(data[0] & 0x0F, data[1], data[2], time); 125 break; 126 } 127 128 case B_CONTROL_CHANGE: 129 { 130 if (length == 3) 131 ControlChange(data[0] & 0x0F, data[1], data[2], time); 132 break; 133 } 134 135 case B_PROGRAM_CHANGE: 136 { 137 if (length == 2) 138 ProgramChange(data[0] & 0x0F, data[1], time); 139 break; 140 } 141 142 case B_CHANNEL_PRESSURE: 143 { 144 if (length == 2) 145 ChannelPressure(data[0] & 0x0F, data[1], time); 146 break; 147 } 148 149 case B_PITCH_BEND: 150 { 151 if (length == 3) 152 PitchBend(data[0] & 0x0F, data[1], data[2], time); 153 break; 154 } 155 156 case 0xF0: 157 { 158 switch (data[0]) { 159 case B_SYS_EX_START: 160 { 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); 165 } 166 break; 167 } 168 169 case B_TUNE_REQUEST: 170 case B_SYS_EX_END: 171 { 172 if (length == 1) { 173 SystemCommon(data[0], 0, 0, time); 174 } 175 break; 176 } 177 178 case B_CABLE_MESSAGE: 179 case B_MIDI_TIME_CODE: 180 case B_SONG_SELECT: 181 { 182 if (length == 2) { 183 SystemCommon(data[0], data[1], 0, time); 184 } 185 break; 186 } 187 188 case B_SONG_POSITION: 189 { 190 if (length == 3) { 191 SystemCommon(data[0], data[1], data[2], time); 192 } 193 break; 194 } 195 196 case B_TIMING_CLOCK: 197 case B_START: 198 case B_CONTINUE: 199 case B_STOP: 200 case B_ACTIVE_SENSING: 201 { 202 if (length == 1) { 203 SystemRealTime(data[0], time); 204 } 205 break; 206 } 207 208 case B_SYSTEM_RESET: 209 { 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]; 216 217 TempoChange(60000000/tempo, time); 218 } 219 } 220 } 221 break; 222 } 223 } 224 } 225 } 226 227 228 void 229 BMidiLocalConsumer::NoteOff(uchar channel, uchar note, uchar velocity, bigtime_t time) 230 { 231 // Do nothing. 232 } 233 234 235 void 236 BMidiLocalConsumer::NoteOn(uchar channel, uchar note, uchar velocity, bigtime_t time) 237 { 238 // Do nothing. 239 } 240 241 242 void 243 BMidiLocalConsumer::KeyPressure(uchar channel, uchar note, uchar pressure, bigtime_t time) 244 { 245 // Do nothing. 246 } 247 248 249 void 250 BMidiLocalConsumer::ControlChange(uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time) 251 { 252 // Do nothing. 253 } 254 255 256 void 257 BMidiLocalConsumer::ProgramChange(uchar channel, uchar programNumber, bigtime_t time) 258 { 259 // Do nothing. 260 } 261 262 263 void BMidiLocalConsumer::ChannelPressure(uchar channel, uchar pressure, bigtime_t time) 264 { 265 // Do nothing. 266 } 267 268 269 void 270 BMidiLocalConsumer::PitchBend(uchar channel, uchar lsb, uchar msb, bigtime_t time) 271 { 272 // Do nothing. 273 } 274 275 276 void 277 BMidiLocalConsumer::SystemExclusive( 278 void* data, size_t length, bigtime_t time) 279 { 280 // Do nothing. 281 } 282 283 284 void 285 BMidiLocalConsumer::SystemCommon( 286 uchar statusByte, uchar data1, uchar data2, bigtime_t time) 287 { 288 // Do nothing. 289 } 290 291 292 void 293 BMidiLocalConsumer::SystemRealTime(uchar statusByte, bigtime_t time) 294 { 295 // Do nothing. 296 } 297 298 299 void 300 BMidiLocalConsumer::TempoChange(int32 beatsPerMinute, bigtime_t time) 301 { 302 // Do nothing. 303 } 304 305 306 void 307 BMidiLocalConsumer::AllNotesOff(bool justChannel, bigtime_t time) 308 { 309 // Do nothing. 310 } 311 312 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() { } 321 322 323 int32 324 BMidiLocalConsumer::EventThread() 325 { 326 int32 msg_code; 327 ssize_t msg_size; 328 ssize_t buf_size = 100; 329 uint8* buffer = (uint8*) malloc(buf_size); 330 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; 341 } 342 } 343 344 if (msg_size < 0) 345 break; // error reading port 346 347 if (msg_size > buf_size) { 348 uint8* tmp_buffer = (uint8*) realloc(buffer, msg_size); 349 if (tmp_buffer == NULL) 350 break; // error in realloc() 351 buffer = tmp_buffer; 352 buf_size = msg_size; 353 } 354 355 read_port(fPort, &msg_code, buffer, msg_size); 356 357 if (msg_size > 20) { // minimum valid size 358 #ifdef DEBUG 359 printf("*** received: "); 360 for (int32 t = 0; t < msg_size; ++t) { 361 printf("%02X, ", ((uint8*) buffer)[t]); 362 } 363 printf("\n"); 364 #endif 365 366 fCurrentProducer = *((uint32*) (buffer + 0)); 367 int32 targetId = *((uint32*) (buffer + 4)); 368 bigtime_t time = *((bigtime_t*) (buffer + 8)); 369 bool atomic = *((bool*) (buffer + 16)); 370 371 if (targetId == fId) { // only if we are the destination 372 Data((uchar*) (buffer + 20), msg_size - 20, atomic, time); 373 } 374 } 375 } 376 377 free(buffer); 378 return 0; 379 } 380 381