1 /** 2 * @file Midi.cpp 3 * 4 * @author Matthijs Hollemans 5 * @author Jerome Leveque 6 * @author Paul Stadler 7 */ 8 9 #include <List.h> 10 11 #include "Midi.h" 12 #include "debug.h" 13 #include "MidiEvent.h" 14 15 #define DEBUG 16 17 //----------------------------------------------- 18 19 #define MSG_CODE_PROCESS_EVENT 1 20 #define MSG_CODE_TERMINATE_THREAD 0 21 22 //----------------------------------------------- 23 24 //----------------------------------------------------------------------------- 25 // Initialization Stuff 26 BMidi::BMidi() 27 { 28 fConnectionList = new BList(); 29 fIsRunning = false; 30 31 fInflowPort = create_port(1, "Inflow Port"); 32 33 fInflowTask = spawn_thread( 34 _inflow_task_, "BMidi Inflow Thread", 35 B_REAL_TIME_PRIORITY, (void *)this); 36 37 fInflowAlive = resume_thread(fInflowTask) == B_OK; 38 } 39 40 BMidi::~BMidi() 41 { 42 write_port(fInflowPort, MSG_CODE_TERMINATE_THREAD, NULL, 0); 43 44 status_t exit_value; 45 wait_for_thread(fInflowTask, &exit_value); 46 47 delete_port(fInflowPort); 48 delete fConnectionList; 49 } 50 51 //----------------------------------------------------------------------------- 52 // Stubs for midi event hooks. 53 void BMidi::NoteOff(uchar chan, uchar note, uchar vel, uint32 time) 54 { 55 } 56 void BMidi::NoteOn(uchar chan, uchar note, uchar vel, uint32 time) 57 { 58 } 59 void BMidi::KeyPressure(uchar chan, uchar note, uchar pres, uint32 time) 60 { 61 } 62 void BMidi::ControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, uint32 time) 63 { 64 } 65 void BMidi::ProgramChange(uchar chan, uchar prog_num, uint32 time) 66 { 67 } 68 void BMidi::ChannelPressure(uchar chan, uchar pres, uint32 time) 69 { 70 } 71 void BMidi::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time) 72 { 73 } 74 void BMidi::SystemExclusive(void * data, size_t data_len, uint32 time) 75 { 76 } 77 void BMidi::SystemCommon(uchar stat_byte, uchar data1, uchar data2, uint32 time) 78 { 79 } 80 void BMidi::SystemRealTime(uchar stat_byte, uint32 time) 81 { 82 } 83 void BMidi::TempoChange(int32 bpm, uint32 time) 84 { 85 } 86 void BMidi::AllNotesOff(bool just_chan, uint32 time) 87 { 88 } 89 90 //----------------------------------------------------------------------------- 91 // Public API Functions 92 status_t BMidi::Start() 93 { 94 fRunTask = spawn_thread(_run_thread_, 95 "BMidi Run Thread", B_REAL_TIME_PRIORITY, (void *)this); 96 fIsRunning = true; 97 status_t ret = resume_thread(fRunTask); 98 if(ret != B_OK) 99 { 100 fIsRunning = false; 101 } 102 return B_OK; 103 } 104 105 //----------------------------------------------------------------------------- 106 107 void BMidi::Stop() 108 { 109 status_t exit_value; 110 status_t ret; 111 fIsRunning = false; 112 ret = wait_for_thread(fRunTask, &exit_value); 113 } 114 115 bool BMidi::IsRunning() const 116 { 117 thread_info info; 118 get_thread_info(fRunTask,&info); 119 if(find_thread("BMidi Run Thread") == fRunTask) 120 return true; 121 return false; 122 } 123 124 void BMidi::Connect(BMidi *to_object) 125 { 126 fConnectionList->AddItem((void *)to_object); 127 } 128 129 void BMidi::Disconnect(BMidi *from_object) 130 { 131 fConnectionList->RemoveItem((void *)from_object); 132 } 133 134 bool BMidi::IsConnected(BMidi * to_object) const 135 { 136 return fConnectionList->HasItem((void *)to_object); 137 } 138 139 BList * BMidi::Connections() const 140 { 141 return fConnectionList; 142 } 143 144 void BMidi::SnoozeUntil(uint32 time) const 145 { 146 snooze_until((uint64)time*1000, B_SYSTEM_TIMEBASE); 147 } 148 149 bool BMidi::KeepRunning() 150 { 151 return fIsRunning; 152 } 153 154 void BMidi::Run() 155 { 156 while(KeepRunning()) 157 snooze(50000); 158 } 159 160 //----------------------------------------------------------------------------- 161 // Spray Functions 162 void BMidi::SprayMidiEvent(BMidiEvent *e) const 163 { 164 // TRACE(("Hello")) 165 int32 num_connections = fConnectionList->CountItems(); 166 BMidi *m; 167 for(int32 i = 0; i < num_connections; i++) 168 { 169 m = (BMidi *)fConnectionList->ItemAt(i); 170 write_port(m->fInflowPort, MSG_CODE_PROCESS_EVENT, e, sizeof(BMidiEvent)); 171 } 172 } 173 174 //---------------------- 175 176 void BMidi::SprayNoteOff( 177 uchar channel, uchar note, uchar velocity, uint32 time) const 178 { 179 BMidiEvent event; 180 event.time = time; 181 event.opcode = BMidiEvent::OP_NOTE_OFF; 182 event.noteOff.channel = channel; 183 event.noteOff.note = note; 184 event.noteOff.velocity = velocity; 185 SprayMidiEvent(&event); 186 } 187 188 //---------------------- 189 190 void BMidi::SprayNoteOn( 191 uchar channel, uchar note, uchar velocity, uint32 time) const 192 { 193 BMidiEvent event; 194 event.time = time; 195 event.opcode = BMidiEvent::OP_NOTE_ON; 196 event.noteOn.channel = channel; 197 event.noteOn.note = note; 198 event.noteOn.velocity = velocity; 199 SprayMidiEvent(&event); 200 } 201 202 //---------------------- 203 204 void BMidi::SprayKeyPressure( 205 uchar channel, uchar note, uchar pressure, uint32 time) const 206 { 207 BMidiEvent event; 208 event.time = time; 209 event.opcode = BMidiEvent::OP_KEY_PRESSURE; 210 event.keyPressure.channel = channel; 211 event.keyPressure.note = note; 212 event.keyPressure.pressure = pressure; 213 SprayMidiEvent(&event); 214 } 215 216 //---------------------- 217 218 void BMidi::SprayControlChange( 219 uchar channel, uchar controlNumber, uchar controlValue, 220 uint32 time) const 221 { 222 BMidiEvent event; 223 event.time = time; 224 event.opcode = BMidiEvent::OP_CONTROL_CHANGE; 225 event.controlChange.channel = channel; 226 event.controlChange.controlNumber = controlNumber; 227 event.controlChange.controlValue = controlValue; 228 SprayMidiEvent(&event); 229 } 230 231 //---------------------- 232 233 void BMidi::SprayProgramChange( 234 uchar channel, uchar programNumber, uint32 time) const 235 { 236 BMidiEvent event; 237 event.time = time; 238 event.opcode = BMidiEvent::OP_PROGRAM_CHANGE; 239 event.programChange.channel = channel; 240 event.programChange.programNumber = programNumber; 241 SprayMidiEvent(&event); 242 } 243 244 //---------------------- 245 246 void BMidi::SprayChannelPressure( 247 uchar channel, uchar pressure, uint32 time) const 248 { 249 BMidiEvent event; 250 event.time = time; 251 event.opcode = BMidiEvent::OP_CHANNEL_PRESSURE; 252 event.channelPressure.channel = channel; 253 event.channelPressure.pressure = pressure; 254 SprayMidiEvent(&event); 255 } 256 257 //---------------------- 258 259 void BMidi::SprayPitchBend( 260 uchar channel, uchar lsb, uchar msb, uint32 time) const 261 { 262 BMidiEvent event; 263 event.time = time; 264 event.opcode = BMidiEvent::OP_PITCH_BEND; 265 event.pitchBend.channel = channel; 266 event.pitchBend.lsb = lsb; 267 event.pitchBend.msb = msb; 268 SprayMidiEvent(&event); 269 } 270 271 //---------------------- 272 273 void BMidi::SpraySystemExclusive( 274 void * data, size_t dataLength, uint32 time) const 275 { 276 // Should this data be duplicated!!?? I think Yes. 277 BMidiEvent event; 278 event.time = time; 279 event.opcode = BMidiEvent::OP_SYSTEM_EXCLUSIVE; 280 event.systemExclusive.data = new uint8[dataLength]; 281 memcpy(event.systemExclusive.data, data, dataLength); 282 event.systemExclusive.dataLength = dataLength; 283 SprayMidiEvent(&event); 284 } 285 286 //---------------------- 287 288 void BMidi::SpraySystemCommon( 289 uchar status, uchar data1, uchar data2, uint32 time) const 290 { 291 BMidiEvent event; 292 event.time = time; 293 event.opcode = BMidiEvent::OP_SYSTEM_COMMON; 294 event.systemCommon.status = status; 295 event.systemCommon.data1 = data1; 296 event.systemCommon.data2 = data2; 297 SprayMidiEvent(&event); 298 } 299 300 //---------------------- 301 302 void BMidi::SpraySystemRealTime(uchar status, uint32 time) const 303 { 304 BMidiEvent event; 305 event.time = time; 306 event.opcode = BMidiEvent::OP_SYSTEM_REAL_TIME; 307 event.systemRealTime.status = status; 308 SprayMidiEvent(&event); 309 } 310 311 //---------------------- 312 313 void BMidi::SprayTempoChange(int32 beatsPerMinute, uint32 time) const 314 { 315 BMidiEvent event; 316 event.time = time; 317 event.opcode = BMidiEvent::OP_TEMPO_CHANGE; 318 event.tempoChange.beatsPerMinute = beatsPerMinute; 319 SprayMidiEvent(&event); 320 } 321 322 //----------------------------------------------------------------------------- 323 // The Inflow Thread 324 void BMidi::InflowTask() 325 { 326 BMidiEvent event; 327 int32 code; 328 size_t len; 329 while(true) 330 { 331 len = read_port(fInflowPort, &code, &event, sizeof(BMidiEvent)); 332 333 if (code == MSG_CODE_TERMINATE_THREAD) { return; } 334 335 if (len != sizeof(BMidiEvent)) { continue; } //ignore errors 336 337 switch (event.opcode) 338 { 339 case BMidiEvent::OP_NONE: 340 case BMidiEvent::OP_TRACK_END: 341 case BMidiEvent::OP_ALL_NOTES_OFF: 342 break; 343 344 case BMidiEvent::OP_NOTE_OFF: 345 NoteOff( 346 event.noteOff.channel, 347 event.noteOff.note, 348 event.noteOff.velocity, 349 event.time); 350 break; 351 352 case BMidiEvent::OP_NOTE_ON: 353 NoteOn( 354 event.noteOn.channel, 355 event.noteOn.note, 356 event.noteOn.velocity, 357 event.time); 358 break; 359 360 case BMidiEvent::OP_KEY_PRESSURE: 361 KeyPressure( 362 event.keyPressure.channel, 363 event.keyPressure.note, 364 event.keyPressure.pressure, 365 event.time); 366 break; 367 368 case BMidiEvent::OP_CONTROL_CHANGE: 369 ControlChange( 370 event.controlChange.channel, 371 event.controlChange.controlNumber, 372 event.controlChange.controlValue, 373 event.time); 374 break; 375 376 case BMidiEvent::OP_PROGRAM_CHANGE: 377 ProgramChange( 378 event.programChange.channel, 379 event.programChange.programNumber, 380 event.time); 381 break; 382 383 case BMidiEvent::OP_CHANNEL_PRESSURE: 384 ChannelPressure( 385 event.channelPressure.channel, 386 event.channelPressure.pressure, 387 event.time); 388 break; 389 390 case BMidiEvent::OP_PITCH_BEND: 391 PitchBend( 392 event.pitchBend.channel, 393 event.pitchBend.lsb, 394 event.pitchBend.msb, 395 event.time); 396 break; 397 398 case BMidiEvent::OP_SYSTEM_EXCLUSIVE: 399 SystemExclusive( 400 event.systemExclusive.data, 401 event.systemExclusive.dataLength, 402 event.time); 403 break; 404 405 case BMidiEvent::OP_SYSTEM_COMMON: 406 SystemCommon( 407 event.systemCommon.status, 408 event.systemCommon.data1, 409 event.systemCommon.data2, 410 event.time); 411 break; 412 413 case BMidiEvent::OP_SYSTEM_REAL_TIME: 414 SystemRealTime( 415 event.systemRealTime.status, 416 event.time); 417 break; 418 419 case BMidiEvent::OP_TEMPO_CHANGE: 420 TempoChange( 421 event.tempoChange.beatsPerMinute, 422 event.time); 423 break; 424 425 default: break; 426 } 427 } 428 } 429 430 //---------------------- 431 //---------------------- 432 //---------------------- 433 //---------------------- 434 //---------------------- 435 //---------------------- 436 //---------------------- 437 //---------------------- 438 439 void BMidi::_ReservedMidi1() {} 440 void BMidi::_ReservedMidi2() {} 441 void BMidi::_ReservedMidi3() {} 442 443 //---------------------- 444 445 status_t _run_thread_(void *data) 446 { 447 ((BMidi*)data)->Run(); 448 return 0; 449 } 450 451 //---------------------- 452 453 status_t _inflow_task_(void * data) 454 { 455 ((BMidi*)data)->InflowTask(); 456 return 0; 457 } 458 459 //----------------------------------------------- 460 //----------------------------------------------- 461 //----------------------------------------------- 462 //----------------------------------------------- 463 //----------------------------------------------- 464 //----------------------------------------------- 465 //----------------------------------------------- 466 //----------------------------------------------- 467 //----------------------------------------------- 468