/*---------------------------------------------------------------------------- | |
* | |
* File: | |
* jet.c | |
* | |
* Contents and purpose: | |
* Implementation for JET sound engine | |
* | |
* Copyright (c) 2006 Sonic Network Inc. | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*---------------------------------------------------------------------------- | |
* Revision Control: | |
* $Revision: 563 $ | |
* $Date: 2007-02-13 20:26:23 -0800 (Tue, 13 Feb 2007) $ | |
*---------------------------------------------------------------------------- | |
*/ | |
//#define LOG_NDEBUG 0 | |
#define LOG_TAG "JET_C" | |
//#define DEBUG_JET | |
#include "eas_data.h" | |
#include "eas_smf.h" | |
#include "jet_data.h" | |
#include "eas_host.h" | |
#include "eas_report.h" | |
/* default configuration */ | |
static const S_JET_CONFIG jetDefaultConfig = | |
{ | |
JET_EVENT_APP_LOW, | |
JET_EVENT_APP_HIGH | |
}; | |
/* function prototypes */ | |
extern EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value); | |
extern EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream); | |
extern EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_DLSLIB_HANDLE *ppDLS); | |
/*---------------------------------------------------------------------------- | |
* JET_ParseEvent() | |
*---------------------------------------------------------------------------- | |
* Returns current status | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC void JET_ParseEvent (EAS_U32 event, S_JET_EVENT *pEvent) | |
{ | |
pEvent->segment = (EAS_U8) ((event & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT); | |
pEvent->track = (EAS_U8) ((event & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT); | |
pEvent->channel = (EAS_U8) ((event & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT); | |
pEvent->controller = (EAS_U8) ((event & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT); | |
pEvent->value = (EAS_U8) (event & JET_EVENT_VAL_MASK); | |
} | |
#ifdef DEBUG_JET | |
/*---------------------------------------------------------------------------- | |
* JET_DumpEvent | |
*---------------------------------------------------------------------------- | |
* Advances queue read/write index | |
*---------------------------------------------------------------------------- | |
*/ | |
static void JET_DumpEvent (const char *procName, EAS_U32 event) | |
{ | |
S_JET_EVENT sEvent; | |
JET_ParseEvent(event, &sEvent); | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "%s: SegID=%d, TrkID=%d, channel=%d, ctrl=%d, val=%d\n", | |
procName, sEvent.segment, sEvent.track, sEvent.channel, sEvent.controller, sEvent.value); */ } | |
} | |
#endif | |
/*---------------------------------------------------------------------------- | |
* JET_IncQueueIndex | |
*---------------------------------------------------------------------------- | |
* Advances queue read/write index | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_INLINE EAS_U8 JET_IncQueueIndex (EAS_U8 index, EAS_U8 queueSize) | |
{ | |
if (++index == queueSize) | |
index = 0; | |
return index; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_WriteQueue | |
*---------------------------------------------------------------------------- | |
* Save event to queue | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_INLINE void JET_WriteQueue (EAS_U32 *pEventQueue, EAS_U8 *pWriteIndex, EAS_U8 readIndex, EAS_U8 queueSize, EAS_U32 event) | |
{ | |
EAS_U8 temp; | |
/* check for queue overflow */ | |
temp = JET_IncQueueIndex(*pWriteIndex, queueSize); | |
if (temp == readIndex) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "JET_Event: Event queue overflow --- event ignored!\n"); */ } | |
return; | |
} | |
/* save in queue and advance write index */ | |
pEventQueue[*pWriteIndex] = event; | |
*pWriteIndex = temp; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_ReadQueue | |
*---------------------------------------------------------------------------- | |
* Read event to queue | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_INLINE EAS_BOOL JET_ReadQueue (EAS_U32 *pEventQueue, EAS_U8 *pReadIndex, EAS_U8 writeIndex, EAS_U8 queueSize, EAS_U32 *pEvent) | |
{ | |
/* check for empty queue */ | |
if (*pReadIndex == writeIndex) | |
return EAS_FALSE; | |
/* save in queue and advance write index */ | |
*pEvent = pEventQueue[*pReadIndex]; | |
*pReadIndex = JET_IncQueueIndex(*pReadIndex, queueSize); | |
return EAS_TRUE; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_NextSegment | |
*---------------------------------------------------------------------------- | |
* Advances segment number | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_INLINE EAS_INT JET_NextSegment (EAS_INT seg_num) | |
{ | |
if (++seg_num == SEG_QUEUE_DEPTH) | |
seg_num = 0; | |
return seg_num; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_PrepareSegment() | |
*---------------------------------------------------------------------------- | |
* Prepare a segment for playback | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT JET_PrepareSegment (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum) | |
{ | |
EAS_RESULT result; | |
S_JET_SEGMENT *p; | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_PrepareSegment: %d\n", queueNum); */ } | |
p = &easHandle->jetHandle->segQueue[queueNum]; | |
result = EAS_Prepare(easHandle, p->streamHandle); | |
if (result != EAS_SUCCESS) | |
return result; | |
/* pause segment - must be triggered by play or end of previous segment */ | |
result = EAS_Pause(easHandle, p->streamHandle); | |
if (result != EAS_SUCCESS) | |
return result; | |
p->state = JET_STATE_READY; | |
/* set calback data */ | |
result = EAS_IntSetStrmParam(easHandle, p->streamHandle, PARSER_DATA_JET_CB, queueNum); | |
if (result != EAS_SUCCESS) | |
return result; | |
/* set DLS collection */ | |
if (p->libNum >= 0) | |
{ | |
result = EAS_IntSetStrmParam(easHandle, p->streamHandle, | |
PARSER_DATA_DLS_COLLECTION, (EAS_I32) easHandle->jetHandle->libHandles[p->libNum]); | |
if (result != EAS_SUCCESS) | |
return result; | |
} | |
/* set transposition */ | |
if (p->transpose) | |
{ | |
result = EAS_SetTransposition(easHandle, p->streamHandle, p->transpose); | |
if (result != EAS_SUCCESS) | |
return result; | |
} | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_StartPlayback() | |
*---------------------------------------------------------------------------- | |
* Start segment playback | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT JET_StartPlayback (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum) | |
{ | |
EAS_RESULT result = EAS_SUCCESS; | |
S_JET_SEGMENT *pSeg; | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_StartPlayback %d\n", queueNum); */ } | |
/* if next segment is queued, start playback */ | |
pSeg = &easHandle->jetHandle->segQueue[queueNum]; | |
if (pSeg->streamHandle != NULL) | |
{ | |
result = EAS_Resume(easHandle, pSeg->streamHandle); | |
easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_PLAYING; | |
/* set mute flags */ | |
if ((result == EAS_SUCCESS) && (pSeg->muteFlags != 0)) | |
result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); | |
} | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_CloseSegment | |
*---------------------------------------------------------------------------- | |
* Closes stream associated with a segment | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_INLINE EAS_INT JET_CloseSegment (EAS_DATA_HANDLE easHandle, EAS_INT queueNum) | |
{ | |
EAS_RESULT result; | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_CloseSegment %d\n", queueNum); */ } | |
/* close the segment */ | |
result = EAS_CloseFile(easHandle, easHandle->jetHandle->segQueue[queueNum].streamHandle); | |
if (result != EAS_SUCCESS) | |
return result; | |
easHandle->jetHandle->segQueue[queueNum].streamHandle = NULL; | |
easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_CLOSED; | |
easHandle->jetHandle->numQueuedSegments--; | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JetParseInfoChunk() | |
*---------------------------------------------------------------------------- | |
* Parses the JET info chunk | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT JetParseInfoChunk (EAS_DATA_HANDLE easHandle, EAS_I32 pos, EAS_I32 chunkSize) | |
{ | |
EAS_RESULT result; | |
EAS_U32 infoType; | |
EAS_U32 temp; | |
/* offset to data */ | |
result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos); | |
if (result != EAS_SUCCESS) | |
return result; | |
/* read the entire chunk */ | |
result = EAS_SUCCESS; | |
while ((result == EAS_SUCCESS) && (chunkSize > 0)) | |
{ | |
/* get info infoType */ | |
result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &infoType, EAS_TRUE); | |
if (result != EAS_SUCCESS) | |
break; | |
/* get info field */ | |
result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &temp, EAS_FALSE); | |
if (result == EAS_SUCCESS) | |
switch (infoType) | |
{ | |
case INFO_NUM_SMF_CHUNKS: | |
easHandle->jetHandle->numSegments = (EAS_U8) temp; | |
break; | |
case INFO_NUM_DLS_CHUNKS: | |
easHandle->jetHandle->numLibraries = (EAS_U8) temp; | |
break; | |
case INFO_JET_VERSION: | |
/* check major version number */ | |
if ((temp & 0xff000000) != (JET_VERSION & 0xff000000)) | |
return EAS_ERROR_INCOMPATIBLE_VERSION; | |
break; | |
default: | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET info type 0x%08x", infoType); */ } | |
break; | |
} | |
chunkSize -= 8; | |
} | |
/* allocate pointers for chunks to follow */ | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_OpenFile() | |
*---------------------------------------------------------------------------- | |
* Opens a JET content file for playback | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_OpenFile (EAS_DATA_HANDLE easHandle, EAS_FILE_LOCATOR locator) | |
{ | |
EAS_RESULT result; | |
EAS_U32 chunkType; | |
EAS_I32 pos; | |
EAS_I32 chunkSize; | |
EAS_INT smfChunkNum; | |
EAS_INT dlsChunkNum; | |
EAS_I32 dataSize = 0; /* make lint happy */ | |
/* make sure that we don't have an open file */ | |
if (easHandle->jetHandle->jetFileHandle != NULL) | |
return EAS_ERROR_FILE_ALREADY_OPEN; | |
/* open the media file */ | |
result = EAS_HWOpenFile(easHandle->hwInstData, locator, &easHandle->jetHandle->jetFileHandle, EAS_FILE_READ); | |
if (result != EAS_SUCCESS) | |
return result; | |
/* check header */ | |
result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE); | |
if (result == EAS_SUCCESS) | |
{ | |
if (chunkType != JET_HEADER_TAG) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "File is not JET format\n"); */ } | |
result = EAS_ERROR_UNRECOGNIZED_FORMAT; | |
} | |
} | |
/* get the file data size */ | |
if (result == EAS_SUCCESS) | |
result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &dataSize, EAS_FALSE); | |
/* parse through the file to find contents */ | |
smfChunkNum = dlsChunkNum = 0; | |
pos = chunkSize = 8; | |
while ((result == EAS_SUCCESS) && (pos < dataSize)) | |
{ | |
/* offset to chunk data */ | |
result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos); | |
if (result != EAS_SUCCESS) | |
break; | |
/* get chunk size and type */ | |
result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE); | |
if (result != EAS_SUCCESS) | |
break; | |
result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkSize, EAS_FALSE); | |
if (result != EAS_SUCCESS) | |
break; | |
pos += 8; | |
switch (chunkType) | |
{ | |
case JET_INFO_CHUNK: | |
result = JetParseInfoChunk(easHandle, pos, chunkSize); | |
break; | |
case JET_SMF_CHUNK: | |
if (smfChunkNum < easHandle->jetHandle->numSegments) | |
easHandle->jetHandle->segmentOffsets[smfChunkNum++] = pos; | |
else | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous SMF chunk"); */ } | |
break; | |
case JET_DLS_CHUNK: | |
if (dlsChunkNum < easHandle->jetHandle->numLibraries) | |
result = DLSParser(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos, &easHandle->jetHandle->libHandles[dlsChunkNum++]); | |
else | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous DLS chunk"); */ } | |
break; | |
case JET_APP_DATA_CHUNK: | |
easHandle->jetHandle->appDataOffset = pos; | |
easHandle->jetHandle->appDataSize = chunkSize; | |
break; | |
case INFO_JET_COPYRIGHT: | |
break; | |
default: | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET chunk type 0x%08x", chunkType); */ } | |
break; | |
} | |
/* offset to next chunk */ | |
pos += chunkSize; | |
} | |
/* close file if something went wrong */ | |
if (result != EAS_SUCCESS) | |
EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle); | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_GetAppData() | |
*---------------------------------------------------------------------------- | |
* Returns location and size of application data in the JET file | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_RESULT JET_GetAppData (EAS_DATA_HANDLE easHandle, EAS_I32 *pAppDataOffset, EAS_I32 *pAppDataSize) | |
{ | |
/* check for app chunk */ | |
if (easHandle->jetHandle->appDataSize == 0) | |
{ | |
*pAppDataOffset = *pAppDataSize = 0; | |
return EAS_FAILURE; | |
} | |
/* return app data */ | |
*pAppDataOffset = easHandle->jetHandle->appDataOffset; | |
*pAppDataSize = easHandle->jetHandle->appDataSize; | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_CloseFile() | |
*---------------------------------------------------------------------------- | |
* Closes a JET content file and releases associated resources | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_CloseFile (EAS_DATA_HANDLE easHandle) | |
{ | |
EAS_INT index; | |
EAS_RESULT result = EAS_SUCCESS; | |
/* close open streams */ | |
for (index = 0; index < SEG_QUEUE_DEPTH; index++) | |
{ | |
if (easHandle->jetHandle->segQueue[index].streamHandle != NULL) | |
{ | |
result = JET_CloseSegment(easHandle, index); | |
if (result != EAS_SUCCESS) | |
break; | |
} | |
} | |
/* close the main file handle */ | |
if ((result == EAS_SUCCESS) && (easHandle->jetHandle->jetFileHandle != NULL)) | |
{ | |
result = EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle); | |
if (result == EAS_SUCCESS) | |
easHandle->jetHandle->jetFileHandle = NULL; | |
} | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Init() | |
*---------------------------------------------------------------------------- | |
* Initializes the JET library, allocates memory, etc. Call | |
* JET_Shutdown to de-allocate memory. | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_Init (EAS_DATA_HANDLE easHandle, const S_JET_CONFIG *pConfig, EAS_INT configSize) | |
{ | |
S_JET_DATA *pJet; | |
EAS_U8 flags = 0; | |
/* sanity check */ | |
if (easHandle == NULL) | |
return EAS_ERROR_HANDLE_INTEGRITY; | |
if (easHandle->jetHandle != NULL) | |
return EAS_ERROR_FEATURE_ALREADY_ACTIVE; | |
if (pConfig == NULL) | |
pConfig = &jetDefaultConfig; | |
/* allocate the JET data object */ | |
pJet = EAS_HWMalloc(easHandle->hwInstData, sizeof(S_JET_DATA)); | |
if (pJet == NULL) | |
return EAS_ERROR_MALLOC_FAILED; | |
/* initialize JET data structure */ | |
EAS_HWMemSet(pJet, 0, sizeof(S_JET_DATA)); | |
easHandle->jetHandle = pJet; | |
pJet->flags = flags; | |
/* copy config data */ | |
if (configSize > (EAS_INT) sizeof(S_JET_CONFIG)) | |
configSize = sizeof(S_JET_CONFIG); | |
EAS_HWMemCpy(&pJet->config, pConfig, configSize); | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Shutdown() | |
*---------------------------------------------------------------------------- | |
* Frees any memory used by the JET library | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_Shutdown (EAS_DATA_HANDLE easHandle) | |
{ | |
EAS_RESULT result; | |
/* close any open files */ | |
result = JET_CloseFile(easHandle); | |
/* free allocated data */ | |
EAS_HWFree(easHandle->hwInstData, easHandle->jetHandle); | |
easHandle->jetHandle = NULL; | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Status() | |
*---------------------------------------------------------------------------- | |
* Returns current status | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_Status (EAS_DATA_HANDLE easHandle, S_JET_STATUS *pStatus) | |
{ | |
S_JET_SEGMENT *pSeg; | |
pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; | |
if (pSeg->streamHandle != NULL) | |
{ | |
pStatus->currentUserID = pSeg->userID; | |
pStatus->segmentRepeatCount = pSeg->repeatCount; | |
} | |
else | |
{ | |
pStatus->currentUserID = -1; | |
pStatus->segmentRepeatCount = 0; | |
} | |
pStatus->paused = !(easHandle->jetHandle->flags & JET_FLAGS_PLAYING); | |
pStatus->numQueuedSegments = easHandle->jetHandle->numQueuedSegments; | |
pStatus->currentPlayingSegment = easHandle->jetHandle->playSegment; | |
pStatus->currentQueuedSegment = easHandle->jetHandle->queueSegment; | |
if (pSeg->streamHandle != NULL) | |
{ | |
EAS_RESULT result; | |
EAS_I32 location ; | |
if ((result = EAS_GetLocation(easHandle, pSeg->streamHandle, &location)) == EAS_SUCCESS) | |
if(location != 0) | |
{ | |
pStatus->location = location; | |
} | |
} | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_GetEvent() | |
*---------------------------------------------------------------------------- | |
* Checks for application events | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_BOOL JET_GetEvent (EAS_DATA_HANDLE easHandle, EAS_U32 *pEventRaw, S_JET_EVENT *pEvent) | |
{ | |
EAS_U32 jetEvent; | |
EAS_BOOL gotEvent; | |
/* process event queue */ | |
gotEvent = JET_ReadQueue(easHandle->jetHandle->appEventQueue, | |
&easHandle->jetHandle->appEventQueueRead, | |
easHandle->jetHandle->appEventQueueWrite, | |
APP_EVENT_QUEUE_SIZE, &jetEvent); | |
if (gotEvent) | |
{ | |
if (pEventRaw != NULL) | |
*pEventRaw = jetEvent; | |
if (pEvent != NULL) | |
JET_ParseEvent(jetEvent, pEvent); | |
} | |
return gotEvent; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_QueueSegment() | |
*---------------------------------------------------------------------------- | |
* Queue a segment for playback | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_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) | |
{ | |
EAS_FILE_HANDLE fileHandle; | |
EAS_RESULT result; | |
S_JET_SEGMENT *p; | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_QueueSegment segNum=%d, queue=%d\n", segmentNum, easHandle->jetHandle->queueSegment); */ } | |
/* make sure it's a valid segment */ | |
if (segmentNum >= easHandle->jetHandle->numSegments) | |
return EAS_ERROR_PARAMETER_RANGE; | |
/* make sure it's a valid DLS */ | |
if (libNum >= easHandle->jetHandle->numLibraries) | |
return EAS_ERROR_PARAMETER_RANGE; | |
/* check to see if queue is full */ | |
p = &easHandle->jetHandle->segQueue[easHandle->jetHandle->queueSegment]; | |
if (p->streamHandle != NULL) | |
return EAS_ERROR_QUEUE_IS_FULL; | |
/* initialize data */ | |
p->userID = userID; | |
p->repeatCount = (EAS_I16) repeatCount; | |
p->transpose = (EAS_I8) transpose; | |
p->libNum = (EAS_I8) libNum; | |
p->muteFlags = muteFlags; | |
p->state = JET_STATE_CLOSED; | |
/* open the file */ | |
result = EAS_OpenJETStream(easHandle, easHandle->jetHandle->jetFileHandle, easHandle->jetHandle->segmentOffsets[segmentNum], &p->streamHandle); | |
if (result != EAS_SUCCESS) | |
return result; | |
p->state = JET_STATE_OPEN; | |
/* if less than SEG_QUEUE_DEPTH segments queued up, prepare file for playback */ | |
if (++easHandle->jetHandle->numQueuedSegments < SEG_QUEUE_DEPTH) | |
{ | |
result = JET_PrepareSegment(easHandle, easHandle->jetHandle->queueSegment); | |
if (result != EAS_SUCCESS) | |
return result; | |
} | |
/* create duplicate file handle */ | |
result = EAS_HWDupHandle(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &fileHandle); | |
if (result != EAS_SUCCESS) | |
return result; | |
easHandle->jetHandle->jetFileHandle = fileHandle; | |
easHandle->jetHandle->queueSegment = (EAS_U8) JET_NextSegment(easHandle->jetHandle->queueSegment); | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Play() | |
*---------------------------------------------------------------------------- | |
* Starts playback of the file | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_Play (EAS_DATA_HANDLE easHandle) | |
{ | |
EAS_RESULT result; | |
EAS_INT index; | |
EAS_INT count = 0; | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Play\n"); */ } | |
/* sanity check */ | |
if (easHandle->jetHandle->flags & JET_FLAGS_PLAYING) | |
return EAS_ERROR_NOT_VALID_IN_THIS_STATE; | |
/* resume all paused streams */ | |
for (index = 0; index < SEG_QUEUE_DEPTH; index++) | |
{ | |
if (((index == easHandle->jetHandle->playSegment) && (easHandle->jetHandle->segQueue[index].state == JET_STATE_READY)) || | |
(easHandle->jetHandle->segQueue[index].state == JET_STATE_PAUSED)) | |
{ | |
result = JET_StartPlayback(easHandle, index); | |
if (result != EAS_SUCCESS) | |
return result; | |
count++; | |
} | |
} | |
/* if no streams are playing, return error */ | |
if (!count) | |
return EAS_ERROR_QUEUE_IS_EMPTY; | |
easHandle->jetHandle->flags |= JET_FLAGS_PLAYING; | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Pause() | |
*---------------------------------------------------------------------------- | |
* Pauses playback of the file | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_Pause (EAS_DATA_HANDLE easHandle) | |
{ | |
EAS_RESULT result; | |
EAS_INT index; | |
EAS_INT count = 0; | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Pause\n"); */ } | |
/* sanity check */ | |
if ((easHandle->jetHandle->flags & JET_FLAGS_PLAYING) == 0) | |
return EAS_ERROR_NOT_VALID_IN_THIS_STATE; | |
/* pause all playing streams */ | |
for (index = 0; index < SEG_QUEUE_DEPTH; index++) | |
{ | |
if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING) | |
{ | |
result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle); | |
if (result != EAS_SUCCESS) | |
return result; | |
easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].state = JET_STATE_PAUSED; | |
count++; | |
} | |
} | |
/* if no streams are paused, return error */ | |
if (!count) | |
return EAS_ERROR_QUEUE_IS_EMPTY; | |
easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_SetMuteFlags() | |
*---------------------------------------------------------------------------- | |
* Change the state of the mute flags | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_SetMuteFlags (EAS_DATA_HANDLE easHandle, EAS_U32 muteFlags, EAS_BOOL sync) | |
{ | |
S_JET_SEGMENT *pSeg; | |
/* get pointer to current segment */ | |
pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; | |
/* unsynchronized mute, set flags and return */ | |
if (!sync) | |
{ | |
if (pSeg->streamHandle == NULL) | |
return EAS_ERROR_QUEUE_IS_EMPTY; | |
pSeg->muteFlags = muteFlags; | |
return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) muteFlags); | |
} | |
/* check for valid stream state */ | |
if (pSeg->state == JET_STATE_CLOSED) | |
return EAS_ERROR_QUEUE_IS_EMPTY; | |
/* save mute flags */ | |
pSeg->muteFlags = muteFlags; | |
/* if repeating segment, set mute update flag */ | |
if (sync) | |
pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE; | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_SetMuteFlag() | |
*---------------------------------------------------------------------------- | |
* Change the state of a single mute flag | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_SetMuteFlag (EAS_DATA_HANDLE easHandle, EAS_INT trackNum, EAS_BOOL muteFlag, EAS_BOOL sync) | |
{ | |
S_JET_SEGMENT *pSeg; | |
EAS_U32 trackMuteFlag; | |
/* setup flag */ | |
if ((trackNum < 0) || (trackNum > 31)) | |
return EAS_ERROR_PARAMETER_RANGE; | |
trackMuteFlag = (1 << trackNum); | |
/* get pointer to current segment */ | |
pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; | |
/* unsynchronized mute, set flags and return */ | |
if (!sync) | |
{ | |
if (pSeg->streamHandle == NULL) | |
return EAS_ERROR_QUEUE_IS_EMPTY; | |
if (muteFlag) | |
pSeg->muteFlags |= trackMuteFlag; | |
else | |
pSeg->muteFlags &= ~trackMuteFlag; | |
return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); | |
} | |
/* check for valid stream state */ | |
if (pSeg->state == JET_STATE_CLOSED) | |
return EAS_ERROR_QUEUE_IS_EMPTY; | |
/* save mute flags and set mute update flag */ | |
if (muteFlag) | |
pSeg->muteFlags |= trackMuteFlag; | |
else | |
pSeg->muteFlags &= ~trackMuteFlag; | |
pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE; | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_TriggerClip() | |
*---------------------------------------------------------------------------- | |
* Unmute a track and then mute it when it is complete. If a clip | |
* is already playing, change mute event to a trigger event. The | |
* JET_Event function will not mute the clip, but will allow it | |
* to continue playing through the next clip. | |
* | |
* NOTE: We use bit 7 to indicate an entry in the queue. For a | |
* small queue, it is cheaper in both memory and CPU cycles to | |
* scan the entire queue for non-zero events than keep enqueue | |
* and dequeue indices. | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_TriggerClip (EAS_DATA_HANDLE easHandle, EAS_INT clipID) | |
{ | |
EAS_INT i; | |
EAS_INT index = -1; | |
/* check for valid clipID */ | |
if ((clipID < 0) || (clipID > 63)) | |
return EAS_ERROR_PARAMETER_RANGE; | |
/* set active flag */ | |
clipID |= JET_CLIP_ACTIVE_FLAG; | |
/* Reverse the search so that we get the first empty element */ | |
for (i = JET_MUTE_QUEUE_SIZE-1; i >= 0 ; i--) | |
{ | |
if (easHandle->jetHandle->muteQueue[i] == clipID) | |
{ | |
index = i; | |
break; | |
} | |
if (easHandle->jetHandle->muteQueue[i] == 0) | |
index = i; | |
} | |
if (index < 0) | |
return EAS_ERROR_QUEUE_IS_FULL; | |
easHandle->jetHandle->muteQueue[index] = (EAS_U8) clipID | JET_CLIP_TRIGGER_FLAG; | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Process() | |
*---------------------------------------------------------------------------- | |
* Called during EAS_Render to process stream states | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_PUBLIC EAS_RESULT JET_Process (EAS_DATA_HANDLE easHandle) | |
{ | |
S_JET_SEGMENT *pSeg; | |
EAS_STATE state; | |
EAS_INT index; | |
EAS_INT playIndex; | |
EAS_RESULT result = EAS_SUCCESS; | |
EAS_BOOL endOfLoop = EAS_FALSE; | |
EAS_BOOL startNextSegment = EAS_FALSE; | |
EAS_BOOL prepareNextSegment = EAS_FALSE; | |
EAS_U32 jetEvent; | |
/* process event queue */ | |
while (JET_ReadQueue(easHandle->jetHandle->jetEventQueue, | |
&easHandle->jetHandle->jetEventQueueRead, | |
easHandle->jetHandle->jetEventQueueWrite, | |
JET_EVENT_QUEUE_SIZE, &jetEvent)) | |
{ | |
S_JET_EVENT event; | |
#ifdef DEBUG_JET | |
JET_DumpEvent("JET_Process", jetEvent); | |
#endif | |
JET_ParseEvent(jetEvent, &event); | |
/* check for end of loop */ | |
if ((event.controller == JET_EVENT_MARKER) && | |
(event.value == JET_MARKER_LOOP_END) && | |
(easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle != NULL)) | |
endOfLoop = EAS_TRUE; | |
} | |
/* check state of all streams */ | |
index = playIndex = easHandle->jetHandle->playSegment; | |
for (;;) | |
{ | |
pSeg = &easHandle->jetHandle->segQueue[index]; | |
if (pSeg->state != JET_STATE_CLOSED) | |
{ | |
/* get playback state */ | |
result = EAS_State(easHandle, pSeg->streamHandle, &state); | |
if (result != EAS_SUCCESS) | |
return result; | |
/* process state */ | |
switch (pSeg->state) | |
{ | |
/* take action if this segment is stopping */ | |
case JET_STATE_PLAYING: | |
if (endOfLoop || (state == EAS_STATE_STOPPING) || (state == EAS_STATE_STOPPED)) | |
{ | |
/* handle repeats */ | |
if (pSeg->repeatCount != 0) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render repeating segment %d\n", index); */ } | |
result = EAS_Locate(easHandle, pSeg->streamHandle, 0, EAS_FALSE); | |
if (result != EAS_SUCCESS) | |
return result; | |
if (pSeg->repeatCount > 0) | |
pSeg->repeatCount--; | |
/* update mute flags if necessary */ | |
if (pSeg->flags & JET_SEG_FLAG_MUTE_UPDATE) | |
{ | |
result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); | |
if (result != EAS_SUCCESS) | |
return result; | |
pSeg->flags &= ~JET_SEG_FLAG_MUTE_UPDATE; | |
} | |
} | |
/* no repeat, start next segment */ | |
else | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render stopping queue %d\n", index); */ } | |
startNextSegment = EAS_TRUE; | |
pSeg->state = JET_STATE_STOPPING; | |
easHandle->jetHandle->playSegment = (EAS_U8) JET_NextSegment(index); | |
} | |
} | |
break; | |
/* if playback has stopped, close the segment */ | |
case JET_STATE_STOPPING: | |
if (state == EAS_STATE_STOPPED) | |
{ | |
result = JET_CloseSegment(easHandle, index); | |
if (result != EAS_SUCCESS) | |
return result; | |
} | |
break; | |
case JET_STATE_READY: | |
if (startNextSegment) | |
{ | |
result = JET_StartPlayback(easHandle, index); | |
if (result != EAS_SUCCESS) | |
return result; | |
startNextSegment = EAS_FALSE; | |
prepareNextSegment = EAS_TRUE; | |
} | |
break; | |
case JET_STATE_OPEN: | |
if (prepareNextSegment) | |
{ | |
result = JET_PrepareSegment(easHandle, index); | |
if (result != EAS_SUCCESS) | |
return result; | |
prepareNextSegment = EAS_FALSE; | |
} | |
break; | |
case JET_STATE_PAUSED: | |
break; | |
default: | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "JET_Render: Unexpected segment state %d\n", pSeg->state); */ } | |
break; | |
} | |
} | |
/* increment index */ | |
index = JET_NextSegment(index); | |
if (index == playIndex) | |
break; | |
} | |
/* if out of segments, clear playing flag */ | |
if (easHandle->jetHandle->numQueuedSegments == 0) | |
easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Event() | |
*---------------------------------------------------------------------------- | |
* Called from MIDI parser when data of interest is received | |
*---------------------------------------------------------------------------- | |
*/ | |
void JET_Event (EAS_DATA_HANDLE easHandle, EAS_U32 segTrack, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) | |
{ | |
EAS_U32 event; | |
if (easHandle->jetHandle == NULL) | |
return; | |
/* handle triggers */ | |
if (controller == JET_EVENT_TRIGGER_CLIP) | |
{ | |
S_JET_SEGMENT *pSeg; | |
EAS_INT i; | |
EAS_U32 muteFlag; | |
for (i = 0; i < JET_MUTE_QUEUE_SIZE; i++) | |
{ | |
/* search for event in queue */ | |
if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_ID_MASK) == (value & JET_CLIP_ID_MASK)) | |
{ | |
/* get segment pointer and mute flag */ | |
pSeg = &easHandle->jetHandle->segQueue[segTrack >> JET_EVENT_SEG_SHIFT]; | |
muteFlag = 1 << ((segTrack & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT); | |
/* un-mute the track */ | |
if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_TRIGGER_FLAG) && ((value & 0x40) > 0)) | |
{ | |
pSeg->muteFlags &= ~muteFlag; | |
easHandle->jetHandle->muteQueue[i] &= ~JET_CLIP_TRIGGER_FLAG; | |
} | |
/* mute the track */ | |
else | |
{ | |
EAS_U32 beforeMute ; | |
beforeMute = pSeg->muteFlags ; | |
pSeg->muteFlags |= muteFlag; | |
if (beforeMute != pSeg->muteFlags) | |
easHandle->jetHandle->muteQueue[i] = 0; | |
} | |
EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); | |
return; | |
} | |
} | |
return; | |
} | |
/* generic event stuff */ | |
event = (channel << JET_EVENT_CHAN_SHIFT) | (controller << JET_EVENT_CTRL_SHIFT) | value; | |
/* write to app queue, translate queue index to segment number */ | |
if ((controller >= easHandle->jetHandle->config.appEventRangeLow) && (controller <= easHandle->jetHandle->config.appEventRangeHigh)) | |
{ | |
event |= easHandle->jetHandle->segQueue[(segTrack & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT].userID << JET_EVENT_SEG_SHIFT; | |
#ifdef DEBUG_JET | |
JET_DumpEvent("JET_Event[app]", event); | |
#endif | |
JET_WriteQueue(easHandle->jetHandle->appEventQueue, | |
&easHandle->jetHandle->appEventQueueWrite, | |
easHandle->jetHandle->appEventQueueRead, | |
APP_EVENT_QUEUE_SIZE, | |
event); | |
} | |
/* write to JET queue */ | |
else if ((controller >= JET_EVENT_LOW) && (controller <= JET_EVENT_HIGH)) | |
{ | |
event |= segTrack; | |
#ifdef DEBUG_JET | |
JET_DumpEvent("JET_Event[jet]", event); | |
#endif | |
JET_WriteQueue(easHandle->jetHandle->jetEventQueue, | |
&easHandle->jetHandle->jetEventQueueWrite, | |
easHandle->jetHandle->jetEventQueueRead, | |
JET_EVENT_QUEUE_SIZE, | |
event); | |
} | |
} | |
/*---------------------------------------------------------------------------- | |
* JET_Clear_Queue() | |
*---------------------------------------------------------------------------- | |
* Clears the queue and stops play without a complete shutdown | |
*---------------------------------------------------------------------------- | |
*/ | |
EAS_RESULT JET_Clear_Queue(EAS_DATA_HANDLE easHandle) | |
{ | |
EAS_INT index; | |
EAS_RESULT result = EAS_SUCCESS; | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Clear_Queue\n"); */ } | |
/* pause all playing streams */ | |
for (index = 0; index < SEG_QUEUE_DEPTH; index++) | |
{ | |
if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING) | |
{ | |
result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[index].streamHandle); | |
if (result != EAS_SUCCESS) | |
return result; | |
easHandle->jetHandle->segQueue[index].state = JET_STATE_PAUSED; | |
} | |
} | |
/* close all streams */ | |
for (index = 0; index < SEG_QUEUE_DEPTH; index++) | |
{ | |
if (easHandle->jetHandle->segQueue[index].streamHandle != NULL) | |
{ | |
result = JET_CloseSegment(easHandle, index); | |
if (result != EAS_SUCCESS) | |
return result; | |
} | |
} | |
/* clear all clips */ | |
for (index = 0; index < JET_MUTE_QUEUE_SIZE ; index++) | |
{ | |
easHandle->jetHandle->muteQueue[index] = 0; | |
} | |
easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; | |
easHandle->jetHandle->playSegment = easHandle->jetHandle->queueSegment = 0; | |
return result; | |
} | |