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