1 /* 2 * Copyright (c) 2002-2003 Matthijs Hollemans 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <stdlib.h> 24 25 #include "debug.h" 26 #include "MidiConsumer.h" 27 #include "MidiProducer.h" 28 #include "MidiRoster.h" 29 #include "protocol.h" 30 31 //------------------------------------------------------------------------------ 32 33 BMidiLocalProducer::BMidiLocalProducer(const char* name) 34 : BMidiProducer(name) 35 { 36 TRACE(("BMidiLocalProducer::BMidiLocalProducer")) 37 38 isLocal = true; 39 refCount = 1; 40 41 BMidiRoster::MidiRoster()->CreateLocal(this); 42 } 43 44 //------------------------------------------------------------------------------ 45 46 BMidiLocalProducer::~BMidiLocalProducer() 47 { 48 TRACE(("BMidiLocalProducer::~BMidiLocalProducer")) 49 50 BMidiRoster::MidiRoster()->DeleteLocal(this); 51 } 52 53 //------------------------------------------------------------------------------ 54 55 void BMidiLocalProducer::Connected(BMidiConsumer* cons) 56 { 57 ASSERT(cons != NULL) 58 TRACE(("Connected() %ld to %ld", ID(), cons->ID())) 59 60 // Do nothing. 61 } 62 63 //------------------------------------------------------------------------------ 64 65 void BMidiLocalProducer::Disconnected(BMidiConsumer* cons) 66 { 67 ASSERT(cons != NULL) 68 TRACE(("Disconnected() %ld from %ld", ID(), cons->ID())) 69 70 // Do nothing. 71 } 72 73 //------------------------------------------------------------------------------ 74 75 void BMidiLocalProducer::SprayData( 76 void* data, size_t length, bool atomic, bigtime_t time) const 77 { 78 SprayEvent(data, length, atomic, time); 79 } 80 81 //------------------------------------------------------------------------------ 82 83 void BMidiLocalProducer::SprayNoteOff( 84 uchar channel, uchar note, uchar velocity, bigtime_t time) const 85 { 86 if (channel < 16) 87 { 88 uchar data[3]; 89 data[0] = B_NOTE_OFF + channel; 90 data[1] = note; 91 data[2] = velocity; 92 93 SprayEvent(&data, 3, true, time); 94 } 95 else 96 { 97 debugger("invalid MIDI channel"); 98 } 99 } 100 101 //------------------------------------------------------------------------------ 102 103 void BMidiLocalProducer::SprayNoteOn( 104 uchar channel, uchar note, uchar velocity, bigtime_t time) const 105 { 106 if (channel < 16) 107 { 108 uchar data[3]; 109 data[0] = B_NOTE_ON + channel; 110 data[1] = note; 111 data[2] = velocity; 112 113 SprayEvent(&data, 3, true, time); 114 } 115 else 116 { 117 debugger("invalid MIDI channel"); 118 } 119 } 120 121 //------------------------------------------------------------------------------ 122 123 void BMidiLocalProducer::SprayKeyPressure( 124 uchar channel, uchar note, uchar pressure, bigtime_t time) const 125 { 126 if (channel < 16) 127 { 128 uchar data[3]; 129 data[0] = B_KEY_PRESSURE + channel; 130 data[1] = note; 131 data[2] = pressure; 132 133 SprayEvent(&data, 3, true, time); 134 } 135 else 136 { 137 debugger("invalid MIDI channel"); 138 } 139 } 140 141 //------------------------------------------------------------------------------ 142 143 void BMidiLocalProducer::SprayControlChange( 144 uchar channel, uchar controlNumber, uchar controlValue, 145 bigtime_t time) const 146 { 147 if (channel < 16) 148 { 149 uchar data[3]; 150 data[0] = B_CONTROL_CHANGE + channel; 151 data[1] = controlNumber; 152 data[2] = controlValue; 153 154 SprayEvent(&data, 3, true, time); 155 } 156 else 157 { 158 debugger("invalid MIDI channel"); 159 } 160 } 161 162 //------------------------------------------------------------------------------ 163 164 void BMidiLocalProducer::SprayProgramChange( 165 uchar channel, uchar programNumber, bigtime_t time) const 166 { 167 if (channel < 16) 168 { 169 uchar data[2]; 170 data[0] = B_PROGRAM_CHANGE + channel; 171 data[1] = programNumber; 172 173 SprayEvent(&data, 2, true, time); 174 } 175 else 176 { 177 debugger("invalid MIDI channel"); 178 } 179 } 180 181 //------------------------------------------------------------------------------ 182 183 void BMidiLocalProducer::SprayChannelPressure( 184 uchar channel, uchar pressure, bigtime_t time) const 185 { 186 if (channel < 16) 187 { 188 uchar data[2]; 189 data[0] = B_CHANNEL_PRESSURE + channel; 190 data[1] = pressure; 191 192 SprayEvent(&data, 2, true, time); 193 } 194 else 195 { 196 debugger("invalid MIDI channel"); 197 } 198 } 199 200 //------------------------------------------------------------------------------ 201 202 void BMidiLocalProducer::SprayPitchBend( 203 uchar channel, uchar lsb, uchar msb, bigtime_t time) const 204 { 205 if (channel < 16) 206 { 207 uchar data[3]; 208 data[0] = B_PITCH_BEND + channel; 209 data[1] = lsb; 210 data[2] = msb; 211 212 SprayEvent(&data, 3, true, time); 213 } 214 else 215 { 216 debugger("invalid MIDI channel"); 217 } 218 } 219 220 //------------------------------------------------------------------------------ 221 222 void BMidiLocalProducer::SpraySystemExclusive( 223 void* data, size_t length, bigtime_t time) const 224 { 225 SprayEvent(data, length, true, time, true); 226 } 227 228 //------------------------------------------------------------------------------ 229 230 void BMidiLocalProducer::SpraySystemCommon( 231 uchar status, uchar data1, uchar data2, bigtime_t time) const 232 { 233 size_t len; 234 uchar data[3]; 235 data[0] = status; 236 data[1] = data1; 237 data[2] = data2; 238 239 switch (status) 240 { 241 case B_TUNE_REQUEST: 242 case B_SYS_EX_END: 243 len = 1; break; 244 245 case B_CABLE_MESSAGE: 246 case B_MIDI_TIME_CODE: 247 case B_SONG_SELECT: 248 len = 2; break; 249 250 case B_SONG_POSITION: 251 len = 3; break; 252 253 default: 254 debugger("invalid system common status"); 255 } 256 257 SprayEvent(&data, len, true, time); 258 } 259 260 //------------------------------------------------------------------------------ 261 262 void BMidiLocalProducer::SpraySystemRealTime( 263 uchar status, bigtime_t time) const 264 { 265 if (status >= B_TIMING_CLOCK) 266 { 267 SprayEvent(&status, 1, true, time); 268 } 269 else 270 { 271 debugger("invalid real time status"); 272 } 273 } 274 275 //------------------------------------------------------------------------------ 276 277 void BMidiLocalProducer::SprayTempoChange( 278 int32 beatsPerMinute, bigtime_t time) const 279 { 280 int32 tempo = 60000000 / beatsPerMinute; 281 282 uchar data[6]; 283 data[0] = 0xFF; 284 data[1] = 0x51; 285 data[2] = 0x03; 286 data[3] = tempo >> 16; 287 data[4] = tempo >> 8; 288 data[5] = tempo; 289 290 SprayEvent(&data, 6, true, time); 291 } 292 293 //------------------------------------------------------------------------------ 294 295 void BMidiLocalProducer::_Reserved1() { } 296 void BMidiLocalProducer::_Reserved2() { } 297 void BMidiLocalProducer::_Reserved3() { } 298 void BMidiLocalProducer::_Reserved4() { } 299 void BMidiLocalProducer::_Reserved5() { } 300 void BMidiLocalProducer::_Reserved6() { } 301 void BMidiLocalProducer::_Reserved7() { } 302 void BMidiLocalProducer::_Reserved8() { } 303 304 //------------------------------------------------------------------------------ 305 306 void BMidiLocalProducer::SprayEvent( 307 const void* data, size_t length, bool atomic, bigtime_t time, 308 bool sysex) const 309 { 310 if (LockProducer()) 311 { 312 if (CountConsumers() > 0) 313 { 314 // We don't just send the MIDI event data to all connected 315 // consumers, we also send a header. The header contains our 316 // ID (4 bytes), the consumer's ID (4 bytes), the performance 317 // time (8 bytes), whether the data is atomic (1 byte), and 318 // padding (3 bytes). The MIDI event data follows the header. 319 320 size_t buf_size = 20 + length; 321 if (sysex) { buf_size += 2; } // add 0xF0 and 0xF7 markers 322 323 uint8* buffer = (uint8*) malloc(buf_size); 324 if (buffer != NULL) 325 { 326 *((uint32*) (buffer + 0)) = id; 327 *((bigtime_t*) (buffer + 8)) = time; 328 *((uint32*) (buffer + 16)) = 0; 329 *((bool*) (buffer + 16)) = atomic; 330 331 if (sysex) 332 { 333 *((uint8*) (buffer + 20)) = B_SYS_EX_START; 334 if (data != NULL) 335 { 336 memcpy(buffer + 21, data, length); 337 } 338 *((uint8*) (buffer + buf_size - 1)) = B_SYS_EX_END; 339 } 340 else if (data != NULL) 341 { 342 memcpy(buffer + 20, data, length); 343 } 344 345 for (int32 t = 0; t < CountConsumers(); ++t) 346 { 347 BMidiConsumer* cons = ConsumerAt(t); 348 *((uint32*) (buffer + 4)) = cons->id; 349 350 #ifdef DEBUG 351 printf("*** spraying: "); 352 for (int32 t = 0; t < buf_size; ++t) 353 { 354 printf("%02X, ", buffer[t]); 355 } 356 printf("\n"); 357 #endif 358 359 write_port(cons->port, 0, buffer, buf_size); 360 } 361 362 free(buffer); 363 } 364 } 365 366 UnlockProducer(); 367 } 368 } 369 370 //------------------------------------------------------------------------------ 371