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