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