1/*----------------------------------------------------------------------------
2 *
3 * File:
4 * jet.c
5 *
6 * Contents and purpose:
7 * Implementation for JET sound engine
8 *
9 * Copyright (c) 2006 Sonic Network Inc.
10
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 *      http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 *----------------------------------------------------------------------------
23 * Revision Control:
24 *   $Revision: 563 $
25 *   $Date: 2007-02-13 20:26:23 -0800 (Tue, 13 Feb 2007) $
26 *----------------------------------------------------------------------------
27*/
28
29//#define LOG_NDEBUG 0
30#define LOG_TAG "JET_C"
31
32//#define DEBUG_JET
33
34#include "eas_data.h"
35#include "eas_smf.h"
36#include "jet_data.h"
37#include "eas_host.h"
38#include "eas_report.h"
39
40
41/* default configuration */
42static const S_JET_CONFIG jetDefaultConfig =
43{
44    JET_EVENT_APP_LOW,
45    JET_EVENT_APP_HIGH
46};
47
48/* function prototypes */
49extern EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value);
50extern EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream);
51extern EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_DLSLIB_HANDLE *ppDLS);
52
53/*----------------------------------------------------------------------------
54 * JET_ParseEvent()
55 *----------------------------------------------------------------------------
56 * Returns current status
57 *----------------------------------------------------------------------------
58*/
59EAS_PUBLIC void JET_ParseEvent (EAS_U32 event, S_JET_EVENT *pEvent)
60{
61    pEvent->segment = (EAS_U8) ((event & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT);
62    pEvent->track = (EAS_U8) ((event & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT);
63    pEvent->channel = (EAS_U8) ((event & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT);
64    pEvent->controller = (EAS_U8) ((event & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT);
65    pEvent->value = (EAS_U8) (event & JET_EVENT_VAL_MASK);
66}
67
68#ifdef DEBUG_JET
69/*----------------------------------------------------------------------------
70 * JET_DumpEvent
71 *----------------------------------------------------------------------------
72 * Advances queue read/write index
73 *----------------------------------------------------------------------------
74*/
75static void JET_DumpEvent (const char *procName, EAS_U32 event)
76{
77    S_JET_EVENT sEvent;
78    JET_ParseEvent(event, &sEvent);
79    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "%s: SegID=%d, TrkID=%d, channel=%d, ctrl=%d, val=%d\n",
80        procName, sEvent.segment, sEvent.track, sEvent.channel, sEvent.controller, sEvent.value); */ }
81}
82#endif
83
84/*----------------------------------------------------------------------------
85 * JET_IncQueueIndex
86 *----------------------------------------------------------------------------
87 * Advances queue read/write index
88 *----------------------------------------------------------------------------
89*/
90EAS_INLINE EAS_U8 JET_IncQueueIndex (EAS_U8 index, EAS_U8 queueSize)
91{
92    if (++index == queueSize)
93        index = 0;
94    return index;
95}
96
97/*----------------------------------------------------------------------------
98 * JET_WriteQueue
99 *----------------------------------------------------------------------------
100 * Save event to queue
101 *----------------------------------------------------------------------------
102*/
103EAS_INLINE void JET_WriteQueue (EAS_U32 *pEventQueue, EAS_U8 *pWriteIndex, EAS_U8 readIndex, EAS_U8 queueSize, EAS_U32 event)
104{
105    EAS_U8 temp;
106
107    /* check for queue overflow */
108    temp = JET_IncQueueIndex(*pWriteIndex, queueSize);
109    if (temp == readIndex)
110    {
111        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "JET_Event: Event queue overflow --- event ignored!\n"); */ }
112        return;
113    }
114
115    /* save in queue and advance write index */
116    pEventQueue[*pWriteIndex] = event;
117    *pWriteIndex = temp;
118}
119
120/*----------------------------------------------------------------------------
121 * JET_ReadQueue
122 *----------------------------------------------------------------------------
123 * Read event to queue
124 *----------------------------------------------------------------------------
125*/
126EAS_INLINE EAS_BOOL JET_ReadQueue (EAS_U32 *pEventQueue, EAS_U8 *pReadIndex, EAS_U8 writeIndex, EAS_U8 queueSize, EAS_U32 *pEvent)
127{
128
129    /* check for empty queue */
130    if (*pReadIndex == writeIndex)
131        return EAS_FALSE;
132
133    /* save in queue and advance write index */
134    *pEvent = pEventQueue[*pReadIndex];
135    *pReadIndex = JET_IncQueueIndex(*pReadIndex, queueSize);
136    return EAS_TRUE;
137}
138
139/*----------------------------------------------------------------------------
140 * JET_NextSegment
141 *----------------------------------------------------------------------------
142 * Advances segment number
143 *----------------------------------------------------------------------------
144*/
145EAS_INLINE EAS_INT JET_NextSegment (EAS_INT seg_num)
146{
147    if (++seg_num == SEG_QUEUE_DEPTH)
148        seg_num = 0;
149    return seg_num;
150}
151
152/*----------------------------------------------------------------------------
153 * JET_PrepareSegment()
154 *----------------------------------------------------------------------------
155 * Prepare a segment for playback
156 *----------------------------------------------------------------------------
157*/
158static EAS_RESULT JET_PrepareSegment (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum)
159{
160    EAS_RESULT result;
161    S_JET_SEGMENT *p;
162
163    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_PrepareSegment: %d\n", queueNum); */ }
164
165    p = &easHandle->jetHandle->segQueue[queueNum];
166    result = EAS_Prepare(easHandle, p->streamHandle);
167    if (result != EAS_SUCCESS)
168        return result;
169
170    /* pause segment - must be triggered by play or end of previous segment */
171    result = EAS_Pause(easHandle, p->streamHandle);
172    if (result != EAS_SUCCESS)
173        return result;
174    p->state = JET_STATE_READY;
175
176    /* set calback data */
177    result = EAS_IntSetStrmParam(easHandle, p->streamHandle, PARSER_DATA_JET_CB, queueNum);
178    if (result != EAS_SUCCESS)
179        return result;
180
181    /* set DLS collection */
182    if (p->libNum >= 0)
183    {
184        result = EAS_IntSetStrmParam(easHandle, p->streamHandle,
185            PARSER_DATA_DLS_COLLECTION, (EAS_I32) easHandle->jetHandle->libHandles[p->libNum]);
186        if (result != EAS_SUCCESS)
187            return result;
188    }
189
190    /* set transposition */
191    if (p->transpose)
192    {
193        result = EAS_SetTransposition(easHandle, p->streamHandle, p->transpose);
194        if (result != EAS_SUCCESS)
195            return result;
196    }
197
198    return result;
199}
200
201/*----------------------------------------------------------------------------
202 * JET_StartPlayback()
203 *----------------------------------------------------------------------------
204 * Start segment playback
205 *----------------------------------------------------------------------------
206*/
207static EAS_RESULT JET_StartPlayback (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum)
208{
209    EAS_RESULT result = EAS_SUCCESS;
210    S_JET_SEGMENT *pSeg;
211
212    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_StartPlayback %d\n", queueNum); */ }
213
214    /* if next segment is queued, start playback */
215    pSeg = &easHandle->jetHandle->segQueue[queueNum];
216    if (pSeg->streamHandle != NULL)
217    {
218        result = EAS_Resume(easHandle, pSeg->streamHandle);
219        easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_PLAYING;
220
221        /* set mute flags */
222        if ((result == EAS_SUCCESS) && (pSeg->muteFlags != 0))
223            result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags);
224    }
225    return result;
226}
227
228/*----------------------------------------------------------------------------
229 * JET_CloseSegment
230 *----------------------------------------------------------------------------
231 * Closes stream associated with a segment
232 *----------------------------------------------------------------------------
233*/
234EAS_INLINE EAS_INT JET_CloseSegment (EAS_DATA_HANDLE easHandle, EAS_INT queueNum)
235{
236    EAS_RESULT result;
237
238    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_CloseSegment %d\n", queueNum); */ }
239
240    /* close the segment */
241    result = EAS_CloseFile(easHandle, easHandle->jetHandle->segQueue[queueNum].streamHandle);
242    if (result != EAS_SUCCESS)
243        return result;
244
245    easHandle->jetHandle->segQueue[queueNum].streamHandle = NULL;
246    easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_CLOSED;
247    easHandle->jetHandle->numQueuedSegments--;
248    return result;
249}
250
251/*----------------------------------------------------------------------------
252 * JetParseInfoChunk()
253 *----------------------------------------------------------------------------
254 * Parses the JET info chunk
255 *----------------------------------------------------------------------------
256*/
257static EAS_RESULT JetParseInfoChunk (EAS_DATA_HANDLE easHandle, EAS_I32 pos, EAS_I32 chunkSize)
258{
259    EAS_RESULT result;
260    EAS_U32 infoType;
261    EAS_U32 temp;
262
263    /* offset to data */
264    result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos);
265    if (result != EAS_SUCCESS)
266        return result;
267
268    /* read the entire chunk */
269    result = EAS_SUCCESS;
270    while ((result == EAS_SUCCESS) && (chunkSize > 0))
271    {
272
273        /* get info infoType */
274        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &infoType, EAS_TRUE);
275        if (result != EAS_SUCCESS)
276            break;
277
278        /* get info field */
279        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &temp, EAS_FALSE);
280        if (result == EAS_SUCCESS)
281
282        switch (infoType)
283        {
284            case INFO_NUM_SMF_CHUNKS:
285                if (temp >= JET_MAX_SEGMENTS) {
286                    return EAS_ERROR_INCOMPATIBLE_VERSION;
287                }
288                easHandle->jetHandle->numSegments = (EAS_U8) temp;
289                break;
290
291            case INFO_NUM_DLS_CHUNKS:
292                if (temp >= JET_MAX_DLS_COLLECTIONS) {
293                    return EAS_ERROR_INCOMPATIBLE_VERSION;
294                }
295                easHandle->jetHandle->numLibraries = (EAS_U8) temp;
296                break;
297
298            case INFO_JET_VERSION:
299                /* check major version number */
300                if ((temp & 0xff000000) != (JET_VERSION & 0xff000000))
301                    return EAS_ERROR_INCOMPATIBLE_VERSION;
302                break;
303
304            default:
305                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET info type 0x%08x", infoType); */ }
306                break;
307        }
308
309        chunkSize -= 8;
310    }
311
312    /* allocate pointers for chunks to follow */
313
314    return result;
315}
316
317/*----------------------------------------------------------------------------
318 * JET_OpenFile()
319 *----------------------------------------------------------------------------
320 * Opens a JET content file for playback
321 *----------------------------------------------------------------------------
322*/
323EAS_PUBLIC EAS_RESULT JET_OpenFile (EAS_DATA_HANDLE easHandle, EAS_FILE_LOCATOR locator)
324{
325    EAS_RESULT result;
326    EAS_U32 chunkType;
327    EAS_I32 pos;
328    EAS_I32 chunkSize;
329    EAS_INT smfChunkNum;
330    EAS_INT dlsChunkNum;
331    EAS_I32 dataSize = 0; /* make lint happy */
332
333    /* make sure that we don't have an open file */
334    if (easHandle->jetHandle->jetFileHandle != NULL)
335        return EAS_ERROR_FILE_ALREADY_OPEN;
336
337    /* open the media file */
338    result = EAS_HWOpenFile(easHandle->hwInstData, locator, &easHandle->jetHandle->jetFileHandle, EAS_FILE_READ);
339    if (result != EAS_SUCCESS)
340        return result;
341
342    /* check header */
343    result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE);
344    if (result == EAS_SUCCESS)
345    {
346        if (chunkType != JET_HEADER_TAG)
347        {
348            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "File is not JET format\n"); */ }
349            result = EAS_ERROR_UNRECOGNIZED_FORMAT;
350        }
351    }
352    /* get the file data size */
353    if (result == EAS_SUCCESS)
354        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &dataSize, EAS_FALSE);
355
356    /* parse through the file to find contents */
357    smfChunkNum = dlsChunkNum = 0;
358    pos = chunkSize = 8;
359    while ((result == EAS_SUCCESS) && (pos < dataSize))
360    {
361
362        /* offset to chunk data */
363        result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos);
364        if (result != EAS_SUCCESS)
365            break;
366
367        /* get chunk size and type */
368        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE);
369        if (result != EAS_SUCCESS)
370            break;
371
372        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkSize, EAS_FALSE);
373        if (result != EAS_SUCCESS)
374            break;
375        pos += 8;
376
377        switch (chunkType)
378        {
379            case JET_INFO_CHUNK:
380                result = JetParseInfoChunk(easHandle, pos, chunkSize);
381                break;
382
383            case JET_SMF_CHUNK:
384                if (smfChunkNum < easHandle->jetHandle->numSegments)
385                    easHandle->jetHandle->segmentOffsets[smfChunkNum++] = pos;
386                else
387                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous SMF chunk"); */ }
388                break;
389
390            case JET_DLS_CHUNK:
391                if (dlsChunkNum < easHandle->jetHandle->numLibraries)
392                    result = DLSParser(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos, &easHandle->jetHandle->libHandles[dlsChunkNum++]);
393                else
394                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous DLS chunk"); */ }
395                break;
396
397            case JET_APP_DATA_CHUNK:
398                easHandle->jetHandle->appDataOffset = pos;
399                easHandle->jetHandle->appDataSize = chunkSize;
400                break;
401
402            case INFO_JET_COPYRIGHT:
403                break;
404
405            default:
406                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET chunk type 0x%08x", chunkType); */ }
407                break;
408        }
409
410        /* offset to next chunk */
411        pos += chunkSize;
412    }
413
414    /* close file if something went wrong */
415    if (result != EAS_SUCCESS)
416        EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle);
417
418    return result;
419}
420
421/*----------------------------------------------------------------------------
422 * JET_GetAppData()
423 *----------------------------------------------------------------------------
424 * Returns location and size of application data in the JET file
425 *----------------------------------------------------------------------------
426*/
427EAS_RESULT JET_GetAppData (EAS_DATA_HANDLE easHandle, EAS_I32 *pAppDataOffset, EAS_I32 *pAppDataSize)
428{
429
430    /* check for app chunk */
431    if (easHandle->jetHandle->appDataSize == 0)
432    {
433        *pAppDataOffset = *pAppDataSize = 0;
434        return EAS_FAILURE;
435    }
436
437    /* return app data */
438    *pAppDataOffset = easHandle->jetHandle->appDataOffset;
439    *pAppDataSize = easHandle->jetHandle->appDataSize;
440    return EAS_SUCCESS;
441}
442
443/*----------------------------------------------------------------------------
444 * JET_CloseFile()
445 *----------------------------------------------------------------------------
446 * Closes a JET content file and releases associated resources
447 *----------------------------------------------------------------------------
448*/
449EAS_PUBLIC EAS_RESULT JET_CloseFile (EAS_DATA_HANDLE easHandle)
450{
451    EAS_INT index;
452    EAS_RESULT result = EAS_SUCCESS;
453
454    /* close open streams */
455    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
456    {
457        if (easHandle->jetHandle->segQueue[index].streamHandle != NULL)
458        {
459            result = JET_CloseSegment(easHandle, index);
460            if (result != EAS_SUCCESS)
461                break;
462        }
463    }
464
465    /* close the main file handle */
466    if ((result == EAS_SUCCESS) && (easHandle->jetHandle->jetFileHandle != NULL))
467    {
468        result = EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle);
469        if (result == EAS_SUCCESS)
470            easHandle->jetHandle->jetFileHandle = NULL;
471    }
472    return result;
473}
474
475/*----------------------------------------------------------------------------
476 * JET_Init()
477 *----------------------------------------------------------------------------
478 * Initializes the JET library, allocates memory, etc. Call
479 * JET_Shutdown to de-allocate memory.
480 *----------------------------------------------------------------------------
481*/
482EAS_PUBLIC EAS_RESULT JET_Init (EAS_DATA_HANDLE easHandle, const S_JET_CONFIG *pConfig, EAS_INT configSize)
483{
484    S_JET_DATA *pJet;
485    EAS_U8 flags = 0;
486
487    /* sanity check */
488    if (easHandle == NULL)
489        return EAS_ERROR_HANDLE_INTEGRITY;
490    if (easHandle->jetHandle != NULL)
491        return EAS_ERROR_FEATURE_ALREADY_ACTIVE;
492    if (pConfig == NULL)
493        pConfig = &jetDefaultConfig;
494
495    /* allocate the JET data object */
496    pJet = EAS_HWMalloc(easHandle->hwInstData, sizeof(S_JET_DATA));
497    if (pJet == NULL)
498        return EAS_ERROR_MALLOC_FAILED;
499
500    /* initialize JET data structure */
501    EAS_HWMemSet(pJet, 0, sizeof(S_JET_DATA));
502    easHandle->jetHandle = pJet;
503    pJet->flags = flags;
504
505    /* copy config data */
506    if (configSize > (EAS_INT) sizeof(S_JET_CONFIG))
507        configSize = sizeof(S_JET_CONFIG);
508    EAS_HWMemCpy(&pJet->config, pConfig, configSize);
509    return EAS_SUCCESS;
510}
511
512/*----------------------------------------------------------------------------
513 * JET_Shutdown()
514 *----------------------------------------------------------------------------
515 * Frees any memory used by the JET library
516 *----------------------------------------------------------------------------
517*/
518EAS_PUBLIC EAS_RESULT JET_Shutdown (EAS_DATA_HANDLE easHandle)
519{
520    EAS_RESULT result;
521
522    /* close any open files */
523    result = JET_CloseFile(easHandle);
524
525    /* free allocated data */
526    EAS_HWFree(easHandle->hwInstData, easHandle->jetHandle);
527    easHandle->jetHandle = NULL;
528    return result;
529}
530
531/*----------------------------------------------------------------------------
532 * JET_Status()
533 *----------------------------------------------------------------------------
534 * Returns current status
535 *----------------------------------------------------------------------------
536*/
537EAS_PUBLIC EAS_RESULT JET_Status (EAS_DATA_HANDLE easHandle, S_JET_STATUS *pStatus)
538{
539    S_JET_SEGMENT *pSeg;
540
541    pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment];
542    if (pSeg->streamHandle != NULL)
543    {
544        pStatus->currentUserID = pSeg->userID;
545        pStatus->segmentRepeatCount = pSeg->repeatCount;
546    }
547    else
548    {
549        pStatus->currentUserID = -1;
550        pStatus->segmentRepeatCount = 0;
551    }
552
553    pStatus->paused = !(easHandle->jetHandle->flags & JET_FLAGS_PLAYING);
554    pStatus->numQueuedSegments = easHandle->jetHandle->numQueuedSegments;
555    pStatus->currentPlayingSegment = easHandle->jetHandle->playSegment;
556    pStatus->currentQueuedSegment = easHandle->jetHandle->queueSegment;
557    if (pSeg->streamHandle != NULL)
558    {
559        EAS_RESULT result;
560        EAS_I32 location ;
561        if ((result = EAS_GetLocation(easHandle, pSeg->streamHandle, &location)) == EAS_SUCCESS)
562            if(location != 0)
563            {
564                pStatus->location = location;
565            }
566    }
567    return EAS_SUCCESS;
568}
569
570/*----------------------------------------------------------------------------
571 * JET_GetEvent()
572 *----------------------------------------------------------------------------
573 * Checks for application events
574 *----------------------------------------------------------------------------
575*/
576EAS_PUBLIC EAS_BOOL JET_GetEvent (EAS_DATA_HANDLE easHandle, EAS_U32 *pEventRaw, S_JET_EVENT *pEvent)
577{
578    EAS_U32 jetEvent;
579    EAS_BOOL gotEvent;
580
581    /* process event queue */
582    gotEvent = JET_ReadQueue(easHandle->jetHandle->appEventQueue,
583        &easHandle->jetHandle->appEventQueueRead,
584        easHandle->jetHandle->appEventQueueWrite,
585        APP_EVENT_QUEUE_SIZE, &jetEvent);
586
587    if (gotEvent)
588    {
589        if (pEventRaw != NULL)
590            *pEventRaw = jetEvent;
591
592        if (pEvent != NULL)
593            JET_ParseEvent(jetEvent, pEvent);
594    }
595
596    return gotEvent;
597}
598
599/*----------------------------------------------------------------------------
600 * JET_QueueSegment()
601 *----------------------------------------------------------------------------
602 * Queue a segment for playback
603 *----------------------------------------------------------------------------
604*/
605EAS_PUBLIC EAS_RESULT JET_QueueSegment (EAS_DATA_HANDLE easHandle, EAS_INT segmentNum, EAS_INT libNum, EAS_INT repeatCount, EAS_INT transpose, EAS_U32 muteFlags, EAS_U8 userID)
606{
607    EAS_FILE_HANDLE fileHandle;
608    EAS_RESULT result;
609    S_JET_SEGMENT *p;
610
611    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_QueueSegment segNum=%d, queue=%d\n", segmentNum, easHandle->jetHandle->queueSegment); */ }
612
613    /* make sure it's a valid segment */
614    if (segmentNum >= easHandle->jetHandle->numSegments)
615        return EAS_ERROR_PARAMETER_RANGE;
616
617    /* make sure it's a valid DLS */
618    if (libNum >= easHandle->jetHandle->numLibraries)
619        return EAS_ERROR_PARAMETER_RANGE;
620
621    /* check to see if queue is full */
622    p = &easHandle->jetHandle->segQueue[easHandle->jetHandle->queueSegment];
623    if (p->streamHandle != NULL)
624        return EAS_ERROR_QUEUE_IS_FULL;
625
626    /* initialize data */
627    p->userID = userID;
628    p->repeatCount = (EAS_I16) repeatCount;
629    p->transpose = (EAS_I8) transpose;
630    p->libNum = (EAS_I8) libNum;
631    p->muteFlags = muteFlags;
632    p->state = JET_STATE_CLOSED;
633
634    /* open the file */
635    result = EAS_OpenJETStream(easHandle, easHandle->jetHandle->jetFileHandle, easHandle->jetHandle->segmentOffsets[segmentNum], &p->streamHandle);
636    if (result != EAS_SUCCESS)
637        return result;
638    p->state = JET_STATE_OPEN;
639
640    /* if less than SEG_QUEUE_DEPTH segments queued up, prepare file for playback */
641    if (++easHandle->jetHandle->numQueuedSegments < SEG_QUEUE_DEPTH)
642    {
643        result = JET_PrepareSegment(easHandle, easHandle->jetHandle->queueSegment);
644        if (result != EAS_SUCCESS)
645            return result;
646    }
647
648    /* create duplicate file handle */
649    result = EAS_HWDupHandle(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &fileHandle);
650    if (result != EAS_SUCCESS)
651        return result;
652
653    easHandle->jetHandle->jetFileHandle = fileHandle;
654    easHandle->jetHandle->queueSegment = (EAS_U8) JET_NextSegment(easHandle->jetHandle->queueSegment);
655    return result;
656}
657
658/*----------------------------------------------------------------------------
659 * JET_Play()
660 *----------------------------------------------------------------------------
661 * Starts playback of the file
662 *----------------------------------------------------------------------------
663*/
664EAS_PUBLIC EAS_RESULT JET_Play (EAS_DATA_HANDLE easHandle)
665{
666    EAS_RESULT result;
667    EAS_INT index;
668    EAS_INT count = 0;
669
670    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Play\n"); */ }
671
672    /* sanity check */
673    if (easHandle->jetHandle->flags & JET_FLAGS_PLAYING)
674        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
675
676    /* resume all paused streams */
677    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
678    {
679        if (((index == easHandle->jetHandle->playSegment) && (easHandle->jetHandle->segQueue[index].state == JET_STATE_READY)) ||
680            (easHandle->jetHandle->segQueue[index].state == JET_STATE_PAUSED))
681        {
682            result = JET_StartPlayback(easHandle, index);
683            if (result != EAS_SUCCESS)
684                return result;
685            count++;
686        }
687    }
688
689    /* if no streams are playing, return error */
690    if (!count)
691        return EAS_ERROR_QUEUE_IS_EMPTY;
692
693    easHandle->jetHandle->flags |= JET_FLAGS_PLAYING;
694    return EAS_SUCCESS;
695}
696
697/*----------------------------------------------------------------------------
698 * JET_Pause()
699 *----------------------------------------------------------------------------
700 * Pauses playback of the file
701 *----------------------------------------------------------------------------
702*/
703EAS_PUBLIC EAS_RESULT JET_Pause (EAS_DATA_HANDLE easHandle)
704{
705    EAS_RESULT result;
706    EAS_INT index;
707    EAS_INT count = 0;
708
709    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Pause\n"); */ }
710
711    /* sanity check */
712    if ((easHandle->jetHandle->flags & JET_FLAGS_PLAYING) == 0)
713        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
714
715    /* pause all playing streams */
716    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
717    {
718        if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING)
719        {
720            result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle);
721            if (result != EAS_SUCCESS)
722                return result;
723            easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].state = JET_STATE_PAUSED;
724            count++;
725        }
726    }
727
728    /* if no streams are paused, return error */
729    if (!count)
730        return EAS_ERROR_QUEUE_IS_EMPTY;
731
732    easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING;
733    return EAS_SUCCESS;
734}
735
736/*----------------------------------------------------------------------------
737 * JET_SetMuteFlags()
738 *----------------------------------------------------------------------------
739 * Change the state of the mute flags
740 *----------------------------------------------------------------------------
741*/
742EAS_PUBLIC EAS_RESULT JET_SetMuteFlags (EAS_DATA_HANDLE easHandle, EAS_U32 muteFlags, EAS_BOOL sync)
743{
744    S_JET_SEGMENT *pSeg;
745
746    /* get pointer to current segment */
747    pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment];
748
749    /* unsynchronized mute, set flags and return */
750    if (!sync)
751    {
752        if (pSeg->streamHandle == NULL)
753            return EAS_ERROR_QUEUE_IS_EMPTY;
754        pSeg->muteFlags = muteFlags;
755        return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) muteFlags);
756    }
757
758
759    /* check for valid stream state */
760    if (pSeg->state == JET_STATE_CLOSED)
761        return EAS_ERROR_QUEUE_IS_EMPTY;
762
763    /* save mute flags */
764    pSeg->muteFlags = muteFlags;
765
766    /* if repeating segment, set mute update flag */
767    if (sync)
768        pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE;
769    return EAS_SUCCESS;
770}
771
772/*----------------------------------------------------------------------------
773 * JET_SetMuteFlag()
774 *----------------------------------------------------------------------------
775 * Change the state of a single mute flag
776 *----------------------------------------------------------------------------
777*/
778EAS_PUBLIC EAS_RESULT JET_SetMuteFlag (EAS_DATA_HANDLE easHandle, EAS_INT trackNum, EAS_BOOL muteFlag, EAS_BOOL sync)
779{
780    S_JET_SEGMENT *pSeg;
781    EAS_U32 trackMuteFlag;
782
783
784    /* setup flag */
785    if ((trackNum < 0) || (trackNum > 31))
786        return EAS_ERROR_PARAMETER_RANGE;
787    trackMuteFlag = (1 << trackNum);
788
789    /* get pointer to current segment */
790    pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment];
791
792    /* unsynchronized mute, set flags and return */
793    if (!sync)
794    {
795        if (pSeg->streamHandle == NULL)
796            return EAS_ERROR_QUEUE_IS_EMPTY;
797        if (muteFlag)
798            pSeg->muteFlags |= trackMuteFlag;
799        else
800            pSeg->muteFlags &= ~trackMuteFlag;
801        return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags);
802    }
803
804
805    /* check for valid stream state */
806    if (pSeg->state == JET_STATE_CLOSED)
807        return EAS_ERROR_QUEUE_IS_EMPTY;
808
809    /* save mute flags and set mute update flag */
810    if (muteFlag)
811        pSeg->muteFlags |= trackMuteFlag;
812    else
813        pSeg->muteFlags &= ~trackMuteFlag;
814    pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE;
815    return EAS_SUCCESS;
816}
817
818/*----------------------------------------------------------------------------
819 * JET_TriggerClip()
820 *----------------------------------------------------------------------------
821 * Unmute a track and then mute it when it is complete. If a clip
822 * is already playing, change mute event to a trigger event. The
823 * JET_Event function will not mute the clip, but will allow it
824 * to continue playing through the next clip.
825 *
826 * NOTE: We use bit 7 to indicate an entry in the queue. For a
827 * small queue, it is cheaper in both memory and CPU cycles to
828 * scan the entire queue for non-zero events than keep enqueue
829 * and dequeue indices.
830 *----------------------------------------------------------------------------
831*/
832EAS_PUBLIC EAS_RESULT JET_TriggerClip (EAS_DATA_HANDLE easHandle, EAS_INT clipID)
833{
834    EAS_INT i;
835    EAS_INT index = -1;
836
837    /* check for valid clipID */
838    if ((clipID < 0) || (clipID > 63))
839        return EAS_ERROR_PARAMETER_RANGE;
840
841    /* set active flag */
842    clipID |= JET_CLIP_ACTIVE_FLAG;
843
844    /* Reverse the search so that we get the first empty element */
845    for (i = JET_MUTE_QUEUE_SIZE-1; i >= 0 ; i--)
846    {
847        if (easHandle->jetHandle->muteQueue[i] == clipID)
848        {
849            index = i;
850            break;
851        }
852        if (easHandle->jetHandle->muteQueue[i] == 0)
853            index = i;
854    }
855    if (index < 0)
856        return EAS_ERROR_QUEUE_IS_FULL;
857
858    easHandle->jetHandle->muteQueue[index] = (EAS_U8) clipID | JET_CLIP_TRIGGER_FLAG;
859    return EAS_SUCCESS;
860}
861
862/*----------------------------------------------------------------------------
863 * JET_Process()
864 *----------------------------------------------------------------------------
865 * Called during EAS_Render to process stream states
866 *----------------------------------------------------------------------------
867*/
868EAS_PUBLIC EAS_RESULT JET_Process (EAS_DATA_HANDLE easHandle)
869{
870    S_JET_SEGMENT *pSeg;
871    EAS_STATE state;
872    EAS_INT index;
873    EAS_INT playIndex;
874    EAS_RESULT result = EAS_SUCCESS;
875    EAS_BOOL endOfLoop = EAS_FALSE;
876    EAS_BOOL startNextSegment = EAS_FALSE;
877    EAS_BOOL prepareNextSegment = EAS_FALSE;
878    EAS_U32 jetEvent;
879
880    /* process event queue */
881    while (JET_ReadQueue(easHandle->jetHandle->jetEventQueue,
882        &easHandle->jetHandle->jetEventQueueRead,
883        easHandle->jetHandle->jetEventQueueWrite,
884        JET_EVENT_QUEUE_SIZE, &jetEvent))
885    {
886        S_JET_EVENT event;
887#ifdef DEBUG_JET
888        JET_DumpEvent("JET_Process", jetEvent);
889#endif
890        JET_ParseEvent(jetEvent, &event);
891
892        /* check for end of loop */
893        if ((event.controller == JET_EVENT_MARKER) &&
894                (event.value == JET_MARKER_LOOP_END) &&
895                (easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle != NULL))
896            endOfLoop = EAS_TRUE;
897    }
898
899    /* check state of all streams */
900    index = playIndex = easHandle->jetHandle->playSegment;
901    for (;;)
902    {
903        pSeg = &easHandle->jetHandle->segQueue[index];
904        if (pSeg->state != JET_STATE_CLOSED)
905        {
906
907            /* get playback state */
908            result = EAS_State(easHandle, pSeg->streamHandle, &state);
909            if (result != EAS_SUCCESS)
910                return result;
911
912            /* process state */
913            switch (pSeg->state)
914            {
915                /* take action if this segment is stopping */
916                case JET_STATE_PLAYING:
917                    if (endOfLoop || (state == EAS_STATE_STOPPING) || (state == EAS_STATE_STOPPED))
918                    {
919                        /* handle repeats */
920                        if (pSeg->repeatCount != 0)
921                        {
922                            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render repeating segment %d\n", index); */ }
923                            result = EAS_Locate(easHandle, pSeg->streamHandle, 0, EAS_FALSE);
924                            if (result != EAS_SUCCESS)
925                                return result;
926                            if (pSeg->repeatCount > 0)
927                                pSeg->repeatCount--;
928
929                            /* update mute flags if necessary */
930                            if (pSeg->flags & JET_SEG_FLAG_MUTE_UPDATE)
931                            {
932                                result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags);
933                                if (result != EAS_SUCCESS)
934                                    return result;
935                                pSeg->flags &= ~JET_SEG_FLAG_MUTE_UPDATE;
936                            }
937
938                        }
939                        /* no repeat, start next segment */
940                        else
941                        {
942                            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render stopping queue %d\n", index); */ }
943                            startNextSegment = EAS_TRUE;
944                            pSeg->state = JET_STATE_STOPPING;
945                            easHandle->jetHandle->playSegment = (EAS_U8) JET_NextSegment(index);
946                        }
947                    }
948                    break;
949
950                /* if playback has stopped, close the segment */
951                case JET_STATE_STOPPING:
952                    if (state == EAS_STATE_STOPPED)
953                    {
954                        result = JET_CloseSegment(easHandle, index);
955                        if (result != EAS_SUCCESS)
956                            return result;
957                    }
958                    break;
959
960                case JET_STATE_READY:
961                    if (startNextSegment)
962                    {
963                        result = JET_StartPlayback(easHandle, index);
964                        if (result != EAS_SUCCESS)
965                            return result;
966                        startNextSegment = EAS_FALSE;
967                        prepareNextSegment = EAS_TRUE;
968                    }
969                    break;
970
971                case JET_STATE_OPEN:
972                    if (prepareNextSegment)
973                    {
974                        result = JET_PrepareSegment(easHandle, index);
975                        if (result != EAS_SUCCESS)
976                            return result;
977                        prepareNextSegment = EAS_FALSE;
978                    }
979                    break;
980
981                case JET_STATE_PAUSED:
982                    break;
983
984                default:
985                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "JET_Render: Unexpected segment state %d\n", pSeg->state); */ }
986                    break;
987            }
988        }
989
990        /* increment index */
991        index = JET_NextSegment(index);
992        if (index == playIndex)
993            break;
994    }
995
996    /* if out of segments, clear playing flag */
997    if (easHandle->jetHandle->numQueuedSegments == 0)
998        easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING;
999
1000    return result;
1001}
1002
1003/*----------------------------------------------------------------------------
1004 * JET_Event()
1005 *----------------------------------------------------------------------------
1006 * Called from MIDI parser when data of interest is received
1007 *----------------------------------------------------------------------------
1008*/
1009void JET_Event (EAS_DATA_HANDLE easHandle, EAS_U32 segTrack, EAS_U8 channel, EAS_U8 controller, EAS_U8 value)
1010{
1011    EAS_U32 event;
1012
1013    if (easHandle->jetHandle == NULL)
1014        return;
1015
1016    /* handle triggers */
1017    if (controller == JET_EVENT_TRIGGER_CLIP)
1018    {
1019        S_JET_SEGMENT *pSeg;
1020        EAS_INT i;
1021        EAS_U32 muteFlag;
1022
1023        for (i = 0; i < JET_MUTE_QUEUE_SIZE; i++)
1024        {
1025            /* search for event in queue */
1026            if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_ID_MASK) == (value & JET_CLIP_ID_MASK))
1027            {
1028                /* get segment pointer and mute flag */
1029                pSeg = &easHandle->jetHandle->segQueue[segTrack >> JET_EVENT_SEG_SHIFT];
1030                muteFlag = 1 << ((segTrack & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT);
1031
1032                /* un-mute the track */
1033                if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_TRIGGER_FLAG) && ((value & 0x40) > 0))
1034                {
1035                    pSeg->muteFlags &= ~muteFlag;
1036                    easHandle->jetHandle->muteQueue[i] &= ~JET_CLIP_TRIGGER_FLAG;
1037                }
1038
1039                /* mute the track */
1040                else
1041                {
1042                    EAS_U32 beforeMute ;
1043                    beforeMute = pSeg->muteFlags ;
1044                    pSeg->muteFlags |= muteFlag;
1045                    if (beforeMute != pSeg->muteFlags)
1046                        easHandle->jetHandle->muteQueue[i] = 0;
1047                }
1048                EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags);
1049                return;
1050            }
1051        }
1052        return;
1053    }
1054
1055    /* generic event stuff */
1056    event = (channel << JET_EVENT_CHAN_SHIFT) | (controller << JET_EVENT_CTRL_SHIFT) | value;
1057
1058    /* write to app queue, translate queue index to segment number */
1059    if ((controller >= easHandle->jetHandle->config.appEventRangeLow) && (controller <= easHandle->jetHandle->config.appEventRangeHigh))
1060    {
1061
1062        event |= easHandle->jetHandle->segQueue[(segTrack & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT].userID << JET_EVENT_SEG_SHIFT;
1063#ifdef DEBUG_JET
1064        JET_DumpEvent("JET_Event[app]", event);
1065#endif
1066        JET_WriteQueue(easHandle->jetHandle->appEventQueue,
1067            &easHandle->jetHandle->appEventQueueWrite,
1068            easHandle->jetHandle->appEventQueueRead,
1069            APP_EVENT_QUEUE_SIZE,
1070            event);
1071    }
1072
1073    /* write to JET queue */
1074    else if ((controller >= JET_EVENT_LOW) && (controller <= JET_EVENT_HIGH))
1075    {
1076        event |= segTrack;
1077#ifdef DEBUG_JET
1078        JET_DumpEvent("JET_Event[jet]", event);
1079#endif
1080        JET_WriteQueue(easHandle->jetHandle->jetEventQueue,
1081            &easHandle->jetHandle->jetEventQueueWrite,
1082            easHandle->jetHandle->jetEventQueueRead,
1083            JET_EVENT_QUEUE_SIZE,
1084            event);
1085    }
1086}
1087
1088/*----------------------------------------------------------------------------
1089 * JET_Clear_Queue()
1090 *----------------------------------------------------------------------------
1091 * Clears the queue and stops play without a complete shutdown
1092 *----------------------------------------------------------------------------
1093*/
1094EAS_RESULT JET_Clear_Queue(EAS_DATA_HANDLE easHandle)
1095{
1096    EAS_INT index;
1097    EAS_RESULT result = EAS_SUCCESS;
1098
1099    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Clear_Queue\n"); */ }
1100
1101    /* pause all playing streams */
1102    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
1103    {
1104        if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING)
1105        {
1106            result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[index].streamHandle);
1107            if (result != EAS_SUCCESS)
1108                return result;
1109
1110            easHandle->jetHandle->segQueue[index].state = JET_STATE_PAUSED;
1111        }
1112    }
1113
1114    /* close all streams */
1115    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
1116    {
1117        if (easHandle->jetHandle->segQueue[index].streamHandle != NULL)
1118        {
1119            result = JET_CloseSegment(easHandle, index);
1120            if (result != EAS_SUCCESS)
1121                return result;
1122        }
1123    }
1124
1125    /* clear all clips */
1126    for (index = 0; index < JET_MUTE_QUEUE_SIZE ; index++)
1127    {
1128        easHandle->jetHandle->muteQueue[index] = 0;
1129    }
1130
1131    easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING;
1132    easHandle->jetHandle->playSegment = easHandle->jetHandle->queueSegment = 0;
1133    return result;
1134}
1135
1136