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                easHandle->jetHandle->numSegments = (EAS_U8) temp;
286                break;
287
288            case INFO_NUM_DLS_CHUNKS:
289                easHandle->jetHandle->numLibraries = (EAS_U8) temp;
290                break;
291
292            case INFO_JET_VERSION:
293                /* check major version number */
294                if ((temp & 0xff000000) != (JET_VERSION & 0xff000000))
295                    return EAS_ERROR_INCOMPATIBLE_VERSION;
296                break;
297
298            default:
299                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET info type 0x%08x", infoType); */ }
300                break;
301        }
302
303        chunkSize -= 8;
304    }
305
306    /* allocate pointers for chunks to follow */
307
308    return result;
309}
310
311/*----------------------------------------------------------------------------
312 * JET_OpenFile()
313 *----------------------------------------------------------------------------
314 * Opens a JET content file for playback
315 *----------------------------------------------------------------------------
316*/
317EAS_PUBLIC EAS_RESULT JET_OpenFile (EAS_DATA_HANDLE easHandle, EAS_FILE_LOCATOR locator)
318{
319    EAS_RESULT result;
320    EAS_U32 chunkType;
321    EAS_I32 pos;
322    EAS_I32 chunkSize;
323    EAS_INT smfChunkNum;
324    EAS_INT dlsChunkNum;
325    EAS_I32 dataSize = 0; /* make lint happy */
326
327    /* make sure that we don't have an open file */
328    if (easHandle->jetHandle->jetFileHandle != NULL)
329        return EAS_ERROR_FILE_ALREADY_OPEN;
330
331    /* open the media file */
332    result = EAS_HWOpenFile(easHandle->hwInstData, locator, &easHandle->jetHandle->jetFileHandle, EAS_FILE_READ);
333    if (result != EAS_SUCCESS)
334        return result;
335
336    /* check header */
337    result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE);
338    if (result == EAS_SUCCESS)
339    {
340        if (chunkType != JET_HEADER_TAG)
341        {
342            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "File is not JET format\n"); */ }
343            result = EAS_ERROR_UNRECOGNIZED_FORMAT;
344        }
345    }
346    /* get the file data size */
347    if (result == EAS_SUCCESS)
348        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &dataSize, EAS_FALSE);
349
350    /* parse through the file to find contents */
351    smfChunkNum = dlsChunkNum = 0;
352    pos = chunkSize = 8;
353    while ((result == EAS_SUCCESS) && (pos < dataSize))
354    {
355
356        /* offset to chunk data */
357        result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos);
358        if (result != EAS_SUCCESS)
359            break;
360
361        /* get chunk size and type */
362        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE);
363        if (result != EAS_SUCCESS)
364            break;
365
366        result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkSize, EAS_FALSE);
367        if (result != EAS_SUCCESS)
368            break;
369        pos += 8;
370
371        switch (chunkType)
372        {
373            case JET_INFO_CHUNK:
374                result = JetParseInfoChunk(easHandle, pos, chunkSize);
375                break;
376
377            case JET_SMF_CHUNK:
378                if (smfChunkNum < easHandle->jetHandle->numSegments)
379                    easHandle->jetHandle->segmentOffsets[smfChunkNum++] = pos;
380                else
381                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous SMF chunk"); */ }
382                break;
383
384            case JET_DLS_CHUNK:
385                if (dlsChunkNum < easHandle->jetHandle->numLibraries)
386                    result = DLSParser(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos, &easHandle->jetHandle->libHandles[dlsChunkNum++]);
387                else
388                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous DLS chunk"); */ }
389                break;
390
391            case JET_APP_DATA_CHUNK:
392                easHandle->jetHandle->appDataOffset = pos;
393                easHandle->jetHandle->appDataSize = chunkSize;
394                break;
395
396            case INFO_JET_COPYRIGHT:
397                break;
398
399            default:
400                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET chunk type 0x%08x", chunkType); */ }
401                break;
402        }
403
404        /* offset to next chunk */
405        pos += chunkSize;
406    }
407
408    /* close file if something went wrong */
409    if (result != EAS_SUCCESS)
410        EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle);
411
412    return result;
413}
414
415/*----------------------------------------------------------------------------
416 * JET_GetAppData()
417 *----------------------------------------------------------------------------
418 * Returns location and size of application data in the JET file
419 *----------------------------------------------------------------------------
420*/
421EAS_RESULT JET_GetAppData (EAS_DATA_HANDLE easHandle, EAS_I32 *pAppDataOffset, EAS_I32 *pAppDataSize)
422{
423
424    /* check for app chunk */
425    if (easHandle->jetHandle->appDataSize == 0)
426    {
427        *pAppDataOffset = *pAppDataSize = 0;
428        return EAS_FAILURE;
429    }
430
431    /* return app data */
432    *pAppDataOffset = easHandle->jetHandle->appDataOffset;
433    *pAppDataSize = easHandle->jetHandle->appDataSize;
434    return EAS_SUCCESS;
435}
436
437/*----------------------------------------------------------------------------
438 * JET_CloseFile()
439 *----------------------------------------------------------------------------
440 * Closes a JET content file and releases associated resources
441 *----------------------------------------------------------------------------
442*/
443EAS_PUBLIC EAS_RESULT JET_CloseFile (EAS_DATA_HANDLE easHandle)
444{
445    EAS_INT index;
446    EAS_RESULT result = EAS_SUCCESS;
447
448    /* close open streams */
449    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
450    {
451        if (easHandle->jetHandle->segQueue[index].streamHandle != NULL)
452        {
453            result = JET_CloseSegment(easHandle, index);
454            if (result != EAS_SUCCESS)
455                break;
456        }
457    }
458
459    /* close the main file handle */
460    if ((result == EAS_SUCCESS) && (easHandle->jetHandle->jetFileHandle != NULL))
461    {
462        result = EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle);
463        if (result == EAS_SUCCESS)
464            easHandle->jetHandle->jetFileHandle = NULL;
465    }
466    return result;
467}
468
469/*----------------------------------------------------------------------------
470 * JET_Init()
471 *----------------------------------------------------------------------------
472 * Initializes the JET library, allocates memory, etc. Call
473 * JET_Shutdown to de-allocate memory.
474 *----------------------------------------------------------------------------
475*/
476EAS_PUBLIC EAS_RESULT JET_Init (EAS_DATA_HANDLE easHandle, const S_JET_CONFIG *pConfig, EAS_INT configSize)
477{
478    S_JET_DATA *pJet;
479    EAS_U8 flags = 0;
480
481    /* sanity check */
482    if (easHandle == NULL)
483        return EAS_ERROR_HANDLE_INTEGRITY;
484    if (easHandle->jetHandle != NULL)
485        return EAS_ERROR_FEATURE_ALREADY_ACTIVE;
486    if (pConfig == NULL)
487        pConfig = &jetDefaultConfig;
488
489    /* allocate the JET data object */
490    pJet = EAS_HWMalloc(easHandle->hwInstData, sizeof(S_JET_DATA));
491    if (pJet == NULL)
492        return EAS_ERROR_MALLOC_FAILED;
493
494    /* initialize JET data structure */
495    EAS_HWMemSet(pJet, 0, sizeof(S_JET_DATA));
496    easHandle->jetHandle = pJet;
497    pJet->flags = flags;
498
499    /* copy config data */
500    if (configSize > (EAS_INT) sizeof(S_JET_CONFIG))
501        configSize = sizeof(S_JET_CONFIG);
502    EAS_HWMemCpy(&pJet->config, pConfig, configSize);
503    return EAS_SUCCESS;
504}
505
506/*----------------------------------------------------------------------------
507 * JET_Shutdown()
508 *----------------------------------------------------------------------------
509 * Frees any memory used by the JET library
510 *----------------------------------------------------------------------------
511*/
512EAS_PUBLIC EAS_RESULT JET_Shutdown (EAS_DATA_HANDLE easHandle)
513{
514    EAS_RESULT result;
515
516    /* close any open files */
517    result = JET_CloseFile(easHandle);
518
519    /* free allocated data */
520    EAS_HWFree(easHandle->hwInstData, easHandle->jetHandle);
521    easHandle->jetHandle = NULL;
522    return result;
523}
524
525/*----------------------------------------------------------------------------
526 * JET_Status()
527 *----------------------------------------------------------------------------
528 * Returns current status
529 *----------------------------------------------------------------------------
530*/
531EAS_PUBLIC EAS_RESULT JET_Status (EAS_DATA_HANDLE easHandle, S_JET_STATUS *pStatus)
532{
533    S_JET_SEGMENT *pSeg;
534
535    pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment];
536    if (pSeg->streamHandle != NULL)
537    {
538        pStatus->currentUserID = pSeg->userID;
539        pStatus->segmentRepeatCount = pSeg->repeatCount;
540    }
541    else
542    {
543        pStatus->currentUserID = -1;
544        pStatus->segmentRepeatCount = 0;
545    }
546
547    pStatus->paused = !(easHandle->jetHandle->flags & JET_FLAGS_PLAYING);
548    pStatus->numQueuedSegments = easHandle->jetHandle->numQueuedSegments;
549    pStatus->currentPlayingSegment = easHandle->jetHandle->playSegment;
550    pStatus->currentQueuedSegment = easHandle->jetHandle->queueSegment;
551    if (pSeg->streamHandle != NULL)
552    {
553        EAS_RESULT result;
554        EAS_I32 location ;
555        if ((result = EAS_GetLocation(easHandle, pSeg->streamHandle, &location)) == EAS_SUCCESS)
556            if(location != 0)
557            {
558                pStatus->location = location;
559            }
560    }
561    return EAS_SUCCESS;
562}
563
564/*----------------------------------------------------------------------------
565 * JET_GetEvent()
566 *----------------------------------------------------------------------------
567 * Checks for application events
568 *----------------------------------------------------------------------------
569*/
570EAS_PUBLIC EAS_BOOL JET_GetEvent (EAS_DATA_HANDLE easHandle, EAS_U32 *pEventRaw, S_JET_EVENT *pEvent)
571{
572    EAS_U32 jetEvent;
573    EAS_BOOL gotEvent;
574
575    /* process event queue */
576    gotEvent = JET_ReadQueue(easHandle->jetHandle->appEventQueue,
577        &easHandle->jetHandle->appEventQueueRead,
578        easHandle->jetHandle->appEventQueueWrite,
579        APP_EVENT_QUEUE_SIZE, &jetEvent);
580
581    if (gotEvent)
582    {
583        if (pEventRaw != NULL)
584            *pEventRaw = jetEvent;
585
586        if (pEvent != NULL)
587            JET_ParseEvent(jetEvent, pEvent);
588    }
589
590    return gotEvent;
591}
592
593/*----------------------------------------------------------------------------
594 * JET_QueueSegment()
595 *----------------------------------------------------------------------------
596 * Queue a segment for playback
597 *----------------------------------------------------------------------------
598*/
599EAS_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)
600{
601    EAS_FILE_HANDLE fileHandle;
602    EAS_RESULT result;
603    S_JET_SEGMENT *p;
604
605    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_QueueSegment segNum=%d, queue=%d\n", segmentNum, easHandle->jetHandle->queueSegment); */ }
606
607    /* make sure it's a valid segment */
608    if (segmentNum >= easHandle->jetHandle->numSegments)
609        return EAS_ERROR_PARAMETER_RANGE;
610
611    /* make sure it's a valid DLS */
612    if (libNum >= easHandle->jetHandle->numLibraries)
613        return EAS_ERROR_PARAMETER_RANGE;
614
615    /* check to see if queue is full */
616    p = &easHandle->jetHandle->segQueue[easHandle->jetHandle->queueSegment];
617    if (p->streamHandle != NULL)
618        return EAS_ERROR_QUEUE_IS_FULL;
619
620    /* initialize data */
621    p->userID = userID;
622    p->repeatCount = (EAS_I16) repeatCount;
623    p->transpose = (EAS_I8) transpose;
624    p->libNum = (EAS_I8) libNum;
625    p->muteFlags = muteFlags;
626    p->state = JET_STATE_CLOSED;
627
628    /* open the file */
629    result = EAS_OpenJETStream(easHandle, easHandle->jetHandle->jetFileHandle, easHandle->jetHandle->segmentOffsets[segmentNum], &p->streamHandle);
630    if (result != EAS_SUCCESS)
631        return result;
632    p->state = JET_STATE_OPEN;
633
634    /* if less than SEG_QUEUE_DEPTH segments queued up, prepare file for playback */
635    if (++easHandle->jetHandle->numQueuedSegments < SEG_QUEUE_DEPTH)
636    {
637        result = JET_PrepareSegment(easHandle, easHandle->jetHandle->queueSegment);
638        if (result != EAS_SUCCESS)
639            return result;
640    }
641
642    /* create duplicate file handle */
643    result = EAS_HWDupHandle(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &fileHandle);
644    if (result != EAS_SUCCESS)
645        return result;
646
647    easHandle->jetHandle->jetFileHandle = fileHandle;
648    easHandle->jetHandle->queueSegment = (EAS_U8) JET_NextSegment(easHandle->jetHandle->queueSegment);
649    return result;
650}
651
652/*----------------------------------------------------------------------------
653 * JET_Play()
654 *----------------------------------------------------------------------------
655 * Starts playback of the file
656 *----------------------------------------------------------------------------
657*/
658EAS_PUBLIC EAS_RESULT JET_Play (EAS_DATA_HANDLE easHandle)
659{
660    EAS_RESULT result;
661    EAS_INT index;
662    EAS_INT count = 0;
663
664    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Play\n"); */ }
665
666    /* sanity check */
667    if (easHandle->jetHandle->flags & JET_FLAGS_PLAYING)
668        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
669
670    /* resume all paused streams */
671    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
672    {
673        if (((index == easHandle->jetHandle->playSegment) && (easHandle->jetHandle->segQueue[index].state == JET_STATE_READY)) ||
674            (easHandle->jetHandle->segQueue[index].state == JET_STATE_PAUSED))
675        {
676            result = JET_StartPlayback(easHandle, index);
677            if (result != EAS_SUCCESS)
678                return result;
679            count++;
680        }
681    }
682
683    /* if no streams are playing, return error */
684    if (!count)
685        return EAS_ERROR_QUEUE_IS_EMPTY;
686
687    easHandle->jetHandle->flags |= JET_FLAGS_PLAYING;
688    return EAS_SUCCESS;
689}
690
691/*----------------------------------------------------------------------------
692 * JET_Pause()
693 *----------------------------------------------------------------------------
694 * Pauses playback of the file
695 *----------------------------------------------------------------------------
696*/
697EAS_PUBLIC EAS_RESULT JET_Pause (EAS_DATA_HANDLE easHandle)
698{
699    EAS_RESULT result;
700    EAS_INT index;
701    EAS_INT count = 0;
702
703    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Pause\n"); */ }
704
705    /* sanity check */
706    if ((easHandle->jetHandle->flags & JET_FLAGS_PLAYING) == 0)
707        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
708
709    /* pause all playing streams */
710    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
711    {
712        if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING)
713        {
714            result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle);
715            if (result != EAS_SUCCESS)
716                return result;
717            easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].state = JET_STATE_PAUSED;
718            count++;
719        }
720    }
721
722    /* if no streams are paused, return error */
723    if (!count)
724        return EAS_ERROR_QUEUE_IS_EMPTY;
725
726    easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING;
727    return EAS_SUCCESS;
728}
729
730/*----------------------------------------------------------------------------
731 * JET_SetMuteFlags()
732 *----------------------------------------------------------------------------
733 * Change the state of the mute flags
734 *----------------------------------------------------------------------------
735*/
736EAS_PUBLIC EAS_RESULT JET_SetMuteFlags (EAS_DATA_HANDLE easHandle, EAS_U32 muteFlags, EAS_BOOL sync)
737{
738    S_JET_SEGMENT *pSeg;
739
740    /* get pointer to current segment */
741    pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment];
742
743    /* unsynchronized mute, set flags and return */
744    if (!sync)
745    {
746        if (pSeg->streamHandle == NULL)
747            return EAS_ERROR_QUEUE_IS_EMPTY;
748        pSeg->muteFlags = muteFlags;
749        return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) muteFlags);
750    }
751
752
753    /* check for valid stream state */
754    if (pSeg->state == JET_STATE_CLOSED)
755        return EAS_ERROR_QUEUE_IS_EMPTY;
756
757    /* save mute flags */
758    pSeg->muteFlags = muteFlags;
759
760    /* if repeating segment, set mute update flag */
761    if (sync)
762        pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE;
763    return EAS_SUCCESS;
764}
765
766/*----------------------------------------------------------------------------
767 * JET_SetMuteFlag()
768 *----------------------------------------------------------------------------
769 * Change the state of a single mute flag
770 *----------------------------------------------------------------------------
771*/
772EAS_PUBLIC EAS_RESULT JET_SetMuteFlag (EAS_DATA_HANDLE easHandle, EAS_INT trackNum, EAS_BOOL muteFlag, EAS_BOOL sync)
773{
774    S_JET_SEGMENT *pSeg;
775    EAS_U32 trackMuteFlag;
776
777
778    /* setup flag */
779    if ((trackNum < 0) || (trackNum > 31))
780        return EAS_ERROR_PARAMETER_RANGE;
781    trackMuteFlag = (1 << trackNum);
782
783    /* get pointer to current segment */
784    pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment];
785
786    /* unsynchronized mute, set flags and return */
787    if (!sync)
788    {
789        if (pSeg->streamHandle == NULL)
790            return EAS_ERROR_QUEUE_IS_EMPTY;
791        if (muteFlag)
792            pSeg->muteFlags |= trackMuteFlag;
793        else
794            pSeg->muteFlags &= ~trackMuteFlag;
795        return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags);
796    }
797
798
799    /* check for valid stream state */
800    if (pSeg->state == JET_STATE_CLOSED)
801        return EAS_ERROR_QUEUE_IS_EMPTY;
802
803    /* save mute flags and set mute update flag */
804    if (muteFlag)
805        pSeg->muteFlags |= trackMuteFlag;
806    else
807        pSeg->muteFlags &= ~trackMuteFlag;
808    pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE;
809    return EAS_SUCCESS;
810}
811
812/*----------------------------------------------------------------------------
813 * JET_TriggerClip()
814 *----------------------------------------------------------------------------
815 * Unmute a track and then mute it when it is complete. If a clip
816 * is already playing, change mute event to a trigger event. The
817 * JET_Event function will not mute the clip, but will allow it
818 * to continue playing through the next clip.
819 *
820 * NOTE: We use bit 7 to indicate an entry in the queue. For a
821 * small queue, it is cheaper in both memory and CPU cycles to
822 * scan the entire queue for non-zero events than keep enqueue
823 * and dequeue indices.
824 *----------------------------------------------------------------------------
825*/
826EAS_PUBLIC EAS_RESULT JET_TriggerClip (EAS_DATA_HANDLE easHandle, EAS_INT clipID)
827{
828    EAS_INT i;
829    EAS_INT index = -1;
830
831    /* check for valid clipID */
832    if ((clipID < 0) || (clipID > 63))
833        return EAS_ERROR_PARAMETER_RANGE;
834
835    /* set active flag */
836    clipID |= JET_CLIP_ACTIVE_FLAG;
837
838    /* Reverse the search so that we get the first empty element */
839    for (i = JET_MUTE_QUEUE_SIZE-1; i >= 0 ; i--)
840    {
841        if (easHandle->jetHandle->muteQueue[i] == clipID)
842        {
843            index = i;
844            break;
845        }
846        if (easHandle->jetHandle->muteQueue[i] == 0)
847            index = i;
848    }
849    if (index < 0)
850        return EAS_ERROR_QUEUE_IS_FULL;
851
852    easHandle->jetHandle->muteQueue[index] = (EAS_U8) clipID | JET_CLIP_TRIGGER_FLAG;
853    return EAS_SUCCESS;
854}
855
856/*----------------------------------------------------------------------------
857 * JET_Process()
858 *----------------------------------------------------------------------------
859 * Called during EAS_Render to process stream states
860 *----------------------------------------------------------------------------
861*/
862EAS_PUBLIC EAS_RESULT JET_Process (EAS_DATA_HANDLE easHandle)
863{
864    S_JET_SEGMENT *pSeg;
865    EAS_STATE state;
866    EAS_INT index;
867    EAS_INT playIndex;
868    EAS_RESULT result = EAS_SUCCESS;
869    EAS_BOOL endOfLoop = EAS_FALSE;
870    EAS_BOOL startNextSegment = EAS_FALSE;
871    EAS_BOOL prepareNextSegment = EAS_FALSE;
872    EAS_U32 jetEvent;
873
874    /* process event queue */
875    while (JET_ReadQueue(easHandle->jetHandle->jetEventQueue,
876        &easHandle->jetHandle->jetEventQueueRead,
877        easHandle->jetHandle->jetEventQueueWrite,
878        JET_EVENT_QUEUE_SIZE, &jetEvent))
879    {
880        S_JET_EVENT event;
881#ifdef DEBUG_JET
882        JET_DumpEvent("JET_Process", jetEvent);
883#endif
884        JET_ParseEvent(jetEvent, &event);
885
886        /* check for end of loop */
887        if ((event.controller == JET_EVENT_MARKER) &&
888                (event.value == JET_MARKER_LOOP_END) &&
889                (easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle != NULL))
890            endOfLoop = EAS_TRUE;
891    }
892
893    /* check state of all streams */
894    index = playIndex = easHandle->jetHandle->playSegment;
895    for (;;)
896    {
897        pSeg = &easHandle->jetHandle->segQueue[index];
898        if (pSeg->state != JET_STATE_CLOSED)
899        {
900
901            /* get playback state */
902            result = EAS_State(easHandle, pSeg->streamHandle, &state);
903            if (result != EAS_SUCCESS)
904                return result;
905
906            /* process state */
907            switch (pSeg->state)
908            {
909                /* take action if this segment is stopping */
910                case JET_STATE_PLAYING:
911                    if (endOfLoop || (state == EAS_STATE_STOPPING) || (state == EAS_STATE_STOPPED))
912                    {
913                        /* handle repeats */
914                        if (pSeg->repeatCount != 0)
915                        {
916                            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render repeating segment %d\n", index); */ }
917                            result = EAS_Locate(easHandle, pSeg->streamHandle, 0, EAS_FALSE);
918                            if (result != EAS_SUCCESS)
919                                return result;
920                            if (pSeg->repeatCount > 0)
921                                pSeg->repeatCount--;
922
923                            /* update mute flags if necessary */
924                            if (pSeg->flags & JET_SEG_FLAG_MUTE_UPDATE)
925                            {
926                                result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags);
927                                if (result != EAS_SUCCESS)
928                                    return result;
929                                pSeg->flags &= ~JET_SEG_FLAG_MUTE_UPDATE;
930                            }
931
932                        }
933                        /* no repeat, start next segment */
934                        else
935                        {
936                            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render stopping queue %d\n", index); */ }
937                            startNextSegment = EAS_TRUE;
938                            pSeg->state = JET_STATE_STOPPING;
939                            easHandle->jetHandle->playSegment = (EAS_U8) JET_NextSegment(index);
940                        }
941                    }
942                    break;
943
944                /* if playback has stopped, close the segment */
945                case JET_STATE_STOPPING:
946                    if (state == EAS_STATE_STOPPED)
947                    {
948                        result = JET_CloseSegment(easHandle, index);
949                        if (result != EAS_SUCCESS)
950                            return result;
951                    }
952                    break;
953
954                case JET_STATE_READY:
955                    if (startNextSegment)
956                    {
957                        result = JET_StartPlayback(easHandle, index);
958                        if (result != EAS_SUCCESS)
959                            return result;
960                        startNextSegment = EAS_FALSE;
961                        prepareNextSegment = EAS_TRUE;
962                    }
963                    break;
964
965                case JET_STATE_OPEN:
966                    if (prepareNextSegment)
967                    {
968                        result = JET_PrepareSegment(easHandle, index);
969                        if (result != EAS_SUCCESS)
970                            return result;
971                        prepareNextSegment = EAS_FALSE;
972                    }
973                    break;
974
975                case JET_STATE_PAUSED:
976                    break;
977
978                default:
979                    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "JET_Render: Unexpected segment state %d\n", pSeg->state); */ }
980                    break;
981            }
982        }
983
984        /* increment index */
985        index = JET_NextSegment(index);
986        if (index == playIndex)
987            break;
988    }
989
990    /* if out of segments, clear playing flag */
991    if (easHandle->jetHandle->numQueuedSegments == 0)
992        easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING;
993
994    return result;
995}
996
997/*----------------------------------------------------------------------------
998 * JET_Event()
999 *----------------------------------------------------------------------------
1000 * Called from MIDI parser when data of interest is received
1001 *----------------------------------------------------------------------------
1002*/
1003void JET_Event (EAS_DATA_HANDLE easHandle, EAS_U32 segTrack, EAS_U8 channel, EAS_U8 controller, EAS_U8 value)
1004{
1005    EAS_U32 event;
1006
1007    if (easHandle->jetHandle == NULL)
1008        return;
1009
1010    /* handle triggers */
1011    if (controller == JET_EVENT_TRIGGER_CLIP)
1012    {
1013        S_JET_SEGMENT *pSeg;
1014        EAS_INT i;
1015        EAS_U32 muteFlag;
1016
1017        for (i = 0; i < JET_MUTE_QUEUE_SIZE; i++)
1018        {
1019            /* search for event in queue */
1020            if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_ID_MASK) == (value & JET_CLIP_ID_MASK))
1021            {
1022                /* get segment pointer and mute flag */
1023                pSeg = &easHandle->jetHandle->segQueue[segTrack >> JET_EVENT_SEG_SHIFT];
1024                muteFlag = 1 << ((segTrack & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT);
1025
1026                /* un-mute the track */
1027                if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_TRIGGER_FLAG) && ((value & 0x40) > 0))
1028                {
1029                    pSeg->muteFlags &= ~muteFlag;
1030                    easHandle->jetHandle->muteQueue[i] &= ~JET_CLIP_TRIGGER_FLAG;
1031                }
1032
1033                /* mute the track */
1034                else
1035                {
1036                    EAS_U32 beforeMute ;
1037                    beforeMute = pSeg->muteFlags ;
1038                    pSeg->muteFlags |= muteFlag;
1039                    if (beforeMute != pSeg->muteFlags)
1040                        easHandle->jetHandle->muteQueue[i] = 0;
1041                }
1042                EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags);
1043                return;
1044            }
1045        }
1046        return;
1047    }
1048
1049    /* generic event stuff */
1050    event = (channel << JET_EVENT_CHAN_SHIFT) | (controller << JET_EVENT_CTRL_SHIFT) | value;
1051
1052    /* write to app queue, translate queue index to segment number */
1053    if ((controller >= easHandle->jetHandle->config.appEventRangeLow) && (controller <= easHandle->jetHandle->config.appEventRangeHigh))
1054    {
1055
1056        event |= easHandle->jetHandle->segQueue[(segTrack & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT].userID << JET_EVENT_SEG_SHIFT;
1057#ifdef DEBUG_JET
1058        JET_DumpEvent("JET_Event[app]", event);
1059#endif
1060        JET_WriteQueue(easHandle->jetHandle->appEventQueue,
1061            &easHandle->jetHandle->appEventQueueWrite,
1062            easHandle->jetHandle->appEventQueueRead,
1063            APP_EVENT_QUEUE_SIZE,
1064            event);
1065    }
1066
1067    /* write to JET queue */
1068    else if ((controller >= JET_EVENT_LOW) && (controller <= JET_EVENT_HIGH))
1069    {
1070        event |= segTrack;
1071#ifdef DEBUG_JET
1072        JET_DumpEvent("JET_Event[jet]", event);
1073#endif
1074        JET_WriteQueue(easHandle->jetHandle->jetEventQueue,
1075            &easHandle->jetHandle->jetEventQueueWrite,
1076            easHandle->jetHandle->jetEventQueueRead,
1077            JET_EVENT_QUEUE_SIZE,
1078            event);
1079    }
1080}
1081
1082/*----------------------------------------------------------------------------
1083 * JET_Clear_Queue()
1084 *----------------------------------------------------------------------------
1085 * Clears the queue and stops play without a complete shutdown
1086 *----------------------------------------------------------------------------
1087*/
1088EAS_RESULT JET_Clear_Queue(EAS_DATA_HANDLE easHandle)
1089{
1090    EAS_INT index;
1091    EAS_RESULT result = EAS_SUCCESS;
1092
1093    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Clear_Queue\n"); */ }
1094
1095    /* pause all playing streams */
1096    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
1097    {
1098        if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING)
1099        {
1100            result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[index].streamHandle);
1101            if (result != EAS_SUCCESS)
1102                return result;
1103
1104            easHandle->jetHandle->segQueue[index].state = JET_STATE_PAUSED;
1105        }
1106    }
1107
1108    /* close all streams */
1109    for (index = 0; index < SEG_QUEUE_DEPTH; index++)
1110    {
1111        if (easHandle->jetHandle->segQueue[index].streamHandle != NULL)
1112        {
1113            result = JET_CloseSegment(easHandle, index);
1114            if (result != EAS_SUCCESS)
1115                return result;
1116        }
1117    }
1118
1119    /* clear all clips */
1120    for (index = 0; index < JET_MUTE_QUEUE_SIZE ; index++)
1121    {
1122        easHandle->jetHandle->muteQueue[index] = 0;
1123    }
1124
1125    easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING;
1126    easHandle->jetHandle->playSegment = easHandle->jetHandle->queueSegment = 0;
1127    return result;
1128}
1129
1130