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
BMidiLocalProducer(const char * name)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
~BMidiLocalProducer()32 BMidiLocalProducer::~BMidiLocalProducer()
33 {
34 TRACE(("BMidiLocalProducer::~BMidiLocalProducer"))
35
36 BMidiRoster::MidiRoster()->DeleteLocal(this);
37 }
38
39
40 void
Connected(BMidiConsumer * cons)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
Disconnected(BMidiConsumer * cons)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
SprayData(void * data,size_t length,bool atomic,bigtime_t time) const61 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
SprayNoteOff(uchar channel,uchar note,uchar velocity,bigtime_t time) const69 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
SprayNoteOn(uchar channel,uchar note,uchar velocity,bigtime_t time) const86 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
SprayKeyPressure(uchar channel,uchar note,uchar pressure,bigtime_t time) const103 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
SprayControlChange(uchar channel,uchar controlNumber,uchar controlValue,bigtime_t time) const120 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
SprayProgramChange(uchar channel,uchar programNumber,bigtime_t time) const137 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
SprayChannelPressure(uchar channel,uchar pressure,bigtime_t time) const153 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
SprayPitchBend(uchar channel,uchar lsb,uchar msb,bigtime_t time) const169 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
SpraySystemExclusive(void * data,size_t length,bigtime_t time) const186 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
SpraySystemCommon(uchar status,uchar data1,uchar data2,bigtime_t time) const194 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
SpraySystemRealTime(uchar status,bigtime_t time) const229 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
SprayTempoChange(int32 beatsPerMinute,bigtime_t time) const240 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
_Reserved1()258 void BMidiLocalProducer::_Reserved1() { }
_Reserved2()259 void BMidiLocalProducer::_Reserved2() { }
_Reserved3()260 void BMidiLocalProducer::_Reserved3() { }
_Reserved4()261 void BMidiLocalProducer::_Reserved4() { }
_Reserved5()262 void BMidiLocalProducer::_Reserved5() { }
_Reserved6()263 void BMidiLocalProducer::_Reserved6() { }
_Reserved7()264 void BMidiLocalProducer::_Reserved7() { }
_Reserved8()265 void BMidiLocalProducer::_Reserved8() { }
266
267 //------------------------------------------------------------------------------
268
269 void
SprayEvent(const void * data,size_t length,bool atomic,bigtime_t time,bool sysex) const270 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