1 /* 2 * Copyright 2005-2006, Haiku. 3 * 4 * Copyright (c) 2002-2004 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 <MidiProducer.h> 16 #include <MidiRoster.h> 17 #include "protocol.h" 18 19 20 BMidiLocalProducer::BMidiLocalProducer(const char* name) 21 : BMidiProducer(name) 22 { 23 TRACE(("BMidiLocalProducer::BMidiLocalProducer")) 24 25 fIsLocal = true; 26 fRefCount = 1; 27 28 BMidiRoster::MidiRoster()->CreateLocal(this); 29 } 30 31 32 BMidiLocalProducer::~BMidiLocalProducer() 33 { 34 TRACE(("BMidiLocalProducer::~BMidiLocalProducer")) 35 36 BMidiRoster::MidiRoster()->DeleteLocal(this); 37 } 38 39 40 void 41 BMidiLocalProducer::Connected(BMidiConsumer* cons) 42 { 43 ASSERT(cons != NULL) 44 TRACE(("Connected() %" B_PRId32 " to %" B_PRId32 "", ID(), cons->ID())) 45 46 // Do nothing. 47 } 48 49 50 void 51 BMidiLocalProducer::Disconnected(BMidiConsumer* cons) 52 { 53 ASSERT(cons != NULL) 54 TRACE(("Disconnected() %" B_PRId32 " from %" B_PRId32 "", ID(), cons->ID())) 55 56 // Do nothing. 57 } 58 59 60 void 61 BMidiLocalProducer::SprayData(void* data, size_t length, 62 bool atomic, bigtime_t time) const 63 { 64 SprayEvent(data, length, atomic, time); 65 } 66 67 68 void 69 BMidiLocalProducer::SprayNoteOff(uchar channel, uchar note, 70 uchar velocity, bigtime_t time) const 71 { 72 if (channel < 16) { 73 uchar data[3]; 74 data[0] = B_NOTE_OFF + channel; 75 data[1] = note; 76 data[2] = velocity; 77 78 SprayEvent(&data, 3, true, time); 79 } else { 80 debugger("invalid MIDI channel"); 81 } 82 } 83 84 85 void 86 BMidiLocalProducer::SprayNoteOn(uchar channel, uchar note, 87 uchar velocity, bigtime_t time) const 88 { 89 if (channel < 16) { 90 uchar data[3]; 91 data[0] = B_NOTE_ON + channel; 92 data[1] = note; 93 data[2] = velocity; 94 95 SprayEvent(&data, 3, true, time); 96 } else { 97 debugger("invalid MIDI channel"); 98 } 99 } 100 101 102 void 103 BMidiLocalProducer::SprayKeyPressure(uchar channel, uchar note, 104 uchar pressure, bigtime_t time) const 105 { 106 if (channel < 16) { 107 uchar data[3]; 108 data[0] = B_KEY_PRESSURE + channel; 109 data[1] = note; 110 data[2] = pressure; 111 112 SprayEvent(&data, 3, true, time); 113 } else { 114 debugger("invalid MIDI channel"); 115 } 116 } 117 118 119 void 120 BMidiLocalProducer::SprayControlChange(uchar channel, 121 uchar controlNumber, uchar controlValue, bigtime_t time) const 122 { 123 if (channel < 16) { 124 uchar data[3]; 125 data[0] = B_CONTROL_CHANGE + channel; 126 data[1] = controlNumber; 127 data[2] = controlValue; 128 129 SprayEvent(&data, 3, true, time); 130 } else { 131 debugger("invalid MIDI channel"); 132 } 133 } 134 135 136 void 137 BMidiLocalProducer::SprayProgramChange(uchar channel, 138 uchar programNumber, bigtime_t time) const 139 { 140 if (channel < 16) { 141 uchar data[2]; 142 data[0] = B_PROGRAM_CHANGE + channel; 143 data[1] = programNumber; 144 145 SprayEvent(&data, 2, true, time); 146 } else { 147 debugger("invalid MIDI channel"); 148 } 149 } 150 151 152 void 153 BMidiLocalProducer::SprayChannelPressure(uchar channel, 154 uchar pressure, bigtime_t time) const 155 { 156 if (channel < 16) { 157 uchar data[2]; 158 data[0] = B_CHANNEL_PRESSURE + channel; 159 data[1] = pressure; 160 161 SprayEvent(&data, 2, true, time); 162 } else { 163 debugger("invalid MIDI channel"); 164 } 165 } 166 167 168 void 169 BMidiLocalProducer::SprayPitchBend(uchar channel, 170 uchar lsb, uchar msb, bigtime_t time) const 171 { 172 if (channel < 16) { 173 uchar data[3]; 174 data[0] = B_PITCH_BEND + channel; 175 data[1] = lsb; 176 data[2] = msb; 177 178 SprayEvent(&data, 3, true, time); 179 } else { 180 debugger("invalid MIDI channel"); 181 } 182 } 183 184 185 void 186 BMidiLocalProducer::SpraySystemExclusive(void* data, 187 size_t length, bigtime_t time) const 188 { 189 SprayEvent(data, length, true, time, true); 190 } 191 192 193 void 194 BMidiLocalProducer::SpraySystemCommon(uchar status, uchar data1, 195 uchar data2, bigtime_t time) const 196 { 197 size_t len; 198 uchar data[3]; 199 data[0] = status; 200 data[1] = data1; 201 data[2] = data2; 202 203 switch (status) { 204 case B_TUNE_REQUEST: 205 case B_SYS_EX_END: 206 len = 1; 207 break; 208 209 case B_CABLE_MESSAGE: 210 case B_MIDI_TIME_CODE: 211 case B_SONG_SELECT: 212 len = 2; 213 break; 214 215 case B_SONG_POSITION: 216 len = 3; 217 break; 218 219 default: 220 debugger("invalid system common status"); 221 len = 0; 222 } 223 224 SprayEvent(&data, len, true, time); 225 } 226 227 228 void 229 BMidiLocalProducer::SpraySystemRealTime(uchar status, 230 bigtime_t time) const 231 { 232 if (status >= B_TIMING_CLOCK) 233 SprayEvent(&status, 1, true, time); 234 else 235 debugger("invalid real time status"); 236 } 237 238 239 void 240 BMidiLocalProducer::SprayTempoChange(int32 beatsPerMinute, 241 bigtime_t time) const 242 { 243 int32 tempo = 60000000 / beatsPerMinute; 244 245 uchar data[6]; 246 data[0] = 0xFF; 247 data[1] = 0x51; 248 data[2] = 0x03; 249 data[3] = tempo >> 16; 250 data[4] = tempo >> 8; 251 data[5] = tempo; 252 253 SprayEvent(&data, 6, true, time); 254 } 255 256 //------------------------------------------------------------------------------ 257 258 void BMidiLocalProducer::_Reserved1() { } 259 void BMidiLocalProducer::_Reserved2() { } 260 void BMidiLocalProducer::_Reserved3() { } 261 void BMidiLocalProducer::_Reserved4() { } 262 void BMidiLocalProducer::_Reserved5() { } 263 void BMidiLocalProducer::_Reserved6() { } 264 void BMidiLocalProducer::_Reserved7() { } 265 void BMidiLocalProducer::_Reserved8() { } 266 267 //------------------------------------------------------------------------------ 268 269 void 270 BMidiLocalProducer::SprayEvent(const void* data, size_t length, 271 bool atomic, bigtime_t time, bool sysex) const 272 { 273 if (LockProducer()) { 274 if (CountConsumers() > 0) { 275 // We don't just send the MIDI event data to all connected 276 // consumers, we also send a header. The header contains our 277 // ID (4 bytes), the consumer's ID (4 bytes), the performance 278 // time (8 bytes), whether the data is atomic (1 byte), and 279 // padding (3 bytes). The MIDI event data follows the header. 280 281 size_t buf_size = 20 + length; 282 if (sysex) { 283 // add 0xF0 and 0xF7 markers 284 buf_size += 2; 285 } 286 287 uint8* buffer = (uint8*)malloc(buf_size); 288 if (buffer != NULL) { 289 *((uint32*) (buffer + 0)) = fId; 290 *((bigtime_t*) (buffer + 8)) = time; 291 *((uint32*) (buffer + 16)) = 0; 292 *((bool*) (buffer + 16)) = atomic; 293 294 if (sysex) { 295 *((uint8*) (buffer + 20)) = B_SYS_EX_START; 296 if (data != NULL) 297 memcpy(buffer + 21, data, length); 298 299 *((uint8*) (buffer + buf_size - 1)) = B_SYS_EX_END; 300 } else if (data != NULL) { 301 memcpy(buffer + 20, data, length); 302 } 303 304 for (int32 t = 0; t < CountConsumers(); ++t) { 305 BMidiConsumer* cons = ConsumerAt(t); 306 *((uint32*) (buffer + 4)) = cons->fId; 307 308 #ifdef DEBUG 309 printf("*** spraying: "); 310 for (uint32 t = 0; t < buf_size; ++t) 311 { 312 printf("%02X, ", buffer[t]); 313 } 314 printf("\n"); 315 #endif 316 317 write_port(cons->fPort, 0, buffer, buf_size); 318 } 319 320 free(buffer); 321 } 322 } 323 324 UnlockProducer(); 325 } 326 } 327 328