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