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