xref: /haiku/src/kits/midi/Midi.cpp (revision 2807c36668a1730dd59bc39de65e0b8f88cd5d0d)
1 /**
2  * @file Midi.cpp
3  *
4  * @author Matthijs Hollemans
5  * @author Jerome Leveque
6  * @author Paul Stadler
7  */
8 
9 #include <List.h>
10 
11 #include "Midi.h"
12 #include "debug.h"
13 #include "MidiEvent.h"
14 
15 #define DEBUG
16 
17 //-----------------------------------------------
18 
19 #define MSG_CODE_PROCESS_EVENT 1
20 #define MSG_CODE_TERMINATE_THREAD 0
21 
22 //-----------------------------------------------
23 
24 //-----------------------------------------------------------------------------
25 // Initialization Stuff
26 BMidi::BMidi()
27 {
28 	fConnectionList = new BList();
29 	fIsRunning = false;
30 
31 	fInflowPort = create_port(1, "Inflow Port");
32 
33 	fInflowTask = spawn_thread(
34 		_inflow_task_, "BMidi Inflow Thread",
35 		B_REAL_TIME_PRIORITY, (void *)this);
36 
37 	fInflowAlive = resume_thread(fInflowTask) == B_OK;
38 }
39 
40 BMidi::~BMidi()
41 {
42 	write_port(fInflowPort, MSG_CODE_TERMINATE_THREAD, NULL, 0);
43 
44 	status_t exit_value;
45 	wait_for_thread(fInflowTask, &exit_value);
46 
47 	delete_port(fInflowPort);
48 	delete fConnectionList;
49 }
50 
51 //-----------------------------------------------------------------------------
52 // Stubs for midi event hooks.
53 void BMidi::NoteOff(uchar chan, uchar note, uchar vel, uint32 time)
54 {
55 }
56 void BMidi::NoteOn(uchar chan, uchar note, uchar vel, uint32 time)
57 {
58 }
59 void BMidi::KeyPressure(uchar chan, uchar note, uchar pres, uint32 time)
60 {
61 }
62 void BMidi::ControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, uint32 time)
63 {
64 }
65 void BMidi::ProgramChange(uchar chan, uchar prog_num, uint32 time)
66 {
67 }
68 void BMidi::ChannelPressure(uchar chan, uchar pres, uint32 time)
69 {
70 }
71 void BMidi::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time)
72 {
73 }
74 void BMidi::SystemExclusive(void * data, size_t data_len, uint32 time)
75 {
76 }
77 void BMidi::SystemCommon(uchar stat_byte, uchar data1, uchar data2, uint32 time)
78 {
79 }
80 void BMidi::SystemRealTime(uchar stat_byte, uint32 time)
81 {
82 }
83 void BMidi::TempoChange(int32 bpm, uint32 time)
84 {
85 }
86 void BMidi::AllNotesOff(bool just_chan, uint32 time)
87 {
88 }
89 
90 //-----------------------------------------------------------------------------
91 // Public API Functions
92 status_t BMidi::Start()
93 {
94 	fRunTask = spawn_thread(_run_thread_,
95 		"BMidi Run Thread", B_REAL_TIME_PRIORITY, (void *)this);
96 	fIsRunning = true;
97 	status_t ret = resume_thread(fRunTask);
98 	if(ret != B_OK)
99 	{
100 		fIsRunning = false;
101 	}
102 	return B_OK;
103 }
104 
105 //-----------------------------------------------------------------------------
106 
107 void BMidi::Stop()
108 {
109 	status_t exit_value;
110 	status_t ret;
111 	fIsRunning = false;
112 	ret = wait_for_thread(fRunTask, &exit_value);
113 }
114 
115 bool BMidi::IsRunning() const
116 {
117 	thread_info info;
118 	get_thread_info(fRunTask,&info);
119 	if(find_thread("BMidi Run Thread") == fRunTask)
120 		return true;
121 return false;
122 }
123 
124 void BMidi::Connect(BMidi *to_object)
125 {
126 	fConnectionList->AddItem((void *)to_object);
127 }
128 
129 void BMidi::Disconnect(BMidi *from_object)
130 {
131 	fConnectionList->RemoveItem((void *)from_object);
132 }
133 
134 bool BMidi::IsConnected(BMidi * to_object) const
135 {
136 	return fConnectionList->HasItem((void *)to_object);
137 }
138 
139 BList * BMidi::Connections() const
140 {
141 	return fConnectionList;
142 }
143 
144 void BMidi::SnoozeUntil(uint32 time) const
145 {
146 	snooze_until((uint64)time*1000, B_SYSTEM_TIMEBASE);
147 }
148 
149 bool BMidi::KeepRunning()
150 {
151 	return fIsRunning;
152 }
153 
154 void BMidi::Run()
155 {
156 	while(KeepRunning())
157 		snooze(50000);
158 }
159 
160 //-----------------------------------------------------------------------------
161 // Spray Functions
162 void BMidi::SprayMidiEvent(BMidiEvent *e) const
163 {
164 //	TRACE(("Hello"))
165 	int32 num_connections = fConnectionList->CountItems();
166 	BMidi *m;
167 	for(int32 i = 0; i < num_connections; i++)
168 	{
169 		m = (BMidi *)fConnectionList->ItemAt(i);
170 		write_port(m->fInflowPort, MSG_CODE_PROCESS_EVENT, e, sizeof(BMidiEvent));
171 	}
172 }
173 
174 //----------------------
175 
176 void BMidi::SprayNoteOff(
177 	uchar channel, uchar note, uchar velocity, uint32 time) const
178 {
179 	BMidiEvent event;
180 	event.time = time;
181 	event.opcode = BMidiEvent::OP_NOTE_OFF;
182 	event.noteOff.channel = channel;
183 	event.noteOff.note = note;
184 	event.noteOff.velocity = velocity;
185 	SprayMidiEvent(&event);
186 }
187 
188 //----------------------
189 
190 void BMidi::SprayNoteOn(
191 	uchar channel, uchar note, uchar velocity, uint32 time) const
192 {
193 	BMidiEvent event;
194 	event.time = time;
195 	event.opcode = BMidiEvent::OP_NOTE_ON;
196 	event.noteOn.channel = channel;
197 	event.noteOn.note = note;
198 	event.noteOn.velocity = velocity;
199 	SprayMidiEvent(&event);
200 }
201 
202 //----------------------
203 
204 void BMidi::SprayKeyPressure(
205 	uchar channel, uchar note, uchar pressure, uint32 time) const
206 {
207 	BMidiEvent event;
208 	event.time = time;
209 	event.opcode = BMidiEvent::OP_KEY_PRESSURE;
210 	event.keyPressure.channel = channel;
211 	event.keyPressure.note = note;
212 	event.keyPressure.pressure = pressure;
213 	SprayMidiEvent(&event);
214 }
215 
216 //----------------------
217 
218 void BMidi::SprayControlChange(
219 	uchar channel, uchar controlNumber, uchar controlValue,
220 	uint32 time) const
221 {
222 	BMidiEvent event;
223 	event.time = time;
224 	event.opcode = BMidiEvent::OP_CONTROL_CHANGE;
225 	event.controlChange.channel = channel;
226 	event.controlChange.controlNumber = controlNumber;
227 	event.controlChange.controlValue = controlValue;
228 	SprayMidiEvent(&event);
229 }
230 
231 //----------------------
232 
233 void BMidi::SprayProgramChange(
234 	uchar channel, uchar programNumber, uint32 time) const
235 {
236 	BMidiEvent event;
237 	event.time = time;
238 	event.opcode = BMidiEvent::OP_PROGRAM_CHANGE;
239 	event.programChange.channel = channel;
240 	event.programChange.programNumber = programNumber;
241 	SprayMidiEvent(&event);
242 }
243 
244 //----------------------
245 
246 void BMidi::SprayChannelPressure(
247 	uchar channel, uchar pressure, uint32 time) const
248 {
249 	BMidiEvent event;
250 	event.time = time;
251 	event.opcode = BMidiEvent::OP_CHANNEL_PRESSURE;
252 	event.channelPressure.channel = channel;
253 	event.channelPressure.pressure = pressure;
254 	SprayMidiEvent(&event);
255 }
256 
257 //----------------------
258 
259 void BMidi::SprayPitchBend(
260 	uchar channel, uchar lsb, uchar msb, uint32 time) const
261 {
262 	BMidiEvent event;
263 	event.time = time;
264 	event.opcode = BMidiEvent::OP_PITCH_BEND;
265 	event.pitchBend.channel = channel;
266 	event.pitchBend.lsb = lsb;
267 	event.pitchBend.msb = msb;
268 	SprayMidiEvent(&event);
269 }
270 
271 //----------------------
272 
273 void BMidi::SpraySystemExclusive(
274 	void * data, size_t dataLength, uint32 time) const
275 {
276 	// Should this data be duplicated!!?? I think Yes.
277 	BMidiEvent event;
278 	event.time = time;
279 	event.opcode = BMidiEvent::OP_SYSTEM_EXCLUSIVE;
280 	event.systemExclusive.data = new uint8[dataLength];
281 	memcpy(event.systemExclusive.data, data, dataLength);
282 	event.systemExclusive.dataLength = dataLength;
283 	SprayMidiEvent(&event);
284 }
285 
286 //----------------------
287 
288 void BMidi::SpraySystemCommon(
289 	uchar status, uchar data1, uchar data2, uint32 time) const
290 {
291 	BMidiEvent event;
292 	event.time = time;
293 	event.opcode = BMidiEvent::OP_SYSTEM_COMMON;
294 	event.systemCommon.status = status;
295 	event.systemCommon.data1 = data1;
296 	event.systemCommon.data2 = data2;
297 	SprayMidiEvent(&event);
298 }
299 
300 //----------------------
301 
302 void BMidi::SpraySystemRealTime(uchar status, uint32 time) const
303 {
304 	BMidiEvent event;
305 	event.time = time;
306 	event.opcode = BMidiEvent::OP_SYSTEM_REAL_TIME;
307 	event.systemRealTime.status = status;
308 	SprayMidiEvent(&event);
309 }
310 
311 //----------------------
312 
313 void BMidi::SprayTempoChange(int32 beatsPerMinute, uint32 time) const
314 {
315 	BMidiEvent event;
316 	event.time = time;
317 	event.opcode = BMidiEvent::OP_TEMPO_CHANGE;
318 	event.tempoChange.beatsPerMinute = beatsPerMinute;
319 	SprayMidiEvent(&event);
320 }
321 
322 //-----------------------------------------------------------------------------
323 // The Inflow Thread
324 void BMidi::InflowTask()
325 {
326 	BMidiEvent event;
327 	int32 code;
328 	size_t len;
329 	while(true)
330 	{
331 		len = read_port(fInflowPort, &code, &event, sizeof(BMidiEvent));
332 
333 		if (code == MSG_CODE_TERMINATE_THREAD) { return; }
334 
335 		if (len != sizeof(BMidiEvent)) { continue; }  //ignore errors
336 
337 		switch (event.opcode)
338 		{
339 			case BMidiEvent::OP_NONE:
340 			case BMidiEvent::OP_TRACK_END:
341 			case BMidiEvent::OP_ALL_NOTES_OFF:
342 				break;
343 
344 			case BMidiEvent::OP_NOTE_OFF:
345 				NoteOff(
346 					event.noteOff.channel,
347 					event.noteOff.note,
348 					event.noteOff.velocity,
349 					event.time);
350 				break;
351 
352 			case BMidiEvent::OP_NOTE_ON:
353 				NoteOn(
354 					event.noteOn.channel,
355 					event.noteOn.note,
356 					event.noteOn.velocity,
357 					event.time);
358 				break;
359 
360 			case BMidiEvent::OP_KEY_PRESSURE:
361 				KeyPressure(
362 					event.keyPressure.channel,
363 					event.keyPressure.note,
364 					event.keyPressure.pressure,
365 					event.time);
366 				break;
367 
368 			case BMidiEvent::OP_CONTROL_CHANGE:
369 				ControlChange(
370 					event.controlChange.channel,
371 					event.controlChange.controlNumber,
372 					event.controlChange.controlValue,
373 					event.time);
374 				break;
375 
376 			case BMidiEvent::OP_PROGRAM_CHANGE:
377 				ProgramChange(
378 					event.programChange.channel,
379 					event.programChange.programNumber,
380 					event.time);
381 				break;
382 
383 			case BMidiEvent::OP_CHANNEL_PRESSURE:
384 				ChannelPressure(
385 					event.channelPressure.channel,
386 					event.channelPressure.pressure,
387 					event.time);
388 				break;
389 
390 			case BMidiEvent::OP_PITCH_BEND:
391 				PitchBend(
392 					event.pitchBend.channel,
393 					event.pitchBend.lsb,
394 					event.pitchBend.msb,
395 					event.time);
396 				break;
397 
398 			case BMidiEvent::OP_SYSTEM_EXCLUSIVE:
399 				SystemExclusive(
400 					event.systemExclusive.data,
401 					event.systemExclusive.dataLength,
402 					event.time);
403 				break;
404 
405 			case BMidiEvent::OP_SYSTEM_COMMON:
406 				SystemCommon(
407 					event.systemCommon.status,
408 					event.systemCommon.data1,
409 					event.systemCommon.data2,
410 					event.time);
411 				break;
412 
413 			case BMidiEvent::OP_SYSTEM_REAL_TIME:
414 				SystemRealTime(
415 					event.systemRealTime.status,
416 					event.time);
417 				break;
418 
419 			case BMidiEvent::OP_TEMPO_CHANGE:
420 				TempoChange(
421 					event.tempoChange.beatsPerMinute,
422 					event.time);
423 				break;
424 
425 			default: break;
426 		}
427 	}
428 }
429 
430 //----------------------
431 //----------------------
432 //----------------------
433 //----------------------
434 //----------------------
435 //----------------------
436 //----------------------
437 //----------------------
438 
439 void BMidi::_ReservedMidi1() {}
440 void BMidi::_ReservedMidi2() {}
441 void BMidi::_ReservedMidi3() {}
442 
443 //----------------------
444 
445 status_t _run_thread_(void *data)
446 {
447 	((BMidi*)data)->Run();
448 	return 0;
449 }
450 
451 //----------------------
452 
453 status_t _inflow_task_(void * data)
454 {
455 	((BMidi*)data)->InflowTask();
456 	return 0;
457 }
458 
459 //-----------------------------------------------
460 //-----------------------------------------------
461 //-----------------------------------------------
462 //-----------------------------------------------
463 //-----------------------------------------------
464 //-----------------------------------------------
465 //-----------------------------------------------
466 //-----------------------------------------------
467 //-----------------------------------------------
468