1 /*----------------------------------------------------------------------------
2 *
3 * File:
4 * eas_smf.c
5 *
6 * Contents and purpose:
7 * SMF Type 0 and 1 File Parser
8 *
9 * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls".
10 *
11 * Copyright Sonic Network Inc. 2005
12
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *
25 *----------------------------------------------------------------------------
26 * Revision Control:
27 * $Revision: 803 $
28 * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $
29 *----------------------------------------------------------------------------
30 */
31
32 #define LOG_TAG "Sonivox"
33 #include "log/log.h"
34
35 #include "eas_data.h"
36 #include "eas_miditypes.h"
37 #include "eas_parser.h"
38 #include "eas_report.h"
39 #include "eas_host.h"
40 #include "eas_midi.h"
41 #include "eas_config.h"
42 #include "eas_vm_protos.h"
43 #include "eas_smfdata.h"
44 #include "eas_smf.h"
45
46 #ifdef JET_INTERFACE
47 #include "jet_data.h"
48 #endif
49
50 //3 dls: The timebase for this module is adequate to keep MIDI and
51 //3 digital audio synchronized for only a few minutes. It should be
52 //3 sufficient for most mobile applications. If better accuracy is
53 //3 required, more fractional bits should be added to the timebase.
54
55 static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' };
56
57 /* local prototypes */
58 static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData);
59 static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream);
60 static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode);
61 static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode);
62 static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream);
63 static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks);
64
65
66 /*----------------------------------------------------------------------------
67 *
68 * SMF_Parser
69 *
70 * This structure contains the functional interface for the SMF parser
71 *----------------------------------------------------------------------------
72 */
73 const S_FILE_PARSER_INTERFACE EAS_SMF_Parser =
74 {
75 SMF_CheckFileType,
76 SMF_Prepare,
77 SMF_Time,
78 SMF_Event,
79 SMF_State,
80 SMF_Close,
81 SMF_Reset,
82 SMF_Pause,
83 SMF_Resume,
84 NULL,
85 SMF_SetData,
86 SMF_GetData,
87 NULL
88 };
89
90 /*----------------------------------------------------------------------------
91 * SMF_CheckFileType()
92 *----------------------------------------------------------------------------
93 * Purpose:
94 * Check the file type to see if we can parse it
95 *
96 * Inputs:
97 * pEASData - pointer to overall EAS data structure
98 * handle - pointer to file handle
99 *
100 * Outputs:
101 *
102 *
103 * Side Effects:
104 *
105 *----------------------------------------------------------------------------
106 */
SMF_CheckFileType(S_EAS_DATA * pEASData,EAS_FILE_HANDLE fileHandle,EAS_VOID_PTR * ppHandle,EAS_I32 offset)107 EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
108 {
109 S_SMF_DATA* pSMFData;
110 EAS_RESULT result;
111
112 /* seek to starting offset - usually 0 */
113 *ppHandle = NULL;
114 if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS)
115 return result;
116
117 /* search through file for header - slow method */
118 if (pEASData->searchHeaderFlag)
119 {
120 result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset);
121 if (result != EAS_SUCCESS)
122 return (result == EAS_EOF) ? EAS_SUCCESS : result;
123 }
124
125 /* read the first 4 bytes of the file - quick method */
126 else {
127 EAS_U8 header[4];
128 EAS_I32 count;
129 if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS)
130 return result;
131
132 /* check for 'MThd' - If no match then return SUCCESS with NULL handle
133 * to indicate not an SMF file. */
134 if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd'))
135 return EAS_SUCCESS;
136 }
137
138 /* check for static memory allocation */
139 if (pEASData->staticMemoryModel)
140 pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA);
141 else
142 {
143 pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA));
144 EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA));
145 }
146 if (!pSMFData)
147 return EAS_ERROR_MALLOC_FAILED;
148
149 /* initialize some critical data */
150 pSMFData->fileHandle = fileHandle;
151 pSMFData->fileOffset = offset;
152 pSMFData->pSynth = NULL;
153 pSMFData->time = 0;
154 pSMFData->state = EAS_STATE_OPEN;
155 *ppHandle = pSMFData;
156
157 return EAS_SUCCESS;
158 }
159
160 /*----------------------------------------------------------------------------
161 * SMF_Prepare()
162 *----------------------------------------------------------------------------
163 * Purpose:
164 * Prepare to parse the file. Allocates instance data (or uses static allocation for
165 * static memory model).
166 *
167 * Inputs:
168 * pEASData - pointer to overall EAS data structure
169 * handle - pointer to file handle
170 *
171 * Outputs:
172 *
173 *
174 * Side Effects:
175 *
176 *----------------------------------------------------------------------------
177 */
SMF_Prepare(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)178 EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
179 {
180 S_SMF_DATA* pSMFData;
181 EAS_RESULT result;
182
183 /* check for valid state */
184 pSMFData = (S_SMF_DATA *) pInstData;
185 if (pSMFData->state != EAS_STATE_OPEN)
186 return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
187
188 /* instantiate a synthesizer */
189 if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS)
190 {
191 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ }
192 return result;
193 }
194
195 /* parse the file header and setup the individual stream parsers */
196 if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS)
197 return result;
198
199 /* ready to play */
200 pSMFData->state = EAS_STATE_READY;
201 return EAS_SUCCESS;
202 }
203
204 /*----------------------------------------------------------------------------
205 * SMF_Time()
206 *----------------------------------------------------------------------------
207 * Purpose:
208 * Returns the time of the next event in msecs
209 *
210 * Inputs:
211 * pEASData - pointer to overall EAS data structure
212 * handle - pointer to file handle
213 * pTime - pointer to variable to hold time of next event (in msecs)
214 *
215 * Outputs:
216 *
217 *
218 * Side Effects:
219 *
220 *----------------------------------------------------------------------------
221 */
222 /*lint -esym(715, pEASData) reserved for future use */
SMF_Time(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_U32 * pTime)223 EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
224 {
225 S_SMF_DATA *pSMFData;
226
227 pSMFData = (S_SMF_DATA*) pInstData;
228
229 /* sanity check */
230 #ifdef _CHECKED_BUILD
231 if (pSMFData->state == EAS_STATE_STOPPED)
232 {
233 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ }
234 }
235
236 if (pSMFData->nextStream == NULL)
237 {
238 { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ }
239 }
240 #endif
241
242 #if 0
243 /* return time in milliseconds */
244 /* if chase mode, lie about time */
245 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
246 *pTime = 0;
247
248 else
249 #endif
250
251 /*lint -e{704} use shift instead of division */
252 *pTime = pSMFData->time >> 8;
253
254 *pTime = pSMFData->time >> 8;
255 return EAS_SUCCESS;
256 }
257
258 /*----------------------------------------------------------------------------
259 * SMF_Event()
260 *----------------------------------------------------------------------------
261 * Purpose:
262 * Parse the next event in the file
263 *
264 * Inputs:
265 * pEASData - pointer to overall EAS data structure
266 * handle - pointer to file handle
267 *
268 * Outputs:
269 *
270 *
271 * Side Effects:
272 *
273 *----------------------------------------------------------------------------
274 */
SMF_Event(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_INT parserMode)275 EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
276 {
277 S_SMF_DATA* pSMFData;
278 EAS_RESULT result;
279 EAS_I32 i;
280 EAS_U32 ticks;
281 EAS_U32 temp;
282
283 /* establish pointer to instance data */
284 pSMFData = (S_SMF_DATA*) pInstData;
285 if (pSMFData->state >= EAS_STATE_OPEN)
286 return EAS_SUCCESS;
287
288 if (!pSMFData->nextStream) {
289 return EAS_ERROR_FILE_FORMAT;
290 }
291
292
293 /* get current ticks */
294 ticks = pSMFData->nextStream->ticks;
295
296 /* assume that an error occurred */
297 pSMFData->state = EAS_STATE_ERROR;
298
299 #ifdef JET_INTERFACE
300 /* if JET has track muted, set parser mode to mute */
301 if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE)
302 parserMode = eParserModeMute;
303 #endif
304
305 /* parse the next event from all the streams */
306 if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS)
307 {
308 /* check for unexpected end-of-file */
309 if (result != EAS_EOF)
310 return result;
311
312 /* indicate end of track for this stream */
313 pSMFData->nextStream->ticks = SMF_END_OF_TRACK;
314 }
315
316 /* get next delta time, unless already at end of track */
317 else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK)
318 {
319 if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS)
320 {
321 /* check for unexpected end-of-file */
322 if (result != EAS_EOF)
323 return result;
324
325 /* indicate end of track for this stream */
326 pSMFData->nextStream->ticks = SMF_END_OF_TRACK;
327 }
328
329 /* if zero delta to next event, stay with this stream */
330 else if (pSMFData->nextStream->ticks == ticks)
331 {
332 pSMFData->state = EAS_STATE_PLAY;
333 return EAS_SUCCESS;
334 }
335 }
336
337 /* find next event in all streams */
338 temp = 0x7ffffff;
339 pSMFData->nextStream = NULL;
340 for (i = 0; i < pSMFData->numStreams; i++)
341 {
342 if (pSMFData->streams[i].ticks < temp)
343 {
344 temp = pSMFData->streams[i].ticks;
345 pSMFData->nextStream = &pSMFData->streams[i];
346 }
347 }
348
349 /* are there any more events to parse? */
350 if (pSMFData->nextStream)
351 {
352 pSMFData->state = EAS_STATE_PLAY;
353
354 /* update the time of the next event */
355 SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks);
356 }
357 else
358 {
359 pSMFData->state = EAS_STATE_STOPPING;
360 VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth);
361 }
362
363 return EAS_SUCCESS;
364 }
365
366 /*----------------------------------------------------------------------------
367 * SMF_State()
368 *----------------------------------------------------------------------------
369 * Purpose:
370 * Returns the current state of the stream
371 *
372 * Inputs:
373 * pEASData - pointer to overall EAS data structure
374 * handle - pointer to file handle
375 * pState - pointer to variable to store state
376 *
377 * Outputs:
378 *
379 *
380 * Side Effects:
381 *
382 *----------------------------------------------------------------------------
383 */
384 /*lint -esym(715, pEASData) reserved for future use */
SMF_State(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 * pState)385 EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
386 {
387 S_SMF_DATA* pSMFData;
388
389 /* establish pointer to instance data */
390 pSMFData = (S_SMF_DATA*) pInstData;
391
392 /* if stopping, check to see if synth voices are active */
393 if (pSMFData->state == EAS_STATE_STOPPING)
394 {
395 if (VMActiveVoices(pSMFData->pSynth) == 0)
396 pSMFData->state = EAS_STATE_STOPPED;
397 }
398
399 if (pSMFData->state == EAS_STATE_PAUSING)
400 {
401 if (VMActiveVoices(pSMFData->pSynth) == 0)
402 pSMFData->state = EAS_STATE_PAUSED;
403 }
404
405 /* return current state */
406 *pState = pSMFData->state;
407 return EAS_SUCCESS;
408 }
409
410 /*----------------------------------------------------------------------------
411 * SMF_Close()
412 *----------------------------------------------------------------------------
413 * Purpose:
414 * Close the file and clean up
415 *
416 * Inputs:
417 * pEASData - pointer to overall EAS data structure
418 * handle - pointer to file handle
419 *
420 * Outputs:
421 *
422 *
423 * Side Effects:
424 *
425 *----------------------------------------------------------------------------
426 */
SMF_Close(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)427 EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
428 {
429 S_SMF_DATA* pSMFData;
430 EAS_I32 i;
431 EAS_RESULT result;
432
433 pSMFData = (S_SMF_DATA*) pInstData;
434
435 /* close all the streams */
436 for (i = 0; i < pSMFData->numStreams; i++)
437 {
438 if (pSMFData->streams[i].fileHandle != NULL)
439 {
440 if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS)
441 return result;
442 }
443 }
444 if (pSMFData->fileHandle != NULL)
445 if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS)
446 return result;
447
448 /* free the synth */
449 if (pSMFData->pSynth != NULL)
450 VMMIDIShutdown(pEASData, pSMFData->pSynth);
451
452 /* if using dynamic memory, free it */
453 if (!pEASData->staticMemoryModel)
454 {
455 if (pSMFData->streams)
456 EAS_HWFree(pEASData->hwInstData, pSMFData->streams);
457
458 /* free the instance data */
459 EAS_HWFree(pEASData->hwInstData, pSMFData);
460 }
461
462 return EAS_SUCCESS;
463 }
464
465 /*----------------------------------------------------------------------------
466 * SMF_Reset()
467 *----------------------------------------------------------------------------
468 * Purpose:
469 * Reset the sequencer. Used for locating backwards in the file.
470 *
471 * Inputs:
472 * pEASData - pointer to overall EAS data structure
473 * handle - pointer to file handle
474 *
475 * Outputs:
476 *
477 *
478 * Side Effects:
479 *
480 *----------------------------------------------------------------------------
481 */
SMF_Reset(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)482 EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
483 {
484 S_SMF_DATA* pSMFData;
485 EAS_I32 i;
486 EAS_RESULT result;
487 EAS_U32 ticks;
488
489 pSMFData = (S_SMF_DATA*) pInstData;
490
491 /* reset time to zero */
492 pSMFData->time = 0;
493
494 /* reset the synth */
495 VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE);
496
497 /* find the start of each track */
498 ticks = 0x7fffffffL;
499 pSMFData->nextStream = NULL;
500 for (i = 0; i < pSMFData->numStreams; i++)
501 {
502
503 /* reset file position to first byte of data in track */
504 if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS)
505 return result;
506
507 /* initalize some data */
508 pSMFData->streams[i].ticks = 0;
509
510 /* initalize the MIDI parser data */
511 EAS_InitMIDIStream(&pSMFData->streams[i].midiStream);
512
513 /* parse the first delta time in each stream */
514 if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS)
515 return result;
516 if (pSMFData->streams[i].ticks < ticks)
517 {
518 ticks = pSMFData->streams[i].ticks;
519 pSMFData->nextStream = &pSMFData->streams[i];
520 }
521 }
522
523
524 pSMFData->state = EAS_STATE_READY;
525 return EAS_SUCCESS;
526 }
527
528 /*----------------------------------------------------------------------------
529 * SMF_Pause()
530 *----------------------------------------------------------------------------
531 * Purpose:
532 * Pauses the sequencer. Mutes all voices and sets state to pause.
533 *
534 * Inputs:
535 * pEASData - pointer to overall EAS data structure
536 * handle - pointer to file handle
537 *
538 * Outputs:
539 *
540 *
541 * Side Effects:
542 *
543 *----------------------------------------------------------------------------
544 */
SMF_Pause(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)545 EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
546 {
547 S_SMF_DATA *pSMFData;
548
549 /* can't pause a stopped stream */
550 pSMFData = (S_SMF_DATA*) pInstData;
551 if (pSMFData->state == EAS_STATE_STOPPED)
552 return EAS_ERROR_ALREADY_STOPPED;
553
554 /* mute the synthesizer */
555 VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth);
556 pSMFData->state = EAS_STATE_PAUSING;
557 return EAS_SUCCESS;
558 }
559
560 /*----------------------------------------------------------------------------
561 * SMF_Resume()
562 *----------------------------------------------------------------------------
563 * Purpose:
564 * Resume playing after a pause, sets state back to playing.
565 *
566 * Inputs:
567 * pEASData - pointer to overall EAS data structure
568 * handle - pointer to file handle
569 *
570 * Outputs:
571 *
572 *
573 * Side Effects:
574 *
575 *----------------------------------------------------------------------------
576 */
577 /*lint -esym(715, pEASData) reserved for future use */
SMF_Resume(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)578 EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
579 {
580 S_SMF_DATA *pSMFData;
581
582 /* can't resume a stopped stream */
583 pSMFData = (S_SMF_DATA*) pInstData;
584 if (pSMFData->state == EAS_STATE_STOPPED)
585 return EAS_ERROR_ALREADY_STOPPED;
586
587 /* nothing to do but resume playback */
588 pSMFData->state = EAS_STATE_PLAY;
589 return EAS_SUCCESS;
590 }
591
592 /*----------------------------------------------------------------------------
593 * SMF_SetData()
594 *----------------------------------------------------------------------------
595 * Purpose:
596 * Sets parser parameters
597 *
598 * Inputs:
599 * pEASData - pointer to overall EAS data structure
600 * handle - pointer to file handle
601 *
602 * Outputs:
603 *
604 *
605 * Side Effects:
606 *
607 *----------------------------------------------------------------------------
608 */
609 /*lint -esym(715, pEASData) reserved for future use */
SMF_SetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 value)610 EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
611 {
612 S_SMF_DATA *pSMFData;
613
614 pSMFData = (S_SMF_DATA*) pInstData;
615 switch (param)
616 {
617
618 /* set metadata callback */
619 case PARSER_DATA_METADATA_CB:
620 EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB));
621 break;
622
623 #ifdef JET_INTERFACE
624 /* set jet segment and track ID of all tracks for callback function */
625 case PARSER_DATA_JET_CB:
626 {
627 EAS_U32 i;
628 EAS_U32 bit = (EAS_U32) value;
629 bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK;
630 for (i = 0; i < pSMFData->numStreams; i++)
631 pSMFData->streams[i].midiStream.jetData =
632 (pSMFData->streams[i].midiStream.jetData &
633 ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) |
634 i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB;
635 pSMFData->flags |= SMF_FLAGS_JET_STREAM;
636 }
637 break;
638
639 /* set state of all mute flags at once */
640 case PARSER_DATA_MUTE_FLAGS:
641 {
642 EAS_INT i;
643 EAS_U32 bit = (EAS_U32) value;
644 for (i = 0; i < pSMFData->numStreams; i++)
645 {
646 if (bit & 1)
647 pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE;
648 else
649 pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE;
650 bit >>= 1;
651 }
652 }
653 break;
654
655 /* set track mute */
656 case PARSER_DATA_SET_MUTE:
657 if (value < pSMFData->numStreams)
658 pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE;
659 else
660 return EAS_ERROR_PARAMETER_RANGE;
661 break;
662
663 /* clear track mute */
664 case PARSER_DATA_CLEAR_MUTE:
665 if (value < pSMFData->numStreams)
666 pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE;
667 else
668 return EAS_ERROR_PARAMETER_RANGE;
669 break;
670 #endif
671
672 default:
673 return EAS_ERROR_INVALID_PARAMETER;
674 }
675
676 return EAS_SUCCESS;
677 }
678
679 /*----------------------------------------------------------------------------
680 * SMF_GetData()
681 *----------------------------------------------------------------------------
682 * Purpose:
683 * Retrieves parser parameters
684 *
685 * Inputs:
686 * pEASData - pointer to overall EAS data structure
687 * handle - pointer to file handle
688 *
689 * Outputs:
690 *
691 *
692 * Side Effects:
693 *
694 *----------------------------------------------------------------------------
695 */
696 /*lint -esym(715, pEASData) reserved for future use */
SMF_GetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 * pValue)697 EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
698 {
699 S_SMF_DATA *pSMFData;
700
701 pSMFData = (S_SMF_DATA*) pInstData;
702 switch (param)
703 {
704 /* return file type */
705 case PARSER_DATA_FILE_TYPE:
706 if (pSMFData->numStreams == 1)
707 *pValue = EAS_FILE_SMF0;
708 else
709 *pValue = EAS_FILE_SMF1;
710 break;
711
712 /* now handled in eas_public.c */
713 #if 0
714 case PARSER_DATA_POLYPHONY:
715 if (pSMFData->pSynth)
716 VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue);
717 else
718 return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
719 break;
720
721 case PARSER_DATA_PRIORITY:
722 if (pSMFData->pSynth)
723 VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue);
724 break;
725
726 /* set transposition */
727 case PARSER_DATA_TRANSPOSITION:
728 *pValue = pSMFData->transposition;
729 break;
730 #endif
731
732 case PARSER_DATA_SYNTH_HANDLE:
733 *pValue = (EAS_I32) pSMFData->pSynth;
734 break;
735
736 default:
737 return EAS_ERROR_INVALID_PARAMETER;
738 }
739
740 return EAS_SUCCESS;
741 }
742
743 /*----------------------------------------------------------------------------
744 * SMF_GetVarLenData()
745 *----------------------------------------------------------------------------
746 * Purpose:
747 * Reads a varible length quantity from an SMF file
748 *
749 * Inputs:
750 *
751 *
752 * Outputs:
753 *
754 *
755 * Side Effects:
756 *
757 *----------------------------------------------------------------------------
758 */
SMF_GetVarLenData(EAS_HW_DATA_HANDLE hwInstData,EAS_FILE_HANDLE fileHandle,EAS_U32 * pData)759 static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData)
760 {
761 EAS_RESULT result;
762 EAS_U32 data;
763 EAS_U8 c;
764
765 /* read until bit 7 is zero */
766 data = 0;
767 do
768 {
769 if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS)
770 return result;
771 data = (data << 7) | (c & 0x7f);
772 } while (c & 0x80);
773 *pData = data;
774 return EAS_SUCCESS;
775 }
776
777 /*----------------------------------------------------------------------------
778 * SMF_GetDeltaTime()
779 *----------------------------------------------------------------------------
780 * Purpose:
781 * Reads a varible length quantity from an SMF file
782 *
783 * Inputs:
784 *
785 *
786 * Outputs:
787 *
788 *
789 * Side Effects:
790 *
791 *----------------------------------------------------------------------------
792 */
SMF_GetDeltaTime(EAS_HW_DATA_HANDLE hwInstData,S_SMF_STREAM * pSMFStream)793 static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream)
794 {
795 EAS_RESULT result;
796 EAS_U32 ticks;
797
798 if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS)
799 return result;
800
801 pSMFStream->ticks += ticks;
802 return EAS_SUCCESS;
803 }
804
805 /*----------------------------------------------------------------------------
806 * SMF_ParseMetaEvent()
807 *----------------------------------------------------------------------------
808 * Purpose:
809 * Reads a varible length quantity from an SMF file
810 *
811 * Inputs:
812 *
813 *
814 * Outputs:
815 *
816 *
817 * Side Effects:
818 *
819 *----------------------------------------------------------------------------
820 */
SMF_ParseMetaEvent(S_EAS_DATA * pEASData,S_SMF_DATA * pSMFData,S_SMF_STREAM * pSMFStream)821 static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream)
822 {
823 EAS_RESULT result;
824 EAS_U32 len;
825 EAS_I32 pos;
826 EAS_U32 temp;
827 EAS_U8 c;
828
829 /* get the meta-event type */
830 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
831 return result;
832
833 /* get the length */
834 if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS)
835 return result;
836
837 /* get the current file position so we can skip the event */
838 if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS)
839 return result;
840
841 /* prevent a large unsigned length from being treated as a negative length */
842 if ((EAS_I32) len < 0) {
843 /* note that EAS_I32 is a long, which can be 64-bits on some computers */
844 ALOGE("%s() negative len = %ld", __func__, (long) len);
845 android_errorWriteLog(0x534e4554, "68953854");
846 return EAS_ERROR_FILE_FORMAT;
847 }
848 /* prevent numeric overflow caused by a very large len, assume pos > 0 */
849 const EAS_I32 EAS_I32_MAX = 0x7FFFFFFF;
850 if ((EAS_I32) len > (EAS_I32_MAX - pos)) {
851 ALOGE("%s() too large len = %ld", __func__, (long) len);
852 android_errorWriteLog(0x534e4554, "68953854");
853 return EAS_ERROR_FILE_FORMAT;
854 }
855
856 pos += (EAS_I32) len;
857
858 /* end of track? */
859 if (c == SMF_META_END_OF_TRACK)
860 {
861 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ }
862 pSMFStream->ticks = SMF_END_OF_TRACK;
863 }
864
865 /* tempo event? */
866 else if (c == SMF_META_TEMPO)
867 {
868 /* read the 3-byte timebase value */
869 temp = 0;
870 while (len--)
871 {
872 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
873 return result;
874 temp = (temp << 8) | c;
875 }
876
877 pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000);
878 pSMFData->flags |= SMF_FLAGS_HAS_TEMPO;
879 }
880
881 /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */
882 else if (c == SMF_META_TIME_SIGNATURE)
883 {
884 pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG;
885 }
886
887 /* if the host has registered a metadata callback return the metadata */
888 else if (pSMFData->metadata.callback)
889 {
890 EAS_I32 readLen;
891 E_EAS_METADATA_TYPE metaType;
892
893 metaType = EAS_METADATA_UNKNOWN;
894
895 /* only process title on the first track */
896 if (c == SMF_META_SEQTRK_NAME)
897 metaType = EAS_METADATA_TITLE;
898 else if (c == SMF_META_TEXT)
899 metaType = EAS_METADATA_TEXT;
900 else if (c == SMF_META_COPYRIGHT)
901 metaType = EAS_METADATA_COPYRIGHT;
902 else if (c == SMF_META_LYRIC)
903 metaType = EAS_METADATA_LYRIC;
904
905 if (metaType != EAS_METADATA_UNKNOWN)
906 {
907 readLen = pSMFData->metadata.bufferSize - 1;
908 if ((EAS_I32) len < readLen)
909 readLen = (EAS_I32) len;
910 if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS)
911 return result;
912 pSMFData->metadata.buffer[readLen] = 0;
913 pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData);
914 }
915 }
916
917 /* position file to next event - in case we ignored all or part of the meta-event */
918 if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS)
919 return result;
920
921 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ }
922 return EAS_SUCCESS;
923 }
924
925 /*----------------------------------------------------------------------------
926 * SMF_ParseSysEx()
927 *----------------------------------------------------------------------------
928 * Purpose:
929 * Reads a varible length quantity from an SMF file
930 *
931 * Inputs:
932 *
933 *
934 * Outputs:
935 *
936 *
937 * Side Effects:
938 *
939 *----------------------------------------------------------------------------
940 */
SMF_ParseSysEx(S_EAS_DATA * pEASData,S_SMF_DATA * pSMFData,S_SMF_STREAM * pSMFStream,EAS_U8 f0,EAS_INT parserMode)941 static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode)
942 {
943 EAS_RESULT result;
944 EAS_U32 len;
945 EAS_U8 c;
946
947 /* get the length */
948 if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS)
949 return result;
950
951 /* start of SysEx message? */
952 if (f0 == 0xf0)
953 {
954 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS)
955 return result;
956 }
957
958 /* feed the SysEx to the stream parser */
959 while (len--)
960 {
961 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
962 return result;
963 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
964 return result;
965
966 /* check for GM system ON */
967 if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON)
968 pSMFData->flags |= SMF_FLAGS_HAS_GM_ON;
969 }
970
971 return EAS_SUCCESS;
972 }
973
974 /*----------------------------------------------------------------------------
975 * SMF_ParseEvent()
976 *----------------------------------------------------------------------------
977 * Purpose:
978 * Reads a varible length quantity from an SMF file
979 *
980 * Inputs:
981 *
982 *
983 * Outputs:
984 *
985 *
986 * Side Effects:
987 *
988 *----------------------------------------------------------------------------
989 */
SMF_ParseEvent(S_EAS_DATA * pEASData,S_SMF_DATA * pSMFData,S_SMF_STREAM * pSMFStream,EAS_INT parserMode)990 static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode)
991 {
992 EAS_RESULT result;
993 EAS_U8 c;
994
995 /* get the event type */
996 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
997 return result;
998
999 /* parse meta-event */
1000 if (c == 0xff)
1001 {
1002 if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS)
1003 return result;
1004 }
1005
1006 /* parse SysEx */
1007 else if ((c == 0xf0) || (c == 0xf7))
1008 {
1009 if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS)
1010 return result;
1011 }
1012
1013 /* parse MIDI message */
1014 else
1015 {
1016 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
1017 return result;
1018
1019 /* keep streaming data to the MIDI parser until the message is complete */
1020 while (pSMFStream->midiStream.pending)
1021 {
1022 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
1023 return result;
1024 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
1025 return result;
1026 }
1027
1028 }
1029
1030 /* chase mode logic */
1031 if (pSMFData->time == 0)
1032 {
1033 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
1034 {
1035 if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE)
1036 pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE;
1037 }
1038 else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR)
1039 pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE;
1040 }
1041
1042 return EAS_SUCCESS;
1043 }
1044
1045 /*----------------------------------------------------------------------------
1046 * SMF_ParseHeader()
1047 *----------------------------------------------------------------------------
1048 * Purpose:
1049 * Parses the header of an SMF file, allocates memory the stream parsers and initializes the
1050 * stream parsers.
1051 *
1052 * Inputs:
1053 * pEASData - pointer to overall EAS data structure
1054 * pSMFData - pointer to parser instance data
1055 * fileHandle - file handle
1056 * fileOffset - offset in the file where the header data starts, usually 0
1057 *
1058 *
1059 * Outputs:
1060 *
1061 *
1062 * Side Effects:
1063 *
1064 *----------------------------------------------------------------------------
1065 */
1066 /*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */
SMF_ParseHeader(EAS_HW_DATA_HANDLE hwInstData,S_SMF_DATA * pSMFData)1067 EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData)
1068 {
1069 EAS_RESULT result;
1070 EAS_I32 i;
1071 EAS_U16 division;
1072 EAS_U16 numStreams;
1073 EAS_U32 chunkSize;
1074 EAS_U32 chunkStart;
1075 EAS_U32 temp;
1076 EAS_U32 ticks;
1077
1078 /* explicitly set numStreams to 0. It will later be used by SMF_Close to
1079 * determine whether we have valid streams or not. */
1080 pSMFData->numStreams = 0;
1081
1082 /* rewind the file and find the end of the header chunk */
1083 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS)
1084 goto ReadError;
1085 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS)
1086 goto ReadError;
1087
1088 /* determine the number of tracks */
1089 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS)
1090 goto ReadError;
1091 if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &numStreams, EAS_TRUE)) != EAS_SUCCESS)
1092 goto ReadError;
1093
1094 /* limit the number of tracks */
1095 if (numStreams > MAX_SMF_STREAMS)
1096 {
1097 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", numStreams, MAX_SMF_STREAMS); */ }
1098 numStreams = MAX_SMF_STREAMS;
1099 } else if (numStreams == 0)
1100 {
1101 /* avoid 0 sized allocation */
1102 return EAS_ERROR_PARAMETER_RANGE;
1103 }
1104
1105 /* get the time division */
1106 if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS)
1107 goto ReadError;
1108
1109 /* setup default timebase for 120 bpm */
1110 pSMFData->ppqn = 192;
1111 if (!division || division & 0x8000)
1112 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ }
1113 else
1114 pSMFData->ppqn = (division & 0x7fff);
1115 pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000);
1116
1117 /* dynamic memory allocation, allocate memory for streams */
1118 if (pSMFData->streams == NULL)
1119 {
1120 pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * numStreams);
1121 if (pSMFData->streams == NULL)
1122 return EAS_ERROR_MALLOC_FAILED;
1123
1124 /* zero the memory to insure complete initialization */
1125 EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * numStreams);
1126 }
1127 pSMFData->numStreams = numStreams;
1128
1129 /* find the start of each track */
1130 chunkStart = (EAS_U32) pSMFData->fileOffset;
1131 ticks = 0x7fffffffL;
1132 pSMFData->nextStream = NULL;
1133 for (i = 0; i < pSMFData->numStreams; i++)
1134 {
1135
1136 for (;;)
1137 {
1138
1139 /* calculate start of next chunk - checking for errors */
1140 temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize;
1141 if (temp <= chunkStart)
1142 {
1143 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ }
1144 return EAS_ERROR_FILE_FORMAT;
1145 }
1146 chunkStart = temp;
1147
1148 /* seek to the start of the next chunk */
1149 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS)
1150 goto ReadError;
1151
1152 /* read the chunk identifier */
1153 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS)
1154 goto ReadError;
1155
1156 /* read the chunk size */
1157 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS)
1158 goto ReadError;
1159
1160 /* make sure this is an 'MTrk' chunk */
1161 if (temp == SMF_CHUNK_TYPE_TRACK)
1162 break;
1163
1164 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ }
1165 }
1166
1167 /* initalize some data */
1168 pSMFData->streams[i].ticks = 0;
1169 pSMFData->streams[i].fileHandle = pSMFData->fileHandle;
1170
1171 /* NULL the file handle so we don't try to close it twice */
1172 pSMFData->fileHandle = NULL;
1173
1174 /* save this file position as the start of the track */
1175 pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE;
1176
1177 /* initalize the MIDI parser data */
1178 EAS_InitMIDIStream(&pSMFData->streams[i].midiStream);
1179
1180 /* parse the first delta time in each stream */
1181 if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS)
1182 goto ReadError;
1183
1184 if (pSMFData->streams[i].ticks < ticks)
1185 {
1186 ticks = pSMFData->streams[i].ticks;
1187 pSMFData->nextStream = &pSMFData->streams[i];
1188 }
1189
1190 /* more tracks to do, create a duplicate file handle */
1191 if (i < (pSMFData->numStreams - 1))
1192 {
1193 if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS)
1194 goto ReadError;
1195 }
1196 }
1197
1198 /* update the time of the next event */
1199 if (pSMFData->nextStream)
1200 SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks);
1201
1202 return EAS_SUCCESS;
1203
1204 /* ugly goto: but simpler than structured */
1205 ReadError:
1206 if (result == EAS_EOF)
1207 return EAS_ERROR_FILE_FORMAT;
1208 return result;
1209 }
1210
1211 /*----------------------------------------------------------------------------
1212 * SMF_UpdateTime()
1213 *----------------------------------------------------------------------------
1214 * Purpose:
1215 * Update the millisecond time base by converting the ticks into millieconds
1216 *
1217 * Inputs:
1218 *
1219 *
1220 * Outputs:
1221 *
1222 *
1223 * Side Effects:
1224 *
1225 *----------------------------------------------------------------------------
1226 */
SMF_UpdateTime(S_SMF_DATA * pSMFData,EAS_U32 ticks)1227 static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks)
1228 {
1229 EAS_U32 temp1, temp2;
1230
1231 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
1232 return;
1233
1234 temp1 = (ticks >> 10) * pSMFData->tickConv;
1235 temp2 = (ticks & 0x3ff) * pSMFData->tickConv;
1236 pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2));
1237 }
1238
1239