headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / midi2 / MidiLocalProducer.cpp
blob22f0af630060269ed01471c4efb034ff852bee9d
1 /*
2 * Copyright 2005-2006, Haiku.
3 *
4 * Copyright (c) 2002-2004 Matthijs Hollemans
5 * Distributed under the terms of the MIT License.
7 * Authors:
8 * Matthijs Hollemans
9 */
11 #include <stdlib.h>
13 #include "debug.h"
14 #include <MidiConsumer.h>
15 #include <MidiProducer.h>
16 #include <MidiRoster.h>
17 #include "protocol.h"
20 BMidiLocalProducer::BMidiLocalProducer(const char* name)
21 : BMidiProducer(name)
23 TRACE(("BMidiLocalProducer::BMidiLocalProducer"))
25 fIsLocal = true;
26 fRefCount = 1;
28 BMidiRoster::MidiRoster()->CreateLocal(this);
32 BMidiLocalProducer::~BMidiLocalProducer()
34 TRACE(("BMidiLocalProducer::~BMidiLocalProducer"))
36 BMidiRoster::MidiRoster()->DeleteLocal(this);
40 void
41 BMidiLocalProducer::Connected(BMidiConsumer* cons)
43 ASSERT(cons != NULL)
44 TRACE(("Connected() %" B_PRId32 " to %" B_PRId32 "", ID(), cons->ID()))
46 // Do nothing.
50 void
51 BMidiLocalProducer::Disconnected(BMidiConsumer* cons)
53 ASSERT(cons != NULL)
54 TRACE(("Disconnected() %" B_PRId32 " from %" B_PRId32 "", ID(), cons->ID()))
56 // Do nothing.
60 void
61 BMidiLocalProducer::SprayData(void* data, size_t length,
62 bool atomic, bigtime_t time) const
64 SprayEvent(data, length, atomic, time);
68 void
69 BMidiLocalProducer::SprayNoteOff(uchar channel, uchar note,
70 uchar velocity, bigtime_t time) const
72 if (channel < 16) {
73 uchar data[3];
74 data[0] = B_NOTE_OFF + channel;
75 data[1] = note;
76 data[2] = velocity;
78 SprayEvent(&data, 3, true, time);
79 } else {
80 debugger("invalid MIDI channel");
85 void
86 BMidiLocalProducer::SprayNoteOn(uchar channel, uchar note,
87 uchar velocity, bigtime_t time) const
89 if (channel < 16) {
90 uchar data[3];
91 data[0] = B_NOTE_ON + channel;
92 data[1] = note;
93 data[2] = velocity;
95 SprayEvent(&data, 3, true, time);
96 } else {
97 debugger("invalid MIDI channel");
102 void
103 BMidiLocalProducer::SprayKeyPressure(uchar channel, uchar note,
104 uchar pressure, bigtime_t time) const
106 if (channel < 16) {
107 uchar data[3];
108 data[0] = B_KEY_PRESSURE + channel;
109 data[1] = note;
110 data[2] = pressure;
112 SprayEvent(&data, 3, true, time);
113 } else {
114 debugger("invalid MIDI channel");
119 void
120 BMidiLocalProducer::SprayControlChange(uchar channel,
121 uchar controlNumber, uchar controlValue, bigtime_t time) const
123 if (channel < 16) {
124 uchar data[3];
125 data[0] = B_CONTROL_CHANGE + channel;
126 data[1] = controlNumber;
127 data[2] = controlValue;
129 SprayEvent(&data, 3, true, time);
130 } else {
131 debugger("invalid MIDI channel");
136 void
137 BMidiLocalProducer::SprayProgramChange(uchar channel,
138 uchar programNumber, bigtime_t time) const
140 if (channel < 16) {
141 uchar data[2];
142 data[0] = B_PROGRAM_CHANGE + channel;
143 data[1] = programNumber;
145 SprayEvent(&data, 2, true, time);
146 } else {
147 debugger("invalid MIDI channel");
152 void
153 BMidiLocalProducer::SprayChannelPressure(uchar channel,
154 uchar pressure, bigtime_t time) const
156 if (channel < 16) {
157 uchar data[2];
158 data[0] = B_CHANNEL_PRESSURE + channel;
159 data[1] = pressure;
161 SprayEvent(&data, 2, true, time);
162 } else {
163 debugger("invalid MIDI channel");
168 void
169 BMidiLocalProducer::SprayPitchBend(uchar channel,
170 uchar lsb, uchar msb, bigtime_t time) const
172 if (channel < 16) {
173 uchar data[3];
174 data[0] = B_PITCH_BEND + channel;
175 data[1] = lsb;
176 data[2] = msb;
178 SprayEvent(&data, 3, true, time);
179 } else {
180 debugger("invalid MIDI channel");
185 void
186 BMidiLocalProducer::SpraySystemExclusive(void* data,
187 size_t length, bigtime_t time) const
189 SprayEvent(data, length, true, time, true);
193 void
194 BMidiLocalProducer::SpraySystemCommon(uchar status, uchar data1,
195 uchar data2, bigtime_t time) const
197 size_t len;
198 uchar data[3];
199 data[0] = status;
200 data[1] = data1;
201 data[2] = data2;
203 switch (status) {
204 case B_TUNE_REQUEST:
205 case B_SYS_EX_END:
206 len = 1;
207 break;
209 case B_CABLE_MESSAGE:
210 case B_MIDI_TIME_CODE:
211 case B_SONG_SELECT:
212 len = 2;
213 break;
215 case B_SONG_POSITION:
216 len = 3;
217 break;
219 default:
220 debugger("invalid system common status");
221 len = 0;
224 SprayEvent(&data, len, true, time);
228 void
229 BMidiLocalProducer::SpraySystemRealTime(uchar status,
230 bigtime_t time) const
232 if (status >= B_TIMING_CLOCK)
233 SprayEvent(&status, 1, true, time);
234 else
235 debugger("invalid real time status");
239 void
240 BMidiLocalProducer::SprayTempoChange(int32 beatsPerMinute,
241 bigtime_t time) const
243 int32 tempo = 60000000 / beatsPerMinute;
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;
253 SprayEvent(&data, 6, true, time);
256 //------------------------------------------------------------------------------
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() { }
267 //------------------------------------------------------------------------------
269 void
270 BMidiLocalProducer::SprayEvent(const void* data, size_t length,
271 bool atomic, bigtime_t time, bool sysex) const
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.
281 size_t buf_size = 20 + length;
282 if (sysex) {
283 // add 0xF0 and 0xF7 markers
284 buf_size += 2;
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;
294 if (sysex) {
295 *((uint8*) (buffer + 20)) = B_SYS_EX_START;
296 if (data != NULL)
297 memcpy(buffer + 21, data, length);
299 *((uint8*) (buffer + buf_size - 1)) = B_SYS_EX_END;
300 } else if (data != NULL) {
301 memcpy(buffer + 20, data, length);
304 for (int32 t = 0; t < CountConsumers(); ++t) {
305 BMidiConsumer* cons = ConsumerAt(t);
306 *((uint32*) (buffer + 4)) = cons->fId;
308 #ifdef DEBUG
309 printf("*** spraying: ");
310 for (uint32 t = 0; t < buf_size; ++t)
312 printf("%02X, ", buffer[t]);
314 printf("\n");
315 #endif
317 write_port(cons->fPort, 0, buffer, buf_size);
320 free(buffer);
324 UnlockProducer();