| /*---------------------------------------------------------------------------- |
| * |
| * 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; |
| } |
| |