1 /*---------------------------------------------------------------------------*
2 Project: MIDI adaptor sample demo
3 File: midiqueue.c
4 Programmer: HIRATSU Daisuke
5
6 Copyright (C)2007 Nintendo All rights reserved.
7
8 These coded instructions, statements, and computer programs contain
9 proprietary information of Nintendo of America Inc. and/or Nintendo
10 Company Ltd., and are protected by Federal copyright law. They may
11 not be disclosed to third parties or copied or duplicated in any form,
12 in whole or in part, without the prior written consent of Nintendo.
13
14 $Log: midiqueue.c,v $
15 Revision 1.2 2007/04/17 08:24:54 hiratsu
16 Refactoring.
17
18 Revision 1.1 2007/04/13 08:39:53 hiratsu
19 Initial check-in.
20
21 *---------------------------------------------------------------------------*/
22
23
24 #include "midiqueue.h"
25
26 #include <revolution/midi.h>
27 #include <demo.h>
28
29 #define RINGBUF_SIZE 128
30
31 // Queue related operations.
32 static int getHeadIndex(void);
33 static int getTailIndex(void);
34 static int getLength(void);
35 static int proceedIndex(int oldIndex);
36 static void proceedHeadIndex(void);
37 static void proceedTailIndex(void);
38
39 // MIDI related operations.
40 static BOOL isStatusByte(u8 ch);
41 static BOOL isDataByte (u8 ch);
42 static BOOL isSupportedMidiMessage(u8 ch);
43 static BOOL isSupportedMidiControl(u8 ch);
44 static BOOL isNoteOnMessage(u8 ch); // 3 bytes
45 static BOOL isNoteOffMessage(u8 ch); // 3 bytes
46 static BOOL isControlChangeMessage(u8 ch); // 3 bytes
47 static BOOL isProgramChangeMessage(u8 ch); // 2 bytes
48 static BOOL isPitchbendChangeMessage(u8 ch); // 3 bytes
49 static BOOL isExclusiveMessage(u8 ch); // Flexible length
50 static BOOL isEndOfExclusiveMessage(u8 ch);
51 static BOOL isActiveSensingMessage(u8 ch);
52 static BOOL isSystemMessage(u8 ch);
53 static int getExpectedDataNum(u8 statusByte);
54
55
56 static u8 s_ringBuffer[RINGBUF_SIZE];
57 static int s_headIndex = 0;
58 static int s_tailIndex = 0;
59 static u8 s_lastStatusByte = 0x00;
60 static int s_expectedDataNum = 0;
61
62
isStatusByte(u8 ch)63 static BOOL isStatusByte(u8 ch)
64 {
65 return (ch & 0x80) ? TRUE : FALSE;
66 }
67
68
isDataByte(u8 ch)69 static BOOL isDataByte(u8 ch)
70 {
71 return isStatusByte(ch) ? FALSE : TRUE;
72 }
73
74
isSupportedMidiMessage(u8 ch)75 static BOOL isSupportedMidiMessage(u8 ch)
76 {
77 if(isNoteOnMessage(ch) ||
78 isNoteOffMessage(ch) ||
79 isControlChangeMessage(ch) ||
80 isProgramChangeMessage(ch) ||
81 isPitchbendChangeMessage(ch) )
82 {
83 return TRUE;
84 }
85 else
86 {
87 return FALSE;
88 }
89 }
90
91
isSupportedMidiControl(u8 ch)92 static BOOL isSupportedMidiControl(u8 ch)
93 {
94 const u8 LIST[] = {
95 0x01, // Modulation wheel
96 0x06, 0x26, // Data entry (for pitch wheel range setting)
97 0x07, // Volume
98 0x0a, // Pan
99 0x0b, // Expression
100 0x40, // Hold pedal
101 0x5b, // Effects (AuxA)
102 0x5c, // Effects (AuxB)
103 0x62, 0x63, // NRPN
104 0x64, 0x65, // RPN
105 0x78, // All sound off
106 0x79, // Reset all controllers
107 0x7b, 0x7c, 0x7d, 0x7e, 0x7f // All note off
108 };
109 int i = 0;
110
111 for(i = 0; i<sizeof(LIST); ++i)
112 {
113 if(ch==LIST[i])
114 {
115 return TRUE;
116 }
117 }
118
119 return FALSE; // Not found
120 }
121
122
123
isNoteOnMessage(u8 ch)124 static BOOL isNoteOnMessage(u8 ch)
125 {
126 return ((ch & 0xf0)==0x90) ? TRUE : FALSE;
127 }
128
129
isNoteOffMessage(u8 ch)130 static BOOL isNoteOffMessage(u8 ch)
131 {
132 return ((ch & 0xf0)==0x80) ? TRUE : FALSE;
133 }
134
135
isControlChangeMessage(u8 ch)136 static BOOL isControlChangeMessage(u8 ch)
137 {
138 return ((ch & 0xf0)==0xb0) ? TRUE : FALSE;
139 }
140
141
isProgramChangeMessage(u8 ch)142 static BOOL isProgramChangeMessage(u8 ch)
143 {
144 return ((ch & 0xf0)==0xc0) ? TRUE : FALSE;
145 }
146
147
isPitchbendChangeMessage(u8 ch)148 static BOOL isPitchbendChangeMessage(u8 ch)
149 {
150 return ((ch & 0xf0)==0xe0) ? TRUE : FALSE;
151 }
152
153
isExclusiveMessage(u8 ch)154 static BOOL isExclusiveMessage(u8 ch)
155 {
156 return (ch==0xf0) ? TRUE : FALSE;
157 }
158
159
isEndOfExclusiveMessage(u8 ch)160 static BOOL isEndOfExclusiveMessage(u8 ch)
161 {
162 return (ch==0xf7) ? TRUE : FALSE;
163 }
164
165
isActiveSensingMessage(u8 ch)166 static BOOL isActiveSensingMessage(u8 ch)
167 {
168 return (ch==0xfe) ? TRUE : FALSE;
169 }
170
171
isSystemMessage(u8 ch)172 static BOOL isSystemMessage(u8 ch)
173 {
174 return ((ch & 0xf0) == 0xf0) ? TRUE : FALSE;
175 }
176
177
getExpectedDataNum(u8 statusByte)178 static int getExpectedDataNum(u8 statusByte)
179 {
180 if(isNoteOnMessage(statusByte) ||
181 isNoteOffMessage(statusByte) ||
182 isControlChangeMessage(statusByte) ||
183 isPitchbendChangeMessage(statusByte) )
184 {
185 return 2;
186 }
187 else if(isProgramChangeMessage(statusByte))
188 {
189 return 1;
190 }
191 else if(isEndOfExclusiveMessage(statusByte))
192 {
193 return 0;
194 }
195 else
196 {
197 OSHalt("Caution! Unexpected status byte.");
198 return 0; // Never reach here.
199 }
200 }
201
202
getHeadIndex(void)203 static int getHeadIndex(void)
204 {
205 return s_headIndex;
206 }
207
208
getTailIndex(void)209 static int getTailIndex(void)
210 {
211 return s_tailIndex;
212 }
213
214
getLength(void)215 static int getLength(void)
216 {
217 int ret = 0;
218 BOOL enabled = OSDisableInterrupts();
219 int tail = getTailIndex();
220 int head = getHeadIndex();
221
222 if(tail >= head)
223 {
224 ret = tail - head;
225 }
226 else
227 {
228 ret = RINGBUF_SIZE+tail - head;
229 }
230 OSRestoreInterrupts(enabled);
231
232 return ret;
233 }
234
235
proceedIndex(int oldIndex)236 static int proceedIndex(int oldIndex)
237 {
238 if((0<=oldIndex) && (oldIndex < RINGBUF_SIZE-1))
239 {
240 return oldIndex+1;
241 }
242 else if(oldIndex == RINGBUF_SIZE-1)
243 {
244 return 0;
245 }
246 else
247 {
248 OSReport("Invalid index (out of range): %d", oldIndex);
249 OSHalt("");
250 return -1; // Never reach here.
251 }
252 }
253
254
proceedHeadIndex(void)255 static void proceedHeadIndex(void)
256 {
257 s_headIndex = proceedIndex(s_headIndex);
258 }
259
260
proceedTailIndex(void)261 static void proceedTailIndex(void)
262 {
263 s_tailIndex = proceedIndex(s_tailIndex);
264 }
265
266
pushImpl(u8 a)267 static void pushImpl(u8 a)
268 {
269 BOOL enabled = OSDisableInterrupts();
270
271 s_ringBuffer[getTailIndex()] = a;
272 proceedTailIndex();
273 if(getHeadIndex()==getTailIndex()){
274 OSReport("Caution! Queue is full.\n");
275 }
276
277 OSRestoreInterrupts(enabled);
278 }
279
280
push(u8 a)281 void push(u8 a)
282 {
283 if(isExclusiveMessage(s_lastStatusByte) && !isEndOfExclusiveMessage(a))
284 {
285 return; // Ignore exclusive message.
286 }
287
288 if(isActiveSensingMessage(a))
289 {
290 return; // Ignore active sensing.
291 }
292
293 if(isStatusByte(a))
294 {
295 s_lastStatusByte = a;
296 s_expectedDataNum = getExpectedDataNum(a);
297 if(!isEndOfExclusiveMessage(a))
298 {
299 pushImpl(a);
300 }
301 }
302 else
303 {
304 if(s_expectedDataNum > 0)
305 {
306 --s_expectedDataNum;
307 pushImpl(a);
308 }
309 else if(s_expectedDataNum == 0)
310 {
311 pushImpl(s_lastStatusByte); // Running status process.
312 pushImpl(a);
313
314 s_expectedDataNum = getExpectedDataNum(s_lastStatusByte)-1;
315 }
316 else
317 {
318 OSHalt("Caution! Unexpected sequence.");
319 }
320 }
321 }
322
323
pop(void)324 void pop(void)
325 {
326 BOOL enabled = OSDisableInterrupts();
327 if(isReady())
328 {
329 int i = 0;
330 int n = getExpectedDataNum(s_ringBuffer[getHeadIndex()]);
331 for(i=0; i<=n; ++i)
332 {
333 proceedHeadIndex();
334 }
335 }
336 else
337 {
338 OSReport("Caution! You're going to pop from empty queue.\n");
339 }
340 OSRestoreInterrupts(enabled);
341 }
342
343
front(u8 msg[3])344 BOOL front(u8 msg[3])
345 {
346 BOOL ret = FALSE;
347 BOOL enabled = OSDisableInterrupts();
348 if(isReady())
349 {
350 int head = getHeadIndex();
351 switch(getExpectedDataNum(s_ringBuffer[head]))
352 {
353 case 2:
354 msg[2] = s_ringBuffer[(head+2)%RINGBUF_SIZE];
355 case 1:
356 msg[1] = s_ringBuffer[(head+1)%RINGBUF_SIZE];
357 case 0:
358 msg[0] = s_ringBuffer[head];
359 break;
360 default:
361 OSHalt("Illegal sequence.");
362 break;
363 }
364 ret = TRUE;
365 }
366 else
367 {
368 ret = FALSE;
369 }
370 OSRestoreInterrupts(enabled);
371
372 return ret;
373 }
374
375
376 // Can one or more MIDI messages be retrieved?
isReady(void)377 BOOL isReady(void)
378 {
379 BOOL ret = FALSE;
380 BOOL enabled = OSDisableInterrupts();
381 int len = getLength();
382 if(len==0)
383 {
384 ret = FALSE;
385 }
386 else
387 {
388 int expect = getExpectedDataNum(s_ringBuffer[getHeadIndex()]);
389 if(expect < len)
390 {
391 ret = TRUE;
392 }
393 else
394 {
395 ret = FALSE;
396 }
397 }
398 OSRestoreInterrupts(enabled);
399
400 return ret;
401 }
402
403
isSupportedCommand(const u8 cmd[3])404 BOOL isSupportedCommand(const u8 cmd[3])
405 {
406 if(isSupportedMidiMessage(cmd[0]))
407 {
408 if(!isControlChangeMessage(cmd[0]))
409 {
410 return TRUE;
411 }
412 else
413 {
414 if(isSupportedMidiControl(cmd[1]))
415 {
416 return TRUE;
417 }
418 else
419 {
420 return FALSE;
421 }
422 }
423 }
424 else
425 {
426 return FALSE;
427 }
428 }
429