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 20BMidiLocalProducer::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 32BMidiLocalProducer::~BMidiLocalProducer() 33{ 34 TRACE(("BMidiLocalProducer::~BMidiLocalProducer")) 35 36 BMidiRoster::MidiRoster()->DeleteLocal(this); 37} 38 39 40void 41BMidiLocalProducer::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 50void 51BMidiLocalProducer::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 60void 61BMidiLocalProducer::SprayData(void* data, size_t length, 62 bool atomic, bigtime_t time) const 63{ 64 SprayEvent(data, length, atomic, time); 65} 66 67 68void 69BMidiLocalProducer::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 85void 86BMidiLocalProducer::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 102void 103BMidiLocalProducer::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 119void 120BMidiLocalProducer::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 136void 137BMidiLocalProducer::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 152void 153BMidiLocalProducer::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 168void 169BMidiLocalProducer::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 185void 186BMidiLocalProducer::SpraySystemExclusive(void* data, 187 size_t length, bigtime_t time) const 188{ 189 SprayEvent(data, length, true, time, true); 190} 191 192 193void 194BMidiLocalProducer::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 228void 229BMidiLocalProducer::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 239void 240BMidiLocalProducer::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 258void BMidiLocalProducer::_Reserved1() { } 259void BMidiLocalProducer::_Reserved2() { } 260void BMidiLocalProducer::_Reserved3() { } 261void BMidiLocalProducer::_Reserved4() { } 262void BMidiLocalProducer::_Reserved5() { } 263void BMidiLocalProducer::_Reserved6() { } 264void BMidiLocalProducer::_Reserved7() { } 265void BMidiLocalProducer::_Reserved8() { } 266 267//------------------------------------------------------------------------------ 268 269void 270BMidiLocalProducer::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