1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: snd_MidiStreamParser.cpp
4
5 Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Revision: 20981 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <nw/snd/snd_MidiStreamParser.h>
19
20 // #define DEBUG_REPORT
21
22 namespace nw {
23 namespace snd {
24 namespace internal {
25
MidiStreamParser()26 MidiStreamParser::MidiStreamParser()
27 {
28 m_RestBuffer.ptr = m_RestBuf;
29 m_RestBuffer.len = 0;
30 m_RestBuffer.readPos = 0;
31 m_RestBuffer.donePos = 0;
32
33 m_BackByte = 0;
34 m_IsBackByteAvailable = false;
35 }
36
SetCallback(MidiCallback callback,void * arg)37 void MidiStreamParser::SetCallback( MidiCallback callback, void* arg )
38 {
39 m_CallbackFunc = callback;
40 m_pCallbackArg = arg;
41 }
42
Parse(const void * buffer,unsigned long size)43 void MidiStreamParser::Parse( const void* buffer, unsigned long size )
44 {
45 // バッファを登録
46 SetMsgBuffer( buffer, size );
47
48 // メッセージ処理
49 // MIDIメッセージに対するコールバック呼び出し
50 ParseBuffer();
51
52 // 未処理メッセージを次回に繰り越し
53 RestBuffer();
54 }
55
Reset()56 void MidiStreamParser::Reset()
57 {
58 m_IsReset = true;
59 m_IsSysEx = false;;
60 }
61
ParseBuffer(void)62 void MidiStreamParser::ParseBuffer( void )
63 {
64 u8 status;
65 u8 data1;
66 u8 data2;
67
68 while( 1 )
69 {
70 status = 0;
71 data1 = 0;
72 data2 = 0;
73
74 // ステータスバイト待ち
75 if ( m_IsReset )
76 {
77 if ( ! SeekStatusByte() ) return;
78 m_IsReset = false;
79 }
80
81 // システムエクスクルーシブ
82 if ( m_IsSysEx ) {
83 u8 b;
84 do {
85 if ( ! ReadByte( &b ) ) return;
86
87 // 読み捨て
88 EatByte();
89
90 } while( IsDataByte( b ) );
91
92 BackByte( b );
93
94 if ( b != 0xf7 ) { // eof sys Ex
95 #ifdef DEBUG_REPORT
96 NN_LOG("Not found EOF sysEx\n");
97 #endif
98 Reset();
99 continue;
100 }
101 }
102
103 // 1バイト読む
104 if ( ! ReadByte( &status ) ) return;
105
106 // ランニングステータス
107 if ( IsDataByte( status ) ) {
108 BackByte( status );
109 status = m_RunningStatus;
110 }
111
112 if ( ( status & 0xf0 ) == 0xf0 ) {
113 // コモンメッセージ
114 switch( status ) {
115 case 0xf0: // sys Ex
116 m_IsSysEx = true;
117 break;
118
119 case 0xf1: // time code quoter frame
120 if ( ! ReadByte( &data1 ) ) return;
121 break;
122
123 case 0xf2: // song pos
124 if ( ! ReadByte( &data1 ) ) return;
125 if ( ! ReadByte( &data2 ) ) return;
126 break;
127
128 case 0xf3: // song select
129 if ( ! ReadByte( &data1 ) ) return;
130 break;
131
132 case 0xf4: // undef
133 case 0xf5: // undef
134 case 0xf6: // tune request
135 break;
136
137 case 0xf7: // eof Ex
138 m_IsSysEx = false;
139 break;
140 }
141 }
142 else {
143 // チャンネルメッセージ
144 u8 ch = (u8)( status & 0x0f );
145
146 if ( ! ReadByte( &data1 ) ) return;
147
148 switch( status & 0xf0 ) {
149 case 0x80: // noteoff
150 case 0x90: // noteon
151 case 0xa0: // polyphonic key pressure
152 case 0xb0: // control change
153 case 0xe0: // pitchbend
154 if ( ! ReadByte( &data2 ) ) return;
155 break;
156 case 0xc0: // program change
157 case 0xd0: // channel presure
158 break;
159 }
160 }
161
162 if ( ! IsDataByte( data1 ) || ! IsDataByte( data2 )) {
163 #ifdef DEBUG_REPORT
164 NN_LOG("Unexpected status byte\n");
165 #endif
166 Reset();
167 continue;
168 }
169
170 #ifdef DEBUG_REPORT
171 NN_LOG("MIDI: %02x %02x %02x\n", status,data1,data2);
172 #endif
173 m_CallbackFunc( status, data1, data2, m_pCallbackArg );
174
175 m_RunningStatus = status;
176 EatByte();
177 }
178 }
179
SetMsgBuffer(const void * buffer,u32 len)180 void MidiStreamParser::SetMsgBuffer( const void* buffer, u32 len )
181 {
182 m_MsgBuffer.ptr = (const u8* )buffer;
183 m_MsgBuffer.len = len;
184 m_MsgBuffer.readPos = 0;
185 m_MsgBuffer.donePos = 0;
186
187 #ifdef DEBUG_REPORT
188 if ( len > 0 )
189 {
190 const u8* p = (const u8*)buffer;
191 for( int i = 0 ; i < len ; i++ ) {
192 NN_LOG("%02x ", p[i]);
193 }
194 NN_LOG("\n");
195 }
196 #endif
197 }
198
ReadByte(u8 * data)199 bool MidiStreamParser::ReadByte( u8* data )
200 {
201 if ( m_IsBackByteAvailable ) {
202 NW_ASSERT( ! IsRealtimeMesg( m_BackByte ) );
203 m_IsBackByteAvailable = false;
204 *data = m_BackByte;
205 return true;
206 }
207
208 while ( m_RestBuffer.readPos < m_RestBuffer.len ) {
209 *data = m_RestBuffer.ptr[ m_RestBuffer.readPos++ ];
210 if ( IsRealtimeMesg( *data ) ) {
211 #ifdef DEBUG_REPORT
212 NN_LOG("MIDI: %02x %02x %02x\n", *data,0,0);
213 #endif
214 m_CallbackFunc( *data, 0, 0, m_pCallbackArg );
215 if ( IsSystemResetMesg(*data) ) m_IsReset = true;
216 continue;
217 }
218 return true;
219 }
220
221 while ( m_MsgBuffer.readPos < m_MsgBuffer.len ) {
222 *data = m_MsgBuffer.ptr[ m_MsgBuffer.readPos++ ];
223 if ( IsRealtimeMesg( *data ) ) {
224 #ifdef DEBUG_REPORT
225 NN_LOG("MIDI: %02x %02x %02x\n", *data,0,0);
226 #endif
227 m_CallbackFunc( *data, 0, 0, m_pCallbackArg );
228 if ( IsSystemResetMesg(*data) ) m_IsReset = true;
229 continue;
230 }
231 return true;
232 }
233
234 return false;
235 }
236
SeekStatusByte(void)237 bool MidiStreamParser::SeekStatusByte( void )
238 {
239 u8 byte;
240
241 if ( m_IsBackByteAvailable ) {
242 NW_ASSERT( ! IsRealtimeMesg( m_BackByte ) );
243 if ( IsStatusByte( m_BackByte ) ) return true;
244 m_IsBackByteAvailable = false;
245 }
246
247 while( m_RestBuffer.readPos < m_RestBuffer.len ) {
248 byte = m_RestBuffer.ptr[ m_RestBuffer.readPos ];
249 if ( IsStatusByte( byte ) && ! IsRealtimeMesg( byte ) ) {
250 EatByte();
251 return true;
252 }
253 m_RestBuffer.readPos++;
254 }
255
256 while ( m_MsgBuffer.readPos < m_MsgBuffer.len ) {
257 byte = m_MsgBuffer.ptr[ m_MsgBuffer.readPos ];
258 if ( IsStatusByte( byte ) && ! IsRealtimeMesg( byte ) ) {
259 EatByte();
260 return true;
261 }
262 m_MsgBuffer.readPos++;
263 }
264
265 EatByte();
266 return false;
267 }
268
BackByte(u8 byte)269 void MidiStreamParser::BackByte( u8 byte )
270 {
271 NW_ASSERT( ! m_IsBackByteAvailable );
272 NW_ASSERT( ! IsRealtimeMesg( byte ) );
273
274 m_BackByte = byte;
275 m_IsBackByteAvailable = true;
276 }
277
EatByte(void)278 void MidiStreamParser::EatByte( void )
279 {
280 m_RestBuffer.donePos = m_RestBuffer.readPos;
281 m_MsgBuffer.donePos = m_MsgBuffer.readPos;
282 }
283
RestBuffer(void)284 void MidiStreamParser::RestBuffer( void )
285 {
286 u8* rest = m_RestBuf;
287 u32 len;
288 u32 restLen;
289
290 restLen = 0;
291
292 NW_ASSERT( ! m_IsBackByteAvailable );
293
294 len = m_RestBuffer.len - m_RestBuffer.donePos;
295 for( u32 i = 0; i < len ; i++ ) {
296 *rest = m_RestBuffer.ptr[ m_RestBuffer.donePos + i ];
297 if ( ! IsRealtimeMesg( *rest ) ) { // リアルタイムメッセージは処理済み
298 rest++;
299 restLen++;
300 }
301 }
302
303 len = m_MsgBuffer.len - m_MsgBuffer.donePos;
304 for( u32 i = 0; i < len ; i++ ) {
305 *rest = m_MsgBuffer.ptr[ m_MsgBuffer.donePos + i ];
306 if ( ! IsRealtimeMesg( *rest ) ) { // リアルタイムメッセージは処理済み
307 rest++;
308 restLen++;
309 }
310 }
311
312 m_RestBuffer.readPos = 0;
313 m_RestBuffer.donePos = 0;
314 m_RestBuffer.len = restLen;
315
316 NW_ASSERT( m_RestBuffer.len < sizeof(m_RestBuf)/sizeof(m_RestBuf[0]) );
317 }
318
319 } // namespace nw::snd::internal
320 } // namespace nw::snd
321 } // namespace nw
322
323