diff options
Diffstat (limited to 'arm-fm-22k')
74 files changed, 30372 insertions, 30372 deletions
diff --git a/arm-fm-22k/host_src/eas.h b/arm-fm-22k/host_src/eas.h index 0bb04fe..c64af49 100644 --- a/arm-fm-22k/host_src/eas.h +++ b/arm-fm-22k/host_src/eas.h @@ -1,17 +1,17 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas.h
- *
- * Contents and purpose:
- * The public interface header for the EAS synthesizer.
- *
- * This header only contains declarations that are specific
- * to this implementation.
- *
- * DO NOT MODIFY THIS FILE!
- *
- * Copyright Sonic Network Inc. 2005, 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005, 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,1039 +24,1039 @@ * 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: 852 $
- * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_H
-#define _EAS_H
-
-#include "eas_types.h"
-
-/* for C++ linkage */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* library version macro */
-#define MAKE_LIB_VERSION(a,b,c,d) (((((((EAS_U32) a <<8) | (EAS_U32) b) << 8) | (EAS_U32) c) << 8) | (EAS_U32) d)
-#define LIB_VERSION MAKE_LIB_VERSION(3, 6, 10, 14)
-
-typedef struct
-{
- EAS_U32 libVersion;
- EAS_BOOL checkedVersion;
- EAS_I32 maxVoices;
- EAS_I32 numChannels;
- EAS_I32 sampleRate;
- EAS_I32 mixBufferSize;
- EAS_BOOL filterEnabled;
- EAS_U32 buildTimeStamp;
- EAS_CHAR *buildGUID;
-} S_EAS_LIB_CONFIG;
-
-/* enumerated effects module numbers for configuration */
-typedef enum
-{
- EAS_MODULE_ENHANCER = 0,
- EAS_MODULE_COMPRESSOR,
- EAS_MODULE_REVERB,
- EAS_MODULE_CHORUS,
- EAS_MODULE_WIDENER,
- EAS_MODULE_GRAPHIC_EQ,
- EAS_MODULE_WOW,
- EAS_MODULE_MAXIMIZER,
- EAS_MODULE_TONECONTROLEQ,
- NUM_EFFECTS_MODULES
-} E_FX_MODULES;
-
-/* enumerated optional module numbers for configuration */
-typedef enum
-{
- EAS_MODULE_MMAPI_TONE_CONTROL = 0,
- EAS_MODULE_METRICS
-} E_OPT_MODULES;
-#define NUM_OPTIONAL_MODULES 2
-
-/* enumerated audio decoders for configuration */
-typedef enum
-{
- EAS_DECODER_PCM = 0,
- EAS_DECODER_SMAF_ADPCM,
- EAS_DECODER_IMA_ADPCM,
- EAS_DECODER_7BIT_SMAF_ADPCM,
- EAS_DECODER_NOT_SUPPORTED
-} E_DECODER_MODULES;
-#define NUM_DECODER_MODULES 4
-
-/* defines for EAS_PEOpenStream flags parameter */
-#define PCM_FLAGS_STEREO 0x00000100 /* stream is stereo */
-#define PCM_FLAGS_8_BIT 0x00000001 /* 8-bit format */
-#define PCM_FLAGS_UNSIGNED 0x00000010 /* unsigned format */
-#define PCM_FLAGS_STREAMING 0x80000000 /* streaming mode */
-
-/* maximum volume setting */
-#define EAS_MAX_VOLUME 100
-
-/*----------------------------------------------------------------------------
- * EAS_Init()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initialize the synthesizer library
- *
- * Inputs:
- * polyphony - number of voices to play (dynamic memory model only)
- * ppLibData - pointer to data handle variable for this instance
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData);
-
-/*----------------------------------------------------------------------------
- * EAS_Config()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns a pointer to a structure containing the configuration options
- * in this library build.
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void);
-
-/*----------------------------------------------------------------------------
- * EAS_Shutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Shuts down the library. Deallocates any memory associated with the
- * synthesizer (dynamic memory model only)
- *
- * Inputs:
- * pEASData - handle to data for this instance
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData);
-
-/*----------------------------------------------------------------------------
- * EAS_Render()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the Midi data and render PCM audio data.
- *
- * Inputs:
- * pEASData - buffer for internal EAS data
- * pOut - output buffer pointer
- * nNumRequested - requested num samples to generate
- * pnNumGenerated - actual number of samples generated
- *
- * Outputs:
- * EAS_SUCCESS if PCM data was successfully rendered
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated);
-
-/*----------------------------------------------------------------------------
- * EAS_SetRepeat()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the selected stream to repeat.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * streamHandle - handle to stream
- * repeatCount - repeat count (0 = no repeat, -1 = repeat forever)
- *
- * Outputs:
- *
- * Side Effects:
- *
- * Notes:
- * 0 = no repeat
- * 1 = repeat once, i.e. play through twice
- * -1 = repeat forever
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 repeatCount);
-
-/*----------------------------------------------------------------------------
- * EAS_GetRepeat()
- *----------------------------------------------------------------------------
- * Purpose:
- * Gets the current repeat count for the selected stream.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * streamHandle - handle to stream
- * pRrepeatCount - pointer to variable to hold repeat count
- *
- * Outputs:
- *
- * Side Effects:
- *
- * Notes:
- * 0 = no repeat
- * 1 = repeat once, i.e. play through twice
- * -1 = repeat forever
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pRepeatCount);
-
-/*----------------------------------------------------------------------------
- * EAS_SetPlaybackRate()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the playback rate.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * streamHandle - handle to stream
- * rate - rate (28-bit fractional amount)
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U32 rate);
-#define MAX_PLAYBACK_RATE (EAS_U32)(1L << 29)
-#define MIN_PLAYBACK_RATE (EAS_U32)(1L << 27)
-
-/*----------------------------------------------------------------------------
- * EAS_SetTransposition)
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the key tranposition for the synthesizer. Transposes all
- * melodic instruments by the specified amount. Range is limited
- * to +/-12 semitones.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * streamHandle - handle to stream
- * transposition - +/-12 semitones
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 transposition);
-#define MAX_TRANSPOSE 12
-
-/*----------------------------------------------------------------------------
- * EAS_SetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the polyphony of the synthesizer. Value must be >= 1 and <= the
- * maximum number of voices. This function will pin the polyphony
- * at those limits
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * synthNum - synthesizer number (0 = onboard, 1 = DSP)
- * polyphonyCount - the desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount);
-
-/*----------------------------------------------------------------------------
- * EAS_GetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current polyphony setting of the synthesizer
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * synthNum - synthesizer number (0 = onboard, 1 = DSP)
- * pPolyphonyCount - pointer to variable to receive polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount);
-
-/*----------------------------------------------------------------------------
- * EAS_SetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the polyphony of the stream. Value must be >= 1 and <= the
- * maximum number of voices. This function will pin the polyphony
- * at those limits
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * polyphonyCount - the desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 polyphonyCount);
-
-/*----------------------------------------------------------------------------
- * EAS_GetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current polyphony setting of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * pPolyphonyCount - pointer to variable to receive polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPolyphonyCount);
-
-/*----------------------------------------------------------------------------
- * EAS_SetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the priority of the stream. Determines which stream's voices
- * are stolen when there are insufficient voices for all notes.
- * Value must be in the range of 1-255, lower values are higher
- * priority. The default priority is 50.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * polyphonyCount - the desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 priority);
-
-/*----------------------------------------------------------------------------
- * EAS_GetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current priority setting of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * pPriority - pointer to variable to receive priority
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPriority);
-
-/*----------------------------------------------------------------------------
- * EAS_SetVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the master volume for the mixer. The default volume setting is
- * 90 (-10 dB). The volume range is 0 to 100 in 1dB increments.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * volume - the desired master volume
- *
- * Outputs:
- *
- *
- * Side Effects:
- * overrides any previously set master volume from sysex
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 volume);
-
-/*----------------------------------------------------------------------------
- * EAS_GetVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the master volume for the mixer in 1dB increments.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * volume - the desired master volume
- *
- * Outputs:
- *
- *
- * Side Effects:
- * overrides any previously set master volume from sysex
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_SetMaxLoad()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the maximum workload the parsers will do in a single call to
- * EAS_Render. The units are currently arbitrary, but should correlate
- * well to the actual CPU cycles consumed. The primary effect is to
- * reduce the occasional peaks in CPU cycles consumed when parsing
- * dense parts of a MIDI score. Setting maxWorkLoad to zero disables
- * the workload limiting function.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * maxLoad - the desired maximum workload
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad);
-
-/*----------------------------------------------------------------------------
- * EAS_SetMaxPCMStreams()
- *----------------------------------------------------------------------------
- * Sets the maximum number of PCM streams allowed in parsers that
- * use PCM streaming.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * maxNumStreams - maximum number of PCM streams
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams);
-
-/*----------------------------------------------------------------------------
- * EAS_OpenFile()
- *----------------------------------------------------------------------------
- * Purpose:
- * Opens a file for audio playback.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * locator - pointer to filename or other locating information
- * pStreamHandle - pointer to stream handle variable
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle);
-
-#ifdef MMAPI_SUPPORT
-/*----------------------------------------------------------------------------
- * EAS_MMAPIToneControl()
- *----------------------------------------------------------------------------
- * Purpose:
- * Opens a ToneControl file for audio playback.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * locator - pointer to filename or other locating information
- * pStreamHandle - pointer to stream handle variable
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_GetWaveFmtChunk
- *----------------------------------------------------------------------------
- * Helper function to retrieve WAVE file fmt chunk for MMAPI
- *----------------------------------------------------------------------------
- * pEASData - pointer to EAS persistent data object
- * streamHandle - stream handle
- * pFmtChunk - pointer to pointer to FMT chunk data
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_VOID_PTR *ppFmtChunk);
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_GetFileType
- *----------------------------------------------------------------------------
- * Returns the file type (see eas_types.h for enumerations)
- *----------------------------------------------------------------------------
- * pEASData - pointer to EAS persistent data object
- * streamHandle - stream handle
- * pFileType - pointer to variable to receive file type
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetFileType (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pFileType);
-
-/*----------------------------------------------------------------------------
- * EAS_ParseMetaData()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- * playLength - pointer to variable to store the play length (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - resets the parser to the start of the file
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPlayLength);
-
-/*----------------------------------------------------------------------------
- * EAS_Prepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepares the synthesizer to play the file or stream. Parses the first
- * frame of data from the file and arms the synthesizer.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_State()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the state of an audio file or stream.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_STATE *pState);
-
-/*----------------------------------------------------------------------------
- * EAS_RegisterMetaDataCallback()
- *----------------------------------------------------------------------------
- * Purpose:
- * Registers a metadata callback function for parsed metadata. To
- * de-register the callback, call this function again with parameter
- * cbFunc set to NULL.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- * cbFunc - pointer to host callback function
- * metaDataBuffer - pointer to metadata buffer
- * metaDataBufSize - maximum size of the metadata buffer
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback (
- EAS_DATA_HANDLE pEASData,
- EAS_HANDLE streamHandle,
- EAS_METADATA_CBFUNC cbFunc,
- char *metaDataBuffer,
- EAS_I32 metaDataBufSize,
- EAS_VOID_PTR pUserData);
-
-/*----------------------------------------------------------------------------
- * EAS_GetNoteCount ()
- *----------------------------------------------------------------------------
- * Returns the total number of notes played in this stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- * pNoteCount - pointer to variable to receive note count
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount);
-
-/*----------------------------------------------------------------------------
- * EAS_CloseFile()
- *----------------------------------------------------------------------------
- * Purpose:
- * Closes an audio file or stream. Playback should have either paused or
- * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_OpenMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pStreamHandle - pointer to variable to hold file or stream handle
- * streamHandle - open stream or NULL for new synthesizer instance
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *pStreamHandle, EAS_HANDLE streamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_WriteMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Send data to the MIDI stream device
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - stream handle
- * pBuffer - pointer to buffer
- * count - number of bytes to write
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream(EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 *pBuffer, EAS_I32 count);
-
-/*----------------------------------------------------------------------------
- * EAS_CloseMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Closes a raw MIDI stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_Locate()
- *----------------------------------------------------------------------------
- * Purpose:
- * Locate into the file associated with the handle.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file handle
- * milliseconds - playback offset from start of file in milliseconds
- *
- * Outputs:
- *
- *
- * Side Effects:
- * the actual offset will be quantized to the closest update period, typically
- * a resolution of 5.9ms. Notes that are started prior to this time will not
- * sound. Any notes currently playing will be shut off.
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 milliseconds, EAS_BOOL offset);
-
-/*----------------------------------------------------------------------------
- * EAS_GetRenderTime()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current playback offset
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Gets the render time clock in msecs.
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime);
-
-/*----------------------------------------------------------------------------
- * EAS_GetLocation()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current playback offset
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file handle
- *
- * Outputs:
- * The offset in milliseconds from the start of the current sequence, quantized
- * to the nearest update period. Actual resolution is typically 5.9 ms.
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pTime);
-
-/*----------------------------------------------------------------------------
- * EAS_Pause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Pauses the playback of the data associated with this handle. The audio
- * is gracefully ramped down to prevent clicks and pops. It may take several
- * buffers of audio before the audio is muted.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_Resume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resumes the playback of the data associated with this handle. The audio
- * is gracefully ramped up to prevent clicks and pops.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_GetParameter()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the parameter of a module. See E_MODULES for a list of modules
- * and the header files of the modules for a list of parameters.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * module - enumerated module number
- * param - enumerated parameter number
- * pValue - pointer to variable to receive parameter value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue);
-
-/*----------------------------------------------------------------------------
- * EAS_SetParameter()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the parameter of a module. See E_MODULES for a list of modules
- * and the header files of the modules for a list of parameters.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- * module - enumerated module number
- * param - enumerated parameter number
- * value - new parameter value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value);
-
-#ifdef _METRICS_ENABLED
-/*----------------------------------------------------------------------------
- * EAS_MetricsReport()
- *----------------------------------------------------------------------------
- * Purpose:
- * Displays the current metrics through the EAS_Report interface.
- *
- * Inputs:
- * pEASData - instance data handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData);
-
-/*----------------------------------------------------------------------------
- * EAS_MetricsReset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Displays the current metrics through the EAS_Report interface.
- *
- * Inputs:
- * pEASData - instance data handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData);
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_SetSoundLibrary()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the location of the sound library.
- *
- * Inputs:
- * pEASData - instance data handle
- * streamHandle - file or stream handle
- * pSoundLib - pointer to sound library
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_SNDLIB_HANDLE pSndLib);
-
-/*----------------------------------------------------------------------------
- * EAS_SetHeaderSearchFlag()
- *----------------------------------------------------------------------------
- * By default, when EAS_OpenFile is called, the parsers check the
- * first few bytes of the file looking for a specific header. Some
- * mobile devices may add a header to the start of a file, which
- * will prevent the parser from recognizing the file. If the
- * searchFlag is set to EAS_TRUE, the parser will search the entire
- * file looking for the header. This may enable EAS to recognize
- * some files that it would ordinarily reject. The negative is that
- * it make take slightly longer to process the EAS_OpenFile request.
- *
- * Inputs:
- * pEASData - instance data handle
- * searchFlag - search flag (EAS_TRUE or EAS_FALSE)
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag);
-
-/*----------------------------------------------------------------------------
- * EAS_SetPlayMode()
- *----------------------------------------------------------------------------
- * Some file formats support special play modes, such as iMode partial
- * play mode. This call can be used to change the play mode. The
- * default play mode (usually straight playback) is always zero.
- *
- * Inputs:
- * pEASData - instance data handle
- * handle - file or stream handle
- * playMode - play mode (see eas_types.h for enumerations)
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode);
-
-#ifdef DLS_SYNTHESIZER
-/*----------------------------------------------------------------------------
- * EAS_LoadDLSCollection()
- *----------------------------------------------------------------------------
- * Purpose:
- * Downloads a DLS collection
- *
- * Inputs:
- * pEASData - instance data handle
- * streamHandle - file or stream handle
- * locator - file locator
- *
- * Outputs:
- *
- *
- * Side Effects:
- * May overlay instruments in the GM sound set
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_FILE_LOCATOR locator);
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_SetFrameBuffer()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the frame buffer pointer passed to the IPC communications functions
- *
- * Inputs:
- * pEASData - instance data handle
- * locator - file locator
- *
- * Outputs:
- *
- *
- * Side Effects:
- * May overlay instruments in the GM sound set
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
-
-#ifdef EXTERNAL_AUDIO
-/*----------------------------------------------------------------------------
- * EAS_RegExtAudioCallback()
- *----------------------------------------------------------------------------
- * Purpose:
- * Registers callback functions for audio events.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- * cbProgChgFunc - pointer to host callback function for program change
- * cbEventFunc - pointer to host callback functio for note events
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData,
- EAS_HANDLE streamHandle,
- EAS_VOID_PTR pInstData,
- EAS_EXT_PRG_CHG_FUNC cbProgChgFunc,
- EAS_EXT_EVENT_FUNC cbEventFunc);
-
-/*----------------------------------------------------------------------------
- * EAS_GetMIDIControllers()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of MIDI controllers on the requested channel.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - file or stream handle
- * pControl - pointer to structure to receive data
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl);
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_SearchFile
- *----------------------------------------------------------------------------
- * Search file for specific sequence starting at current file
- * position. Returns offset to start of sequence.
- *
- * Inputs:
- * pEASData - pointer to EAS persistent data object
- * fileHandle - file handle
- * searchString - pointer to search sequence
- * len - length of search sequence
- * pOffset - pointer to variable to store offset to sequence
- *
- * Returns EAS_EOF if end-of-file is reached
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_SearchFile (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset);
-
-#ifdef __cplusplus
-} /* end extern "C" */
-#endif
-
-#endif /* #ifndef _EAS_H */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_H +#define _EAS_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* library version macro */ +#define MAKE_LIB_VERSION(a,b,c,d) (((((((EAS_U32) a <<8) | (EAS_U32) b) << 8) | (EAS_U32) c) << 8) | (EAS_U32) d) +#define LIB_VERSION MAKE_LIB_VERSION(3, 6, 10, 14) + +typedef struct +{ + EAS_U32 libVersion; + EAS_BOOL checkedVersion; + EAS_I32 maxVoices; + EAS_I32 numChannels; + EAS_I32 sampleRate; + EAS_I32 mixBufferSize; + EAS_BOOL filterEnabled; + EAS_U32 buildTimeStamp; + EAS_CHAR *buildGUID; +} S_EAS_LIB_CONFIG; + +/* enumerated effects module numbers for configuration */ +typedef enum +{ + EAS_MODULE_ENHANCER = 0, + EAS_MODULE_COMPRESSOR, + EAS_MODULE_REVERB, + EAS_MODULE_CHORUS, + EAS_MODULE_WIDENER, + EAS_MODULE_GRAPHIC_EQ, + EAS_MODULE_WOW, + EAS_MODULE_MAXIMIZER, + EAS_MODULE_TONECONTROLEQ, + NUM_EFFECTS_MODULES +} E_FX_MODULES; + +/* enumerated optional module numbers for configuration */ +typedef enum +{ + EAS_MODULE_MMAPI_TONE_CONTROL = 0, + EAS_MODULE_METRICS +} E_OPT_MODULES; +#define NUM_OPTIONAL_MODULES 2 + +/* enumerated audio decoders for configuration */ +typedef enum +{ + EAS_DECODER_PCM = 0, + EAS_DECODER_SMAF_ADPCM, + EAS_DECODER_IMA_ADPCM, + EAS_DECODER_7BIT_SMAF_ADPCM, + EAS_DECODER_NOT_SUPPORTED +} E_DECODER_MODULES; +#define NUM_DECODER_MODULES 4 + +/* defines for EAS_PEOpenStream flags parameter */ +#define PCM_FLAGS_STEREO 0x00000100 /* stream is stereo */ +#define PCM_FLAGS_8_BIT 0x00000001 /* 8-bit format */ +#define PCM_FLAGS_UNSIGNED 0x00000010 /* unsigned format */ +#define PCM_FLAGS_STREAMING 0x80000000 /* streaming mode */ + +/* maximum volume setting */ +#define EAS_MAX_VOLUME 100 + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * polyphony - number of voices to play (dynamic memory model only) + * ppLibData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData); + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void); + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated); + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * repeatCount - repeat count (0 = no repeat, -1 = repeat forever) + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 repeatCount); + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pRepeatCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Set the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U32 rate); +#define MAX_PLAYBACK_RATE (EAS_U32)(1L << 29) +#define MIN_PLAYBACK_RATE (EAS_U32)(1L << 27) + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 transposition); +#define MAX_TRANSPOSE 12 + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synthesizer. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-255, lower values are higher + * priority. The default priority is 50. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for the mixer. The default volume setting is + * 90 (-10 dB). The volume range is 0 to 100 in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 volume); + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the mixer in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. Setting maxWorkLoad to zero disables + * the workload limiting function. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams); + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFmtChunk - pointer to pointer to FMT chunk data + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_VOID_PTR *ppFmtChunk); +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pFileType); + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPlayLength); + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. To + * de-register the callback, call this function again with parameter + * cbFunc set to NULL. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData); + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pNoteCount - pointer to variable to receive note count + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount); + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pStreamHandle - pointer to variable to hold file or stream handle + * streamHandle - open stream or NULL for new synthesizer instance + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *pStreamHandle, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream(EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 *pBuffer, EAS_I32 count); + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 milliseconds, EAS_BOOL offset); + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue); + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value); + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_SNDLIB_HANDLE pSndLib); + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag); + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Downloads a DLS collection + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_FILE_LOCATOR locator); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* #ifndef _EAS_H */ diff --git a/arm-fm-22k/host_src/eas_build.h b/arm-fm-22k/host_src/eas_build.h index 64ccf5a..5b058e7 100644 --- a/arm-fm-22k/host_src/eas_build.h +++ b/arm-fm-22k/host_src/eas_build.h @@ -1,15 +1,15 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * host_src\eas_build.h
- *
- * Contents and purpose:
- * This file contains the build configuration for this
- * build. The buildGUIDStr is a GUID created during
- * the build process and is guaranteed to be unique
- * for each build.
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * host_src\eas_build.h + * + * Contents and purpose: + * This file contains the build configuration for this + * build. The buildGUIDStr is a GUID created during + * the build process and is guaranteed to be unique + * for each build. + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,15 +22,15 @@ * 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. - *
- * This file was autogenerated by buildid.exe
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _GUID_53c2509edf8f42e3975a054126c0cc1b_
-#define _GUID_53c2509edf8f42e3975a054126c0cc1b_
-
-#define _BUILD_VERSION_ "53c2509e-df8f-42e3-975a-054126c0cc1b"
-#define _BUILD_TIME_ 0x4743b8c9
-
-#endif /* _GUID_53c2509edf8f42e3975a054126c0cc1b_ */
+ * + * This file was autogenerated by buildid.exe + *---------------------------------------------------------------------------- +*/ + +#ifndef _GUID_53c2509edf8f42e3975a054126c0cc1b_ +#define _GUID_53c2509edf8f42e3975a054126c0cc1b_ + +#define _BUILD_VERSION_ "53c2509e-df8f-42e3-975a-054126c0cc1b" +#define _BUILD_TIME_ 0x4743b8c9 + +#endif /* _GUID_53c2509edf8f42e3975a054126c0cc1b_ */ diff --git a/arm-fm-22k/host_src/eas_chorus.h b/arm-fm-22k/host_src/eas_chorus.h index 0e9057f..998a828 100644 --- a/arm-fm-22k/host_src/eas_chorus.h +++ b/arm-fm-22k/host_src/eas_chorus.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_chorus.h
- *
- * Contents and purpose:
- * Contains parameter enumerations for the Chorus effect
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.h + * + * Contents and purpose: + * Contains parameter enumerations for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,34 +20,34 @@ * 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: 309 $
- * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef EAS_CHORUS_H
-#define EAS_CHORUS_H
-
-/* enumerated parameter settings for Chorus effect */
-typedef enum
-{
- EAS_PARAM_CHORUS_BYPASS,
- EAS_PARAM_CHORUS_PRESET,
- EAS_PARAM_CHORUS_RATE,
- EAS_PARAM_CHORUS_DEPTH,
- EAS_PARAM_CHORUS_LEVEL
-} E_CHORUS_PARAMS;
-
-typedef enum
-{
- EAS_PARAM_CHORUS_PRESET1,
- EAS_PARAM_CHORUS_PRESET2,
- EAS_PARAM_CHORUS_PRESET3,
- EAS_PARAM_CHORUS_PRESET4
-} E_CHORUS_PRESETS;
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_CHORUS_H +#define EAS_CHORUS_H + +/* enumerated parameter settings for Chorus effect */ +typedef enum +{ + EAS_PARAM_CHORUS_BYPASS, + EAS_PARAM_CHORUS_PRESET, + EAS_PARAM_CHORUS_RATE, + EAS_PARAM_CHORUS_DEPTH, + EAS_PARAM_CHORUS_LEVEL +} E_CHORUS_PARAMS; + +typedef enum +{ + EAS_PARAM_CHORUS_PRESET1, + EAS_PARAM_CHORUS_PRESET2, + EAS_PARAM_CHORUS_PRESET3, + EAS_PARAM_CHORUS_PRESET4 +} E_CHORUS_PRESETS; + + #endif
\ No newline at end of file diff --git a/arm-fm-22k/host_src/eas_config.c b/arm-fm-22k/host_src/eas_config.c index c45fbb7..0b92357 100644 --- a/arm-fm-22k/host_src/eas_config.c +++ b/arm-fm-22k/host_src/eas_config.c @@ -1,22 +1,22 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_config.c
- *
- * Contents and purpose:
- * This file contains the Configuration Module interface (CM). The CM
- * is a module compiled external to the library that sets the configuration
- * for this build. It allows the library to find optional components and
- * links to static memory allocations (when used in a static configuration).
- *
- * DO NOT MODIFY THIS FILE!
- *
- * NOTE: This module is not intended to be modified by the customer. It
- * needs to be included in the build process with the correct configuration
- * defines (see the library documentation for information on how to configure
- * the library).
- *
- * Copyright Sonic Network Inc. 2004-2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_config.c + * + * Contents and purpose: + * This file contains the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * DO NOT MODIFY THIS FILE! + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * Copyright Sonic Network Inc. 2004-2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,591 +29,591 @@ * 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: 796 $
- * $Date: 2007-08-01 00:15:25 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas.h"
-#include "eas_config.h"
-
-
-#ifdef _MFI_PARSER
-/*----------------------------------------------------------------------------
- * Vendor/Device ID for MFi Extensions
- *
- * Define the preprocessor symbols to establish the vendor ID and
- * device ID for the MFi PCM/ADPCM extensions.
- *----------------------------------------------------------------------------
-*/
-const EAS_U8 eas_MFIVendorIDMSB = (MFI_VENDOR_ID >> 8) & 0xff;
-const EAS_U8 eas_MFIVendorIDLSB = MFI_VENDOR_ID & 0xff;
-const EAS_U8 eas_MFIDeviceID = MFI_DEVICE_ID;
-#endif
-
-/*----------------------------------------------------------------------------
- *
- * parserModules
- *
- * This structure is used by the EAS library to locate file parsing
- * modules.
- *----------------------------------------------------------------------------
-*/
-
-/* define the external file parsers */
-extern EAS_VOID_PTR EAS_SMF_Parser;
-
-#ifdef _XMF_PARSER
-extern EAS_VOID_PTR EAS_XMF_Parser;
-#endif
-
-#ifdef _SMAF_PARSER
-extern EAS_VOID_PTR EAS_SMAF_Parser;
-#endif
-
-#ifdef _WAVE_PARSER
-extern EAS_VOID_PTR EAS_Wave_Parser;
-#endif
-
-#ifdef _OTA_PARSER
-extern EAS_VOID_PTR EAS_OTA_Parser;
-#endif
-
-#ifdef _IMELODY_PARSER
-extern EAS_VOID_PTR EAS_iMelody_Parser;
-#endif
-
-#ifdef _RTTTL_PARSER
-extern EAS_VOID_PTR EAS_RTTTL_Parser;
-#endif
-
-#if defined (_CMX_PARSER) || defined(_MFI_PARSER)
-extern EAS_VOID_PTR EAS_CMF_Parser;
-#endif
-
-/* initalize pointers to parser interfaces */
-/*lint -e{605} not pretty, but it works */
-EAS_VOID_PTR const parserModules[] =
-{
- &EAS_SMF_Parser,
-
-#ifdef _XMF_PARSER
- &EAS_XMF_Parser,
-#endif
-
-#ifdef _WAVE_PARSER
- &EAS_Wave_Parser,
-#endif
-
-#ifdef _SMAF_PARSER
- &EAS_SMAF_Parser,
-#endif
-
-#ifdef _OTA_PARSER
- &EAS_OTA_Parser,
-#endif
-
-#ifdef _IMELODY_PARSER
- &EAS_iMelody_Parser,
-#endif
-
-#ifdef _RTTTL_PARSER
- &EAS_RTTTL_Parser,
-#endif
-
-#if defined (_CMX_PARSER) || defined(_MFI_PARSER)
- &EAS_CMF_Parser
-#endif
-};
-#define NUM_PARSER_MODULES (sizeof(parserModules) / sizeof(EAS_VOID_PTR))
-
-/*----------------------------------------------------------------------------
- * Data Modules
- *----------------------------------------------------------------------------
-*/
-
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_SMFData;
-extern EAS_VOID_PTR eas_Data;
-extern EAS_VOID_PTR eas_MixBuffer;
-extern EAS_VOID_PTR eas_Synth;
-extern EAS_VOID_PTR eas_MIDI;
-extern EAS_VOID_PTR eas_PCMData;
-extern EAS_VOID_PTR eas_MIDIData;
-
-#ifdef _XMF_PARSER
-extern EAS_VOID_PTR eas_XMFData;
-#endif
-
-#ifdef _SMAF_PARSER
-extern EAS_VOID_PTR eas_SMAFData;
-#endif
-
-#ifdef _OTA_PARSER
-extern EAS_VOID_PTR eas_OTAData;
-#endif
-
-#ifdef _IMELODY_PARSER
-extern EAS_VOID_PTR eas_iMelodyData;
-#endif
-
-#ifdef _RTTTL_PARSER
-extern EAS_VOID_PTR eas_RTTTLData;
-#endif
-
-#ifdef _WAVE_PARSER
-extern EAS_VOID_PTR eas_WaveData;
-#endif
-
-#if defined (_CMX_PARSER) || defined(_MFI_PARSER)
-extern EAS_VOID_PTR eas_CMFData;
-#endif
-#endif
-
-/*----------------------------------------------------------------------------
- *
- * Effects Modules
- *
- * These declarations are used by the EAS library to locate
- * effects modules.
- *----------------------------------------------------------------------------
-*/
-
-#ifdef _ENHANCER_ENABLED
-extern EAS_VOID_PTR EAS_Enhancer;
-#define EAS_ENHANCER_INTERFACE &EAS_Enhancer
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_EnhancerData;
-#define EAS_ENHANCER_DATA &eas_EnhancerData
-#else
-#define EAS_ENHANCER_DATA NULL
-#endif
-#else
-#define EAS_ENHANCER_INTERFACE NULL
-#define EAS_ENHANCER_DATA NULL
-#endif
-
-#ifdef _COMPRESSOR_ENABLED
-extern EAS_VOID_PTR EAS_Compressor;
-#define EAS_COMPRESSOR_INTERFACE &EAS_Compressor
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_CompressorData;
-#define EAS_COMPRESSOR_DATA &eas_CompressorData
-#else
-#define EAS_COMPRESSOR_DATA NULL
-#endif
-#else
-#define EAS_COMPRESSOR_INTERFACE NULL
-#define EAS_COMPRESSOR_DATA NULL
-#endif
-
-#ifdef _MAXIMIZER_ENABLED
-extern EAS_VOID_PTR EAS_Maximizer;
-#define EAS_MAXIMIZER_INTERFACE &EAS_Maximizer
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_MaximizerData;
-#define EAS_MAXIMIZER_DATA &eas_MaximizerData
-#else
-#define EAS_MAXIMIZER_DATA NULL
-#endif
-#else
-#define EAS_MAXIMIZER_INTERFACE NULL
-#define EAS_MAXIMIZER_DATA NULL
-#endif
-
-
-#ifdef _REVERB_ENABLED
-extern EAS_VOID_PTR EAS_Reverb;
-#define EAS_REVERB_INTERFACE &EAS_Reverb
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_ReverbData;
-#define EAS_REVERB_DATA &eas_ReverbData
-#else
-#define EAS_REVERB_DATA NULL
-#endif
-#else
-#define EAS_REVERB_INTERFACE NULL
-#define EAS_REVERB_DATA NULL
-#endif
-
-#ifdef _CHORUS_ENABLED
-extern EAS_VOID_PTR EAS_Chorus;
-#define EAS_CHORUS_INTERFACE &EAS_Chorus
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_ChorusData;
-#define EAS_CHORUS_DATA &eas_ChorusData
-#else
-#define EAS_CHORUS_DATA NULL
-#endif
-#else
-#define EAS_CHORUS_INTERFACE NULL
-#define EAS_CHORUS_DATA NULL
-#endif
-
-#ifdef _WIDENER_ENABLED
-extern EAS_VOID_PTR EAS_Widener;
-#define EAS_WIDENER_INTERFACE &EAS_Widener
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_WidenerData;
-#define EAS_WIDENER_DATA &eas_WidenerData
-#else
-#define EAS_WIDENER_DATA NULL
-#endif
-#else
-#define EAS_WIDENER_INTERFACE NULL
-#define EAS_WIDENER_DATA NULL
-#endif
-
-#ifdef _GRAPHIC_EQ_ENABLED
-extern EAS_VOID_PTR EAS_GraphicEQ;
-#define EAS_GRAPHIC_EQ_INTERFACE &EAS_GraphicEQ
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_GraphicEQData;
-#define EAS_GRAPHIC_EQ_DATA &eas_GraphicEQData
-#else
-#define EAS_GRAPHIC_EQ_DATA NULL
-#endif
-#else
-#define EAS_GRAPHIC_EQ_INTERFACE NULL
-#define EAS_GRAPHIC_EQ_DATA NULL
-#endif
-
-#ifdef _WOW_ENABLED
-extern EAS_VOID_PTR EAS_Wow;
-#define EAS_WOW_INTERFACE &EAS_Wow
-#ifdef _STATIC_MEMORY
-#error "WOW module requires dynamic memory model"
-#else
-#define EAS_WOW_DATA NULL
-#endif
-#else
-#define EAS_WOW_INTERFACE NULL
-#define EAS_WOW_DATA NULL
-#endif
-
-#ifdef _TONECONTROLEQ_ENABLED
-extern EAS_VOID_PTR EAS_ToneControlEQ;
-#define EAS_TONECONTROLEQ_INTERFACE &EAS_ToneControlEQ
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_ToneControlEQData;
-#define EAS_TONECONTROLEQ_DATA &eas_ToneControlEQData
-#else
-#define EAS_TONECONTROLEQ_DATA NULL
-#endif
-#else
-#define EAS_TONECONTROLEQ_INTERFACE NULL
-#define EAS_TONECONTROLEQ_DATA NULL
-#endif
-
-/*lint -e{605} not pretty, but it works */
-EAS_VOID_PTR const effectsModules[] =
-{
- EAS_ENHANCER_INTERFACE,
- EAS_COMPRESSOR_INTERFACE,
- EAS_REVERB_INTERFACE,
- EAS_CHORUS_INTERFACE,
- EAS_WIDENER_INTERFACE,
- EAS_GRAPHIC_EQ_INTERFACE,
- EAS_WOW_INTERFACE,
- EAS_MAXIMIZER_INTERFACE,
- EAS_TONECONTROLEQ_INTERFACE
-};
-
-EAS_VOID_PTR const effectsData[] =
-{
- EAS_ENHANCER_DATA,
- EAS_COMPRESSOR_DATA,
- EAS_REVERB_DATA,
- EAS_CHORUS_DATA,
- EAS_WIDENER_DATA,
- EAS_GRAPHIC_EQ_DATA,
- EAS_WOW_DATA,
- EAS_MAXIMIZER_DATA,
- EAS_TONECONTROLEQ_DATA
-};
-
-/*----------------------------------------------------------------------------
- *
- * Optional Modules
- *
- * These declarations are used by the EAS library to locate
- * effects modules.
- *----------------------------------------------------------------------------
-*/
-
-#ifdef _METRICS_ENABLED
-extern EAS_VOID_PTR EAS_Metrics;
-#define EAS_METRICS_INTERFACE &EAS_Metrics
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_MetricsData;
-#define EAS_METRICS_DATA &eas_MetricsData
-#else
-#define EAS_METRICS_DATA NULL
-#endif
-#else
-#define EAS_METRICS_INTERFACE NULL
-#define EAS_METRICS_DATA NULL
-#endif
-
-#ifdef MMAPI_SUPPORT
-extern EAS_VOID_PTR EAS_TC_Parser;
-#define EAS_TONE_CONTROL_PARSER &EAS_TC_Parser
-#ifdef _STATIC_MEMORY
-extern EAS_VOID_PTR eas_TCData;
-#define EAS_TONE_CONTROL_DATA &eas_TCData
-#else
-#define EAS_TONE_CONTROL_DATA NULL
-#endif
-#else
-#define EAS_TONE_CONTROL_PARSER NULL
-#define EAS_TONE_CONTROL_DATA NULL
-#endif
-
-/*lint -e{605} not pretty, but it works */
-EAS_VOID_PTR const optionalModules[] =
-{
- EAS_TONE_CONTROL_PARSER,
- EAS_METRICS_INTERFACE
-};
-
-EAS_VOID_PTR const optionalData[] =
-{
- EAS_TONE_CONTROL_DATA,
- EAS_METRICS_DATA
-};
-
-/*----------------------------------------------------------------------------
- * EAS_CMStaticMemoryModel()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function returns true if EAS has been configured for
- * a static memory model. There are some limitations in the
- * static memory model, see the documentation for more
- * information.
- *
- * Outputs:
- * returns EAS_TRUE if a module is found
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL EAS_CMStaticMemoryModel (void)
-{
-#ifdef _STATIC_MEMORY
- return EAS_TRUE;
-#else
- return EAS_FALSE;
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumModules()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to optional modules.
- *
- * Inputs:
- * module - module number
- *
- * Outputs:
- * returns a pointer to the module function table or NULL if no module
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module)
-{
-
- if (module >= (EAS_INT) NUM_PARSER_MODULES)
- return NULL;
- return parserModules[module];
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumData()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to static memory allocations.
- *
- * Inputs:
- * dataModule - enumerated module number
- *
- * Outputs:
- * Returns handle to data or NULL if not found
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, dataModule) used only when _STATIC_MEMORY is defined */
-EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule)
-{
-
-#ifdef _STATIC_MEMORY
- switch (dataModule)
- {
-
- /* main instance data for synthesizer */
- case EAS_CM_EAS_DATA:
- return &eas_Data;
-
- /* mix buffer for mix engine */
- case EAS_CM_MIX_BUFFER:
- /*lint -e{545} lint doesn't like this because it sees the underlying type */
- return &eas_MixBuffer;
-
- /* instance data for synth */
- case EAS_CM_SYNTH_DATA:
- return &eas_Synth;
-
- /* instance data for MIDI parser */
- case EAS_CM_MIDI_DATA:
- return &eas_MIDI;
-
- /* instance data for SMF parser */
- case EAS_CM_SMF_DATA:
- return &eas_SMFData;
-
-#ifdef _XMF_PARSER
- /* instance data for XMF parser */
- case EAS_CM_XMF_DATA:
- return &eas_XMFData;
-#endif
-
-#ifdef _SMAF_PARSER
- /* instance data for SMAF parser */
- case EAS_CM_SMAF_DATA:
- return &eas_SMAFData;
-#endif
-
- /* instance data for the PCM engine */
- case EAS_CM_PCM_DATA:
- /*lint -e{545} lint doesn't like this because it sees the underlying type */
- return &eas_PCMData;
-
- case EAS_CM_MIDI_STREAM_DATA:
- return &eas_MIDIData;
-
-#ifdef _OTA_PARSER
- /* instance data for OTA parser */
- case EAS_CM_OTA_DATA:
- return &eas_OTAData;
-#endif
-
-#ifdef _IMELODY_PARSER
- /* instance data for iMelody parser */
- case EAS_CM_IMELODY_DATA:
- return &eas_iMelodyData;
-#endif
-
-#ifdef _RTTTL_PARSER
- /* instance data for RTTTL parser */
- case EAS_CM_RTTTL_DATA:
- return &eas_RTTTLData;
-#endif
-
-#ifdef _WAVE_PARSER
- /* instance data for WAVE parser */
- case EAS_CM_WAVE_DATA:
- return &eas_WaveData;
-#endif
-
-#if defined (_CMX_PARSER) || defined(_MFI_PARSER)
- /* instance data for CMF parser */
- case EAS_CM_CMF_DATA:
- return &eas_CMFData;
-#endif
-
- default:
- return NULL;
- }
-
-#else
- return NULL;
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumFXModules()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to optional effects modules.
- *
- * Inputs:
- * module - enumerated module number
- * pModule - pointer to module interface
- *
- * Outputs:
- * Returns pointer to function table or NULL if not found
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module)
-{
-
- if (module >= NUM_EFFECTS_MODULES)
- return NULL;
- return effectsModules[module];
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumFXData()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to static memory allocations.
- *
- * Inputs:
- * dataModule - enumerated module number
- * pData - pointer to handle variable
- *
- * Outputs:
- * Returns handle to data or NULL if not found
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule)
-{
-
- if (dataModule >= NUM_EFFECTS_MODULES)
- return NULL;
- return effectsData[dataModule];
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumOptModules()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to optional modules.
- *
- * Inputs:
- * module - enumerated module number
- *
- * Outputs:
- * returns pointer to function table or NULL if no module
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module)
-{
-
- /* sanity check */
- if (module >= NUM_OPTIONAL_MODULES)
- return EAS_FALSE;
- return optionalModules[module];
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumOptData()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to static memory allocations.
- *
- * Inputs:
- * dataModule - enumerated module number
- *
- * Outputs:
- * Returns handle to data or NULL if not found
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule)
-{
-
- if (dataModule >= NUM_OPTIONAL_MODULES)
- return NULL;
- return optionalData[dataModule];
-}
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 796 $ + * $Date: 2007-08-01 00:15:25 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_config.h" + + +#ifdef _MFI_PARSER +/*---------------------------------------------------------------------------- + * Vendor/Device ID for MFi Extensions + * + * Define the preprocessor symbols to establish the vendor ID and + * device ID for the MFi PCM/ADPCM extensions. + *---------------------------------------------------------------------------- +*/ +const EAS_U8 eas_MFIVendorIDMSB = (MFI_VENDOR_ID >> 8) & 0xff; +const EAS_U8 eas_MFIVendorIDLSB = MFI_VENDOR_ID & 0xff; +const EAS_U8 eas_MFIDeviceID = MFI_DEVICE_ID; +#endif + +/*---------------------------------------------------------------------------- + * + * parserModules + * + * This structure is used by the EAS library to locate file parsing + * modules. + *---------------------------------------------------------------------------- +*/ + +/* define the external file parsers */ +extern EAS_VOID_PTR EAS_SMF_Parser; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR EAS_XMF_Parser; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR EAS_SMAF_Parser; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR EAS_Wave_Parser; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR EAS_OTA_Parser; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR EAS_iMelody_Parser; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR EAS_RTTTL_Parser; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR EAS_CMF_Parser; +#endif + +/* initalize pointers to parser interfaces */ +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const parserModules[] = +{ + &EAS_SMF_Parser, + +#ifdef _XMF_PARSER + &EAS_XMF_Parser, +#endif + +#ifdef _WAVE_PARSER + &EAS_Wave_Parser, +#endif + +#ifdef _SMAF_PARSER + &EAS_SMAF_Parser, +#endif + +#ifdef _OTA_PARSER + &EAS_OTA_Parser, +#endif + +#ifdef _IMELODY_PARSER + &EAS_iMelody_Parser, +#endif + +#ifdef _RTTTL_PARSER + &EAS_RTTTL_Parser, +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + &EAS_CMF_Parser +#endif +}; +#define NUM_PARSER_MODULES (sizeof(parserModules) / sizeof(EAS_VOID_PTR)) + +/*---------------------------------------------------------------------------- + * Data Modules + *---------------------------------------------------------------------------- +*/ + +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_SMFData; +extern EAS_VOID_PTR eas_Data; +extern EAS_VOID_PTR eas_MixBuffer; +extern EAS_VOID_PTR eas_Synth; +extern EAS_VOID_PTR eas_MIDI; +extern EAS_VOID_PTR eas_PCMData; +extern EAS_VOID_PTR eas_MIDIData; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR eas_XMFData; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR eas_SMAFData; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR eas_CMFData; +#endif +#endif + +/*---------------------------------------------------------------------------- + * + * Effects Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _ENHANCER_ENABLED +extern EAS_VOID_PTR EAS_Enhancer; +#define EAS_ENHANCER_INTERFACE &EAS_Enhancer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_EnhancerData; +#define EAS_ENHANCER_DATA &eas_EnhancerData +#else +#define EAS_ENHANCER_DATA NULL +#endif +#else +#define EAS_ENHANCER_INTERFACE NULL +#define EAS_ENHANCER_DATA NULL +#endif + +#ifdef _COMPRESSOR_ENABLED +extern EAS_VOID_PTR EAS_Compressor; +#define EAS_COMPRESSOR_INTERFACE &EAS_Compressor +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_CompressorData; +#define EAS_COMPRESSOR_DATA &eas_CompressorData +#else +#define EAS_COMPRESSOR_DATA NULL +#endif +#else +#define EAS_COMPRESSOR_INTERFACE NULL +#define EAS_COMPRESSOR_DATA NULL +#endif + +#ifdef _MAXIMIZER_ENABLED +extern EAS_VOID_PTR EAS_Maximizer; +#define EAS_MAXIMIZER_INTERFACE &EAS_Maximizer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MaximizerData; +#define EAS_MAXIMIZER_DATA &eas_MaximizerData +#else +#define EAS_MAXIMIZER_DATA NULL +#endif +#else +#define EAS_MAXIMIZER_INTERFACE NULL +#define EAS_MAXIMIZER_DATA NULL +#endif + + +#ifdef _REVERB_ENABLED +extern EAS_VOID_PTR EAS_Reverb; +#define EAS_REVERB_INTERFACE &EAS_Reverb +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ReverbData; +#define EAS_REVERB_DATA &eas_ReverbData +#else +#define EAS_REVERB_DATA NULL +#endif +#else +#define EAS_REVERB_INTERFACE NULL +#define EAS_REVERB_DATA NULL +#endif + +#ifdef _CHORUS_ENABLED +extern EAS_VOID_PTR EAS_Chorus; +#define EAS_CHORUS_INTERFACE &EAS_Chorus +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ChorusData; +#define EAS_CHORUS_DATA &eas_ChorusData +#else +#define EAS_CHORUS_DATA NULL +#endif +#else +#define EAS_CHORUS_INTERFACE NULL +#define EAS_CHORUS_DATA NULL +#endif + +#ifdef _WIDENER_ENABLED +extern EAS_VOID_PTR EAS_Widener; +#define EAS_WIDENER_INTERFACE &EAS_Widener +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_WidenerData; +#define EAS_WIDENER_DATA &eas_WidenerData +#else +#define EAS_WIDENER_DATA NULL +#endif +#else +#define EAS_WIDENER_INTERFACE NULL +#define EAS_WIDENER_DATA NULL +#endif + +#ifdef _GRAPHIC_EQ_ENABLED +extern EAS_VOID_PTR EAS_GraphicEQ; +#define EAS_GRAPHIC_EQ_INTERFACE &EAS_GraphicEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_GraphicEQData; +#define EAS_GRAPHIC_EQ_DATA &eas_GraphicEQData +#else +#define EAS_GRAPHIC_EQ_DATA NULL +#endif +#else +#define EAS_GRAPHIC_EQ_INTERFACE NULL +#define EAS_GRAPHIC_EQ_DATA NULL +#endif + +#ifdef _WOW_ENABLED +extern EAS_VOID_PTR EAS_Wow; +#define EAS_WOW_INTERFACE &EAS_Wow +#ifdef _STATIC_MEMORY +#error "WOW module requires dynamic memory model" +#else +#define EAS_WOW_DATA NULL +#endif +#else +#define EAS_WOW_INTERFACE NULL +#define EAS_WOW_DATA NULL +#endif + +#ifdef _TONECONTROLEQ_ENABLED +extern EAS_VOID_PTR EAS_ToneControlEQ; +#define EAS_TONECONTROLEQ_INTERFACE &EAS_ToneControlEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ToneControlEQData; +#define EAS_TONECONTROLEQ_DATA &eas_ToneControlEQData +#else +#define EAS_TONECONTROLEQ_DATA NULL +#endif +#else +#define EAS_TONECONTROLEQ_INTERFACE NULL +#define EAS_TONECONTROLEQ_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const effectsModules[] = +{ + EAS_ENHANCER_INTERFACE, + EAS_COMPRESSOR_INTERFACE, + EAS_REVERB_INTERFACE, + EAS_CHORUS_INTERFACE, + EAS_WIDENER_INTERFACE, + EAS_GRAPHIC_EQ_INTERFACE, + EAS_WOW_INTERFACE, + EAS_MAXIMIZER_INTERFACE, + EAS_TONECONTROLEQ_INTERFACE +}; + +EAS_VOID_PTR const effectsData[] = +{ + EAS_ENHANCER_DATA, + EAS_COMPRESSOR_DATA, + EAS_REVERB_DATA, + EAS_CHORUS_DATA, + EAS_WIDENER_DATA, + EAS_GRAPHIC_EQ_DATA, + EAS_WOW_DATA, + EAS_MAXIMIZER_DATA, + EAS_TONECONTROLEQ_DATA +}; + +/*---------------------------------------------------------------------------- + * + * Optional Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _METRICS_ENABLED +extern EAS_VOID_PTR EAS_Metrics; +#define EAS_METRICS_INTERFACE &EAS_Metrics +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MetricsData; +#define EAS_METRICS_DATA &eas_MetricsData +#else +#define EAS_METRICS_DATA NULL +#endif +#else +#define EAS_METRICS_INTERFACE NULL +#define EAS_METRICS_DATA NULL +#endif + +#ifdef MMAPI_SUPPORT +extern EAS_VOID_PTR EAS_TC_Parser; +#define EAS_TONE_CONTROL_PARSER &EAS_TC_Parser +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_TCData; +#define EAS_TONE_CONTROL_DATA &eas_TCData +#else +#define EAS_TONE_CONTROL_DATA NULL +#endif +#else +#define EAS_TONE_CONTROL_PARSER NULL +#define EAS_TONE_CONTROL_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const optionalModules[] = +{ + EAS_TONE_CONTROL_PARSER, + EAS_METRICS_INTERFACE +}; + +EAS_VOID_PTR const optionalData[] = +{ + EAS_TONE_CONTROL_DATA, + EAS_METRICS_DATA +}; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void) +{ +#ifdef _STATIC_MEMORY + return EAS_TRUE; +#else + return EAS_FALSE; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module) +{ + + if (module >= (EAS_INT) NUM_PARSER_MODULES) + return NULL; + return parserModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, dataModule) used only when _STATIC_MEMORY is defined */ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule) +{ + +#ifdef _STATIC_MEMORY + switch (dataModule) + { + + /* main instance data for synthesizer */ + case EAS_CM_EAS_DATA: + return &eas_Data; + + /* mix buffer for mix engine */ + case EAS_CM_MIX_BUFFER: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_MixBuffer; + + /* instance data for synth */ + case EAS_CM_SYNTH_DATA: + return &eas_Synth; + + /* instance data for MIDI parser */ + case EAS_CM_MIDI_DATA: + return &eas_MIDI; + + /* instance data for SMF parser */ + case EAS_CM_SMF_DATA: + return &eas_SMFData; + +#ifdef _XMF_PARSER + /* instance data for XMF parser */ + case EAS_CM_XMF_DATA: + return &eas_XMFData; +#endif + +#ifdef _SMAF_PARSER + /* instance data for SMAF parser */ + case EAS_CM_SMAF_DATA: + return &eas_SMAFData; +#endif + + /* instance data for the PCM engine */ + case EAS_CM_PCM_DATA: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_PCMData; + + case EAS_CM_MIDI_STREAM_DATA: + return &eas_MIDIData; + +#ifdef _OTA_PARSER + /* instance data for OTA parser */ + case EAS_CM_OTA_DATA: + return &eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER + /* instance data for iMelody parser */ + case EAS_CM_IMELODY_DATA: + return &eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER + /* instance data for RTTTL parser */ + case EAS_CM_RTTTL_DATA: + return &eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER + /* instance data for WAVE parser */ + case EAS_CM_WAVE_DATA: + return &eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + /* instance data for CMF parser */ + case EAS_CM_CMF_DATA: + return &eas_CMFData; +#endif + + default: + return NULL; + } + +#else + return NULL; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module) +{ + + if (module >= NUM_EFFECTS_MODULES) + return NULL; + return effectsModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_EFFECTS_MODULES) + return NULL; + return effectsData[dataModule]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module) +{ + + /* sanity check */ + if (module >= NUM_OPTIONAL_MODULES) + return EAS_FALSE; + return optionalModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_OPTIONAL_MODULES) + return NULL; + return optionalData[dataModule]; +} + + diff --git a/arm-fm-22k/host_src/eas_config.h b/arm-fm-22k/host_src/eas_config.h index d16be4a..49c2ef2 100644 --- a/arm-fm-22k/host_src/eas_config.h +++ b/arm-fm-22k/host_src/eas_config.h @@ -1,22 +1,22 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_config.h
- *
- * Contents and purpose:
- * This header declares the Configuration Module interface (CM). The CM
- * is a module compiled external to the library that sets the configuration
- * for this build. It allows the library to find optional components and
- * links to static memory allocations (when used in a static configuration).
- *
- * NOTE: This module is not intended to be modified by the customer. It
- * needs to be included in the build process with the correct configuration
- * defines (see the library documentation for information on how to configure
- * the library).
- *
- * DO NOT MODIFY THIS FILE!
- *
- * Copyright 2005 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_config.h + * + * Contents and purpose: + * This header declares the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 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. @@ -29,163 +29,163 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-// sentinel
-#ifndef _EAS_CONFIG_H
-#define _EAS_CONFIG_H
-
-#include "eas_types.h"
-
-/* list of enumerators for optional modules */
-typedef enum {
- EAS_CM_FILE_PARSERS = 1
-} E_CM_ENUM_MODULES;
-
-/* list of enumerators for module and memory pointers */
-typedef enum {
- EAS_CM_EAS_DATA = 1,
- EAS_CM_MIX_BUFFER,
- EAS_CM_SYNTH_DATA,
- EAS_CM_MIDI_DATA,
- EAS_CM_SMF_DATA,
- EAS_CM_XMF_DATA,
- EAS_CM_SMAF_DATA,
- EAS_CM_PCM_DATA,
- EAS_CM_MIDI_STREAM_DATA,
- EAS_CM_METRICS_DATA,
- EAS_CM_OTA_DATA,
- EAS_CM_IMELODY_DATA,
- EAS_CM_RTTTL_DATA,
- EAS_CM_WAVE_DATA,
- EAS_CM_CMF_DATA
-} E_CM_DATA_MODULES;
-
-typedef struct
-{
- int maxSMFStreams;
- void *pSMFData;
- void *pSMFStream;
-} S_EAS_SMF_PTRS;
-
-typedef struct
-{
- int maxSMAFStreams;
- void *pSMAFData;
- void *pSMAFStream;
-} S_EAS_SMAF_PTRS;
-
-/*----------------------------------------------------------------------------
- * EAS_CMStaticMemoryModel()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function returns true if EAS has been configured for
- * a static memory model. There are some limitations in the
- * static memory model, see the documentation for more
- * information.
- *
- * Outputs:
- * returns EAS_TRUE if a module is found
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL EAS_CMStaticMemoryModel (void);
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumModules()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to optional modules.
- *
- * Inputs:
- * module - module number
- *
- * Outputs:
- * returns a pointer to the module function table or NULL if no module
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module);
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumData()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to static memory allocations.
- *
- * Inputs:
- * dataModule - enumerated module number
- *
- * Outputs:
- * Returns handle to data or NULL if not found
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule);
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumFXModules()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to optional effects modules.
- *
- * Inputs:
- * module - enumerated module number
- * pModule - pointer to module interface
- *
- * Outputs:
- * Returns pointer to function table or NULL if not found
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module);
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumFXData()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to static memory allocations.
- *
- * Inputs:
- * dataModule - enumerated module number
- * pData - pointer to handle variable
- *
- * Outputs:
- * Returns handle to data or NULL if not found
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule);
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumOptModules()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to optional modules.
- *
- * Inputs:
- * module - enumerated module number
- *
- * Outputs:
- * returns pointer to function table or NULL if no module
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module);
-
-/*----------------------------------------------------------------------------
- * EAS_CMEnumOptData()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function is used to find pointers to static memory allocations.
- *
- * Inputs:
- * dataModule - enumerated module number
- *
- * Outputs:
- * Returns handle to data or NULL if not found
- *----------------------------------------------------------------------------
-*/
-EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule);
-
-#endif /* end _EAS_CONFIG_H */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_CONFIG_H +#define _EAS_CONFIG_H + +#include "eas_types.h" + +/* list of enumerators for optional modules */ +typedef enum { + EAS_CM_FILE_PARSERS = 1 +} E_CM_ENUM_MODULES; + +/* list of enumerators for module and memory pointers */ +typedef enum { + EAS_CM_EAS_DATA = 1, + EAS_CM_MIX_BUFFER, + EAS_CM_SYNTH_DATA, + EAS_CM_MIDI_DATA, + EAS_CM_SMF_DATA, + EAS_CM_XMF_DATA, + EAS_CM_SMAF_DATA, + EAS_CM_PCM_DATA, + EAS_CM_MIDI_STREAM_DATA, + EAS_CM_METRICS_DATA, + EAS_CM_OTA_DATA, + EAS_CM_IMELODY_DATA, + EAS_CM_RTTTL_DATA, + EAS_CM_WAVE_DATA, + EAS_CM_CMF_DATA +} E_CM_DATA_MODULES; + +typedef struct +{ + int maxSMFStreams; + void *pSMFData; + void *pSMFStream; +} S_EAS_SMF_PTRS; + +typedef struct +{ + int maxSMAFStreams; + void *pSMAFData; + void *pSMAFStream; +} S_EAS_SMAF_PTRS; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule); + +#endif /* end _EAS_CONFIG_H */ diff --git a/arm-fm-22k/host_src/eas_debugmsgs.h b/arm-fm-22k/host_src/eas_debugmsgs.h index 436875b..de60259 100644 --- a/arm-fm-22k/host_src/eas_debugmsgs.h +++ b/arm-fm-22k/host_src/eas_debugmsgs.h @@ -1,43 +1,43 @@ -/* Auto-generated from source file: eas_chorusdata.c */
-/* Auto-generated from source file: eas_imelodydata.c */
-/* Auto-generated from source file: eas_mididata.c */
-/* Auto-generated from source file: eas_pan.c */
-/* Auto-generated from source file: eas_wavefiledata.c */
-/* Auto-generated from source file: eas_voicemgt.c */
-/* Auto-generated from source file: eas_ota.c */
-/* Auto-generated from source file: eas_mixbuf.c */
-/* Auto-generated from source file: eas_fmsndlib.c */
-/* Auto-generated from source file: eas_rtttl.c */
-/* Auto-generated from source file: eas_reverb.c */
-/* Auto-generated from source file: eas_fmsynth.c */
-/* Auto-generated from source file: eas_pcmdata.c */
-/* Auto-generated from source file: eas_chorus.c */
-/* Auto-generated from source file: eas_math.c */
-/* Auto-generated from source file: eas_fmengine.c */
-/* Auto-generated from source file: eas_smfdata.c */
-/* Auto-generated from source file: eas_fmtables.c */
-/* Auto-generated from source file: eas_imelody.c */
-/* Auto-generated from source file: eas_public.c */
-/* Auto-generated from source file: eas_rtttldata.c */
-/* Auto-generated from source file: eas_reverbdata.c */
-/* Auto-generated from source file: eas_imaadpcm.c */
-{ 0x2380b977, 0x00000006, "eas_imaadpcm.c[305]: IMADecoderLocate: Time=%d, samples=%d\n" },
-{ 0x2380b977, 0x00000007, "eas_imaadpcm.c[328]: IMADecoderLocate: Looped sample, numBlocks=%d, samplesPerLoop=%d, samplesInLastBlock=%d, samples=%d\n" },
-{ 0x2380b977, 0x00000008, "eas_imaadpcm.c[335]: IMADecoderLocate: Byte location in audio = %d\n" },
-{ 0x2380b977, 0x00000009, "eas_imaadpcm.c[345]: IMADecoderLocate: bytesLeft = %d\n" },
-/* Auto-generated from source file: eas_midi.c */
-/* Auto-generated from source file: eas_otadata.c */
-/* Auto-generated from source file: eas_ima_tables.c */
-/* Auto-generated from source file: eas_data.c */
-/* Auto-generated from source file: eas_pcm.c */
-/* Auto-generated from source file: eas_mixer.c */
-/* Auto-generated from source file: eas_wavefile.c */
-/* Auto-generated from source file: eas_smf.c */
-/* Auto-generated from source file: eas_wave.c */
-/* Auto-generated from source file: eas_hostmm.c */
-{ 0x1a54b6e8, 0x00000001, "eas_hostmm.c[586]: Vibrate state: %d\n" },
-{ 0x1a54b6e8, 0x00000002, "eas_hostmm.c[601]: LED state: %d\n" },
-{ 0x1a54b6e8, 0x00000003, "eas_hostmm.c[616]: Backlight state: %d\n" },
-/* Auto-generated from source file: eas_config.c */
-/* Auto-generated from source file: eas_main.c */
-{ 0xe624f4d9, 0x00000005, "eas_main.c[106]: Play length: %d.%03d (secs)\n" },
+/* Auto-generated from source file: eas_chorusdata.c */ +/* Auto-generated from source file: eas_imelodydata.c */ +/* Auto-generated from source file: eas_mididata.c */ +/* Auto-generated from source file: eas_pan.c */ +/* Auto-generated from source file: eas_wavefiledata.c */ +/* Auto-generated from source file: eas_voicemgt.c */ +/* Auto-generated from source file: eas_ota.c */ +/* Auto-generated from source file: eas_mixbuf.c */ +/* Auto-generated from source file: eas_fmsndlib.c */ +/* Auto-generated from source file: eas_rtttl.c */ +/* Auto-generated from source file: eas_reverb.c */ +/* Auto-generated from source file: eas_fmsynth.c */ +/* Auto-generated from source file: eas_pcmdata.c */ +/* Auto-generated from source file: eas_chorus.c */ +/* Auto-generated from source file: eas_math.c */ +/* Auto-generated from source file: eas_fmengine.c */ +/* Auto-generated from source file: eas_smfdata.c */ +/* Auto-generated from source file: eas_fmtables.c */ +/* Auto-generated from source file: eas_imelody.c */ +/* Auto-generated from source file: eas_public.c */ +/* Auto-generated from source file: eas_rtttldata.c */ +/* Auto-generated from source file: eas_reverbdata.c */ +/* Auto-generated from source file: eas_imaadpcm.c */ +{ 0x2380b977, 0x00000006, "eas_imaadpcm.c[305]: IMADecoderLocate: Time=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000007, "eas_imaadpcm.c[328]: IMADecoderLocate: Looped sample, numBlocks=%d, samplesPerLoop=%d, samplesInLastBlock=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000008, "eas_imaadpcm.c[335]: IMADecoderLocate: Byte location in audio = %d\n" }, +{ 0x2380b977, 0x00000009, "eas_imaadpcm.c[345]: IMADecoderLocate: bytesLeft = %d\n" }, +/* Auto-generated from source file: eas_midi.c */ +/* Auto-generated from source file: eas_otadata.c */ +/* Auto-generated from source file: eas_ima_tables.c */ +/* Auto-generated from source file: eas_data.c */ +/* Auto-generated from source file: eas_pcm.c */ +/* Auto-generated from source file: eas_mixer.c */ +/* Auto-generated from source file: eas_wavefile.c */ +/* Auto-generated from source file: eas_smf.c */ +/* Auto-generated from source file: eas_wave.c */ +/* Auto-generated from source file: eas_hostmm.c */ +{ 0x1a54b6e8, 0x00000001, "eas_hostmm.c[586]: Vibrate state: %d\n" }, +{ 0x1a54b6e8, 0x00000002, "eas_hostmm.c[601]: LED state: %d\n" }, +{ 0x1a54b6e8, 0x00000003, "eas_hostmm.c[616]: Backlight state: %d\n" }, +/* Auto-generated from source file: eas_config.c */ +/* Auto-generated from source file: eas_main.c */ +{ 0xe624f4d9, 0x00000005, "eas_main.c[106]: Play length: %d.%03d (secs)\n" }, diff --git a/arm-fm-22k/host_src/eas_host.h b/arm-fm-22k/host_src/eas_host.h index 0db0e30..b356982 100644 --- a/arm-fm-22k/host_src/eas_host.h +++ b/arm-fm-22k/host_src/eas_host.h @@ -1,16 +1,16 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_host.h
- *
- * Contents and purpose:
- * This header defines the host wrapper functions for stdio, stdlib, etc.
- * The host application must provide an abstraction layer for these functions
- * to support certain features, such as SMAF and SMF-1 conversion.
- *
- * DO NOT MODIFY THIS FILE!
- *
- * Copyright 2005 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_host.h + * + * Contents and purpose: + * This header defines the host wrapper functions for stdio, stdlib, etc. + * The host application must provide an abstraction layer for these functions + * to support certain features, such as SMAF and SMF-1 conversion. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 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. @@ -23,61 +23,61 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-// sentinel
-#ifndef _EAS_HOST_H
-#define _EAS_HOST_H
-
-#include "eas_types.h"
-
-/* for C++ linkage */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* initialization and shutdown routines */
-extern EAS_RESULT EAS_HWInit(EAS_HW_DATA_HANDLE *hwInstData);
-extern EAS_RESULT EAS_HWShutdown(EAS_HW_DATA_HANDLE hwInstData);
-
-/* memory functions */
-extern void *EAS_HWMemSet(void *s, int c, EAS_I32 n);
-extern void *EAS_HWMemCpy(void *s1, const void *s2, EAS_I32 n);
-extern EAS_I32 EAS_HWMemCmp(const void *s1, const void *s2, EAS_I32 n);
-
-/* memory allocation */
-extern void *EAS_HWMalloc(EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size);
-extern void EAS_HWFree(EAS_HW_DATA_HANDLE hwInstData, void *p);
-
-/* file I/O */
-extern EAS_RESULT EAS_HWOpenFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode);
-extern EAS_RESULT EAS_HWReadFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead);
-extern EAS_RESULT EAS_HWGetByte(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p);
-extern EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst);
-extern EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst);
-extern EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition);
-extern EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position);
-extern EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position);
-extern EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength);
-extern EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pFile);
-extern EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file);
-
-/* vibrate, LED, and backlight functions */
-extern EAS_RESULT EAS_HWVibrate(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state);
-extern EAS_RESULT EAS_HWLED(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state);
-extern EAS_RESULT EAS_HWBackLight(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state);
-
-#ifdef __cplusplus
-} /* end extern "C" */
-#endif
-
-
-/* host yield function */
-extern EAS_BOOL EAS_HWYield(EAS_HW_DATA_HANDLE hwInstData);
-#endif /* end _EAS_HOST_H */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_HOST_H +#define _EAS_HOST_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* initialization and shutdown routines */ +extern EAS_RESULT EAS_HWInit(EAS_HW_DATA_HANDLE *hwInstData); +extern EAS_RESULT EAS_HWShutdown(EAS_HW_DATA_HANDLE hwInstData); + +/* memory functions */ +extern void *EAS_HWMemSet(void *s, int c, EAS_I32 n); +extern void *EAS_HWMemCpy(void *s1, const void *s2, EAS_I32 n); +extern EAS_I32 EAS_HWMemCmp(const void *s1, const void *s2, EAS_I32 n); + +/* memory allocation */ +extern void *EAS_HWMalloc(EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size); +extern void EAS_HWFree(EAS_HW_DATA_HANDLE hwInstData, void *p); + +/* file I/O */ +extern EAS_RESULT EAS_HWOpenFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode); +extern EAS_RESULT EAS_HWReadFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead); +extern EAS_RESULT EAS_HWGetByte(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p); +extern EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition); +extern EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength); +extern EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pFile); +extern EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file); + +/* vibrate, LED, and backlight functions */ +extern EAS_RESULT EAS_HWVibrate(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWLED(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWBackLight(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + + +/* host yield function */ +extern EAS_BOOL EAS_HWYield(EAS_HW_DATA_HANDLE hwInstData); +#endif /* end _EAS_HOST_H */ diff --git a/arm-fm-22k/host_src/eas_hostmm.c b/arm-fm-22k/host_src/eas_hostmm.c index 7e58838..df24cf2 100644 --- a/arm-fm-22k/host_src/eas_hostmm.c +++ b/arm-fm-22k/host_src/eas_hostmm.c @@ -1,33 +1,33 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_hostmm.c
- *
- * Contents and purpose:
- * This file contains the host wrapper functions for stdio, stdlib, etc.
- * This is a sample version that maps the requested files to an
- * allocated memory block and uses in-memory pointers to replace
- * file system calls. The file locator (EAS_FILE_LOCATOR) handle passed
- * HWOpenFile is the same one that is passed to EAS_OpenFile. If your
- * system stores data in fixed locations (such as flash) instead of
- * using a file system, you can use the locator handle to point to
- * your memory. You will need a way of knowing the length of the
- * data stored at that location in order to respond correctly in the
- * HW_FileLength function.
- *
- * Modify this file to suit the needs of your particular system.
- *
- * EAS_MAX_FILE_HANDLES sets the maximum number of MIDI streams within
- * a MIDI type 1 file that can be played.
- *
- * EAS_HW_FILE is a structure to support the file I/O functions. It
- * comprises the base memory pointer, the file read pointer, and
- * the dup flag, which when sets, indicates that the file handle has
- * been duplicated. If your system uses in-memory resources, you
- * can eliminate the duplicate handle logic, and simply copy the
- * base memory pointer and file read pointer to the duplicate handle.
- *
- * Copyright 2005 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_hostmm.c + * + * Contents and purpose: + * This file contains the host wrapper functions for stdio, stdlib, etc. + * This is a sample version that maps the requested files to an + * allocated memory block and uses in-memory pointers to replace + * file system calls. The file locator (EAS_FILE_LOCATOR) handle passed + * HWOpenFile is the same one that is passed to EAS_OpenFile. If your + * system stores data in fixed locations (such as flash) instead of + * using a file system, you can use the locator handle to point to + * your memory. You will need a way of knowing the length of the + * data stored at that location in order to respond correctly in the + * HW_FileLength function. + * + * Modify this file to suit the needs of your particular system. + * + * EAS_MAX_FILE_HANDLES sets the maximum number of MIDI streams within + * a MIDI type 1 file that can be played. + * + * EAS_HW_FILE is a structure to support the file I/O functions. It + * comprises the base memory pointer, the file read pointer, and + * the dup flag, which when sets, indicates that the file handle has + * been duplicated. If your system uses in-memory resources, you + * can eliminate the duplicate handle logic, and simply copy the + * base memory pointer and file read pointer to the duplicate handle. + * + * Copyright 2005 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. @@ -40,621 +40,621 @@ * 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: 795 $
- * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifdef _lint
-#include "lint_stdlib.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#endif
-
-#include "eas_host.h"
-
-/* Only for debugging LED, vibrate, and backlight functions */
-#include "eas_report.h"
-
-/* this module requires dynamic memory support */
-#ifdef _STATIC_MEMORY
-#error "eas_hostmm.c requires the dynamic memory model!\n"
-#endif
-
-#ifndef EAS_MAX_FILE_HANDLES
-#define EAS_MAX_FILE_HANDLES 32
-#endif
-
-/*
- * this structure and the related function are here
- * to support the ability to create duplicate handles
- * and buffering it in memory. If your system uses
- * in-memory resources, you can eliminate the calls
- * to malloc and free, the dup flag, and simply track
- * the file size and read position.
- */
-typedef struct eas_hw_file_tag
-{
- EAS_I32 fileSize;
- EAS_I32 filePos;
- EAS_BOOL dup;
- EAS_U8 *buffer;
-} EAS_HW_FILE;
-
-typedef struct eas_hw_inst_data_tag
-{
- EAS_HW_FILE files[EAS_MAX_FILE_HANDLES];
-} EAS_HW_INST_DATA;
-
-/*----------------------------------------------------------------------------
- * EAS_HWInit
- *
- * Initialize host wrapper interface
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData)
-{
-
- /* need to track file opens for duplicate handles */
- *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA));
- if (!(*pHWInstData))
- return EAS_ERROR_MALLOC_FAILED;
-
- EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA));
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_HWShutdown
- *
- * Shut down host wrapper interface
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData)
-{
-
- free(hwInstData);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWMalloc
- *
- * Allocates dynamic memory
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size)
-{
- return malloc((size_t) size);
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWFree
- *
- * Frees dynamic memory
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-void EAS_HWFree (EAS_HW_DATA_HANDLE hwInstData, void *p)
-{
- free(p);
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWMemCpy
- *
- * Copy memory wrapper
- *
- *----------------------------------------------------------------------------
-*/
-void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount)
-{
- return memcpy(dest, src, (size_t) amount);
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWMemSet
- *
- * Set memory wrapper
- *
- *----------------------------------------------------------------------------
-*/
-void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount)
-{
- return memset(dest, val, (size_t) amount);
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWMemCmp
- *
- * Compare memory wrapper
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount)
-{
- return (EAS_I32) memcmp(s1, s2, (size_t) amount);
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWOpenFile
- *
- * Open a file for read or write
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode)
-{
- EAS_HW_FILE *file;
- FILE *ioFile;
- int i, temp;
-
- /* set return value to NULL */
- *pFile = NULL;
-
- /* only support read mode at this time */
- if (mode != EAS_FILE_READ)
- return EAS_ERROR_INVALID_FILE_MODE;
-
- /* find an empty entry in the file table */
- file = hwInstData->files;
- for (i = 0; i < EAS_MAX_FILE_HANDLES; i++)
- {
- /* is this slot being used? */
- if (file->buffer == NULL)
- {
- /* open the file */
- if ((ioFile = fopen(locator,"rb")) == NULL)
- return EAS_ERROR_FILE_OPEN_FAILED;
-
- /* determine the file size */
- if (fseek(ioFile, 0L, SEEK_END) != 0)
- return EAS_ERROR_FILE_LENGTH;
- if ((file->fileSize = ftell(ioFile)) == -1L)
- return EAS_ERROR_FILE_LENGTH;
- if (fseek(ioFile, 0L, SEEK_SET) != 0)
- return EAS_ERROR_FILE_LENGTH;
-
- /* allocate a buffer */
- file->buffer = EAS_HWMalloc(hwInstData, file->fileSize);
- if (file->buffer == NULL)
- {
- fclose(ioFile);
- return EAS_ERROR_MALLOC_FAILED;
- }
-
- /* read the file into memory */
- temp = (int) fread(file->buffer, (size_t) file->fileSize, 1, ioFile);
-
- /* close the file - don't need it any more */
- fclose(ioFile);
-
- /* check for error reading file */
- if (temp != 1)
- return EAS_ERROR_FILE_READ_FAILED;
-
- /* initialize some values */
- file->filePos = 0;
- file->dup = EAS_FALSE;
-
- *pFile = file;
- return EAS_SUCCESS;
- }
- file++;
- }
-
- /* too many open files */
- return EAS_ERROR_MAX_FILES_OPEN;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWReadFile
- *
- * Read data from a file
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead)
-{
- EAS_I32 count;
-
- /* make sure we have a valid handle */
- if (file->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- /* calculate the bytes to read */
- count = file->fileSize - file->filePos;
- if (n < count)
- count = n;
-
- /* copy the data to the requested location, and advance the pointer */
- if (count)
- EAS_HWMemCpy(pBuffer, &file->buffer[file->filePos], count);
- file->filePos += count;
- *pBytesRead = count;
-
- /* were n bytes read? */
- if (count!= n)
- return EAS_EOF;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWGetByte
- *
- * Read a byte from a file
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p)
-{
-
- /* make sure we have a valid handle */
- if (file->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- /* check for end of file */
- if (file->filePos >= file->fileSize)
- {
- *((EAS_U8*) p) = 0;
- return EAS_EOF;
- }
-
- /* get a character from the buffer */
- *((EAS_U8*) p) = file->buffer[file->filePos++];
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWGetWord
- *
- * Returns the current location in the file
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst)
-{
- EAS_RESULT result;
- EAS_U8 c1, c2;
-
- /* read 2 bytes from the file */
- if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS)
- return result;
- if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS)
- return result;
-
- /* order them as requested */
- if (msbFirst)
- *((EAS_U16*) p) = ((EAS_U16) c1 << 8) | c2;
- else
- *((EAS_U16*) p) = ((EAS_U16) c2 << 8) | c1;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWGetDWord
- *
- * Returns the current location in the file
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst)
-{
- EAS_RESULT result;
- EAS_U8 c1, c2,c3,c4;
-
- /* read 4 bytes from the file */
- if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS)
- return result;
- if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS)
- return result;
- if ((result = EAS_HWGetByte(hwInstData, file, &c3)) != EAS_SUCCESS)
- return result;
- if ((result = EAS_HWGetByte(hwInstData, file, &c4)) != EAS_SUCCESS)
- return result;
-
- /* order them as requested */
- if (msbFirst)
- *((EAS_U32*) p) = ((EAS_U32) c1 << 24) | ((EAS_U32) c2 << 16) | ((EAS_U32) c3 << 8) | c4;
- else
- *((EAS_U32*) p)= ((EAS_U32) c4 << 24) | ((EAS_U32) c3 << 16) | ((EAS_U32) c2 << 8) | c1;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWFilePos
- *
- * Returns the current location in the file
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition)
-{
-
- /* make sure we have a valid handle */
- if (file->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- *pPosition = file->filePos;
- return EAS_SUCCESS;
-} /* end EAS_HWFilePos */
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWFileSeek
- *
- * Seek to a specific location in the file
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position)
-{
-
- /* make sure we have a valid handle */
- if (file->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- /* validate new position */
- if ((position < 0) || (position > file->fileSize))
- return EAS_ERROR_FILE_SEEK;
-
- /* save new position */
- file->filePos = position;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWFileSeekOfs
- *
- * Seek forward or back relative to the current position
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position)
-{
-
- /* make sure we have a valid handle */
- if (file->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- /* determine the file position */
- position += file->filePos;
- if ((position < 0) || (position > file->fileSize))
- return EAS_ERROR_FILE_SEEK;
-
- /* save new position */
- file->filePos = position;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWFileLength
- *
- * Return the file length
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength)
-{
-
- /* make sure we have a valid handle */
- if (file->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- *pLength = file->fileSize;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWDupHandle
- *
- * Duplicate a file handle
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE *pDupFile)
-{
- EAS_HW_FILE *dupFile;
- int i;
-
- /* make sure we have a valid handle */
- if (file->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- /* find an empty entry in the file table */
- dupFile = hwInstData->files;
- for (i = 0; i < EAS_MAX_FILE_HANDLES; i++)
- {
- /* is this slot being used? */
- if (dupFile->buffer == NULL)
- {
-
- /* copy info from the handle to be duplicated */
- dupFile->filePos = file->filePos;
- dupFile->fileSize = file->fileSize;
- dupFile->buffer = file->buffer;
-
- /* set the duplicate handle flag */
- dupFile->dup = file->dup = EAS_TRUE;
-
- *pDupFile = dupFile;
- return EAS_SUCCESS;
- }
- dupFile++;
- }
-
- /* too many open files */
- return EAS_ERROR_MAX_FILES_OPEN;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWClose
- *
- * Wrapper for fclose function
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1)
-{
- EAS_HW_FILE *file2,*dupFile;
- int i;
-
-
- /* make sure we have a valid handle */
- if (file1->buffer == NULL)
- return EAS_ERROR_INVALID_HANDLE;
-
- /* check for duplicate handle */
- if (file1->dup)
- {
- dupFile = NULL;
- file2 = hwInstData->files;
- for (i = 0; i < EAS_MAX_FILE_HANDLES; i++)
- {
- /* check for duplicate */
- if ((file1 != file2) && (file2->buffer == file1->buffer))
- {
- /* is there more than one duplicate? */
- if (dupFile != NULL)
- {
- /* clear this entry and return */
- file1->buffer = NULL;
- return EAS_SUCCESS;
- }
-
- /* this is the first duplicate found */
- else
- dupFile = file2;
- }
- file2++;
- }
-
- /* there is only one duplicate, clear the dup flag */
- if (dupFile)
- dupFile->dup = EAS_FALSE;
- else
- /* if we get here, there's a serious problem */
- return EAS_ERROR_HANDLE_INTEGRITY;
-
- /* clear this entry and return */
- file1->buffer = NULL;
- return EAS_SUCCESS;
- }
-
- /* no duplicates -free the buffer */
- EAS_HWFree(hwInstData, file1->buffer);
-
- /* clear this entry and return */
- file1->buffer = NULL;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWVibrate
- *
- * Turn on/off vibrate function
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state)
-{
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000001 , state);
- return EAS_SUCCESS;
-} /* end EAS_HWVibrate */
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWLED
- *
- * Turn on/off LED
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state)
-{
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000002 , state);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWBackLight
- *
- * Turn on/off backlight
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state)
-{
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000003 , state);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * EAS_HWYield
- *
- * This function is called periodically by the EAS library to give the
- * host an opportunity to allow other tasks to run. There are two ways to
- * use this call:
- *
- * If you have a multi-tasking OS, you can call the yield function in the
- * OS to allow other tasks to run. In this case, return EAS_FALSE to tell
- * the EAS library to continue processing when control returns from this
- * function.
- *
- * If tasks run in a single thread by sequential function calls (sometimes
- * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to
- * return to the caller. Be sure to check the number of bytes rendered
- * before passing the audio buffer to the codec - it may not be filled.
- * The next call to EAS_Render will continue processing until the buffer
- * has been filled.
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, hwInstData) hwInstData available for customer use */
-EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData)
-{
- /* put your code here */
- return EAS_FALSE;
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#endif + +#include "eas_host.h" + +/* Only for debugging LED, vibrate, and backlight functions */ +#include "eas_report.h" + +/* this module requires dynamic memory support */ +#ifdef _STATIC_MEMORY +#error "eas_hostmm.c requires the dynamic memory model!\n" +#endif + +#ifndef EAS_MAX_FILE_HANDLES +#define EAS_MAX_FILE_HANDLES 32 +#endif + +/* + * this structure and the related function are here + * to support the ability to create duplicate handles + * and buffering it in memory. If your system uses + * in-memory resources, you can eliminate the calls + * to malloc and free, the dup flag, and simply track + * the file size and read position. + */ +typedef struct eas_hw_file_tag +{ + EAS_I32 fileSize; + EAS_I32 filePos; + EAS_BOOL dup; + EAS_U8 *buffer; +} EAS_HW_FILE; + +typedef struct eas_hw_inst_data_tag +{ + EAS_HW_FILE files[EAS_MAX_FILE_HANDLES]; +} EAS_HW_INST_DATA; + +/*---------------------------------------------------------------------------- + * EAS_HWInit + * + * Initialize host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData) +{ + + /* need to track file opens for duplicate handles */ + *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA)); + if (!(*pHWInstData)) + return EAS_ERROR_MALLOC_FAILED; + + EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA)); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_HWShutdown + * + * Shut down host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData) +{ + + free(hwInstData); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMalloc + * + * Allocates dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size) +{ + return malloc((size_t) size); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFree + * + * Frees dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void EAS_HWFree (EAS_HW_DATA_HANDLE hwInstData, void *p) +{ + free(p); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCpy + * + * Copy memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount) +{ + return memcpy(dest, src, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemSet + * + * Set memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount) +{ + return memset(dest, val, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCmp + * + * Compare memory wrapper + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount) +{ + return (EAS_I32) memcmp(s1, s2, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + FILE *ioFile; + int i, temp; + + /* set return value to NULL */ + *pFile = NULL; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->buffer == NULL) + { + /* open the file */ + if ((ioFile = fopen(locator,"rb")) == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + + /* determine the file size */ + if (fseek(ioFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((file->fileSize = ftell(ioFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(ioFile, 0L, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + + /* allocate a buffer */ + file->buffer = EAS_HWMalloc(hwInstData, file->fileSize); + if (file->buffer == NULL) + { + fclose(ioFile); + return EAS_ERROR_MALLOC_FAILED; + } + + /* read the file into memory */ + temp = (int) fread(file->buffer, (size_t) file->fileSize, 1, ioFile); + + /* close the file - don't need it any more */ + fclose(ioFile); + + /* check for error reading file */ + if (temp != 1) + return EAS_ERROR_FILE_READ_FAILED; + + /* initialize some values */ + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_I32 count; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* calculate the bytes to read */ + count = file->fileSize - file->filePos; + if (n < count) + count = n; + + /* copy the data to the requested location, and advance the pointer */ + if (count) + EAS_HWMemCpy(pBuffer, &file->buffer[file->filePos], count); + file->filePos += count; + *pBytesRead = count; + + /* were n bytes read? */ + if (count!= n) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for end of file */ + if (file->filePos >= file->fileSize) + { + *((EAS_U8*) p) = 0; + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->filePos++]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2; + + /* read 2 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c1 << 8) | c2; + else + *((EAS_U16*) p) = ((EAS_U16) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2,c3,c4; + + /* read 4 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c3)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c4)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c1 << 24) | ((EAS_U32) c2 << 16) | ((EAS_U32) c3 << 8) | c4; + else + *((EAS_U32*) p)= ((EAS_U32) c4 << 24) | ((EAS_U32) c3 << 16) | ((EAS_U32) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} /* end EAS_HWFilePos */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* validate new position */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* determine the file position */ + position += file->filePos; + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pLength = file->fileSize; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE *pDupFile) +{ + EAS_HW_FILE *dupFile; + int i; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupFile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupFile->buffer == NULL) + { + + /* copy info from the handle to be duplicated */ + dupFile->filePos = file->filePos; + dupFile->fileSize = file->fileSize; + dupFile->buffer = file->buffer; + + /* set the duplicate handle flag */ + dupFile->dup = file->dup = EAS_TRUE; + + *pDupFile = dupFile; + return EAS_SUCCESS; + } + dupFile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + + /* make sure we have a valid handle */ + if (file1->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->buffer == file1->buffer)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + else + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* no duplicates -free the buffer */ + EAS_HWFree(hwInstData, file1->buffer); + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWVibrate + * + * Turn on/off vibrate function + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000001 , state); + return EAS_SUCCESS; +} /* end EAS_HWVibrate */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWLED + * + * Turn on/off LED + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000002 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWBackLight + * + * Turn on/off backlight + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000003 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWYield + * + * This function is called periodically by the EAS library to give the + * host an opportunity to allow other tasks to run. There are two ways to + * use this call: + * + * If you have a multi-tasking OS, you can call the yield function in the + * OS to allow other tasks to run. In this case, return EAS_FALSE to tell + * the EAS library to continue processing when control returns from this + * function. + * + * If tasks run in a single thread by sequential function calls (sometimes + * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to + * return to the caller. Be sure to check the number of bytes rendered + * before passing the audio buffer to the codec - it may not be filled. + * The next call to EAS_Render will continue processing until the buffer + * has been filled. + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData) +{ + /* put your code here */ + return EAS_FALSE; +} + diff --git a/arm-fm-22k/host_src/eas_main.c b/arm-fm-22k/host_src/eas_main.c index 809a132..6ebb13e 100644 --- a/arm-fm-22k/host_src/eas_main.c +++ b/arm-fm-22k/host_src/eas_main.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_main.c
- *
- * Contents and purpose:
- * The entry point and high-level functions for the EAS Synthesizer test
- * harness.
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_main.c + * + * Contents and purpose: + * The entry point and high-level functions for the EAS Synthesizer test + * harness. + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,442 +20,442 @@ * 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: 775 $
- * $Date: 2007-07-20 10:11:11 -0700 (Fri, 20 Jul 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifdef _lint
-#include "lint_stdlib.h"
-#else
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#endif
-
-#include "eas.h"
-#include "eas_wave.h"
-#include "eas_report.h"
-
-/* determines how many EAS buffers to fill a host buffer */
-#define NUM_BUFFERS 8
-
-/* default file to play if no filename is specified on the command line */
-static const char defaultTestFile[] = "test.mid";
-
-EAS_I32 polyphony;
-
-/* prototypes for helper functions */
-static void StrCopy(char *dest, const char *src, EAS_I32 size);
-static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size);
-static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize);
-static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig);
-
-/* main is defined after playfile to avoid the need for two passes through lint */
-
-/*----------------------------------------------------------------------------
- * PlayFile()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function plays the file requested by filename
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-
-static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize)
-{
- EAS_HANDLE handle;
- EAS_RESULT result, reportResult;
- EAS_I32 count;
- EAS_STATE state;
- EAS_I32 playTime;
- char waveFilename[256];
- WAVE_FILE *wFile;
- EAS_INT i;
- EAS_PCM *p;
-
- /* determine the name of the output file */
- wFile = NULL;
- if (outputFile == NULL)
- {
- StrCopy(waveFilename, filename, sizeof(waveFilename));
- if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename)))
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ }
- return EAS_FAILURE;
- }
- outputFile = waveFilename;
- }
-
- /* call EAS library to open file */
- if ((reportResult = EAS_OpenFile(easData, filename, &handle)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ }
- return reportResult;
- }
-
- /* prepare to play the file */
- if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ }
- reportResult = result;
- }
-
- /* get play length */
- if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ }
- return result;
- }
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000);
-
- if (reportResult == EAS_SUCCESS)
- {
- /* create the output file */
- wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8);
- if (!wFile)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ }
- reportResult = EAS_FAILURE;
- }
- }
-
- /* rendering loop */
- while (reportResult == EAS_SUCCESS)
- {
-
- /* we may render several buffers here to fill one host buffer */
- for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels)
- {
-
- /* get the current time */
- if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ }
- if (reportResult == EAS_SUCCESS)
- reportResult = result;
- break;
- }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ }
-
- /* render a buffer of audio */
- if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ }
- if (reportResult == EAS_SUCCESS)
- reportResult = result;
- }
- }
-
- if (result == EAS_SUCCESS)
- {
- /* write it to the wave file */
- if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ }
- reportResult = EAS_FAILURE;
- }
- }
-
- if (reportResult == EAS_SUCCESS)
- {
- /* check stream state */
- if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ }
- reportResult = result;
- }
-
- /* is playback complete */
- if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR))
- break;
- }
- }
-
- /* close the output file */
- if (wFile)
- {
- if (!WaveFileClose(wFile))
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ }
- if (reportResult == EAS_SUCCESS)
- result = EAS_FAILURE;
- }
- }
-
- /* close the input file */
- if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ }
- if (reportResult == EAS_SUCCESS)
- result = EAS_FAILURE;
- }
-
- return reportResult;
-} /* end PlayFile */
-
-/*----------------------------------------------------------------------------
- * main()
- *----------------------------------------------------------------------------
- * Purpose: The entry point for the EAS sample application
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-int main( int argc, char **argv )
-{
- EAS_DATA_HANDLE easData;
- const S_EAS_LIB_CONFIG *pLibConfig;
- void *buffer;
- EAS_RESULT result, playResult;
- EAS_I32 bufferSize;
- int i;
- int temp;
- FILE *debugFile;
- char *outputFile = NULL;
-
- /* set the error reporting level */
- EAS_SetDebugLevel(_EAS_SEVERITY_INFO);
- debugFile = NULL;
-
- /* process command-line arguments */
- for (i = 1; i < argc; i++)
- {
- /* check for switch */
- if (argv[i][0] == '-')
- {
- switch (argv[i][1])
- {
- case 'd':
- temp = argv[i][2];
- if ((temp >= '0') || (temp <= '9'))
- EAS_SetDebugLevel(temp);
- else
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ }
- break;
- case 'f':
- if ((debugFile = fopen(&argv[i][2],"w")) == NULL)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ }
- else
- EAS_SetDebugFile(debugFile, EAS_TRUE);
- break;
- case 'o':
- outputFile = &argv[i][2];
- break;
- case 'p':
- polyphony = atoi(&argv[i][2]);
- if (polyphony < 1)
- polyphony = 1;
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ }
- break;
- default:
- break;
- }
- continue;
- }
- }
-
- /* assume success */
- playResult = EAS_SUCCESS;
-
- /* get the library configuration */
- pLibConfig = EAS_Config();
- if (!EASLibraryCheck(pLibConfig))
- return -1;
- if (polyphony > pLibConfig->maxVoices)
- polyphony = pLibConfig->maxVoices;
-
- /* calculate buffer size */
- bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS;
-
- /* allocate output buffer memory */
- buffer = malloc((EAS_U32)bufferSize);
- if (!buffer)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ }
- return EAS_FAILURE;
- }
-
- /* initialize the EAS library */
- polyphony = pLibConfig->maxVoices;
- if ((result = EAS_Init(&easData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ }
- free(buffer);
- return result;
- }
-
- /*
- * Some debugging environments don't allow for passed parameters.
- * In this case, just play the default MIDI file "test.mid"
- */
- if (argc < 2)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ }
- if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ }
- }
- }
- /* iterate through the list of files to be played */
- else
- {
- for (i = 1; i < argc; i++)
- {
- /* check for switch */
- if (argv[i][0] != '-')
- {
-
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ }
- if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ }
- break;
- }
- }
- }
- }
-
- /* shutdown the EAS library */
- if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ }
- }
-
- /* free the output buffer */
- free(buffer);
-
- /* close the debug file */
- if (debugFile)
- fclose(debugFile);
-
- /* play errors take precedence over shutdown errors */
- if (playResult != EAS_SUCCESS)
- return playResult;
- return result;
-} /* end main */
-
-/*----------------------------------------------------------------------------
- * StrCopy()
- *----------------------------------------------------------------------------
- * Purpose:
- * Safe string copy
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static void StrCopy(char *dest, const char *src, EAS_I32 size)
-{
- int len;
-
- strncpy(dest, src, (size_t) size-1);
- len = (int) strlen(src);
- if (len < size)
- dest[len] = 0;
-} /* end StrCopy */
-
-/*----------------------------------------------------------------------------
- * ChangeFileExt()
- *----------------------------------------------------------------------------
- * Purpose:
- * Changes the file extension of a filename
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size)
-{
- char *p;
-
- /* find the extension, if any */
- p = strrchr(str,'.');
- if (!p)
- {
- if ((EAS_I32)(strlen(str) + 5) > size)
- return EAS_FALSE;
- strcat(str,".");
- strcat(str,ext);
- return EAS_TRUE;
- }
-
- /* make sure there's room for the extension */
- p++;
- *p = 0;
- if ((EAS_I32)(strlen(str) + 4) > size)
- return EAS_FALSE;
- strcat(str,ext);
- return EAS_TRUE;
-} /* end ChangeFileExt */
-
-/*----------------------------------------------------------------------------
- * EASLibraryCheck()
- *----------------------------------------------------------------------------
- * Purpose:
- * Displays the library version and checks it against the header
- * file used to build this code.
- *
- * Inputs:
- * pLibConfig - library configuration retrieved from the library
- *
- * Outputs:
- * returns EAS_TRUE if matched
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig)
-{
-
- /* display the library version */
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n",
- pLibConfig->libVersion >> 24,
- (pLibConfig->libVersion >> 16) & 0x0f,
- (pLibConfig->libVersion >> 8) & 0x0f,
- pLibConfig->libVersion & 0x0f); */ }
-
- /* display some info about the library build */
- if (pLibConfig->checkedVersion)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ }
- if (pLibConfig->filterEnabled)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ }
-#ifndef _WIN32_WCE
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ }
-#endif
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ }
-
- /* check it against the header file used to build this code */
- /*lint -e{778} constant expression used for display purposes may evaluate to zero */
- if (LIB_VERSION != pLibConfig->libVersion)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n",
- LIB_VERSION >> 24,
- (LIB_VERSION >> 16) & 0x0f,
- (LIB_VERSION >> 8) & 0x0f,
- LIB_VERSION & 0x0f); */ }
- return EAS_FALSE;
- }
- return EAS_TRUE;
-} /* end EASLibraryCheck */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 775 $ + * $Date: 2007-07-20 10:11:11 -0700 (Fri, 20 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#endif + +#include "eas.h" +#include "eas_wave.h" +#include "eas_report.h" + +/* determines how many EAS buffers to fill a host buffer */ +#define NUM_BUFFERS 8 + +/* default file to play if no filename is specified on the command line */ +static const char defaultTestFile[] = "test.mid"; + +EAS_I32 polyphony; + +/* prototypes for helper functions */ +static void StrCopy(char *dest, const char *src, EAS_I32 size); +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size); +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize); +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig); + +/* main is defined after playfile to avoid the need for two passes through lint */ + +/*---------------------------------------------------------------------------- + * PlayFile() + *---------------------------------------------------------------------------- + * Purpose: + * This function plays the file requested by filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize) +{ + EAS_HANDLE handle; + EAS_RESULT result, reportResult; + EAS_I32 count; + EAS_STATE state; + EAS_I32 playTime; + char waveFilename[256]; + WAVE_FILE *wFile; + EAS_INT i; + EAS_PCM *p; + + /* determine the name of the output file */ + wFile = NULL; + if (outputFile == NULL) + { + StrCopy(waveFilename, filename, sizeof(waveFilename)); + if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename))) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ } + return EAS_FAILURE; + } + outputFile = waveFilename; + } + + /* call EAS library to open file */ + if ((reportResult = EAS_OpenFile(easData, filename, &handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ } + return reportResult; + } + + /* prepare to play the file */ + if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ } + reportResult = result; + } + + /* get play length */ + if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ } + return result; + } + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000); + + if (reportResult == EAS_SUCCESS) + { + /* create the output file */ + wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8); + if (!wFile) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ } + reportResult = EAS_FAILURE; + } + } + + /* rendering loop */ + while (reportResult == EAS_SUCCESS) + { + + /* we may render several buffers here to fill one host buffer */ + for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels) + { + + /* get the current time */ + if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + break; + } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ } + + /* render a buffer of audio */ + if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + if (result == EAS_SUCCESS) + { + /* write it to the wave file */ + if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ } + reportResult = EAS_FAILURE; + } + } + + if (reportResult == EAS_SUCCESS) + { + /* check stream state */ + if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ } + reportResult = result; + } + + /* is playback complete */ + if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) + break; + } + } + + /* close the output file */ + if (wFile) + { + if (!WaveFileClose(wFile)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + } + + /* close the input file */ + if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + + return reportResult; +} /* end PlayFile */ + +/*---------------------------------------------------------------------------- + * main() + *---------------------------------------------------------------------------- + * Purpose: The entry point for the EAS sample application + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +int main( int argc, char **argv ) +{ + EAS_DATA_HANDLE easData; + const S_EAS_LIB_CONFIG *pLibConfig; + void *buffer; + EAS_RESULT result, playResult; + EAS_I32 bufferSize; + int i; + int temp; + FILE *debugFile; + char *outputFile = NULL; + + /* set the error reporting level */ + EAS_SetDebugLevel(_EAS_SEVERITY_INFO); + debugFile = NULL; + + /* process command-line arguments */ + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'd': + temp = argv[i][2]; + if ((temp >= '0') || (temp <= '9')) + EAS_SetDebugLevel(temp); + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ } + break; + case 'f': + if ((debugFile = fopen(&argv[i][2],"w")) == NULL) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ } + else + EAS_SetDebugFile(debugFile, EAS_TRUE); + break; + case 'o': + outputFile = &argv[i][2]; + break; + case 'p': + polyphony = atoi(&argv[i][2]); + if (polyphony < 1) + polyphony = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ } + break; + default: + break; + } + continue; + } + } + + /* assume success */ + playResult = EAS_SUCCESS; + + /* get the library configuration */ + pLibConfig = EAS_Config(); + if (!EASLibraryCheck(pLibConfig)) + return -1; + if (polyphony > pLibConfig->maxVoices) + polyphony = pLibConfig->maxVoices; + + /* calculate buffer size */ + bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS; + + /* allocate output buffer memory */ + buffer = malloc((EAS_U32)bufferSize); + if (!buffer) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ } + return EAS_FAILURE; + } + + /* initialize the EAS library */ + polyphony = pLibConfig->maxVoices; + if ((result = EAS_Init(&easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ } + free(buffer); + return result; + } + + /* + * Some debugging environments don't allow for passed parameters. + * In this case, just play the default MIDI file "test.mid" + */ + if (argc < 2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ } + if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ } + } + } + /* iterate through the list of files to be played */ + else + { + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] != '-') + { + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ } + if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ } + break; + } + } + } + } + + /* shutdown the EAS library */ + if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ } + } + + /* free the output buffer */ + free(buffer); + + /* close the debug file */ + if (debugFile) + fclose(debugFile); + + /* play errors take precedence over shutdown errors */ + if (playResult != EAS_SUCCESS) + return playResult; + return result; +} /* end main */ + +/*---------------------------------------------------------------------------- + * StrCopy() + *---------------------------------------------------------------------------- + * Purpose: + * Safe string copy + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void StrCopy(char *dest, const char *src, EAS_I32 size) +{ + int len; + + strncpy(dest, src, (size_t) size-1); + len = (int) strlen(src); + if (len < size) + dest[len] = 0; +} /* end StrCopy */ + +/*---------------------------------------------------------------------------- + * ChangeFileExt() + *---------------------------------------------------------------------------- + * Purpose: + * Changes the file extension of a filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size) +{ + char *p; + + /* find the extension, if any */ + p = strrchr(str,'.'); + if (!p) + { + if ((EAS_I32)(strlen(str) + 5) > size) + return EAS_FALSE; + strcat(str,"."); + strcat(str,ext); + return EAS_TRUE; + } + + /* make sure there's room for the extension */ + p++; + *p = 0; + if ((EAS_I32)(strlen(str) + 4) > size) + return EAS_FALSE; + strcat(str,ext); + return EAS_TRUE; +} /* end ChangeFileExt */ + +/*---------------------------------------------------------------------------- + * EASLibraryCheck() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the library version and checks it against the header + * file used to build this code. + * + * Inputs: + * pLibConfig - library configuration retrieved from the library + * + * Outputs: + * returns EAS_TRUE if matched + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig) +{ + + /* display the library version */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n", + pLibConfig->libVersion >> 24, + (pLibConfig->libVersion >> 16) & 0x0f, + (pLibConfig->libVersion >> 8) & 0x0f, + pLibConfig->libVersion & 0x0f); */ } + + /* display some info about the library build */ + if (pLibConfig->checkedVersion) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ } + if (pLibConfig->filterEnabled) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ } +#ifndef _WIN32_WCE + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ } +#endif + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ } + + /* check it against the header file used to build this code */ + /*lint -e{778} constant expression used for display purposes may evaluate to zero */ + if (LIB_VERSION != pLibConfig->libVersion) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n", + LIB_VERSION >> 24, + (LIB_VERSION >> 16) & 0x0f, + (LIB_VERSION >> 8) & 0x0f, + LIB_VERSION & 0x0f); */ } + return EAS_FALSE; + } + return EAS_TRUE; +} /* end EASLibraryCheck */ + diff --git a/arm-fm-22k/host_src/eas_report.c b/arm-fm-22k/host_src/eas_report.c index d4dd22c..04a828c 100644 --- a/arm-fm-22k/host_src/eas_report.c +++ b/arm-fm-22k/host_src/eas_report.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_report.c
- *
- * Contents and purpose:
- * This file contains the debug message handling routines for the EAS library.
- * These routines should be modified as needed for your system.
- *
- * Copyright 2005 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_report.c + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * Copyright 2005 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. @@ -20,245 +20,245 @@ * 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: 659 $
- * $Date: 2007-04-24 13:36:35 -0700 (Tue, 24 Apr 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifdef _lint
-#include "lint_stdlib.h"
-#else
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#endif
-
-#include "eas_report.h"
-
-static int severityLevel = 9999;
-
-/* debug file */
-static FILE *debugFile = NULL;
-int flush = 0;
-
-#ifndef _NO_DEBUG_PREPROCESSOR
-
-/* structure should have an #include for each error message header file */
-S_DEBUG_MESSAGES debugMessages[] =
-{
-#ifndef UNIFIED_DEBUG_MESSAGES
-#include "eas_config_msgs.h"
-
-
-#include "eas_host_msgs.h"
-#include "eas_hostmm_msgs.h"
-#include "eas_math_msgs.h"
-#include "eas_midi_msgs.h"
-#include "eas_mixer_msgs.h"
-#include "eas_pcm_msgs.h"
-#include "eas_public_msgs.h"
-#include "eas_smf_msgs.h"
-#include "eas_wave_msgs.h"
-#include "eas_voicemgt_msgs.h"
-
-#ifdef _FM_SYNTH
-#include "eas_fmsynth_msgs.h"
-#include "eas_fmengine_msgs.h"
-#endif
-
-#ifdef _WT_SYNTH
-#include "eas_wtsynth_msgs.h"
-#include "eas_wtengine_msgs.h"
-#endif
-
-#ifdef _ARM_TEST_MAIN
-#include "arm_main_msgs.h"
-#endif
-
-#ifdef _EAS_MAIN
-#include "eas_main_msgs.h"
-#endif
-
-#ifdef _EAS_MAIN_IPC
-#include "eas_main_ipc_msgs.h"
-#endif
-
-#ifdef _METRICS_ENABLED
-#include "eas_perf_msgs.h"
-#endif
-
-#ifdef _COMPRESSOR_ENABLED
-#include "eas_compressor_msgs.h"
-#endif
-
-#ifdef _ENHANCER_ENABLED
-#include "eas_enhancer_msgs.h"
-#endif
-
-#ifdef _WOW_ENABLED
-#include "eas_wow_msgs.h"
-#endif
-
-#ifdef _SMAF_PARSER
-#include "eas_smaf_msgs.h"
-#endif
-
-#ifdef _OTA_PARSER
-#include "eas_ota_msgs.h"
-#endif
-
-#ifdef _IMELODY_PARSER
-#include "eas_imelody_msgs.h"
-#endif
-
-#ifdef _WAVE_PARSER
-#include "eas_wavefile_msgs.h"
-#endif
-
-#if defined(_CMX_PARSER) || defined(_MFI_PARSER)
-#include "eas_cmf_msgs.h"
-#endif
-
-#if defined(_CMX_PARSER) || defined(_MFI_PARSER) || defined(_WAVE_PARSER)
-#include "eas_imaadpcm_msgs.h"
-#endif
-
-#else
-#include "eas_debugmsgs.h"
-#endif
-
-/* denotes end of error messages */
-{ 0,0,0 }
-};
-
-/*----------------------------------------------------------------------------
- * EAS_ReportEx()
- *
- * This is the error message handler. The default handler outputs error
- * messages to stdout. Modify this as needed for your system.
- *----------------------------------------------------------------------------
-*/
-void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...)
-{
- va_list vargs;
- int i;
-
- /* check severity level */
- if (severity > severityLevel)
- return;
-
- /* find the error message and output to stdout */
- /*lint -e{661} we check for NULL pointer - no fence post error here */
- for (i = 0; debugMessages[i].m_pDebugMsg; i++)
- {
- if ((debugMessages[i].m_nHashCode == hashCode) &&
- (debugMessages[i].m_nSerialNum == serialNum))
- {
- /*lint -e{826} <allow variable args> */
- va_start(vargs, serialNum);
- if (debugFile)
- {
- vfprintf(debugFile, debugMessages[i].m_pDebugMsg, vargs);
- if (flush)
- fflush(debugFile);
- }
- else
- {
- vprintf(debugMessages[i].m_pDebugMsg, vargs);
- }
- va_end(vargs);
- return;
- }
- }
- printf("Unrecognized error: Severity=%d; HashCode=%lu; SerialNum=%d\n", severity, hashCode, serialNum);
-} /* end EAS_ReportEx */
-
-#else
-/*----------------------------------------------------------------------------
- * EAS_Report()
- *
- * This is the error message handler. The default handler outputs error
- * messages to stdout. Modify this as needed for your system.
- *----------------------------------------------------------------------------
-*/
-void EAS_Report (int severity, const char *fmt, ...)
-{
- va_list vargs;
-
- /* check severity level */
- if (severity > severityLevel)
- return;
-
- /*lint -e{826} <allow variable args> */
- va_start(vargs, fmt);
- if (debugFile)
- {
- vfprintf(debugFile, fmt, vargs);
- if (flush)
- fflush(debugFile);
- }
- else
- {
- vprintf(fmt, vargs);
- }
- va_end(vargs);
-} /* end EAS_Report */
-
-/*----------------------------------------------------------------------------
- * EAS_ReportX()
- *
- * This is the error message handler. The default handler outputs error
- * messages to stdout. Modify this as needed for your system.
- *----------------------------------------------------------------------------
-*/
-void EAS_ReportX (int severity, const char *fmt, ...)
-{
- va_list vargs;
-
- /* check severity level */
- if (severity > severityLevel)
- return;
-
- /*lint -e{826} <allow variable args> */
- va_start(vargs, fmt);
- if (debugFile)
- {
- vfprintf(debugFile, fmt, vargs);
- if (flush)
- fflush(debugFile);
- }
- else
- {
- vprintf(fmt, vargs);
- }
- va_end(vargs);
-} /* end EAS_ReportX */
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_SetDebugLevel()
- *
- * Sets the level for debug message output
- *----------------------------------------------------------------------------
-*/
-
-void EAS_SetDebugLevel (int severity)
-{
- severityLevel = severity;
-} /* end EAS_SetDebugLevel */
-
-/*----------------------------------------------------------------------------
- * EAS_SetDebugFile()
- *
- * Redirect debugger output to the specified file.
- *----------------------------------------------------------------------------
-*/
-void EAS_SetDebugFile (void *file, int flushAfterWrite)
-{
- debugFile = (FILE*) file;
- flush = flushAfterWrite;
-} /* end EAS_SetDebugFile */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 659 $ + * $Date: 2007-04-24 13:36:35 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#endif + +#include "eas_report.h" + +static int severityLevel = 9999; + +/* debug file */ +static FILE *debugFile = NULL; +int flush = 0; + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure should have an #include for each error message header file */ +S_DEBUG_MESSAGES debugMessages[] = +{ +#ifndef UNIFIED_DEBUG_MESSAGES +#include "eas_config_msgs.h" + + +#include "eas_host_msgs.h" +#include "eas_hostmm_msgs.h" +#include "eas_math_msgs.h" +#include "eas_midi_msgs.h" +#include "eas_mixer_msgs.h" +#include "eas_pcm_msgs.h" +#include "eas_public_msgs.h" +#include "eas_smf_msgs.h" +#include "eas_wave_msgs.h" +#include "eas_voicemgt_msgs.h" + +#ifdef _FM_SYNTH +#include "eas_fmsynth_msgs.h" +#include "eas_fmengine_msgs.h" +#endif + +#ifdef _WT_SYNTH +#include "eas_wtsynth_msgs.h" +#include "eas_wtengine_msgs.h" +#endif + +#ifdef _ARM_TEST_MAIN +#include "arm_main_msgs.h" +#endif + +#ifdef _EAS_MAIN +#include "eas_main_msgs.h" +#endif + +#ifdef _EAS_MAIN_IPC +#include "eas_main_ipc_msgs.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf_msgs.h" +#endif + +#ifdef _COMPRESSOR_ENABLED +#include "eas_compressor_msgs.h" +#endif + +#ifdef _ENHANCER_ENABLED +#include "eas_enhancer_msgs.h" +#endif + +#ifdef _WOW_ENABLED +#include "eas_wow_msgs.h" +#endif + +#ifdef _SMAF_PARSER +#include "eas_smaf_msgs.h" +#endif + +#ifdef _OTA_PARSER +#include "eas_ota_msgs.h" +#endif + +#ifdef _IMELODY_PARSER +#include "eas_imelody_msgs.h" +#endif + +#ifdef _WAVE_PARSER +#include "eas_wavefile_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) +#include "eas_cmf_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) || defined(_WAVE_PARSER) +#include "eas_imaadpcm_msgs.h" +#endif + +#else +#include "eas_debugmsgs.h" +#endif + +/* denotes end of error messages */ +{ 0,0,0 } +}; + +/*---------------------------------------------------------------------------- + * EAS_ReportEx() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...) +{ + va_list vargs; + int i; + + /* check severity level */ + if (severity > severityLevel) + return; + + /* find the error message and output to stdout */ + /*lint -e{661} we check for NULL pointer - no fence post error here */ + for (i = 0; debugMessages[i].m_pDebugMsg; i++) + { + if ((debugMessages[i].m_nHashCode == hashCode) && + (debugMessages[i].m_nSerialNum == serialNum)) + { + /*lint -e{826} <allow variable args> */ + va_start(vargs, serialNum); + if (debugFile) + { + vfprintf(debugFile, debugMessages[i].m_pDebugMsg, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(debugMessages[i].m_pDebugMsg, vargs); + } + va_end(vargs); + return; + } + } + printf("Unrecognized error: Severity=%d; HashCode=%lu; SerialNum=%d\n", severity, hashCode, serialNum); +} /* end EAS_ReportEx */ + +#else +/*---------------------------------------------------------------------------- + * EAS_Report() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_Report (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} <allow variable args> */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_Report */ + +/*---------------------------------------------------------------------------- + * EAS_ReportX() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportX (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} <allow variable args> */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_ReportX */ +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetDebugLevel() + * + * Sets the level for debug message output + *---------------------------------------------------------------------------- +*/ + +void EAS_SetDebugLevel (int severity) +{ + severityLevel = severity; +} /* end EAS_SetDebugLevel */ + +/*---------------------------------------------------------------------------- + * EAS_SetDebugFile() + * + * Redirect debugger output to the specified file. + *---------------------------------------------------------------------------- +*/ +void EAS_SetDebugFile (void *file, int flushAfterWrite) +{ + debugFile = (FILE*) file; + flush = flushAfterWrite; +} /* end EAS_SetDebugFile */ + diff --git a/arm-fm-22k/host_src/eas_report.h b/arm-fm-22k/host_src/eas_report.h index 9d7c8e8..b603b12 100644 --- a/arm-fm-22k/host_src/eas_report.h +++ b/arm-fm-22k/host_src/eas_report.h @@ -1,15 +1,15 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_report.h
- *
- * Contents and purpose:
- * This file contains the debug message handling routines for the EAS library.
- * These routines should be modified as needed for your system.
- *
- * DO NOT MODIFY THIS FILE!
- *
- * Copyright 2005 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_report.h + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 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. @@ -22,56 +22,56 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-/* sentinel */
-#ifndef _EAS_REPORT_H
-#define _EAS_REPORT_H
-
-#define _EAS_SEVERITY_NOFILTER 0
-#define _EAS_SEVERITY_FATAL 1
-#define _EAS_SEVERITY_ERROR 2
-#define _EAS_SEVERITY_WARNING 3
-#define _EAS_SEVERITY_INFO 4
-#define _EAS_SEVERITY_DETAIL 5
-
-/* for C++ linkage */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _NO_DEBUG_PREPROCESSOR
-
-/* structure for included debug message header files */
-typedef struct
-{
- unsigned long m_nHashCode;
- int m_nSerialNum;
- char *m_pDebugMsg;
-} S_DEBUG_MESSAGES;
-
-/* debug message handling prototypes */
-extern void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...);
-
-#else
-
-/* these prototypes are used if the debug preprocessor is not used */
-extern void EAS_Report (int severity, const char* fmt, ...);
-extern void EAS_ReportX (int severity, const char* fmt, ...);
-
-#endif
-
-extern void EAS_SetDebugLevel (int severity);
-extern void EAS_SetDebugFile (void *file, int flushAfterWrite);
-
-#ifdef __cplusplus
-} /* end extern "C" */
-#endif
-
-#endif
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +/* sentinel */ +#ifndef _EAS_REPORT_H +#define _EAS_REPORT_H + +#define _EAS_SEVERITY_NOFILTER 0 +#define _EAS_SEVERITY_FATAL 1 +#define _EAS_SEVERITY_ERROR 2 +#define _EAS_SEVERITY_WARNING 3 +#define _EAS_SEVERITY_INFO 4 +#define _EAS_SEVERITY_DETAIL 5 + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure for included debug message header files */ +typedef struct +{ + unsigned long m_nHashCode; + int m_nSerialNum; + char *m_pDebugMsg; +} S_DEBUG_MESSAGES; + +/* debug message handling prototypes */ +extern void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...); + +#else + +/* these prototypes are used if the debug preprocessor is not used */ +extern void EAS_Report (int severity, const char* fmt, ...); +extern void EAS_ReportX (int severity, const char* fmt, ...); + +#endif + +extern void EAS_SetDebugLevel (int severity); +extern void EAS_SetDebugFile (void *file, int flushAfterWrite); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif diff --git a/arm-fm-22k/host_src/eas_reverb.h b/arm-fm-22k/host_src/eas_reverb.h index a2535fb..559abed 100644 --- a/arm-fm-22k/host_src/eas_reverb.h +++ b/arm-fm-22k/host_src/eas_reverb.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_reverb.h
- *
- * Contents and purpose:
- * Contains parameter enumerations for the Reverb effect
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.h + * + * Contents and purpose: + * Contains parameter enumerations for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,35 +20,35 @@ * 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: 300 $
- * $Date: 2006-09-11 17:37:20 -0700 (Mon, 11 Sep 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_REVERB_H
-#define _EAS_REVERB_H
-
-
-/* enumerated parameter settings for Reverb effect */
-typedef enum
-{
- EAS_PARAM_REVERB_BYPASS,
- EAS_PARAM_REVERB_PRESET,
- EAS_PARAM_REVERB_WET,
- EAS_PARAM_REVERB_DRY
-} E_REVERB_PARAMS;
-
-
-typedef enum
-{
- EAS_PARAM_REVERB_LARGE_HALL,
- EAS_PARAM_REVERB_HALL,
- EAS_PARAM_REVERB_CHAMBER,
- EAS_PARAM_REVERB_ROOM,
-} E_REVERB_PRESETS;
-
-
-#endif /* _REVERB_H */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 300 $ + * $Date: 2006-09-11 17:37:20 -0700 (Mon, 11 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERB_H +#define _EAS_REVERB_H + + +/* enumerated parameter settings for Reverb effect */ +typedef enum +{ + EAS_PARAM_REVERB_BYPASS, + EAS_PARAM_REVERB_PRESET, + EAS_PARAM_REVERB_WET, + EAS_PARAM_REVERB_DRY +} E_REVERB_PARAMS; + + +typedef enum +{ + EAS_PARAM_REVERB_LARGE_HALL, + EAS_PARAM_REVERB_HALL, + EAS_PARAM_REVERB_CHAMBER, + EAS_PARAM_REVERB_ROOM, +} E_REVERB_PRESETS; + + +#endif /* _REVERB_H */ diff --git a/arm-fm-22k/host_src/eas_types.h b/arm-fm-22k/host_src/eas_types.h index f0293ef..45fa4b2 100644 --- a/arm-fm-22k/host_src/eas_types.h +++ b/arm-fm-22k/host_src/eas_types.h @@ -1,17 +1,17 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_types.h
- *
- * Contents and purpose:
- * The public interface header for the EAS synthesizer.
- *
- * This header only contains declarations that are specific
- * to this implementation.
- *
- * DO NOT MODIFY THIS FILE!
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_types.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,245 +24,245 @@ * 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: 726 $
- * $Date: 2007-06-14 23:10:46 -0700 (Thu, 14 Jun 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_TYPES_H
-#define _EAS_TYPES_H
-
-/* EAS_RESULT return codes */
-typedef long EAS_RESULT;
-#define EAS_SUCCESS 0
-#define EAS_FAILURE -1
-#define EAS_ERROR_INVALID_MODULE -2
-#define EAS_ERROR_MALLOC_FAILED -3
-#define EAS_ERROR_FILE_POS -4
-#define EAS_ERROR_INVALID_FILE_MODE -5
-#define EAS_ERROR_FILE_SEEK -6
-#define EAS_ERROR_FILE_LENGTH -7
-#define EAS_ERROR_NOT_IMPLEMENTED -8
-#define EAS_ERROR_CLOSE_FAILED -9
-#define EAS_ERROR_FILE_OPEN_FAILED -10
-#define EAS_ERROR_INVALID_HANDLE -11
-#define EAS_ERROR_NO_MIX_BUFFER -12
-#define EAS_ERROR_PARAMETER_RANGE -13
-#define EAS_ERROR_MAX_FILES_OPEN -14
-#define EAS_ERROR_UNRECOGNIZED_FORMAT -15
-#define EAS_BUFFER_SIZE_MISMATCH -16
-#define EAS_ERROR_FILE_FORMAT -17
-#define EAS_ERROR_SMF_NOT_INITIALIZED -18
-#define EAS_ERROR_LOCATE_BEYOND_END -19
-#define EAS_ERROR_INVALID_PCM_TYPE -20
-#define EAS_ERROR_MAX_PCM_STREAMS -21
-#define EAS_ERROR_NO_VOICE_ALLOCATED -22
-#define EAS_ERROR_INVALID_CHANNEL -23
-#define EAS_ERROR_ALREADY_STOPPED -24
-#define EAS_ERROR_FILE_READ_FAILED -25
-#define EAS_ERROR_HANDLE_INTEGRITY -26
-#define EAS_ERROR_MAX_STREAMS_OPEN -27
-#define EAS_ERROR_INVALID_PARAMETER -28
-#define EAS_ERROR_FEATURE_NOT_AVAILABLE -29
-#define EAS_ERROR_SOUND_LIBRARY -30
-#define EAS_ERROR_NOT_VALID_IN_THIS_STATE -31
-#define EAS_ERROR_NO_VIRTUAL_SYNTHESIZER -32
-#define EAS_ERROR_FILE_ALREADY_OPEN -33
-#define EAS_ERROR_FILE_ALREADY_CLOSED -34
-#define EAS_ERROR_INCOMPATIBLE_VERSION -35
-#define EAS_ERROR_QUEUE_IS_FULL -36
-#define EAS_ERROR_QUEUE_IS_EMPTY -37
-#define EAS_ERROR_FEATURE_ALREADY_ACTIVE -38
-
-/* special return codes */
-#define EAS_EOF 3
-#define EAS_STREAM_BUFFERING 4
-#define EAS_BUFFER_FULL 5
-
-/* EAS_STATE return codes */
-typedef long EAS_STATE;
-typedef enum
-{
- EAS_STATE_READY = 0,
- EAS_STATE_PLAY,
- EAS_STATE_STOPPING,
- EAS_STATE_PAUSING,
- EAS_STATE_STOPPED,
- EAS_STATE_PAUSED,
- EAS_STATE_OPEN,
- EAS_STATE_ERROR,
- EAS_STATE_EMPTY
-} E_EAS_STATE;
-
-/* constants */
-#ifndef EAS_CONST
-#define EAS_CONST const
-#endif
-
-/* definition for public interface functions */
-#ifndef EAS_PUBLIC
-#define EAS_PUBLIC
-#endif
-
-/* boolean values */
-typedef unsigned EAS_BOOL;
-typedef unsigned char EAS_BOOL8;
-
-#define EAS_FALSE 0
-#define EAS_TRUE 1
-
-/* scalar variable definitions */
-typedef unsigned char EAS_U8;
-typedef signed char EAS_I8;
-typedef char EAS_CHAR;
-
-typedef unsigned short EAS_U16;
-typedef short EAS_I16;
-
-typedef unsigned long EAS_U32;
-typedef long EAS_I32;
-
-typedef unsigned EAS_UINT;
-typedef int EAS_INT;
-typedef long EAS_LONG;
-
-/* audio output type */
-typedef short EAS_PCM;
-
-/* file open modes */
-typedef EAS_I32 EAS_FILE_MODE;
-#define EAS_FILE_READ 1
-#define EAS_FILE_WRITE 2
-
-/* file locator e.g. filename or memory pointer */
-typedef const void *EAS_FILE_LOCATOR;
-
-/* handle to stream */
-typedef struct s_eas_stream_tag *EAS_HANDLE;
-
-/* handle to file */
-typedef struct eas_hw_file_tag *EAS_FILE_HANDLE;
-
-/* handle for synthesizer data */
-typedef struct s_eas_data_tag *EAS_DATA_HANDLE;
-
-/* handle to persistent data for host wrapper interface */
-typedef struct eas_hw_inst_data_tag *EAS_HW_DATA_HANDLE;
-
-/* handle to sound library */
-typedef struct s_eas_sndlib_tag *EAS_SNDLIB_HANDLE;
-typedef struct s_eas_dls_tag *EAS_DLSLIB_HANDLE;
-
-/* pointer to frame buffer - used in split architecture only */
-typedef struct s_eas_frame_buffer_tag *EAS_FRAME_BUFFER_HANDLE;
-
-/* untyped pointer for instance data */
-typedef void *EAS_VOID_PTR;
-
-/* inline functions */
-#ifndef EAS_INLINE
-#if defined (__XCC__)
-#define EAS_INLINE __inline__
-#elif defined (__GNUC__)
-#define EAS_INLINE inline static
-#else
-#define EAS_INLINE __inline
-#endif
-#endif
-
-/* define NULL value */
-#ifndef NULL
-#define NULL 0
-#endif
-
-/* metadata types for metadata return codes */
-typedef enum
-{
- EAS_METADATA_UNKNOWN = 0,
- EAS_METADATA_TITLE,
- EAS_METADATA_AUTHOR,
- EAS_METADATA_COPYRIGHT,
- EAS_METADATA_LYRIC,
- EAS_METADATA_TEXT
-} E_EAS_METADATA_TYPE;
-
-/* metadata callback function */
-typedef void (*EAS_METADATA_CBFUNC) (E_EAS_METADATA_TYPE metaDataType, char *metaDataBuf, EAS_VOID_PTR pUserData);
-
-/* file types for metadata return codes */
-typedef enum
-{
- EAS_FILE_UNKNOWN = 0,
- EAS_FILE_SMF0,
- EAS_FILE_SMF1,
- EAS_FILE_SMAF_UNKNOWN,
- EAS_FILE_SMAF_MA2,
- EAS_FILE_SMAF_MA3,
- EAS_FILE_SMAF_MA5,
- EAS_FILE_CMX,
- EAS_FILE_MFI,
- EAS_FILE_OTA,
- EAS_FILE_IMELODY,
- EAS_FILE_RTTTL,
- EAS_FILE_XMF0,
- EAS_FILE_XMF1,
- EAS_FILE_WAVE_PCM,
- EAS_FILE_WAVE_IMA_ADPCM,
- EAS_FILE_MMAPI_TONE_CONTROL
-} E_EAS_FILE_TYPE;
-
-/* enumeration for synthesizers */
-typedef enum
-{
- EAS_MCU_SYNTH = 0,
- EAS_DSP_SYNTH
-} E_SYNTHESIZER;
-
-/* external audio callback program change */
-typedef struct s_ext_audio_prg_chg_tag
-{
- EAS_U16 bank;
- EAS_U8 program;
- EAS_U8 channel;
-} S_EXT_AUDIO_PRG_CHG;
-
-/* external audio callback event */
-typedef struct s_ext_audio_event_tag
-{
- EAS_U8 channel;
- EAS_U8 note;
- EAS_U8 velocity;
- EAS_BOOL8 noteOn;
-} S_EXT_AUDIO_EVENT;
-
-typedef struct s_midi_controllers_tag
-{
- EAS_U8 modWheel; /* CC1 */
- EAS_U8 volume; /* CC7 */
- EAS_U8 pan; /* CC10 */
- EAS_U8 expression; /* CC11 */
- EAS_U8 channelPressure; /* MIDI channel pressure */
-
-#ifdef _REVERB
- EAS_U8 reverbSend; /* CC91 */
-#endif
-
-#ifdef _CHORUS
- EAS_U8 chorusSend; /* CC93 */
-#endif
-} S_MIDI_CONTROLLERS;
-
-/* iMode play modes enumeration for EAS_SetPlayMode */
-typedef enum
-{
- IMODE_PLAY_ALL = 0,
- IMODE_PLAY_PARTIAL
-} E_I_MODE_PLAY_MODE;
-
-typedef EAS_BOOL (*EAS_EXT_PRG_CHG_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_PRG_CHG *pPrgChg);
-typedef EAS_BOOL (*EAS_EXT_EVENT_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_EVENT *pEvent);
-
-#endif /* #ifndef _EAS_TYPES_H */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 726 $ + * $Date: 2007-06-14 23:10:46 -0700 (Thu, 14 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_TYPES_H +#define _EAS_TYPES_H + +/* EAS_RESULT return codes */ +typedef long EAS_RESULT; +#define EAS_SUCCESS 0 +#define EAS_FAILURE -1 +#define EAS_ERROR_INVALID_MODULE -2 +#define EAS_ERROR_MALLOC_FAILED -3 +#define EAS_ERROR_FILE_POS -4 +#define EAS_ERROR_INVALID_FILE_MODE -5 +#define EAS_ERROR_FILE_SEEK -6 +#define EAS_ERROR_FILE_LENGTH -7 +#define EAS_ERROR_NOT_IMPLEMENTED -8 +#define EAS_ERROR_CLOSE_FAILED -9 +#define EAS_ERROR_FILE_OPEN_FAILED -10 +#define EAS_ERROR_INVALID_HANDLE -11 +#define EAS_ERROR_NO_MIX_BUFFER -12 +#define EAS_ERROR_PARAMETER_RANGE -13 +#define EAS_ERROR_MAX_FILES_OPEN -14 +#define EAS_ERROR_UNRECOGNIZED_FORMAT -15 +#define EAS_BUFFER_SIZE_MISMATCH -16 +#define EAS_ERROR_FILE_FORMAT -17 +#define EAS_ERROR_SMF_NOT_INITIALIZED -18 +#define EAS_ERROR_LOCATE_BEYOND_END -19 +#define EAS_ERROR_INVALID_PCM_TYPE -20 +#define EAS_ERROR_MAX_PCM_STREAMS -21 +#define EAS_ERROR_NO_VOICE_ALLOCATED -22 +#define EAS_ERROR_INVALID_CHANNEL -23 +#define EAS_ERROR_ALREADY_STOPPED -24 +#define EAS_ERROR_FILE_READ_FAILED -25 +#define EAS_ERROR_HANDLE_INTEGRITY -26 +#define EAS_ERROR_MAX_STREAMS_OPEN -27 +#define EAS_ERROR_INVALID_PARAMETER -28 +#define EAS_ERROR_FEATURE_NOT_AVAILABLE -29 +#define EAS_ERROR_SOUND_LIBRARY -30 +#define EAS_ERROR_NOT_VALID_IN_THIS_STATE -31 +#define EAS_ERROR_NO_VIRTUAL_SYNTHESIZER -32 +#define EAS_ERROR_FILE_ALREADY_OPEN -33 +#define EAS_ERROR_FILE_ALREADY_CLOSED -34 +#define EAS_ERROR_INCOMPATIBLE_VERSION -35 +#define EAS_ERROR_QUEUE_IS_FULL -36 +#define EAS_ERROR_QUEUE_IS_EMPTY -37 +#define EAS_ERROR_FEATURE_ALREADY_ACTIVE -38 + +/* special return codes */ +#define EAS_EOF 3 +#define EAS_STREAM_BUFFERING 4 +#define EAS_BUFFER_FULL 5 + +/* EAS_STATE return codes */ +typedef long EAS_STATE; +typedef enum +{ + EAS_STATE_READY = 0, + EAS_STATE_PLAY, + EAS_STATE_STOPPING, + EAS_STATE_PAUSING, + EAS_STATE_STOPPED, + EAS_STATE_PAUSED, + EAS_STATE_OPEN, + EAS_STATE_ERROR, + EAS_STATE_EMPTY +} E_EAS_STATE; + +/* constants */ +#ifndef EAS_CONST +#define EAS_CONST const +#endif + +/* definition for public interface functions */ +#ifndef EAS_PUBLIC +#define EAS_PUBLIC +#endif + +/* boolean values */ +typedef unsigned EAS_BOOL; +typedef unsigned char EAS_BOOL8; + +#define EAS_FALSE 0 +#define EAS_TRUE 1 + +/* scalar variable definitions */ +typedef unsigned char EAS_U8; +typedef signed char EAS_I8; +typedef char EAS_CHAR; + +typedef unsigned short EAS_U16; +typedef short EAS_I16; + +typedef unsigned long EAS_U32; +typedef long EAS_I32; + +typedef unsigned EAS_UINT; +typedef int EAS_INT; +typedef long EAS_LONG; + +/* audio output type */ +typedef short EAS_PCM; + +/* file open modes */ +typedef EAS_I32 EAS_FILE_MODE; +#define EAS_FILE_READ 1 +#define EAS_FILE_WRITE 2 + +/* file locator e.g. filename or memory pointer */ +typedef const void *EAS_FILE_LOCATOR; + +/* handle to stream */ +typedef struct s_eas_stream_tag *EAS_HANDLE; + +/* handle to file */ +typedef struct eas_hw_file_tag *EAS_FILE_HANDLE; + +/* handle for synthesizer data */ +typedef struct s_eas_data_tag *EAS_DATA_HANDLE; + +/* handle to persistent data for host wrapper interface */ +typedef struct eas_hw_inst_data_tag *EAS_HW_DATA_HANDLE; + +/* handle to sound library */ +typedef struct s_eas_sndlib_tag *EAS_SNDLIB_HANDLE; +typedef struct s_eas_dls_tag *EAS_DLSLIB_HANDLE; + +/* pointer to frame buffer - used in split architecture only */ +typedef struct s_eas_frame_buffer_tag *EAS_FRAME_BUFFER_HANDLE; + +/* untyped pointer for instance data */ +typedef void *EAS_VOID_PTR; + +/* inline functions */ +#ifndef EAS_INLINE +#if defined (__XCC__) +#define EAS_INLINE __inline__ +#elif defined (__GNUC__) +#define EAS_INLINE inline static +#else +#define EAS_INLINE __inline +#endif +#endif + +/* define NULL value */ +#ifndef NULL +#define NULL 0 +#endif + +/* metadata types for metadata return codes */ +typedef enum +{ + EAS_METADATA_UNKNOWN = 0, + EAS_METADATA_TITLE, + EAS_METADATA_AUTHOR, + EAS_METADATA_COPYRIGHT, + EAS_METADATA_LYRIC, + EAS_METADATA_TEXT +} E_EAS_METADATA_TYPE; + +/* metadata callback function */ +typedef void (*EAS_METADATA_CBFUNC) (E_EAS_METADATA_TYPE metaDataType, char *metaDataBuf, EAS_VOID_PTR pUserData); + +/* file types for metadata return codes */ +typedef enum +{ + EAS_FILE_UNKNOWN = 0, + EAS_FILE_SMF0, + EAS_FILE_SMF1, + EAS_FILE_SMAF_UNKNOWN, + EAS_FILE_SMAF_MA2, + EAS_FILE_SMAF_MA3, + EAS_FILE_SMAF_MA5, + EAS_FILE_CMX, + EAS_FILE_MFI, + EAS_FILE_OTA, + EAS_FILE_IMELODY, + EAS_FILE_RTTTL, + EAS_FILE_XMF0, + EAS_FILE_XMF1, + EAS_FILE_WAVE_PCM, + EAS_FILE_WAVE_IMA_ADPCM, + EAS_FILE_MMAPI_TONE_CONTROL +} E_EAS_FILE_TYPE; + +/* enumeration for synthesizers */ +typedef enum +{ + EAS_MCU_SYNTH = 0, + EAS_DSP_SYNTH +} E_SYNTHESIZER; + +/* external audio callback program change */ +typedef struct s_ext_audio_prg_chg_tag +{ + EAS_U16 bank; + EAS_U8 program; + EAS_U8 channel; +} S_EXT_AUDIO_PRG_CHG; + +/* external audio callback event */ +typedef struct s_ext_audio_event_tag +{ + EAS_U8 channel; + EAS_U8 note; + EAS_U8 velocity; + EAS_BOOL8 noteOn; +} S_EXT_AUDIO_EVENT; + +typedef struct s_midi_controllers_tag +{ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + EAS_U8 expression; /* CC11 */ + EAS_U8 channelPressure; /* MIDI channel pressure */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_MIDI_CONTROLLERS; + +/* iMode play modes enumeration for EAS_SetPlayMode */ +typedef enum +{ + IMODE_PLAY_ALL = 0, + IMODE_PLAY_PARTIAL +} E_I_MODE_PLAY_MODE; + +typedef EAS_BOOL (*EAS_EXT_PRG_CHG_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_PRG_CHG *pPrgChg); +typedef EAS_BOOL (*EAS_EXT_EVENT_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_EVENT *pEvent); + +#endif /* #ifndef _EAS_TYPES_H */ diff --git a/arm-fm-22k/host_src/eas_wave.c b/arm-fm-22k/host_src/eas_wave.c index 02fed6e..4f6ffbd 100644 --- a/arm-fm-22k/host_src/eas_wave.c +++ b/arm-fm-22k/host_src/eas_wave.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_wave.c
- *
- * Contents and purpose:
- * This module contains .WAV file functions for the EAS synthesizer
- * test harness.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.c + * + * Contents and purpose: + * This module contains .WAV file functions for the EAS synthesizer + * test harness. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,404 +20,404 @@ * 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: 658 $
- * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $
- *----------------------------------------------------------------------------
-*/
-
-/* lint complaints about most C library headers, so we use our own during lint step */
-#ifdef _lint
-#include "lint_stdlib.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#endif
-
-#include "eas_wave.h"
-
-/* .WAV file format tags */
-const EAS_U32 riffTag = 0x46464952;
-const EAS_U32 waveTag = 0x45564157;
-const EAS_U32 fmtTag = 0x20746d66;
-const EAS_U32 dataTag = 0x61746164;
-
-#ifdef _BIG_ENDIAN
-/*----------------------------------------------------------------------------
- * FlipDWord()
- *----------------------------------------------------------------------------
- * Purpose: Endian flip a DWORD for big-endian processors
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static void FlipDWord (EAS_U32 *pValue)
-{
- EAS_U8 *p;
- EAS_U32 temp;
-
- p = (EAS_U8*) pValue;
- temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
- *pValue = temp;
-}
-
-/*----------------------------------------------------------------------------
- * FlipWord()
- *----------------------------------------------------------------------------
- * Purpose: Endian flip a WORD for big-endian processors
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static void FlipWord (EAS_U16 *pValue)
-{
- EAS_U8 *p;
- EAS_U16 temp;
-
- p = (EAS_U8*) pValue;
- temp = (p[1] << 8) | p[0];
- *pValue = temp;
-}
-
-/*----------------------------------------------------------------------------
- * FlipWaveHeader()
- *----------------------------------------------------------------------------
- * Purpose: Endian flip the wave header for big-endian processors
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static void FlipWaveHeader (WAVE_HEADER *p)
-{
-
- FlipDWord(&p->nRiffTag);
- FlipDWord(&p->nRiffSize);
- FlipDWord(&p->nWaveTag);
- FlipDWord(&p->nFmtTag);
- FlipDWord(&p->nFmtSize);
- FlipDWord(&p->nDataTag);
- FlipDWord(&p->nDataSize);
- FlipWord(&p->fc.wFormatTag);
- FlipWord(&p->fc.nChannels);
- FlipDWord(&p->fc.nSamplesPerSec);
- FlipDWord(&p->fc.nAvgBytesPerSec);
- FlipWord(&p->fc.nBlockAlign);
- FlipWord(&p->fc.wBitsPerSample);
-
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * WaveFileCreate()
- *----------------------------------------------------------------------------
- * Purpose: Opens a wave file for writing and writes the header
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-
-WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample)
-{
- WAVE_FILE *wFile;
-
- /* allocate memory */
- wFile = malloc(sizeof(WAVE_FILE));
- if (!wFile)
- return NULL;
- wFile->write = EAS_TRUE;
-
- /* create the file */
- wFile->file = fopen(filename,"wb");
- if (!wFile->file)
- {
- free(wFile);
- return NULL;
- }
-
- /* initialize PCM format .WAV file header */
- wFile->wh.nRiffTag = riffTag;
- wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8;
- wFile->wh.nWaveTag = waveTag;
- wFile->wh.nFmtTag = fmtTag;
- wFile->wh.nFmtSize = sizeof(FMT_CHUNK);
-
- /* initalize 'fmt' chunk */
- wFile->wh.fc.wFormatTag = 1;
- wFile->wh.fc.nChannels = (EAS_U16) nChannels;
- wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec;
- wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample;
- wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8));
- wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec;
-
- /* initialize 'data' chunk */
- wFile->wh.nDataTag = dataTag;
- wFile->wh.nDataSize = 0;
-
-#ifdef _BIG_ENDIAN
- FlipWaveHeader(&wFile->wh);
-#endif
-
- /* write the header */
- if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1)
- {
- fclose(wFile->file);
- free(wFile);
- return NULL;
- }
-
-#ifdef _BIG_ENDIAN
- FlipWaveHeader(&wFile->wh);
-#endif
-
- /* return the file handle */
- return wFile;
-} /* end WaveFileCreate */
-
-/*----------------------------------------------------------------------------
- * WaveFileWrite()
- *----------------------------------------------------------------------------
- * Purpose: Writes data to the wave file
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n)
-{
- EAS_I32 count;
-
- /* make sure we have an open file */
- if (wFile == NULL)
- {
- return 0;
- }
-
-#ifdef _BIG_ENDIAN
- {
- EAS_I32 i;
- EAS_U16 *p;
- p = buffer;
- i = n >> 1;
- while (i--)
- FlipWord(p++);
- }
-#endif
-
- /* write the data */
- count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file);
-
- /* add the number of bytes written */
- wFile->wh.nRiffSize += (EAS_U32) count;
- wFile->wh.nDataSize += (EAS_U32) count;
-
- /* return the count of bytes written */
- return count;
-} /* end WriteWaveHeader */
-
-/*----------------------------------------------------------------------------
- * WaveFileClose()
- *----------------------------------------------------------------------------
- * Purpose: Opens a wave file for writing and writes the header
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-
-EAS_BOOL WaveFileClose (WAVE_FILE *wFile)
-{
- EAS_I32 count = 1;
-
- /* return to beginning of file and write the header */
- if (wFile->write)
- {
- if (fseek(wFile->file, 0L, SEEK_SET) == 0)
- {
-
-#ifdef _BIG_ENDIAN
- FlipWaveHeader(&wFile->wh);
-#endif
- count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file);
-#ifdef _BIG_ENDIAN
- FlipWaveHeader(&wFile->wh);
-#endif
- }
- }
-
- /* close the file */
- if (fclose(wFile->file) != 0)
- count = 0;
-
- /* free the memory */
- free(wFile);
-
- /* return the file handle */
- return (count == 1 ? EAS_TRUE : EAS_FALSE);
-} /* end WaveFileClose */
-
-#ifdef _WAVE_FILE_READ
-#ifdef _BIG_ENDIAN
-#error "WaveFileOpen not currently supported on big-endian processors"
-#endif
-/*----------------------------------------------------------------------------
- * WaveFileOpen()
- *----------------------------------------------------------------------------
- * Purpose: Opens a wave file for reading and reads the header
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-
-WAVE_FILE *WaveFileOpen (const char *filename)
-{
- WAVE_FILE *wFile;
- struct
- {
- EAS_U32 tag;
- EAS_U32 size;
- } chunk;
- EAS_U32 tag;
- EAS_I32 startChunkPos;
- EAS_INT state;
- EAS_BOOL done;
-
- /* allocate memory */
- wFile = malloc(sizeof(WAVE_FILE));
- if (!wFile)
- return NULL;
-
- /* open the file */
- wFile->write = EAS_FALSE;
- wFile->file = fopen(filename,"rb");
- if (!wFile->file)
- {
- free(wFile);
- return NULL;
- }
-
- /* make lint happy */
- chunk.tag = chunk.size = 0;
- startChunkPos = 0;
-
- /* read the RIFF tag and file size */
- state = 0;
- done = EAS_FALSE;
- while (!done)
- {
-
- switch(state)
- {
- /* read the RIFF tag */
- case 0:
- if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
- done = EAS_TRUE;
- else
- {
- if (chunk.tag != riffTag)
- done = EAS_TRUE;
- else
- state++;
- }
- break;
-
- /* read the WAVE tag */
- case 1:
- if (fread(&tag, sizeof(tag), 1, wFile->file) != 1)
- done = EAS_TRUE;
- else
- {
- if (tag != waveTag)
- done = EAS_TRUE;
- else
- state++;
- }
- break;
-
- /* looking for fmt chunk */
- case 2:
- if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
- done = EAS_TRUE;
- else
- {
- startChunkPos = ftell(wFile->file);
-
- /* not fmt tag, skip it */
- if (chunk.tag != fmtTag)
- fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
- else
- state++;
- }
- break;
-
- /* read fmt chunk */
- case 3:
- if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1)
- done = EAS_TRUE;
- else
- {
- fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
- state++;
- }
- break;
-
- /* looking for data chunk */
- case 4:
- if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
- done = EAS_TRUE;
- else
- {
- startChunkPos = ftell(wFile->file);
-
- /* not data tag, skip it */
- if (chunk.tag != dataTag)
- fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
- else
- {
- wFile->dataSize = chunk.size;
- state++;
- done = EAS_TRUE;
- }
- }
- break;
-
- default:
- done = EAS_TRUE;
- break;
- }
- }
-
- /* if not final state, an error occurred */
- if (state != 5)
- {
- fclose(wFile->file);
- free(wFile);
- return NULL;
- }
-
- /* return the file handle */
- return wFile;
-} /* end WaveFileOpen */
-#endif
-
-
-
+ *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 658 $ + * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint complaints about most C library headers, so we use our own during lint step */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include <stdio.h> +#include <stdlib.h> +#endif + +#include "eas_wave.h" + +/* .WAV file format tags */ +const EAS_U32 riffTag = 0x46464952; +const EAS_U32 waveTag = 0x45564157; +const EAS_U32 fmtTag = 0x20746d66; +const EAS_U32 dataTag = 0x61746164; + +#ifdef _BIG_ENDIAN +/*---------------------------------------------------------------------------- + * FlipDWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a DWORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipDWord (EAS_U32 *pValue) +{ + EAS_U8 *p; + EAS_U32 temp; + + p = (EAS_U8*) pValue; + temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a WORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWord (EAS_U16 *pValue) +{ + EAS_U8 *p; + EAS_U16 temp; + + p = (EAS_U8*) pValue; + temp = (p[1] << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWaveHeader() + *---------------------------------------------------------------------------- + * Purpose: Endian flip the wave header for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWaveHeader (WAVE_HEADER *p) +{ + + FlipDWord(&p->nRiffTag); + FlipDWord(&p->nRiffSize); + FlipDWord(&p->nWaveTag); + FlipDWord(&p->nFmtTag); + FlipDWord(&p->nFmtSize); + FlipDWord(&p->nDataTag); + FlipDWord(&p->nDataSize); + FlipWord(&p->fc.wFormatTag); + FlipWord(&p->fc.nChannels); + FlipDWord(&p->fc.nSamplesPerSec); + FlipDWord(&p->fc.nAvgBytesPerSec); + FlipWord(&p->fc.nBlockAlign); + FlipWord(&p->fc.wBitsPerSample); + +} +#endif + +/*---------------------------------------------------------------------------- + * WaveFileCreate() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample) +{ + WAVE_FILE *wFile; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + wFile->write = EAS_TRUE; + + /* create the file */ + wFile->file = fopen(filename,"wb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* initialize PCM format .WAV file header */ + wFile->wh.nRiffTag = riffTag; + wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8; + wFile->wh.nWaveTag = waveTag; + wFile->wh.nFmtTag = fmtTag; + wFile->wh.nFmtSize = sizeof(FMT_CHUNK); + + /* initalize 'fmt' chunk */ + wFile->wh.fc.wFormatTag = 1; + wFile->wh.fc.nChannels = (EAS_U16) nChannels; + wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec; + wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample; + wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8)); + wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec; + + /* initialize 'data' chunk */ + wFile->wh.nDataTag = dataTag; + wFile->wh.nDataSize = 0; + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* write the header */ + if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* return the file handle */ + return wFile; +} /* end WaveFileCreate */ + +/*---------------------------------------------------------------------------- + * WaveFileWrite() + *---------------------------------------------------------------------------- + * Purpose: Writes data to the wave file + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n) +{ + EAS_I32 count; + + /* make sure we have an open file */ + if (wFile == NULL) + { + return 0; + } + +#ifdef _BIG_ENDIAN + { + EAS_I32 i; + EAS_U16 *p; + p = buffer; + i = n >> 1; + while (i--) + FlipWord(p++); + } +#endif + + /* write the data */ + count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file); + + /* add the number of bytes written */ + wFile->wh.nRiffSize += (EAS_U32) count; + wFile->wh.nDataSize += (EAS_U32) count; + + /* return the count of bytes written */ + return count; +} /* end WriteWaveHeader */ + +/*---------------------------------------------------------------------------- + * WaveFileClose() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +EAS_BOOL WaveFileClose (WAVE_FILE *wFile) +{ + EAS_I32 count = 1; + + /* return to beginning of file and write the header */ + if (wFile->write) + { + if (fseek(wFile->file, 0L, SEEK_SET) == 0) + { + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file); +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + } + } + + /* close the file */ + if (fclose(wFile->file) != 0) + count = 0; + + /* free the memory */ + free(wFile); + + /* return the file handle */ + return (count == 1 ? EAS_TRUE : EAS_FALSE); +} /* end WaveFileClose */ + +#ifdef _WAVE_FILE_READ +#ifdef _BIG_ENDIAN +#error "WaveFileOpen not currently supported on big-endian processors" +#endif +/*---------------------------------------------------------------------------- + * WaveFileOpen() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for reading and reads the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileOpen (const char *filename) +{ + WAVE_FILE *wFile; + struct + { + EAS_U32 tag; + EAS_U32 size; + } chunk; + EAS_U32 tag; + EAS_I32 startChunkPos; + EAS_INT state; + EAS_BOOL done; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + + /* open the file */ + wFile->write = EAS_FALSE; + wFile->file = fopen(filename,"rb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* make lint happy */ + chunk.tag = chunk.size = 0; + startChunkPos = 0; + + /* read the RIFF tag and file size */ + state = 0; + done = EAS_FALSE; + while (!done) + { + + switch(state) + { + /* read the RIFF tag */ + case 0: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (chunk.tag != riffTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* read the WAVE tag */ + case 1: + if (fread(&tag, sizeof(tag), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (tag != waveTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* looking for fmt chunk */ + case 2: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not fmt tag, skip it */ + if (chunk.tag != fmtTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + state++; + } + break; + + /* read fmt chunk */ + case 3: + if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + state++; + } + break; + + /* looking for data chunk */ + case 4: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not data tag, skip it */ + if (chunk.tag != dataTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + { + wFile->dataSize = chunk.size; + state++; + done = EAS_TRUE; + } + } + break; + + default: + done = EAS_TRUE; + break; + } + } + + /* if not final state, an error occurred */ + if (state != 5) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + + /* return the file handle */ + return wFile; +} /* end WaveFileOpen */ +#endif + + + diff --git a/arm-fm-22k/host_src/eas_wave.h b/arm-fm-22k/host_src/eas_wave.h index ca388f5..968782f 100644 --- a/arm-fm-22k/host_src/eas_wave.h +++ b/arm-fm-22k/host_src/eas_wave.h @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_wave.h
- *
- * Contents and purpose:
- * Writes output to a .WAV file
- *
- * DO NOT MODIFY THIS FILE!
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.h + * + * Contents and purpose: + * Writes output to a .WAV file + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,54 +21,54 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_types.h"
-
-/* sentinel */
-#ifndef _EAS_WAVE_H
-#define _EAS_WAVE_H
-
-/* .WAV file format chunk */
-typedef struct {
- EAS_U16 wFormatTag;
- EAS_U16 nChannels;
- EAS_U32 nSamplesPerSec;
- EAS_U32 nAvgBytesPerSec;
- EAS_U16 nBlockAlign;
- EAS_U16 wBitsPerSample;
-} FMT_CHUNK;
-
-/* .WAV file header */
-typedef struct {
- EAS_U32 nRiffTag;
- EAS_U32 nRiffSize;
- EAS_U32 nWaveTag;
- EAS_U32 nFmtTag;
- EAS_U32 nFmtSize;
- FMT_CHUNK fc;
- EAS_U32 nDataTag;
- EAS_U32 nDataSize;
-} WAVE_HEADER;
-
-typedef struct {
- WAVE_HEADER wh;
- FILE *file;
- EAS_BOOL write;
- EAS_U32 dataSize;
-} WAVE_FILE;
-
-WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample);
-EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n);
-EAS_BOOL WaveFileClose (WAVE_FILE *wFile);
-WAVE_FILE *WaveFileOpen (const char *filename);
-
-#endif /* end #ifndef _EAS_WAVE_H */
-
-
-
+ *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/* sentinel */ +#ifndef _EAS_WAVE_H +#define _EAS_WAVE_H + +/* .WAV file format chunk */ +typedef struct { + EAS_U16 wFormatTag; + EAS_U16 nChannels; + EAS_U32 nSamplesPerSec; + EAS_U32 nAvgBytesPerSec; + EAS_U16 nBlockAlign; + EAS_U16 wBitsPerSample; +} FMT_CHUNK; + +/* .WAV file header */ +typedef struct { + EAS_U32 nRiffTag; + EAS_U32 nRiffSize; + EAS_U32 nWaveTag; + EAS_U32 nFmtTag; + EAS_U32 nFmtSize; + FMT_CHUNK fc; + EAS_U32 nDataTag; + EAS_U32 nDataSize; +} WAVE_HEADER; + +typedef struct { + WAVE_HEADER wh; + FILE *file; + EAS_BOOL write; + EAS_U32 dataSize; +} WAVE_FILE; + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample); +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n); +EAS_BOOL WaveFileClose (WAVE_FILE *wFile); +WAVE_FILE *WaveFileOpen (const char *filename); + +#endif /* end #ifndef _EAS_WAVE_H */ + + + diff --git a/arm-fm-22k/lib_src/eas_audioconst.h b/arm-fm-22k/lib_src/eas_audioconst.h index 1cfa404..066148e 100644 --- a/arm-fm-22k/lib_src/eas_audioconst.h +++ b/arm-fm-22k/lib_src/eas_audioconst.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_audioconst.h
- *
- * Contents and purpose:
- * Defines audio constants related to the sample rate, bit size, etc.
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_audioconst.h + * + * Contents and purpose: + * Defines audio constants related to the sample rate, bit size, etc. + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,78 +20,78 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_AUDIOCONST_H
-#define _EAS_AUDIOCONST_H
-
-/*----------------------------------------------------------------------------
- * These macros define the various characteristics of the defined sample rates
- *----------------------------------------------------------------------------
- * BUFFER_SIZE_IN_MONO_SAMPLES size of buffer in samples
- * _OUTPUT_SAMPLE_RATE compiled output sample rate
- * AUDIO_FRAME_LENGTH length of an audio frame in 256ths of a millisecond
- * SYNTH_UPDATE_PERIOD_IN_BITS length of an audio frame (2^x samples)
- *----------------------------------------------------------------------------
-*/
-
-#if defined (_SAMPLE_RATE_8000)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 32
-#define _OUTPUT_SAMPLE_RATE 8000
-#define AUDIO_FRAME_LENGTH 1024
-#define SYNTH_UPDATE_PERIOD_IN_BITS 5
-
-#elif defined (_SAMPLE_RATE_16000)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 64
-#define _OUTPUT_SAMPLE_RATE 16000
-#define AUDIO_FRAME_LENGTH 1024
-#define SYNTH_UPDATE_PERIOD_IN_BITS 6
-
-#elif defined (_SAMPLE_RATE_20000)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 128
-#define _OUTPUT_SAMPLE_RATE 20000
-#define AUDIO_FRAME_LENGTH 1638
-#define SYNTH_UPDATE_PERIOD_IN_BITS 7
-
-#elif defined (_SAMPLE_RATE_22050)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 128
-#define _OUTPUT_SAMPLE_RATE 22050
-#define AUDIO_FRAME_LENGTH 1486
-#define SYNTH_UPDATE_PERIOD_IN_BITS 7
-
-#elif defined (_SAMPLE_RATE_24000)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 128
-#define _OUTPUT_SAMPLE_RATE 24000
-#define AUDIO_FRAME_LENGTH 1365
-#define SYNTH_UPDATE_PERIOD_IN_BITS 7
-
-#elif defined (_SAMPLE_RATE_32000)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 128
-#define _OUTPUT_SAMPLE_RATE 32000
-#define AUDIO_FRAME_LENGTH 1024
-#define SYNTH_UPDATE_PERIOD_IN_BITS 7
-
-#elif defined (_SAMPLE_RATE_44100)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 256
-#define _OUTPUT_SAMPLE_RATE 44100
-#define AUDIO_FRAME_LENGTH 1486
-#define SYNTH_UPDATE_PERIOD_IN_BITS 8
-
-#elif defined (_SAMPLE_RATE_48000)
-#define BUFFER_SIZE_IN_MONO_SAMPLES 256
-#define _OUTPUT_SAMPLE_RATE 48000
-#define AUDIO_FRAME_LENGTH 1365
-#define SYNTH_UPDATE_PERIOD_IN_BITS 8
-
-#else
-#error "_SAMPLE_RATE_XXXXX must be defined to valid rate"
-#endif
-
-#endif /* #ifndef _EAS_AUDIOCONST_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_AUDIOCONST_H +#define _EAS_AUDIOCONST_H + +/*---------------------------------------------------------------------------- + * These macros define the various characteristics of the defined sample rates + *---------------------------------------------------------------------------- + * BUFFER_SIZE_IN_MONO_SAMPLES size of buffer in samples + * _OUTPUT_SAMPLE_RATE compiled output sample rate + * AUDIO_FRAME_LENGTH length of an audio frame in 256ths of a millisecond + * SYNTH_UPDATE_PERIOD_IN_BITS length of an audio frame (2^x samples) + *---------------------------------------------------------------------------- +*/ + +#if defined (_SAMPLE_RATE_8000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 32 +#define _OUTPUT_SAMPLE_RATE 8000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 5 + +#elif defined (_SAMPLE_RATE_16000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 64 +#define _OUTPUT_SAMPLE_RATE 16000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 6 + +#elif defined (_SAMPLE_RATE_20000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 20000 +#define AUDIO_FRAME_LENGTH 1638 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_22050) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 22050 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_24000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_32000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 32000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_44100) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 44100 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#elif defined (_SAMPLE_RATE_48000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 48000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +#endif /* #ifndef _EAS_AUDIOCONST_H */ + diff --git a/arm-fm-22k/lib_src/eas_chorus.c b/arm-fm-22k/lib_src/eas_chorus.c index bc42237..4a2c8d0 100644 --- a/arm-fm-22k/lib_src/eas_chorus.c +++ b/arm-fm-22k/lib_src/eas_chorus.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_chorus.c
- *
- * Contents and purpose:
- * Contains the implementation of the Chorus effect.
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.c + * + * Contents and purpose: + * Contains the implementation of the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,585 +20,585 @@ * 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: 499 $
- * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_effects.h"
-#include "eas_math.h"
-#include "eas_chorusdata.h"
-#include "eas_chorus.h"
-#include "eas_config.h"
-#include "eas_host.h"
-#include "eas_report.h"
-
-/* prototypes for effects interface */
-static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData);
-static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples);
-static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-
-/* common effects interface for configuration module */
-const S_EFFECTS_INTERFACE EAS_Chorus =
-{
- ChorusInit,
- ChorusProcess,
- ChorusShutdown,
- ChorusGetParam,
- ChorusSetParam
-};
-
-
-
-//LFO shape table used by the chorus, larger table would sound better
-//this is a sine wave, where 32767 = 1.0
-static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = {
- 0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170,
- 24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728,
- 32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329,
- 24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212,
- 1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519,
- -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785,
- -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621,
- -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010,
- -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608
-};
-
-/*----------------------------------------------------------------------------
- * InitializeChorus()
- *----------------------------------------------------------------------------
- * Purpose: Initializes chorus parameters
- *
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData)
-{
- S_CHORUS_OBJECT *pChorusData;
- S_CHORUS_PRESET *pPreset;
- EAS_I32 index;
-
- /* check Configuration Module for data allocation */
- if (pEASData->staticMemoryModel)
- pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS);
-
- /* allocate dynamic memory */
- else
- pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT));
-
- if (pChorusData == NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
-
- /* clear the structure */
- EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT));
-
- ChorusReadInPresets(pChorusData);
-
- /* set some default values */
- pChorusData->bypass = EAS_CHORUS_BYPASS_DEFAULT;
- pChorusData->preset = EAS_CHORUS_PRESET_DEFAULT;
- pChorusData->m_nLevel = EAS_CHORUS_LEVEL_DEFAULT;
- pChorusData->m_nRate = EAS_CHORUS_RATE_DEFAULT;
- pChorusData->m_nDepth = EAS_CHORUS_DEPTH_DEFAULT;
-
- //chorus rate and depth need some massaging from preset value (which is sample rate independent)
-
- //convert rate from steps of .05 Hz to value which can be used as phase increment,
- //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits
- //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate;
- //computing it as below allows rate steps to be evenly spaced
- //uses 32 bit divide, but only once when new value is selected
- pChorusData->m_nRate = (EAS_I16)
- ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate);
-
- //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction
- //want to compute ((depth * sampleRate)/20000)
- //use the following approximation since 105/32 is roughly 65536/20000
- /*lint -e{704} use shift for performance */
- pChorusData->m_nDepth = (EAS_I16)
- (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16);
-
- pChorusData->m_nLevel = pChorusData->m_nLevel;
-
- //zero delay memory for chorus
- for (index = CHORUS_L_SIZE - 1; index >= 0; index--)
- {
- pChorusData->chorusDelayL[index] = 0;
- }
- for (index = CHORUS_R_SIZE - 1; index >= 0; index--)
- {
- pChorusData->chorusDelayR[index] = 0;
- }
-
- //init delay line index, these are used to implement circular delay buffer
- pChorusData->chorusIndexL = 0;
- pChorusData->chorusIndexR = 0;
-
- //init LFO phase
- //16 bit whole part, 16 bit fraction
- pChorusData->lfoLPhase = 0;
- pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase;
-
- //init chorus delay position
- //right now chorus delay is a compile-time value, as is sample rate
- pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000);
-
- //now copy from the new preset into Chorus
- pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus];
-
- pChorusData->m_nLevel = pPreset->m_nLevel;
- pChorusData->m_nRate = pPreset->m_nRate;
- pChorusData->m_nDepth = pPreset->m_nDepth;
-
- pChorusData->m_nRate = (EAS_I16)
- ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate);
-
- /*lint -e{704} use shift for performance */
- pChorusData->m_nDepth = (EAS_I16)
- (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16);
-
- *pInstData = pChorusData;
-
- return EAS_SUCCESS;
-} /* end ChorusInit */
-
-/*----------------------------------------------------------------------------
- * WeightedTap()
- *----------------------------------------------------------------------------
- * Purpose: Does fractional array look-up using linear interpolation
- *
- * first convert indexDesired to actual desired index by taking into account indexReference
- * then do linear interpolation between two actual samples using fractional part
- *
- * Inputs:
- * array: pointer to array of signed 16 bit values, typically either PCM data or control data
- * indexReference: the circular buffer relative offset
- * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction)
- * indexLimit: the total size of the array, used to compute buffer wrap
- *
- * Outputs:
- * Value from the input array, linearly interpolated between two actual data values
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit)
-{
- EAS_I16 index;
- EAS_I16 fraction;
- EAS_I16 val1;
- EAS_I16 val2;
-
- //separate indexDesired into whole and fractional parts
- /*lint -e{704} use shift for performance */
- index = (EAS_I16)(indexDesired >> 16);
- /*lint -e{704} use shift for performance */
- fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part
-
- //adjust whole part by indexReference
- index = indexReference - index;
- //make sure we stay within array bounds, this implements circular buffer
- while (index < 0)
- {
- index += indexLimit;
- }
-
- //get two adjacent values from the array
- val1 = array[index];
-
- //handle special case when index == 0, else typical case
- if (index == 0)
- {
- val2 = array[indexLimit-1]; //get last value from array
- }
- else
- {
- val2 = array[index-1]; //get previous value from array
- }
-
- //compute linear interpolation as (val1 + ((val2-val1)*fraction))
- return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction));
-}
-
-/*----------------------------------------------------------------------------
- * ChorusProcess()
- *----------------------------------------------------------------------------
- * Purpose: compute the chorus on the input buffer, and mix into output buffer
- *
- *
- * Inputs:
- * src: pointer to input buffer of PCM values to be processed
- * dst: pointer to output buffer of PCM values we are to sume the result with
- * bufSize: the number of sample frames (i.e. stereo samples) in the buffer
- *
- * Outputs:
- * None
- *
- *----------------------------------------------------------------------------
-*/
-//compute the chorus, and mix into output buffer
-static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples)
-{
- EAS_I32 ix;
- EAS_I32 nChannelNumber;
- EAS_I16 lfoValueLeft;
- EAS_I16 lfoValueRight;
- EAS_I32 positionOffsetL;
- EAS_I32 positionOffsetR;
- EAS_PCM tapL;
- EAS_PCM tapR;
- EAS_I32 tempValue;
- EAS_PCM nInputSample;
- EAS_I32 nOutputSample;
- EAS_PCM *pIn;
- EAS_PCM *pOut;
-
- S_CHORUS_OBJECT *pChorusData;
-
- pChorusData = (S_CHORUS_OBJECT*) pInstData;
-
- //if the chorus is disabled or turned all the way down
- if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0)
- {
- if (pSrc != pDst)
- EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM));
- return;
- }
-
- if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus)
- {
- ChorusUpdate(pChorusData);
- }
-
- for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++)
- {
-
- pIn = pSrc + nChannelNumber;
- pOut = pDst + nChannelNumber;
-
- if(nChannelNumber==0)
- {
- for (ix = 0; ix < numSamples; ix++)
- {
- nInputSample = *pIn;
- pIn += NUM_OUTPUT_CHANNELS;
-
- //feed input into chorus delay line
- pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample;
-
- //compute chorus lfo value using phase as fractional index into chorus shape table
- //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number
- lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE);
-
- //scale chorus depth by lfo value to get relative fractional sample index
- //index is expressed as 32 bit number with 16 bit fractional part
- /*lint -e{703} use shift for performance */
- positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1);
-
- //add fixed chorus delay to get actual fractional sample index
- positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16;
-
- //get tap value from chorus delay using fractional sample index
- tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE);
-
- //scale by chorus level, then sum with input buffer contents and saturate
- tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel);
- nOutputSample = SATURATE(tempValue + nInputSample);
-
- *pOut = (EAS_I16)SATURATE(nOutputSample);
- pOut += NUM_OUTPUT_CHANNELS;
-
-
- //increment chorus delay index and make it wrap as needed
- //this implements circular buffer
- if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE)
- pChorusData->chorusIndexL = 0;
-
- //increment fractional lfo phase, and make it wrap as needed
- pChorusData->lfoLPhase += pChorusData->m_nRate;
- while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16))
- {
- pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16);
- }
- }
- }
- else
- {
- for (ix = 0; ix < numSamples; ix++)
- {
- nInputSample = *pIn;
- pIn += NUM_OUTPUT_CHANNELS;
-
- //feed input into chorus delay line
- pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample;
-
- //compute chorus lfo value using phase as fractional index into chorus shape table
- //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number
- lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE);
-
- //scale chorus depth by lfo value to get relative fractional sample index
- //index is expressed as 32 bit number with 16 bit fractional part
- /*lint -e{703} use shift for performance */
- positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1);
-
- //add fixed chorus delay to get actual fractional sample index
- positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16;
-
- //get tap value from chorus delay using fractional sample index
- tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE);
-
- //scale by chorus level, then sum with output buffer contents and saturate
- tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel);
- nOutputSample = SATURATE(tempValue + nInputSample);
-
- *pOut = (EAS_I16)SATURATE(nOutputSample);
- pOut += NUM_OUTPUT_CHANNELS;
-
- //increment chorus delay index and make it wrap as needed
- //this implements circular buffer
- if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE)
- pChorusData->chorusIndexR = 0;
-
- //increment fractional lfo phase, and make it wrap as needed
- pChorusData->lfoRPhase += pChorusData->m_nRate;
- while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16))
- {
- pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16);
- }
- }
- }
-
- }
-} /* end ChorusProcess */
-
-
-
-/*----------------------------------------------------------------------------
- * ChorusShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the Chorus effect.
- *
- * Inputs:
- * pInstData - handle to instance data
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData)
-{
- /* check Configuration Module for static memory allocation */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pInstData);
- return EAS_SUCCESS;
-} /* end ChorusShutdown */
-
-/*----------------------------------------------------------------------------
- * ChorusGetParam()
- *----------------------------------------------------------------------------
- * Purpose:
- * Get a Chorus parameter
- *
- * Inputs:
- * pInstData - handle to instance data
- * param - parameter index
- * *pValue - pointer to variable to hold retrieved value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_CHORUS_OBJECT *p;
-
- p = (S_CHORUS_OBJECT*) pInstData;
-
- switch (param)
- {
- case EAS_PARAM_CHORUS_BYPASS:
- *pValue = (EAS_I32) p->bypass;
- break;
- case EAS_PARAM_CHORUS_PRESET:
- *pValue = (EAS_I8) p->m_nCurrentChorus;
- break;
- case EAS_PARAM_CHORUS_RATE:
- *pValue = (EAS_I32) p->m_nRate;
- break;
- case EAS_PARAM_CHORUS_DEPTH:
- *pValue = (EAS_I32) p->m_nDepth;
- break;
- case EAS_PARAM_CHORUS_LEVEL:
- *pValue = (EAS_I32) p->m_nLevel;
- break;
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
- return EAS_SUCCESS;
-} /* end ChorusGetParam */
-
-
-/*----------------------------------------------------------------------------
- * ChorusSetParam()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set a Chorus parameter
- *
- * Inputs:
- * pInstData - handle to instance data
- * param - parameter index
- * *pValue - new paramter value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_CHORUS_OBJECT *p;
-
- p = (S_CHORUS_OBJECT*) pInstData;
-
- switch (param)
- {
- case EAS_PARAM_CHORUS_BYPASS:
- p->bypass = (EAS_BOOL) value;
- break;
- case EAS_PARAM_CHORUS_PRESET:
- if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 &&
- value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4)
- return EAS_ERROR_INVALID_PARAMETER;
- p->m_nNextChorus = (EAS_I8)value;
- break;
- case EAS_PARAM_CHORUS_RATE:
- if(value<EAS_CHORUS_RATE_MIN || value>EAS_CHORUS_RATE_MAX)
- return EAS_ERROR_INVALID_PARAMETER;
- p->m_nRate = (EAS_I16) value;
- break;
- case EAS_PARAM_CHORUS_DEPTH:
- if(value<EAS_CHORUS_DEPTH_MIN || value>EAS_CHORUS_DEPTH_MAX)
- return EAS_ERROR_INVALID_PARAMETER;
- p->m_nDepth = (EAS_I16) value;
- break;
- case EAS_PARAM_CHORUS_LEVEL:
- if(value<EAS_CHORUS_LEVEL_MIN || value>EAS_CHORUS_LEVEL_MAX)
- return EAS_ERROR_INVALID_PARAMETER;
- p->m_nLevel = (EAS_I16) value;
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
- return EAS_SUCCESS;
-} /* end ChorusSetParam */
-
-
-/*----------------------------------------------------------------------------
- * ChorusReadInPresets()
- *----------------------------------------------------------------------------
- * Purpose: sets global Chorus preset bank to defaults
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData)
-{
-
- int preset = 0;
- int defaultPreset = 0;
-
- //now init any remaining presets to defaults
- for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++)
- {
- S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset];
- if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1)
- {
- pPreset->m_nDepth = 39;
- pPreset->m_nRate = 30;
- pPreset->m_nLevel = 32767;
- }
- else if (defaultPreset == 1)
- {
- pPreset->m_nDepth = 21;
- pPreset->m_nRate = 45;
- pPreset->m_nLevel = 25000;
- }
- else if (defaultPreset == 2)
- {
- pPreset->m_nDepth = 53;
- pPreset->m_nRate = 25;
- pPreset->m_nLevel = 32000;
- }
- else if (defaultPreset == 3)
- {
- pPreset->m_nDepth = 32;
- pPreset->m_nRate = 37;
- pPreset->m_nLevel = 29000;
- }
- }
-
- return EAS_SUCCESS;
-}
-
-
-/*----------------------------------------------------------------------------
- * ChorusUpdate
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the Chorus preset parameters as required
- *
- * Inputs:
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - chorus paramters will be changed
- * - m_nCurrentRoom := m_nNextRoom
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData)
-{
- S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus];
-
- pChorusData->m_nLevel = pPreset->m_nLevel;
- pChorusData->m_nRate = pPreset->m_nRate;
- pChorusData->m_nDepth = pPreset->m_nDepth;
-
- pChorusData->m_nRate = (EAS_I16)
- ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate);
-
- /*lint -e{704} use shift for performance */
- pChorusData->m_nDepth = (EAS_I16)
- (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16);
-
- pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus;
-
- return EAS_SUCCESS;
-
-} /* end ChorusUpdate */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_chorusdata.h" +#include "eas_chorus.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Chorus = +{ + ChorusInit, + ChorusProcess, + ChorusShutdown, + ChorusGetParam, + ChorusSetParam +}; + + + +//LFO shape table used by the chorus, larger table would sound better +//this is a sine wave, where 32767 = 1.0 +static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = { + 0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170, + 24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728, + 32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329, + 24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212, + 1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519, + -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785, + -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621, + -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010, + -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608 +}; + +/*---------------------------------------------------------------------------- + * InitializeChorus() + *---------------------------------------------------------------------------- + * Purpose: Initializes chorus parameters + * + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + S_CHORUS_OBJECT *pChorusData; + S_CHORUS_PRESET *pPreset; + EAS_I32 index; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS); + + /* allocate dynamic memory */ + else + pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT)); + + if (pChorusData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT)); + + ChorusReadInPresets(pChorusData); + + /* set some default values */ + pChorusData->bypass = EAS_CHORUS_BYPASS_DEFAULT; + pChorusData->preset = EAS_CHORUS_PRESET_DEFAULT; + pChorusData->m_nLevel = EAS_CHORUS_LEVEL_DEFAULT; + pChorusData->m_nRate = EAS_CHORUS_RATE_DEFAULT; + pChorusData->m_nDepth = EAS_CHORUS_DEPTH_DEFAULT; + + //chorus rate and depth need some massaging from preset value (which is sample rate independent) + + //convert rate from steps of .05 Hz to value which can be used as phase increment, + //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits + //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate; + //computing it as below allows rate steps to be evenly spaced + //uses 32 bit divide, but only once when new value is selected + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction + //want to compute ((depth * sampleRate)/20000) + //use the following approximation since 105/32 is roughly 65536/20000 + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nLevel = pChorusData->m_nLevel; + + //zero delay memory for chorus + for (index = CHORUS_L_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayL[index] = 0; + } + for (index = CHORUS_R_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayR[index] = 0; + } + + //init delay line index, these are used to implement circular delay buffer + pChorusData->chorusIndexL = 0; + pChorusData->chorusIndexR = 0; + + //init LFO phase + //16 bit whole part, 16 bit fraction + pChorusData->lfoLPhase = 0; + pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase; + + //init chorus delay position + //right now chorus delay is a compile-time value, as is sample rate + pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000); + + //now copy from the new preset into Chorus + pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + *pInstData = pChorusData; + + return EAS_SUCCESS; +} /* end ChorusInit */ + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit) +{ + EAS_I16 index; + EAS_I16 fraction; + EAS_I16 val1; + EAS_I16 val2; + + //separate indexDesired into whole and fractional parts + /*lint -e{704} use shift for performance */ + index = (EAS_I16)(indexDesired >> 16); + /*lint -e{704} use shift for performance */ + fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part + + //adjust whole part by indexReference + index = indexReference - index; + //make sure we stay within array bounds, this implements circular buffer + while (index < 0) + { + index += indexLimit; + } + + //get two adjacent values from the array + val1 = array[index]; + + //handle special case when index == 0, else typical case + if (index == 0) + { + val2 = array[indexLimit-1]; //get last value from array + } + else + { + val2 = array[index-1]; //get previous value from array + } + + //compute linear interpolation as (val1 + ((val2-val1)*fraction)) + return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction)); +} + +/*---------------------------------------------------------------------------- + * ChorusProcess() + *---------------------------------------------------------------------------- + * Purpose: compute the chorus on the input buffer, and mix into output buffer + * + * + * Inputs: + * src: pointer to input buffer of PCM values to be processed + * dst: pointer to output buffer of PCM values we are to sume the result with + * bufSize: the number of sample frames (i.e. stereo samples) in the buffer + * + * Outputs: + * None + * + *---------------------------------------------------------------------------- +*/ +//compute the chorus, and mix into output buffer +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + EAS_I32 ix; + EAS_I32 nChannelNumber; + EAS_I16 lfoValueLeft; + EAS_I16 lfoValueRight; + EAS_I32 positionOffsetL; + EAS_I32 positionOffsetR; + EAS_PCM tapL; + EAS_PCM tapR; + EAS_I32 tempValue; + EAS_PCM nInputSample; + EAS_I32 nOutputSample; + EAS_PCM *pIn; + EAS_PCM *pOut; + + S_CHORUS_OBJECT *pChorusData; + + pChorusData = (S_CHORUS_OBJECT*) pInstData; + + //if the chorus is disabled or turned all the way down + if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus) + { + ChorusUpdate(pChorusData); + } + + for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++) + { + + pIn = pSrc + nChannelNumber; + pOut = pDst + nChannelNumber; + + if(nChannelNumber==0) + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE); + + //scale by chorus level, then sum with input buffer contents and saturate + tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE) + pChorusData->chorusIndexL = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoLPhase += pChorusData->m_nRate; + while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + else + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE); + + //scale by chorus level, then sum with output buffer contents and saturate + tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE) + pChorusData->chorusIndexR = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoRPhase += pChorusData->m_nRate; + while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + + } +} /* end ChorusProcess */ + + + +/*---------------------------------------------------------------------------- + * ChorusShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Chorus effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ChorusShutdown */ + +/*---------------------------------------------------------------------------- + * ChorusGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + *pValue = (EAS_I32) p->bypass; + break; + case EAS_PARAM_CHORUS_PRESET: + *pValue = (EAS_I8) p->m_nCurrentChorus; + break; + case EAS_PARAM_CHORUS_RATE: + *pValue = (EAS_I32) p->m_nRate; + break; + case EAS_PARAM_CHORUS_DEPTH: + *pValue = (EAS_I32) p->m_nDepth; + break; + case EAS_PARAM_CHORUS_LEVEL: + *pValue = (EAS_I32) p->m_nLevel; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusGetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + p->bypass = (EAS_BOOL) value; + break; + case EAS_PARAM_CHORUS_PRESET: + if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 && + value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextChorus = (EAS_I8)value; + break; + case EAS_PARAM_CHORUS_RATE: + if(value<EAS_CHORUS_RATE_MIN || value>EAS_CHORUS_RATE_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nRate = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_DEPTH: + if(value<EAS_CHORUS_DEPTH_MIN || value>EAS_CHORUS_DEPTH_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nDepth = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_LEVEL: + if(value<EAS_CHORUS_LEVEL_MIN || value>EAS_CHORUS_LEVEL_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nLevel = (EAS_I16) value; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusSetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++) + { + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1) + { + pPreset->m_nDepth = 39; + pPreset->m_nRate = 30; + pPreset->m_nLevel = 32767; + } + else if (defaultPreset == 1) + { + pPreset->m_nDepth = 21; + pPreset->m_nRate = 45; + pPreset->m_nLevel = 25000; + } + else if (defaultPreset == 2) + { + pPreset->m_nDepth = 53; + pPreset->m_nRate = 25; + pPreset->m_nLevel = 32000; + } + else if (defaultPreset == 3) + { + pPreset->m_nDepth = 32; + pPreset->m_nRate = 37; + pPreset->m_nLevel = 29000; + } + } + + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData) +{ + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus; + + return EAS_SUCCESS; + +} /* end ChorusUpdate */ diff --git a/arm-fm-22k/lib_src/eas_chorusdata.c b/arm-fm-22k/lib_src/eas_chorusdata.c index caee1ed..ec71ff8 100644 --- a/arm-fm-22k/lib_src/eas_chorusdata.c +++ b/arm-fm-22k/lib_src/eas_chorusdata.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_chorusdata.c
- *
- * Contents and purpose:
- * Contains the static data allocation for the Chorus effect
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,15 @@ * 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: 550 $
- * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_chorusdata.h"
-
-S_CHORUS_OBJECT eas_ChorusData;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_chorusdata.h" + +S_CHORUS_OBJECT eas_ChorusData; + diff --git a/arm-fm-22k/lib_src/eas_chorusdata.h b/arm-fm-22k/lib_src/eas_chorusdata.h index 4420ddd..ec8daa4 100644 --- a/arm-fm-22k/lib_src/eas_chorusdata.h +++ b/arm-fm-22k/lib_src/eas_chorusdata.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_chorusdata.h
- *
- * Contents and purpose:
- * Contains the prototypes for the Chorus effect.
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.h + * + * Contents and purpose: + * Contains the prototypes for the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,141 +20,141 @@ * 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: 309 $
- * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_CHORUS_H
-#define _EAS_CHORUS_H
-
-#include "eas_types.h"
-#include "eas_audioconst.h"
-
-//defines for chorus
-
-#define EAS_CHORUS_BYPASS_DEFAULT 1
-#define EAS_CHORUS_PRESET_DEFAULT 0
-#define EAS_CHORUS_RATE_DEFAULT 30
-#define EAS_CHORUS_DEPTH_DEFAULT 39
-#define EAS_CHORUS_LEVEL_DEFAULT 32767
-
-#define EAS_CHORUS_LEVEL_MIN 0
-#define EAS_CHORUS_LEVEL_MAX 32767
-
-#define EAS_CHORUS_RATE_MIN 10
-#define EAS_CHORUS_RATE_MAX 50
-
-#define EAS_CHORUS_DEPTH_MIN 15
-#define EAS_CHORUS_DEPTH_MAX 60
-
-#define CHORUS_SIZE_MS 20
-#define CHORUS_L_SIZE ((CHORUS_SIZE_MS*_OUTPUT_SAMPLE_RATE)/1000)
-#define CHORUS_R_SIZE CHORUS_L_SIZE
-#define CHORUS_SHAPE_SIZE 128
-#define CHORUS_DELAY_MS 10
-
-#define CHORUS_MAX_TYPE 4 // any Chorus numbers larger than this are invalid
-
-typedef struct
-{
- EAS_I16 m_nRate;
- EAS_I16 m_nDepth;
- EAS_I16 m_nLevel;
-
-} S_CHORUS_PRESET;
-
-typedef struct
-{
- S_CHORUS_PRESET m_sPreset[CHORUS_MAX_TYPE]; //array of presets
-
-} S_CHORUS_PRESET_BANK;
-
-/* parameters for each Chorus */
-typedef struct
-{
- EAS_I32 lfoLPhase;
- EAS_I32 lfoRPhase;
- EAS_I16 chorusIndexL;
- EAS_I16 chorusIndexR;
- EAS_U16 chorusTapPosition;
-
- EAS_I16 m_nRate;
- EAS_I16 m_nDepth;
- EAS_I16 m_nLevel;
-
- //delay lines used by the chorus, longer would sound better
- EAS_PCM chorusDelayL[CHORUS_L_SIZE];
- EAS_PCM chorusDelayR[CHORUS_R_SIZE];
-
- EAS_BOOL bypass;
- EAS_I8 preset;
-
- EAS_I16 m_nCurrentChorus; // preset number for current Chorus
- EAS_I16 m_nNextChorus; // preset number for next Chorus
-
- S_CHORUS_PRESET pPreset;
-
- S_CHORUS_PRESET_BANK m_sPreset;
-
-} S_CHORUS_OBJECT;
-
-
-/*----------------------------------------------------------------------------
- * WeightedTap()
- *----------------------------------------------------------------------------
- * Purpose: Does fractional array look-up using linear interpolation
- *
- * first convert indexDesired to actual desired index by taking into account indexReference
- * then do linear interpolation between two actual samples using fractional part
- *
- * Inputs:
- * array: pointer to array of signed 16 bit values, typically either PCM data or control data
- * indexReference: the circular buffer relative offset
- * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction)
- * indexLimit: the total size of the array, used to compute buffer wrap
- *
- * Outputs:
- * Value from the input array, linearly interpolated between two actual data values
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit);
-
-/*----------------------------------------------------------------------------
- * ChorusReadInPresets()
- *----------------------------------------------------------------------------
- * Purpose: sets global Chorus preset bank to defaults
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData);
-
-/*----------------------------------------------------------------------------
- * ChorusUpdate
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the Chorus preset parameters as required
- *
- * Inputs:
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - chorus paramters will be changed
- * - m_nCurrentChorus := m_nNextChorus
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT* pChorusData);
-
-#endif /* #ifndef _EAS_CHORUSDATA_H */
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CHORUS_H +#define _EAS_CHORUS_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +//defines for chorus + +#define EAS_CHORUS_BYPASS_DEFAULT 1 +#define EAS_CHORUS_PRESET_DEFAULT 0 +#define EAS_CHORUS_RATE_DEFAULT 30 +#define EAS_CHORUS_DEPTH_DEFAULT 39 +#define EAS_CHORUS_LEVEL_DEFAULT 32767 + +#define EAS_CHORUS_LEVEL_MIN 0 +#define EAS_CHORUS_LEVEL_MAX 32767 + +#define EAS_CHORUS_RATE_MIN 10 +#define EAS_CHORUS_RATE_MAX 50 + +#define EAS_CHORUS_DEPTH_MIN 15 +#define EAS_CHORUS_DEPTH_MAX 60 + +#define CHORUS_SIZE_MS 20 +#define CHORUS_L_SIZE ((CHORUS_SIZE_MS*_OUTPUT_SAMPLE_RATE)/1000) +#define CHORUS_R_SIZE CHORUS_L_SIZE +#define CHORUS_SHAPE_SIZE 128 +#define CHORUS_DELAY_MS 10 + +#define CHORUS_MAX_TYPE 4 // any Chorus numbers larger than this are invalid + +typedef struct +{ + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + +} S_CHORUS_PRESET; + +typedef struct +{ + S_CHORUS_PRESET m_sPreset[CHORUS_MAX_TYPE]; //array of presets + +} S_CHORUS_PRESET_BANK; + +/* parameters for each Chorus */ +typedef struct +{ + EAS_I32 lfoLPhase; + EAS_I32 lfoRPhase; + EAS_I16 chorusIndexL; + EAS_I16 chorusIndexR; + EAS_U16 chorusTapPosition; + + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + + //delay lines used by the chorus, longer would sound better + EAS_PCM chorusDelayL[CHORUS_L_SIZE]; + EAS_PCM chorusDelayR[CHORUS_R_SIZE]; + + EAS_BOOL bypass; + EAS_I8 preset; + + EAS_I16 m_nCurrentChorus; // preset number for current Chorus + EAS_I16 m_nNextChorus; // preset number for next Chorus + + S_CHORUS_PRESET pPreset; + + S_CHORUS_PRESET_BANK m_sPreset; + +} S_CHORUS_OBJECT; + + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit); + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData); + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentChorus := m_nNextChorus + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT* pChorusData); + +#endif /* #ifndef _EAS_CHORUSDATA_H */ + + diff --git a/arm-fm-22k/lib_src/eas_ctype.h b/arm-fm-22k/lib_src/eas_ctype.h index 8503870..14fa96f 100644 --- a/arm-fm-22k/lib_src/eas_ctype.h +++ b/arm-fm-22k/lib_src/eas_ctype.h @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_ctype.h
- *
- * Contents and purpose:
- * This is a replacement for the CRT ctype.h functions. These
- * functions are currently ASCII only, but eventually, we will want
- * to support wide-characters for localization.
- *
- * Copyright (c) 2005 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_ctype.h + * + * Contents and purpose: + * This is a replacement for the CRT ctype.h functions. These + * functions are currently ASCII only, but eventually, we will want + * to support wide-characters for localization. + * + * Copyright (c) 2005 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. @@ -21,21 +21,21 @@ * 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: 429 $
- * $Date: 2006-10-19 23:50:15 -0700 (Thu, 19 Oct 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_CTYPE_H
-#define _EAS_CTYPE_H
-
-EAS_INLINE EAS_I8 IsDigit (EAS_I8 c) { return ((c >= '0') && (c <= '9')); }
-EAS_INLINE EAS_I8 IsSpace (EAS_I8 c) { return (((c >= 9) && (c <= 13)) || (c == ' ')); }
-EAS_INLINE EAS_I8 ToUpper (EAS_I8 c) { if ((c >= 'a') && (c <= 'z')) return c & ~0x20; else return c; }
-EAS_INLINE EAS_I8 ToLower (EAS_I8 c) { if ((c >= 'A') && (c <= 'Z')) return c |= 0x20; else return c; }
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 429 $ + * $Date: 2006-10-19 23:50:15 -0700 (Thu, 19 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CTYPE_H +#define _EAS_CTYPE_H + +EAS_INLINE EAS_I8 IsDigit (EAS_I8 c) { return ((c >= '0') && (c <= '9')); } +EAS_INLINE EAS_I8 IsSpace (EAS_I8 c) { return (((c >= 9) && (c <= 13)) || (c == ' ')); } +EAS_INLINE EAS_I8 ToUpper (EAS_I8 c) { if ((c >= 'a') && (c <= 'z')) return c & ~0x20; else return c; } +EAS_INLINE EAS_I8 ToLower (EAS_I8 c) { if ((c >= 'A') && (c <= 'Z')) return c |= 0x20; else return c; } + +#endif + diff --git a/arm-fm-22k/lib_src/eas_data.c b/arm-fm-22k/lib_src/eas_data.c index bb60ef2..31a4e6a 100644 --- a/arm-fm-22k/lib_src/eas_data.c +++ b/arm-fm-22k/lib_src/eas_data.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_data.c
- *
- * Contents and purpose:
- * Contains a data allocation for synthesizer
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_data.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,19 +19,19 @@ * 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: 547 $
- * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $
- *----------------------------------------------------------------------------
-*/
-
-// includes
-#include "eas_data.h"
-
-// globals
-S_EAS_DATA eas_Data;
-S_VOICE_MGR eas_Synth;
-S_SYNTH eas_MIDI;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" + +// globals +S_EAS_DATA eas_Data; +S_VOICE_MGR eas_Synth; +S_SYNTH eas_MIDI; + diff --git a/arm-fm-22k/lib_src/eas_data.h b/arm-fm-22k/lib_src/eas_data.h index 0a47d04..e2fcb1a 100644 --- a/arm-fm-22k/lib_src/eas_data.h +++ b/arm-fm-22k/lib_src/eas_data.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_data.h
- *
- * Contents and purpose:
- * This header defines all types, to support dynamic allocation of the
- * memory resources needed for persistent EAS data.
- *
- * Copyright 2004 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_data.h + * + * Contents and purpose: + * This header defines all types, to support dynamic allocation of the + * memory resources needed for persistent EAS data. + * + * Copyright 2004 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. @@ -20,112 +20,112 @@ * 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: 842 $
- * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_DATA_H
-#define _EAS_DATA_H
-
-#include "eas_types.h"
-#include "eas_synthcfg.h"
-#include "eas.h"
-#include "eas_audioconst.h"
-#include "eas_sndlib.h"
-#include "eas_pcm.h"
-#include "eas_pcmdata.h"
-#include "eas_synth.h"
-#include "eas_miditypes.h"
-#include "eas_effects.h"
-
-#ifdef AUX_MIXER
-#include "eas_auxmixdata.h"
-#endif
-
-#ifdef JET_INTERFACE
-#include "jet.h"
-#endif
-
-#ifdef _METRICS_ENABLED
-#include "eas_perf.h"
-#endif
-
-#ifndef MAX_NUMBER_STREAMS
-#define MAX_NUMBER_STREAMS 4
-#endif
-
-/* flags for S_EAS_STREAM */
-#define STREAM_FLAGS_PARSED 1
-#define STREAM_FLAGS_PAUSE 2
-#define STREAM_FLAGS_LOCATE 4
-#define STREAM_FLAGS_RESUME 8
-
-/* structure for parsing a stream */
-typedef struct s_eas_stream_tag
-{
- void *pParserModule;
- EAS_U32 time;
- EAS_U32 frameLength;
- EAS_I32 repeatCount;
- EAS_VOID_PTR handle;
- EAS_U8 volume;
- EAS_BOOL8 streamFlags;
-} S_EAS_STREAM;
-
-/* default master volume is -10dB */
-#define DEFAULT_VOLUME 90
-#define DEFAULT_STREAM_VOLUME 100
-#define DEFAULT_STREAM_GAIN 14622
-
-/* 10 dB of boost available for individual parsers */
-#define STREAM_VOLUME_HEADROOM 10
-
-/* amalgamated persistent data type */
-typedef struct s_eas_data_tag
-{
-#ifdef _CHECKED_BUILD
- EAS_U32 handleCheck;
-#endif
- EAS_HW_DATA_HANDLE hwInstData;
-
- S_EFFECTS_MODULE effectsModules[NUM_EFFECTS_MODULES];
-
-#ifdef _METRICS_ENABLED
- S_METRICS_INTERFACE *pMetricsModule;
- EAS_VOID_PTR pMetricsData;
-#endif
-
- EAS_I32 *pMixBuffer;
- EAS_PCM *pOutputAudioBuffer;
-
-#ifdef AUX_MIXER
- S_EAS_AUX_MIXER auxMixer;
-#endif
-
-#ifdef _MAXIMIZER_ENABLED
- EAS_VOID_PTR pMaximizerData;
-#endif
-
- S_EAS_STREAM streams[MAX_NUMBER_STREAMS];
-
- S_PCM_STATE *pPCMStreams;
-
- S_VOICE_MGR *pVoiceMgr;
-
-#ifdef JET_INTERFACE
- JET_DATA_HANDLE jetHandle;
-#endif
-
- EAS_U32 renderTime;
- EAS_I16 masterGain;
- EAS_U8 masterVolume;
- EAS_BOOL8 staticMemoryModel;
- EAS_BOOL8 searchHeaderFlag;
-} S_EAS_DATA;
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_DATA_H +#define _EAS_DATA_H + +#include "eas_types.h" +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_pcm.h" +#include "eas_pcmdata.h" +#include "eas_synth.h" +#include "eas_miditypes.h" +#include "eas_effects.h" + +#ifdef AUX_MIXER +#include "eas_auxmixdata.h" +#endif + +#ifdef JET_INTERFACE +#include "jet.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +#ifndef MAX_NUMBER_STREAMS +#define MAX_NUMBER_STREAMS 4 +#endif + +/* flags for S_EAS_STREAM */ +#define STREAM_FLAGS_PARSED 1 +#define STREAM_FLAGS_PAUSE 2 +#define STREAM_FLAGS_LOCATE 4 +#define STREAM_FLAGS_RESUME 8 + +/* structure for parsing a stream */ +typedef struct s_eas_stream_tag +{ + void *pParserModule; + EAS_U32 time; + EAS_U32 frameLength; + EAS_I32 repeatCount; + EAS_VOID_PTR handle; + EAS_U8 volume; + EAS_BOOL8 streamFlags; +} S_EAS_STREAM; + +/* default master volume is -10dB */ +#define DEFAULT_VOLUME 90 +#define DEFAULT_STREAM_VOLUME 100 +#define DEFAULT_STREAM_GAIN 14622 + +/* 10 dB of boost available for individual parsers */ +#define STREAM_VOLUME_HEADROOM 10 + +/* amalgamated persistent data type */ +typedef struct s_eas_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; +#endif + EAS_HW_DATA_HANDLE hwInstData; + + S_EFFECTS_MODULE effectsModules[NUM_EFFECTS_MODULES]; + +#ifdef _METRICS_ENABLED + S_METRICS_INTERFACE *pMetricsModule; + EAS_VOID_PTR pMetricsData; +#endif + + EAS_I32 *pMixBuffer; + EAS_PCM *pOutputAudioBuffer; + +#ifdef AUX_MIXER + S_EAS_AUX_MIXER auxMixer; +#endif + +#ifdef _MAXIMIZER_ENABLED + EAS_VOID_PTR pMaximizerData; +#endif + + S_EAS_STREAM streams[MAX_NUMBER_STREAMS]; + + S_PCM_STATE *pPCMStreams; + + S_VOICE_MGR *pVoiceMgr; + +#ifdef JET_INTERFACE + JET_DATA_HANDLE jetHandle; +#endif + + EAS_U32 renderTime; + EAS_I16 masterGain; + EAS_U8 masterVolume; + EAS_BOOL8 staticMemoryModel; + EAS_BOOL8 searchHeaderFlag; +} S_EAS_DATA; + +#endif + diff --git a/arm-fm-22k/lib_src/eas_effects.h b/arm-fm-22k/lib_src/eas_effects.h index 01e64c0..86dedac 100644 --- a/arm-fm-22k/lib_src/eas_effects.h +++ b/arm-fm-22k/lib_src/eas_effects.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_effects.h
- *
- * Contents and purpose:
- * Defines a generic effects interface.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_effects.h + * + * Contents and purpose: + * Defines a generic effects interface. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,43 +19,43 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_EFFECTS_H
-#define _EAS_EFFECTS_H
-
-#include "eas_types.h"
-
-typedef struct
-{
- EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData);
- void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_PCM *in, EAS_PCM *out, EAS_I32 numSamples);
- EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData);
- EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
- EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-} S_EFFECTS_INTERFACE;
-
-typedef struct
-{
- EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData);
- void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_I32 *in, EAS_I32 *out, EAS_I32 numSamples);
- EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData);
- EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
- EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-} S_EFFECTS32_INTERFACE;
-
-/* mixer instance data */
-typedef struct
-{
- S_EFFECTS_INTERFACE *effect;
- EAS_VOID_PTR effectData;
-} S_EFFECTS_MODULE;
-
-#endif /* end _EAS_EFFECTS_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_EFFECTS_H +#define _EAS_EFFECTS_H + +#include "eas_types.h" + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_PCM *in, EAS_PCM *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS_INTERFACE; + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_I32 *in, EAS_I32 *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS32_INTERFACE; + +/* mixer instance data */ +typedef struct +{ + S_EFFECTS_INTERFACE *effect; + EAS_VOID_PTR effectData; +} S_EFFECTS_MODULE; + +#endif /* end _EAS_EFFECTS_H */ + diff --git a/arm-fm-22k/lib_src/eas_fmengine.c b/arm-fm-22k/lib_src/eas_fmengine.c index 9c3da66..ea7f69c 100644 --- a/arm-fm-22k/lib_src/eas_fmengine.c +++ b/arm-fm-22k/lib_src/eas_fmengine.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_fmengine.c
- *
- * Contents and purpose:
- * Implements the low-level FM synthesizer functions.
- *
- * Copyright Sonic Network Inc. 2004, 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_fmengine.c + * + * Contents and purpose: + * Implements the low-level FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004, 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,767 +19,767 @@ * 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: 795 $
- * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-/* includes */
-#include "eas_types.h"
-#include "eas_math.h"
-#include "eas_audioconst.h"
-#include "eas_fmengine.h"
-
-#if defined(EAS_FM_SYNTH) || defined(EAS_HYBRID_SYNTH) || defined(EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH)
-#include "eas_data.h"
-#endif
-
-/* externals */
-extern const EAS_I16 sineTable[];
-extern const EAS_U8 fmScaleTable[16];
-
-// saturation constants for 32-bit to 16-bit conversion
-#define _EAS_MAX_OUTPUT 32767
-#define _EAS_MIN_OUTPUT -32767
-
-static S_FM_ENG_VOICE voices[NUM_FM_VOICES];
-
-/* local prototypes */
-void FM_SynthMixVoice (S_FM_ENG_VOICE *p, EAS_U16 gainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer);
-
-/* used in development environment */
-#if defined(_SATURATION_MONITOR)
-static EAS_BOOL bSaturated = EAS_FALSE;
-
-/*----------------------------------------------------------------------------
- * FM_CheckSaturation()
- *----------------------------------------------------------------------------
- * Purpose:
- * Allows the sound development tool to check for saturation at the voice
- * level. Useful for tuning the level controls.
- *
- * Inputs:
- *
- * Outputs:
- * Returns true if saturation has occurred since the last time the function
- * was called.
- *
- * Side Effects:
- * Resets the saturation flag
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL FM_CheckSaturation ()
-{
- EAS_BOOL bTemp;
- bTemp = bSaturated;
- bSaturated = EAS_FALSE;
- return bTemp;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * FM_Saturate()
- *----------------------------------------------------------------------------
- * Purpose:
- * This inline function saturates a 32-bit number to 16-bits
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Returns a 16-bit integer
- *----------------------------------------------------------------------------
-*/
-EAS_INLINE EAS_I16 FM_Saturate (EAS_I32 nValue)
-{
- if (nValue > _EAS_MAX_OUTPUT)
- {
-#if defined(_SATURATION_MONITOR)
- bSaturated = EAS_TRUE;
-#endif
- return _EAS_MAX_OUTPUT;
- }
- if (nValue < _EAS_MIN_OUTPUT)
- {
-#if defined(_SATURATION_MONITOR)
- bSaturated = EAS_TRUE;
-#endif
- return _EAS_MIN_OUTPUT;
- }
- return (EAS_I16) nValue;
-}
-
-/*----------------------------------------------------------------------------
- * FM_Noise()
- *----------------------------------------------------------------------------
- * Purpose:
- * A 31-bit low-cost linear congruential PRNG algorithm used to
- * generate noise.
- *
- * Inputs:
- * pnSeed - pointer to 32-bit PRNG seed
- *
- * Outputs:
- * Returns a 16-bit integer
- *----------------------------------------------------------------------------
-*/
-EAS_INLINE EAS_I16 FM_Noise (EAS_U32 *pnSeed)
-{
- *pnSeed = *pnSeed * 214013L + 2531011L;
- return (EAS_I16) ((*pnSeed >> 15) & 0xffff);
-}
-
-/*----------------------------------------------------------------------------
- * FM_PhaseInc()
- *----------------------------------------------------------------------------
- * Purpose:
- * Transform pitch cents to linear phase increment
- *
- * Inputs:
- * nCents - measured in cents
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_I32 FM_PhaseInc (EAS_I32 nCents)
-{
- EAS_I32 nDents;
- EAS_I32 nExponentInt, nExponentFrac;
- EAS_I32 nTemp1, nTemp2;
- EAS_I32 nResult;
-
- /* convert cents to dents */
- nDents = FMUL_15x15(nCents, CENTS_TO_DENTS);
- nExponentInt = GET_DENTS_INT_PART(nDents) + (32 - SINE_TABLE_SIZE_IN_BITS - NUM_EG1_FRAC_BITS);
- nExponentFrac = GET_DENTS_FRAC_PART(nDents);
-
- /* implement 2^(fracPart) as a power series */
- nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3);
- nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1);
- nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2);
-
- /*
- implement 2^(intPart) as
- a left shift for intPart >= 0 or
- a left shift for intPart < 0
- */
- if (nExponentInt >= 0)
- {
- /* left shift for positive exponents */
- /*lint -e{703} <avoid multiply for performance>*/
- nResult = nTemp1 << nExponentInt;
- }
- else
- {
- /* right shift for negative exponents */
- nExponentInt = -nExponentInt;
- nResult = nTemp1 >> nExponentInt;
- }
-
- return nResult;
-}
-
-#if (NUM_OUTPUT_CHANNELS == 2)
-/*----------------------------------------------------------------------------
- * FM_CalculatePan()
- *----------------------------------------------------------------------------
- * Purpose:
- * Assign the left and right gain values corresponding to the given pan value.
- *
- * Inputs:
- * psVoice - ptr to the voice we have assigned for this channel
- * psArticulation - ptr to this voice's articulation
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * the given voice's m_nGainLeft and m_nGainRight are assigned
- *----------------------------------------------------------------------------
-*/
-static void FM_CalculatePan (EAS_I16 pan, EAS_U16 *pGainLeft, EAS_U16 *pGainRight)
-{
- EAS_I32 nTemp;
- EAS_INT nNetAngle;
-
- /*
- Implement the following
- sin(x) = (2-4*c)*x^2 + c + x
- cos(x) = (2-4*c)*x^2 + c - x
-
- where c = 1/sqrt(2)
- using the a0 + x*(a1 + x*a2) approach
- */
-
- /*
- Get the Midi CC10 pan value for this voice's channel
- convert the pan value to an "angle" representation suitable for
- our sin, cos calculator. This representation is NOT necessarily the same
- as the transform in the GM manuals because of our sin, cos calculator.
- "angle" = (CC10 - 64)/128
- */
- /*lint -e{703} <avoid multiply for performance reasons>*/
- nNetAngle = ((EAS_I32) pan) << (NUM_EG1_FRAC_BITS -7);
-
- /* calculate sin */
- nTemp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle);
- nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle);
-
- if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN)
- nTemp = SYNTH_FULL_SCALE_EG1_GAIN;
- else if (nTemp < 0)
- nTemp = 0;
-
- *pGainRight = (EAS_U16) nTemp;
-
- /* calculate cos */
- nTemp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle);
- nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle);
-
- if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN)
- nTemp = SYNTH_FULL_SCALE_EG1_GAIN;
- else if (nTemp < 0)
- nTemp = 0;
-
- *pGainLeft = (EAS_U16) nTemp;
-}
-#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */
-
-/*----------------------------------------------------------------------------
- * FM_Operator()
- *----------------------------------------------------------------------------
- * Purpose:
- * Synthesizes a buffer of samples based on passed parameters.
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to synthesize
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void FM_Operator (
- S_FM_ENG_OPER *p,
- EAS_I32 numSamplesToAdd,
- EAS_PCM *pBuffer,
- EAS_PCM *pModBuffer,
- EAS_BOOL mix,
- EAS_U16 gainTarget,
- EAS_I16 pitch,
- EAS_U8 feedback,
- EAS_I16 *pLastOutput)
-{
- EAS_I32 gain;
- EAS_I32 gainInc;
- EAS_U32 phase;
- EAS_U32 phaseInc;
- EAS_U32 phaseTemp;
- EAS_I32 temp;
- EAS_I32 temp2;
-
- /* establish local gain variable */
- gain = (EAS_I32) p->gain << 16;
-
- /* calculate gain increment */
- /*lint -e{703} use shift for performance */
- gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
-
- /* establish local phase variables */
- phase = p->phase;
-
- /* calculate the new phase increment */
- phaseInc = (EAS_U32) FM_PhaseInc(pitch);
-
- /* restore final output from previous frame for feedback loop */
- if (pLastOutput)
- temp = *pLastOutput;
- else
- temp = 0;
-
- /* generate a buffer of samples */
- while (numSamplesToAdd--)
- {
-
- /* incorporate modulation */
- if (pModBuffer)
- {
- /*lint -e{701} use shift for performance */
- temp = *pModBuffer++ << FM_MODULATOR_INPUT_SHIFT;
- }
-
- /* incorporate feedback */
- else
- {
- /*lint -e{703} use shift for performance */
- temp = (temp * (EAS_I32) feedback) << FM_FEEDBACK_SHIFT;
- }
-
- /*lint -e{737} <use this behavior to avoid extra mask step> */
- phaseTemp = phase + temp;
-
- /* fetch sample from wavetable */
- temp = sineTable[phaseTemp >> (32 - SINE_TABLE_SIZE_IN_BITS)];
-
- /* increment operator phase */
- phase += phaseInc;
-
- /* internal gain for modulation effects */
- temp = FMUL_15x15(temp, (gain >> 16));
-
- /* output gain calculation */
- temp2 = FMUL_15x15(temp, p->outputGain);
-
- /* saturating add to buffer */
- if (mix)
- {
- temp2 += *pBuffer;
- *pBuffer++ = FM_Saturate(temp2);
- }
-
- /* output to buffer */
- else
- *pBuffer++ = (EAS_I16) temp2;
-
- /* increment gain */
- gain += gainInc;
-
- }
-
- /* save phase and gain */
- p->phase = phase;
- p->gain = gainTarget;
-
- /* save last output for feedback in next frame */
- if (pLastOutput)
- *pLastOutput = (EAS_I16) temp;
-}
-
-/*----------------------------------------------------------------------------
- * FM_NoiseOperator()
- *----------------------------------------------------------------------------
- * Purpose:
- * Synthesizes a buffer of samples based on passed parameters.
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to synthesize
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void FM_NoiseOperator (
- S_FM_ENG_OPER *p,
- EAS_I32 numSamplesToAdd,
- EAS_PCM *pBuffer,
- EAS_BOOL mix,
- EAS_U16 gainTarget,
- EAS_U8 feedback,
- EAS_I16 *pLastOutput)
-{
- EAS_I32 gain;
- EAS_I32 gainInc;
- EAS_U32 phase;
- EAS_I32 temp;
- EAS_I32 temp2;
-
- /* establish local gain variable */
- gain = (EAS_I32) p->gain << 16;
-
- /* calculate gain increment */
- /*lint -e{703} use shift for performance */
- gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
-
- /* establish local phase variables */
- phase = p->phase;
-
- /* establish local phase variables */
- phase = p->phase;
-
- /* recall last sample for filter Z-1 term */
- temp = 0;
- if (pLastOutput)
- temp = *pLastOutput;
-
- /* generate a buffer of samples */
- while (numSamplesToAdd--)
- {
-
- /* if using filter */
- if (pLastOutput)
- {
- /* use PRNG for noise */
- temp2 = FM_Noise(&phase);
-
- /*lint -e{704} use shift for performance */
- temp += ((temp2 -temp) * feedback) >> 8;
- }
- else
- {
- temp = FM_Noise(&phase);
- }
-
- /* internal gain for modulation effects */
- temp2 = FMUL_15x15(temp, (gain >> 16));
-
- /* output gain calculation */
- temp2 = FMUL_15x15(temp2, p->outputGain);
-
- /* saturating add to buffer */
- if (mix)
- {
- temp2 += *pBuffer;
- *pBuffer++ = FM_Saturate(temp2);
- }
-
- /* output to buffer */
- else
- *pBuffer++ = (EAS_I16) temp2;
-
- /* increment gain */
- gain += gainInc;
-
- }
-
- /* save phase and gain */
- p->phase = phase;
- p->gain = gainTarget;
-
- /* save last output for feedback in next frame */
- if (pLastOutput)
- *pLastOutput = (EAS_I16) temp;
-}
-
-/*----------------------------------------------------------------------------
- * FM_ConfigVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Receives parameters to start a new voice.
- *
- * Inputs:
- * voiceNum - voice number to start
- * vCfg - configuration data
- * pMixBuffer - pointer to host supplied buffer
- *
- * Outputs:
- *
- * Side Effects:
- *
- * Notes:
- * pFrameBuffer is not used in the test version, but is passed as a
- * courtesy to split architecture implementations. It can be used as
- * as pointer to the interprocessor communications buffer when the
- * synthesis parameters are passed off to a DSP for synthesis.
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pFrameBuffer) pFrameBuffer not used in test version - see above */
-void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
-{
- S_FM_ENG_VOICE *pVoice;
- EAS_INT i;
-
- /* establish pointer to voice data */
- pVoice = &voices[voiceNum];
-
- /* save data */
- pVoice->feedback = vCfg->feedback;
- pVoice->flags = vCfg->flags;
- pVoice->voiceGain = vCfg->voiceGain;
-
- /* initialize Z-1 terms */
- pVoice->op1Out = 0;
- pVoice->op3Out = 0;
-
- /* initialize operators */
- for (i = 0; i < 4; i++)
- {
- /* save operator data */
- pVoice->oper[i].gain = vCfg->gain[i];
- pVoice->oper[i].outputGain = vCfg->outputGain[i];
- pVoice->oper[i].outputGain = vCfg->outputGain[i];
-
- /* initalize operator */
- pVoice->oper[i].phase = 0;
- }
-
- /* calculate pan */
-#if NUM_OUTPUT_CHANNELS == 2
- FM_CalculatePan(vCfg->pan, &pVoice->gainLeft, &pVoice->gainRight);
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * FM_ProcessVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Synthesizes a buffer of samples based on calculated parameters.
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to synthesize
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- *
- * Notes:
- * pOut is not used in the test version, but is passed as a
- * courtesy to split architecture implementations. It can be used as
- * as pointer to the interprocessor communications buffer when the
- * synthesis parameters are passed off to a DSP for synthesis.
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pOut) pOut not used in test version - see above */
-void FM_ProcessVoice (
- EAS_I32 voiceNum,
- S_FM_VOICE_FRAME *pFrame,
- EAS_I32 numSamplesToAdd,
- EAS_PCM *pTempBuffer,
- EAS_PCM *pBuffer,
- EAS_I32 *pMixBuffer,
- EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
-{
- S_FM_ENG_VOICE *p;
- EAS_PCM *pOutBuf;
- EAS_PCM *pMod;
- EAS_BOOL mix;
- EAS_U8 feedback1;
- EAS_U8 feedback3;
- EAS_U8 mode;
-
- /* establish pointer to voice data */
- p = &voices[voiceNum];
- mode = p->flags & 0x07;
-
- /* lookup feedback values */
- feedback1 = fmScaleTable[p->feedback >> 4];
- feedback3 = fmScaleTable[p->feedback & 0x0f];
-
- /* operator 3 is on output bus in modes 0, 1, and 3 */
- if ((mode == 0) || (mode == 1) || (mode == 3))
- pOutBuf = pBuffer;
- else
- pOutBuf = pTempBuffer;
-
- if (p->flags & FLAG_FM_ENG_VOICE_OP3_NOISE)
- {
- FM_NoiseOperator(
- p->oper + 2,
- numSamplesToAdd,
- pOutBuf,
- EAS_FALSE,
- pFrame->gain[2],
- feedback3,
- &p->op3Out);
- }
- else
- {
- FM_Operator(
- p->oper + 2,
- numSamplesToAdd,
- pOutBuf,
- 0,
- EAS_FALSE,
- pFrame->gain[2],
- pFrame->pitch[2],
- feedback3,
- &p->op3Out);
- }
-
- /* operator 4 is on output bus in modes 0, 1, and 2 */
- if (mode < 3)
- pOutBuf = pBuffer;
- else
- pOutBuf = pTempBuffer;
-
- /* operator 4 is modulated in modes 2, 4, and 5 */
- if ((mode == 2) || (mode == 4) || (mode == 5))
- pMod = pTempBuffer;
- else
- pMod = 0;
-
- /* operator 4 is in mix mode in modes 0 and 1 */
- mix = (mode < 2);
-
- if (p->flags & FLAG_FM_ENG_VOICE_OP4_NOISE)
- {
- FM_NoiseOperator(
- p->oper + 3,
- numSamplesToAdd,
- pOutBuf,
- mix,
- pFrame->gain[3],
- 0,
- 0);
- }
- else
- {
- FM_Operator(
- p->oper + 3,
- numSamplesToAdd,
- pOutBuf,
- pMod,
- mix,
- pFrame->gain[3],
- pFrame->pitch[3],
- 0,
- 0);
- }
-
- /* operator 1 is on output bus in mode 0 */
- if (mode == 0)
- pOutBuf = pBuffer;
- else
- pOutBuf = pTempBuffer;
-
- /* operator 1 is modulated in modes 3 and 4 */
- if ((mode == 3) || (mode == 4))
- pMod = pTempBuffer;
- else
- pMod = 0;
-
- /* operator 1 is in mix mode in modes 0 and 5 */
- mix = ((mode == 0) || (mode == 5));
-
- if (p->flags & FLAG_FM_ENG_VOICE_OP1_NOISE)
- {
- FM_NoiseOperator(
- p->oper,
- numSamplesToAdd,
- pOutBuf,
- mix,
- pFrame->gain[0],
- feedback1,
- &p->op1Out);
- }
- else
- {
- FM_Operator(
- p->oper,
- numSamplesToAdd,
- pOutBuf,
- pMod,
- mix,
- pFrame->gain[0],
- pFrame->pitch[0],
- feedback1,
- &p->op1Out);
- }
-
- /* operator 2 is modulated in all modes except 0 */
- if (mode != 0)
- pMod = pTempBuffer;
- else
- pMod = 0;
-
- /* operator 1 is in mix mode in modes 0 -3 */
- mix = (mode < 4);
-
- if (p->flags & FLAG_FM_ENG_VOICE_OP2_NOISE)
- {
- FM_NoiseOperator(
- p->oper + 1,
- numSamplesToAdd,
- pBuffer,
- mix,
- pFrame->gain[1],
- 0,
- 0);
- }
- else
- {
- FM_Operator(
- p->oper + 1,
- numSamplesToAdd,
- pBuffer,
- pMod,
- mix,
- pFrame->gain[1],
- pFrame->pitch[1],
- 0,
- 0);
- }
-
- /* mix voice output to synthesizer output buffer */
- FM_SynthMixVoice(p, pFrame->voiceGain, numSamplesToAdd, pBuffer, pMixBuffer);
-}
-
-/*----------------------------------------------------------------------------
- * FM_SynthMixVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Mixes the voice output buffer into the final mix using an anti-zipper
- * filter.
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to synthesize
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void FM_SynthMixVoice(S_FM_ENG_VOICE *p, EAS_U16 nGainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer)
-{
- EAS_I32 nGain;
- EAS_I32 nGainInc;
- EAS_I32 nTemp;
-
- /* restore previous gain */
- /*lint -e{703} <use shift for performance> */
- nGain = (EAS_I32) p->voiceGain << 16;
-
- /* calculate gain increment */
- /*lint -e{703} <use shift for performance> */
- nGainInc = ((EAS_I32) nGainTarget - (EAS_I32) p->voiceGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
-
- /* mix the output buffer */
- while (numSamplesToAdd--)
- {
- /* output gain calculation */
- nTemp = *pInputBuffer++;
-
- /* sum to output buffer */
-#if (NUM_OUTPUT_CHANNELS == 2)
-
- /*lint -e{704} <use shift for performance> */
- nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT;
-
- /*lint -e{704} <use shift for performance> */
- {
- EAS_I32 nTemp2;
- nTemp = nTemp >> FM_STEREO_PRE_GAIN_SHIFT;
- nTemp2 = (nTemp * p->gainLeft) >> FM_STEREO_POST_GAIN_SHIFT;
- *pBuffer++ += nTemp2;
- nTemp2 = (nTemp * p->gainRight) >> FM_STEREO_POST_GAIN_SHIFT;
- *pBuffer++ += nTemp2;
- }
-#else
- /*lint -e{704} <use shift for performance> */
- nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_MONO_GAIN_SHIFT;
- *pBuffer++ += nTemp;
-#endif
-
- /* increment gain for anti-zipper filter */
- nGain += nGainInc;
- }
-
- /* save gain */
- p->voiceGain = nGainTarget;
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* includes */ +#include "eas_types.h" +#include "eas_math.h" +#include "eas_audioconst.h" +#include "eas_fmengine.h" + +#if defined(EAS_FM_SYNTH) || defined(EAS_HYBRID_SYNTH) || defined(EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH) +#include "eas_data.h" +#endif + +/* externals */ +extern const EAS_I16 sineTable[]; +extern const EAS_U8 fmScaleTable[16]; + +// saturation constants for 32-bit to 16-bit conversion +#define _EAS_MAX_OUTPUT 32767 +#define _EAS_MIN_OUTPUT -32767 + +static S_FM_ENG_VOICE voices[NUM_FM_VOICES]; + +/* local prototypes */ +void FM_SynthMixVoice (S_FM_ENG_VOICE *p, EAS_U16 gainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer); + +/* used in development environment */ +#if defined(_SATURATION_MONITOR) +static EAS_BOOL bSaturated = EAS_FALSE; + +/*---------------------------------------------------------------------------- + * FM_CheckSaturation() + *---------------------------------------------------------------------------- + * Purpose: + * Allows the sound development tool to check for saturation at the voice + * level. Useful for tuning the level controls. + * + * Inputs: + * + * Outputs: + * Returns true if saturation has occurred since the last time the function + * was called. + * + * Side Effects: + * Resets the saturation flag + *---------------------------------------------------------------------------- +*/ +EAS_BOOL FM_CheckSaturation () +{ + EAS_BOOL bTemp; + bTemp = bSaturated; + bSaturated = EAS_FALSE; + return bTemp; +} +#endif + +/*---------------------------------------------------------------------------- + * FM_Saturate() + *---------------------------------------------------------------------------- + * Purpose: + * This inline function saturates a 32-bit number to 16-bits + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Returns a 16-bit integer + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_I16 FM_Saturate (EAS_I32 nValue) +{ + if (nValue > _EAS_MAX_OUTPUT) + { +#if defined(_SATURATION_MONITOR) + bSaturated = EAS_TRUE; +#endif + return _EAS_MAX_OUTPUT; + } + if (nValue < _EAS_MIN_OUTPUT) + { +#if defined(_SATURATION_MONITOR) + bSaturated = EAS_TRUE; +#endif + return _EAS_MIN_OUTPUT; + } + return (EAS_I16) nValue; +} + +/*---------------------------------------------------------------------------- + * FM_Noise() + *---------------------------------------------------------------------------- + * Purpose: + * A 31-bit low-cost linear congruential PRNG algorithm used to + * generate noise. + * + * Inputs: + * pnSeed - pointer to 32-bit PRNG seed + * + * Outputs: + * Returns a 16-bit integer + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_I16 FM_Noise (EAS_U32 *pnSeed) +{ + *pnSeed = *pnSeed * 214013L + 2531011L; + return (EAS_I16) ((*pnSeed >> 15) & 0xffff); +} + +/*---------------------------------------------------------------------------- + * FM_PhaseInc() + *---------------------------------------------------------------------------- + * Purpose: + * Transform pitch cents to linear phase increment + * + * Inputs: + * nCents - measured in cents + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_I32 FM_PhaseInc (EAS_I32 nCents) +{ + EAS_I32 nDents; + EAS_I32 nExponentInt, nExponentFrac; + EAS_I32 nTemp1, nTemp2; + EAS_I32 nResult; + + /* convert cents to dents */ + nDents = FMUL_15x15(nCents, CENTS_TO_DENTS); + nExponentInt = GET_DENTS_INT_PART(nDents) + (32 - SINE_TABLE_SIZE_IN_BITS - NUM_EG1_FRAC_BITS); + nExponentFrac = GET_DENTS_FRAC_PART(nDents); + + /* implement 2^(fracPart) as a power series */ + nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3); + nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1); + nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2); + + /* + implement 2^(intPart) as + a left shift for intPart >= 0 or + a left shift for intPart < 0 + */ + if (nExponentInt >= 0) + { + /* left shift for positive exponents */ + /*lint -e{703} <avoid multiply for performance>*/ + nResult = nTemp1 << nExponentInt; + } + else + { + /* right shift for negative exponents */ + nExponentInt = -nExponentInt; + nResult = nTemp1 >> nExponentInt; + } + + return nResult; +} + +#if (NUM_OUTPUT_CHANNELS == 2) +/*---------------------------------------------------------------------------- + * FM_CalculatePan() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * Inputs: + * psVoice - ptr to the voice we have assigned for this channel + * psArticulation - ptr to this voice's articulation + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * the given voice's m_nGainLeft and m_nGainRight are assigned + *---------------------------------------------------------------------------- +*/ +static void FM_CalculatePan (EAS_I16 pan, EAS_U16 *pGainLeft, EAS_U16 *pGainRight) +{ + EAS_I32 nTemp; + EAS_INT nNetAngle; + + /* + Implement the following + sin(x) = (2-4*c)*x^2 + c + x + cos(x) = (2-4*c)*x^2 + c - x + + where c = 1/sqrt(2) + using the a0 + x*(a1 + x*a2) approach + */ + + /* + Get the Midi CC10 pan value for this voice's channel + convert the pan value to an "angle" representation suitable for + our sin, cos calculator. This representation is NOT necessarily the same + as the transform in the GM manuals because of our sin, cos calculator. + "angle" = (CC10 - 64)/128 + */ + /*lint -e{703} <avoid multiply for performance reasons>*/ + nNetAngle = ((EAS_I32) pan) << (NUM_EG1_FRAC_BITS -7); + + /* calculate sin */ + nTemp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle); + nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle); + + if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN) + nTemp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (nTemp < 0) + nTemp = 0; + + *pGainRight = (EAS_U16) nTemp; + + /* calculate cos */ + nTemp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle); + nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle); + + if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN) + nTemp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (nTemp < 0) + nTemp = 0; + + *pGainLeft = (EAS_U16) nTemp; +} +#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */ + +/*---------------------------------------------------------------------------- + * FM_Operator() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on passed parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_Operator ( + S_FM_ENG_OPER *p, + EAS_I32 numSamplesToAdd, + EAS_PCM *pBuffer, + EAS_PCM *pModBuffer, + EAS_BOOL mix, + EAS_U16 gainTarget, + EAS_I16 pitch, + EAS_U8 feedback, + EAS_I16 *pLastOutput) +{ + EAS_I32 gain; + EAS_I32 gainInc; + EAS_U32 phase; + EAS_U32 phaseInc; + EAS_U32 phaseTemp; + EAS_I32 temp; + EAS_I32 temp2; + + /* establish local gain variable */ + gain = (EAS_I32) p->gain << 16; + + /* calculate gain increment */ + /*lint -e{703} use shift for performance */ + gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* establish local phase variables */ + phase = p->phase; + + /* calculate the new phase increment */ + phaseInc = (EAS_U32) FM_PhaseInc(pitch); + + /* restore final output from previous frame for feedback loop */ + if (pLastOutput) + temp = *pLastOutput; + else + temp = 0; + + /* generate a buffer of samples */ + while (numSamplesToAdd--) + { + + /* incorporate modulation */ + if (pModBuffer) + { + /*lint -e{701} use shift for performance */ + temp = *pModBuffer++ << FM_MODULATOR_INPUT_SHIFT; + } + + /* incorporate feedback */ + else + { + /*lint -e{703} use shift for performance */ + temp = (temp * (EAS_I32) feedback) << FM_FEEDBACK_SHIFT; + } + + /*lint -e{737} <use this behavior to avoid extra mask step> */ + phaseTemp = phase + temp; + + /* fetch sample from wavetable */ + temp = sineTable[phaseTemp >> (32 - SINE_TABLE_SIZE_IN_BITS)]; + + /* increment operator phase */ + phase += phaseInc; + + /* internal gain for modulation effects */ + temp = FMUL_15x15(temp, (gain >> 16)); + + /* output gain calculation */ + temp2 = FMUL_15x15(temp, p->outputGain); + + /* saturating add to buffer */ + if (mix) + { + temp2 += *pBuffer; + *pBuffer++ = FM_Saturate(temp2); + } + + /* output to buffer */ + else + *pBuffer++ = (EAS_I16) temp2; + + /* increment gain */ + gain += gainInc; + + } + + /* save phase and gain */ + p->phase = phase; + p->gain = gainTarget; + + /* save last output for feedback in next frame */ + if (pLastOutput) + *pLastOutput = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * FM_NoiseOperator() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on passed parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_NoiseOperator ( + S_FM_ENG_OPER *p, + EAS_I32 numSamplesToAdd, + EAS_PCM *pBuffer, + EAS_BOOL mix, + EAS_U16 gainTarget, + EAS_U8 feedback, + EAS_I16 *pLastOutput) +{ + EAS_I32 gain; + EAS_I32 gainInc; + EAS_U32 phase; + EAS_I32 temp; + EAS_I32 temp2; + + /* establish local gain variable */ + gain = (EAS_I32) p->gain << 16; + + /* calculate gain increment */ + /*lint -e{703} use shift for performance */ + gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* establish local phase variables */ + phase = p->phase; + + /* establish local phase variables */ + phase = p->phase; + + /* recall last sample for filter Z-1 term */ + temp = 0; + if (pLastOutput) + temp = *pLastOutput; + + /* generate a buffer of samples */ + while (numSamplesToAdd--) + { + + /* if using filter */ + if (pLastOutput) + { + /* use PRNG for noise */ + temp2 = FM_Noise(&phase); + + /*lint -e{704} use shift for performance */ + temp += ((temp2 -temp) * feedback) >> 8; + } + else + { + temp = FM_Noise(&phase); + } + + /* internal gain for modulation effects */ + temp2 = FMUL_15x15(temp, (gain >> 16)); + + /* output gain calculation */ + temp2 = FMUL_15x15(temp2, p->outputGain); + + /* saturating add to buffer */ + if (mix) + { + temp2 += *pBuffer; + *pBuffer++ = FM_Saturate(temp2); + } + + /* output to buffer */ + else + *pBuffer++ = (EAS_I16) temp2; + + /* increment gain */ + gain += gainInc; + + } + + /* save phase and gain */ + p->phase = phase; + p->gain = gainTarget; + + /* save last output for feedback in next frame */ + if (pLastOutput) + *pLastOutput = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * FM_ConfigVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Receives parameters to start a new voice. + * + * Inputs: + * voiceNum - voice number to start + * vCfg - configuration data + * pMixBuffer - pointer to host supplied buffer + * + * Outputs: + * + * Side Effects: + * + * Notes: + * pFrameBuffer is not used in the test version, but is passed as a + * courtesy to split architecture implementations. It can be used as + * as pointer to the interprocessor communications buffer when the + * synthesis parameters are passed off to a DSP for synthesis. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pFrameBuffer) pFrameBuffer not used in test version - see above */ +void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + S_FM_ENG_VOICE *pVoice; + EAS_INT i; + + /* establish pointer to voice data */ + pVoice = &voices[voiceNum]; + + /* save data */ + pVoice->feedback = vCfg->feedback; + pVoice->flags = vCfg->flags; + pVoice->voiceGain = vCfg->voiceGain; + + /* initialize Z-1 terms */ + pVoice->op1Out = 0; + pVoice->op3Out = 0; + + /* initialize operators */ + for (i = 0; i < 4; i++) + { + /* save operator data */ + pVoice->oper[i].gain = vCfg->gain[i]; + pVoice->oper[i].outputGain = vCfg->outputGain[i]; + pVoice->oper[i].outputGain = vCfg->outputGain[i]; + + /* initalize operator */ + pVoice->oper[i].phase = 0; + } + + /* calculate pan */ +#if NUM_OUTPUT_CHANNELS == 2 + FM_CalculatePan(vCfg->pan, &pVoice->gainLeft, &pVoice->gainRight); +#endif +} + +/*---------------------------------------------------------------------------- + * FM_ProcessVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on calculated parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + * Notes: + * pOut is not used in the test version, but is passed as a + * courtesy to split architecture implementations. It can be used as + * as pointer to the interprocessor communications buffer when the + * synthesis parameters are passed off to a DSP for synthesis. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pOut) pOut not used in test version - see above */ +void FM_ProcessVoice ( + EAS_I32 voiceNum, + S_FM_VOICE_FRAME *pFrame, + EAS_I32 numSamplesToAdd, + EAS_PCM *pTempBuffer, + EAS_PCM *pBuffer, + EAS_I32 *pMixBuffer, + EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + S_FM_ENG_VOICE *p; + EAS_PCM *pOutBuf; + EAS_PCM *pMod; + EAS_BOOL mix; + EAS_U8 feedback1; + EAS_U8 feedback3; + EAS_U8 mode; + + /* establish pointer to voice data */ + p = &voices[voiceNum]; + mode = p->flags & 0x07; + + /* lookup feedback values */ + feedback1 = fmScaleTable[p->feedback >> 4]; + feedback3 = fmScaleTable[p->feedback & 0x0f]; + + /* operator 3 is on output bus in modes 0, 1, and 3 */ + if ((mode == 0) || (mode == 1) || (mode == 3)) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + if (p->flags & FLAG_FM_ENG_VOICE_OP3_NOISE) + { + FM_NoiseOperator( + p->oper + 2, + numSamplesToAdd, + pOutBuf, + EAS_FALSE, + pFrame->gain[2], + feedback3, + &p->op3Out); + } + else + { + FM_Operator( + p->oper + 2, + numSamplesToAdd, + pOutBuf, + 0, + EAS_FALSE, + pFrame->gain[2], + pFrame->pitch[2], + feedback3, + &p->op3Out); + } + + /* operator 4 is on output bus in modes 0, 1, and 2 */ + if (mode < 3) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + /* operator 4 is modulated in modes 2, 4, and 5 */ + if ((mode == 2) || (mode == 4) || (mode == 5)) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 4 is in mix mode in modes 0 and 1 */ + mix = (mode < 2); + + if (p->flags & FLAG_FM_ENG_VOICE_OP4_NOISE) + { + FM_NoiseOperator( + p->oper + 3, + numSamplesToAdd, + pOutBuf, + mix, + pFrame->gain[3], + 0, + 0); + } + else + { + FM_Operator( + p->oper + 3, + numSamplesToAdd, + pOutBuf, + pMod, + mix, + pFrame->gain[3], + pFrame->pitch[3], + 0, + 0); + } + + /* operator 1 is on output bus in mode 0 */ + if (mode == 0) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + /* operator 1 is modulated in modes 3 and 4 */ + if ((mode == 3) || (mode == 4)) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 1 is in mix mode in modes 0 and 5 */ + mix = ((mode == 0) || (mode == 5)); + + if (p->flags & FLAG_FM_ENG_VOICE_OP1_NOISE) + { + FM_NoiseOperator( + p->oper, + numSamplesToAdd, + pOutBuf, + mix, + pFrame->gain[0], + feedback1, + &p->op1Out); + } + else + { + FM_Operator( + p->oper, + numSamplesToAdd, + pOutBuf, + pMod, + mix, + pFrame->gain[0], + pFrame->pitch[0], + feedback1, + &p->op1Out); + } + + /* operator 2 is modulated in all modes except 0 */ + if (mode != 0) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 1 is in mix mode in modes 0 -3 */ + mix = (mode < 4); + + if (p->flags & FLAG_FM_ENG_VOICE_OP2_NOISE) + { + FM_NoiseOperator( + p->oper + 1, + numSamplesToAdd, + pBuffer, + mix, + pFrame->gain[1], + 0, + 0); + } + else + { + FM_Operator( + p->oper + 1, + numSamplesToAdd, + pBuffer, + pMod, + mix, + pFrame->gain[1], + pFrame->pitch[1], + 0, + 0); + } + + /* mix voice output to synthesizer output buffer */ + FM_SynthMixVoice(p, pFrame->voiceGain, numSamplesToAdd, pBuffer, pMixBuffer); +} + +/*---------------------------------------------------------------------------- + * FM_SynthMixVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Mixes the voice output buffer into the final mix using an anti-zipper + * filter. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_SynthMixVoice(S_FM_ENG_VOICE *p, EAS_U16 nGainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer) +{ + EAS_I32 nGain; + EAS_I32 nGainInc; + EAS_I32 nTemp; + + /* restore previous gain */ + /*lint -e{703} <use shift for performance> */ + nGain = (EAS_I32) p->voiceGain << 16; + + /* calculate gain increment */ + /*lint -e{703} <use shift for performance> */ + nGainInc = ((EAS_I32) nGainTarget - (EAS_I32) p->voiceGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* mix the output buffer */ + while (numSamplesToAdd--) + { + /* output gain calculation */ + nTemp = *pInputBuffer++; + + /* sum to output buffer */ +#if (NUM_OUTPUT_CHANNELS == 2) + + /*lint -e{704} <use shift for performance> */ + nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT; + + /*lint -e{704} <use shift for performance> */ + { + EAS_I32 nTemp2; + nTemp = nTemp >> FM_STEREO_PRE_GAIN_SHIFT; + nTemp2 = (nTemp * p->gainLeft) >> FM_STEREO_POST_GAIN_SHIFT; + *pBuffer++ += nTemp2; + nTemp2 = (nTemp * p->gainRight) >> FM_STEREO_POST_GAIN_SHIFT; + *pBuffer++ += nTemp2; + } +#else + /*lint -e{704} <use shift for performance> */ + nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_MONO_GAIN_SHIFT; + *pBuffer++ += nTemp; +#endif + + /* increment gain for anti-zipper filter */ + nGain += nGainInc; + } + + /* save gain */ + p->voiceGain = nGainTarget; +} + diff --git a/arm-fm-22k/lib_src/eas_fmengine.h b/arm-fm-22k/lib_src/eas_fmengine.h index 4ddc12b..dd248f8 100644 --- a/arm-fm-22k/lib_src/eas_fmengine.h +++ b/arm-fm-22k/lib_src/eas_fmengine.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_fmengine.h
- *
- * Contents and purpose:
- * Declarations, interfaces, and prototypes for FM synthesize low-level.
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_fmengine.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for FM synthesize low-level. + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,103 +19,103 @@ * 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: 664 $
- * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $
- *----------------------------------------------------------------------------
-*/
-
-/* sentinel */
-#ifndef _FMENGINE_H
-#define _FMENGINE_H
-
-/* check for split architecture */
-#if defined (EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH)
-#define FM_OFFBOARD
-#endif
-
-/* output level to mix buffer (3 = -24dB) */
-#define FM_GAIN_SHIFT 3
-#define FM_MONO_GAIN_SHIFT 9
-
-/* voice output level for stereo 15 = +6dB */
-#define FM_STEREO_PRE_GAIN_SHIFT 11
-#define FM_STEREO_POST_GAIN_SHIFT 10
-
-/* modulator input level shift (21 = -30dB) */
-#define FM_MODULATOR_INPUT_SHIFT 21
-
-/* feedback control level shift (7 = 0dB) */
-#define FM_FEEDBACK_SHIFT 7
-
-/* synth final output level */
-#define SYNTH_POST_GAIN_SHIFT 14
-
-/* LFO modulation to gain control */
-#define FM_LFO_GAIN_SHIFT 12
-
-/* sine table is always a power of 2 - saves cycles in inner loop */
-#define SINE_TABLE_SIZE_IN_BITS 11
-#define SINE_TABLE_SIZE 2048
-
-/* operator structure for FM engine */
-typedef struct
-{
- EAS_U32 phase; /* current waveform phase */
- EAS_U16 gain; /* current internal gain */
- EAS_U16 outputGain; /* current output gain */
-} S_FM_ENG_OPER;
-
-typedef struct
-{
- S_FM_ENG_OPER oper[4]; /* operator data */
- EAS_I16 op1Out; /* op1 output for feedback loop */
- EAS_I16 op3Out; /* op3 output for feedback loop */
- EAS_U16 voiceGain; /* LFO + channel parameters */
-#if (NUM_OUTPUT_CHANNELS == 2)
- EAS_U16 gainLeft; /* left gain multiplier */
- EAS_U16 gainRight; /* right gain multiplier */
-#endif
- EAS_U8 flags; /* mode bits and noise waveform flags */
- EAS_U8 feedback; /* feedback for Op1 and Op3 */
-} S_FM_ENG_VOICE;
-
-typedef struct
-{
- EAS_U16 gain[4]; /* initial operator gain value */
- EAS_U16 outputGain[4]; /* initial operator output gain value */
- EAS_U16 voiceGain; /* initial voice gain */
- EAS_U8 flags; /* mode bits and noise waveform flags */
- EAS_U8 feedback; /* feedback for Op1 and Op3 */
-#if (NUM_OUTPUT_CHANNELS == 2)
- EAS_I8 pan; /* pan value +/-64 */
-#endif
-} S_FM_VOICE_CONFIG;
-
-typedef struct
-{
- EAS_U16 gain[4]; /* new operator gain value */
- EAS_I16 pitch[4]; /* new pitch value */
- EAS_U16 voiceGain; /* new voice gain */
-} S_FM_VOICE_FRAME;
-
-/* bit definitions for S_FM_ENG_VOICE.flags */
-#define FLAG_FM_ENG_VOICE_OP1_NOISE 0x10 /* operator 1 source is PRNG */
-#define FLAG_FM_ENG_VOICE_OP2_NOISE 0x20 /* operator 2 source is PRNG */
-#define FLAG_FM_ENG_VOICE_OP3_NOISE 0x40 /* operator 3 source is PRNG */
-#define FLAG_FM_ENG_VOICE_OP4_NOISE 0x80 /* operator 4 source is PRNG */
-
-#ifdef FM_OFFBOARD
-extern EAS_BOOL FM_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
-extern EAS_BOOL FM_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffe, EAS_I32 *pMixBuffer, EAS_I16 masterGain);
-#endif
-
-/* FM engine prototypes */
-extern void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
-extern void FM_ProcessVoice (EAS_I32 voiceNum, S_FM_VOICE_FRAME *pFrame, EAS_I32 numSamplesToAdd, EAS_PCM *pTempBuffer, EAS_PCM *pBuffer, EAS_I32 *pMixBuffer, EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
-
-#endif
-/* #ifndef _FMENGINE_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 664 $ + * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* sentinel */ +#ifndef _FMENGINE_H +#define _FMENGINE_H + +/* check for split architecture */ +#if defined (EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH) +#define FM_OFFBOARD +#endif + +/* output level to mix buffer (3 = -24dB) */ +#define FM_GAIN_SHIFT 3 +#define FM_MONO_GAIN_SHIFT 9 + +/* voice output level for stereo 15 = +6dB */ +#define FM_STEREO_PRE_GAIN_SHIFT 11 +#define FM_STEREO_POST_GAIN_SHIFT 10 + +/* modulator input level shift (21 = -30dB) */ +#define FM_MODULATOR_INPUT_SHIFT 21 + +/* feedback control level shift (7 = 0dB) */ +#define FM_FEEDBACK_SHIFT 7 + +/* synth final output level */ +#define SYNTH_POST_GAIN_SHIFT 14 + +/* LFO modulation to gain control */ +#define FM_LFO_GAIN_SHIFT 12 + +/* sine table is always a power of 2 - saves cycles in inner loop */ +#define SINE_TABLE_SIZE_IN_BITS 11 +#define SINE_TABLE_SIZE 2048 + +/* operator structure for FM engine */ +typedef struct +{ + EAS_U32 phase; /* current waveform phase */ + EAS_U16 gain; /* current internal gain */ + EAS_U16 outputGain; /* current output gain */ +} S_FM_ENG_OPER; + +typedef struct +{ + S_FM_ENG_OPER oper[4]; /* operator data */ + EAS_I16 op1Out; /* op1 output for feedback loop */ + EAS_I16 op3Out; /* op3 output for feedback loop */ + EAS_U16 voiceGain; /* LFO + channel parameters */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_U16 gainLeft; /* left gain multiplier */ + EAS_U16 gainRight; /* right gain multiplier */ +#endif + EAS_U8 flags; /* mode bits and noise waveform flags */ + EAS_U8 feedback; /* feedback for Op1 and Op3 */ +} S_FM_ENG_VOICE; + +typedef struct +{ + EAS_U16 gain[4]; /* initial operator gain value */ + EAS_U16 outputGain[4]; /* initial operator output gain value */ + EAS_U16 voiceGain; /* initial voice gain */ + EAS_U8 flags; /* mode bits and noise waveform flags */ + EAS_U8 feedback; /* feedback for Op1 and Op3 */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I8 pan; /* pan value +/-64 */ +#endif +} S_FM_VOICE_CONFIG; + +typedef struct +{ + EAS_U16 gain[4]; /* new operator gain value */ + EAS_I16 pitch[4]; /* new pitch value */ + EAS_U16 voiceGain; /* new voice gain */ +} S_FM_VOICE_FRAME; + +/* bit definitions for S_FM_ENG_VOICE.flags */ +#define FLAG_FM_ENG_VOICE_OP1_NOISE 0x10 /* operator 1 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP2_NOISE 0x20 /* operator 2 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP3_NOISE 0x40 /* operator 3 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP4_NOISE 0x80 /* operator 4 source is PRNG */ + +#ifdef FM_OFFBOARD +extern EAS_BOOL FM_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern EAS_BOOL FM_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffe, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +#endif + +/* FM engine prototypes */ +extern void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern void FM_ProcessVoice (EAS_I32 voiceNum, S_FM_VOICE_FRAME *pFrame, EAS_I32 numSamplesToAdd, EAS_PCM *pTempBuffer, EAS_PCM *pBuffer, EAS_I32 *pMixBuffer, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + +#endif +/* #ifndef _FMENGINE_H */ + diff --git a/arm-fm-22k/lib_src/eas_fmsndlib.c b/arm-fm-22k/lib_src/eas_fmsndlib.c index bdd063c..dcde967 100644 --- a/arm-fm-22k/lib_src/eas_fmsndlib.c +++ b/arm-fm-22k/lib_src/eas_fmsndlib.c @@ -1,8 +1,8 @@ -/********************************************************************
- *
- * fmsndlib.c
- *
- * (c) Copyright 2005 Sonic Network, Inc. All Rights Reserved
+/******************************************************************** + * + * fmsndlib.c + * + * (c) Copyright 2005 Sonic Network, Inc. All Rights Reserved * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,1660 +15,1660 @@ * 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. - *
- * Source: C:\Sonic\Source\Gen3.3\FMSynth\GMdblib-3.fml
- ********************************************************************/
-
-
-#include "eas_data.h"
-
-/* begin region data */
-/*lint -e{651} lint complains about unnecessary brackets */
-const S_FM_REGION regions[] =
-{
-
- /* Region 0 */
- {
- 0x8005, 0, 127, 0, 255, 8, 0,
- 514, 239, 47, 97, 0, 184, 3,
- 1, 244, 89, 114, 0, 248, 2,
- 3370, 244, 49, 76, 40, 192, 2,
- -1, 227, 97, 51, 160, 212, 2
- },
-
- /* Region 1 */
- {
- 0x8005, 0, 127, 160, 255, 8, 0,
- 2514, 223, 95, 72, 0, 176, 3,
- 1, 244, 73, 145, 0, 244, 2,
- 3600, 245, 81, 198, 40, 192, 2,
- 3, 246, 81, 163, 108, 212, 2
- },
-
- /* Region 2 */
- {
- 0x8005, 0, 127, 160, 255, 119, 0,
- 0, 216, 79, 72, 0, 216, 2,
- 2, 244, 73, 145, 0, 244, 2,
- 3370, 247, 33, 182, 60, 204, 2,
- 1200, 246, 65, 163, 108, 204, 2
- },
-
- /* Region 3 */
- {
- 0x8005, 0, 127, 160, 255, 1, 0,
- 3369, 248, 65, 71, 40, 208, 2,
- -3, 245, 88, 113, 0, 244, 2,
- 2784, 225, 65, 133, 80, 192, 2,
- 3, 241, 81, 113, 80, 216, 2
- },
-
- /* Region 4 */
- {
- 0x8002, 0, 127, 0, 255, 128, 0,
- 0, 229, 155, 183, 0, 228, 2,
- -3, 243, 90, 81, 0, 244, 2,
- 4800, 248, 109, 180, 36, 192, 2,
- 3, 245, 90, 85, 16, 244, 2
- },
-
- /* Region 5 */
- {
- 0x8002, 0, 127, 9, 96, 192, 0,
- 1200, 229, 157, 180, 0, 216, 2,
- -3, 244, 90, 81, 0, 244, 2,
- 1902, 255, 111, 182, 80, 208, 2,
- 3, 246, 92, 83, 0, 244, 2
- },
-
- /* Region 6 */
- {
- 0x8002, 0, 127, 0, 255, 154, 0,
- 3102, 244, 63, 102, 228, 228, 2,
- 1200, 247, 93, 97, 0, 236, 2,
- 1902, 255, 63, 98, 156, 220, 2,
- 1200, 244, 92, 98, 0, 236, 2
- },
-
- /* Region 7 */
- {
- 0x8005, 0, 127, 0, 255, 202, 0,
- 0, 251, 131, 19, 216, 220, 2,
- 1201, 247, 62, 113, 0, 240, 2,
- 0, 243, 154, 36, 240, 224, 2,
- 2784, 250, 61, 36, 240, 208, 2
- },
-
- /* Region 8 */
- {
- 0x8001, 0, 127, 0, 255, 80, 0,
- -1, 213, 191, 183, 0, 204, 2,
- 1, 245, 154, 129, 0, 244, 2,
- 3831, 252, 159, 100, 0, 200, 2,
- 1197, 246, 91, 182, 0, 244, 2
- },
-
- /* Region 9 */
- {
- 0x8002, 0, 127, 48, 80, 21, 0,
- 2982, 255, 43, 96, 0, 196, 3,
- 3, 247, 71, 130, 0, 244, 2,
- 3358, 253, 40, 98, 144, 208, 2,
- -2, 246, 70, 130, 0, 236, 2
- },
-
- /* Region 10 */
- {
- 0x8002, 0, 127, 48, 80, 26, 0,
- 3096, 249, 72, 100, 0, 208, 2,
- 2185, 249, 102, 130, 0, 240, 2,
- 3386, 247, 66, 100, 144, 212, 2,
- -2, 247, 102, 130, 0, 240, 2
- },
-
- /* Region 11 */
- {
- 0x8002, 0, 127, 92, 67, 21, 0,
- 2982, 255, 27, 146, 0, 200, 3,
- 3, 246, 68, 146, 0, 240, 2,
- 3358, 250, 149, 116, 144, 208, 2,
- -3, 245, 68, 146, 0, 240, 0
- },
-
- /* Region 12 */
- {
- 0x8002, 0, 127, 0, 67, 0, 0,
- 1500, 239, 60, 151, 0, 220, 2,
- 0, 247, 76, 146, 0, 240, 2,
- 2398, 234, 156, 151, 0, 212, 2,
- 0, 246, 105, 146, 0, 244, 2
- },
-
- /* Region 13 */
- {
- 0x8002, 0, 127, 0, 67, 0, 0,
- 2500, 255, 60, 151, 0, 220, 2,
- 0, 249, 92, 146, 0, 244, 2,
- 3369, 250, 156, 151, 0, 196, 2,
- 0, 248, 89, 146, 0, 244, 2
- },
-
- /* Region 14 */
- {
- 0x8005, 0, 127, 160, 255, 0, 0,
- 2300, 229, 112, 49, 0, 208, 2,
- -3, 247, 67, 50, 0, 248, 2,
- 1074, 255, 41, 49, 0, 196, 2,
- 686, 240, 97, 18, 0, 196, 2
- },
-
- /* Region 15 */
- {
- 0x8005, 0, 127, 160, 255, 219, 0,
- 3369, 255, 65, 70, 40, 216, 2,
- 1, 246, 72, 113, 0, 240, 2,
- 1902, 225, 33, 129, 80, 204, 2,
- 2400, 225, 97, 113, 80, 200, 2
- },
-
- /* Region 16 */
- {
- 0x8003, 0, 127, 32, 48, 151, 0,
- 1201, 215, 35, 66, 252, 208, 0,
- -9581, 254, 63, 177, 240, 240, 3,
- 1902, 248, 47, 64, 112, 244, 2,
- 0, 247, 35, 66, 208, 212, 2
- },
-
- /* Region 17 */
- {
- 0x8001, 0, 127, 0, 255, 153, 0,
- 1, 252, 31, 3, 244, 196, 2,
- -1, 208, 31, 4, 248, 244, 2,
- 1205, 209, 31, 4, 248, 236, 2,
- 1899, 250, 31, 32, 0, 240, 2
- },
-
- /* Region 18 */
- {
- 0x8002, 0, 127, 32, 49, 201, 0,
- 1, 220, 47, 3, 244, 220, 0,
- -10000, 208, 63, 1, 248, 240, 3,
- 1586, 255, 47, 3, 188, 216, 2,
- -1, 202, 63, 32, 80, 232, 2
- },
-
- /* Region 19 */
- {
- 0x8001, 0, 127, 0, 143, 29, 0,
- -1200, 223, 64, 0, 252, 216, 2,
- 1200, 96, 41, 35, 248, 240, 2,
- 1200, 143, 41, 64, 252, 224, 2,
- 3102, 161, 41, 96, 248, 216, 2
- },
-
- /* Region 20 */
- {
- 0x8002, 0, 127, 0, 143, 34, 0,
- -1200, 133, 79, 1, 252, 212, 2,
- 1201, 112, 46, 34, 248, 232, 2,
- 0, 116, 79, 65, 252, 200, 2,
- 1900, 161, 46, 98, 248, 232, 2
- },
-
- /* Region 21 */
- {
- 0x8002, 0, 127, 0, 143, 187, 0,
- 1202, 80, 74, 1, 252, 216, 2,
- 2402, 112, 46, 34, 248, 232, 2,
- 0, 99, 78, 97, 184, 216, 2,
- 1899, 81, 46, 98, 236, 232, 2
- },
-
- /* Region 22 */
- {
- 0x8005, 0, 127, 22, 141, 34, 0,
- 2787, 176, 79, 4, 252, 208, 2,
- 2785, 144, 45, 34, 248, 236, 2,
- 3369, 83, 77, 100, 184, 172, 2,
- 1902, 102, 45, 100, 172, 212, 0
- },
-
- /* Region 23 */
- {
- 0x8002, 0, 127, 0, 143, 135, 0,
- 1900, 112, 79, 3, 252, 220, 2,
- 2400, 128, 45, 34, 248, 232, 2,
- 1200, 115, 77, 98, 184, 220, 2,
- 1904, 97, 45, 98, 236, 232, 2
- },
-
- /* Region 24 */
- {
- 0x8005, 0, 127, 0, 255, 157, 0,
- 1200, 244, 54, 4, 20, 200, 2,
- 0, 245, 92, 130, 0, 244, 2,
- 3802, 247, 68, 21, 0, 196, 2,
- 1, 245, 43, 114, 0, 204, 2
- },
-
- /* Region 25 */
- {
- 0x8005, 0, 127, 0, 128, 83, 0,
- 0, 244, 51, 4, 200, 204, 0,
- 0, 247, 108, 129, 0, 248, 0,
- 2786, 243, 31, 70, 200, 220, 0,
- 1902, 246, 44, 113, 12, 188, 0
- },
-
- /* Region 26 */
- {
- 0x8005, 0, 127, 0, 128, 61, 0,
- 0, 246, 51, 97, 76, 204, 0,
- 0, 244, 60, 97, 0, 240, 0,
- 1786, 255, 31, 64, 0, 180, 0,
- 1200, 247, 60, 97, 12, 204, 0
- },
-
- /* Region 27 */
- {
- 0x8005, 0, 127, 0, 128, 153, 0,
- -2, 243, 53, 99, 96, 200, 0,
- 0, 243, 60, 97, 0, 240, 0,
- 3983, 247, 63, 100, 24, 204, 0,
- 2, 242, 53, 99, 52, 212, 0
- },
-
- /* Region 28 */
- {
- 0x8005, 0, 127, 0, 128, 205, 0,
- -2, 244, 47, 97, 20, 208, 0,
- 0, 252, 75, 193, 0, 248, 0,
- 0, 254, 63, 98, 132, 224, 0,
- 2786, 251, 63, 98, 52, 192, 0
- },
-
- /* Region 29 */
- {
- 0x8005, 0, 127, 0, 128, 221, 0,
- -1, 208, 191, 99, 220, 224, 0,
- 1200, 243, 92, 97, 0, 244, 0,
- 3984, 212, 11, 96, 168, 196, 0,
- 1, 242, 127, 98, 108, 204, 0
- },
-
- /* Region 30 */
- {
- 0x8005, 0, 127, 0, 128, 174, 0,
- -3, 212, 207, 99, 0, 228, 0,
- 1902, 241, 108, 97, 0, 248, 0,
- 3805, 212, 59, 98, 0, 220, 0,
- 1902, 146, 107, 98, 144, 196, 0
- },
-
- /* Region 31 */
- {
- 0x8009, 0, 127, 0, 255, 128, 0,
- 1206, 239, 43, 69, 0, 216, 2,
- 4, 254, 42, 66, 0, 244, 2,
- 702, 88, 55, 66, 0, 204, 2,
- -4, 71, 55, 66, 0, 240, 2
- },
-
- /* Region 32 */
- {
- 0x8005, 0, 127, 0, 255, 85, 0,
- 500, 239, 95, 82, 0, 184, 3,
- 0, 248, 73, 132, 0, 252, 2,
- 2786, 203, 59, 130, 0, 176, 2,
- 0, 216, 42, 100, 0, 208, 2
- },
-
- /* Region 33 */
- {
- 0x8005, 0, 127, 0, 128, 73, 0,
- 1, 229, 54, 131, 160, 208, 0,
- -1, 244, 62, 97, 0, 248, 0,
- 3986, 227, 127, 69, 140, 184, 0,
- 1201, 249, 92, 114, 0, 204, 0
- },
-
- /* Region 34 */
- {
- 0x8005, 0, 127, 0, 128, 73, 0,
- 1, 225, 54, 100, 200, 212, 0,
- -1, 244, 94, 97, 0, 248, 0,
- 3986, 249, 127, 88, 112, 188, 0,
- 1201, 249, 92, 85, 52, 208, 0
- },
-
- /* Region 35 */
- {
- 0x8005, 0, 127, 0, 128, 188, 0,
- -3, 198, 92, 179, 28, 212, 0,
- 0, 243, 90, 145, 0, 248, 0,
- 1901, 215, 95, 69, 28, 196, 0,
- 3, 84, 108, 196, 32, 208, 0
- },
-
- /* Region 36 */
- {
- 0x8005, 0, 127, 0, 136, 6, 0,
- 0, 226, 99, 36, 224, 216, 0,
- 1902, 248, 78, 33, 0, 252, 0,
- 3369, 239, 250, 33, 0, 204, 0,
- 0, 230, 253, 33, 0, 208, 0
- },
-
- /* Region 37 */
- {
- 0x8005, 0, 127, 0, 136, 195, 0,
- 0, 245, 99, 36, 152, 208, 0,
- 1200, 248, 78, 33, 0, 252, 0,
- 3369, 246, 250, 33, 0, 216, 0,
- 0, 246, 61, 33, 0, 180, 0
- },
-
- /* Region 38 */
- {
- 0x8002, 0, 127, 0, 133, 221, 0,
- 1, 244, 67, 35, 80, 220, 0,
- 3, 246, 94, 33, 0, 244, 0,
- -1, 245, 70, 35, 80, 236, 2,
- -3, 246, 63, 33, 0, 236, 2
- },
-
- /* Region 39 */
- {
- 0x8002, 0, 127, 0, 133, 220, 0,
- 0, 114, 51, 34, 132, 208, 0,
- 3, 214, 62, 33, 0, 248, 0,
- 0, 85, 54, 34, 44, 224, 2,
- -3, 214, 63, 33, 0, 236, 2
- },
-
- /* Region 40 */
- {
- 0x8005, 0, 127, 48, 142, 187, 0,
- -1, 33, 22, 33, 200, 208, 0,
- 0, 81, 105, 33, 220, 240, 0,
- 2786, 245, 19, 50, 208, 192, 0,
- 1, 245, 21, 82, 200, 220, 0
- },
-
- /* Region 41 */
- {
- 0x8005, 0, 127, 48, 126, 103, 0,
- -1, 193, 22, 33, 228, 212, 0,
- 0, 81, 105, 33, 220, 244, 0,
- 0, 245, 19, 50, 216, 228, 0,
- 1200, 245, 19, 82, 200, 188, 0
- },
-
- /* Region 42 */
- {
- 0x8005, 0, 127, 16, 126, 202, 0,
- -1, 49, 24, 41, 200, 212, 0,
- 0, 81, 71, 49, 220, 244, 0,
- 3371, 243, 19, 36, 232, 192, 0,
- 1, 242, 24, 36, 220, 212, 0
- },
-
- /* Region 43 */
- {
- 0x8005, 0, 127, 16, 124, 205, 0,
- 0, 129, 24, 49, 208, 200, 0,
- 0, 67, 102, 81, 224, 244, 0,
- 3804, 246, 23, 36, 160, 196, 0,
- 1200, 244, 24, 35, 208, 200, 0
- },
-
- /* Region 44 */
- {
- 0x8005, 0, 127, 48, 144, 208, 0,
- -3, 209, 22, 33, 200, 204, 2,
- 0, 81, 89, 33, 220, 240, 2,
- -5000, 208, 6, 33, 244, 188, 3,
- 3, 97, 89, 33, 224, 200, 0
- },
-
- /* Region 45 */
- {
- 0x8005, 0, 127, 0, 255, 186, 0,
- 500, 223, 95, 0, 0, 192, 3,
- 0, 247, 89, 100, 0, 248, 2,
- 3369, 255, 59, 168, 0, 212, 2,
- 0, 216, 42, 97, 0, 212, 2
- },
-
- /* Region 46 */
- {
- 0x8002, 0, 127, 0, 255, 221, 0,
- 1206, 235, 70, 69, 0, 216, 2,
- 4, 248, 84, 66, 0, 244, 2,
- 1902, 247, 52, 137, 80, 216, 2,
- -4, 245, 84, 131, 0, 240, 2
- },
-
- /* Region 47 */
- {
- 0x8005, 0, 127, 0, 255, 105, 0,
- 387, 231, 115, 34, 4, 216, 2,
- 0, 248, 37, 65, 0, 252, 2,
- 3308, 248, 117, 34, 8, 200, 2,
- 1900, 213, 82, 50, 0, 192, 2
- },
-
- /* Region 48 */
- {
- 0x8002, 0, 127, 32, 160, 221, 0,
- -7, 209, 22, 33, 200, 204, 2,
- -7, 81, 73, 33, 220, 244, 0,
- 7, 209, 22, 33, 200, 208, 0,
- 7, 97, 73, 33, 224, 244, 2
- },
-
- /* Region 49 */
- {
- 0x8002, 0, 127, 64, 128, 189, 0,
- -2, 209, 54, 32, 224, 216, 2,
- -7726, 97, 105, 33, 220, 240, 3,
- 1902, 209, 54, 34, 216, 208, 0,
- 2, 81, 105, 33, 224, 236, 0
- },
-
- /* Region 50 */
- {
- 0x8002, 0, 127, 80, 144, 206, 0,
- -3, 179, 38, 33, 160, 220, 2,
- -7726, 81, 69, 34, 220, 244, 3,
- 3, 193, 38, 33, 240, 212, 0,
- -8000, 65, 69, 34, 224, 236, 3
- },
-
- /* Region 51 */
- {
- 0x8005, 0, 127, 96, 128, 204, 0,
- -3, 97, 38, 33, 180, 216, 0,
- 0, 81, 69, 34, 220, 240, 2,
- 3369, 145, 38, 33, 240, 196, 2,
- -13190, 65, 69, 34, 240, 200, 3
- },
-
- /* Region 52 */
- {
- 0x8002, 0, 127, 64, 128, 108, 0,
- -3, 193, 37, 35, 236, 208, 0,
- 2394, 97, 90, 36, 224, 232, 2,
- 3, 65, 40, 35, 236, 204, 2,
- 1203, 97, 89, 33, 224, 240, 0
- },
-
- /* Region 53 */
- {
- 0x8005, 0, 127, 128, 128, 122, 0,
- 0, 193, 21, 34, 236, 188, 0,
- 3, 97, 74, 36, 224, 248, 2,
- 1906, 251, 24, 32, 96, 192, 3,
- 1200, 97, 73, 32, 224, 184, 0
- },
-
- /* Region 54 */
- {
- 0x8002, 0, 127, 64, 133, 135, 0,
- 0, 194, 25, 35, 120, 200, 2,
- 0, 97, 75, 36, 224, 240, 0,
- 2906, 254, 28, 48, 0, 184, 3,
- 0, 216, 75, 80, 204, 240, 2
- },
-
- /* Region 55 */
- {
- 0x8009, 0, 127, 208, 64, 255, 0,
- 475, 249, 16, 32, 252, 240, 2,
- 702, 248, 71, 32, 0, 244, 2,
- 1136, 232, 27, 32, 216, 248, 0,
- 0, 249, 23, 48, 0, 248, 2
- },
-
- /* Region 56 */
- {
- 0x8005, 0, 127, 0, 132, 233, 0,
- 0, 195, 95, 64, 240, 208, 0,
- 0, 225, 94, 64, 248, 240, 0,
- 0, 254, 127, 0, 4, 196, 4,
- 1902, 228, 95, 1, 248, 200, 0
- },
-
- /* Region 57 */
- {
- 0x8005, 0, 127, 16, 140, 238, 0,
- 0, 163, 90, 67, 228, 208, 0,
- 0, 209, 77, 65, 248, 240, 0,
- 1969, 173, 58, 65, 0, 176, 0,
- 0, 210, 61, 52, 204, 220, 0
- },
-
- /* Region 58 */
- {
- 0x8005, 0, 127, 16, 140, 222, 0,
- 0, 119, 74, 67, 160, 212, 0,
- 0, 146, 61, 65, 248, 244, 0,
- 1900, 137, 58, 65, 100, 196, 0,
- 0, 119, 61, 52, 120, 200, 0
- },
-
- /* Region 59 */
- {
- 0x8005, 0, 127, 16, 135, 219, 0,
- 0, 176, 79, 69, 240, 216, 0,
- 0, 193, 79, 64, 248, 236, 0,
- 0, 178, 123, 54, 92, 228, 0,
- 3369, 212, 95, 38, 144, 212, 0
- },
-
- /* Region 60 */
- {
- 0x8002, 0, 127, 0, 119, 203, 0,
- 2, 65, 77, 66, 228, 204, 0,
- 2, 161, 74, 64, 240, 240, 0,
- -2, 85, 60, 66, 180, 216, 2,
- -2, 162, 74, 64, 220, 240, 2
- },
-
- /* Region 61 */
- {
- 0x8002, 0, 127, 16, 154, 237, 0,
- 0, 179, 42, 64, 216, 208, 0,
- 0, 209, 61, 64, 248, 244, 0,
- -1200, 226, 55, 65, 244, 220, 2,
- 1902, 162, 62, 52, 204, 236, 2
- },
-
- /* Region 62 */
- {
- 0x8002, 0, 127, 48, 119, 221, 0,
- 2, 119, 79, 64, 208, 212, 0,
- 2, 209, 110, 64, 248, 236, 0,
- -2, 84, 79, 64, 136, 212, 2,
- -2, 209, 110, 64, 240, 240, 2
- },
-
- /* Region 63 */
- {
- 0x8002, 0, 127, 32, 135, 221, 0,
- 2, 165, 79, 64, 152, 216, 0,
- 2, 225, 110, 64, 248, 236, 0,
- -2, 132, 79, 64, 72, 224, 2,
- -2, 241, 110, 64, 252, 236, 2
- },
-
- /* Region 64 */
- {
- 0x8005, 0, 127, 17, 127, 190, 0,
- 0, 209, 60, 67, 244, 208, 0,
- 1200, 145, 94, 65, 248, 244, 2,
- 3369, 197, 47, 4, 128, 192, 0,
- 1902, 167, 94, 6, 200, 200, 0
- },
-
- /* Region 65 */
- {
- 0x8005, 0, 127, 17, 143, 190, 0,
- 0, 209, 60, 67, 244, 216, 0,
- 1902, 145, 62, 65, 248, 240, 2,
- 3369, 197, 47, 4, 128, 196, 0,
- 2400, 167, 94, 6, 200, 212, 2
- },
-
- /* Region 66 */
- {
- 0x8005, 0, 127, 17, 143, 190, 0,
- 0, 209, 60, 67, 244, 208, 0,
- 1902, 145, 62, 65, 248, 240, 2,
- 3369, 197, 47, 4, 128, 192, 0,
- 1902, 167, 94, 6, 200, 216, 2
- },
-
- /* Region 67 */
- {
- 0x8005, 0, 127, 17, 125, 190, 0,
- 0, 114, 109, 67, 244, 224, 0,
- 1902, 166, 93, 97, 200, 240, 0,
- 2786, 165, 95, 52, 160, 200, 0,
- 2400, 173, 78, 54, 240, 212, 2
- },
-
- /* Region 68 */
- {
- 0x8002, 0, 127, 16, 140, 205, 0,
- 0, 211, 55, 66, 244, 208, 0,
- 1902, 193, 93, 65, 248, 240, 0,
- 0, 204, 47, 4, 244, 216, 0,
- 3600, 183, 95, 6, 160, 232, 0
- },
-
- /* Region 69 */
- {
- 0x8002, 0, 127, 16, 126, 222, 0,
- 0, 243, 36, 66, 172, 200, 0,
- 1200, 193, 110, 67, 248, 244, 0,
- 0, 215, 33, 2, 232, 212, 0,
- 3369, 178, 63, 6, 184, 240, 0
- },
-
- /* Region 70 */
- {
- 0x8002, 0, 127, 16, 140, 221, 0,
- 1200, 213, 61, 66, 136, 200, 0,
- 1902, 193, 93, 68, 248, 240, 0,
- 0, 197, 47, 2, 228, 216, 0,
- 3369, 183, 95, 2, 160, 236, 0
- },
-
- /* Region 71 */
- {
- 0x8002, 0, 127, 16, 124, 201, 0,
- 1200, 195, 55, 68, 240, 208, 0,
- 0, 209, 76, 65, 248, 236, 0,
- 1902, 147, 47, 19, 208, 212, 0,
- 0, 183, 79, 22, 156, 228, 0
- },
-
- /* Region 72 */
- {
- 0x8005, 0, 127, 32, 110, 234, 0,
- 500, 237, 60, 68, 0, 192, 1,
- 1, 161, 93, 65, 248, 240, 2,
- 3365, 154, 47, 16, 48, 180, 6,
- 1200, 165, 92, 52, 160, 212, 2
- },
-
- /* Region 73 */
- {
- 0x8005, 0, 127, 32, 142, 200, 0,
- 0, 193, 60, 68, 248, 200, 0,
- 1, 129, 61, 65, 248, 240, 2,
- 3365, 154, 47, 16, 68, 184, 6,
- 1200, 169, 92, 52, 160, 204, 2
- },
-
- /* Region 74 */
- {
- 0x8003, 0, 127, 32, 135, 36, 0,
- 1199, 165, 79, 66, 152, 192, 2,
- -3, 145, 110, 64, 248, 240, 2,
- 0, 199, 79, 66, 44, 236, 2,
- 2986, 136, 110, 67, 100, 196, 2
- },
-
- /* Region 75 */
- {
- 0x8005, 0, 127, 32, 190, 71, 0,
- 868, 202, 140, 16, 24, 188, 2,
- 0, 176, 77, 65, 248, 240, 2,
- 3750, 169, 127, 16, 36, 228, 6,
- 2400, 195, 60, 17, 232, 172, 2
- },
-
- /* Region 76 */
- {
- 0x8005, 0, 127, 224, 16, 123, 0,
- 275, 202, 14, 2, 44, 196, 2,
- 0, 165, 89, 65, 56, 244, 2,
- 0, 255, 12, 2, 64, 216, 6,
- 963, 169, 14, 4, 40, 196, 2
- },
-
- /* Region 77 */
- {
- 0x8012, 0, 127, 192, 128, 100, 0,
- 1500, 202, 79, 68, 76, 204, 2,
- -2, 97, 26, 64, 248, 232, 2,
- 1588, 202, 223, 69, 4, 220, 0,
- 3, 188, 121, 67, 48, 252, 2
- },
-
- /* Region 78 */
- {
- 0x8002, 0, 127, 112, 140, 205, 0,
- 0, 68, 47, 66, 60, 176, 2,
- -2, 113, 94, 64, 248, 236, 0,
- 5000, 121, 47, 64, 32, 168, 7,
- 3, 136, 94, 64, 0, 236, 0
- },
-
- /* Region 79 */
- {
- 0x8003, 0, 127, 32, 135, 33, 0,
- 1199, 197, 79, 66, 152, 184, 2,
- 0, 161, 110, 64, 248, 240, 2,
- 0, 199, 79, 66, 44, 236, 2,
- 2400, 255, 110, 65, 36, 208, 6
- },
-
- /* Region 80 */
- {
- 0x8002, 0, 127, 0, 192, 170, 0,
- 1199, 192, 77, 33, 200, 212, 0,
- 0, 209, 107, 33, 232, 240, 0,
- 1201, 80, 77, 33, 200, 212, 0,
- 0, 241, 107, 33, 232, 240, 0
- },
-
- /* Region 81 */
- {
- 0x8002, 0, 127, 0, 192, 221, 0,
- -1, 192, 45, 33, 200, 212, 0,
- -1, 209, 107, 33, 232, 244, 0,
- 1, 80, 45, 33, 200, 212, 0,
- 1, 241, 107, 33, 232, 244, 0
- },
-
- /* Region 82 */
- {
- 0x8005, 0, 127, 0, 112, 255, 0,
- 4750, 221, 45, 34, 48, 172, 4,
- -10000, 161, 107, 33, 200, 244, 3,
- 2204, 137, 45, 37, 64, 184, 0,
- -2, 211, 107, 33, 160, 208, 0
- },
-
- /* Region 83 */
- {
- 0x8005, 0, 127, 16, 127, 238, 0,
- 2, 248, 45, 32, 204, 208, 0,
- -9500, 241, 107, 33, 200, 240, 3,
- 3369, 186, 45, 38, 24, 208, 0,
- -2, 211, 107, 32, 220, 212, 0
- },
-
- /* Region 84 */
- {
- 0x8005, 0, 127, 0, 128, 221, 0,
- -1, 192, 191, 99, 220, 216, 0,
- 1200, 243, 92, 97, 0, 244, 0,
- 3984, 200, 11, 96, 168, 192, 0,
- 1, 194, 127, 98, 108, 200, 0
- },
-
- /* Region 85 */
- {
- 0x8002, 0, 127, 128, 128, 111, 0,
- 1, 194, 25, 35, 120, 204, 2,
- -9750, 193, 107, 36, 224, 244, 3,
- 3906, 255, 28, 50, 12, 188, 3,
- -1, 216, 107, 80, 204, 240, 2
- },
-
- /* Region 86 */
- {
- 0x8002, 0, 127, 32, 134, 222, 0,
- 0, 195, 52, 33, 200, 208, 0,
- 0, 177, 90, 33, 232, 240, 2,
- 702, 195, 52, 33, 200, 208, 2,
- 702, 177, 90, 34, 232, 240, 2
- },
-
- /* Region 87 */
- {
- 0x8002, 0, 127, 32, 134, 205, 0,
- 0, 198, 75, 36, 120, 220, 2,
- 0, 225, 78, 52, 40, 244, 2,
- 0, 246, 47, 32, 220, 208, 2,
- 1902, 241, 124, 32, 240, 236, 2
- },
-
- /* Region 88 */
- {
- 0x8003, 0, 127, 32, 120, 14, 0,
- 3600, 244, 67, 34, 88, 208, 0,
- 3, 194, 84, 33, 84, 240, 2,
- -3, 194, 84, 33, 172, 236, 2,
- 902, 254, 114, 34, 0, 224, 3
- },
-
- /* Region 89 */
- {
- 0x8002, 0, 127, 64, 169, 170, 0,
- -3, 83, 69, 34, 184, 212, 0,
- -7500, 50, 69, 33, 176, 244, 3,
- 3, 81, 69, 34, 212, 212, 2,
- -8500, 66, 69, 33, 176, 244, 3
- },
-
- /* Region 90 */
- {
- 0x8002, 0, 127, 64, 120, 221, 0,
- -2, 82, 69, 34, 244, 216, 0,
- 0, 145, 102, 33, 228, 240, 0,
- 2, 81, 69, 34, 244, 208, 2,
- 0, 145, 102, 33, 224, 240, 2
- },
-
- /* Region 91 */
- {
- 0x8003, 0, 127, 32, 138, 14, 0,
- 2400, 148, 67, 34, 176, 200, 0,
- 3, 194, 85, 33, 220, 236, 2,
- -3, 194, 69, 33, 220, 236, 2,
- 1905, 254, 114, 34, 48, 224, 2
- },
-
- /* Region 92 */
- {
- 0x8002, 0, 127, 82, 67, 71, 0,
- 2982, 228, 22, 146, 88, 192, 3,
- 3, 102, 84, 146, 196, 240, 2,
- 3358, 50, 149, 116, 144, 208, 2,
- -3, 85, 84, 146, 120, 240, 0
- },
-
- /* Region 93 */
- {
- 0x8005, 0, 127, 48, 126, 219, 0,
- -3, 49, 19, 33, 120, 200, 0,
- 0, 81, 70, 33, 220, 240, 0,
- 3804, 242, 18, 50, 200, 200, 0,
- 1203, 82, 19, 82, 200, 176, 0
- },
-
- /* Region 94 */
- {
- 0x8003, 0, 127, 32, 138, 13, 0,
- 2786, 116, 67, 34, 204, 184, 0,
- 1902, 114, 69, 33, 192, 232, 2,
- -3, 178, 69, 33, 188, 232, 2,
- 3804, 254, 82, 34, 164, 228, 2
- },
-
- /* Region 95 */
- {
- 0x8002, 0, 127, 48, 135, 238, 0,
- -2, 34, 85, 34, 184, 224, 0,
- 1, 113, 70, 33, 228, 236, 0,
- 2, 19, 85, 34, 156, 224, 2,
- -1, 129, 70, 33, 224, 236, 2
- },
-
- /* Region 96 */
- {
- 0x8012, 0, 127, 240, 112, 221, 0,
- 3369, 213, 69, 32, 0, 204, 0,
- 0, 193, 70, 33, 112, 232, 2,
- 0, 145, 69, 34, 244, 208, 2,
- -9000, 145, 70, 33, 224, 236, 3
- },
-
- /* Region 97 */
- {
- 0x8002, 0, 127, 96, 122, 168, 0,
- -1, 99, 51, 33, 200, 208, 0,
- -8500, 81, 83, 33, 232, 240, 3,
- 702, 99, 52, 33, 200, 208, 2,
- -9500, 65, 83, 34, 224, 240, 3
- },
-
- /* Region 98 */
- {
- 0x8002, 0, 127, 0, 67, 0, 0,
- 1500, 217, 55, 151, 20, 224, 2,
- 3, 231, 70, 146, 88, 220, 2,
- 2369, 115, 148, 151, 32, 196, 2,
- -3, 118, 36, 146, 64, 244, 2
- },
-
- /* Region 99 */
- {
- 0x8002, 0, 127, 64, 169, 204, 0,
- -3, 228, 69, 34, 148, 220, 0,
- -7448, 243, 69, 33, 200, 240, 3,
- 3, 81, 68, 34, 212, 212, 2,
- -8526, 65, 68, 33, 196, 240, 3
- },
-
- /* Region 100 */
- {
- 0x8002, 0, 127, 64, 119, 187, 0,
- 2786, 228, 22, 146, 176, 192, 0,
- 3, 102, 68, 146, 196, 236, 2,
- 3369, 178, 149, 116, 176, 208, 2,
- -3, 231, 68, 146, 120, 240, 0
- },
-
- /* Region 101 */
- {
- 0x8002, 0, 127, 240, 144, 239, 0,
- -2, 49, 69, 34, 236, 208, 2,
- -9000, 113, 102, 33, 228, 236, 3,
- 2400, 149, 69, 34, 12, 216, 1,
- 0, 145, 102, 33, 224, 236, 2
- },
-
- /* Region 102 */
- {
- 0x8012, 0, 127, 241, 176, 6, 0,
- 1200, 247, 49, 64, 252, 204, 0,
- 3804, 246, 101, 32, 0, 232, 2,
- 1902, 247, 32, 32, 112, 188, 2,
- 0, 228, 84, 32, 0, 240, 2
- },
-
- /* Region 103 */
- {
- 0x8005, 0, 127, 64, 101, 221, 0,
- 1, 194, 68, 97, 196, 200, 2,
- -10001, 247, 100, 114, 176, 240, 3,
- 3370, 213, 33, 70, 52, 200, 2,
- -1, 178, 68, 49, 208, 212, 0
- },
-
- /* Region 104 */
- {
- 0x8002, 0, 127, 0, 255, 203, 0,
- -3, 245, 82, 99, 200, 232, 2,
- 2787, 244, 84, 96, 0, 236, 2,
- 1198, 133, 81, 100, 196, 220, 2,
- 1902, 147, 67, 80, 0, 232, 2
- },
-
- /* Region 105 */
- {
- 0x8005, 0, 127, 0, 255, 140, 0,
- 500, 255, 137, 179, 0, 200, 3,
- 1902, 248, 90, 160, 0, 244, 2,
- 3804, 245, 57, 35, 164, 204, 2,
- 0, 245, 38, 51, 196, 208, 2
- },
-
- /* Region 106 */
- {
- 0x8005, 0, 127, 0, 255, 72, 0,
- 1000, 238, 57, 65, 0, 188, 3,
- 1902, 247, 103, 112, 0, 244, 2,
- 2786, 250, 36, 81, 68, 212, 2,
- 0, 249, 50, 49, 172, 204, 2
- },
-
- /* Region 107 */
- {
- 0x8005, 0, 127, 16, 119, 72, 0,
- 1500, 255, 89, 65, 0, 196, 3,
- 2790, 246, 39, 112, 0, 240, 0,
- 1905, 246, 36, 81, 168, 208, 0,
- 0, 249, 114, 49, 172, 212, 0
- },
-
- /* Region 108 */
- {
- 0x8005, 0, 127, 0, 255, 237, 0,
- 1902, 254, 89, 65, 0, 212, 2,
- 0, 248, 87, 112, 0, 240, 2,
- 3369, 231, 62, 81, 0, 208, 2,
- 3, 245, 118, 49, 96, 196, 2
- },
-
- /* Region 109 */
- {
- 0x8002, 0, 127, 16, 188, 205, 0,
- -2, 179, 47, 50, 244, 224, 2,
- 1900, 145, 94, 49, 248, 232, 2,
- 3, 210, 46, 2, 244, 208, 2,
- 2789, 133, 93, 4, 180, 244, 2
- },
-
- /* Region 110 */
- {
- 0x8005, 0, 127, 48, 135, 220, 0,
- 1901, 162, 25, 35, 144, 208, 0,
- 0, 113, 105, 65, 220, 240, 0,
- 3369, 233, 88, 51, 120, 212, 0,
- 0, 229, 24, 84, 200, 208, 0
- },
-
- /* Region 111 */
- {
- 0x8002, 0, 127, 112, 32, 190, 0,
- 0, 53, 79, 66, 152, 212, 2,
- 1200, 53, 75, 64, 136, 244, 2,
- 500, 149, 60, 66, 16, 208, 2,
- 1902, 200, 78, 64, 0, 248, 0
- },
-
- /* Region 112 */
- {
- 0x8005, 0, 127, 0, 144, 130, 0,
- 2514, 255, 68, 53, 0, 204, 2,
- 2400, 247, 133, 48, 0, 240, 2,
- 4151, 243, 67, 50, 0, 212, 2,
- 3369, 243, 66, 56, 0, 204, 2
- },
-
- /* Region 113 */
- {
- 0x8005, 0, 127, 0, 255, 0, 0,
- 514, 253, 79, 51, 0, 196, 3,
- 1905, 252, 89, 51, 0, 244, 2,
- 4349, 245, 35, 51, 0, 208, 2,
- 1205, 247, 34, 51, 0, 208, 2
- },
-
- /* Region 114 */
- {
- 0x8005, 0, 127, 0, 255, 0, 0,
- 514, 221, 69, 35, 0, 204, 3,
- 0, 250, 86, 115, 0, 252, 2,
- 1884, 244, 116, 51, 0, 200, 2,
- 1208, 210, 35, 51, 0, 208, 2
- },
-
- /* Region 115 */
- {
- 0x8005, 0, 127, 0, 255, 16, 0,
- 514, 222, 85, 163, 0, 192, 3,
- 0, 254, 108, 163, 0, 252, 2,
- 3800, 255, 143, 160, 0, 176, 2,
- 1200, 250, 105, 163, 0, 212, 2
- },
-
- /* Region 116 */
- {
- 0x8005, 0, 127, 0, 255, 16, 0,
- 1514, 249, 101, 163, 0, 204, 3,
- -1200, 249, 87, 160, 0, 252, 2,
- 0, 235, 143, 160, 0, 204, 2,
- 1200, 234, 73, 163, 0, 204, 2
- },
-
- /* Region 117 */
- {
- 0x8005, 0, 127, 0, 255, 16, 0,
- 500, 239, 101, 160, 0, 204, 3,
- -1195, 248, 104, 160, 0, 252, 2,
- 1898, 252, 72, 163, 0, 216, 2,
- 1239, 248, 87, 163, 0, 196, 2
- },
-
- /* Region 118 */
- {
- 0x8005, 0, 127, 0, 255, 255, 0,
- 500, 255, 98, 160, 0, 196, 3,
- -1, 249, 105, 160, 0, 252, 2,
- 1907, 250, 71, 160, 0, 252, 2,
- 1182, 249, 87, 161, 0, 192, 2
- },
-
- /* Region 119 */
- {
- 0x8005, 0, 127, 0, 0, 100, 0,
- 600, 32, 15, 0, 252, 224, 6,
- 0, 47, 111, 65, 0, 244, 2,
- 1826, 16, 47, 0, 252, 216, 2,
- 3551, 240, 47, 0, 252, 212, 2
- },
-
- /* Region 120 */
- {
- 0x8014, 0, 127, 240, 128, 235, 0,
- 1228, 161, 47, 17, 196, 200, 3,
- 3000, 123, 75, 17, 0, 240, 2,
- 7022, 72, 43, 17, 0, 216, 0,
- 4000, 150, 79, 17, 48, 196, 3
- },
-
- /* Region 121 */
- {
- 0x8005, 0, 127, 224, 16, 86, 0,
- 275, 251, 6, 0, 36, 200, 2,
- 0, 101, 104, 65, 56, 240, 2,
- 0, 240, 6, 0, 252, 208, 6,
- 1000, 195, 8, 0, 248, 200, 2
- },
-
- /* Region 122 */
- {
- 0x8002, 0, 127, 0, 0, 185, 0,
- 600, 35, 66, 17, 72, 224, 4,
- -13000, 81, 67, 17, 228, 244, 2,
- 702, 97, 38, 17, 212, 196, 6,
- -14000, 81, 65, 17, 224, 244, 3
- },
-
- /* Region 123 */
- {
- 0x8012, 0, 127, 240, 112, 237, 0,
- -6528, 153, 127, 16, 0, 252, 3,
- 1200, 105, 109, 16, 0, 216, 2,
- -6022, 179, 139, 17, 0, 248, 3,
- 2000, 104, 79, 17, 0, 240, 0
- },
-
- /* Region 124 */
- {
- 0x8012, 0, 127, 240, 240, 16, 0,
- 1914, 240, 64, 160, 240, 208, 2,
- 1200, 240, 73, 163, 240, 244, 0,
- 1900, 240, 64, 160, 240, 148, 2,
- 4151, 240, 73, 163, 240, 244, 0
- },
-
- /* Region 125 */
- {
- 0x8002, 0, 127, 240, 56, 235, 0,
- -5522, 97, 32, 17, 196, 240, 3,
- 0, 84, 75, 17, 180, 248, 3,
- 702, 65, 38, 17, 224, 212, 6,
- -4000, 161, 73, 17, 224, 252, 1
- },
-
- /* Region 126 */
- {
- 0x8015, 0, 127, 240, 248, 37, 0,
- 1050, 243, 0, 0, 252, 224, 7,
- 2000, 49, 68, 0, 224, 236, 3,
- 350, 240, 0, 0, 252, 216, 1,
- 700, 240, 0, 0, 252, 212, 3
- },
-
- /* Region 127 */
- {
- 0x8015, 0, 127, 240, 248, 37, 0,
- 1050, 245, 85, 0, 0, 244, 7,
- -5000, 247, 71, 0, 0, 252, 3,
- 350, 240, 0, 0, 0, 164, 0,
- 700, 32, 0, 0, 0, 252, 2
- },
-
- /* Region 128 */
- {
- 0x0005, 35, 35, 0, 255, 103, 0,
- 3, 215, 68, 65, 0, 204, 2,
- -1700, 249, 95, 177, 0, 252, 2,
- 5374, 236, 144, 204, 0, 176, 3,
- 114, 253, 144, 179, 0, 200, 3
- },
-
- /* Region 129 */
- {
- 0x0005, 36, 36, 0, 255, 103, 0,
- 3, 219, 68, 65, 0, 204, 2,
- -1700, 251, 95, 177, 0, 252, 2,
- 5374, 255, 144, 204, 0, 176, 3,
- 114, 255, 144, 179, 0, 208, 3
- },
-
- /* Region 130 */
- {
- 0x001a, 37, 37, 240, 128, 216, 0,
- 2780, 255, 16, 0, 112, 200, 3,
- 3800, 255, 32, 0, 0, 240, 3,
- 2501, 251, 48, 0, 48, 240, 3,
- 2751, 254, 48, 0, 0, 244, 3
- },
-
- /* Region 131 */
- {
- 0x000d, 38, 38, 0, 255, 190, 0,
- -2000, 239, 48, 128, 0, 236, 3,
- -2400, 254, 92, 128, 0, 252, 2,
- 3374, 255, 33, 192, 240, 244, 2,
- 1000, 255, 49, 176, 240, 204, 2
- },
-
- /* Region 132 */
- {
- 0x001a, 39, 39, 240, 128, 254, -10,
- 5780, 186, 16, 0, 112, 240, 3,
- 3800, 254, 32, 0, 0, 248, 3,
- 5780, 234, 16, 0, 112, 240, 3,
- 4829, 254, 32, 0, 0, 252, 3
- },
-
- /* Region 133 */
- {
- 0x000d, 40, 40, 0, 255, 203, 0,
- 0, 254, 74, 128, 0, 176, 3,
- -600, 252, 73, 128, 0, 252, 3,
- 3368, 251, 80, 192, 0, 244, 3,
- 1200, 254, 64, 176, 0, 208, 3
- },
-
- /* Region 134 */
- {
- 0x000d, 41, 41, 208, 16, 187, -30,
- -600, 247, 128, 0, 0, 204, 1,
- -890, 248, 88, 0, 0, 252, 3,
- 1068, 250, 182, 0, 0, 200, 3,
- -100, 249, 116, 0, 0, 208, 3
- },
-
- /* Region 135 */
- {
- 0x0005, 42, 42, 160, 255, 126, 20,
- 3514, 247, 23, 72, 0, 212, 3,
- 400, 255, 94, 177, 0, 232, 2,
- 2347, 250, 47, 0, 196, 184, 6,
- 4388, 248, 26, 0, 136, 224, 2
- },
-
- /* Region 136 */
- {
- 0x000d, 43, 43, 208, 16, 187, -20,
- -500, 247, 128, 0, 0, 204, 1,
- -690, 249, 88, 0, 0, 252, 3,
- 1068, 254, 182, 0, 0, 200, 3,
- 0, 249, 116, 0, 0, 208, 3
- },
-
- /* Region 137 */
- {
- 0x0005, 44, 44, 160, 255, 126, 20,
- 3514, 151, 20, 72, 0, 244, 3,
- 400, 223, 92, 177, 0, 240, 2,
- 2347, 134, 34, 0, 176, 208, 6,
- 4388, 200, 21, 0, 100, 220, 2
- },
-
- /* Region 138 */
- {
- 0x000d, 45, 45, 208, 16, 187, -10,
- -350, 246, 128, 0, 0, 204, 1,
- -590, 249, 88, 0, 0, 252, 3,
- 2368, 254, 182, 0, 0, 196, 3,
- 500, 249, 116, 0, 0, 208, 3
- },
-
- /* Region 139 */
- {
- 0x0005, 46, 46, 160, 255, 126, 20,
- 3510, 147, 51, 72, 0, 236, 3,
- 400, 219, 90, 177, 0, 240, 2,
- 2347, 134, 66, 0, 176, 224, 6,
- 4388, 200, 84, 0, 100, 212, 2
- },
-
- /* Region 140 */
- {
- 0x000d, 47, 47, 176, 32, 187, 10,
- 0, 247, 128, 0, 0, 204, 1,
- -280, 249, 88, 0, 0, 252, 3,
- 2968, 255, 182, 0, 0, 200, 3,
- 700, 250, 116, 0, 0, 204, 3
- },
-
- /* Region 141 */
- {
- 0x000d, 48, 48, 0, 255, 187, 20,
- 10, 247, 128, 0, 0, 204, 3,
- -130, 249, 88, 0, 0, 252, 3,
- 3068, 255, 182, 0, 0, 188, 3,
- 800, 250, 116, 0, 0, 204, 3
- },
-
- /* Region 142 */
- {
- 0x000d, 49, 49, 160, 255, 215, 20,
- 3986, 18, 6, 8, 0, 252, 2,
- 0, 247, 70, 1, 0, 240, 2,
- 5354, 242, 48, 0, 252, 216, 2,
- 3868, 193, 48, 0, 212, 208, 2
- },
-
- /* Region 143 */
- {
- 0x000d, 50, 50, 0, 255, 201, 30,
- 200, 247, 128, 0, 0, 208, 3,
- 20, 249, 88, 0, 0, 252, 3,
- 3368, 255, 182, 0, 0, 200, 3,
- 1100, 250, 116, 0, 0, 204, 3
- },
-
- /* Region 144 */
- {
- 0x000d, 51, 51, 160, 255, 97, -20,
- 3831, 240, 39, 0, 232, 224, 3,
- 1258, 246, 102, 0, 0, 232, 3,
- 4323, 242, 32, 0, 0, 216, 3,
- 868, 243, 64, 0, 0, 204, 3
- },
-
- /* Region 145 */
- {
- 0x000d, 52, 52, 112, 128, 234, -20,
- 725, 228, 32, 0, 0, 208, 1,
- 400, 248, 86, 0, 0, 248, 3,
- 2003, 53, 32, 0, 0, 236, 3,
- 100, 209, 32, 0, 0, 212, 1
- },
-
- /* Region 146 */
- {
- 0x000d, 53, 53, 160, 255, 97, -20,
- 3831, 240, 39, 0, 232, 224, 3,
- 1258, 246, 102, 0, 0, 232, 3,
- 4323, 242, 32, 0, 0, 224, 3,
- 868, 243, 64, 0, 0, 196, 3
- },
-
- /* Region 147 */
- {
- 0x001d, 54, 54, 240, 240, 242, 10,
- -1, 245, 71, 1, 24, 236, 0,
- 1200, 218, 102, 1, 0, 236, 2,
- 1354, 255, 48, 0, 0, 208, 2,
- 5868, 209, 48, 0, 160, 212, 0
- },
-
- /* Region 148 */
- {
- 0x000d, 55, 55, 48, 32, 234, -10,
- 725, 228, 32, 0, 0, 208, 3,
- 900, 249, 86, 0, 0, 240, 3,
- 2303, 69, 32, 0, 0, 236, 1,
- 400, 177, 32, 0, 0, 212, 3
- },
-
- /* Region 149 */
- {
- 0x000d, 56, 56, 0, 255, 149, 20,
- 414, 254, 123, 48, 0, 204, 3,
- 1986, 252, 118, 48, 0, 244, 3,
- 4383, 242, 67, 48, 0, 200, 3,
- 4205, 243, 81, 48, 0, 204, 3
- },
-
- /* Region 150 */
- {
- 0x000d, 57, 57, 48, 32, 234, -20,
- 526, 210, 32, 0, 0, 200, 3,
- 719, 246, 86, 0, 0, 240, 3,
- 1303, 48, 32, 0, 0, 236, 1,
- 202, 98, 32, 0, 0, 212, 3
- },
-
- /* Region 151 */
- {
- 0x001d, 58, 58, 240, 240, 204, -40,
- 5650, 247, 16, 0, 84, 220, 1,
- 3800, 248, 32, 0, 0, 248, 3,
- 1780, 252, 16, 0, 0, 152, 3,
- 6825, 245, 32, 0, 0, 208, 1
- },
-
- /* Region 152 */
- {
- 0x000d, 59, 59, 144, 0, 108, -20,
- 3531, 240, 103, 0, 232, 220, 3,
- 1058, 246, 102, 0, 0, 232, 3,
- 5331, 242, 64, 0, 0, 220, 3,
- 1968, 243, 64, 0, 0, 204, 1
- },
-
- /* Region 153 */
- {
- 0x000d, 60, 60, 192, 64, 155, 40,
- 700, 214, 84, 0, 0, 208, 1,
- 950, 253, 76, 0, 0, 248, 3,
- 2803, 255, 127, 0, 0, 200, 3,
- 750, 255, 89, 0, 0, 204, 3
- },
-
- /* Region 154 */
- {
- 0x000d, 61, 61, 224, 48, 91, 40,
- 400, 229, 68, 0, 0, 204, 1,
- 700, 251, 76, 0, 0, 248, 3,
- 1803, 255, 95, 0, 0, 196, 3,
- 450, 255, 89, 0, 0, 208, 3
- },
-
- /* Region 155 */
- {
- 0x000d, 62, 62, 240, 32, 191, 25,
- 214, 237, 69, 0, 0, 204, 1,
- 400, 252, 78, 0, 0, 248, 3,
- 2830, 255, 95, 0, 0, 208, 3,
- 2500, 255, 25, 0, 0, 192, 3
- },
-
- /* Region 156 */
- {
- 0x000d, 63, 63, 240, 32, 91, 25,
- 400, 229, 68, 0, 0, 188, 1,
- -100, 250, 76, 0, 0, 248, 3,
- 1803, 254, 95, 0, 0, 200, 3,
- 450, 238, 89, 0, 0, 200, 3
- },
-
- /* Region 157 */
- {
- 0x000d, 64, 64, 240, 16, 91, 20,
- 300, 210, 68, 0, 0, 196, 1,
- -400, 250, 76, 0, 0, 248, 3,
- 1803, 254, 95, 0, 0, 200, 3,
- 550, 238, 89, 0, 0, 200, 3
- },
-
- /* Region 158 */
- {
- 0x001c, 65, 65, 240, 128, 223, 20,
- 1780, 234, 16, 0, 112, 208, 3,
- 800, 251, 32, 0, 0, 248, 3,
- 5501, 231, 48, 0, 48, 200, 3,
- 2751, 232, 48, 0, 0, 220, 3
- },
-
- /* Region 159 */
- {
- 0x001c, 66, 66, 240, 128, 223, 20,
- 1580, 234, 16, 0, 112, 208, 3,
- 600, 250, 32, 0, 0, 248, 3,
- 5201, 231, 48, 0, 48, 200, 3,
- 2510, 232, 48, 0, 0, 220, 3
- },
-
- /* Region 160 */
- {
- 0x000d, 67, 67, 0, 255, 0, -35,
- 1514, 255, 63, 51, 0, 184, 3,
- 4830, 251, 73, 51, 0, 252, 3,
- 4349, 245, 67, 51, 0, 212, 3,
- 5267, 246, 65, 51, 0, 200, 3
- },
-
- /* Region 161 */
- {
- 0x000d, 68, 68, 0, 255, 0, -35,
- 1514, 255, 63, 51, 0, 196, 3,
- 4905, 251, 73, 51, 0, 252, 3,
- 4349, 245, 67, 51, 0, 196, 3,
- 5214, 246, 65, 51, 0, 208, 3
- },
-
- /* Region 162 */
- {
- 0x000a, 69, 69, 240, 240, 243, -35,
- 10000, 160, 68, 0, 0, 200, 3,
- 7000, 156, 140, 0, 0, 228, 3,
- 1586, 176, 16, 0, 0, 228, 7,
- 8000, 140, 80, 0, 0, 236, 3
- },
-
- /* Region 163 */
- {
- 0x001a, 70, 70, 240, 240, 227, -38,
- 500, 240, 52, 0, 0, 220, 1,
- 8000, 188, 124, 0, 0, 228, 3,
- 1586, 240, 16, 0, 0, 224, 7,
- 8000, 203, 80, 0, 0, 228, 3
- },
-
- /* Region 164 */
- {
- 0x0004, 71, 71, 226, 240, 181, 35,
- 7253, 224, 32, 48, 0, 184, 3,
- 3594, 224, 79, 48, 0, 248, 1,
- 220, 97, 19, 48, 156, 152, 3,
- 5243, 172, 16, 48, 92, 204, 1
- },
-
- /* Region 165 */
- {
- 0x0004, 72, 72, 240, 241, 181, 35,
- 6253, 134, 32, 48, 0, 184, 3,
- 3994, 176, 76, 48, 160, 248, 1,
- 22, 183, 19, 48, 156, 172, 3,
- 1243, 160, 16, 48, 240, 188, 3
- },
-
- /* Region 166 */
- {
- 0x001a, 73, 73, 240, 224, 155, 30,
- -2145, 240, 70, 0, 0, 252, 3,
- 600, 109, 111, 0, 0, 240, 3,
- -1800, 240, 71, 0, 0, 248, 3,
- 200, 173, 111, 0, 0, 240, 3
- },
-
- /* Region 167 */
- {
- 0x0012, 74, 74, 240, 224, 119, 30,
- -2545, 240, 70, 0, 252, 252, 3,
- 0, 153, 111, 0, 0, 240, 3,
- -2400, 240, 71, 0, 252, 252, 3,
- 100, 137, 111, 0, 0, 240, 3
- },
-
- /* Region 168 */
- {
- 0x001a, 75, 75, 240, 128, 240, 20,
- 3780, 255, 16, 0, 252, 188, 2,
- 800, 255, 64, 0, 0, 248, 2,
- 2501, 255, 48, 0, 252, 208, 0,
- 751, 255, 48, 0, 0, 236, 2
- },
-
- /* Region 169 */
- {
- 0x000d, 76, 76, 0, 255, 68, 35,
- 1100, 239, 69, 0, 0, 184, 3,
- 2600, 255, 76, 0, 0, 252, 3,
- 5000, 255, 111, 0, 0, 204, 3,
- 3400, 254, 73, 0, 0, 184, 3
- },
-
- /* Region 170 */
- {
- 0x000d, 77, 77, 0, 255, 68, 35,
- 914, 239, 69, 0, 0, 180, 3,
- 1801, 254, 76, 0, 0, 252, 3,
- 4800, 255, 111, 0, 0, 192, 3,
- 3200, 254, 73, 0, 0, 192, 3
- },
-
- /* Region 171 */
- {
- 0x000d, 78, 78, 240, 32, 197, -20,
- 1200, 216, 86, 0, 0, 180, 1,
- 1800, 189, 127, 0, 0, 244, 3,
- 2700, 156, 102, 0, 0, 196, 1,
- 700, 109, 104, 0, 0, 196, 1
- },
-
- /* Region 172 */
- {
- 0x000d, 79, 79, 240, 32, 197, -20,
- 1200, 216, 86, 0, 0, 196, 1,
- 2200, 171, 127, 0, 0, 244, 3,
- 2700, 145, 102, 0, 0, 192, 1,
- 700, 106, 104, 0, 0, 192, 1
- },
-
- /* Region 173 */
- {
- 0x000d, 80, 80, 0, 255, 0, -40,
- 3514, 254, 79, 51, 0, 196, 3,
- 5905, 252, 73, 51, 0, 248, 3,
- 6348, 245, 35, 51, 0, 176, 3,
- 2203, 244, 33, 51, 0, 216, 3
- },
-
- /* Region 174 */
- {
- 0x800d, 81, 81, 0, 255, 0, -40,
- 3514, 255, 79, 51, 0, 192, 3,
- 5905, 246, 73, 51, 0, 252, 3,
- 6348, 241, 35, 51, 0, 180, 3,
- 2203, 242, 33, 51, 0, 212, 3
- }
-};
-
-
-/*----------------------------------------------------------------------------
- * Programs
- *----------------------------------------------------------------------------
-*/
-const S_PROGRAM programs[] =
-{
- { 7864320, 128 } /* program 0 */
-}; /* end Programs */
-
-/*----------------------------------------------------------------------------
- * Banks
- *----------------------------------------------------------------------------
-*/
-const S_BANK banks[] =
-{
- { /* bank 0 */
- 30976,
- {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127
- }
- }
-}; /* end Banks */
-
-/*----------------------------------------------------------------------------
- * S_EAS
- *----------------------------------------------------------------------------
-*/
-const S_EAS easSoundLib =
-{
- 0x01534145,
- 0x00105622,
-
- banks,
- programs,
-
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-
- regions,
-
- 1,
- 1,
-
- 0,
- 0,
- 0,
-
- 175
-}; /* end S_EAS */
-/* end sound library */
+ * + * Source: C:\Sonic\Source\Gen3.3\FMSynth\GMdblib-3.fml + ********************************************************************/ + + +#include "eas_data.h" + +/* begin region data */ +/*lint -e{651} lint complains about unnecessary brackets */ +const S_FM_REGION regions[] = +{ + + /* Region 0 */ + { + 0x8005, 0, 127, 0, 255, 8, 0, + 514, 239, 47, 97, 0, 184, 3, + 1, 244, 89, 114, 0, 248, 2, + 3370, 244, 49, 76, 40, 192, 2, + -1, 227, 97, 51, 160, 212, 2 + }, + + /* Region 1 */ + { + 0x8005, 0, 127, 160, 255, 8, 0, + 2514, 223, 95, 72, 0, 176, 3, + 1, 244, 73, 145, 0, 244, 2, + 3600, 245, 81, 198, 40, 192, 2, + 3, 246, 81, 163, 108, 212, 2 + }, + + /* Region 2 */ + { + 0x8005, 0, 127, 160, 255, 119, 0, + 0, 216, 79, 72, 0, 216, 2, + 2, 244, 73, 145, 0, 244, 2, + 3370, 247, 33, 182, 60, 204, 2, + 1200, 246, 65, 163, 108, 204, 2 + }, + + /* Region 3 */ + { + 0x8005, 0, 127, 160, 255, 1, 0, + 3369, 248, 65, 71, 40, 208, 2, + -3, 245, 88, 113, 0, 244, 2, + 2784, 225, 65, 133, 80, 192, 2, + 3, 241, 81, 113, 80, 216, 2 + }, + + /* Region 4 */ + { + 0x8002, 0, 127, 0, 255, 128, 0, + 0, 229, 155, 183, 0, 228, 2, + -3, 243, 90, 81, 0, 244, 2, + 4800, 248, 109, 180, 36, 192, 2, + 3, 245, 90, 85, 16, 244, 2 + }, + + /* Region 5 */ + { + 0x8002, 0, 127, 9, 96, 192, 0, + 1200, 229, 157, 180, 0, 216, 2, + -3, 244, 90, 81, 0, 244, 2, + 1902, 255, 111, 182, 80, 208, 2, + 3, 246, 92, 83, 0, 244, 2 + }, + + /* Region 6 */ + { + 0x8002, 0, 127, 0, 255, 154, 0, + 3102, 244, 63, 102, 228, 228, 2, + 1200, 247, 93, 97, 0, 236, 2, + 1902, 255, 63, 98, 156, 220, 2, + 1200, 244, 92, 98, 0, 236, 2 + }, + + /* Region 7 */ + { + 0x8005, 0, 127, 0, 255, 202, 0, + 0, 251, 131, 19, 216, 220, 2, + 1201, 247, 62, 113, 0, 240, 2, + 0, 243, 154, 36, 240, 224, 2, + 2784, 250, 61, 36, 240, 208, 2 + }, + + /* Region 8 */ + { + 0x8001, 0, 127, 0, 255, 80, 0, + -1, 213, 191, 183, 0, 204, 2, + 1, 245, 154, 129, 0, 244, 2, + 3831, 252, 159, 100, 0, 200, 2, + 1197, 246, 91, 182, 0, 244, 2 + }, + + /* Region 9 */ + { + 0x8002, 0, 127, 48, 80, 21, 0, + 2982, 255, 43, 96, 0, 196, 3, + 3, 247, 71, 130, 0, 244, 2, + 3358, 253, 40, 98, 144, 208, 2, + -2, 246, 70, 130, 0, 236, 2 + }, + + /* Region 10 */ + { + 0x8002, 0, 127, 48, 80, 26, 0, + 3096, 249, 72, 100, 0, 208, 2, + 2185, 249, 102, 130, 0, 240, 2, + 3386, 247, 66, 100, 144, 212, 2, + -2, 247, 102, 130, 0, 240, 2 + }, + + /* Region 11 */ + { + 0x8002, 0, 127, 92, 67, 21, 0, + 2982, 255, 27, 146, 0, 200, 3, + 3, 246, 68, 146, 0, 240, 2, + 3358, 250, 149, 116, 144, 208, 2, + -3, 245, 68, 146, 0, 240, 0 + }, + + /* Region 12 */ + { + 0x8002, 0, 127, 0, 67, 0, 0, + 1500, 239, 60, 151, 0, 220, 2, + 0, 247, 76, 146, 0, 240, 2, + 2398, 234, 156, 151, 0, 212, 2, + 0, 246, 105, 146, 0, 244, 2 + }, + + /* Region 13 */ + { + 0x8002, 0, 127, 0, 67, 0, 0, + 2500, 255, 60, 151, 0, 220, 2, + 0, 249, 92, 146, 0, 244, 2, + 3369, 250, 156, 151, 0, 196, 2, + 0, 248, 89, 146, 0, 244, 2 + }, + + /* Region 14 */ + { + 0x8005, 0, 127, 160, 255, 0, 0, + 2300, 229, 112, 49, 0, 208, 2, + -3, 247, 67, 50, 0, 248, 2, + 1074, 255, 41, 49, 0, 196, 2, + 686, 240, 97, 18, 0, 196, 2 + }, + + /* Region 15 */ + { + 0x8005, 0, 127, 160, 255, 219, 0, + 3369, 255, 65, 70, 40, 216, 2, + 1, 246, 72, 113, 0, 240, 2, + 1902, 225, 33, 129, 80, 204, 2, + 2400, 225, 97, 113, 80, 200, 2 + }, + + /* Region 16 */ + { + 0x8003, 0, 127, 32, 48, 151, 0, + 1201, 215, 35, 66, 252, 208, 0, + -9581, 254, 63, 177, 240, 240, 3, + 1902, 248, 47, 64, 112, 244, 2, + 0, 247, 35, 66, 208, 212, 2 + }, + + /* Region 17 */ + { + 0x8001, 0, 127, 0, 255, 153, 0, + 1, 252, 31, 3, 244, 196, 2, + -1, 208, 31, 4, 248, 244, 2, + 1205, 209, 31, 4, 248, 236, 2, + 1899, 250, 31, 32, 0, 240, 2 + }, + + /* Region 18 */ + { + 0x8002, 0, 127, 32, 49, 201, 0, + 1, 220, 47, 3, 244, 220, 0, + -10000, 208, 63, 1, 248, 240, 3, + 1586, 255, 47, 3, 188, 216, 2, + -1, 202, 63, 32, 80, 232, 2 + }, + + /* Region 19 */ + { + 0x8001, 0, 127, 0, 143, 29, 0, + -1200, 223, 64, 0, 252, 216, 2, + 1200, 96, 41, 35, 248, 240, 2, + 1200, 143, 41, 64, 252, 224, 2, + 3102, 161, 41, 96, 248, 216, 2 + }, + + /* Region 20 */ + { + 0x8002, 0, 127, 0, 143, 34, 0, + -1200, 133, 79, 1, 252, 212, 2, + 1201, 112, 46, 34, 248, 232, 2, + 0, 116, 79, 65, 252, 200, 2, + 1900, 161, 46, 98, 248, 232, 2 + }, + + /* Region 21 */ + { + 0x8002, 0, 127, 0, 143, 187, 0, + 1202, 80, 74, 1, 252, 216, 2, + 2402, 112, 46, 34, 248, 232, 2, + 0, 99, 78, 97, 184, 216, 2, + 1899, 81, 46, 98, 236, 232, 2 + }, + + /* Region 22 */ + { + 0x8005, 0, 127, 22, 141, 34, 0, + 2787, 176, 79, 4, 252, 208, 2, + 2785, 144, 45, 34, 248, 236, 2, + 3369, 83, 77, 100, 184, 172, 2, + 1902, 102, 45, 100, 172, 212, 0 + }, + + /* Region 23 */ + { + 0x8002, 0, 127, 0, 143, 135, 0, + 1900, 112, 79, 3, 252, 220, 2, + 2400, 128, 45, 34, 248, 232, 2, + 1200, 115, 77, 98, 184, 220, 2, + 1904, 97, 45, 98, 236, 232, 2 + }, + + /* Region 24 */ + { + 0x8005, 0, 127, 0, 255, 157, 0, + 1200, 244, 54, 4, 20, 200, 2, + 0, 245, 92, 130, 0, 244, 2, + 3802, 247, 68, 21, 0, 196, 2, + 1, 245, 43, 114, 0, 204, 2 + }, + + /* Region 25 */ + { + 0x8005, 0, 127, 0, 128, 83, 0, + 0, 244, 51, 4, 200, 204, 0, + 0, 247, 108, 129, 0, 248, 0, + 2786, 243, 31, 70, 200, 220, 0, + 1902, 246, 44, 113, 12, 188, 0 + }, + + /* Region 26 */ + { + 0x8005, 0, 127, 0, 128, 61, 0, + 0, 246, 51, 97, 76, 204, 0, + 0, 244, 60, 97, 0, 240, 0, + 1786, 255, 31, 64, 0, 180, 0, + 1200, 247, 60, 97, 12, 204, 0 + }, + + /* Region 27 */ + { + 0x8005, 0, 127, 0, 128, 153, 0, + -2, 243, 53, 99, 96, 200, 0, + 0, 243, 60, 97, 0, 240, 0, + 3983, 247, 63, 100, 24, 204, 0, + 2, 242, 53, 99, 52, 212, 0 + }, + + /* Region 28 */ + { + 0x8005, 0, 127, 0, 128, 205, 0, + -2, 244, 47, 97, 20, 208, 0, + 0, 252, 75, 193, 0, 248, 0, + 0, 254, 63, 98, 132, 224, 0, + 2786, 251, 63, 98, 52, 192, 0 + }, + + /* Region 29 */ + { + 0x8005, 0, 127, 0, 128, 221, 0, + -1, 208, 191, 99, 220, 224, 0, + 1200, 243, 92, 97, 0, 244, 0, + 3984, 212, 11, 96, 168, 196, 0, + 1, 242, 127, 98, 108, 204, 0 + }, + + /* Region 30 */ + { + 0x8005, 0, 127, 0, 128, 174, 0, + -3, 212, 207, 99, 0, 228, 0, + 1902, 241, 108, 97, 0, 248, 0, + 3805, 212, 59, 98, 0, 220, 0, + 1902, 146, 107, 98, 144, 196, 0 + }, + + /* Region 31 */ + { + 0x8009, 0, 127, 0, 255, 128, 0, + 1206, 239, 43, 69, 0, 216, 2, + 4, 254, 42, 66, 0, 244, 2, + 702, 88, 55, 66, 0, 204, 2, + -4, 71, 55, 66, 0, 240, 2 + }, + + /* Region 32 */ + { + 0x8005, 0, 127, 0, 255, 85, 0, + 500, 239, 95, 82, 0, 184, 3, + 0, 248, 73, 132, 0, 252, 2, + 2786, 203, 59, 130, 0, 176, 2, + 0, 216, 42, 100, 0, 208, 2 + }, + + /* Region 33 */ + { + 0x8005, 0, 127, 0, 128, 73, 0, + 1, 229, 54, 131, 160, 208, 0, + -1, 244, 62, 97, 0, 248, 0, + 3986, 227, 127, 69, 140, 184, 0, + 1201, 249, 92, 114, 0, 204, 0 + }, + + /* Region 34 */ + { + 0x8005, 0, 127, 0, 128, 73, 0, + 1, 225, 54, 100, 200, 212, 0, + -1, 244, 94, 97, 0, 248, 0, + 3986, 249, 127, 88, 112, 188, 0, + 1201, 249, 92, 85, 52, 208, 0 + }, + + /* Region 35 */ + { + 0x8005, 0, 127, 0, 128, 188, 0, + -3, 198, 92, 179, 28, 212, 0, + 0, 243, 90, 145, 0, 248, 0, + 1901, 215, 95, 69, 28, 196, 0, + 3, 84, 108, 196, 32, 208, 0 + }, + + /* Region 36 */ + { + 0x8005, 0, 127, 0, 136, 6, 0, + 0, 226, 99, 36, 224, 216, 0, + 1902, 248, 78, 33, 0, 252, 0, + 3369, 239, 250, 33, 0, 204, 0, + 0, 230, 253, 33, 0, 208, 0 + }, + + /* Region 37 */ + { + 0x8005, 0, 127, 0, 136, 195, 0, + 0, 245, 99, 36, 152, 208, 0, + 1200, 248, 78, 33, 0, 252, 0, + 3369, 246, 250, 33, 0, 216, 0, + 0, 246, 61, 33, 0, 180, 0 + }, + + /* Region 38 */ + { + 0x8002, 0, 127, 0, 133, 221, 0, + 1, 244, 67, 35, 80, 220, 0, + 3, 246, 94, 33, 0, 244, 0, + -1, 245, 70, 35, 80, 236, 2, + -3, 246, 63, 33, 0, 236, 2 + }, + + /* Region 39 */ + { + 0x8002, 0, 127, 0, 133, 220, 0, + 0, 114, 51, 34, 132, 208, 0, + 3, 214, 62, 33, 0, 248, 0, + 0, 85, 54, 34, 44, 224, 2, + -3, 214, 63, 33, 0, 236, 2 + }, + + /* Region 40 */ + { + 0x8005, 0, 127, 48, 142, 187, 0, + -1, 33, 22, 33, 200, 208, 0, + 0, 81, 105, 33, 220, 240, 0, + 2786, 245, 19, 50, 208, 192, 0, + 1, 245, 21, 82, 200, 220, 0 + }, + + /* Region 41 */ + { + 0x8005, 0, 127, 48, 126, 103, 0, + -1, 193, 22, 33, 228, 212, 0, + 0, 81, 105, 33, 220, 244, 0, + 0, 245, 19, 50, 216, 228, 0, + 1200, 245, 19, 82, 200, 188, 0 + }, + + /* Region 42 */ + { + 0x8005, 0, 127, 16, 126, 202, 0, + -1, 49, 24, 41, 200, 212, 0, + 0, 81, 71, 49, 220, 244, 0, + 3371, 243, 19, 36, 232, 192, 0, + 1, 242, 24, 36, 220, 212, 0 + }, + + /* Region 43 */ + { + 0x8005, 0, 127, 16, 124, 205, 0, + 0, 129, 24, 49, 208, 200, 0, + 0, 67, 102, 81, 224, 244, 0, + 3804, 246, 23, 36, 160, 196, 0, + 1200, 244, 24, 35, 208, 200, 0 + }, + + /* Region 44 */ + { + 0x8005, 0, 127, 48, 144, 208, 0, + -3, 209, 22, 33, 200, 204, 2, + 0, 81, 89, 33, 220, 240, 2, + -5000, 208, 6, 33, 244, 188, 3, + 3, 97, 89, 33, 224, 200, 0 + }, + + /* Region 45 */ + { + 0x8005, 0, 127, 0, 255, 186, 0, + 500, 223, 95, 0, 0, 192, 3, + 0, 247, 89, 100, 0, 248, 2, + 3369, 255, 59, 168, 0, 212, 2, + 0, 216, 42, 97, 0, 212, 2 + }, + + /* Region 46 */ + { + 0x8002, 0, 127, 0, 255, 221, 0, + 1206, 235, 70, 69, 0, 216, 2, + 4, 248, 84, 66, 0, 244, 2, + 1902, 247, 52, 137, 80, 216, 2, + -4, 245, 84, 131, 0, 240, 2 + }, + + /* Region 47 */ + { + 0x8005, 0, 127, 0, 255, 105, 0, + 387, 231, 115, 34, 4, 216, 2, + 0, 248, 37, 65, 0, 252, 2, + 3308, 248, 117, 34, 8, 200, 2, + 1900, 213, 82, 50, 0, 192, 2 + }, + + /* Region 48 */ + { + 0x8002, 0, 127, 32, 160, 221, 0, + -7, 209, 22, 33, 200, 204, 2, + -7, 81, 73, 33, 220, 244, 0, + 7, 209, 22, 33, 200, 208, 0, + 7, 97, 73, 33, 224, 244, 2 + }, + + /* Region 49 */ + { + 0x8002, 0, 127, 64, 128, 189, 0, + -2, 209, 54, 32, 224, 216, 2, + -7726, 97, 105, 33, 220, 240, 3, + 1902, 209, 54, 34, 216, 208, 0, + 2, 81, 105, 33, 224, 236, 0 + }, + + /* Region 50 */ + { + 0x8002, 0, 127, 80, 144, 206, 0, + -3, 179, 38, 33, 160, 220, 2, + -7726, 81, 69, 34, 220, 244, 3, + 3, 193, 38, 33, 240, 212, 0, + -8000, 65, 69, 34, 224, 236, 3 + }, + + /* Region 51 */ + { + 0x8005, 0, 127, 96, 128, 204, 0, + -3, 97, 38, 33, 180, 216, 0, + 0, 81, 69, 34, 220, 240, 2, + 3369, 145, 38, 33, 240, 196, 2, + -13190, 65, 69, 34, 240, 200, 3 + }, + + /* Region 52 */ + { + 0x8002, 0, 127, 64, 128, 108, 0, + -3, 193, 37, 35, 236, 208, 0, + 2394, 97, 90, 36, 224, 232, 2, + 3, 65, 40, 35, 236, 204, 2, + 1203, 97, 89, 33, 224, 240, 0 + }, + + /* Region 53 */ + { + 0x8005, 0, 127, 128, 128, 122, 0, + 0, 193, 21, 34, 236, 188, 0, + 3, 97, 74, 36, 224, 248, 2, + 1906, 251, 24, 32, 96, 192, 3, + 1200, 97, 73, 32, 224, 184, 0 + }, + + /* Region 54 */ + { + 0x8002, 0, 127, 64, 133, 135, 0, + 0, 194, 25, 35, 120, 200, 2, + 0, 97, 75, 36, 224, 240, 0, + 2906, 254, 28, 48, 0, 184, 3, + 0, 216, 75, 80, 204, 240, 2 + }, + + /* Region 55 */ + { + 0x8009, 0, 127, 208, 64, 255, 0, + 475, 249, 16, 32, 252, 240, 2, + 702, 248, 71, 32, 0, 244, 2, + 1136, 232, 27, 32, 216, 248, 0, + 0, 249, 23, 48, 0, 248, 2 + }, + + /* Region 56 */ + { + 0x8005, 0, 127, 0, 132, 233, 0, + 0, 195, 95, 64, 240, 208, 0, + 0, 225, 94, 64, 248, 240, 0, + 0, 254, 127, 0, 4, 196, 4, + 1902, 228, 95, 1, 248, 200, 0 + }, + + /* Region 57 */ + { + 0x8005, 0, 127, 16, 140, 238, 0, + 0, 163, 90, 67, 228, 208, 0, + 0, 209, 77, 65, 248, 240, 0, + 1969, 173, 58, 65, 0, 176, 0, + 0, 210, 61, 52, 204, 220, 0 + }, + + /* Region 58 */ + { + 0x8005, 0, 127, 16, 140, 222, 0, + 0, 119, 74, 67, 160, 212, 0, + 0, 146, 61, 65, 248, 244, 0, + 1900, 137, 58, 65, 100, 196, 0, + 0, 119, 61, 52, 120, 200, 0 + }, + + /* Region 59 */ + { + 0x8005, 0, 127, 16, 135, 219, 0, + 0, 176, 79, 69, 240, 216, 0, + 0, 193, 79, 64, 248, 236, 0, + 0, 178, 123, 54, 92, 228, 0, + 3369, 212, 95, 38, 144, 212, 0 + }, + + /* Region 60 */ + { + 0x8002, 0, 127, 0, 119, 203, 0, + 2, 65, 77, 66, 228, 204, 0, + 2, 161, 74, 64, 240, 240, 0, + -2, 85, 60, 66, 180, 216, 2, + -2, 162, 74, 64, 220, 240, 2 + }, + + /* Region 61 */ + { + 0x8002, 0, 127, 16, 154, 237, 0, + 0, 179, 42, 64, 216, 208, 0, + 0, 209, 61, 64, 248, 244, 0, + -1200, 226, 55, 65, 244, 220, 2, + 1902, 162, 62, 52, 204, 236, 2 + }, + + /* Region 62 */ + { + 0x8002, 0, 127, 48, 119, 221, 0, + 2, 119, 79, 64, 208, 212, 0, + 2, 209, 110, 64, 248, 236, 0, + -2, 84, 79, 64, 136, 212, 2, + -2, 209, 110, 64, 240, 240, 2 + }, + + /* Region 63 */ + { + 0x8002, 0, 127, 32, 135, 221, 0, + 2, 165, 79, 64, 152, 216, 0, + 2, 225, 110, 64, 248, 236, 0, + -2, 132, 79, 64, 72, 224, 2, + -2, 241, 110, 64, 252, 236, 2 + }, + + /* Region 64 */ + { + 0x8005, 0, 127, 17, 127, 190, 0, + 0, 209, 60, 67, 244, 208, 0, + 1200, 145, 94, 65, 248, 244, 2, + 3369, 197, 47, 4, 128, 192, 0, + 1902, 167, 94, 6, 200, 200, 0 + }, + + /* Region 65 */ + { + 0x8005, 0, 127, 17, 143, 190, 0, + 0, 209, 60, 67, 244, 216, 0, + 1902, 145, 62, 65, 248, 240, 2, + 3369, 197, 47, 4, 128, 196, 0, + 2400, 167, 94, 6, 200, 212, 2 + }, + + /* Region 66 */ + { + 0x8005, 0, 127, 17, 143, 190, 0, + 0, 209, 60, 67, 244, 208, 0, + 1902, 145, 62, 65, 248, 240, 2, + 3369, 197, 47, 4, 128, 192, 0, + 1902, 167, 94, 6, 200, 216, 2 + }, + + /* Region 67 */ + { + 0x8005, 0, 127, 17, 125, 190, 0, + 0, 114, 109, 67, 244, 224, 0, + 1902, 166, 93, 97, 200, 240, 0, + 2786, 165, 95, 52, 160, 200, 0, + 2400, 173, 78, 54, 240, 212, 2 + }, + + /* Region 68 */ + { + 0x8002, 0, 127, 16, 140, 205, 0, + 0, 211, 55, 66, 244, 208, 0, + 1902, 193, 93, 65, 248, 240, 0, + 0, 204, 47, 4, 244, 216, 0, + 3600, 183, 95, 6, 160, 232, 0 + }, + + /* Region 69 */ + { + 0x8002, 0, 127, 16, 126, 222, 0, + 0, 243, 36, 66, 172, 200, 0, + 1200, 193, 110, 67, 248, 244, 0, + 0, 215, 33, 2, 232, 212, 0, + 3369, 178, 63, 6, 184, 240, 0 + }, + + /* Region 70 */ + { + 0x8002, 0, 127, 16, 140, 221, 0, + 1200, 213, 61, 66, 136, 200, 0, + 1902, 193, 93, 68, 248, 240, 0, + 0, 197, 47, 2, 228, 216, 0, + 3369, 183, 95, 2, 160, 236, 0 + }, + + /* Region 71 */ + { + 0x8002, 0, 127, 16, 124, 201, 0, + 1200, 195, 55, 68, 240, 208, 0, + 0, 209, 76, 65, 248, 236, 0, + 1902, 147, 47, 19, 208, 212, 0, + 0, 183, 79, 22, 156, 228, 0 + }, + + /* Region 72 */ + { + 0x8005, 0, 127, 32, 110, 234, 0, + 500, 237, 60, 68, 0, 192, 1, + 1, 161, 93, 65, 248, 240, 2, + 3365, 154, 47, 16, 48, 180, 6, + 1200, 165, 92, 52, 160, 212, 2 + }, + + /* Region 73 */ + { + 0x8005, 0, 127, 32, 142, 200, 0, + 0, 193, 60, 68, 248, 200, 0, + 1, 129, 61, 65, 248, 240, 2, + 3365, 154, 47, 16, 68, 184, 6, + 1200, 169, 92, 52, 160, 204, 2 + }, + + /* Region 74 */ + { + 0x8003, 0, 127, 32, 135, 36, 0, + 1199, 165, 79, 66, 152, 192, 2, + -3, 145, 110, 64, 248, 240, 2, + 0, 199, 79, 66, 44, 236, 2, + 2986, 136, 110, 67, 100, 196, 2 + }, + + /* Region 75 */ + { + 0x8005, 0, 127, 32, 190, 71, 0, + 868, 202, 140, 16, 24, 188, 2, + 0, 176, 77, 65, 248, 240, 2, + 3750, 169, 127, 16, 36, 228, 6, + 2400, 195, 60, 17, 232, 172, 2 + }, + + /* Region 76 */ + { + 0x8005, 0, 127, 224, 16, 123, 0, + 275, 202, 14, 2, 44, 196, 2, + 0, 165, 89, 65, 56, 244, 2, + 0, 255, 12, 2, 64, 216, 6, + 963, 169, 14, 4, 40, 196, 2 + }, + + /* Region 77 */ + { + 0x8012, 0, 127, 192, 128, 100, 0, + 1500, 202, 79, 68, 76, 204, 2, + -2, 97, 26, 64, 248, 232, 2, + 1588, 202, 223, 69, 4, 220, 0, + 3, 188, 121, 67, 48, 252, 2 + }, + + /* Region 78 */ + { + 0x8002, 0, 127, 112, 140, 205, 0, + 0, 68, 47, 66, 60, 176, 2, + -2, 113, 94, 64, 248, 236, 0, + 5000, 121, 47, 64, 32, 168, 7, + 3, 136, 94, 64, 0, 236, 0 + }, + + /* Region 79 */ + { + 0x8003, 0, 127, 32, 135, 33, 0, + 1199, 197, 79, 66, 152, 184, 2, + 0, 161, 110, 64, 248, 240, 2, + 0, 199, 79, 66, 44, 236, 2, + 2400, 255, 110, 65, 36, 208, 6 + }, + + /* Region 80 */ + { + 0x8002, 0, 127, 0, 192, 170, 0, + 1199, 192, 77, 33, 200, 212, 0, + 0, 209, 107, 33, 232, 240, 0, + 1201, 80, 77, 33, 200, 212, 0, + 0, 241, 107, 33, 232, 240, 0 + }, + + /* Region 81 */ + { + 0x8002, 0, 127, 0, 192, 221, 0, + -1, 192, 45, 33, 200, 212, 0, + -1, 209, 107, 33, 232, 244, 0, + 1, 80, 45, 33, 200, 212, 0, + 1, 241, 107, 33, 232, 244, 0 + }, + + /* Region 82 */ + { + 0x8005, 0, 127, 0, 112, 255, 0, + 4750, 221, 45, 34, 48, 172, 4, + -10000, 161, 107, 33, 200, 244, 3, + 2204, 137, 45, 37, 64, 184, 0, + -2, 211, 107, 33, 160, 208, 0 + }, + + /* Region 83 */ + { + 0x8005, 0, 127, 16, 127, 238, 0, + 2, 248, 45, 32, 204, 208, 0, + -9500, 241, 107, 33, 200, 240, 3, + 3369, 186, 45, 38, 24, 208, 0, + -2, 211, 107, 32, 220, 212, 0 + }, + + /* Region 84 */ + { + 0x8005, 0, 127, 0, 128, 221, 0, + -1, 192, 191, 99, 220, 216, 0, + 1200, 243, 92, 97, 0, 244, 0, + 3984, 200, 11, 96, 168, 192, 0, + 1, 194, 127, 98, 108, 200, 0 + }, + + /* Region 85 */ + { + 0x8002, 0, 127, 128, 128, 111, 0, + 1, 194, 25, 35, 120, 204, 2, + -9750, 193, 107, 36, 224, 244, 3, + 3906, 255, 28, 50, 12, 188, 3, + -1, 216, 107, 80, 204, 240, 2 + }, + + /* Region 86 */ + { + 0x8002, 0, 127, 32, 134, 222, 0, + 0, 195, 52, 33, 200, 208, 0, + 0, 177, 90, 33, 232, 240, 2, + 702, 195, 52, 33, 200, 208, 2, + 702, 177, 90, 34, 232, 240, 2 + }, + + /* Region 87 */ + { + 0x8002, 0, 127, 32, 134, 205, 0, + 0, 198, 75, 36, 120, 220, 2, + 0, 225, 78, 52, 40, 244, 2, + 0, 246, 47, 32, 220, 208, 2, + 1902, 241, 124, 32, 240, 236, 2 + }, + + /* Region 88 */ + { + 0x8003, 0, 127, 32, 120, 14, 0, + 3600, 244, 67, 34, 88, 208, 0, + 3, 194, 84, 33, 84, 240, 2, + -3, 194, 84, 33, 172, 236, 2, + 902, 254, 114, 34, 0, 224, 3 + }, + + /* Region 89 */ + { + 0x8002, 0, 127, 64, 169, 170, 0, + -3, 83, 69, 34, 184, 212, 0, + -7500, 50, 69, 33, 176, 244, 3, + 3, 81, 69, 34, 212, 212, 2, + -8500, 66, 69, 33, 176, 244, 3 + }, + + /* Region 90 */ + { + 0x8002, 0, 127, 64, 120, 221, 0, + -2, 82, 69, 34, 244, 216, 0, + 0, 145, 102, 33, 228, 240, 0, + 2, 81, 69, 34, 244, 208, 2, + 0, 145, 102, 33, 224, 240, 2 + }, + + /* Region 91 */ + { + 0x8003, 0, 127, 32, 138, 14, 0, + 2400, 148, 67, 34, 176, 200, 0, + 3, 194, 85, 33, 220, 236, 2, + -3, 194, 69, 33, 220, 236, 2, + 1905, 254, 114, 34, 48, 224, 2 + }, + + /* Region 92 */ + { + 0x8002, 0, 127, 82, 67, 71, 0, + 2982, 228, 22, 146, 88, 192, 3, + 3, 102, 84, 146, 196, 240, 2, + 3358, 50, 149, 116, 144, 208, 2, + -3, 85, 84, 146, 120, 240, 0 + }, + + /* Region 93 */ + { + 0x8005, 0, 127, 48, 126, 219, 0, + -3, 49, 19, 33, 120, 200, 0, + 0, 81, 70, 33, 220, 240, 0, + 3804, 242, 18, 50, 200, 200, 0, + 1203, 82, 19, 82, 200, 176, 0 + }, + + /* Region 94 */ + { + 0x8003, 0, 127, 32, 138, 13, 0, + 2786, 116, 67, 34, 204, 184, 0, + 1902, 114, 69, 33, 192, 232, 2, + -3, 178, 69, 33, 188, 232, 2, + 3804, 254, 82, 34, 164, 228, 2 + }, + + /* Region 95 */ + { + 0x8002, 0, 127, 48, 135, 238, 0, + -2, 34, 85, 34, 184, 224, 0, + 1, 113, 70, 33, 228, 236, 0, + 2, 19, 85, 34, 156, 224, 2, + -1, 129, 70, 33, 224, 236, 2 + }, + + /* Region 96 */ + { + 0x8012, 0, 127, 240, 112, 221, 0, + 3369, 213, 69, 32, 0, 204, 0, + 0, 193, 70, 33, 112, 232, 2, + 0, 145, 69, 34, 244, 208, 2, + -9000, 145, 70, 33, 224, 236, 3 + }, + + /* Region 97 */ + { + 0x8002, 0, 127, 96, 122, 168, 0, + -1, 99, 51, 33, 200, 208, 0, + -8500, 81, 83, 33, 232, 240, 3, + 702, 99, 52, 33, 200, 208, 2, + -9500, 65, 83, 34, 224, 240, 3 + }, + + /* Region 98 */ + { + 0x8002, 0, 127, 0, 67, 0, 0, + 1500, 217, 55, 151, 20, 224, 2, + 3, 231, 70, 146, 88, 220, 2, + 2369, 115, 148, 151, 32, 196, 2, + -3, 118, 36, 146, 64, 244, 2 + }, + + /* Region 99 */ + { + 0x8002, 0, 127, 64, 169, 204, 0, + -3, 228, 69, 34, 148, 220, 0, + -7448, 243, 69, 33, 200, 240, 3, + 3, 81, 68, 34, 212, 212, 2, + -8526, 65, 68, 33, 196, 240, 3 + }, + + /* Region 100 */ + { + 0x8002, 0, 127, 64, 119, 187, 0, + 2786, 228, 22, 146, 176, 192, 0, + 3, 102, 68, 146, 196, 236, 2, + 3369, 178, 149, 116, 176, 208, 2, + -3, 231, 68, 146, 120, 240, 0 + }, + + /* Region 101 */ + { + 0x8002, 0, 127, 240, 144, 239, 0, + -2, 49, 69, 34, 236, 208, 2, + -9000, 113, 102, 33, 228, 236, 3, + 2400, 149, 69, 34, 12, 216, 1, + 0, 145, 102, 33, 224, 236, 2 + }, + + /* Region 102 */ + { + 0x8012, 0, 127, 241, 176, 6, 0, + 1200, 247, 49, 64, 252, 204, 0, + 3804, 246, 101, 32, 0, 232, 2, + 1902, 247, 32, 32, 112, 188, 2, + 0, 228, 84, 32, 0, 240, 2 + }, + + /* Region 103 */ + { + 0x8005, 0, 127, 64, 101, 221, 0, + 1, 194, 68, 97, 196, 200, 2, + -10001, 247, 100, 114, 176, 240, 3, + 3370, 213, 33, 70, 52, 200, 2, + -1, 178, 68, 49, 208, 212, 0 + }, + + /* Region 104 */ + { + 0x8002, 0, 127, 0, 255, 203, 0, + -3, 245, 82, 99, 200, 232, 2, + 2787, 244, 84, 96, 0, 236, 2, + 1198, 133, 81, 100, 196, 220, 2, + 1902, 147, 67, 80, 0, 232, 2 + }, + + /* Region 105 */ + { + 0x8005, 0, 127, 0, 255, 140, 0, + 500, 255, 137, 179, 0, 200, 3, + 1902, 248, 90, 160, 0, 244, 2, + 3804, 245, 57, 35, 164, 204, 2, + 0, 245, 38, 51, 196, 208, 2 + }, + + /* Region 106 */ + { + 0x8005, 0, 127, 0, 255, 72, 0, + 1000, 238, 57, 65, 0, 188, 3, + 1902, 247, 103, 112, 0, 244, 2, + 2786, 250, 36, 81, 68, 212, 2, + 0, 249, 50, 49, 172, 204, 2 + }, + + /* Region 107 */ + { + 0x8005, 0, 127, 16, 119, 72, 0, + 1500, 255, 89, 65, 0, 196, 3, + 2790, 246, 39, 112, 0, 240, 0, + 1905, 246, 36, 81, 168, 208, 0, + 0, 249, 114, 49, 172, 212, 0 + }, + + /* Region 108 */ + { + 0x8005, 0, 127, 0, 255, 237, 0, + 1902, 254, 89, 65, 0, 212, 2, + 0, 248, 87, 112, 0, 240, 2, + 3369, 231, 62, 81, 0, 208, 2, + 3, 245, 118, 49, 96, 196, 2 + }, + + /* Region 109 */ + { + 0x8002, 0, 127, 16, 188, 205, 0, + -2, 179, 47, 50, 244, 224, 2, + 1900, 145, 94, 49, 248, 232, 2, + 3, 210, 46, 2, 244, 208, 2, + 2789, 133, 93, 4, 180, 244, 2 + }, + + /* Region 110 */ + { + 0x8005, 0, 127, 48, 135, 220, 0, + 1901, 162, 25, 35, 144, 208, 0, + 0, 113, 105, 65, 220, 240, 0, + 3369, 233, 88, 51, 120, 212, 0, + 0, 229, 24, 84, 200, 208, 0 + }, + + /* Region 111 */ + { + 0x8002, 0, 127, 112, 32, 190, 0, + 0, 53, 79, 66, 152, 212, 2, + 1200, 53, 75, 64, 136, 244, 2, + 500, 149, 60, 66, 16, 208, 2, + 1902, 200, 78, 64, 0, 248, 0 + }, + + /* Region 112 */ + { + 0x8005, 0, 127, 0, 144, 130, 0, + 2514, 255, 68, 53, 0, 204, 2, + 2400, 247, 133, 48, 0, 240, 2, + 4151, 243, 67, 50, 0, 212, 2, + 3369, 243, 66, 56, 0, 204, 2 + }, + + /* Region 113 */ + { + 0x8005, 0, 127, 0, 255, 0, 0, + 514, 253, 79, 51, 0, 196, 3, + 1905, 252, 89, 51, 0, 244, 2, + 4349, 245, 35, 51, 0, 208, 2, + 1205, 247, 34, 51, 0, 208, 2 + }, + + /* Region 114 */ + { + 0x8005, 0, 127, 0, 255, 0, 0, + 514, 221, 69, 35, 0, 204, 3, + 0, 250, 86, 115, 0, 252, 2, + 1884, 244, 116, 51, 0, 200, 2, + 1208, 210, 35, 51, 0, 208, 2 + }, + + /* Region 115 */ + { + 0x8005, 0, 127, 0, 255, 16, 0, + 514, 222, 85, 163, 0, 192, 3, + 0, 254, 108, 163, 0, 252, 2, + 3800, 255, 143, 160, 0, 176, 2, + 1200, 250, 105, 163, 0, 212, 2 + }, + + /* Region 116 */ + { + 0x8005, 0, 127, 0, 255, 16, 0, + 1514, 249, 101, 163, 0, 204, 3, + -1200, 249, 87, 160, 0, 252, 2, + 0, 235, 143, 160, 0, 204, 2, + 1200, 234, 73, 163, 0, 204, 2 + }, + + /* Region 117 */ + { + 0x8005, 0, 127, 0, 255, 16, 0, + 500, 239, 101, 160, 0, 204, 3, + -1195, 248, 104, 160, 0, 252, 2, + 1898, 252, 72, 163, 0, 216, 2, + 1239, 248, 87, 163, 0, 196, 2 + }, + + /* Region 118 */ + { + 0x8005, 0, 127, 0, 255, 255, 0, + 500, 255, 98, 160, 0, 196, 3, + -1, 249, 105, 160, 0, 252, 2, + 1907, 250, 71, 160, 0, 252, 2, + 1182, 249, 87, 161, 0, 192, 2 + }, + + /* Region 119 */ + { + 0x8005, 0, 127, 0, 0, 100, 0, + 600, 32, 15, 0, 252, 224, 6, + 0, 47, 111, 65, 0, 244, 2, + 1826, 16, 47, 0, 252, 216, 2, + 3551, 240, 47, 0, 252, 212, 2 + }, + + /* Region 120 */ + { + 0x8014, 0, 127, 240, 128, 235, 0, + 1228, 161, 47, 17, 196, 200, 3, + 3000, 123, 75, 17, 0, 240, 2, + 7022, 72, 43, 17, 0, 216, 0, + 4000, 150, 79, 17, 48, 196, 3 + }, + + /* Region 121 */ + { + 0x8005, 0, 127, 224, 16, 86, 0, + 275, 251, 6, 0, 36, 200, 2, + 0, 101, 104, 65, 56, 240, 2, + 0, 240, 6, 0, 252, 208, 6, + 1000, 195, 8, 0, 248, 200, 2 + }, + + /* Region 122 */ + { + 0x8002, 0, 127, 0, 0, 185, 0, + 600, 35, 66, 17, 72, 224, 4, + -13000, 81, 67, 17, 228, 244, 2, + 702, 97, 38, 17, 212, 196, 6, + -14000, 81, 65, 17, 224, 244, 3 + }, + + /* Region 123 */ + { + 0x8012, 0, 127, 240, 112, 237, 0, + -6528, 153, 127, 16, 0, 252, 3, + 1200, 105, 109, 16, 0, 216, 2, + -6022, 179, 139, 17, 0, 248, 3, + 2000, 104, 79, 17, 0, 240, 0 + }, + + /* Region 124 */ + { + 0x8012, 0, 127, 240, 240, 16, 0, + 1914, 240, 64, 160, 240, 208, 2, + 1200, 240, 73, 163, 240, 244, 0, + 1900, 240, 64, 160, 240, 148, 2, + 4151, 240, 73, 163, 240, 244, 0 + }, + + /* Region 125 */ + { + 0x8002, 0, 127, 240, 56, 235, 0, + -5522, 97, 32, 17, 196, 240, 3, + 0, 84, 75, 17, 180, 248, 3, + 702, 65, 38, 17, 224, 212, 6, + -4000, 161, 73, 17, 224, 252, 1 + }, + + /* Region 126 */ + { + 0x8015, 0, 127, 240, 248, 37, 0, + 1050, 243, 0, 0, 252, 224, 7, + 2000, 49, 68, 0, 224, 236, 3, + 350, 240, 0, 0, 252, 216, 1, + 700, 240, 0, 0, 252, 212, 3 + }, + + /* Region 127 */ + { + 0x8015, 0, 127, 240, 248, 37, 0, + 1050, 245, 85, 0, 0, 244, 7, + -5000, 247, 71, 0, 0, 252, 3, + 350, 240, 0, 0, 0, 164, 0, + 700, 32, 0, 0, 0, 252, 2 + }, + + /* Region 128 */ + { + 0x0005, 35, 35, 0, 255, 103, 0, + 3, 215, 68, 65, 0, 204, 2, + -1700, 249, 95, 177, 0, 252, 2, + 5374, 236, 144, 204, 0, 176, 3, + 114, 253, 144, 179, 0, 200, 3 + }, + + /* Region 129 */ + { + 0x0005, 36, 36, 0, 255, 103, 0, + 3, 219, 68, 65, 0, 204, 2, + -1700, 251, 95, 177, 0, 252, 2, + 5374, 255, 144, 204, 0, 176, 3, + 114, 255, 144, 179, 0, 208, 3 + }, + + /* Region 130 */ + { + 0x001a, 37, 37, 240, 128, 216, 0, + 2780, 255, 16, 0, 112, 200, 3, + 3800, 255, 32, 0, 0, 240, 3, + 2501, 251, 48, 0, 48, 240, 3, + 2751, 254, 48, 0, 0, 244, 3 + }, + + /* Region 131 */ + { + 0x000d, 38, 38, 0, 255, 190, 0, + -2000, 239, 48, 128, 0, 236, 3, + -2400, 254, 92, 128, 0, 252, 2, + 3374, 255, 33, 192, 240, 244, 2, + 1000, 255, 49, 176, 240, 204, 2 + }, + + /* Region 132 */ + { + 0x001a, 39, 39, 240, 128, 254, -10, + 5780, 186, 16, 0, 112, 240, 3, + 3800, 254, 32, 0, 0, 248, 3, + 5780, 234, 16, 0, 112, 240, 3, + 4829, 254, 32, 0, 0, 252, 3 + }, + + /* Region 133 */ + { + 0x000d, 40, 40, 0, 255, 203, 0, + 0, 254, 74, 128, 0, 176, 3, + -600, 252, 73, 128, 0, 252, 3, + 3368, 251, 80, 192, 0, 244, 3, + 1200, 254, 64, 176, 0, 208, 3 + }, + + /* Region 134 */ + { + 0x000d, 41, 41, 208, 16, 187, -30, + -600, 247, 128, 0, 0, 204, 1, + -890, 248, 88, 0, 0, 252, 3, + 1068, 250, 182, 0, 0, 200, 3, + -100, 249, 116, 0, 0, 208, 3 + }, + + /* Region 135 */ + { + 0x0005, 42, 42, 160, 255, 126, 20, + 3514, 247, 23, 72, 0, 212, 3, + 400, 255, 94, 177, 0, 232, 2, + 2347, 250, 47, 0, 196, 184, 6, + 4388, 248, 26, 0, 136, 224, 2 + }, + + /* Region 136 */ + { + 0x000d, 43, 43, 208, 16, 187, -20, + -500, 247, 128, 0, 0, 204, 1, + -690, 249, 88, 0, 0, 252, 3, + 1068, 254, 182, 0, 0, 200, 3, + 0, 249, 116, 0, 0, 208, 3 + }, + + /* Region 137 */ + { + 0x0005, 44, 44, 160, 255, 126, 20, + 3514, 151, 20, 72, 0, 244, 3, + 400, 223, 92, 177, 0, 240, 2, + 2347, 134, 34, 0, 176, 208, 6, + 4388, 200, 21, 0, 100, 220, 2 + }, + + /* Region 138 */ + { + 0x000d, 45, 45, 208, 16, 187, -10, + -350, 246, 128, 0, 0, 204, 1, + -590, 249, 88, 0, 0, 252, 3, + 2368, 254, 182, 0, 0, 196, 3, + 500, 249, 116, 0, 0, 208, 3 + }, + + /* Region 139 */ + { + 0x0005, 46, 46, 160, 255, 126, 20, + 3510, 147, 51, 72, 0, 236, 3, + 400, 219, 90, 177, 0, 240, 2, + 2347, 134, 66, 0, 176, 224, 6, + 4388, 200, 84, 0, 100, 212, 2 + }, + + /* Region 140 */ + { + 0x000d, 47, 47, 176, 32, 187, 10, + 0, 247, 128, 0, 0, 204, 1, + -280, 249, 88, 0, 0, 252, 3, + 2968, 255, 182, 0, 0, 200, 3, + 700, 250, 116, 0, 0, 204, 3 + }, + + /* Region 141 */ + { + 0x000d, 48, 48, 0, 255, 187, 20, + 10, 247, 128, 0, 0, 204, 3, + -130, 249, 88, 0, 0, 252, 3, + 3068, 255, 182, 0, 0, 188, 3, + 800, 250, 116, 0, 0, 204, 3 + }, + + /* Region 142 */ + { + 0x000d, 49, 49, 160, 255, 215, 20, + 3986, 18, 6, 8, 0, 252, 2, + 0, 247, 70, 1, 0, 240, 2, + 5354, 242, 48, 0, 252, 216, 2, + 3868, 193, 48, 0, 212, 208, 2 + }, + + /* Region 143 */ + { + 0x000d, 50, 50, 0, 255, 201, 30, + 200, 247, 128, 0, 0, 208, 3, + 20, 249, 88, 0, 0, 252, 3, + 3368, 255, 182, 0, 0, 200, 3, + 1100, 250, 116, 0, 0, 204, 3 + }, + + /* Region 144 */ + { + 0x000d, 51, 51, 160, 255, 97, -20, + 3831, 240, 39, 0, 232, 224, 3, + 1258, 246, 102, 0, 0, 232, 3, + 4323, 242, 32, 0, 0, 216, 3, + 868, 243, 64, 0, 0, 204, 3 + }, + + /* Region 145 */ + { + 0x000d, 52, 52, 112, 128, 234, -20, + 725, 228, 32, 0, 0, 208, 1, + 400, 248, 86, 0, 0, 248, 3, + 2003, 53, 32, 0, 0, 236, 3, + 100, 209, 32, 0, 0, 212, 1 + }, + + /* Region 146 */ + { + 0x000d, 53, 53, 160, 255, 97, -20, + 3831, 240, 39, 0, 232, 224, 3, + 1258, 246, 102, 0, 0, 232, 3, + 4323, 242, 32, 0, 0, 224, 3, + 868, 243, 64, 0, 0, 196, 3 + }, + + /* Region 147 */ + { + 0x001d, 54, 54, 240, 240, 242, 10, + -1, 245, 71, 1, 24, 236, 0, + 1200, 218, 102, 1, 0, 236, 2, + 1354, 255, 48, 0, 0, 208, 2, + 5868, 209, 48, 0, 160, 212, 0 + }, + + /* Region 148 */ + { + 0x000d, 55, 55, 48, 32, 234, -10, + 725, 228, 32, 0, 0, 208, 3, + 900, 249, 86, 0, 0, 240, 3, + 2303, 69, 32, 0, 0, 236, 1, + 400, 177, 32, 0, 0, 212, 3 + }, + + /* Region 149 */ + { + 0x000d, 56, 56, 0, 255, 149, 20, + 414, 254, 123, 48, 0, 204, 3, + 1986, 252, 118, 48, 0, 244, 3, + 4383, 242, 67, 48, 0, 200, 3, + 4205, 243, 81, 48, 0, 204, 3 + }, + + /* Region 150 */ + { + 0x000d, 57, 57, 48, 32, 234, -20, + 526, 210, 32, 0, 0, 200, 3, + 719, 246, 86, 0, 0, 240, 3, + 1303, 48, 32, 0, 0, 236, 1, + 202, 98, 32, 0, 0, 212, 3 + }, + + /* Region 151 */ + { + 0x001d, 58, 58, 240, 240, 204, -40, + 5650, 247, 16, 0, 84, 220, 1, + 3800, 248, 32, 0, 0, 248, 3, + 1780, 252, 16, 0, 0, 152, 3, + 6825, 245, 32, 0, 0, 208, 1 + }, + + /* Region 152 */ + { + 0x000d, 59, 59, 144, 0, 108, -20, + 3531, 240, 103, 0, 232, 220, 3, + 1058, 246, 102, 0, 0, 232, 3, + 5331, 242, 64, 0, 0, 220, 3, + 1968, 243, 64, 0, 0, 204, 1 + }, + + /* Region 153 */ + { + 0x000d, 60, 60, 192, 64, 155, 40, + 700, 214, 84, 0, 0, 208, 1, + 950, 253, 76, 0, 0, 248, 3, + 2803, 255, 127, 0, 0, 200, 3, + 750, 255, 89, 0, 0, 204, 3 + }, + + /* Region 154 */ + { + 0x000d, 61, 61, 224, 48, 91, 40, + 400, 229, 68, 0, 0, 204, 1, + 700, 251, 76, 0, 0, 248, 3, + 1803, 255, 95, 0, 0, 196, 3, + 450, 255, 89, 0, 0, 208, 3 + }, + + /* Region 155 */ + { + 0x000d, 62, 62, 240, 32, 191, 25, + 214, 237, 69, 0, 0, 204, 1, + 400, 252, 78, 0, 0, 248, 3, + 2830, 255, 95, 0, 0, 208, 3, + 2500, 255, 25, 0, 0, 192, 3 + }, + + /* Region 156 */ + { + 0x000d, 63, 63, 240, 32, 91, 25, + 400, 229, 68, 0, 0, 188, 1, + -100, 250, 76, 0, 0, 248, 3, + 1803, 254, 95, 0, 0, 200, 3, + 450, 238, 89, 0, 0, 200, 3 + }, + + /* Region 157 */ + { + 0x000d, 64, 64, 240, 16, 91, 20, + 300, 210, 68, 0, 0, 196, 1, + -400, 250, 76, 0, 0, 248, 3, + 1803, 254, 95, 0, 0, 200, 3, + 550, 238, 89, 0, 0, 200, 3 + }, + + /* Region 158 */ + { + 0x001c, 65, 65, 240, 128, 223, 20, + 1780, 234, 16, 0, 112, 208, 3, + 800, 251, 32, 0, 0, 248, 3, + 5501, 231, 48, 0, 48, 200, 3, + 2751, 232, 48, 0, 0, 220, 3 + }, + + /* Region 159 */ + { + 0x001c, 66, 66, 240, 128, 223, 20, + 1580, 234, 16, 0, 112, 208, 3, + 600, 250, 32, 0, 0, 248, 3, + 5201, 231, 48, 0, 48, 200, 3, + 2510, 232, 48, 0, 0, 220, 3 + }, + + /* Region 160 */ + { + 0x000d, 67, 67, 0, 255, 0, -35, + 1514, 255, 63, 51, 0, 184, 3, + 4830, 251, 73, 51, 0, 252, 3, + 4349, 245, 67, 51, 0, 212, 3, + 5267, 246, 65, 51, 0, 200, 3 + }, + + /* Region 161 */ + { + 0x000d, 68, 68, 0, 255, 0, -35, + 1514, 255, 63, 51, 0, 196, 3, + 4905, 251, 73, 51, 0, 252, 3, + 4349, 245, 67, 51, 0, 196, 3, + 5214, 246, 65, 51, 0, 208, 3 + }, + + /* Region 162 */ + { + 0x000a, 69, 69, 240, 240, 243, -35, + 10000, 160, 68, 0, 0, 200, 3, + 7000, 156, 140, 0, 0, 228, 3, + 1586, 176, 16, 0, 0, 228, 7, + 8000, 140, 80, 0, 0, 236, 3 + }, + + /* Region 163 */ + { + 0x001a, 70, 70, 240, 240, 227, -38, + 500, 240, 52, 0, 0, 220, 1, + 8000, 188, 124, 0, 0, 228, 3, + 1586, 240, 16, 0, 0, 224, 7, + 8000, 203, 80, 0, 0, 228, 3 + }, + + /* Region 164 */ + { + 0x0004, 71, 71, 226, 240, 181, 35, + 7253, 224, 32, 48, 0, 184, 3, + 3594, 224, 79, 48, 0, 248, 1, + 220, 97, 19, 48, 156, 152, 3, + 5243, 172, 16, 48, 92, 204, 1 + }, + + /* Region 165 */ + { + 0x0004, 72, 72, 240, 241, 181, 35, + 6253, 134, 32, 48, 0, 184, 3, + 3994, 176, 76, 48, 160, 248, 1, + 22, 183, 19, 48, 156, 172, 3, + 1243, 160, 16, 48, 240, 188, 3 + }, + + /* Region 166 */ + { + 0x001a, 73, 73, 240, 224, 155, 30, + -2145, 240, 70, 0, 0, 252, 3, + 600, 109, 111, 0, 0, 240, 3, + -1800, 240, 71, 0, 0, 248, 3, + 200, 173, 111, 0, 0, 240, 3 + }, + + /* Region 167 */ + { + 0x0012, 74, 74, 240, 224, 119, 30, + -2545, 240, 70, 0, 252, 252, 3, + 0, 153, 111, 0, 0, 240, 3, + -2400, 240, 71, 0, 252, 252, 3, + 100, 137, 111, 0, 0, 240, 3 + }, + + /* Region 168 */ + { + 0x001a, 75, 75, 240, 128, 240, 20, + 3780, 255, 16, 0, 252, 188, 2, + 800, 255, 64, 0, 0, 248, 2, + 2501, 255, 48, 0, 252, 208, 0, + 751, 255, 48, 0, 0, 236, 2 + }, + + /* Region 169 */ + { + 0x000d, 76, 76, 0, 255, 68, 35, + 1100, 239, 69, 0, 0, 184, 3, + 2600, 255, 76, 0, 0, 252, 3, + 5000, 255, 111, 0, 0, 204, 3, + 3400, 254, 73, 0, 0, 184, 3 + }, + + /* Region 170 */ + { + 0x000d, 77, 77, 0, 255, 68, 35, + 914, 239, 69, 0, 0, 180, 3, + 1801, 254, 76, 0, 0, 252, 3, + 4800, 255, 111, 0, 0, 192, 3, + 3200, 254, 73, 0, 0, 192, 3 + }, + + /* Region 171 */ + { + 0x000d, 78, 78, 240, 32, 197, -20, + 1200, 216, 86, 0, 0, 180, 1, + 1800, 189, 127, 0, 0, 244, 3, + 2700, 156, 102, 0, 0, 196, 1, + 700, 109, 104, 0, 0, 196, 1 + }, + + /* Region 172 */ + { + 0x000d, 79, 79, 240, 32, 197, -20, + 1200, 216, 86, 0, 0, 196, 1, + 2200, 171, 127, 0, 0, 244, 3, + 2700, 145, 102, 0, 0, 192, 1, + 700, 106, 104, 0, 0, 192, 1 + }, + + /* Region 173 */ + { + 0x000d, 80, 80, 0, 255, 0, -40, + 3514, 254, 79, 51, 0, 196, 3, + 5905, 252, 73, 51, 0, 248, 3, + 6348, 245, 35, 51, 0, 176, 3, + 2203, 244, 33, 51, 0, 216, 3 + }, + + /* Region 174 */ + { + 0x800d, 81, 81, 0, 255, 0, -40, + 3514, 255, 79, 51, 0, 192, 3, + 5905, 246, 73, 51, 0, 252, 3, + 6348, 241, 35, 51, 0, 180, 3, + 2203, 242, 33, 51, 0, 212, 3 + } +}; + + +/*---------------------------------------------------------------------------- + * Programs + *---------------------------------------------------------------------------- +*/ +const S_PROGRAM programs[] = +{ + { 7864320, 128 } /* program 0 */ +}; /* end Programs */ + +/*---------------------------------------------------------------------------- + * Banks + *---------------------------------------------------------------------------- +*/ +const S_BANK banks[] = +{ + { /* bank 0 */ + 30976, + { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127 + } + } +}; /* end Banks */ + +/*---------------------------------------------------------------------------- + * S_EAS + *---------------------------------------------------------------------------- +*/ +const S_EAS easSoundLib = +{ + 0x01534145, + 0x00105622, + + banks, + programs, + + NULL, + NULL, + NULL, + NULL, + NULL, + + regions, + + 1, + 1, + + 0, + 0, + 0, + + 175 +}; /* end S_EAS */ +/* end sound library */ diff --git a/arm-fm-22k/lib_src/eas_fmsynth.c b/arm-fm-22k/lib_src/eas_fmsynth.c index 83f0087..629506a 100644 --- a/arm-fm-22k/lib_src/eas_fmsynth.c +++ b/arm-fm-22k/lib_src/eas_fmsynth.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * fmsynth.c
- *
- * Contents and purpose:
- * Implements the high-level FM synthesizer functions.
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * fmsynth.c + * + * Contents and purpose: + * Implements the high-level FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,892 +19,892 @@ * 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: 795 $
- * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-// includes
-#include "eas_host.h"
-#include "eas_report.h"
-
-#include "eas_data.h"
-#include "eas_synth_protos.h"
-#include "eas_audioconst.h"
-#include "eas_fmengine.h"
-#include "eas_math.h"
-
-/* option sanity check */
-#ifdef _REVERB
-#error "No reverb for FM synthesizer"
-#endif
-#ifdef _CHORUS
-#error "No chorus for FM synthesizer"
-#endif
-
-/*
- * WARNING: These macros can cause unwanted side effects. Use them
- * with care. For example, min(x++,y++) will cause either x or y to be
- * incremented twice.
- */
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#define max(a,b) ((a) > (b) ? (a) : (b))
-
-/* pivot point for keyboard scalars */
-#define EG_SCALE_PIVOT_POINT 64
-#define KEY_SCALE_PIVOT_POINT 36
-
-/* This number is the negative of the frequency of the note (in cents) of
- * the sine wave played at unity. The number can be calculated as follows:
- *
- * MAGIC_NUMBER = 1200 * log(base2) (SINE_TABLE_SIZE * 8.175798916 / SAMPLE_RATE)
- *
- * 8.17578 is a reference to the frequency of MIDI note 0
- */
-#if defined (_SAMPLE_RATE_8000)
-#define MAGIC_NUMBER 1279
-#elif defined (_SAMPLE_RATE_16000)
-#define MAGIC_NUMBER 79
-#elif defined (_SAMPLE_RATE_20000)
-#define MAGIC_NUMBER -308
-#elif defined (_SAMPLE_RATE_22050)
-#define MAGIC_NUMBER -477
-#elif defined (_SAMPLE_RATE_24000)
-#define MAGIC_NUMBER -623
-#elif defined (_SAMPLE_RATE_32000)
-#define MAGIC_NUMBER -1121
-#elif defined (_SAMPLE_RATE_44100)
-#define MAGIC_NUMBER -1677
-#elif defined (_SAMPLE_RATE_48000)
-#define MAGIC_NUMBER -1823
-#endif
-
-/* externs */
-extern const EAS_I16 fmControlTable[128];
-extern const EAS_U16 fmRateTable[256];
-extern const EAS_U16 fmAttackTable[16];
-extern const EAS_U8 fmDecayTable[16];
-extern const EAS_U8 fmReleaseTable[16];
-extern const EAS_U8 fmScaleTable[16];
-
-/* local prototypes */
-/*lint -esym(715, pVoiceMgr) standard synthesizer interface - pVoiceMgr not used */
-static EAS_RESULT FM_Initialize (S_VOICE_MGR *pVoiceMgr) { return EAS_SUCCESS; }
-static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex);
-static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples);
-static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
-static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
-static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum);
-static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
-
-
-/*----------------------------------------------------------------------------
- * Synthesizer interface
- *----------------------------------------------------------------------------
-*/
-const S_SYNTH_INTERFACE fmSynth =
-{
- FM_Initialize,
- FM_StartVoice,
- FM_UpdateVoice,
- FM_ReleaseVoice,
- FM_MuteVoice,
- FM_SustainPedal,
- FM_UpdateChannel
-};
-
-#ifdef FM_OFFBOARD
-const S_FRAME_INTERFACE fmFrameInterface =
-{
- FM_StartFrame,
- FM_EndFrame
-};
-#endif
-
-/*----------------------------------------------------------------------------
- * inline functions
- *----------------------------------------------------------------------------
- */
-EAS_INLINE S_FM_VOICE *GetFMVoicePtr (S_VOICE_MGR *pVoiceMgr, EAS_INT voiceNum)
-{
- return &pVoiceMgr->fmVoices[voiceNum];
-}
-EAS_INLINE S_SYNTH_CHANNEL *GetChannelPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
-{
- return &pSynth->channels[pVoice->channel & 15];
-}
-EAS_INLINE const S_FM_REGION *GetFMRegionPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
-{
-#ifdef _SECONDARY_SYNTH
- return &pSynth->pEAS->pFMRegions[pVoice->regionIndex & REGION_INDEX_MASK];
-#else
- return &pSynth->pEAS->pFMRegions[pVoice->regionIndex];
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * FM_SynthIsOutputOperator
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns true if the operator is a direct output and not muted
- *
- * Inputs:
- *
- * Outputs:
- * Returns boolean
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL FM_SynthIsOutputOperator (const S_FM_REGION *pRegion, EAS_INT operIndex)
-{
-
- /* see if voice is muted */
- if ((pRegion->oper[operIndex].gain & 0xfc) == 0)
- return 0;
-
- /* check based on mode */
- switch (pRegion->region.keyGroupAndFlags & 7)
- {
-
- /* mode 0 - all operators are external */
- case 0:
- return EAS_TRUE;
-
- /* mode 1 - operators 1-3 are external */
- case 1:
- if (operIndex != 0)
- return EAS_TRUE;
- break;
-
- /* mode 2 - operators 1 & 3 are external */
- case 2:
- if ((operIndex == 1) || (operIndex == 3))
- return EAS_TRUE;
- break;
-
- /* mode 2 - operators 1 & 2 are external */
- case 3:
- if ((operIndex == 1) || (operIndex == 2))
- return EAS_TRUE;
- break;
-
- /* modes 4 & 5 - operator 1 is external */
- case 4:
- case 5:
- if (operIndex == 1)
- return EAS_TRUE;
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid voice mode: %d",
- pRegion->region.keyGroupAndFlags & 7); */ }
- }
-
- return EAS_FALSE;
-}
-
-/*----------------------------------------------------------------------------
- * FM_CalcEGRate()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * nKeyNumber - MIDI note
- * nLogRate - logarithmic scale rate from patch data
- * nKeyScale - key scaling factor for this EG
- *
- * Outputs:
- * 16-bit linear multiplier
- *----------------------------------------------------------------------------
-*/
-
-static EAS_U16 FM_CalcEGRate (EAS_U8 nKeyNumber, EAS_U8 nLogRate, EAS_U8 nEGScale)
-{
- EAS_I32 temp;
-
- /* incorporate key scaling on release rate */
- temp = (EAS_I32) nLogRate << 7;
- temp += ((EAS_I32) nKeyNumber - EG_SCALE_PIVOT_POINT) * (EAS_I32) nEGScale;
-
- /* saturate */
- temp = max(temp, 0);
- temp = min(temp, 32767);
-
- /* look up in rate table */
- /*lint -e{704} use shift for performance */
- return fmRateTable[temp >> 8];
-}
-
-/*----------------------------------------------------------------------------
- * FM_ReleaseVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * The selected voice is being released.
- *
- * Inputs:
- * psEASData - pointer to S_EAS_DATA
- * pVoice - pointer to voice to release
- *
- * Outputs:
- * None
- *----------------------------------------------------------------------------
-*/
-static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
-{
- EAS_INT operIndex;
- const S_FM_REGION *pRegion;
- S_FM_VOICE *pFMVoice;
-
- /* check to see if voice responds to NOTE-OFF's */
- pRegion = GetFMRegionPtr(pSynth, pVoice);
- if (pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT)
- return;
-
- /* set all envelopes to release state */
- pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
- for (operIndex = 0; operIndex < 4; operIndex++)
- {
- pFMVoice->oper[operIndex].envState = eFMEnvelopeStateRelease;
-
- /* incorporate key scaling on release rate */
- pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
- pVoice->note,
- fmReleaseTable[pRegion->oper[operIndex].velocityRelease & 0x0f],
- fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
- } /* end for (operIndex = 0; operIndex < 4; operIndex++) */
-}
-
-/*----------------------------------------------------------------------------
- * FM_MuteVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * The selected voice is being muted.
- *
- * Inputs:
- * pVoice - pointer to voice to release
- *
- * Outputs:
- * None
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pSynth) standard interface, pVoiceMgr not used */
-static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
-{
- S_FM_VOICE *pFMVoice;
-
- /* clear deferred action flags */
- pVoice->voiceFlags &=
- ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
- VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF |
- VOICE_FLAG_DEFER_MUTE);
-
- /* set all envelopes to muted state */
- pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
- pFMVoice->oper[0].envState = eFMEnvelopeStateMuted;
- pFMVoice->oper[1].envState = eFMEnvelopeStateMuted;
- pFMVoice->oper[2].envState = eFMEnvelopeStateMuted;
- pFMVoice->oper[3].envState = eFMEnvelopeStateMuted;
-}
-
-/*----------------------------------------------------------------------------
- * FM_SustainPedal()
- *----------------------------------------------------------------------------
- * Purpose:
- * The selected voice is held due to sustain pedal
- *
- * Inputs:
- * pVoice - pointer to voice to sustain
- *
- * Outputs:
- * None
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pChannel) standard interface, pVoiceMgr not used */
-static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum)
-{
- const S_FM_REGION *pRegion;
- S_FM_VOICE *pFMVoice;
- EAS_INT operIndex;
-
- pRegion = GetFMRegionPtr(pSynth, pVoice);
- pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
-
- /* check to see if any envelopes are above the sustain level */
- for (operIndex = 0; operIndex < 4; operIndex++)
- {
-
- /* if level control or envelope gain is zero, skip this envelope */
- if (((pRegion->oper[operIndex].gain & 0xfc) == 0) ||
- (pFMVoice->oper[operIndex].envGain == 0))
- {
- continue;
- }
-
- /* if the envelope gain is above the sustain level, we need to catch this voice */
- if (pFMVoice->oper[operIndex].envGain >= ((EAS_U16) (pRegion->oper[operIndex].sustain & 0xfc) << 7))
- {
-
- /* reset envelope to decay state */
- pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay;
-
- pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
- pVoice->note,
- fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f],
- fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
-
- /* set voice to decay state */
- pVoice->voiceState = eVoiceStatePlay;
-
- /* set sustain flag */
- pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
- }
- } /* end for (operIndex = 0; operIndex < 4; operIndex++) */
-}
-
-/*----------------------------------------------------------------------------
- * FM_StartVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Assign the region for the given instrument using the midi key number
- * and the RPN2 (coarse tuning) value. By using RPN2 as part of the
- * region selection process, we reduce the amount a given sample has
- * to be transposed by selecting the closest recorded root instead.
- *
- * This routine is the second half of SynthAssignRegion().
- * If the region was successfully found by SynthFindRegionIndex(),
- * then assign the region's parameters to the voice.
- *
- * Setup and initialize the following voice parameters:
- * m_nRegionIndex
- *
- * Inputs:
- * pVoice - ptr to the voice we have assigned for this channel
- * nRegionIndex - index of the region
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * success - could find and assign the region for this voice's note otherwise
- * failure - could not find nor assign the region for this voice's note
- *
- * Side Effects:
- * psSynthObject->m_sVoice[].m_nRegionIndex is assigned
- * psSynthObject->m_sVoice[] parameters are assigned
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex)
-{
- S_FM_VOICE *pFMVoice;
- S_SYNTH_CHANNEL *pChannel;
- const S_FM_REGION *pRegion;
- EAS_I32 temp;
- EAS_INT operIndex;
-
- /* establish pointers to data */
- pVoice->regionIndex = regionIndex;
- pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
- pChannel = GetChannelPtr(pSynth, pVoice);
- pRegion = GetFMRegionPtr(pSynth, pVoice);
-
- /* update static channel parameters */
- if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)
- FM_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15);
-
- /* init the LFO */
- pFMVoice->lfoValue = 0;
- pFMVoice->lfoPhase = 0;
- pFMVoice->lfoDelay = (EAS_U16) (fmScaleTable[pRegion->lfoFreqDelay & 0x0f] >> 1);
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- /* calculate pan gain values only if stereo output */
- /* set up panning only at note start */
- temp = (EAS_I32) pChannel->pan - 64;
- temp += (EAS_I32) pRegion->pan;
- if (temp < -64)
- temp = -64;
- if (temp > 64)
- temp = 64;
- pFMVoice->pan = (EAS_I8) temp;
-#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */
-
- /* no samples have been synthesized for this note yet */
- pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
-
- /* initialize gain value for anti-zipper filter */
- pFMVoice->voiceGain = (EAS_I16) EAS_LogToLinear16(pChannel->staticGain);
- pFMVoice->voiceGain = (EAS_I16) FMUL_15x15(pFMVoice->voiceGain, pSynth->masterVolume);
-
- /* initialize the operators */
- for (operIndex = 0; operIndex < 4; operIndex++)
- {
-
- /* establish operator output gain level */
- /*lint -e{701} <use shift for performance> */
- pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7);
-
- /* check for linear velocity flag */
- /*lint -e{703} <use shift for performance> */
- if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_LINEAR_VELOCITY)
- temp = (EAS_I32) (pVoice->velocity - 127) << 5;
- else
- temp = (EAS_I32) fmControlTable[pVoice->velocity];
-
- /* scale velocity */
- /*lint -e{704} use shift for performance */
- temp = (temp * (EAS_I32)(pRegion->oper[operIndex].velocityRelease & 0xf0)) >> 7;
-
- /* include key scalar */
- temp -= ((EAS_I32) pVoice->note - KEY_SCALE_PIVOT_POINT) * (EAS_I32) fmScaleTable[pRegion->oper[operIndex].egKeyScale & 0x0f];
-
- /* saturate */
- temp = min(temp, 0);
- temp = max(temp, -32768);
-
- /* save static gain parameters */
- pFMVoice->oper[operIndex].baseGain = (EAS_I16) EAS_LogToLinear16(temp);
-
- /* incorporate key scaling on decay rate */
- pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
- pVoice->note,
- fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f],
- fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
-
- /* if zero attack time, max out envelope and jump to decay state */
- if ((pRegion->oper[operIndex].attackDecay & 0xf0) == 0xf0)
- {
-
- /* start out envelope at max */
- pFMVoice->oper[operIndex].envGain = 0x7fff;
-
- /* set envelope to decay state */
- pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay;
- }
-
- /* start envelope at zero and start in attack state */
- else
- {
- pFMVoice->oper[operIndex].envGain = 0;
- pFMVoice->oper[operIndex].envState = eFMEnvelopeStateAttack;
- }
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * FM_UpdateChannel()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate and assign static channel parameters
- * These values only need to be updated if one of the controller values
- * for this channel changes.
- * Called when CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS flag is set.
- *
- * Inputs:
- * nChannel - channel to update
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - the given channel's static gain and static pitch are updated
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pVoiceMgr) standard interface, pVoiceMgr not used */
-static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
-{
- S_SYNTH_CHANNEL *pChannel;
- EAS_I32 temp;
-
- pChannel = &pSynth->channels[channel];
-
- /* convert CC7 volume controller to log scale */
- temp = fmControlTable[pChannel->volume];
-
- /* incorporate CC11 expression controller */
- temp += fmControlTable[pChannel->expression];
-
- /* saturate */
- pChannel->staticGain = (EAS_I16) max(temp,-32768);
-
- /* calculate pitch bend */
- /*lint -e{703} <avoid multiply for performance>*/
- temp = (((EAS_I32)(pChannel->pitchBend) << 2) - 32768);
-
- temp = FMUL_15x15(temp, pChannel->pitchBendSensitivity);
-
- /* include "magic number" compensation for sample rate and lookup table size */
- temp += MAGIC_NUMBER;
-
- /* if this is not a drum channel, then add in the per-channel tuning */
- if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL))
- temp += (pChannel->finePitch + (pChannel->coarsePitch * 100));
-
- /* save static pitch */
- pChannel->staticPitch = temp;
-
- /* Calculate LFO modulation depth */
- /* mod wheel to LFO depth */
- temp = FMUL_15x15(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS,
- pChannel->modWheel << (NUM_EG1_FRAC_BITS -7));
-
- /* channel pressure to LFO depth */
- pChannel->lfoAmt = (EAS_I16) (temp +
- FMUL_15x15(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS,
- pChannel->channelPressure << (NUM_EG1_FRAC_BITS -7)));
-
- /* clear update flag */
- pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
- return;
-}
-
-/*----------------------------------------------------------------------------
- * FM_UpdateLFO()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate the LFO for the given voice
- *
- * Inputs:
- * pVoice - ptr to the voice whose LFO we want to update
- * psEASData - pointer to overall EAS data structure - used for debug only
- *
- * Outputs:
- *
- * Side Effects:
- * - updates LFO values for the given voice
- *----------------------------------------------------------------------------
-*/
-static void FM_UpdateLFO (S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion)
-{
-
- /* increment the LFO phase if the delay time has elapsed */
- if (!pFMVoice->lfoDelay)
- {
- /*lint -e{701} <use shift for performance> */
- pFMVoice->lfoPhase = pFMVoice->lfoPhase + (EAS_U16) (-fmControlTable[((15 - (pRegion->lfoFreqDelay >> 4)) << 3) + 4]);
-
- /* square wave LFO? */
- if (pRegion->region.keyGroupAndFlags & REGION_FLAG_SQUARE_WAVE)
- pFMVoice->lfoValue = (EAS_I16)(pFMVoice->lfoPhase & 0x8000 ? -32767 : 32767);
-
- /* trick to get a triangle wave out of a sawtooth */
- else
- {
- pFMVoice->lfoValue = (EAS_I16) (pFMVoice->lfoPhase << 1);
- /*lint -e{502} <shortcut to turn sawtooth into sine wave> */
- if ((pFMVoice->lfoPhase > 0x3fff) && (pFMVoice->lfoPhase < 0xC000))
- pFMVoice->lfoValue = ~pFMVoice->lfoValue;
- }
- }
-
- /* still in delay */
- else
- pFMVoice->lfoDelay--;
-
- return;
-}
-
-/*----------------------------------------------------------------------------
- * FM_UpdateEG()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate the synthesis parameters for an operator to be used during
- * the next buffer
- *
- * Inputs:
- * pVoice - pointer to the voice being updated
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL FM_UpdateEG (S_SYNTH_VOICE *pVoice, S_OPERATOR *pOper, const S_FM_OPER *pOperData, EAS_BOOL oneShot)
-{
- EAS_U32 temp;
- EAS_BOOL done;
-
- /* set flag assuming the envelope is not done */
- done = EAS_FALSE;
-
- /* take appropriate action based on state */
- switch (pOper->envState)
- {
-
- case eFMEnvelopeStateAttack:
-
- /* the envelope is linear during the attack, so add the value */
- temp = pOper->envGain + fmAttackTable[pOperData->attackDecay >> 4];
-
- /* check for end of attack */
- if (temp >= 0x7fff)
- {
- pOper->envGain = 0x7fff;
- pOper->envState = eFMEnvelopeStateDecay;
- }
- else
- pOper->envGain = (EAS_U16) temp;
- break;
-
- case eFMEnvelopeStateDecay:
-
- /* decay is exponential, multiply by decay rate */
- pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate);
-
- /* check for sustain level reached */
- temp = (EAS_U32) (pOperData->sustain & 0xfc) << 7;
- if (pOper->envGain <= (EAS_U16) temp)
- {
- /* if this is a one-shot patch, go directly to release phase */
- if (oneShot)
- {
- pOper->envRate = FM_CalcEGRate(
- pVoice->note,
- fmReleaseTable[pOperData->velocityRelease & 0x0f],
- fmScaleTable[pOperData->egKeyScale >> 4]);
- pOper->envState = eFMEnvelopeStateRelease;
- }
-
- /* normal sustaining type */
- else
- {
- pOper->envGain = (EAS_U16) temp;
- pOper->envState = eFMEnvelopeStateSustain;
- }
- }
- break;
-
- case eFMEnvelopeStateSustain:
- pOper->envGain = (EAS_U16)((EAS_U16)(pOperData->sustain & 0xfc) << 7);
- break;
-
- case eFMEnvelopeStateRelease:
-
- /* release is exponential, multiply by release rate */
- pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate);
-
- /* fully released */
- if (pOper->envGain == 0)
- {
- pOper->envGain = 0;
- pOper->envState = eFMEnvelopeStateMuted;
- done = EAS_TRUE;
- }
- break;
-
- case eFMEnvelopeStateMuted:
- pOper->envGain = 0;
- done = EAS_TRUE;
- break;
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid operator state: %d", pOper->envState); */ }
- } /* end switch (pOper->m_eState) */
-
- return done;
-}
-
-/*----------------------------------------------------------------------------
- * FM_UpdateDynamic()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate the synthesis parameters for this voice that will be used to
- * synthesize the next buffer
- *
- * Inputs:
- * pVoice - pointer to the voice being updated
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Returns EAS_TRUE if voice will be fully ramped to zero at the end of
- * the next synthesized buffer.
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL FM_UpdateDynamic (S_SYNTH_VOICE *pVoice, S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion, S_SYNTH_CHANNEL *pChannel)
-{
- EAS_I32 temp;
- EAS_I32 pitch;
- EAS_I32 lfoPitch;
- EAS_INT operIndex;
- EAS_BOOL done;
-
- /* increment LFO phase */
- FM_UpdateLFO(pFMVoice, pRegion);
-
- /* base pitch in cents */
- pitch = pVoice->note * 100;
-
- /* LFO amount includes LFO depth from programming + channel dynamics */
- temp = (fmScaleTable[pRegion->vibTrem >> 4] >> 1) + pChannel->lfoAmt;
-
- /* multiply by LFO output to get final pitch modulation */
- lfoPitch = FMUL_15x15(pFMVoice->lfoValue, temp);
-
- /* flag to indicate this voice is done */
- done = EAS_TRUE;
-
- /* iterate through operators to establish parameters */
- for (operIndex = 0; operIndex < 4; operIndex++)
- {
- EAS_BOOL bTemp;
-
- /* set base phase increment for each operator */
- temp = pRegion->oper[operIndex].tuning +
- pChannel->staticPitch;
-
- /* add vibrato effect unless it is disabled for this operator */
- if ((pRegion->oper[operIndex].flags & FM_OPER_FLAG_NO_VIBRATO) == 0)
- temp += lfoPitch;
-
- /* if note is monotonic, bias to MIDI note 60 */
- if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_MONOTONE)
- temp += 6000;
- else
- temp += pitch;
- pFMVoice->oper[operIndex].pitch = (EAS_I16) temp;
-
- /* calculate envelope, returns true if done */
- bTemp = FM_UpdateEG(pVoice, &pFMVoice->oper[operIndex], &pRegion->oper[operIndex], pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT);
-
- /* check if all output envelopes have completed */
- if (FM_SynthIsOutputOperator(pRegion, operIndex))
- done = done && bTemp;
- }
-
- return done;
-}
-
-/*----------------------------------------------------------------------------
- * FM_UpdateVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Synthesize a block of samples for the given voice.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * number of samples actually written to buffer
- *
- * Side Effects:
- * - samples are added to the presently free buffer
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples)
-{
- S_SYNTH_CHANNEL *pChannel;
- const S_FM_REGION *pRegion;
- S_FM_VOICE *pFMVoice;
- S_FM_VOICE_CONFIG vCfg;
- S_FM_VOICE_FRAME vFrame;
- EAS_I32 temp;
- EAS_INT oper;
- EAS_U16 voiceGainTarget;
- EAS_BOOL done;
-
- /* setup some pointers */
- pChannel = GetChannelPtr(pSynth, pVoice);
- pRegion = GetFMRegionPtr(pSynth, pVoice);
- pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
-
- /* if the voice is just starting, get the voice configuration data */
- if (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
- {
-
- /* split architecture may limit the number of voice starts */
-#ifdef MAX_VOICE_STARTS
- if (pVoiceMgr->numVoiceStarts == MAX_VOICE_STARTS)
- return EAS_FALSE;
- pVoiceMgr->numVoiceStarts++;
-#endif
-
- /* get initial parameters */
- vCfg.feedback = pRegion->feedback;
- vCfg.voiceGain = (EAS_U16) pFMVoice->voiceGain;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- vCfg.pan = pFMVoice->pan;
-#endif
-
- /* get voice mode */
- vCfg.flags = pRegion->region.keyGroupAndFlags & 7;
-
- /* get operator parameters */
- for (oper = 0; oper < 4; oper++)
- {
- /* calculate initial gain */
- vCfg.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain);
- vCfg.outputGain[oper] = pFMVoice->oper[oper].outputGain;
-
- /* copy noise waveform flag */
- if (pRegion->oper[oper].flags & FM_OPER_FLAG_NOISE)
- vCfg.flags |= (EAS_U8) (FLAG_FM_ENG_VOICE_OP1_NOISE << oper);
- }
-
-#ifdef FM_OFFBOARD
- FM_ConfigVoice(voiceNum, &vCfg, pVoiceMgr->pFrameBuffer);
-#else
- FM_ConfigVoice(voiceNum, &vCfg, NULL);
-#endif
-
- /* clear startup flag */
- pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
- }
-
- /* calculate new synthesis parameters */
- done = FM_UpdateDynamic(pVoice, pFMVoice, pRegion, pChannel);
-
- /* calculate LFO gain modulation */
- /*lint -e{702} <use shift for performance> */
- temp = ((fmScaleTable[pRegion->vibTrem & 0x0f] >> 1) * pFMVoice->lfoValue) >> FM_LFO_GAIN_SHIFT;
-
- /* include channel gain */
- temp += pChannel->staticGain;
-
- /* -32768 or lower is infinite attenuation */
- if (temp < -32767)
- voiceGainTarget = 0;
-
- /* translate to linear gain multiplier */
- else
- voiceGainTarget = EAS_LogToLinear16(temp);
-
- /* include synth master volume */
- voiceGainTarget = (EAS_U16) FMUL_15x15(voiceGainTarget, pSynth->masterVolume);
-
- /* save target values for this frame */
- vFrame.voiceGain = voiceGainTarget;
-
- /* assume voice output is zero */
- pVoice->gain = 0;
-
- /* save operator targets for this frame */
- for (oper = 0; oper < 4; oper++)
- {
- vFrame.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain);
- vFrame.pitch[oper] = pFMVoice->oper[oper].pitch;
-
- /* use the highest output envelope level as the gain for the voice stealing algorithm */
- if (FM_SynthIsOutputOperator(pRegion, oper))
- pVoice->gain = max(pVoice->gain, (EAS_I16) vFrame.gain[oper]);
- }
-
- /* consider voice gain multiplier in calculating gain for stealing algorithm */
- pVoice->gain = (EAS_I16) FMUL_15x15(voiceGainTarget, pVoice->gain);
-
- /* synthesize samples */
-#ifdef FM_OFFBOARD
- FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, pVoiceMgr->pFrameBuffer);
-#else
- FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, NULL);
-#endif
-
- return done;
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_host.h" +#include "eas_report.h" + +#include "eas_data.h" +#include "eas_synth_protos.h" +#include "eas_audioconst.h" +#include "eas_fmengine.h" +#include "eas_math.h" + +/* option sanity check */ +#ifdef _REVERB +#error "No reverb for FM synthesizer" +#endif +#ifdef _CHORUS +#error "No chorus for FM synthesizer" +#endif + +/* + * WARNING: These macros can cause unwanted side effects. Use them + * with care. For example, min(x++,y++) will cause either x or y to be + * incremented twice. + */ +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +/* pivot point for keyboard scalars */ +#define EG_SCALE_PIVOT_POINT 64 +#define KEY_SCALE_PIVOT_POINT 36 + +/* This number is the negative of the frequency of the note (in cents) of + * the sine wave played at unity. The number can be calculated as follows: + * + * MAGIC_NUMBER = 1200 * log(base2) (SINE_TABLE_SIZE * 8.175798916 / SAMPLE_RATE) + * + * 8.17578 is a reference to the frequency of MIDI note 0 + */ +#if defined (_SAMPLE_RATE_8000) +#define MAGIC_NUMBER 1279 +#elif defined (_SAMPLE_RATE_16000) +#define MAGIC_NUMBER 79 +#elif defined (_SAMPLE_RATE_20000) +#define MAGIC_NUMBER -308 +#elif defined (_SAMPLE_RATE_22050) +#define MAGIC_NUMBER -477 +#elif defined (_SAMPLE_RATE_24000) +#define MAGIC_NUMBER -623 +#elif defined (_SAMPLE_RATE_32000) +#define MAGIC_NUMBER -1121 +#elif defined (_SAMPLE_RATE_44100) +#define MAGIC_NUMBER -1677 +#elif defined (_SAMPLE_RATE_48000) +#define MAGIC_NUMBER -1823 +#endif + +/* externs */ +extern const EAS_I16 fmControlTable[128]; +extern const EAS_U16 fmRateTable[256]; +extern const EAS_U16 fmAttackTable[16]; +extern const EAS_U8 fmDecayTable[16]; +extern const EAS_U8 fmReleaseTable[16]; +extern const EAS_U8 fmScaleTable[16]; + +/* local prototypes */ +/*lint -esym(715, pVoiceMgr) standard synthesizer interface - pVoiceMgr not used */ +static EAS_RESULT FM_Initialize (S_VOICE_MGR *pVoiceMgr) { return EAS_SUCCESS; } +static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); +static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); +static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); +static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + + +/*---------------------------------------------------------------------------- + * Synthesizer interface + *---------------------------------------------------------------------------- +*/ +const S_SYNTH_INTERFACE fmSynth = +{ + FM_Initialize, + FM_StartVoice, + FM_UpdateVoice, + FM_ReleaseVoice, + FM_MuteVoice, + FM_SustainPedal, + FM_UpdateChannel +}; + +#ifdef FM_OFFBOARD +const S_FRAME_INTERFACE fmFrameInterface = +{ + FM_StartFrame, + FM_EndFrame +}; +#endif + +/*---------------------------------------------------------------------------- + * inline functions + *---------------------------------------------------------------------------- + */ +EAS_INLINE S_FM_VOICE *GetFMVoicePtr (S_VOICE_MGR *pVoiceMgr, EAS_INT voiceNum) +{ + return &pVoiceMgr->fmVoices[voiceNum]; +} +EAS_INLINE S_SYNTH_CHANNEL *GetChannelPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ + return &pSynth->channels[pVoice->channel & 15]; +} +EAS_INLINE const S_FM_REGION *GetFMRegionPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ +#ifdef _SECONDARY_SYNTH + return &pSynth->pEAS->pFMRegions[pVoice->regionIndex & REGION_INDEX_MASK]; +#else + return &pSynth->pEAS->pFMRegions[pVoice->regionIndex]; +#endif +} + +/*---------------------------------------------------------------------------- + * FM_SynthIsOutputOperator + *---------------------------------------------------------------------------- + * Purpose: + * Returns true if the operator is a direct output and not muted + * + * Inputs: + * + * Outputs: + * Returns boolean + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_SynthIsOutputOperator (const S_FM_REGION *pRegion, EAS_INT operIndex) +{ + + /* see if voice is muted */ + if ((pRegion->oper[operIndex].gain & 0xfc) == 0) + return 0; + + /* check based on mode */ + switch (pRegion->region.keyGroupAndFlags & 7) + { + + /* mode 0 - all operators are external */ + case 0: + return EAS_TRUE; + + /* mode 1 - operators 1-3 are external */ + case 1: + if (operIndex != 0) + return EAS_TRUE; + break; + + /* mode 2 - operators 1 & 3 are external */ + case 2: + if ((operIndex == 1) || (operIndex == 3)) + return EAS_TRUE; + break; + + /* mode 2 - operators 1 & 2 are external */ + case 3: + if ((operIndex == 1) || (operIndex == 2)) + return EAS_TRUE; + break; + + /* modes 4 & 5 - operator 1 is external */ + case 4: + case 5: + if (operIndex == 1) + return EAS_TRUE; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid voice mode: %d", + pRegion->region.keyGroupAndFlags & 7); */ } + } + + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * FM_CalcEGRate() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * nKeyNumber - MIDI note + * nLogRate - logarithmic scale rate from patch data + * nKeyScale - key scaling factor for this EG + * + * Outputs: + * 16-bit linear multiplier + *---------------------------------------------------------------------------- +*/ + +static EAS_U16 FM_CalcEGRate (EAS_U8 nKeyNumber, EAS_U8 nLogRate, EAS_U8 nEGScale) +{ + EAS_I32 temp; + + /* incorporate key scaling on release rate */ + temp = (EAS_I32) nLogRate << 7; + temp += ((EAS_I32) nKeyNumber - EG_SCALE_PIVOT_POINT) * (EAS_I32) nEGScale; + + /* saturate */ + temp = max(temp, 0); + temp = min(temp, 32767); + + /* look up in rate table */ + /*lint -e{704} use shift for performance */ + return fmRateTable[temp >> 8]; +} + +/*---------------------------------------------------------------------------- + * FM_ReleaseVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being released. + * + * Inputs: + * psEASData - pointer to S_EAS_DATA + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + EAS_INT operIndex; + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + + /* check to see if voice responds to NOTE-OFF's */ + pRegion = GetFMRegionPtr(pSynth, pVoice); + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT) + return; + + /* set all envelopes to release state */ + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + for (operIndex = 0; operIndex < 4; operIndex++) + { + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateRelease; + + /* incorporate key scaling on release rate */ + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmReleaseTable[pRegion->oper[operIndex].velocityRelease & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ +} + +/*---------------------------------------------------------------------------- + * FM_MuteVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being muted. + * + * Inputs: + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pSynth) standard interface, pVoiceMgr not used */ +static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_FM_VOICE *pFMVoice; + + /* clear deferred action flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE); + + /* set all envelopes to muted state */ + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + pFMVoice->oper[0].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[1].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[2].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[3].envState = eFMEnvelopeStateMuted; +} + +/*---------------------------------------------------------------------------- + * FM_SustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is held due to sustain pedal + * + * Inputs: + * pVoice - pointer to voice to sustain + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) standard interface, pVoiceMgr not used */ +static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) +{ + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + EAS_INT operIndex; + + pRegion = GetFMRegionPtr(pSynth, pVoice); + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + + /* check to see if any envelopes are above the sustain level */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + + /* if level control or envelope gain is zero, skip this envelope */ + if (((pRegion->oper[operIndex].gain & 0xfc) == 0) || + (pFMVoice->oper[operIndex].envGain == 0)) + { + continue; + } + + /* if the envelope gain is above the sustain level, we need to catch this voice */ + if (pFMVoice->oper[operIndex].envGain >= ((EAS_U16) (pRegion->oper[operIndex].sustain & 0xfc) << 7)) + { + + /* reset envelope to decay state */ + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; + + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + + /* set voice to decay state */ + pVoice->voiceState = eVoiceStatePlay; + + /* set sustain flag */ + pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + } + } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ +} + +/*---------------------------------------------------------------------------- + * FM_StartVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the region for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * This routine is the second half of SynthAssignRegion(). + * If the region was successfully found by SynthFindRegionIndex(), + * then assign the region's parameters to the voice. + * + * Setup and initialize the following voice parameters: + * m_nRegionIndex + * + * Inputs: + * pVoice - ptr to the voice we have assigned for this channel + * nRegionIndex - index of the region + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * success - could find and assign the region for this voice's note otherwise + * failure - could not find nor assign the region for this voice's note + * + * Side Effects: + * psSynthObject->m_sVoice[].m_nRegionIndex is assigned + * psSynthObject->m_sVoice[] parameters are assigned + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) +{ + S_FM_VOICE *pFMVoice; + S_SYNTH_CHANNEL *pChannel; + const S_FM_REGION *pRegion; + EAS_I32 temp; + EAS_INT operIndex; + + /* establish pointers to data */ + pVoice->regionIndex = regionIndex; + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + pChannel = GetChannelPtr(pSynth, pVoice); + pRegion = GetFMRegionPtr(pSynth, pVoice); + + /* update static channel parameters */ + if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) + FM_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); + + /* init the LFO */ + pFMVoice->lfoValue = 0; + pFMVoice->lfoPhase = 0; + pFMVoice->lfoDelay = (EAS_U16) (fmScaleTable[pRegion->lfoFreqDelay & 0x0f] >> 1); + +#if (NUM_OUTPUT_CHANNELS == 2) + /* calculate pan gain values only if stereo output */ + /* set up panning only at note start */ + temp = (EAS_I32) pChannel->pan - 64; + temp += (EAS_I32) pRegion->pan; + if (temp < -64) + temp = -64; + if (temp > 64) + temp = 64; + pFMVoice->pan = (EAS_I8) temp; +#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */ + + /* no samples have been synthesized for this note yet */ + pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* initialize gain value for anti-zipper filter */ + pFMVoice->voiceGain = (EAS_I16) EAS_LogToLinear16(pChannel->staticGain); + pFMVoice->voiceGain = (EAS_I16) FMUL_15x15(pFMVoice->voiceGain, pSynth->masterVolume); + + /* initialize the operators */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + + /* establish operator output gain level */ + /*lint -e{701} <use shift for performance> */ + pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7); + + /* check for linear velocity flag */ + /*lint -e{703} <use shift for performance> */ + if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_LINEAR_VELOCITY) + temp = (EAS_I32) (pVoice->velocity - 127) << 5; + else + temp = (EAS_I32) fmControlTable[pVoice->velocity]; + + /* scale velocity */ + /*lint -e{704} use shift for performance */ + temp = (temp * (EAS_I32)(pRegion->oper[operIndex].velocityRelease & 0xf0)) >> 7; + + /* include key scalar */ + temp -= ((EAS_I32) pVoice->note - KEY_SCALE_PIVOT_POINT) * (EAS_I32) fmScaleTable[pRegion->oper[operIndex].egKeyScale & 0x0f]; + + /* saturate */ + temp = min(temp, 0); + temp = max(temp, -32768); + + /* save static gain parameters */ + pFMVoice->oper[operIndex].baseGain = (EAS_I16) EAS_LogToLinear16(temp); + + /* incorporate key scaling on decay rate */ + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + + /* if zero attack time, max out envelope and jump to decay state */ + if ((pRegion->oper[operIndex].attackDecay & 0xf0) == 0xf0) + { + + /* start out envelope at max */ + pFMVoice->oper[operIndex].envGain = 0x7fff; + + /* set envelope to decay state */ + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; + } + + /* start envelope at zero and start in attack state */ + else + { + pFMVoice->oper[operIndex].envGain = 0; + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateAttack; + } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateChannel() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static channel parameters + * These values only need to be updated if one of the controller values + * for this channel changes. + * Called when CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS flag is set. + * + * Inputs: + * nChannel - channel to update + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - the given channel's static gain and static pitch are updated + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) standard interface, pVoiceMgr not used */ +static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_I32 temp; + + pChannel = &pSynth->channels[channel]; + + /* convert CC7 volume controller to log scale */ + temp = fmControlTable[pChannel->volume]; + + /* incorporate CC11 expression controller */ + temp += fmControlTable[pChannel->expression]; + + /* saturate */ + pChannel->staticGain = (EAS_I16) max(temp,-32768); + + /* calculate pitch bend */ + /*lint -e{703} <avoid multiply for performance>*/ + temp = (((EAS_I32)(pChannel->pitchBend) << 2) - 32768); + + temp = FMUL_15x15(temp, pChannel->pitchBendSensitivity); + + /* include "magic number" compensation for sample rate and lookup table size */ + temp += MAGIC_NUMBER; + + /* if this is not a drum channel, then add in the per-channel tuning */ + if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) + temp += (pChannel->finePitch + (pChannel->coarsePitch * 100)); + + /* save static pitch */ + pChannel->staticPitch = temp; + + /* Calculate LFO modulation depth */ + /* mod wheel to LFO depth */ + temp = FMUL_15x15(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, + pChannel->modWheel << (NUM_EG1_FRAC_BITS -7)); + + /* channel pressure to LFO depth */ + pChannel->lfoAmt = (EAS_I16) (temp + + FMUL_15x15(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, + pChannel->channelPressure << (NUM_EG1_FRAC_BITS -7))); + + /* clear update flag */ + pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + return; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateLFO() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the LFO for the given voice + * + * Inputs: + * pVoice - ptr to the voice whose LFO we want to update + * psEASData - pointer to overall EAS data structure - used for debug only + * + * Outputs: + * + * Side Effects: + * - updates LFO values for the given voice + *---------------------------------------------------------------------------- +*/ +static void FM_UpdateLFO (S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion) +{ + + /* increment the LFO phase if the delay time has elapsed */ + if (!pFMVoice->lfoDelay) + { + /*lint -e{701} <use shift for performance> */ + pFMVoice->lfoPhase = pFMVoice->lfoPhase + (EAS_U16) (-fmControlTable[((15 - (pRegion->lfoFreqDelay >> 4)) << 3) + 4]); + + /* square wave LFO? */ + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_SQUARE_WAVE) + pFMVoice->lfoValue = (EAS_I16)(pFMVoice->lfoPhase & 0x8000 ? -32767 : 32767); + + /* trick to get a triangle wave out of a sawtooth */ + else + { + pFMVoice->lfoValue = (EAS_I16) (pFMVoice->lfoPhase << 1); + /*lint -e{502} <shortcut to turn sawtooth into sine wave> */ + if ((pFMVoice->lfoPhase > 0x3fff) && (pFMVoice->lfoPhase < 0xC000)) + pFMVoice->lfoValue = ~pFMVoice->lfoValue; + } + } + + /* still in delay */ + else + pFMVoice->lfoDelay--; + + return; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateEG() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the synthesis parameters for an operator to be used during + * the next buffer + * + * Inputs: + * pVoice - pointer to the voice being updated + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateEG (S_SYNTH_VOICE *pVoice, S_OPERATOR *pOper, const S_FM_OPER *pOperData, EAS_BOOL oneShot) +{ + EAS_U32 temp; + EAS_BOOL done; + + /* set flag assuming the envelope is not done */ + done = EAS_FALSE; + + /* take appropriate action based on state */ + switch (pOper->envState) + { + + case eFMEnvelopeStateAttack: + + /* the envelope is linear during the attack, so add the value */ + temp = pOper->envGain + fmAttackTable[pOperData->attackDecay >> 4]; + + /* check for end of attack */ + if (temp >= 0x7fff) + { + pOper->envGain = 0x7fff; + pOper->envState = eFMEnvelopeStateDecay; + } + else + pOper->envGain = (EAS_U16) temp; + break; + + case eFMEnvelopeStateDecay: + + /* decay is exponential, multiply by decay rate */ + pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); + + /* check for sustain level reached */ + temp = (EAS_U32) (pOperData->sustain & 0xfc) << 7; + if (pOper->envGain <= (EAS_U16) temp) + { + /* if this is a one-shot patch, go directly to release phase */ + if (oneShot) + { + pOper->envRate = FM_CalcEGRate( + pVoice->note, + fmReleaseTable[pOperData->velocityRelease & 0x0f], + fmScaleTable[pOperData->egKeyScale >> 4]); + pOper->envState = eFMEnvelopeStateRelease; + } + + /* normal sustaining type */ + else + { + pOper->envGain = (EAS_U16) temp; + pOper->envState = eFMEnvelopeStateSustain; + } + } + break; + + case eFMEnvelopeStateSustain: + pOper->envGain = (EAS_U16)((EAS_U16)(pOperData->sustain & 0xfc) << 7); + break; + + case eFMEnvelopeStateRelease: + + /* release is exponential, multiply by release rate */ + pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); + + /* fully released */ + if (pOper->envGain == 0) + { + pOper->envGain = 0; + pOper->envState = eFMEnvelopeStateMuted; + done = EAS_TRUE; + } + break; + + case eFMEnvelopeStateMuted: + pOper->envGain = 0; + done = EAS_TRUE; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid operator state: %d", pOper->envState); */ } + } /* end switch (pOper->m_eState) */ + + return done; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateDynamic() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the synthesis parameters for this voice that will be used to + * synthesize the next buffer + * + * Inputs: + * pVoice - pointer to the voice being updated + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Returns EAS_TRUE if voice will be fully ramped to zero at the end of + * the next synthesized buffer. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateDynamic (S_SYNTH_VOICE *pVoice, S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion, S_SYNTH_CHANNEL *pChannel) +{ + EAS_I32 temp; + EAS_I32 pitch; + EAS_I32 lfoPitch; + EAS_INT operIndex; + EAS_BOOL done; + + /* increment LFO phase */ + FM_UpdateLFO(pFMVoice, pRegion); + + /* base pitch in cents */ + pitch = pVoice->note * 100; + + /* LFO amount includes LFO depth from programming + channel dynamics */ + temp = (fmScaleTable[pRegion->vibTrem >> 4] >> 1) + pChannel->lfoAmt; + + /* multiply by LFO output to get final pitch modulation */ + lfoPitch = FMUL_15x15(pFMVoice->lfoValue, temp); + + /* flag to indicate this voice is done */ + done = EAS_TRUE; + + /* iterate through operators to establish parameters */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + EAS_BOOL bTemp; + + /* set base phase increment for each operator */ + temp = pRegion->oper[operIndex].tuning + + pChannel->staticPitch; + + /* add vibrato effect unless it is disabled for this operator */ + if ((pRegion->oper[operIndex].flags & FM_OPER_FLAG_NO_VIBRATO) == 0) + temp += lfoPitch; + + /* if note is monotonic, bias to MIDI note 60 */ + if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_MONOTONE) + temp += 6000; + else + temp += pitch; + pFMVoice->oper[operIndex].pitch = (EAS_I16) temp; + + /* calculate envelope, returns true if done */ + bTemp = FM_UpdateEG(pVoice, &pFMVoice->oper[operIndex], &pRegion->oper[operIndex], pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT); + + /* check if all output envelopes have completed */ + if (FM_SynthIsOutputOperator(pRegion, operIndex)) + done = done && bTemp; + } + + return done; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_SYNTH_CHANNEL *pChannel; + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + S_FM_VOICE_CONFIG vCfg; + S_FM_VOICE_FRAME vFrame; + EAS_I32 temp; + EAS_INT oper; + EAS_U16 voiceGainTarget; + EAS_BOOL done; + + /* setup some pointers */ + pChannel = GetChannelPtr(pSynth, pVoice); + pRegion = GetFMRegionPtr(pSynth, pVoice); + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + + /* if the voice is just starting, get the voice configuration data */ + if (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + { + + /* split architecture may limit the number of voice starts */ +#ifdef MAX_VOICE_STARTS + if (pVoiceMgr->numVoiceStarts == MAX_VOICE_STARTS) + return EAS_FALSE; + pVoiceMgr->numVoiceStarts++; +#endif + + /* get initial parameters */ + vCfg.feedback = pRegion->feedback; + vCfg.voiceGain = (EAS_U16) pFMVoice->voiceGain; + +#if (NUM_OUTPUT_CHANNELS == 2) + vCfg.pan = pFMVoice->pan; +#endif + + /* get voice mode */ + vCfg.flags = pRegion->region.keyGroupAndFlags & 7; + + /* get operator parameters */ + for (oper = 0; oper < 4; oper++) + { + /* calculate initial gain */ + vCfg.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); + vCfg.outputGain[oper] = pFMVoice->oper[oper].outputGain; + + /* copy noise waveform flag */ + if (pRegion->oper[oper].flags & FM_OPER_FLAG_NOISE) + vCfg.flags |= (EAS_U8) (FLAG_FM_ENG_VOICE_OP1_NOISE << oper); + } + +#ifdef FM_OFFBOARD + FM_ConfigVoice(voiceNum, &vCfg, pVoiceMgr->pFrameBuffer); +#else + FM_ConfigVoice(voiceNum, &vCfg, NULL); +#endif + + /* clear startup flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + } + + /* calculate new synthesis parameters */ + done = FM_UpdateDynamic(pVoice, pFMVoice, pRegion, pChannel); + + /* calculate LFO gain modulation */ + /*lint -e{702} <use shift for performance> */ + temp = ((fmScaleTable[pRegion->vibTrem & 0x0f] >> 1) * pFMVoice->lfoValue) >> FM_LFO_GAIN_SHIFT; + + /* include channel gain */ + temp += pChannel->staticGain; + + /* -32768 or lower is infinite attenuation */ + if (temp < -32767) + voiceGainTarget = 0; + + /* translate to linear gain multiplier */ + else + voiceGainTarget = EAS_LogToLinear16(temp); + + /* include synth master volume */ + voiceGainTarget = (EAS_U16) FMUL_15x15(voiceGainTarget, pSynth->masterVolume); + + /* save target values for this frame */ + vFrame.voiceGain = voiceGainTarget; + + /* assume voice output is zero */ + pVoice->gain = 0; + + /* save operator targets for this frame */ + for (oper = 0; oper < 4; oper++) + { + vFrame.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); + vFrame.pitch[oper] = pFMVoice->oper[oper].pitch; + + /* use the highest output envelope level as the gain for the voice stealing algorithm */ + if (FM_SynthIsOutputOperator(pRegion, oper)) + pVoice->gain = max(pVoice->gain, (EAS_I16) vFrame.gain[oper]); + } + + /* consider voice gain multiplier in calculating gain for stealing algorithm */ + pVoice->gain = (EAS_I16) FMUL_15x15(voiceGainTarget, pVoice->gain); + + /* synthesize samples */ +#ifdef FM_OFFBOARD + FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, pVoiceMgr->pFrameBuffer); +#else + FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, NULL); +#endif + + return done; +} + diff --git a/arm-fm-22k/lib_src/eas_fmsynth.h b/arm-fm-22k/lib_src/eas_fmsynth.h index 76f8adc..8ceda46 100644 --- a/arm-fm-22k/lib_src/eas_fmsynth.h +++ b/arm-fm-22k/lib_src/eas_fmsynth.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_fmsynth.h
- *
- * Contents and purpose:
- * Implements the FM synthesizer functions.
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_fmsynth.h + * + * Contents and purpose: + * Implements the FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,63 +19,63 @@ * 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: 90 $
- * $Date: 2006-07-11 20:18:13 -0700 (Tue, 11 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef fmsynthH
-#define fmsynthH
-
-#include "eas_data.h"
-
-#if defined (_FM_SYNTH)
-
-/* FM envelope state */
-typedef enum {
- eFMEnvelopeStateAttack = 0,
- eFMEnvelopeStateDecay,
- eFMEnvelopeStateSustain,
- eFMEnvelopeStateRelease,
- eFMEnvelopeStateMuted,
- eFMEnvelopeStateInvalid /* should never be in this state! */
-} E_FM_ENVELOPE_STATE;
-
-/*------------------------------------
- * S_OPERATOR data structure
- *------------------------------------
-*/
-typedef struct s_operator_tag
-{
- EAS_I16 pitch; /* operator pitch in cents */
- EAS_U16 envGain; /* envelope target */
- EAS_I16 baseGain; /* patch gain (inc. vel & key scale) */
- EAS_U16 outputGain; /* current output gain */
- EAS_U16 envRate; /* calculated envelope rate */
- EAS_U8 envState; /* envelope state */
- EAS_U8 pad; /* pad to 16-bits */
-} S_OPERATOR;
-#endif
-
-typedef struct s_fm_voice_tag
-{
- S_OPERATOR oper[4]; /* operator data */
- EAS_I16 voiceGain; /* LFO + channel parameters */
- EAS_U16 lfoPhase; /* LFO current phase */
- EAS_I16 lfoValue; /* LFO current value */
- EAS_U16 lfoDelay; /* keeps track of elapsed delay time */
- EAS_I8 pan; /* stereo pan value (-64 to +64) */
- EAS_I8 pad; /* reserved to maintain alignment */
-} S_FM_VOICE;
-
-#ifdef _FM_EDITOR
-extern S_FM_REGION newPatch;
-extern S_FM_REGION OriginalPatch;
-#endif
-
-extern EAS_U32 freqTable[];
-
-#endif
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 90 $ + * $Date: 2006-07-11 20:18:13 -0700 (Tue, 11 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef fmsynthH +#define fmsynthH + +#include "eas_data.h" + +#if defined (_FM_SYNTH) + +/* FM envelope state */ +typedef enum { + eFMEnvelopeStateAttack = 0, + eFMEnvelopeStateDecay, + eFMEnvelopeStateSustain, + eFMEnvelopeStateRelease, + eFMEnvelopeStateMuted, + eFMEnvelopeStateInvalid /* should never be in this state! */ +} E_FM_ENVELOPE_STATE; + +/*------------------------------------ + * S_OPERATOR data structure + *------------------------------------ +*/ +typedef struct s_operator_tag +{ + EAS_I16 pitch; /* operator pitch in cents */ + EAS_U16 envGain; /* envelope target */ + EAS_I16 baseGain; /* patch gain (inc. vel & key scale) */ + EAS_U16 outputGain; /* current output gain */ + EAS_U16 envRate; /* calculated envelope rate */ + EAS_U8 envState; /* envelope state */ + EAS_U8 pad; /* pad to 16-bits */ +} S_OPERATOR; +#endif + +typedef struct s_fm_voice_tag +{ + S_OPERATOR oper[4]; /* operator data */ + EAS_I16 voiceGain; /* LFO + channel parameters */ + EAS_U16 lfoPhase; /* LFO current phase */ + EAS_I16 lfoValue; /* LFO current value */ + EAS_U16 lfoDelay; /* keeps track of elapsed delay time */ + EAS_I8 pan; /* stereo pan value (-64 to +64) */ + EAS_I8 pad; /* reserved to maintain alignment */ +} S_FM_VOICE; + +#ifdef _FM_EDITOR +extern S_FM_REGION newPatch; +extern S_FM_REGION OriginalPatch; +#endif + +extern EAS_U32 freqTable[]; + +#endif diff --git a/arm-fm-22k/lib_src/eas_fmtables.c b/arm-fm-22k/lib_src/eas_fmtables.c index 25c6961..a8ff0a2 100644 --- a/arm-fm-22k/lib_src/eas_fmtables.c +++ b/arm-fm-22k/lib_src/eas_fmtables.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_fmtables.c
- *
- * Contents and purpose:
- * Contains lookup tables for the FM synthesizer
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_fmtables.c + * + * Contents and purpose: + * Contains lookup tables for the FM synthesizer + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,349 +20,349 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *
- *----------------------------------------------------------------------------
-*/
-
-
-#include "eas_types.h"
-
-/* this table is needed by the DSP and the main processor */
-const EAS_U8 fmScaleTable[16] =
-{
- 0,8,16,24,32,40,48,56,64,72,80,96,128,160,192,255
-};
-
-/* these tables are needed on the main processor */
-#ifndef _DSP_CODE
-const EAS_I16 fmControlTable[128] =
-{
- -32768,-14313,-12265,-11067,-10217,-9558,-9019,-8563,
- -8169,-7821,-7510,-7228,-6971,-6734,-6515,-6312,
- -6121,-5942,-5773,-5613,-5462,-5317,-5180,-5049,
- -4923,-4802,-4686,-4575,-4467,-4364,-4264,-4167,
- -4073,-3982,-3894,-3808,-3725,-3644,-3565,-3488,
- -3414,-3341,-3269,-3200,-3132,-3066,-3001,-2937,
- -2875,-2814,-2754,-2696,-2638,-2582,-2527,-2473,
- -2419,-2367,-2316,-2265,-2216,-2167,-2119,-2071,
- -2025,-1979,-1934,-1889,-1846,-1803,-1760,-1718,
- -1677,-1636,-1596,-1556,-1517,-1478,-1440,-1403,
- -1366,-1329,-1293,-1257,-1221,-1186,-1152,-1118,
- -1084,-1051,-1018,-985,-953,-921,-889,-858,
- -827,-796,-766,-736,-706,-677,-648,-619,
- -590,-562,-534,-506,-479,-452,-425,-398,
- -371,-345,-319,-293,-268,-242,-217,-192,
- -168,-143,-119,-95,-71,-47,-23,0
-};
-
-const EAS_U16 fmRateTable[128] =
-{
- 32767,32764,32758,32747,32731,32712,32688,32659,
- 32627,32590,32548,32503,32453,32398,32340,32277,
- 32211,32140,32065,31985,31902,31815,31724,31628,
- 31529,31426,31319,31208,31094,30976,30854,30728,
- 30599,30466,30330,30191,30048,29902,29752,29599,
- 29443,29285,29123,28958,28790,28619,28445,28269,
- 28090,27909,27725,27538,27349,27158,26964,26769,
- 26571,26371,26169,25965,25760,25552,25343,25132,
- 24920,24706,24490,24274,24056,23836,23616,23394,
- 23172,22948,22724,22499,22273,22046,21819,21591,
- 21363,21135,20906,20676,20447,20217,19987,19758,
- 19528,19298,19069,18840,18610,18382,18153,17926,
- 17698,17471,17245,17020,16795,16571,16347,16125,
- 15903,15683,15463,15245,15027,14811,14596,14382,
- 14169,13957,13747,13538,13331,13125,12920,12717,
- 12516,12316,12117,11921,11725,11532,11340,0
-};
-
-const EAS_U16 fmAttackTable[15] =
-{
- 27,54,109,327,655,1310,2730,4095,
- 4681,5461,6553,8191,10922,16383,32767
-};
-
-const EAS_U8 fmDecayTable[16] =
-{
- 4,7,10,15,20,25,30,35,40,50,60,70,80,90,100,127
-};
-
-const EAS_U8 fmReleaseTable[16] =
-{
- 10,15,20,25,30,35,40,45,50,60,70,80,90,100,113,127
-};
-#endif
-
-/* this table is needed only on the DSP */
-#if defined(_DSP_CODE) || !defined(_SPLIT_ARCHITECTURE)
-//---------------------------------------------------------------------
-// sineTable
-//
-// Contains sine lookup table
-//---------------------------------------------------------------------
-
-const EAS_I16 sineTable[2048] =
-{
- 0,101,201,302,402,503,603,704,
- 804,905,1005,1106,1206,1307,1407,1507,
- 1608,1708,1809,1909,2009,2110,2210,2310,
- 2410,2511,2611,2711,2811,2911,3012,3112,
- 3212,3312,3412,3512,3612,3712,3811,3911,
- 4011,4111,4210,4310,4410,4509,4609,4708,
- 4808,4907,5007,5106,5205,5305,5404,5503,
- 5602,5701,5800,5899,5998,6096,6195,6294,
- 6393,6491,6590,6688,6786,6885,6983,7081,
- 7179,7277,7375,7473,7571,7669,7767,7864,
- 7962,8059,8157,8254,8351,8448,8545,8642,
- 8739,8836,8933,9030,9126,9223,9319,9416,
- 9512,9608,9704,9800,9896,9992,10087,10183,
- 10278,10374,10469,10564,10659,10754,10849,10944,
- 11039,11133,11228,11322,11417,11511,11605,11699,
- 11793,11886,11980,12074,12167,12260,12353,12446,
- 12539,12632,12725,12817,12910,13002,13094,13187,
- 13279,13370,13462,13554,13645,13736,13828,13919,
- 14010,14101,14191,14282,14372,14462,14553,14643,
- 14732,14822,14912,15001,15090,15180,15269,15358,
- 15446,15535,15623,15712,15800,15888,15976,16063,
- 16151,16238,16325,16413,16499,16586,16673,16759,
- 16846,16932,17018,17104,17189,17275,17360,17445,
- 17530,17615,17700,17784,17869,17953,18037,18121,
- 18204,18288,18371,18454,18537,18620,18703,18785,
- 18868,18950,19032,19113,19195,19276,19357,19438,
- 19519,19600,19680,19761,19841,19921,20000,20080,
- 20159,20238,20317,20396,20475,20553,20631,20709,
- 20787,20865,20942,21019,21096,21173,21250,21326,
- 21403,21479,21554,21630,21705,21781,21856,21930,
- 22005,22079,22154,22227,22301,22375,22448,22521,
- 22594,22667,22739,22812,22884,22956,23027,23099,
- 23170,23241,23311,23382,23452,23522,23592,23662,
- 23731,23801,23870,23938,24007,24075,24143,24211,
- 24279,24346,24413,24480,24547,24613,24680,24746,
- 24811,24877,24942,25007,25072,25137,25201,25265,
- 25329,25393,25456,25519,25582,25645,25708,25770,
- 25832,25893,25955,26016,26077,26138,26198,26259,
- 26319,26378,26438,26497,26556,26615,26674,26732,
- 26790,26848,26905,26962,27019,27076,27133,27189,
- 27245,27300,27356,27411,27466,27521,27575,27629,
- 27683,27737,27790,27843,27896,27949,28001,28053,
- 28105,28157,28208,28259,28310,28360,28411,28460,
- 28510,28560,28609,28658,28706,28755,28803,28850,
- 28898,28945,28992,29039,29085,29131,29177,29223,
- 29268,29313,29358,29403,29447,29491,29534,29578,
- 29621,29664,29706,29749,29791,29832,29874,29915,
- 29956,29997,30037,30077,30117,30156,30195,30234,
- 30273,30311,30349,30387,30424,30462,30498,30535,
- 30571,30607,30643,30679,30714,30749,30783,30818,
- 30852,30885,30919,30952,30985,31017,31050,31082,
- 31113,31145,31176,31206,31237,31267,31297,31327,
- 31356,31385,31414,31442,31470,31498,31526,31553,
- 31580,31607,31633,31659,31685,31710,31736,31760,
- 31785,31809,31833,31857,31880,31903,31926,31949,
- 31971,31993,32014,32036,32057,32077,32098,32118,
- 32137,32157,32176,32195,32213,32232,32250,32267,
- 32285,32302,32318,32335,32351,32367,32382,32397,
- 32412,32427,32441,32455,32469,32482,32495,32508,
- 32521,32533,32545,32556,32567,32578,32589,32599,
- 32609,32619,32628,32637,32646,32655,32663,32671,
- 32678,32685,32692,32699,32705,32711,32717,32722,
- 32728,32732,32737,32741,32745,32748,32752,32755,
- 32757,32759,32761,32763,32765,32766,32766,32767,
- 32767,32767,32766,32766,32765,32763,32761,32759,
- 32757,32755,32752,32748,32745,32741,32737,32732,
- 32728,32722,32717,32711,32705,32699,32692,32685,
- 32678,32671,32663,32655,32646,32637,32628,32619,
- 32609,32599,32589,32578,32567,32556,32545,32533,
- 32521,32508,32495,32482,32469,32455,32441,32427,
- 32412,32397,32382,32367,32351,32335,32318,32302,
- 32285,32267,32250,32232,32213,32195,32176,32157,
- 32137,32118,32098,32077,32057,32036,32014,31993,
- 31971,31949,31926,31903,31880,31857,31833,31809,
- 31785,31760,31736,31710,31685,31659,31633,31607,
- 31580,31553,31526,31498,31470,31442,31414,31385,
- 31356,31327,31297,31267,31237,31206,31176,31145,
- 31113,31082,31050,31017,30985,30952,30919,30885,
- 30852,30818,30783,30749,30714,30679,30643,30607,
- 30571,30535,30498,30462,30424,30387,30349,30311,
- 30273,30234,30195,30156,30117,30077,30037,29997,
- 29956,29915,29874,29832,29791,29749,29706,29664,
- 29621,29578,29534,29491,29447,29403,29358,29313,
- 29268,29223,29177,29131,29085,29039,28992,28945,
- 28898,28850,28803,28755,28706,28658,28609,28560,
- 28510,28460,28411,28360,28310,28259,28208,28157,
- 28105,28053,28001,27949,27896,27843,27790,27737,
- 27683,27629,27575,27521,27466,27411,27356,27300,
- 27245,27189,27133,27076,27019,26962,26905,26848,
- 26790,26732,26674,26615,26556,26497,26438,26378,
- 26319,26259,26198,26138,26077,26016,25955,25893,
- 25832,25770,25708,25645,25582,25519,25456,25393,
- 25329,25265,25201,25137,25072,25007,24942,24877,
- 24811,24746,24680,24613,24547,24480,24413,24346,
- 24279,24211,24143,24075,24007,23938,23870,23801,
- 23731,23662,23592,23522,23452,23382,23311,23241,
- 23170,23099,23027,22956,22884,22812,22739,22667,
- 22594,22521,22448,22375,22301,22227,22154,22079,
- 22005,21930,21856,21781,21705,21630,21554,21479,
- 21403,21326,21250,21173,21096,21019,20942,20865,
- 20787,20709,20631,20553,20475,20396,20317,20238,
- 20159,20080,20000,19921,19841,19761,19680,19600,
- 19519,19438,19357,19276,19195,19113,19032,18950,
- 18868,18785,18703,18620,18537,18454,18371,18288,
- 18204,18121,18037,17953,17869,17784,17700,17615,
- 17530,17445,17360,17275,17189,17104,17018,16932,
- 16846,16759,16673,16586,16499,16413,16325,16238,
- 16151,16063,15976,15888,15800,15712,15623,15535,
- 15446,15358,15269,15180,15090,15001,14912,14822,
- 14732,14643,14553,14462,14372,14282,14191,14101,
- 14010,13919,13828,13736,13645,13554,13462,13370,
- 13279,13187,13094,13002,12910,12817,12725,12632,
- 12539,12446,12353,12260,12167,12074,11980,11886,
- 11793,11699,11605,11511,11417,11322,11228,11133,
- 11039,10944,10849,10754,10659,10564,10469,10374,
- 10278,10183,10087,9992,9896,9800,9704,9608,
- 9512,9416,9319,9223,9126,9030,8933,8836,
- 8739,8642,8545,8448,8351,8254,8157,8059,
- 7962,7864,7767,7669,7571,7473,7375,7277,
- 7179,7081,6983,6885,6786,6688,6590,6491,
- 6393,6294,6195,6096,5998,5899,5800,5701,
- 5602,5503,5404,5305,5205,5106,5007,4907,
- 4808,4708,4609,4509,4410,4310,4210,4111,
- 4011,3911,3811,3712,3612,3512,3412,3312,
- 3212,3112,3012,2911,2811,2711,2611,2511,
- 2410,2310,2210,2110,2009,1909,1809,1708,
- 1608,1507,1407,1307,1206,1106,1005,905,
- 804,704,603,503,402,302,201,101,
- 0,-101,-201,-302,-402,-503,-603,-704,
- -804,-905,-1005,-1106,-1206,-1307,-1407,-1507,
- -1608,-1708,-1809,-1909,-2009,-2110,-2210,-2310,
- -2410,-2511,-2611,-2711,-2811,-2911,-3012,-3112,
- -3212,-3312,-3412,-3512,-3612,-3712,-3811,-3911,
- -4011,-4111,-4210,-4310,-4410,-4509,-4609,-4708,
- -4808,-4907,-5007,-5106,-5205,-5305,-5404,-5503,
- -5602,-5701,-5800,-5899,-5998,-6096,-6195,-6294,
- -6393,-6491,-6590,-6688,-6786,-6885,-6983,-7081,
- -7179,-7277,-7375,-7473,-7571,-7669,-7767,-7864,
- -7962,-8059,-8157,-8254,-8351,-8448,-8545,-8642,
- -8739,-8836,-8933,-9030,-9126,-9223,-9319,-9416,
- -9512,-9608,-9704,-9800,-9896,-9992,-10087,-10183,
- -10278,-10374,-10469,-10564,-10659,-10754,-10849,-10944,
- -11039,-11133,-11228,-11322,-11417,-11511,-11605,-11699,
- -11793,-11886,-11980,-12074,-12167,-12260,-12353,-12446,
- -12539,-12632,-12725,-12817,-12910,-13002,-13094,-13187,
- -13279,-13370,-13462,-13554,-13645,-13736,-13828,-13919,
- -14010,-14101,-14191,-14282,-14372,-14462,-14553,-14643,
- -14732,-14822,-14912,-15001,-15090,-15180,-15269,-15358,
- -15446,-15535,-15623,-15712,-15800,-15888,-15976,-16063,
- -16151,-16238,-16325,-16413,-16499,-16586,-16673,-16759,
- -16846,-16932,-17018,-17104,-17189,-17275,-17360,-17445,
- -17530,-17615,-17700,-17784,-17869,-17953,-18037,-18121,
- -18204,-18288,-18371,-18454,-18537,-18620,-18703,-18785,
- -18868,-18950,-19032,-19113,-19195,-19276,-19357,-19438,
- -19519,-19600,-19680,-19761,-19841,-19921,-20000,-20080,
- -20159,-20238,-20317,-20396,-20475,-20553,-20631,-20709,
- -20787,-20865,-20942,-21019,-21096,-21173,-21250,-21326,
- -21403,-21479,-21554,-21630,-21705,-21781,-21856,-21930,
- -22005,-22079,-22154,-22227,-22301,-22375,-22448,-22521,
- -22594,-22667,-22739,-22812,-22884,-22956,-23027,-23099,
- -23170,-23241,-23311,-23382,-23452,-23522,-23592,-23662,
- -23731,-23801,-23870,-23938,-24007,-24075,-24143,-24211,
- -24279,-24346,-24413,-24480,-24547,-24613,-24680,-24746,
- -24811,-24877,-24942,-25007,-25072,-25137,-25201,-25265,
- -25329,-25393,-25456,-25519,-25582,-25645,-25708,-25770,
- -25832,-25893,-25955,-26016,-26077,-26138,-26198,-26259,
- -26319,-26378,-26438,-26497,-26556,-26615,-26674,-26732,
- -26790,-26848,-26905,-26962,-27019,-27076,-27133,-27189,
- -27245,-27300,-27356,-27411,-27466,-27521,-27575,-27629,
- -27683,-27737,-27790,-27843,-27896,-27949,-28001,-28053,
- -28105,-28157,-28208,-28259,-28310,-28360,-28411,-28460,
- -28510,-28560,-28609,-28658,-28706,-28755,-28803,-28850,
- -28898,-28945,-28992,-29039,-29085,-29131,-29177,-29223,
- -29268,-29313,-29358,-29403,-29447,-29491,-29534,-29578,
- -29621,-29664,-29706,-29749,-29791,-29832,-29874,-29915,
- -29956,-29997,-30037,-30077,-30117,-30156,-30195,-30234,
- -30273,-30311,-30349,-30387,-30424,-30462,-30498,-30535,
- -30571,-30607,-30643,-30679,-30714,-30749,-30783,-30818,
- -30852,-30885,-30919,-30952,-30985,-31017,-31050,-31082,
- -31113,-31145,-31176,-31206,-31237,-31267,-31297,-31327,
- -31356,-31385,-31414,-31442,-31470,-31498,-31526,-31553,
- -31580,-31607,-31633,-31659,-31685,-31710,-31736,-31760,
- -31785,-31809,-31833,-31857,-31880,-31903,-31926,-31949,
- -31971,-31993,-32014,-32036,-32057,-32077,-32098,-32118,
- -32137,-32157,-32176,-32195,-32213,-32232,-32250,-32267,
- -32285,-32302,-32318,-32335,-32351,-32367,-32382,-32397,
- -32412,-32427,-32441,-32455,-32469,-32482,-32495,-32508,
- -32521,-32533,-32545,-32556,-32567,-32578,-32589,-32599,
- -32609,-32619,-32628,-32637,-32646,-32655,-32663,-32671,
- -32678,-32685,-32692,-32699,-32705,-32711,-32717,-32722,
- -32728,-32732,-32737,-32741,-32745,-32748,-32752,-32755,
- -32757,-32759,-32761,-32763,-32765,-32766,-32766,-32767,
- -32767,-32767,-32766,-32766,-32765,-32763,-32761,-32759,
- -32757,-32755,-32752,-32748,-32745,-32741,-32737,-32732,
- -32728,-32722,-32717,-32711,-32705,-32699,-32692,-32685,
- -32678,-32671,-32663,-32655,-32646,-32637,-32628,-32619,
- -32609,-32599,-32589,-32578,-32567,-32556,-32545,-32533,
- -32521,-32508,-32495,-32482,-32469,-32455,-32441,-32427,
- -32412,-32397,-32382,-32367,-32351,-32335,-32318,-32302,
- -32285,-32267,-32250,-32232,-32213,-32195,-32176,-32157,
- -32137,-32118,-32098,-32077,-32057,-32036,-32014,-31993,
- -31971,-31949,-31926,-31903,-31880,-31857,-31833,-31809,
- -31785,-31760,-31736,-31710,-31685,-31659,-31633,-31607,
- -31580,-31553,-31526,-31498,-31470,-31442,-31414,-31385,
- -31356,-31327,-31297,-31267,-31237,-31206,-31176,-31145,
- -31113,-31082,-31050,-31017,-30985,-30952,-30919,-30885,
- -30852,-30818,-30783,-30749,-30714,-30679,-30643,-30607,
- -30571,-30535,-30498,-30462,-30424,-30387,-30349,-30311,
- -30273,-30234,-30195,-30156,-30117,-30077,-30037,-29997,
- -29956,-29915,-29874,-29832,-29791,-29749,-29706,-29664,
- -29621,-29578,-29534,-29491,-29447,-29403,-29358,-29313,
- -29268,-29223,-29177,-29131,-29085,-29039,-28992,-28945,
- -28898,-28850,-28803,-28755,-28706,-28658,-28609,-28560,
- -28510,-28460,-28411,-28360,-28310,-28259,-28208,-28157,
- -28105,-28053,-28001,-27949,-27896,-27843,-27790,-27737,
- -27683,-27629,-27575,-27521,-27466,-27411,-27356,-27300,
- -27245,-27189,-27133,-27076,-27019,-26962,-26905,-26848,
- -26790,-26732,-26674,-26615,-26556,-26497,-26438,-26378,
- -26319,-26259,-26198,-26138,-26077,-26016,-25955,-25893,
- -25832,-25770,-25708,-25645,-25582,-25519,-25456,-25393,
- -25329,-25265,-25201,-25137,-25072,-25007,-24942,-24877,
- -24811,-24746,-24680,-24613,-24547,-24480,-24413,-24346,
- -24279,-24211,-24143,-24075,-24007,-23938,-23870,-23801,
- -23731,-23662,-23592,-23522,-23452,-23382,-23311,-23241,
- -23170,-23099,-23027,-22956,-22884,-22812,-22739,-22667,
- -22594,-22521,-22448,-22375,-22301,-22227,-22154,-22079,
- -22005,-21930,-21856,-21781,-21705,-21630,-21554,-21479,
- -21403,-21326,-21250,-21173,-21096,-21019,-20942,-20865,
- -20787,-20709,-20631,-20553,-20475,-20396,-20317,-20238,
- -20159,-20080,-20000,-19921,-19841,-19761,-19680,-19600,
- -19519,-19438,-19357,-19276,-19195,-19113,-19032,-18950,
- -18868,-18785,-18703,-18620,-18537,-18454,-18371,-18288,
- -18204,-18121,-18037,-17953,-17869,-17784,-17700,-17615,
- -17530,-17445,-17360,-17275,-17189,-17104,-17018,-16932,
- -16846,-16759,-16673,-16586,-16499,-16413,-16325,-16238,
- -16151,-16063,-15976,-15888,-15800,-15712,-15623,-15535,
- -15446,-15358,-15269,-15180,-15090,-15001,-14912,-14822,
- -14732,-14643,-14553,-14462,-14372,-14282,-14191,-14101,
- -14010,-13919,-13828,-13736,-13645,-13554,-13462,-13370,
- -13279,-13187,-13094,-13002,-12910,-12817,-12725,-12632,
- -12539,-12446,-12353,-12260,-12167,-12074,-11980,-11886,
- -11793,-11699,-11605,-11511,-11417,-11322,-11228,-11133,
- -11039,-10944,-10849,-10754,-10659,-10564,-10469,-10374,
- -10278,-10183,-10087,-9992,-9896,-9800,-9704,-9608,
- -9512,-9416,-9319,-9223,-9126,-9030,-8933,-8836,
- -8739,-8642,-8545,-8448,-8351,-8254,-8157,-8059,
- -7962,-7864,-7767,-7669,-7571,-7473,-7375,-7277,
- -7179,-7081,-6983,-6885,-6786,-6688,-6590,-6491,
- -6393,-6294,-6195,-6096,-5998,-5899,-5800,-5701,
- -5602,-5503,-5404,-5305,-5205,-5106,-5007,-4907,
- -4808,-4708,-4609,-4509,-4410,-4310,-4210,-4111,
- -4011,-3911,-3811,-3712,-3612,-3512,-3412,-3312,
- -3212,-3112,-3012,-2911,-2811,-2711,-2611,-2511,
- -2410,-2310,-2210,-2110,-2009,-1909,-1809,-1708,
- -1608,-1507,-1407,-1307,-1206,-1106,-1005,-905,
- -804,-704,-603,-503,-402,-302,-201,-101
-};
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + * + *---------------------------------------------------------------------------- +*/ + + +#include "eas_types.h" + +/* this table is needed by the DSP and the main processor */ +const EAS_U8 fmScaleTable[16] = +{ + 0,8,16,24,32,40,48,56,64,72,80,96,128,160,192,255 +}; + +/* these tables are needed on the main processor */ +#ifndef _DSP_CODE +const EAS_I16 fmControlTable[128] = +{ + -32768,-14313,-12265,-11067,-10217,-9558,-9019,-8563, + -8169,-7821,-7510,-7228,-6971,-6734,-6515,-6312, + -6121,-5942,-5773,-5613,-5462,-5317,-5180,-5049, + -4923,-4802,-4686,-4575,-4467,-4364,-4264,-4167, + -4073,-3982,-3894,-3808,-3725,-3644,-3565,-3488, + -3414,-3341,-3269,-3200,-3132,-3066,-3001,-2937, + -2875,-2814,-2754,-2696,-2638,-2582,-2527,-2473, + -2419,-2367,-2316,-2265,-2216,-2167,-2119,-2071, + -2025,-1979,-1934,-1889,-1846,-1803,-1760,-1718, + -1677,-1636,-1596,-1556,-1517,-1478,-1440,-1403, + -1366,-1329,-1293,-1257,-1221,-1186,-1152,-1118, + -1084,-1051,-1018,-985,-953,-921,-889,-858, + -827,-796,-766,-736,-706,-677,-648,-619, + -590,-562,-534,-506,-479,-452,-425,-398, + -371,-345,-319,-293,-268,-242,-217,-192, + -168,-143,-119,-95,-71,-47,-23,0 +}; + +const EAS_U16 fmRateTable[128] = +{ + 32767,32764,32758,32747,32731,32712,32688,32659, + 32627,32590,32548,32503,32453,32398,32340,32277, + 32211,32140,32065,31985,31902,31815,31724,31628, + 31529,31426,31319,31208,31094,30976,30854,30728, + 30599,30466,30330,30191,30048,29902,29752,29599, + 29443,29285,29123,28958,28790,28619,28445,28269, + 28090,27909,27725,27538,27349,27158,26964,26769, + 26571,26371,26169,25965,25760,25552,25343,25132, + 24920,24706,24490,24274,24056,23836,23616,23394, + 23172,22948,22724,22499,22273,22046,21819,21591, + 21363,21135,20906,20676,20447,20217,19987,19758, + 19528,19298,19069,18840,18610,18382,18153,17926, + 17698,17471,17245,17020,16795,16571,16347,16125, + 15903,15683,15463,15245,15027,14811,14596,14382, + 14169,13957,13747,13538,13331,13125,12920,12717, + 12516,12316,12117,11921,11725,11532,11340,0 +}; + +const EAS_U16 fmAttackTable[15] = +{ + 27,54,109,327,655,1310,2730,4095, + 4681,5461,6553,8191,10922,16383,32767 +}; + +const EAS_U8 fmDecayTable[16] = +{ + 4,7,10,15,20,25,30,35,40,50,60,70,80,90,100,127 +}; + +const EAS_U8 fmReleaseTable[16] = +{ + 10,15,20,25,30,35,40,45,50,60,70,80,90,100,113,127 +}; +#endif + +/* this table is needed only on the DSP */ +#if defined(_DSP_CODE) || !defined(_SPLIT_ARCHITECTURE) +//--------------------------------------------------------------------- +// sineTable +// +// Contains sine lookup table +//--------------------------------------------------------------------- + +const EAS_I16 sineTable[2048] = +{ + 0,101,201,302,402,503,603,704, + 804,905,1005,1106,1206,1307,1407,1507, + 1608,1708,1809,1909,2009,2110,2210,2310, + 2410,2511,2611,2711,2811,2911,3012,3112, + 3212,3312,3412,3512,3612,3712,3811,3911, + 4011,4111,4210,4310,4410,4509,4609,4708, + 4808,4907,5007,5106,5205,5305,5404,5503, + 5602,5701,5800,5899,5998,6096,6195,6294, + 6393,6491,6590,6688,6786,6885,6983,7081, + 7179,7277,7375,7473,7571,7669,7767,7864, + 7962,8059,8157,8254,8351,8448,8545,8642, + 8739,8836,8933,9030,9126,9223,9319,9416, + 9512,9608,9704,9800,9896,9992,10087,10183, + 10278,10374,10469,10564,10659,10754,10849,10944, + 11039,11133,11228,11322,11417,11511,11605,11699, + 11793,11886,11980,12074,12167,12260,12353,12446, + 12539,12632,12725,12817,12910,13002,13094,13187, + 13279,13370,13462,13554,13645,13736,13828,13919, + 14010,14101,14191,14282,14372,14462,14553,14643, + 14732,14822,14912,15001,15090,15180,15269,15358, + 15446,15535,15623,15712,15800,15888,15976,16063, + 16151,16238,16325,16413,16499,16586,16673,16759, + 16846,16932,17018,17104,17189,17275,17360,17445, + 17530,17615,17700,17784,17869,17953,18037,18121, + 18204,18288,18371,18454,18537,18620,18703,18785, + 18868,18950,19032,19113,19195,19276,19357,19438, + 19519,19600,19680,19761,19841,19921,20000,20080, + 20159,20238,20317,20396,20475,20553,20631,20709, + 20787,20865,20942,21019,21096,21173,21250,21326, + 21403,21479,21554,21630,21705,21781,21856,21930, + 22005,22079,22154,22227,22301,22375,22448,22521, + 22594,22667,22739,22812,22884,22956,23027,23099, + 23170,23241,23311,23382,23452,23522,23592,23662, + 23731,23801,23870,23938,24007,24075,24143,24211, + 24279,24346,24413,24480,24547,24613,24680,24746, + 24811,24877,24942,25007,25072,25137,25201,25265, + 25329,25393,25456,25519,25582,25645,25708,25770, + 25832,25893,25955,26016,26077,26138,26198,26259, + 26319,26378,26438,26497,26556,26615,26674,26732, + 26790,26848,26905,26962,27019,27076,27133,27189, + 27245,27300,27356,27411,27466,27521,27575,27629, + 27683,27737,27790,27843,27896,27949,28001,28053, + 28105,28157,28208,28259,28310,28360,28411,28460, + 28510,28560,28609,28658,28706,28755,28803,28850, + 28898,28945,28992,29039,29085,29131,29177,29223, + 29268,29313,29358,29403,29447,29491,29534,29578, + 29621,29664,29706,29749,29791,29832,29874,29915, + 29956,29997,30037,30077,30117,30156,30195,30234, + 30273,30311,30349,30387,30424,30462,30498,30535, + 30571,30607,30643,30679,30714,30749,30783,30818, + 30852,30885,30919,30952,30985,31017,31050,31082, + 31113,31145,31176,31206,31237,31267,31297,31327, + 31356,31385,31414,31442,31470,31498,31526,31553, + 31580,31607,31633,31659,31685,31710,31736,31760, + 31785,31809,31833,31857,31880,31903,31926,31949, + 31971,31993,32014,32036,32057,32077,32098,32118, + 32137,32157,32176,32195,32213,32232,32250,32267, + 32285,32302,32318,32335,32351,32367,32382,32397, + 32412,32427,32441,32455,32469,32482,32495,32508, + 32521,32533,32545,32556,32567,32578,32589,32599, + 32609,32619,32628,32637,32646,32655,32663,32671, + 32678,32685,32692,32699,32705,32711,32717,32722, + 32728,32732,32737,32741,32745,32748,32752,32755, + 32757,32759,32761,32763,32765,32766,32766,32767, + 32767,32767,32766,32766,32765,32763,32761,32759, + 32757,32755,32752,32748,32745,32741,32737,32732, + 32728,32722,32717,32711,32705,32699,32692,32685, + 32678,32671,32663,32655,32646,32637,32628,32619, + 32609,32599,32589,32578,32567,32556,32545,32533, + 32521,32508,32495,32482,32469,32455,32441,32427, + 32412,32397,32382,32367,32351,32335,32318,32302, + 32285,32267,32250,32232,32213,32195,32176,32157, + 32137,32118,32098,32077,32057,32036,32014,31993, + 31971,31949,31926,31903,31880,31857,31833,31809, + 31785,31760,31736,31710,31685,31659,31633,31607, + 31580,31553,31526,31498,31470,31442,31414,31385, + 31356,31327,31297,31267,31237,31206,31176,31145, + 31113,31082,31050,31017,30985,30952,30919,30885, + 30852,30818,30783,30749,30714,30679,30643,30607, + 30571,30535,30498,30462,30424,30387,30349,30311, + 30273,30234,30195,30156,30117,30077,30037,29997, + 29956,29915,29874,29832,29791,29749,29706,29664, + 29621,29578,29534,29491,29447,29403,29358,29313, + 29268,29223,29177,29131,29085,29039,28992,28945, + 28898,28850,28803,28755,28706,28658,28609,28560, + 28510,28460,28411,28360,28310,28259,28208,28157, + 28105,28053,28001,27949,27896,27843,27790,27737, + 27683,27629,27575,27521,27466,27411,27356,27300, + 27245,27189,27133,27076,27019,26962,26905,26848, + 26790,26732,26674,26615,26556,26497,26438,26378, + 26319,26259,26198,26138,26077,26016,25955,25893, + 25832,25770,25708,25645,25582,25519,25456,25393, + 25329,25265,25201,25137,25072,25007,24942,24877, + 24811,24746,24680,24613,24547,24480,24413,24346, + 24279,24211,24143,24075,24007,23938,23870,23801, + 23731,23662,23592,23522,23452,23382,23311,23241, + 23170,23099,23027,22956,22884,22812,22739,22667, + 22594,22521,22448,22375,22301,22227,22154,22079, + 22005,21930,21856,21781,21705,21630,21554,21479, + 21403,21326,21250,21173,21096,21019,20942,20865, + 20787,20709,20631,20553,20475,20396,20317,20238, + 20159,20080,20000,19921,19841,19761,19680,19600, + 19519,19438,19357,19276,19195,19113,19032,18950, + 18868,18785,18703,18620,18537,18454,18371,18288, + 18204,18121,18037,17953,17869,17784,17700,17615, + 17530,17445,17360,17275,17189,17104,17018,16932, + 16846,16759,16673,16586,16499,16413,16325,16238, + 16151,16063,15976,15888,15800,15712,15623,15535, + 15446,15358,15269,15180,15090,15001,14912,14822, + 14732,14643,14553,14462,14372,14282,14191,14101, + 14010,13919,13828,13736,13645,13554,13462,13370, + 13279,13187,13094,13002,12910,12817,12725,12632, + 12539,12446,12353,12260,12167,12074,11980,11886, + 11793,11699,11605,11511,11417,11322,11228,11133, + 11039,10944,10849,10754,10659,10564,10469,10374, + 10278,10183,10087,9992,9896,9800,9704,9608, + 9512,9416,9319,9223,9126,9030,8933,8836, + 8739,8642,8545,8448,8351,8254,8157,8059, + 7962,7864,7767,7669,7571,7473,7375,7277, + 7179,7081,6983,6885,6786,6688,6590,6491, + 6393,6294,6195,6096,5998,5899,5800,5701, + 5602,5503,5404,5305,5205,5106,5007,4907, + 4808,4708,4609,4509,4410,4310,4210,4111, + 4011,3911,3811,3712,3612,3512,3412,3312, + 3212,3112,3012,2911,2811,2711,2611,2511, + 2410,2310,2210,2110,2009,1909,1809,1708, + 1608,1507,1407,1307,1206,1106,1005,905, + 804,704,603,503,402,302,201,101, + 0,-101,-201,-302,-402,-503,-603,-704, + -804,-905,-1005,-1106,-1206,-1307,-1407,-1507, + -1608,-1708,-1809,-1909,-2009,-2110,-2210,-2310, + -2410,-2511,-2611,-2711,-2811,-2911,-3012,-3112, + -3212,-3312,-3412,-3512,-3612,-3712,-3811,-3911, + -4011,-4111,-4210,-4310,-4410,-4509,-4609,-4708, + -4808,-4907,-5007,-5106,-5205,-5305,-5404,-5503, + -5602,-5701,-5800,-5899,-5998,-6096,-6195,-6294, + -6393,-6491,-6590,-6688,-6786,-6885,-6983,-7081, + -7179,-7277,-7375,-7473,-7571,-7669,-7767,-7864, + -7962,-8059,-8157,-8254,-8351,-8448,-8545,-8642, + -8739,-8836,-8933,-9030,-9126,-9223,-9319,-9416, + -9512,-9608,-9704,-9800,-9896,-9992,-10087,-10183, + -10278,-10374,-10469,-10564,-10659,-10754,-10849,-10944, + -11039,-11133,-11228,-11322,-11417,-11511,-11605,-11699, + -11793,-11886,-11980,-12074,-12167,-12260,-12353,-12446, + -12539,-12632,-12725,-12817,-12910,-13002,-13094,-13187, + -13279,-13370,-13462,-13554,-13645,-13736,-13828,-13919, + -14010,-14101,-14191,-14282,-14372,-14462,-14553,-14643, + -14732,-14822,-14912,-15001,-15090,-15180,-15269,-15358, + -15446,-15535,-15623,-15712,-15800,-15888,-15976,-16063, + -16151,-16238,-16325,-16413,-16499,-16586,-16673,-16759, + -16846,-16932,-17018,-17104,-17189,-17275,-17360,-17445, + -17530,-17615,-17700,-17784,-17869,-17953,-18037,-18121, + -18204,-18288,-18371,-18454,-18537,-18620,-18703,-18785, + -18868,-18950,-19032,-19113,-19195,-19276,-19357,-19438, + -19519,-19600,-19680,-19761,-19841,-19921,-20000,-20080, + -20159,-20238,-20317,-20396,-20475,-20553,-20631,-20709, + -20787,-20865,-20942,-21019,-21096,-21173,-21250,-21326, + -21403,-21479,-21554,-21630,-21705,-21781,-21856,-21930, + -22005,-22079,-22154,-22227,-22301,-22375,-22448,-22521, + -22594,-22667,-22739,-22812,-22884,-22956,-23027,-23099, + -23170,-23241,-23311,-23382,-23452,-23522,-23592,-23662, + -23731,-23801,-23870,-23938,-24007,-24075,-24143,-24211, + -24279,-24346,-24413,-24480,-24547,-24613,-24680,-24746, + -24811,-24877,-24942,-25007,-25072,-25137,-25201,-25265, + -25329,-25393,-25456,-25519,-25582,-25645,-25708,-25770, + -25832,-25893,-25955,-26016,-26077,-26138,-26198,-26259, + -26319,-26378,-26438,-26497,-26556,-26615,-26674,-26732, + -26790,-26848,-26905,-26962,-27019,-27076,-27133,-27189, + -27245,-27300,-27356,-27411,-27466,-27521,-27575,-27629, + -27683,-27737,-27790,-27843,-27896,-27949,-28001,-28053, + -28105,-28157,-28208,-28259,-28310,-28360,-28411,-28460, + -28510,-28560,-28609,-28658,-28706,-28755,-28803,-28850, + -28898,-28945,-28992,-29039,-29085,-29131,-29177,-29223, + -29268,-29313,-29358,-29403,-29447,-29491,-29534,-29578, + -29621,-29664,-29706,-29749,-29791,-29832,-29874,-29915, + -29956,-29997,-30037,-30077,-30117,-30156,-30195,-30234, + -30273,-30311,-30349,-30387,-30424,-30462,-30498,-30535, + -30571,-30607,-30643,-30679,-30714,-30749,-30783,-30818, + -30852,-30885,-30919,-30952,-30985,-31017,-31050,-31082, + -31113,-31145,-31176,-31206,-31237,-31267,-31297,-31327, + -31356,-31385,-31414,-31442,-31470,-31498,-31526,-31553, + -31580,-31607,-31633,-31659,-31685,-31710,-31736,-31760, + -31785,-31809,-31833,-31857,-31880,-31903,-31926,-31949, + -31971,-31993,-32014,-32036,-32057,-32077,-32098,-32118, + -32137,-32157,-32176,-32195,-32213,-32232,-32250,-32267, + -32285,-32302,-32318,-32335,-32351,-32367,-32382,-32397, + -32412,-32427,-32441,-32455,-32469,-32482,-32495,-32508, + -32521,-32533,-32545,-32556,-32567,-32578,-32589,-32599, + -32609,-32619,-32628,-32637,-32646,-32655,-32663,-32671, + -32678,-32685,-32692,-32699,-32705,-32711,-32717,-32722, + -32728,-32732,-32737,-32741,-32745,-32748,-32752,-32755, + -32757,-32759,-32761,-32763,-32765,-32766,-32766,-32767, + -32767,-32767,-32766,-32766,-32765,-32763,-32761,-32759, + -32757,-32755,-32752,-32748,-32745,-32741,-32737,-32732, + -32728,-32722,-32717,-32711,-32705,-32699,-32692,-32685, + -32678,-32671,-32663,-32655,-32646,-32637,-32628,-32619, + -32609,-32599,-32589,-32578,-32567,-32556,-32545,-32533, + -32521,-32508,-32495,-32482,-32469,-32455,-32441,-32427, + -32412,-32397,-32382,-32367,-32351,-32335,-32318,-32302, + -32285,-32267,-32250,-32232,-32213,-32195,-32176,-32157, + -32137,-32118,-32098,-32077,-32057,-32036,-32014,-31993, + -31971,-31949,-31926,-31903,-31880,-31857,-31833,-31809, + -31785,-31760,-31736,-31710,-31685,-31659,-31633,-31607, + -31580,-31553,-31526,-31498,-31470,-31442,-31414,-31385, + -31356,-31327,-31297,-31267,-31237,-31206,-31176,-31145, + -31113,-31082,-31050,-31017,-30985,-30952,-30919,-30885, + -30852,-30818,-30783,-30749,-30714,-30679,-30643,-30607, + -30571,-30535,-30498,-30462,-30424,-30387,-30349,-30311, + -30273,-30234,-30195,-30156,-30117,-30077,-30037,-29997, + -29956,-29915,-29874,-29832,-29791,-29749,-29706,-29664, + -29621,-29578,-29534,-29491,-29447,-29403,-29358,-29313, + -29268,-29223,-29177,-29131,-29085,-29039,-28992,-28945, + -28898,-28850,-28803,-28755,-28706,-28658,-28609,-28560, + -28510,-28460,-28411,-28360,-28310,-28259,-28208,-28157, + -28105,-28053,-28001,-27949,-27896,-27843,-27790,-27737, + -27683,-27629,-27575,-27521,-27466,-27411,-27356,-27300, + -27245,-27189,-27133,-27076,-27019,-26962,-26905,-26848, + -26790,-26732,-26674,-26615,-26556,-26497,-26438,-26378, + -26319,-26259,-26198,-26138,-26077,-26016,-25955,-25893, + -25832,-25770,-25708,-25645,-25582,-25519,-25456,-25393, + -25329,-25265,-25201,-25137,-25072,-25007,-24942,-24877, + -24811,-24746,-24680,-24613,-24547,-24480,-24413,-24346, + -24279,-24211,-24143,-24075,-24007,-23938,-23870,-23801, + -23731,-23662,-23592,-23522,-23452,-23382,-23311,-23241, + -23170,-23099,-23027,-22956,-22884,-22812,-22739,-22667, + -22594,-22521,-22448,-22375,-22301,-22227,-22154,-22079, + -22005,-21930,-21856,-21781,-21705,-21630,-21554,-21479, + -21403,-21326,-21250,-21173,-21096,-21019,-20942,-20865, + -20787,-20709,-20631,-20553,-20475,-20396,-20317,-20238, + -20159,-20080,-20000,-19921,-19841,-19761,-19680,-19600, + -19519,-19438,-19357,-19276,-19195,-19113,-19032,-18950, + -18868,-18785,-18703,-18620,-18537,-18454,-18371,-18288, + -18204,-18121,-18037,-17953,-17869,-17784,-17700,-17615, + -17530,-17445,-17360,-17275,-17189,-17104,-17018,-16932, + -16846,-16759,-16673,-16586,-16499,-16413,-16325,-16238, + -16151,-16063,-15976,-15888,-15800,-15712,-15623,-15535, + -15446,-15358,-15269,-15180,-15090,-15001,-14912,-14822, + -14732,-14643,-14553,-14462,-14372,-14282,-14191,-14101, + -14010,-13919,-13828,-13736,-13645,-13554,-13462,-13370, + -13279,-13187,-13094,-13002,-12910,-12817,-12725,-12632, + -12539,-12446,-12353,-12260,-12167,-12074,-11980,-11886, + -11793,-11699,-11605,-11511,-11417,-11322,-11228,-11133, + -11039,-10944,-10849,-10754,-10659,-10564,-10469,-10374, + -10278,-10183,-10087,-9992,-9896,-9800,-9704,-9608, + -9512,-9416,-9319,-9223,-9126,-9030,-8933,-8836, + -8739,-8642,-8545,-8448,-8351,-8254,-8157,-8059, + -7962,-7864,-7767,-7669,-7571,-7473,-7375,-7277, + -7179,-7081,-6983,-6885,-6786,-6688,-6590,-6491, + -6393,-6294,-6195,-6096,-5998,-5899,-5800,-5701, + -5602,-5503,-5404,-5305,-5205,-5106,-5007,-4907, + -4808,-4708,-4609,-4509,-4410,-4310,-4210,-4111, + -4011,-3911,-3811,-3712,-3612,-3512,-3412,-3312, + -3212,-3112,-3012,-2911,-2811,-2711,-2611,-2511, + -2410,-2310,-2210,-2110,-2009,-1909,-1809,-1708, + -1608,-1507,-1407,-1307,-1206,-1106,-1005,-905, + -804,-704,-603,-503,-402,-302,-201,-101 +}; +#endif + diff --git a/arm-fm-22k/lib_src/eas_ima_tables.c b/arm-fm-22k/lib_src/eas_ima_tables.c index 56bd1eb..b03b4d4 100644 --- a/arm-fm-22k/lib_src/eas_ima_tables.c +++ b/arm-fm-22k/lib_src/eas_ima_tables.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_ima_tables.c
- *
- * Contents and purpose:
- * Contains the constant tables for IMA encode/decode
- *
- * Copyright (c) 2005 Sonic Network Inc.
+/*---------------------------------------------------------------------------- + * + * File: + * eas_ima_tables.c + * + * Contents and purpose: + * Contains the constant tables for IMA encode/decode + * + * Copyright (c) 2005 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. @@ -19,36 +19,36 @@ * 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: 760 $
- * $Date: 2007-07-17 23:09:36 -0700 (Tue, 17 Jul 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_types.h"
-
-/*----------------------------------------------------------------------------
- * ADPCM decode tables
- *----------------------------------------------------------------------------
-*/
-const EAS_I16 imaIndexTable[16] =
-{
- -1, -1, -1, -1, 2, 4, 6, 8,
- -1, -1, -1, -1, 2, 4, 6, 8
-};
-
-const EAS_I16 imaStepSizeTable[89] =
-{
- 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
- 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
- 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
- 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
- 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
- 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
- 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
- 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
- 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
-};
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 760 $ + * $Date: 2007-07-17 23:09:36 -0700 (Tue, 17 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * ADPCM decode tables + *---------------------------------------------------------------------------- +*/ +const EAS_I16 imaIndexTable[16] = +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +const EAS_I16 imaStepSizeTable[89] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + diff --git a/arm-fm-22k/lib_src/eas_imaadpcm.c b/arm-fm-22k/lib_src/eas_imaadpcm.c index 68bf257..41280b5 100644 --- a/arm-fm-22k/lib_src/eas_imaadpcm.c +++ b/arm-fm-22k/lib_src/eas_imaadpcm.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_imaadpcm.c
- *
- * Contents and purpose:
- * Implements the IMA ADPCM decoder
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_imaadpcm.c + * + * Contents and purpose: + * Implements the IMA ADPCM decoder + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,350 +19,350 @@ * 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: 847 $
- * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_host.h"
-#include "eas_pcm.h"
-#include "eas_math.h"
-#include "eas_report.h"
-
-// #define _DEBUG_IMA_ADPCM_LOCATE
-
-/*----------------------------------------------------------------------------
- * externs
- *----------------------------------------------------------------------------
-*/
-extern const EAS_I16 imaIndexTable[];
-extern const EAS_I16 imaStepSizeTable[];
-
-/*----------------------------------------------------------------------------
- * prototypes
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
-static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
-static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble);
-static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time);
-
-/*----------------------------------------------------------------------------
- * IMA ADPCM Decoder interface
- *----------------------------------------------------------------------------
-*/
-const S_DECODER_INTERFACE IMADecoder =
-{
- IMADecoderInit,
- IMADecoderSample,
- IMADecoderLocate
-};
-
-/*----------------------------------------------------------------------------
- * IMADecoderInit()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the IMA ADPCM decoder
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState)
-{
- pState->decoderL.step = 0;
- pState->decoderR.step = 0;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMADecoderSample()
- *----------------------------------------------------------------------------
- * Purpose:
- * Decodes an IMA ADPCM sample
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState)
-{
- EAS_RESULT result;
- EAS_I16 sTemp;
-
- /* if high nibble, decode */
- if (pState->hiNibble)
- {
- IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte >> 4));
- pState->hiNibble = EAS_FALSE;
- }
-
- /* low nibble, need to fetch another byte */
- else
- {
- /* check for loop */
- if ((pState->bytesLeft == 0) && (pState->loopSamples != 0))
- {
- /* seek to start of loop */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS)
- return result;
- pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop;
- pState->blockCount = 0;
- pState->flags &= ~PCM_FLAGS_EMPTY;
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMADecoderSample: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ }
- }
-
- /* if start of block, fetch new predictor and step index */
- if ((pState->blockSize != 0) && (pState->blockCount == 0) && (pState->bytesLeft != 0))
- {
-
- /* get predicted sample for left channel */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
- return result;
-#ifdef _DEBUG_IMA_ADPCM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Predictor: Was %d, now %d\n", pState->decoderL.acc, sTemp); */ }
-#endif
- pState->decoderL.acc = pState->decoderL.x1 = sTemp;
-
- /* get step index for left channel - upper 8 bits are reserved */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
- return result;
-#ifdef _DEBUG_IMA_ADPCM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderL.step, sTemp); */ }
-#endif
- pState->decoderL.step = sTemp & 0xff;
-
- if (pState->flags & PCM_FLAGS_STEREO)
- {
- /* get predicted sample for right channel */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
- return result;
- pState->decoderR.acc = pState->decoderR.x1 = sTemp;
-
- /* get step index for right channel - upper 8 bits are reserved */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
- return result;
-#ifdef _DEBUG_IMA_ADPCM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderR.step, sTemp); */ }
-#endif
- pState->decoderR.step = sTemp & 0xff;
-
- pState->blockCount = pState->blockSize - 8;
- pState->bytesLeft -= 8;
- }
- else
- {
- pState->blockCount = pState->blockSize - 4;
- pState->bytesLeft -= 4;
- }
- }
- else
- {
-
- /* get another ADPCM data pair */
- if (pState->bytesLeft)
- {
-
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS)
- return result;
-
- /* decode the low nibble */
- pState->bytesLeft--;
- pState->blockCount--;
- IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte & 0x0f));
-
- if (pState->flags & PCM_FLAGS_STEREO)
- IMADecoderADPCM(&pState->decoderR, (EAS_U8)(pState->srcByte >> 4));
- else
- pState->hiNibble = EAS_TRUE;
- }
-
- /* out of ADPCM data, generate enough samples to fill buffer */
- else
- {
- pState->decoderL.x1 = pState->decoderL.x0;
- pState->decoderR.x1 = pState->decoderR.x0;
- }
- }
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMADecoderADPCM()
- *----------------------------------------------------------------------------
- * Purpose:
- * Decodes an IMA ADPCM sample
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble)
-{
- EAS_INT delta;
- EAS_INT stepSize;
-
- /* get stepsize from table */
- stepSize = imaStepSizeTable[pState->step];
-
- /* delta = (abs(delta) + 0.5) * step / 4 */
- delta = 0;
- if (nibble & 4)
- delta += stepSize;
-
- if (nibble & 2)
- /*lint -e{702} use shift for performance */
- delta += stepSize >> 1;
-
- if (nibble & 1)
- /*lint -e{702} use shift for performance */
- delta += stepSize >> 2;
-
- /*lint -e{702} use shift for performance */
- delta += stepSize >> 3;
-
- /* integrate the delta */
- if (nibble & 8)
- pState->acc -= delta;
- else
- pState->acc += delta;
-
- /* saturate */
- if (pState->acc > 32767)
- pState->acc = 32767;
- if (pState->acc < -32768)
- pState->acc = -32768;
- pState->x1 = (EAS_PCM) pState->acc;
-
- /* compute new step size */
- pState->step += imaIndexTable[nibble];
- if (pState->step < 0)
- pState->step = 0;
- if (pState->step > 88)
- pState->step = 88;
-
-#ifdef _DEBUG_IMA_ADPCM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "In=%u, Pred=%d, Step=%d\n", nibble, pState->acc, imaStepSizeTable[pState->step]); */ }
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * IMADecoderLocate()
- *----------------------------------------------------------------------------
- * Locate in an IMA ADPCM stream
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time)
-{
- EAS_RESULT result;
- EAS_I32 temp;
- EAS_I32 samplesPerBlock;
- EAS_I32 secs, msecs;
-
- /* no need to calculate if time is zero */
- if (time == 0)
- temp = 0;
-
- /* not zero */
- else
- {
-
- /* can't seek if not a blocked file */
- if (pState->blockSize == 0)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- /* calculate number of samples per block */
- if (pState->flags & PCM_FLAGS_STEREO)
- samplesPerBlock = pState->blockSize - 7;
- else
- samplesPerBlock = (pState->blockSize << 1) - 7;
-
- /* break down into secs and msecs */
- secs = time / 1000;
- msecs = time - (secs * 1000);
-
- /* calculate sample number fraction from msecs */
- temp = (msecs * pState->sampleRate);
- temp = (temp >> 10) + ((temp * 49) >> 21);
-
- /* add integer sample count */
- temp += secs * pState->sampleRate;
-
-#ifdef _DEBUG_IMA_ADPCM_LOCATE
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000006 , time, temp);
-#endif
-
- /* for looped samples, calculate position in the loop */
- if ((temp > pState->byteCount) && (pState->loopSamples != 0))
- {
- EAS_I32 numBlocks;
- EAS_I32 samplesPerLoop;
- EAS_I32 samplesInLastBlock;
-
- numBlocks = (EAS_I32) (pState->loopStart / pState->blockSize);
- samplesInLastBlock = (EAS_I32) pState->loopStart - (numBlocks * pState->blockSize);
- if (samplesInLastBlock)
- {
- if (pState->flags & PCM_FLAGS_STEREO)
- samplesInLastBlock = samplesInLastBlock - 7;
- else
- /*lint -e{703} use shift for performance */
- samplesInLastBlock = (samplesInLastBlock << 1) - 7;
- }
- samplesPerLoop = numBlocks * samplesPerBlock + samplesInLastBlock;
- temp = temp % samplesPerLoop;
-#ifdef _DEBUG_IMA_ADPCM_LOCATE
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000007 , numBlocks, samplesPerLoop, samplesInLastBlock, temp);
-#endif
- }
-
- /* find start of block for requested sample */
- temp = (temp / samplesPerBlock) * pState->blockSize;
-#ifdef _DEBUG_IMA_ADPCM_LOCATE
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000008 , temp);
-#endif
-
- }
-
- /* seek to new location */
- if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS)
- return result;
-
-#ifdef _DEBUG_IMA_ADPCM_LOCATE
- EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000009 , pState->bytesLeft);
-#endif
-
- /* reset state */
- pState->blockCount = 0;
- pState->hiNibble = EAS_FALSE;
- if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED))
- pState->state = EAS_STATE_READY;
-
- return EAS_SUCCESS;
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_host.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_report.h" + +// #define _DEBUG_IMA_ADPCM_LOCATE + +/*---------------------------------------------------------------------------- + * externs + *---------------------------------------------------------------------------- +*/ +extern const EAS_I16 imaIndexTable[]; +extern const EAS_I16 imaStepSizeTable[]; + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble); +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * IMA ADPCM Decoder interface + *---------------------------------------------------------------------------- +*/ +const S_DECODER_INTERFACE IMADecoder = +{ + IMADecoderInit, + IMADecoderSample, + IMADecoderLocate +}; + +/*---------------------------------------------------------------------------- + * IMADecoderInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the IMA ADPCM decoder + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + pState->decoderL.step = 0; + pState->decoderR.step = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderSample() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_I16 sTemp; + + /* if high nibble, decode */ + if (pState->hiNibble) + { + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte >> 4)); + pState->hiNibble = EAS_FALSE; + } + + /* low nibble, need to fetch another byte */ + else + { + /* check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + /* seek to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->blockCount = 0; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMADecoderSample: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + /* if start of block, fetch new predictor and step index */ + if ((pState->blockSize != 0) && (pState->blockCount == 0) && (pState->bytesLeft != 0)) + { + + /* get predicted sample for left channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Predictor: Was %d, now %d\n", pState->decoderL.acc, sTemp); */ } +#endif + pState->decoderL.acc = pState->decoderL.x1 = sTemp; + + /* get step index for left channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderL.step, sTemp); */ } +#endif + pState->decoderL.step = sTemp & 0xff; + + if (pState->flags & PCM_FLAGS_STEREO) + { + /* get predicted sample for right channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->decoderR.acc = pState->decoderR.x1 = sTemp; + + /* get step index for right channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderR.step, sTemp); */ } +#endif + pState->decoderR.step = sTemp & 0xff; + + pState->blockCount = pState->blockSize - 8; + pState->bytesLeft -= 8; + } + else + { + pState->blockCount = pState->blockSize - 4; + pState->bytesLeft -= 4; + } + } + else + { + + /* get another ADPCM data pair */ + if (pState->bytesLeft) + { + + if ((result = EAS_HWGetByte(pEASData->hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* decode the low nibble */ + pState->bytesLeft--; + pState->blockCount--; + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte & 0x0f)); + + if (pState->flags & PCM_FLAGS_STEREO) + IMADecoderADPCM(&pState->decoderR, (EAS_U8)(pState->srcByte >> 4)); + else + pState->hiNibble = EAS_TRUE; + } + + /* out of ADPCM data, generate enough samples to fill buffer */ + else + { + pState->decoderL.x1 = pState->decoderL.x0; + pState->decoderR.x1 = pState->decoderR.x0; + } + } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderADPCM() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble) +{ + EAS_INT delta; + EAS_INT stepSize; + + /* get stepsize from table */ + stepSize = imaStepSizeTable[pState->step]; + + /* delta = (abs(delta) + 0.5) * step / 4 */ + delta = 0; + if (nibble & 4) + delta += stepSize; + + if (nibble & 2) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 1; + + if (nibble & 1) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 2; + + /*lint -e{702} use shift for performance */ + delta += stepSize >> 3; + + /* integrate the delta */ + if (nibble & 8) + pState->acc -= delta; + else + pState->acc += delta; + + /* saturate */ + if (pState->acc > 32767) + pState->acc = 32767; + if (pState->acc < -32768) + pState->acc = -32768; + pState->x1 = (EAS_PCM) pState->acc; + + /* compute new step size */ + pState->step += imaIndexTable[nibble]; + if (pState->step < 0) + pState->step = 0; + if (pState->step > 88) + pState->step = 88; + +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "In=%u, Pred=%d, Step=%d\n", nibble, pState->acc, imaStepSizeTable[pState->step]); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * IMADecoderLocate() + *---------------------------------------------------------------------------- + * Locate in an IMA ADPCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 samplesPerBlock; + EAS_I32 secs, msecs; + + /* no need to calculate if time is zero */ + if (time == 0) + temp = 0; + + /* not zero */ + else + { + + /* can't seek if not a blocked file */ + if (pState->blockSize == 0) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* calculate number of samples per block */ + if (pState->flags & PCM_FLAGS_STEREO) + samplesPerBlock = pState->blockSize - 7; + else + samplesPerBlock = (pState->blockSize << 1) - 7; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000006 , time, temp); +#endif + + /* for looped samples, calculate position in the loop */ + if ((temp > pState->byteCount) && (pState->loopSamples != 0)) + { + EAS_I32 numBlocks; + EAS_I32 samplesPerLoop; + EAS_I32 samplesInLastBlock; + + numBlocks = (EAS_I32) (pState->loopStart / pState->blockSize); + samplesInLastBlock = (EAS_I32) pState->loopStart - (numBlocks * pState->blockSize); + if (samplesInLastBlock) + { + if (pState->flags & PCM_FLAGS_STEREO) + samplesInLastBlock = samplesInLastBlock - 7; + else + /*lint -e{703} use shift for performance */ + samplesInLastBlock = (samplesInLastBlock << 1) - 7; + } + samplesPerLoop = numBlocks * samplesPerBlock + samplesInLastBlock; + temp = temp % samplesPerLoop; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000007 , numBlocks, samplesPerLoop, samplesInLastBlock, temp); +#endif + } + + /* find start of block for requested sample */ + temp = (temp / samplesPerBlock) * pState->blockSize; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000008 , temp); +#endif + + } + + /* seek to new location */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000009 , pState->bytesLeft); +#endif + + /* reset state */ + pState->blockCount = 0; + pState->hiNibble = EAS_FALSE; + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + diff --git a/arm-fm-22k/lib_src/eas_imelody.c b/arm-fm-22k/lib_src/eas_imelody.c index 9f4d541..698c7df 100644 --- a/arm-fm-22k/lib_src/eas_imelody.c +++ b/arm-fm-22k/lib_src/eas_imelody.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_imelody.c
- *
- * Contents and purpose:
- * iMelody parser
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_imelody.c + * + * Contents and purpose: + * iMelody parser + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,1720 +19,1720 @@ * 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: 797 $
- * $Date: 2007-08-01 00:15:56 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-/* lint doesn't like the way some string.h files look */
-#ifdef _lint
-#include "lint_stdlib.h"
-#else
-#include <string.h>
-#endif
-
-#include "eas_data.h"
-#include "eas_miditypes.h"
-#include "eas_parser.h"
-#include "eas_report.h"
-#include "eas_host.h"
-#include "eas_midi.h"
-#include "eas_config.h"
-#include "eas_vm_protos.h"
-#include "eas_imelodydata.h"
-#include "eas_ctype.h"
-
-// #define _DEBUG_IMELODY
-
-/* increase gain for mono ringtones */
-#define IMELODY_GAIN_OFFSET 8
-
-/* length of 32nd note in 1/256ths of a msec for 120 BPM tempo */
-#define DEFAULT_TICK_CONV 16000
-#define TICK_CONVERT 1920000
-
-/* default channel and program for iMelody playback */
-#define IMELODY_CHANNEL 0
-#define IMELODY_PROGRAM 80
-#define IMELODY_VEL_MUL 4
-#define IMELODY_VEL_OFS 67
-
-/* multiplier for fixed point triplet conversion */
-#define TRIPLET_MULTIPLIER 683
-#define TRIPLET_SHIFT 10
-
-static const char* const tokens[] =
-{
- "BEGIN:IMELODY",
- "VERSION:",
- "FORMAT:CLASS",
- "NAME:",
- "COMPOSER:",
- "BEAT:",
- "STYLE:",
- "VOLUME:",
- "MELODY:",
- "END:IMELODY"
-};
-
-/* ledon or ledoff */
-static const char ledStr[] = "edo";
-
-/* vibeon or vibeoff */
-static const char vibeStr[] = "ibeo";
-
-/* backon or backoff */
-static const char backStr[] = "cko";
-
-typedef enum
-{
- TOKEN_BEGIN,
- TOKEN_VERSION,
- TOKEN_FORMAT,
- TOKEN_NAME,
- TOKEN_COMPOSER,
- TOKEN_BEAT,
- TOKEN_STYLE,
- TOKEN_VOLUME,
- TOKEN_MELODY,
- TOKEN_END,
- TOKEN_INVALID
-} ENUM_IMELODY_TOKENS;
-
-/* lookup table for note values */
-static const EAS_I8 noteTable[] = { 9, 11, 0, 2, 4, 5, 7 };
-
-/* inline functions */
-#ifdef _DEBUG_IMELODY
-static void PutBackChar (S_IMELODY_DATA *pData)
-{
- if (pData->index)
- pData->index--;
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "PutBackChar '%c'\n", pData->buffer[pData->index]); */ }
-}
-#else
-EAS_INLINE void PutBackChar (S_IMELODY_DATA *pData) { if (pData->index) pData->index--; }
-#endif
-
-
-/* local prototypes */
-static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
-static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
-static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
-static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
-static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode);
-static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
-static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration);
-static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
-static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
-static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
-static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader);
-static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader);
-static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData);
-static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader);
-static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine);
-static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex);
-
-
-/*----------------------------------------------------------------------------
- *
- * EAS_iMelody_Parser
- *
- * This structure contains the functional interface for the iMelody parser
- *----------------------------------------------------------------------------
-*/
-const S_FILE_PARSER_INTERFACE EAS_iMelody_Parser =
-{
- IMY_CheckFileType,
- IMY_Prepare,
- IMY_Time,
- IMY_Event,
- IMY_State,
- IMY_Close,
- IMY_Reset,
- IMY_Pause,
- IMY_Resume,
- NULL,
- IMY_SetData,
- IMY_GetData,
- NULL
-};
-
-/*----------------------------------------------------------------------------
- * IMY_CheckFileType()
- *----------------------------------------------------------------------------
- * Purpose:
- * Check the file type to see if we can parse it
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
-{
- S_IMELODY_DATA* pData;
- EAS_I8 buffer[MAX_LINE_SIZE+1];
- EAS_U8 index;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_CheckFileType\n"); */ }
-#endif
-
- /* read the first line of the file */
- *ppHandle = NULL;
- if (IMY_ReadLine(pEASData->hwInstData, fileHandle, buffer, NULL) != EAS_SUCCESS)
- return EAS_SUCCESS;
-
- /* check for header string */
- if (IMY_ParseLine(buffer, &index) == TOKEN_BEGIN)
- {
-
- /* check for static memory allocation */
- if (pEASData->staticMemoryModel)
- pData = EAS_CMEnumData(EAS_CM_IMELODY_DATA);
- else
- pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_IMELODY_DATA));
- if (!pData)
- return EAS_ERROR_MALLOC_FAILED;
- EAS_HWMemSet(pData, 0, sizeof(S_IMELODY_DATA));
-
- /* initialize */
- pData->fileHandle = fileHandle;
- pData->fileOffset = offset;
- pData->state = EAS_STATE_ERROR;
- pData->state = EAS_STATE_OPEN;
-
- /* return a pointer to the instance data */
- *ppHandle = pData;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_Prepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_IMELODY_DATA* pData;
- EAS_RESULT result;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_Prepare\n"); */ }
-#endif
-
- /* check for valid state */
- pData = (S_IMELODY_DATA*) pInstData;
- if (pData->state != EAS_STATE_OPEN)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* instantiate a synthesizer */
- if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ }
- return result;
- }
-
- /* parse the header */
- if ((result = IMY_ParseHeader(pEASData, pData)) != EAS_SUCCESS)
- return result;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Prepare: state set to EAS_STATE_READY\n"); */ }
-#endif
-
- pData ->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_Time()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the time of the next event in msecs
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pTime - pointer to variable to hold time of next event (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
-{
- S_IMELODY_DATA *pData;
-
- pData = (S_IMELODY_DATA*) pInstData;
-
- /* return time in milliseconds */
- /*lint -e{704} use shift instead of division */
- *pTime = pData->time >> 8;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_Event()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the next event in the file
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
-{
- S_IMELODY_DATA* pData;
- EAS_RESULT result;
- EAS_I8 c;
- EAS_BOOL eof;
- EAS_INT temp;
-
- pData = (S_IMELODY_DATA*) pInstData;
- if (pData->state >= EAS_STATE_OPEN)
- return EAS_SUCCESS;
-
- /* initialize MIDI channel when the track starts playing */
- if (pData->time == 0)
- {
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: Reset\n"); */ }
-#endif
- /* set program to square lead */
- VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, IMELODY_PROGRAM);
-
- /* set channel volume to max */
- VMControlChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, 7, 127);
- }
-
- /* check for end of note */
- if (pData->note)
- {
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Stopping note %d\n", pData->note); */ }
-#endif
- /* stop the note */
- VMStopNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, 0);
- pData->note = 0;
-
- /* check for rest between notes */
- if (pData->restTicks)
- {
- pData->time += pData->restTicks;
- pData->restTicks = 0;
- return EAS_SUCCESS;
- }
- }
-
- /* parse the next event */
- eof = EAS_FALSE;
- while (!eof)
- {
-
- /* get next character */
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
-
- switch (c)
- {
- /* start repeat */
- case '(':
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter repeat section\n", c); */ }
-#endif
-
- if (pData->repeatOffset < 0)
- {
- pData->repeatOffset = pData->startLine + (EAS_I32) pData->index;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat offset = %d\n", pData->repeatOffset); */ }
-#endif
- }
- else
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring nested repeat section\n"); */ }
- break;
-
- /* end repeat */
- case ')':
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "End repeat section, repeat offset = %d\n", pData->repeatOffset); */ }
-#endif
- /* ignore invalid repeats */
- if (pData->repeatCount >= 0)
- {
-
- /* decrement repeat count (repeatCount == 0 means infinite loop) */
- if (pData->repeatCount > 0)
- {
- if (--pData->repeatCount == 0)
- {
- pData->repeatCount = -1;
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat loop complete\n"); */ }
-#endif
- }
- }
-
-//2 TEMPORARY FIX: If locating, don't do infinite loops.
-//3 We need a different mode for metadata parsing where we don't loop at all
- if ((parserMode == eParserModePlay) || (pData->repeatCount != 0))
- {
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Rewinding file for repeat\n"); */ }
-#endif
- /* rewind to start of loop */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS)
- return result;
- IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine);
- pData->index = 0;
-
- /* if last loop, prevent future loops */
- if (pData->repeatCount == -1)
- pData->repeatOffset = -1;
- }
- }
- break;
-
- /* repeat count */
- case '@':
- if (!IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_FALSE))
- eof = EAS_TRUE;
- else if (pData->repeatOffset > 0)
- {
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat count = %dt", pData->repeatCount); */ }
-#endif
- if (pData->repeatCount < 0)
- pData->repeatCount = (EAS_I16) temp;
- }
- break;
-
- /* volume */
- case 'V':
- if (!IMY_GetVolume(pEASData->hwInstData, pData, EAS_FALSE))
- eof = EAS_TRUE;
- break;
-
- /* flat */
- case '&':
- pData->noteModifier = -1;
- break;
-
- /* sharp */
- case '#':
- pData->noteModifier = +1;
- break;
-
- /* octave */
- case '*':
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
- if (IsDigit(c))
- pData->octave = (EAS_U8) ((c - '0' + 1) * 12);
- else if (!c)
- eof = EAS_TRUE;
- break;
-
- /* ledon or ledoff */
- case 'l':
- if (!IMY_GetLEDState(pEASData, pData))
- eof = EAS_TRUE;
- break;
-
- /* vibeon or vibeoff */
- case 'v':
- if (!IMY_GetVibeState(pEASData, pData))
- eof = EAS_TRUE;
- break;
-
- /* either a B note or backon or backoff */
- case 'b':
- if (IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE) == 'a')
- {
- if (!IMY_GetBackState(pEASData, pData))
- eof = EAS_TRUE;
- }
- else
- {
- PutBackChar(pData);
- if (IMY_PlayNote(pEASData, pData, c, parserMode))
- return EAS_SUCCESS;
- eof = EAS_TRUE;
- }
- break;
-
- /* rest */
- case 'r':
- case 'R':
- if (IMY_PlayRest(pEASData, pData))
- return EAS_SUCCESS;
- eof = EAS_TRUE;
- break;
-
- /* EOF */
- case 0:
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: end of iMelody file detected\n"); */ }
-#endif
- eof = EAS_TRUE;
- break;
-
- /* must be a note */
- default:
- c = ToLower(c);
- if ((c >= 'a') && (c <= 'g'))
- {
- if (IMY_PlayNote(pEASData, pData, c, parserMode))
- return EAS_SUCCESS;
- eof = EAS_TRUE;
- }
- else
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unexpected character '%c' [0x%02x]\n", c, c); */ }
- break;
- }
- }
-
- /* handle EOF */
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: state set to EAS_STATE_STOPPING\n"); */ }
-#endif
- pData->state = EAS_STATE_STOPPING;
- VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_State()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
-{
- S_IMELODY_DATA* pData;
-
- /* establish pointer to instance data */
- pData = (S_IMELODY_DATA*) pInstData;
-
- /* if stopping, check to see if synth voices are active */
- if (pData->state == EAS_STATE_STOPPING)
- {
- if (VMActiveVoices(pData->pSynth) == 0)
- {
- pData->state = EAS_STATE_STOPPED;
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_STOPPED\n"); */ }
-#endif
- }
- }
-
- if (pData->state == EAS_STATE_PAUSING)
- {
- if (VMActiveVoices(pData->pSynth) == 0)
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_PAUSED\n"); */ }
-#endif
- pData->state = EAS_STATE_PAUSED;
- }
- }
-
- /* return current state */
- *pState = pData->state;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_Close()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_IMELODY_DATA* pData;
- EAS_RESULT result;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Close: close file\n"); */ }
-#endif
-
- pData = (S_IMELODY_DATA*) pInstData;
-
- /* close the file */
- if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS)
- return result;
-
- /* free the synth */
- if (pData->pSynth != NULL)
- VMMIDIShutdown(pEASData, pData->pSynth);
-
- /* if using dynamic memory, free it */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pData);
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_Reset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_IMELODY_DATA* pData;
- EAS_RESULT result;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: reset file\n"); */ }
-#endif
- pData = (S_IMELODY_DATA*) pInstData;
-
- /* reset the synth */
- VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE);
-
- /* reset time to zero */
- pData->time = 0;
- pData->note = 0;
-
- /* reset file position and re-parse header */
- pData->state = EAS_STATE_ERROR;
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS)
- return result;
- if ((result = IMY_ParseHeader (pEASData, pData)) != EAS_SUCCESS)
- return result;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: state set to EAS_STATE_ERROR\n"); */ }
-#endif
-
- pData->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_Pause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Pauses the sequencer. Mutes all voices and sets state to pause.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_IMELODY_DATA *pData;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Pause: pause file\n"); */ }
-#endif
-
- /* can't pause a stopped stream */
- pData = (S_IMELODY_DATA*) pInstData;
- if (pData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* mute the synthesizer */
- VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth);
- pData->state = EAS_STATE_PAUSING;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_Resume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume playing after a pause, sets state back to playing.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_IMELODY_DATA *pData;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Resume: resume file\n"); */ }
-#endif
-
- /* can't resume a stopped stream */
- pData = (S_IMELODY_DATA*) pInstData;
- if (pData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* nothing to do but resume playback */
- pData->state = EAS_STATE_PLAY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_SetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Adjust tempo relative to song tempo
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pInstData - pointer to iMelody instance data
- * rate - rate (28-bit fractional amount)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_IMELODY_DATA *pData;
-
- pData = (S_IMELODY_DATA*) pInstData;
- switch (param)
- {
-
- /* set metadata callback */
- case PARSER_DATA_METADATA_CB:
- EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB));
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Return the file type
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pInstData - pointer to iMelody instance data
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_IMELODY_DATA *pData;
-
- pData = (S_IMELODY_DATA*) pInstData;
-
- switch (param)
- {
- /* return file type as iMelody */
- case PARSER_DATA_FILE_TYPE:
- *pValue = EAS_FILE_IMELODY;
- break;
-
- case PARSER_DATA_SYNTH_HANDLE:
- *pValue = (EAS_I32) pData->pSynth;
- break;
-
- case PARSER_DATA_GAIN_OFFSET:
- *pValue = IMELODY_GAIN_OFFSET;
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_PlayNote()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode)
-{
- EAS_I32 duration;
- EAS_U8 velocity;
-
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: start note %d\n", note); */ }
-#endif
-
- /* get the duration */
- if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration))
- return EAS_FALSE;
-
- /* save note value */
- pData->note = (EAS_U8) (pData->octave + noteTable[note - 'a'] + pData->noteModifier);
- velocity = (EAS_U8) (pData->volume ? pData->volume * IMELODY_VEL_MUL + IMELODY_VEL_OFS : 0);
-
- /* start note only if in play mode */
- if (parserMode == eParserModePlay)
- VMStartNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, velocity);
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: Start note %d, duration %d\n", pData->note, duration); */ }
-#endif
-
- /* determine note length */
- switch (pData->style)
- {
- case 0:
- /*lint -e{704} shift for performance */
- pData->restTicks = duration >> 4;
- break;
- case 1:
- pData->restTicks = 0;
- break;
- case 2:
- /*lint -e{704} shift for performance */
- pData->restTicks = duration >> 1;
- break;
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "IMY_PlayNote: Note style out of range: %d\n", pData->style); */ }
- /*lint -e{704} shift for performance */
- pData->restTicks = duration >> 4;
- break;
- }
-
- /* next event is at end of this note */
- pData->time += duration - pData->restTicks;
-
- /* reset the flat/sharp modifier */
- pData->noteModifier = 0;
-
- return EAS_TRUE;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_PlayRest()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
-{
- EAS_I32 duration;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_PlayRest]n"); */ }
-#endif
-
- /* get the duration */
- if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration))
- return EAS_FALSE;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayRest: note duration %d\n", duration); */ }
-#endif
-
- /* next event is at end of this note */
- pData->time += duration;
- return EAS_TRUE;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetDuration()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-
-static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration)
-{
- EAS_I32 duration;
- EAS_I8 c;
-
- /* get the duration */
- *pDuration = 0;
- c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE);
- if (!c)
- return EAS_FALSE;
- if ((c < '0') || (c > '5'))
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetDuration: error in duration '%c'\n", c); */ }
-#endif
- return EAS_FALSE;
- }
-
- /* calculate total length of note */
- duration = pData->tick * (1 << ('5' - c));
-
- /* check for duration modifier */
- c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE);
- if (c)
- {
- if (c == '.')
- /*lint -e{704} shift for performance */
- duration += duration >> 1;
- else if (c == ':')
- /*lint -e{704} shift for performance */
- duration += (duration >> 1) + (duration >> 2);
- else if (c == ';')
- /*lint -e{704} shift for performance */
- duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT;
- else
- PutBackChar(pData);
- }
-
- *pDuration = duration;
- return EAS_TRUE;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetLEDState()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
-{
- EAS_I8 c;
- EAS_INT i;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetLEDState\n"); */ }
-#endif
-
- for (i = 0; i < 5; i++)
- {
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
- if (!c)
- return EAS_FALSE;
- switch (i)
- {
- case 3:
- if (c == 'n')
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED on\n"); */ }
-#endif
- EAS_HWLED(pEASData->hwInstData, EAS_TRUE);
- return EAS_TRUE;
- }
- else if (c != 'f')
- return EAS_FALSE;
- break;
-
- case 4:
- if (c == 'f')
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED off\n"); */ }
-#endif
- EAS_HWLED(pEASData->hwInstData, EAS_FALSE);
- return EAS_TRUE;
- }
- return EAS_FALSE;
-
- default:
- if (c != ledStr[i])
- return EAS_FALSE;
- break;
- }
- }
- return EAS_FALSE;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetVibeState()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
-{
- EAS_I8 c;
- EAS_INT i;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVibeState\n"); */ }
-#endif
-
- for (i = 0; i < 6; i++)
- {
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
- if (!c)
- return EAS_FALSE;
- switch (i)
- {
- case 4:
- if (c == 'n')
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate on\n"); */ }
-#endif
- EAS_HWVibrate(pEASData->hwInstData, EAS_TRUE);
- return EAS_TRUE;
- }
- else if (c != 'f')
- return EAS_FALSE;
- break;
-
- case 5:
- if (c == 'f')
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate off\n"); */ }
-#endif
- EAS_HWVibrate(pEASData->hwInstData, EAS_FALSE);
- return EAS_TRUE;
- }
- return EAS_FALSE;
-
- default:
- if (c != vibeStr[i])
- return EAS_FALSE;
- break;
- }
- }
- return EAS_FALSE;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetBackState()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
-{
- EAS_I8 c;
- EAS_INT i;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetBackState\n"); */ }
-#endif
-
- for (i = 0; i < 5; i++)
- {
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
- if (!c)
- return EAS_FALSE;
- switch (i)
- {
- case 3:
- if (c == 'n')
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight on\n"); */ }
-#endif
- EAS_HWBackLight(pEASData->hwInstData, EAS_TRUE);
- return EAS_TRUE;
- }
- else if (c != 'f')
- return EAS_FALSE;
- break;
-
- case 4:
- if (c == 'f')
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight off\n"); */ }
-#endif
- EAS_HWBackLight(pEASData->hwInstData, EAS_FALSE);
- return EAS_TRUE;
- }
- return EAS_FALSE;
-
- default:
- if (c != backStr[i])
- return EAS_FALSE;
- break;
- }
- }
- return EAS_FALSE;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader)
-{
- EAS_INT temp;
- EAS_I8 c;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVolume\n"); */ }
-#endif
-
- c = IMY_GetNextChar(hwInstData, pData, inHeader);
- if (c == '+')
- {
- if (pData->volume < 15)
- pData->volume++;
- return EAS_TRUE;
- }
- else if (c == '-')
- {
- if (pData->volume > 0)
- pData->volume--;
- return EAS_TRUE;
- }
- else if (IsDigit(c))
- temp = c - '0';
- else
- return EAS_FALSE;
-
- c = IMY_GetNextChar(hwInstData, pData, inHeader);
- if (IsDigit(c))
- temp = temp * 10 + c - '0';
- else if (c)
- PutBackChar(pData);
- if ((temp >= 0) && (temp <= 15))
- {
- if (inHeader && (temp == 0))
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring V0 encountered in header\n"); */ }
- else
- pData->volume = (EAS_U8) temp;
- }
- return EAS_TRUE;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetNumber()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader)
-{
- EAS_BOOL ok;
- EAS_I8 c;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetNumber\n"); */ }
-#endif
-
- *temp = 0;
- ok = EAS_FALSE;
- for (;;)
- {
- c = IMY_GetNextChar(hwInstData, pData, inHeader);
- if (IsDigit(c))
- {
- *temp = *temp * 10 + c - '0';
- ok = EAS_TRUE;
- }
- else
- {
- if (c)
- PutBackChar(pData);
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNumber: value %d\n", *temp); */ }
-#endif
-
- return ok;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetVersion()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL IMY_GetVersion (S_IMELODY_DATA *pData, EAS_INT *pVersion)
-{
- EAS_I8 c;
- EAS_INT temp;
- EAS_INT version;
-
- version = temp = 0;
- for (;;)
- {
- c = pData->buffer[pData->index++];
- if ((c == 0) || (c == '.'))
- {
- /*lint -e{701} use shift for performance */
- version = (version << 8) + temp;
- if (c == 0)
- {
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVersion: version 0x%04x\n", version); */ }
-#endif
-
- *pVersion = version;
- return EAS_TRUE;
- }
- temp = 0;
- }
- else if (IsDigit(c))
- temp = (temp * 10) + c - '0';
- }
-}
-
-/*----------------------------------------------------------------------------
- * IMY_MetaData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static void IMY_MetaData (S_IMELODY_DATA *pData, E_EAS_METADATA_TYPE metaType, EAS_I8 *buffer)
-{
- EAS_I32 len;
-
- /* check for callback */
- if (!pData->metadata.callback)
- return;
-
- /* copy data to host buffer */
- len = (EAS_I32) strlen((char*) buffer);
- if (len >pData->metadata.bufferSize)
- len = pData->metadata.bufferSize;
- strncpy((char*) pData->metadata.buffer, (char*) buffer, (size_t) len);
- pData->metadata.buffer[len] = 0;
-
- /* callback to host */
- pData->metadata.callback(metaType, pData->metadata.buffer, pData->metadata.pUserData);
-}
-
-/*----------------------------------------------------------------------------
- * IMY_ParseHeader()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData)
-{
- EAS_RESULT result;
- EAS_INT token;
- EAS_INT temp;
- EAS_I8 c;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_ParseHeader\n"); */ }
-#endif
-
- /* initialize some defaults */
- pData->time = 0;
- pData->tick = DEFAULT_TICK_CONV;
- pData->note = 0;
- pData->noteModifier = 0;
- pData ->restTicks = 0;
- pData->volume = 7;
- pData->octave = 60;
- pData->repeatOffset = -1;
- pData->repeatCount = -1;
- pData->style = 0;
-
- /* force the read of the first line */
- pData->index = 1;
-
- /* read data until we get to melody */
- for (;;)
- {
- /* read a line from the file and parse the token */
- if (pData->index != 0)
- {
- if ((result = IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine)) != EAS_SUCCESS)
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: IMY_ReadLine returned %d\n", result); */ }
-#endif
- return result;
- }
- }
- token = IMY_ParseLine(pData->buffer, &pData->index);
-
- switch (token)
- {
- /* ignore these valid tokens */
- case TOKEN_BEGIN:
- break;
-
- case TOKEN_FORMAT:
- if (!IMY_GetVersion(pData, &temp))
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid FORMAT field '%s'\n", pData->buffer); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
- if ((temp != 0x0100) && (temp != 0x0200))
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported FORMAT %02x\n", temp); */ }
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
- }
- break;
-
- case TOKEN_VERSION:
- if (!IMY_GetVersion(pData, &temp))
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid VERSION field '%s'\n", pData->buffer); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
- if ((temp != 0x0100) && (temp != 0x0102))
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported VERSION %02x\n", temp); */ }
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
- }
- break;
-
- case TOKEN_NAME:
- IMY_MetaData(pData, EAS_METADATA_TITLE, pData->buffer + pData->index);
- break;
-
- case TOKEN_COMPOSER:
- IMY_MetaData(pData, EAS_METADATA_AUTHOR, pData->buffer + pData->index);
- break;
-
- /* handle beat */
- case TOKEN_BEAT:
- IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_TRUE);
- if ((temp >= 25) && (temp <= 900))
- pData->tick = TICK_CONVERT / temp;
- break;
-
- /* handle style */
- case TOKEN_STYLE:
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE);
- if (c == 'S')
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE);
- if ((c >= '0') && (c <= '2'))
- pData->style = (EAS_U8) (c - '0');
- else
- {
- PutBackChar(pData);
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in style command: %s\n", pData->buffer); */ }
- }
- break;
-
- /* handle volume */
- case TOKEN_VOLUME:
- c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE);
- if (c != 'V')
- {
- PutBackChar(pData);
- if (!IsDigit(c))
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in volume command: %s\n", pData->buffer); */ }
- break;
- }
- }
- IMY_GetVolume(pEASData->hwInstData, pData, EAS_TRUE);
- break;
-
- case TOKEN_MELODY:
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Header successfully parsed\n"); */ }
-#endif
- return EAS_SUCCESS;
-
- case TOKEN_END:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unexpected END:IMELODY encountered\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
-
- default:
- /* force a read of the next line */
- pData->index = 1;
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized token in iMelody file: %s\n", pData->buffer); */ }
- break;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * IMY_GetNextChar()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader)
-{
- EAS_I8 c;
- EAS_U8 index;
-
- for (;;)
- {
- /* get next character */
- c = pData->buffer[pData->index++];
-
- /* buffer empty, read more */
- if (!c)
- {
- /* don't read the next line in the header */
- if (inHeader)
- return 0;
-
- pData->index = 0;
- pData->buffer[0] = 0;
- if (IMY_ReadLine(hwInstData, pData->fileHandle, pData->buffer, &pData->startLine) != EAS_SUCCESS)
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: EOF\n"); */ }
-#endif
- return 0;
- }
-
- /* check for END:IMELODY token */
- if (IMY_ParseLine(pData->buffer, &index) == TOKEN_END)
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: found END:IMELODY\n"); */ }
-#endif
- pData->buffer[0] = 0;
- return 0;
- }
- continue;
- }
-
- /* ignore white space */
- if (!IsSpace(c))
- {
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar returned '%c'\n", c); */ }
-#endif
- return c;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * IMY_ReadLine()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reads a line of input from the file, discarding the CR/LF
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine)
-{
- EAS_RESULT result;
- EAS_INT i;
- EAS_I8 c;
-
- /* fetch current file position and save it */
- if (pStartLine != NULL)
- {
- if ((result = EAS_HWFilePos(hwInstData, fileHandle, pStartLine)) != EAS_SUCCESS)
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: EAS_HWFilePos returned %d\n", result); */ }
-#endif
- return result;
- }
- }
-
- buffer[0] = 0;
- for (i = 0; i < MAX_LINE_SIZE; )
- {
- if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
- {
- if ((result == EAS_EOF) && (i > 0))
- break;
- return result;
- }
-
- /* return on LF or end of data */
- if (c == '\n')
- break;
-
- /* store characters in buffer */
- if (c != '\r')
- buffer[i++] = c;
- }
- buffer[i] = 0;
-
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ReadLine read %s\n", buffer); */ }
-#endif
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * IMY_ParseLine()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex)
-{
- EAS_INT i;
- EAS_INT j;
-
- /* there's no strnicmp() in stdlib, so we have to roll our own */
- for (i = 0; i < TOKEN_INVALID; i++)
- {
- for (j = 0; ; j++)
- {
- /* end of token, must be a match */
- if (tokens[i][j] == 0)
- {
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine found token %d\n", i); */ }
-#endif
- *pIndex = (EAS_U8) j;
- return i;
- }
- if (tokens[i][j] != ToUpper(buffer[j]))
- break;
- }
- }
-#ifdef _DEBUG_IMELODY
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine: no token found\n"); */ }
-#endif
- return TOKEN_INVALID;
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 797 $ + * $Date: 2007-08-01 00:15:56 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint doesn't like the way some string.h files look */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include <string.h> +#endif + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_imelodydata.h" +#include "eas_ctype.h" + +// #define _DEBUG_IMELODY + +/* increase gain for mono ringtones */ +#define IMELODY_GAIN_OFFSET 8 + +/* length of 32nd note in 1/256ths of a msec for 120 BPM tempo */ +#define DEFAULT_TICK_CONV 16000 +#define TICK_CONVERT 1920000 + +/* default channel and program for iMelody playback */ +#define IMELODY_CHANNEL 0 +#define IMELODY_PROGRAM 80 +#define IMELODY_VEL_MUL 4 +#define IMELODY_VEL_OFS 67 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +static const char* const tokens[] = +{ + "BEGIN:IMELODY", + "VERSION:", + "FORMAT:CLASS", + "NAME:", + "COMPOSER:", + "BEAT:", + "STYLE:", + "VOLUME:", + "MELODY:", + "END:IMELODY" +}; + +/* ledon or ledoff */ +static const char ledStr[] = "edo"; + +/* vibeon or vibeoff */ +static const char vibeStr[] = "ibeo"; + +/* backon or backoff */ +static const char backStr[] = "cko"; + +typedef enum +{ + TOKEN_BEGIN, + TOKEN_VERSION, + TOKEN_FORMAT, + TOKEN_NAME, + TOKEN_COMPOSER, + TOKEN_BEAT, + TOKEN_STYLE, + TOKEN_VOLUME, + TOKEN_MELODY, + TOKEN_END, + TOKEN_INVALID +} ENUM_IMELODY_TOKENS; + +/* lookup table for note values */ +static const EAS_I8 noteTable[] = { 9, 11, 0, 2, 4, 5, 7 }; + +/* inline functions */ +#ifdef _DEBUG_IMELODY +static void PutBackChar (S_IMELODY_DATA *pData) +{ + if (pData->index) + pData->index--; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "PutBackChar '%c'\n", pData->buffer[pData->index]); */ } +} +#else +EAS_INLINE void PutBackChar (S_IMELODY_DATA *pData) { if (pData->index) pData->index--; } +#endif + + +/* local prototypes */ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode); +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration); +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader); +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData); +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine); +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex); + + +/*---------------------------------------------------------------------------- + * + * EAS_iMelody_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_iMelody_Parser = +{ + IMY_CheckFileType, + IMY_Prepare, + IMY_Time, + IMY_Event, + IMY_State, + IMY_Close, + IMY_Reset, + IMY_Pause, + IMY_Resume, + NULL, + IMY_SetData, + IMY_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * IMY_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_IMELODY_DATA* pData; + EAS_I8 buffer[MAX_LINE_SIZE+1]; + EAS_U8 index; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_CheckFileType\n"); */ } +#endif + + /* read the first line of the file */ + *ppHandle = NULL; + if (IMY_ReadLine(pEASData->hwInstData, fileHandle, buffer, NULL) != EAS_SUCCESS) + return EAS_SUCCESS; + + /* check for header string */ + if (IMY_ParseLine(buffer, &index) == TOKEN_BEGIN) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_IMELODY_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_IMELODY_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_IMELODY_DATA)); + + /* initialize */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_ERROR; + pData->state = EAS_STATE_OPEN; + + /* return a pointer to the instance data */ + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_Prepare\n"); */ } +#endif + + /* check for valid state */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the header */ + if ((result = IMY_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Prepare: state set to EAS_STATE_READY\n"); */ } +#endif + + pData ->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + EAS_I8 c; + EAS_BOOL eof; + EAS_INT temp; + + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: Reset\n"); */ } +#endif + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, IMELODY_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Stopping note %d\n", pData->note); */ } +#endif + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + eof = EAS_FALSE; + while (!eof) + { + + /* get next character */ + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + + switch (c) + { + /* start repeat */ + case '(': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter repeat section\n", c); */ } +#endif + + if (pData->repeatOffset < 0) + { + pData->repeatOffset = pData->startLine + (EAS_I32) pData->index; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat offset = %d\n", pData->repeatOffset); */ } +#endif + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring nested repeat section\n"); */ } + break; + + /* end repeat */ + case ')': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "End repeat section, repeat offset = %d\n", pData->repeatOffset); */ } +#endif + /* ignore invalid repeats */ + if (pData->repeatCount >= 0) + { + + /* decrement repeat count (repeatCount == 0 means infinite loop) */ + if (pData->repeatCount > 0) + { + if (--pData->repeatCount == 0) + { + pData->repeatCount = -1; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat loop complete\n"); */ } +#endif + } + } + +//2 TEMPORARY FIX: If locating, don't do infinite loops. +//3 We need a different mode for metadata parsing where we don't loop at all + if ((parserMode == eParserModePlay) || (pData->repeatCount != 0)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Rewinding file for repeat\n"); */ } +#endif + /* rewind to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine); + pData->index = 0; + + /* if last loop, prevent future loops */ + if (pData->repeatCount == -1) + pData->repeatOffset = -1; + } + } + break; + + /* repeat count */ + case '@': + if (!IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_FALSE)) + eof = EAS_TRUE; + else if (pData->repeatOffset > 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat count = %dt", pData->repeatCount); */ } +#endif + if (pData->repeatCount < 0) + pData->repeatCount = (EAS_I16) temp; + } + break; + + /* volume */ + case 'V': + if (!IMY_GetVolume(pEASData->hwInstData, pData, EAS_FALSE)) + eof = EAS_TRUE; + break; + + /* flat */ + case '&': + pData->noteModifier = -1; + break; + + /* sharp */ + case '#': + pData->noteModifier = +1; + break; + + /* octave */ + case '*': + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (IsDigit(c)) + pData->octave = (EAS_U8) ((c - '0' + 1) * 12); + else if (!c) + eof = EAS_TRUE; + break; + + /* ledon or ledoff */ + case 'l': + if (!IMY_GetLEDState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* vibeon or vibeoff */ + case 'v': + if (!IMY_GetVibeState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* either a B note or backon or backoff */ + case 'b': + if (IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE) == 'a') + { + if (!IMY_GetBackState(pEASData, pData)) + eof = EAS_TRUE; + } + else + { + PutBackChar(pData); + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + break; + + /* rest */ + case 'r': + case 'R': + if (IMY_PlayRest(pEASData, pData)) + return EAS_SUCCESS; + eof = EAS_TRUE; + break; + + /* EOF */ + case 0: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: end of iMelody file detected\n"); */ } +#endif + eof = EAS_TRUE; + break; + + /* must be a note */ + default: + c = ToLower(c); + if ((c >= 'a') && (c <= 'g')) + { + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unexpected character '%c' [0x%02x]\n", c, c); */ } + break; + } + } + + /* handle EOF */ +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: state set to EAS_STATE_STOPPING\n"); */ } +#endif + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_IMELODY_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_IMELODY_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { + pData->state = EAS_STATE_STOPPED; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_STOPPED\n"); */ } +#endif + } + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_PAUSED\n"); */ } +#endif + pData->state = EAS_STATE_PAUSED; + } + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Close: close file\n"); */ } +#endif + + pData = (S_IMELODY_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: reset file\n"); */ } +#endif + pData = (S_IMELODY_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = IMY_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: state set to EAS_STATE_ERROR\n"); */ } +#endif + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Pause: pause file\n"); */ } +#endif + + /* can't pause a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Resume: resume file\n"); */ } +#endif + + /* can't resume a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Adjust tempo relative to song tempo + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return the file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + switch (param) + { + /* return file type as iMelody */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_IMELODY; + break; + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = IMELODY_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayNote() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode) +{ + EAS_I32 duration; + EAS_U8 velocity; + + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: start note %d\n", note); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + + /* save note value */ + pData->note = (EAS_U8) (pData->octave + noteTable[note - 'a'] + pData->noteModifier); + velocity = (EAS_U8) (pData->volume ? pData->volume * IMELODY_VEL_MUL + IMELODY_VEL_OFS : 0); + + /* start note only if in play mode */ + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, velocity); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: Start note %d, duration %d\n", pData->note, duration); */ } +#endif + + /* determine note length */ + switch (pData->style) + { + case 0: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "IMY_PlayNote: Note style out of range: %d\n", pData->style); */ } + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + } + + /* next event is at end of this note */ + pData->time += duration - pData->restTicks; + + /* reset the flat/sharp modifier */ + pData->noteModifier = 0; + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayRest() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I32 duration; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_PlayRest]n"); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayRest: note duration %d\n", duration); */ } +#endif + + /* next event is at end of this note */ + pData->time += duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration) +{ + EAS_I32 duration; + EAS_I8 c; + + /* get the duration */ + *pDuration = 0; + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + if ((c < '0') || (c > '5')) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetDuration: error in duration '%c'\n", c); */ } +#endif + return EAS_FALSE; + } + + /* calculate total length of note */ + duration = pData->tick * (1 << ('5' - c)); + + /* check for duration modifier */ + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (c) + { + if (c == '.') + /*lint -e{704} shift for performance */ + duration += duration >> 1; + else if (c == ':') + /*lint -e{704} shift for performance */ + duration += (duration >> 1) + (duration >> 2); + else if (c == ';') + /*lint -e{704} shift for performance */ + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + else + PutBackChar(pData); + } + + *pDuration = duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetLEDState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetLEDState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED on\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED off\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != ledStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVibeState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVibeState\n"); */ } +#endif + + for (i = 0; i < 6; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 4: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate on\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 5: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate off\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != vibeStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetBackState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetBackState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight on\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight off\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != backStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVolume\n"); */ } +#endif + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (c == '+') + { + if (pData->volume < 15) + pData->volume++; + return EAS_TRUE; + } + else if (c == '-') + { + if (pData->volume > 0) + pData->volume--; + return EAS_TRUE; + } + else if (IsDigit(c)) + temp = c - '0'; + else + return EAS_FALSE; + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + temp = temp * 10 + c - '0'; + else if (c) + PutBackChar(pData); + if ((temp >= 0) && (temp <= 15)) + { + if (inHeader && (temp == 0)) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring V0 encountered in header\n"); */ } + else + pData->volume = (EAS_U8) temp; + } + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader) +{ + EAS_BOOL ok; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetNumber\n"); */ } +#endif + + *temp = 0; + ok = EAS_FALSE; + for (;;) + { + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + { + *temp = *temp * 10 + c - '0'; + ok = EAS_TRUE; + } + else + { + if (c) + PutBackChar(pData); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNumber: value %d\n", *temp); */ } +#endif + + return ok; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetVersion() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVersion (S_IMELODY_DATA *pData, EAS_INT *pVersion) +{ + EAS_I8 c; + EAS_INT temp; + EAS_INT version; + + version = temp = 0; + for (;;) + { + c = pData->buffer[pData->index++]; + if ((c == 0) || (c == '.')) + { + /*lint -e{701} use shift for performance */ + version = (version << 8) + temp; + if (c == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVersion: version 0x%04x\n", version); */ } +#endif + + *pVersion = version; + return EAS_TRUE; + } + temp = 0; + } + else if (IsDigit(c)) + temp = (temp * 10) + c - '0'; + } +} + +/*---------------------------------------------------------------------------- + * IMY_MetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMY_MetaData (S_IMELODY_DATA *pData, E_EAS_METADATA_TYPE metaType, EAS_I8 *buffer) +{ + EAS_I32 len; + + /* check for callback */ + if (!pData->metadata.callback) + return; + + /* copy data to host buffer */ + len = (EAS_I32) strlen((char*) buffer); + if (len >pData->metadata.bufferSize) + len = pData->metadata.bufferSize; + strncpy((char*) pData->metadata.buffer, (char*) buffer, (size_t) len); + pData->metadata.buffer[len] = 0; + + /* callback to host */ + pData->metadata.callback(metaType, pData->metadata.buffer, pData->metadata.pUserData); +} + +/*---------------------------------------------------------------------------- + * IMY_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData) +{ + EAS_RESULT result; + EAS_INT token; + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_ParseHeader\n"); */ } +#endif + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->noteModifier = 0; + pData ->restTicks = 0; + pData->volume = 7; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = -1; + pData->style = 0; + + /* force the read of the first line */ + pData->index = 1; + + /* read data until we get to melody */ + for (;;) + { + /* read a line from the file and parse the token */ + if (pData->index != 0) + { + if ((result = IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: IMY_ReadLine returned %d\n", result); */ } +#endif + return result; + } + } + token = IMY_ParseLine(pData->buffer, &pData->index); + + switch (token) + { + /* ignore these valid tokens */ + case TOKEN_BEGIN: + break; + + case TOKEN_FORMAT: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid FORMAT field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0200)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported FORMAT %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_VERSION: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid VERSION field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0102)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported VERSION %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_NAME: + IMY_MetaData(pData, EAS_METADATA_TITLE, pData->buffer + pData->index); + break; + + case TOKEN_COMPOSER: + IMY_MetaData(pData, EAS_METADATA_AUTHOR, pData->buffer + pData->index); + break; + + /* handle beat */ + case TOKEN_BEAT: + IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_TRUE); + if ((temp >= 25) && (temp <= 900)) + pData->tick = TICK_CONVERT / temp; + break; + + /* handle style */ + case TOKEN_STYLE: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c == 'S') + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if ((c >= '0') && (c <= '2')) + pData->style = (EAS_U8) (c - '0'); + else + { + PutBackChar(pData); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in style command: %s\n", pData->buffer); */ } + } + break; + + /* handle volume */ + case TOKEN_VOLUME: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c != 'V') + { + PutBackChar(pData); + if (!IsDigit(c)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in volume command: %s\n", pData->buffer); */ } + break; + } + } + IMY_GetVolume(pEASData->hwInstData, pData, EAS_TRUE); + break; + + case TOKEN_MELODY: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Header successfully parsed\n"); */ } +#endif + return EAS_SUCCESS; + + case TOKEN_END: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unexpected END:IMELODY encountered\n"); */ } + return EAS_ERROR_FILE_FORMAT; + + default: + /* force a read of the next line */ + pData->index = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized token in iMelody file: %s\n", pData->buffer); */ } + break; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_I8 c; + EAS_U8 index; + + for (;;) + { + /* get next character */ + c = pData->buffer[pData->index++]; + + /* buffer empty, read more */ + if (!c) + { + /* don't read the next line in the header */ + if (inHeader) + return 0; + + pData->index = 0; + pData->buffer[0] = 0; + if (IMY_ReadLine(hwInstData, pData->fileHandle, pData->buffer, &pData->startLine) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: EOF\n"); */ } +#endif + return 0; + } + + /* check for END:IMELODY token */ + if (IMY_ParseLine(pData->buffer, &index) == TOKEN_END) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: found END:IMELODY\n"); */ } +#endif + pData->buffer[0] = 0; + return 0; + } + continue; + } + + /* ignore white space */ + if (!IsSpace(c)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar returned '%c'\n", c); */ } +#endif + return c; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_ReadLine() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a line of input from the file, discarding the CR/LF + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine) +{ + EAS_RESULT result; + EAS_INT i; + EAS_I8 c; + + /* fetch current file position and save it */ + if (pStartLine != NULL) + { + if ((result = EAS_HWFilePos(hwInstData, fileHandle, pStartLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: EAS_HWFilePos returned %d\n", result); */ } +#endif + return result; + } + } + + buffer[0] = 0; + for (i = 0; i < MAX_LINE_SIZE; ) + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (i > 0)) + break; + return result; + } + + /* return on LF or end of data */ + if (c == '\n') + break; + + /* store characters in buffer */ + if (c != '\r') + buffer[i++] = c; + } + buffer[i] = 0; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ReadLine read %s\n", buffer); */ } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_ParseLine() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex) +{ + EAS_INT i; + EAS_INT j; + + /* there's no strnicmp() in stdlib, so we have to roll our own */ + for (i = 0; i < TOKEN_INVALID; i++) + { + for (j = 0; ; j++) + { + /* end of token, must be a match */ + if (tokens[i][j] == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine found token %d\n", i); */ } +#endif + *pIndex = (EAS_U8) j; + return i; + } + if (tokens[i][j] != ToUpper(buffer[j])) + break; + } + } +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine: no token found\n"); */ } +#endif + return TOKEN_INVALID; +} + diff --git a/arm-fm-22k/lib_src/eas_imelodydata.c b/arm-fm-22k/lib_src/eas_imelodydata.c index e72dc0b..9437e08 100644 --- a/arm-fm-22k/lib_src/eas_imelodydata.c +++ b/arm-fm-22k/lib_src/eas_imelodydata.c @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_imelodydata.c
- *
- * Contents and purpose:
- * SMF File Parser
- *
- * This file contains data definitions for the SMF parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,23 +21,23 @@ * 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: 547 $
- * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_types.h"
-#include "eas_imelodydata.h"
-
-/*----------------------------------------------------------------------------
- *
- * eas_iMelodyData
- *
- * Static memory allocation for iMelody parser
- *----------------------------------------------------------------------------
-*/
-S_IMELODY_DATA eas_iMelodyData;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_imelodydata.h" + +/*---------------------------------------------------------------------------- + * + * eas_iMelodyData + * + * Static memory allocation for iMelody parser + *---------------------------------------------------------------------------- +*/ +S_IMELODY_DATA eas_iMelodyData; + diff --git a/arm-fm-22k/lib_src/eas_imelodydata.h b/arm-fm-22k/lib_src/eas_imelodydata.h index 303b8f6..57c1ed0 100644 --- a/arm-fm-22k/lib_src/eas_imelodydata.h +++ b/arm-fm-22k/lib_src/eas_imelodydata.h @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_imelodydata.h
- *
- * Contents and purpose:
- * SMF File Parser
- *
- * This file contains data declarations for the iMelody parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the iMelody parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,53 +21,53 @@ * 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: 778 $
- * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef EAS_IMELODYDATA_H
-#define EAS_IMELODYDATA_H
-
-#include "eas_data.h"
-
-/* maximum line size as specified in iMelody V1.2 spec */
-#define MAX_LINE_SIZE 75
-
-/*----------------------------------------------------------------------------
- *
- * S_IMELODY_DATA
- *
- * This structure contains the state data for the iMelody parser
- *----------------------------------------------------------------------------
-*/
-
-typedef struct
-{
- EAS_FILE_HANDLE fileHandle; /* file handle */
- S_SYNTH *pSynth; /* pointer to synth */
- EAS_I32 fileOffset; /* offset to start of data */
- EAS_I32 time; /* current time in 256ths of a msec */
- EAS_I32 tickBase; /* basline length of 32nd note in 256th of a msec */
- EAS_I32 tick; /* actual length of 32nd note in 256th of a msec */
- EAS_I32 restTicks; /* ticks to rest after current note */
- EAS_I32 startLine; /* file offset at start of line (for repeats) */
- EAS_I32 repeatOffset; /* file offset to start of repeat section */
- S_METADATA_CB metadata; /* metadata callback */
- EAS_I16 repeatCount; /* repeat counter */
- EAS_U8 state; /* current state EAS_STATE_XXXX */
- EAS_U8 style; /* from STYLE */
- EAS_U8 index; /* index into buffer */
- EAS_U8 octave; /* octave prefix */
- EAS_U8 volume; /* current volume */
- EAS_U8 note; /* MIDI note number */
- EAS_I8 noteModifier; /* sharp or flat */
- EAS_I8 buffer[MAX_LINE_SIZE+1]; /* buffer for ASCII data */
-} S_IMELODY_DATA;
-
-#endif
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_IMELODYDATA_H +#define EAS_IMELODYDATA_H + +#include "eas_data.h" + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_IMELODY_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tickBase; /* basline length of 32nd note in 256th of a msec */ + EAS_I32 tick; /* actual length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 startLine; /* file offset at start of line (for repeats) */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I16 repeatCount; /* repeat counter */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 style; /* from STYLE */ + EAS_U8 index; /* index into buffer */ + EAS_U8 octave; /* octave prefix */ + EAS_U8 volume; /* current volume */ + EAS_U8 note; /* MIDI note number */ + EAS_I8 noteModifier; /* sharp or flat */ + EAS_I8 buffer[MAX_LINE_SIZE+1]; /* buffer for ASCII data */ +} S_IMELODY_DATA; + +#endif + + diff --git a/arm-fm-22k/lib_src/eas_math.c b/arm-fm-22k/lib_src/eas_math.c index 12d788e..dc85051 100644 --- a/arm-fm-22k/lib_src/eas_math.c +++ b/arm-fm-22k/lib_src/eas_math.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_math.c
- *
- * Contents and purpose:
- * Contains common math routines for the various audio engines.
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_math.c + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,149 +20,149 @@ * 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: 586 $
- * $Date: 2007-03-08 20:33:04 -0800 (Thu, 08 Mar 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas.h"
-#include "eas_math.h"
-
-/* anything less than this converts to a fraction too small to represent in 32-bits */
-#define MIN_CENTS -18000
-
-/*----------------------------------------------------------------------------
- * EAS_Calculate2toX()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate 2^x
- *
- * Inputs:
- * nCents - measured in cents
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 EAS_Calculate2toX (EAS_I32 nCents)
-{
- EAS_I32 nDents;
- EAS_I32 nExponentInt, nExponentFrac;
- EAS_I32 nTemp1, nTemp2;
- EAS_I32 nResult;
-
- /* check for minimum value */
- if (nCents < MIN_CENTS)
- return 0;
-
- /* for the time being, convert cents to dents */
- nDents = FMUL_15x15(nCents, CENTS_TO_DENTS);
-
- nExponentInt = GET_DENTS_INT_PART(nDents);
- nExponentFrac = GET_DENTS_FRAC_PART(nDents);
-
- /*
- implement 2^(fracPart) as a power series
- */
- nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3);
- nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1);
- nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2);
-
- /*
- implement 2^(intPart) as
- a left shift for intPart >= 0 or
- a left shift for intPart < 0
- */
- if (nExponentInt >= 0)
- {
- /* left shift for positive exponents */
- /*lint -e{703} <avoid multiply for performance>*/
- nResult = nTemp1 << nExponentInt;
- }
- else
- {
- /* right shift for negative exponents */
- nExponentInt = -nExponentInt;
- nResult = nTemp1 >> nExponentInt;
- }
-
- return nResult;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_LogToLinear16()
- *----------------------------------------------------------------------------
- * Purpose:
- * Transform log value to linear gain multiplier using piece-wise linear
- * approximation
- *
- * Inputs:
- * nGain - log scale value in 20.10 format. Even though gain is normally
- * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate
- * the need for saturation checking when combining gain values.
- *
- * Outputs:
- * Returns a 16-bit linear value approximately equal to 2^(nGain/1024)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain)
-{
- EAS_INT nExp;
- EAS_U16 nTemp;
-
- /* bias to positive */
- nGain += 32767;
-
- /* check for infinite attenuation */
- if (nGain < 0)
- return 0;
-
- /* extract the exponent */
- nExp = 31 - (nGain >> 10);
-
- /* check for maximum output */
- if (nExp < 0)
- return 0x7fff;
-
- /* extract mantissa and restore implied 1 bit */
- nTemp = (EAS_U16)((((nGain & 0x3ff) << 4) | 0x4000) >> nExp);
-
- /* use shift to approximate power-of-2 operation */
- return nTemp;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_VolumeToGain()
- *----------------------------------------------------------------------------
- * Purpose:
- * Transform volume control in 1dB increments to gain multiplier
- *
- * Inputs:
- * volume - 100 = 0dB, 99 = -1dB, 0 = -inf
- *
- * Outputs:
- * Returns a 16-bit linear value
- *----------------------------------------------------------------------------
-*/
-EAS_I16 EAS_VolumeToGain (EAS_INT volume)
-{
- /* check for limits */
- if (volume <= 0)
- return 0;
- if (volume >= 100)
- return 0x7fff;
-
- /*lint -e{702} use shift instead of division */
- return (EAS_I16) EAS_Calculate2toX((((volume - EAS_MAX_VOLUME) * 204099) >> 10) - 1);
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 586 $ + * $Date: 2007-03-08 20:33:04 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_math.h" + +/* anything less than this converts to a fraction too small to represent in 32-bits */ +#define MIN_CENTS -18000 + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents) +{ + EAS_I32 nDents; + EAS_I32 nExponentInt, nExponentFrac; + EAS_I32 nTemp1, nTemp2; + EAS_I32 nResult; + + /* check for minimum value */ + if (nCents < MIN_CENTS) + return 0; + + /* for the time being, convert cents to dents */ + nDents = FMUL_15x15(nCents, CENTS_TO_DENTS); + + nExponentInt = GET_DENTS_INT_PART(nDents); + nExponentFrac = GET_DENTS_FRAC_PART(nDents); + + /* + implement 2^(fracPart) as a power series + */ + nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3); + nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1); + nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2); + + /* + implement 2^(intPart) as + a left shift for intPart >= 0 or + a left shift for intPart < 0 + */ + if (nExponentInt >= 0) + { + /* left shift for positive exponents */ + /*lint -e{703} <avoid multiply for performance>*/ + nResult = nTemp1 << nExponentInt; + } + else + { + /* right shift for negative exponents */ + nExponentInt = -nExponentInt; + nResult = nTemp1 >> nExponentInt; + } + + return nResult; +} + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain) +{ + EAS_INT nExp; + EAS_U16 nTemp; + + /* bias to positive */ + nGain += 32767; + + /* check for infinite attenuation */ + if (nGain < 0) + return 0; + + /* extract the exponent */ + nExp = 31 - (nGain >> 10); + + /* check for maximum output */ + if (nExp < 0) + return 0x7fff; + + /* extract mantissa and restore implied 1 bit */ + nTemp = (EAS_U16)((((nGain & 0x3ff) << 4) | 0x4000) >> nExp); + + /* use shift to approximate power-of-2 operation */ + return nTemp; +} + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume) +{ + /* check for limits */ + if (volume <= 0) + return 0; + if (volume >= 100) + return 0x7fff; + + /*lint -e{702} use shift instead of division */ + return (EAS_I16) EAS_Calculate2toX((((volume - EAS_MAX_VOLUME) * 204099) >> 10) - 1); +} + diff --git a/arm-fm-22k/lib_src/eas_math.h b/arm-fm-22k/lib_src/eas_math.h index 719270b..f240b51 100644 --- a/arm-fm-22k/lib_src/eas_math.h +++ b/arm-fm-22k/lib_src/eas_math.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_math.h
- *
- * Contents and purpose:
- * Contains common math routines for the various audio engines.
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_math.h + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,393 +20,393 @@ * 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: 584 $
- * $Date: 2007-03-08 09:49:24 -0800 (Thu, 08 Mar 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_MATH_H
-#define _EAS_MATH_H
-
-
-/** coefs for pan, generates sin, cos */
-#define COEFF_PAN_G2 -27146 /* -0.82842712474619 = 2 - 4/sqrt(2) */
-#define COEFF_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */
-
-/*
-coefficients for approximating
-2^x = gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3
-where x is a int.frac number representing number of octaves.
-Actually, we approximate only the 2^(frac) using the power series
-and implement the 2^(int) as a shift, so that
-2^x == 2^(int.frac) == 2^(int) * 2^(fract)
- == (gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3) << (int)
-
-The gn2toX.. were generated using a best fit for a 3rd
-order polynomial, instead of taking the coefficients from
-a truncated Taylor (or Maclaurin?) series.
-*/
-
-#define GN2_TO_X0 32768 /* 1 */
-#define GN2_TO_X1 22833 /* 0.696807861328125 */
-#define GN2_TO_X2 7344 /* 0.22412109375 */
-#define GN2_TO_X3 2588 /* 0.0789794921875 */
-
-/*----------------------------------------------------------------------------
- * Fixed Point Math
- *----------------------------------------------------------------------------
- * These macros are used for fixed point multiplies. If the processor
- * supports fixed point multiplies, replace these macros with inline
- * assembly code to improve performance.
- *----------------------------------------------------------------------------
-*/
-
-/* Fixed point multiply 0.15 x 0.15 = 0.15 returned as 32-bits */
-#define FMUL_15x15(a,b) \
- /*lint -e(704) <avoid multiply for performance>*/ \
- (((EAS_I32)(a) * (EAS_I32)(b)) >> 15)
-
-/* Fixed point multiply 0.7 x 0.7 = 0.15 returned as 32-bits */
-#define FMUL_7x7(a,b) \
- /*lint -e(704) <avoid multiply for performance>*/ \
- (((EAS_I32)(a) * (EAS_I32)(b) ) << 1)
-
-/* Fixed point multiply 0.8 x 0.8 = 0.15 returned as 32-bits */
-#define FMUL_8x8(a,b) \
- /*lint -e(704) <avoid multiply for performance>*/ \
- (((EAS_I32)(a) * (EAS_I32)(b) ) >> 1)
-
-/* Fixed point multiply 0.8 x 1.15 = 0.15 returned as 32-bits */
-#define FMUL_8x15(a,b) \
- /*lint -e(704) <avoid divide for performance>*/ \
- (((EAS_I32)((a) << 7) * (EAS_I32)(b)) >> 15)
-
-/* macros for fractional phase accumulator */
-/*
-Note: changed the _U32 to _I32 on 03/14/02. This should not
-affect the phase calculations, and should allow us to reuse these
-macros for other audio sample related math.
-*/
-#define HARDWARE_BIT_WIDTH 32
-
-#define NUM_PHASE_INT_BITS 1
-#define NUM_PHASE_FRAC_BITS 15
-
-#define PHASE_FRAC_MASK (EAS_U32) ((0x1L << NUM_PHASE_FRAC_BITS) -1)
-
-#define GET_PHASE_INT_PART(x) (EAS_U32)((EAS_U32)(x) >> NUM_PHASE_FRAC_BITS)
-#define GET_PHASE_FRAC_PART(x) (EAS_U32)((EAS_U32)(x) & PHASE_FRAC_MASK)
-
-#define DEFAULT_PHASE_FRAC 0
-#define DEFAULT_PHASE_INT 0
-
-/*
-Linear interpolation calculates:
-output = (1-frac) * sample[n] + (frac) * sample[n+1]
-
-where conceptually 0 <= frac < 1
-
-For a fixed point implementation, frac is actually an integer value
-with an implied binary point one position to the left. The value of
-one (unity) is given by PHASE_ONE
-one half and one quarter are useful for 4-point linear interp.
-*/
-#define PHASE_ONE (EAS_I32) (0x1L << NUM_PHASE_FRAC_BITS)
-
-/*
- Multiply the signed audio sample by the unsigned fraction.
-- a is the signed audio sample
-- b is the unsigned fraction (cast to signed int as long as coef
- uses (n-1) or less bits, where n == hardware bit width)
-*/
-#define MULT_AUDIO_COEF(audio,coef) /*lint -e704 <avoid divide for performance>*/ \
- (EAS_I32)( \
- ( \
- ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \
- ) \
- >> NUM_PHASE_FRAC_BITS \
- ) \
- /* lint +704 <restore checking>*/
-
-/* wet / dry calculation macros */
-#define NUM_WET_DRY_FRAC_BITS 7 // 15
-#define NUM_WET_DRY_INT_BITS 9 // 1
-
-/* define a 1.0 */
-#define WET_DRY_ONE (EAS_I32) ((0x1L << NUM_WET_DRY_FRAC_BITS))
-#define WET_DRY_MINUS_ONE (EAS_I32) (~WET_DRY_ONE)
-#define WET_DRY_FULL_SCALE (EAS_I32) (WET_DRY_ONE - 1)
-
-#define MULT_AUDIO_WET_DRY_COEF(audio,coef) /*lint -e(702) <avoid divide for performance>*/ \
- (EAS_I32)( \
- ( \
- ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \
- ) \
- >> NUM_WET_DRY_FRAC_BITS \
- )
-
-/* Envelope 1 (EG1) calculation macros */
-#define NUM_EG1_INT_BITS 1
-#define NUM_EG1_FRAC_BITS 15
-
-/* the max positive gain used in the synth for EG1 */
-/* SYNTH_FULL_SCALE_EG1_GAIN must match the value in the dls2eas
-converter, otherwise, the values we read from the .eas file are bogus. */
-#define SYNTH_FULL_SCALE_EG1_GAIN (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS) -1)
-
-/* define a 1.0 */
-#define EG1_ONE (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS))
-#define EG1_MINUS_ONE (EAS_I32) (~SYNTH_FULL_SCALE_EG1_GAIN)
-
-#define EG1_HALF (EAS_I32) (EG1_ONE/2)
-#define EG1_MINUS_HALF (EAS_I32) (EG1_MINUS_ONE/2)
-
-/*
-We implement the EG1 using a linear gain value, which means that the
-attack segment is handled by incrementing (adding) the linear gain.
-However, EG1 treats the Decay, Sustain, and Release differently than
-the Attack portion. For Decay, Sustain, and Release, the gain is
-linear on dB scale, which is equivalent to exponential damping on
-a linear scale. Because we use a linear gain for EG1, we implement
-the Decay and Release as multiplication (instead of incrementing
-as we did for the attack segment).
-Therefore, we need the following macro to implement the multiplication
-(i.e., exponential damping) during the Decay and Release segments of
-the EG1
-*/
-#define MULT_EG1_EG1(gain,damping) /*lint -e(704) <avoid divide for performance>*/ \
- (EAS_I32)( \
- ( \
- ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \
- ) \
- >> NUM_EG1_FRAC_BITS \
- )
-
-// Use the following macro specifically for the filter, when multiplying
-// the b1 coefficient. The 0 <= |b1| < 2, which therefore might overflow
-// in certain conditions because we store b1 as a 1.15 value.
-// Instead, we could store b1 as b1p (b1' == b1 "prime") where
-// b1p == b1/2, thus ensuring no potential overflow for b1p because
-// 0 <= |b1p| < 1
-// However, during the filter calculation, we must account for the fact
-// that we are using b1p instead of b1, and thereby multiply by
-// an extra factor of 2. Rather than multiply by an extra factor of 2,
-// we can instead shift the result right by one less, hence the
-// modified shift right value of (NUM_EG1_FRAC_BITS -1)
-#define MULT_EG1_EG1_X2(gain,damping) /*lint -e(702) <avoid divide for performance>*/ \
- (EAS_I32)( \
- ( \
- ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \
- ) \
- >> (NUM_EG1_FRAC_BITS -1) \
- )
-
-#define SATURATE_EG1(x) /*lint -e{734} saturation operation */ \
- ((EAS_I32)(x) > SYNTH_FULL_SCALE_EG1_GAIN) ? (SYNTH_FULL_SCALE_EG1_GAIN) : \
- ((EAS_I32)(x) < EG1_MINUS_ONE) ? (EG1_MINUS_ONE) : (x);
-
-
-/* use "digital cents" == "dents" instead of cents */
-/* we coudl re-use the phase frac macros, but if we do,
-we must change the phase macros to cast to _I32 instead of _U32,
-because using a _U32 cast causes problems when shifting the exponent
-for the 2^x calculation, because right shift a negative values MUST
-be sign extended, or else the 2^x calculation is wrong */
-
-/* use "digital cents" == "dents" instead of cents */
-#define NUM_DENTS_FRAC_BITS 12
-#define NUM_DENTS_INT_BITS (HARDWARE_BIT_WIDTH - NUM_DENTS_FRAC_BITS)
-
-#define DENTS_FRAC_MASK (EAS_I32) ((0x1L << NUM_DENTS_FRAC_BITS) -1)
-
-#define GET_DENTS_INT_PART(x) /*lint -e(704) <avoid divide for performance>*/ \
- (EAS_I32)((EAS_I32)(x) >> NUM_DENTS_FRAC_BITS)
-
-#define GET_DENTS_FRAC_PART(x) (EAS_I32)((EAS_I32)(x) & DENTS_FRAC_MASK)
-
-#define DENTS_ONE (EAS_I32) (0x1L << NUM_DENTS_FRAC_BITS)
-
-/* use CENTS_TO_DENTS to convert a value in cents to dents */
-#define CENTS_TO_DENTS (EAS_I32) (DENTS_ONE * (0x1L << NUM_EG1_FRAC_BITS) / 1200L) \
-
-
-/*
-For gain, the LFO generates a value that modulates in terms
-of dB. However, we use a linear gain value, so we must convert
-the LFO value in dB to a linear gain. Normally, we would use
-linear gain = 10^x, where x = LFO value in dB / 20.
-Instead, we implement 10^x using our 2^x approximation.
-because
-
- 10^x = 2^(log2(10^x)) = 2^(x * log2(10))
-
-so we need to multiply by log2(10) which is just a constant.
-Ah, but just wait -- our 2^x actually doesn't exactly implement
-2^x, but it actually assumes that the input is in cents, and within
-the 2^x approximation converts its input from cents to octaves
-by dividing its input by 1200.
-
-So, in order to convert the LFO gain value in dB to something
-that our existing 2^x approximation can use, multiply the LFO gain
-by log2(10) * 1200 / 20
-
-The divide by 20 helps convert dB to linear gain, and we might
-as well incorporate that operation into this conversion.
-Of course, we need to keep some fractional bits, so multiply
-the constant by NUM_EG1_FRAC_BITS
-*/
-
-/* use LFO_GAIN_TO_CENTS to convert the LFO gain value to cents */
-#if 0
-#define DOUBLE_LOG2_10 (double) (3.32192809488736) /* log2(10) */
-
-#define DOUBLE_LFO_GAIN_TO_CENTS (double) \
- ( \
- (DOUBLE_LOG2_10) * \
- 1200.0 / \
- 20.0 \
- )
-
-#define LFO_GAIN_TO_CENTS (EAS_I32) \
- ( \
- DOUBLE_LFO_GAIN_TO_CENTS * \
- (0x1L << NUM_EG1_FRAC_BITS) \
- )
-#endif
-
-#define LFO_GAIN_TO_CENTS (EAS_I32) (1671981156L >> (23 - NUM_EG1_FRAC_BITS))
-
-
-#define MULT_DENTS_COEF(dents,coef) /*lint -e704 <avoid divide for performance>*/ \
- (EAS_I32)( \
- ( \
- ((EAS_I32)(dents)) * ((EAS_I32)(coef)) \
- ) \
- >> NUM_DENTS_FRAC_BITS \
- ) \
- /* lint +e704 <restore checking>*/
-
-/* we use 16-bits in the PC per audio sample */
-#define BITS_PER_AUDIO_SAMPLE 16
-
-/* we define 1 as 1.0 - 1 LSbit */
-#define DISTORTION_ONE (EAS_I32)((0x1L << (BITS_PER_AUDIO_SAMPLE-1)) -1)
-#define DISTORTION_MINUS_ONE (EAS_I32)(~DISTORTION_ONE)
-
-/* drive coef is given as int.frac */
-#define NUM_DRIVE_COEF_INT_BITS 1
-#define NUM_DRIVE_COEF_FRAC_BITS 4
-
-#define MULT_AUDIO_DRIVE(audio,drive) /*lint -e(702) <avoid divide for performance>*/ \
- (EAS_I32) ( \
- ( \
- ((EAS_I32)(audio)) * ((EAS_I32)(drive)) \
- ) \
- >> NUM_DRIVE_COEF_FRAC_BITS \
- )
-
-#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) <avoid divide for performance>*/ \
- (EAS_I32) ( \
- ( \
- ((EAS_I32)(audio1)) * ((EAS_I32)(audio2)) \
- ) \
- >> (BITS_PER_AUDIO_SAMPLE-1) \
- )
-
-#define SATURATE(x) \
- ((((EAS_I32)(x)) > DISTORTION_ONE) ? (DISTORTION_ONE) : \
- (((EAS_I32)(x)) < DISTORTION_MINUS_ONE) ? (DISTORTION_MINUS_ONE) : ((EAS_I32)(x)));
-
-
-
-/*----------------------------------------------------------------------------
- * EAS_Calculate2toX()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate 2^x
- *
- * Inputs:
- * nCents - measured in cents
- *
- * Outputs:
- * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 EAS_Calculate2toX (EAS_I32 nCents);
-
-/*----------------------------------------------------------------------------
- * EAS_LogToLinear16()
- *----------------------------------------------------------------------------
- * Purpose:
- * Transform log value to linear gain multiplier using piece-wise linear
- * approximation
- *
- * Inputs:
- * nGain - log scale value in 20.10 format. Even though gain is normally
- * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate
- * the need for saturation checking when combining gain values.
- *
- * Outputs:
- * Returns a 16-bit linear value approximately equal to 2^(nGain/1024)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain);
-
-/*----------------------------------------------------------------------------
- * EAS_VolumeToGain()
- *----------------------------------------------------------------------------
- * Purpose:
- * Transform volume control in 1dB increments to gain multiplier
- *
- * Inputs:
- * volume - 100 = 0dB, 99 = -1dB, 0 = -inf
- *
- * Outputs:
- * Returns a 16-bit linear value
- *----------------------------------------------------------------------------
-*/
-EAS_I16 EAS_VolumeToGain (EAS_INT volume);
-
-/*----------------------------------------------------------------------------
- * EAS_fsqrt()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculates the square root of a 32-bit fixed point value
- *
- * Inputs:
- * n = value of interest
- *
- * Outputs:
- * returns the square root of n
- *
- *----------------------------------------------------------------------------
-*/
-EAS_U16 EAS_fsqrt (EAS_U32 n);
-
-/*----------------------------------------------------------------------------
- * EAS_flog2()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculates the log2 of a 32-bit fixed point value
- *
- * Inputs:
- * n = value of interest
- *
- * Outputs:
- * returns the log2 of n
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 EAS_flog2 (EAS_U32 n);
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 584 $ + * $Date: 2007-03-08 09:49:24 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MATH_H +#define _EAS_MATH_H + + +/** coefs for pan, generates sin, cos */ +#define COEFF_PAN_G2 -27146 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +#define COEFF_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/* +coefficients for approximating +2^x = gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3 +where x is a int.frac number representing number of octaves. +Actually, we approximate only the 2^(frac) using the power series +and implement the 2^(int) as a shift, so that +2^x == 2^(int.frac) == 2^(int) * 2^(fract) + == (gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3) << (int) + +The gn2toX.. were generated using a best fit for a 3rd +order polynomial, instead of taking the coefficients from +a truncated Taylor (or Maclaurin?) series. +*/ + +#define GN2_TO_X0 32768 /* 1 */ +#define GN2_TO_X1 22833 /* 0.696807861328125 */ +#define GN2_TO_X2 7344 /* 0.22412109375 */ +#define GN2_TO_X3 2588 /* 0.0789794921875 */ + +/*---------------------------------------------------------------------------- + * Fixed Point Math + *---------------------------------------------------------------------------- + * These macros are used for fixed point multiplies. If the processor + * supports fixed point multiplies, replace these macros with inline + * assembly code to improve performance. + *---------------------------------------------------------------------------- +*/ + +/* Fixed point multiply 0.15 x 0.15 = 0.15 returned as 32-bits */ +#define FMUL_15x15(a,b) \ + /*lint -e(704) <avoid multiply for performance>*/ \ + (((EAS_I32)(a) * (EAS_I32)(b)) >> 15) + +/* Fixed point multiply 0.7 x 0.7 = 0.15 returned as 32-bits */ +#define FMUL_7x7(a,b) \ + /*lint -e(704) <avoid multiply for performance>*/ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) << 1) + +/* Fixed point multiply 0.8 x 0.8 = 0.15 returned as 32-bits */ +#define FMUL_8x8(a,b) \ + /*lint -e(704) <avoid multiply for performance>*/ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) >> 1) + +/* Fixed point multiply 0.8 x 1.15 = 0.15 returned as 32-bits */ +#define FMUL_8x15(a,b) \ + /*lint -e(704) <avoid divide for performance>*/ \ + (((EAS_I32)((a) << 7) * (EAS_I32)(b)) >> 15) + +/* macros for fractional phase accumulator */ +/* +Note: changed the _U32 to _I32 on 03/14/02. This should not +affect the phase calculations, and should allow us to reuse these +macros for other audio sample related math. +*/ +#define HARDWARE_BIT_WIDTH 32 + +#define NUM_PHASE_INT_BITS 1 +#define NUM_PHASE_FRAC_BITS 15 + +#define PHASE_FRAC_MASK (EAS_U32) ((0x1L << NUM_PHASE_FRAC_BITS) -1) + +#define GET_PHASE_INT_PART(x) (EAS_U32)((EAS_U32)(x) >> NUM_PHASE_FRAC_BITS) +#define GET_PHASE_FRAC_PART(x) (EAS_U32)((EAS_U32)(x) & PHASE_FRAC_MASK) + +#define DEFAULT_PHASE_FRAC 0 +#define DEFAULT_PHASE_INT 0 + +/* +Linear interpolation calculates: +output = (1-frac) * sample[n] + (frac) * sample[n+1] + +where conceptually 0 <= frac < 1 + +For a fixed point implementation, frac is actually an integer value +with an implied binary point one position to the left. The value of +one (unity) is given by PHASE_ONE +one half and one quarter are useful for 4-point linear interp. +*/ +#define PHASE_ONE (EAS_I32) (0x1L << NUM_PHASE_FRAC_BITS) + +/* + Multiply the signed audio sample by the unsigned fraction. +- a is the signed audio sample +- b is the unsigned fraction (cast to signed int as long as coef + uses (n-1) or less bits, where n == hardware bit width) +*/ +#define MULT_AUDIO_COEF(audio,coef) /*lint -e704 <avoid divide for performance>*/ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_PHASE_FRAC_BITS \ + ) \ + /* lint +704 <restore checking>*/ + +/* wet / dry calculation macros */ +#define NUM_WET_DRY_FRAC_BITS 7 // 15 +#define NUM_WET_DRY_INT_BITS 9 // 1 + +/* define a 1.0 */ +#define WET_DRY_ONE (EAS_I32) ((0x1L << NUM_WET_DRY_FRAC_BITS)) +#define WET_DRY_MINUS_ONE (EAS_I32) (~WET_DRY_ONE) +#define WET_DRY_FULL_SCALE (EAS_I32) (WET_DRY_ONE - 1) + +#define MULT_AUDIO_WET_DRY_COEF(audio,coef) /*lint -e(702) <avoid divide for performance>*/ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_WET_DRY_FRAC_BITS \ + ) + +/* Envelope 1 (EG1) calculation macros */ +#define NUM_EG1_INT_BITS 1 +#define NUM_EG1_FRAC_BITS 15 + +/* the max positive gain used in the synth for EG1 */ +/* SYNTH_FULL_SCALE_EG1_GAIN must match the value in the dls2eas +converter, otherwise, the values we read from the .eas file are bogus. */ +#define SYNTH_FULL_SCALE_EG1_GAIN (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS) -1) + +/* define a 1.0 */ +#define EG1_ONE (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS)) +#define EG1_MINUS_ONE (EAS_I32) (~SYNTH_FULL_SCALE_EG1_GAIN) + +#define EG1_HALF (EAS_I32) (EG1_ONE/2) +#define EG1_MINUS_HALF (EAS_I32) (EG1_MINUS_ONE/2) + +/* +We implement the EG1 using a linear gain value, which means that the +attack segment is handled by incrementing (adding) the linear gain. +However, EG1 treats the Decay, Sustain, and Release differently than +the Attack portion. For Decay, Sustain, and Release, the gain is +linear on dB scale, which is equivalent to exponential damping on +a linear scale. Because we use a linear gain for EG1, we implement +the Decay and Release as multiplication (instead of incrementing +as we did for the attack segment). +Therefore, we need the following macro to implement the multiplication +(i.e., exponential damping) during the Decay and Release segments of +the EG1 +*/ +#define MULT_EG1_EG1(gain,damping) /*lint -e(704) <avoid divide for performance>*/ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> NUM_EG1_FRAC_BITS \ + ) + +// Use the following macro specifically for the filter, when multiplying +// the b1 coefficient. The 0 <= |b1| < 2, which therefore might overflow +// in certain conditions because we store b1 as a 1.15 value. +// Instead, we could store b1 as b1p (b1' == b1 "prime") where +// b1p == b1/2, thus ensuring no potential overflow for b1p because +// 0 <= |b1p| < 1 +// However, during the filter calculation, we must account for the fact +// that we are using b1p instead of b1, and thereby multiply by +// an extra factor of 2. Rather than multiply by an extra factor of 2, +// we can instead shift the result right by one less, hence the +// modified shift right value of (NUM_EG1_FRAC_BITS -1) +#define MULT_EG1_EG1_X2(gain,damping) /*lint -e(702) <avoid divide for performance>*/ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> (NUM_EG1_FRAC_BITS -1) \ + ) + +#define SATURATE_EG1(x) /*lint -e{734} saturation operation */ \ + ((EAS_I32)(x) > SYNTH_FULL_SCALE_EG1_GAIN) ? (SYNTH_FULL_SCALE_EG1_GAIN) : \ + ((EAS_I32)(x) < EG1_MINUS_ONE) ? (EG1_MINUS_ONE) : (x); + + +/* use "digital cents" == "dents" instead of cents */ +/* we coudl re-use the phase frac macros, but if we do, +we must change the phase macros to cast to _I32 instead of _U32, +because using a _U32 cast causes problems when shifting the exponent +for the 2^x calculation, because right shift a negative values MUST +be sign extended, or else the 2^x calculation is wrong */ + +/* use "digital cents" == "dents" instead of cents */ +#define NUM_DENTS_FRAC_BITS 12 +#define NUM_DENTS_INT_BITS (HARDWARE_BIT_WIDTH - NUM_DENTS_FRAC_BITS) + +#define DENTS_FRAC_MASK (EAS_I32) ((0x1L << NUM_DENTS_FRAC_BITS) -1) + +#define GET_DENTS_INT_PART(x) /*lint -e(704) <avoid divide for performance>*/ \ + (EAS_I32)((EAS_I32)(x) >> NUM_DENTS_FRAC_BITS) + +#define GET_DENTS_FRAC_PART(x) (EAS_I32)((EAS_I32)(x) & DENTS_FRAC_MASK) + +#define DENTS_ONE (EAS_I32) (0x1L << NUM_DENTS_FRAC_BITS) + +/* use CENTS_TO_DENTS to convert a value in cents to dents */ +#define CENTS_TO_DENTS (EAS_I32) (DENTS_ONE * (0x1L << NUM_EG1_FRAC_BITS) / 1200L) \ + + +/* +For gain, the LFO generates a value that modulates in terms +of dB. However, we use a linear gain value, so we must convert +the LFO value in dB to a linear gain. Normally, we would use +linear gain = 10^x, where x = LFO value in dB / 20. +Instead, we implement 10^x using our 2^x approximation. +because + + 10^x = 2^(log2(10^x)) = 2^(x * log2(10)) + +so we need to multiply by log2(10) which is just a constant. +Ah, but just wait -- our 2^x actually doesn't exactly implement +2^x, but it actually assumes that the input is in cents, and within +the 2^x approximation converts its input from cents to octaves +by dividing its input by 1200. + +So, in order to convert the LFO gain value in dB to something +that our existing 2^x approximation can use, multiply the LFO gain +by log2(10) * 1200 / 20 + +The divide by 20 helps convert dB to linear gain, and we might +as well incorporate that operation into this conversion. +Of course, we need to keep some fractional bits, so multiply +the constant by NUM_EG1_FRAC_BITS +*/ + +/* use LFO_GAIN_TO_CENTS to convert the LFO gain value to cents */ +#if 0 +#define DOUBLE_LOG2_10 (double) (3.32192809488736) /* log2(10) */ + +#define DOUBLE_LFO_GAIN_TO_CENTS (double) \ + ( \ + (DOUBLE_LOG2_10) * \ + 1200.0 / \ + 20.0 \ + ) + +#define LFO_GAIN_TO_CENTS (EAS_I32) \ + ( \ + DOUBLE_LFO_GAIN_TO_CENTS * \ + (0x1L << NUM_EG1_FRAC_BITS) \ + ) +#endif + +#define LFO_GAIN_TO_CENTS (EAS_I32) (1671981156L >> (23 - NUM_EG1_FRAC_BITS)) + + +#define MULT_DENTS_COEF(dents,coef) /*lint -e704 <avoid divide for performance>*/ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(dents)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_DENTS_FRAC_BITS \ + ) \ + /* lint +e704 <restore checking>*/ + +/* we use 16-bits in the PC per audio sample */ +#define BITS_PER_AUDIO_SAMPLE 16 + +/* we define 1 as 1.0 - 1 LSbit */ +#define DISTORTION_ONE (EAS_I32)((0x1L << (BITS_PER_AUDIO_SAMPLE-1)) -1) +#define DISTORTION_MINUS_ONE (EAS_I32)(~DISTORTION_ONE) + +/* drive coef is given as int.frac */ +#define NUM_DRIVE_COEF_INT_BITS 1 +#define NUM_DRIVE_COEF_FRAC_BITS 4 + +#define MULT_AUDIO_DRIVE(audio,drive) /*lint -e(702) <avoid divide for performance>*/ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(drive)) \ + ) \ + >> NUM_DRIVE_COEF_FRAC_BITS \ + ) + +#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) <avoid divide for performance>*/ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio1)) * ((EAS_I32)(audio2)) \ + ) \ + >> (BITS_PER_AUDIO_SAMPLE-1) \ + ) + +#define SATURATE(x) \ + ((((EAS_I32)(x)) > DISTORTION_ONE) ? (DISTORTION_ONE) : \ + (((EAS_I32)(x)) < DISTORTION_MINUS_ONE) ? (DISTORTION_MINUS_ONE) : ((EAS_I32)(x))); + + + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents); + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain); + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume); + +/*---------------------------------------------------------------------------- + * EAS_fsqrt() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the square root of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the square root of n + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_fsqrt (EAS_U32 n); + +/*---------------------------------------------------------------------------- + * EAS_flog2() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the log2 of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the log2 of n + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_flog2 (EAS_U32 n); + +#endif + diff --git a/arm-fm-22k/lib_src/eas_midi.c b/arm-fm-22k/lib_src/eas_midi.c index 08aed72..2c0c793 100644 --- a/arm-fm-22k/lib_src/eas_midi.c +++ b/arm-fm-22k/lib_src/eas_midi.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_midi.c
- *
- * Contents and purpose:
- * This file implements the MIDI stream parser. It is called by eas_smf.c to parse MIDI messages
- * that are streamed out of the file. It can also parse live MIDI streams.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.c + * + * Contents and purpose: + * This file implements the MIDI stream parser. It is called by eas_smf.c to parse MIDI messages + * that are streamed out of the file. It can also parse live MIDI streams. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,550 +20,550 @@ * 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: 794 $
- * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_report.h"
-#include "eas_miditypes.h"
-#include "eas_midi.h"
-#include "eas_vm_protos.h"
-#include "eas_parser.h"
-
-#ifdef JET_INTERFACE
-#include "jet_data.h"
-#endif
-
-
-/* state enumerations for ProcessSysExMessage */
-typedef enum
-{
- eSysEx,
- eSysExUnivNonRealTime,
- eSysExUnivNrtTargetID,
- eSysExGMControl,
- eSysExUnivRealTime,
- eSysExUnivRtTargetID,
- eSysExDeviceControl,
- eSysExMasterVolume,
- eSysExMasterVolLSB,
- eSysExSPMIDI,
- eSysExSPMIDIchan,
- eSysExSPMIDIMIP,
- eSysExMfgID1,
- eSysExMfgID2,
- eSysExMfgID3,
- eSysExEnhancer,
- eSysExEnhancerSubID,
- eSysExEnhancerFeedback1,
- eSysExEnhancerFeedback2,
- eSysExEnhancerDrive,
- eSysExEnhancerWet,
- eSysExEOX,
- eSysExIgnore
-} E_SYSEX_STATES;
-
-/* local prototypes */
-static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode);
-static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode);
-
-/*----------------------------------------------------------------------------
- * EAS_InitMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the MIDI stream state for parsing.
- *
- * Inputs:
- *
- * Outputs:
- * returns EAS_RESULT (EAS_SUCCESS is OK)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream)
-{
- pMIDIStream->byte3 = EAS_FALSE;
- pMIDIStream->pending = EAS_FALSE;
- pMIDIStream->runningStatus = 0;
- pMIDIStream->status = 0;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_ParseMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled)
- * so the interface works equally well for both file and stream I/O.
- *
- * Inputs:
- * c - character from MIDI stream
- *
- * Outputs:
- * returns EAS_RESULT (EAS_SUCCESS is OK)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode)
-{
-
- /* check for new status byte */
- if (c & 0x80)
- {
- /* save new running status */
- if (c < 0xf8)
- {
- pMIDIStream->runningStatus = c;
- pMIDIStream->byte3 = EAS_FALSE;
-
- /* deal with SysEx */
- if ((c == 0xf7) || (c == 0xf0))
- {
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode);
- }
-
- /* inform the file parser that we're in the middle of a message */
- if ((c < 0xf4) || (c > 0xf6))
- pMIDIStream->pending = EAS_TRUE;
- }
-
- /* real-time message - ignore it */
- return EAS_SUCCESS;
- }
-
- /* 3rd byte of a 3-byte message? */
- if (pMIDIStream->byte3)
- {
- pMIDIStream->d2 = c;
- pMIDIStream->byte3 = EAS_FALSE;
- pMIDIStream->pending = EAS_FALSE;
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode);
- }
-
- /* check for status received */
- if (pMIDIStream->runningStatus)
- {
-
- /* save new status and data byte */
- pMIDIStream->status = pMIDIStream->runningStatus;
-
- /* check for 3-byte messages */
- if (pMIDIStream->status < 0xc0)
- {
- pMIDIStream->d1 = c;
- pMIDIStream->pending = EAS_TRUE;
- pMIDIStream->byte3 = EAS_TRUE;
- return EAS_SUCCESS;
- }
-
- /* check for 2-byte messages */
- if (pMIDIStream->status < 0xe0)
- {
- pMIDIStream->d1 = c;
- pMIDIStream->pending = EAS_FALSE;
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode);
- }
-
- /* check for more 3-bytes message */
- if (pMIDIStream->status < 0xf0)
- {
- pMIDIStream->d1 = c;
- pMIDIStream->pending = EAS_TRUE;
- pMIDIStream->byte3 = EAS_TRUE;
- return EAS_SUCCESS;
- }
-
- /* SysEx message? */
- if (pMIDIStream->status == 0xF0)
- {
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode);
- }
-
- /* remaining messages all clear running status */
- pMIDIStream->runningStatus = 0;
-
- /* F2 is 3-byte message */
- if (pMIDIStream->status == 0xf2)
- {
- pMIDIStream->byte3 = EAS_TRUE;
- return EAS_SUCCESS;
- }
- }
-
- /* no status byte received, provide a warning, but we should be able to recover */
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Received MIDI data without a valid status byte: %d\n",c); */ }
- pMIDIStream->pending = EAS_FALSE;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * ProcessMIDIMessage()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function processes a typical MIDI message. All of the data has been received, just need
- * to take appropriate action.
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode)
-{
- EAS_U8 channel;
-
- channel = pMIDIStream->status & 0x0f;
- switch (pMIDIStream->status & 0xf0)
- {
- case 0x80:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- break;
-
- case 0x90:
- if (pMIDIStream->d2)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOn: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- pMIDIStream->flags |= MIDI_FLAG_FIRST_NOTE;
- if (parserMode == eParserModePlay)
- VMStartNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- }
- else
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- }
- break;
-
- case 0xa0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PolyPres: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- break;
-
- case 0xb0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Control: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMControlChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
-#ifdef JET_INTERFACE
- if (pMIDIStream->jetData & MIDI_FLAGS_JET_CB)
- {
- JET_Event(pEASData, pMIDIStream->jetData & (JET_EVENT_SEG_MASK | JET_EVENT_TRACK_MASK),
- channel, pMIDIStream->d1, pMIDIStream->d2);
- }
-#endif
- break;
-
- case 0xc0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Program: %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1); */ }
- if (parserMode < eParserModeMute)
- VMProgramChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1);
- break;
-
- case 0xd0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"ChanPres: %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1); */ }
- if (parserMode < eParserModeMute)
- VMChannelPressure(pSynth, channel, pMIDIStream->d1);
- break;
-
- case 0xe0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PBend: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMPitchBend(pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Unknown: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * ProcessSysExMessage()
- *----------------------------------------------------------------------------
- * Purpose:
- * Process a SysEx character byte from the MIDI stream. Since we cannot
- * simply wait for the next character to arrive, we are forced to save
- * state after each character. It would be easier to parse at the file
- * level, but then we lose the nice feature of being able to support
- * these messages in a real-time MIDI stream.
- *
- * Inputs:
- * pEASData - pointer to synthesizer instance data
- * c - character to be processed
- * locating - if true, the sequencer is relocating to a new position
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes:
- * These are the SysEx messages we can receive:
- *
- * SysEx messages
- * { f0 7e 7f 09 01 f7 } GM 1 On
- * { f0 7e 7f 09 02 f7 } GM 1/2 Off
- * { f0 7e 7f 09 03 f7 } GM 2 On
- * { f0 7f 7f 04 01 lsb msb } Master Volume
- * { f0 7f 7f 0b 01 ch mip [ch mip ...] f7 } SP-MIDI
- * { f0 00 01 3a 04 01 fdbk1 fdbk2 drive wet dry f7 } Enhancer
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode)
-{
-
- /* check for start byte */
- if (c == 0xf0)
- {
- pMIDIStream->sysExState = eSysEx;
- }
- /* check for end byte */
- else if (c == 0xf7)
- {
- /* if this was a MIP message, update the MIP table */
- if ((pMIDIStream->sysExState == eSysExSPMIDIchan) && (parserMode != eParserModeMetaData))
- VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth);
- pMIDIStream->sysExState = eSysExIgnore;
- }
-
- /* process SysEx message */
- else
- {
- switch (pMIDIStream->sysExState)
- {
- case eSysEx:
-
- /* first byte, determine message class */
- switch (c)
- {
- case 0x7e:
- pMIDIStream->sysExState = eSysExUnivNonRealTime;
- break;
- case 0x7f:
- pMIDIStream->sysExState = eSysExUnivRealTime;
- break;
- case 0x00:
- pMIDIStream->sysExState = eSysExMfgID1;
- break;
- default:
- pMIDIStream->sysExState = eSysExIgnore;
- break;
- }
- break;
-
- /* process GM message */
- case eSysExUnivNonRealTime:
- if (c == 0x7f)
- pMIDIStream->sysExState = eSysExUnivNrtTargetID;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExUnivNrtTargetID:
- if (c == 0x09)
- pMIDIStream->sysExState = eSysExGMControl;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExGMControl:
- if ((c == 1) || (c == 3))
- {
- /* GM 1 or GM2 On, reset synth */
- if (parserMode != eParserModeMetaData)
- {
- pMIDIStream->flags |= MIDI_FLAG_GM_ON;
- VMReset(pEASData->pVoiceMgr, pSynth, EAS_FALSE);
- VMInitMIPTable(pSynth);
- }
- pMIDIStream->sysExState = eSysExEOX;
- }
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- /* Process Master Volume and SP-MIDI */
- case eSysExUnivRealTime:
- if (c == 0x7f)
- pMIDIStream->sysExState = eSysExUnivRtTargetID;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExUnivRtTargetID:
- if (c == 0x04)
- pMIDIStream->sysExState = eSysExDeviceControl;
- else if (c == 0x0b)
- pMIDIStream->sysExState = eSysExSPMIDI;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- /* process master volume */
- case eSysExDeviceControl:
- if (c == 0x01)
- pMIDIStream->sysExState = eSysExMasterVolume;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExMasterVolume:
- /* save LSB */
- pMIDIStream->d1 = c;
- pMIDIStream->sysExState = eSysExMasterVolLSB;
- break;
-
- case eSysExMasterVolLSB:
- if (parserMode != eParserModeMetaData)
- {
- EAS_I32 gain = ((EAS_I32) c << 8) | ((EAS_I32) pMIDIStream->d1 << 1);
- gain = (gain * gain) >> 15;
- VMSetVolume(pSynth, (EAS_U16) gain);
- }
- pMIDIStream->sysExState = eSysExEOX;
- break;
-
- /* process SP-MIDI MIP message */
- case eSysExSPMIDI:
- if (c == 0x01)
- {
- /* assume all channels are muted */
- if (parserMode != eParserModeMetaData)
- VMInitMIPTable(pSynth);
- pMIDIStream->d1 = 0;
- pMIDIStream->sysExState = eSysExSPMIDIchan;
- }
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExSPMIDIchan:
- if (c < NUM_SYNTH_CHANNELS)
- {
- pMIDIStream->d2 = c;
- pMIDIStream->sysExState = eSysExSPMIDIMIP;
- }
- else
- {
- /* bad MIP message - unmute channels */
- if (parserMode != eParserModeMetaData)
- VMInitMIPTable(pSynth);
- pMIDIStream->sysExState = eSysExIgnore;
- }
- break;
-
- case eSysExSPMIDIMIP:
- /* process MIP entry here */
- if (parserMode != eParserModeMetaData)
- VMSetMIPEntry(pEASData->pVoiceMgr, pSynth, pMIDIStream->d2, pMIDIStream->d1, c);
- pMIDIStream->sysExState = eSysExSPMIDIchan;
-
- /* if 16 channels received, update MIP table */
- if (++pMIDIStream->d1 == NUM_SYNTH_CHANNELS)
- {
- if (parserMode != eParserModeMetaData)
- VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth);
- pMIDIStream->sysExState = eSysExEOX;
- }
- break;
-
- /* process Enhancer */
- case eSysExMfgID1:
- if (c == 0x01)
- pMIDIStream->sysExState = eSysExMfgID1;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExMfgID2:
- if (c == 0x3a)
- pMIDIStream->sysExState = eSysExMfgID1;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExMfgID3:
- if (c == 0x04)
- pMIDIStream->sysExState = eSysExEnhancer;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExEnhancer:
- if (c == 0x01)
- pMIDIStream->sysExState = eSysExEnhancerSubID;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExEnhancerSubID:
- pMIDIStream->sysExState = eSysExEnhancerFeedback1;
- break;
-
- case eSysExEnhancerFeedback1:
- pMIDIStream->sysExState = eSysExEnhancerFeedback2;
- break;
-
- case eSysExEnhancerFeedback2:
- pMIDIStream->sysExState = eSysExEnhancerDrive;
- break;
-
- case eSysExEnhancerDrive:
- pMIDIStream->sysExState = eSysExEnhancerWet;
- break;
-
- case eSysExEnhancerWet:
- pMIDIStream->sysExState = eSysExEOX;
- break;
-
- case eSysExEOX:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Expected F7, received %02x\n", c); */ }
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExIgnore:
- break;
-
- default:
- pMIDIStream->sysExState = eSysExIgnore;
- break;
- }
- }
-
- if (pMIDIStream->sysExState == eSysExIgnore)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Ignoring SysEx byte %02x\n", c); */ }
- return EAS_SUCCESS;
-} /* end ProcessSysExMessage */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_miditypes.h" +#include "eas_midi.h" +#include "eas_vm_protos.h" +#include "eas_parser.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + + +/* state enumerations for ProcessSysExMessage */ +typedef enum +{ + eSysEx, + eSysExUnivNonRealTime, + eSysExUnivNrtTargetID, + eSysExGMControl, + eSysExUnivRealTime, + eSysExUnivRtTargetID, + eSysExDeviceControl, + eSysExMasterVolume, + eSysExMasterVolLSB, + eSysExSPMIDI, + eSysExSPMIDIchan, + eSysExSPMIDIMIP, + eSysExMfgID1, + eSysExMfgID2, + eSysExMfgID3, + eSysExEnhancer, + eSysExEnhancerSubID, + eSysExEnhancerFeedback1, + eSysExEnhancerFeedback2, + eSysExEnhancerDrive, + eSysExEnhancerWet, + eSysExEOX, + eSysExIgnore +} E_SYSEX_STATES; + +/* local prototypes */ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode); +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream) +{ + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + pMIDIStream->runningStatus = 0; + pMIDIStream->status = 0; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for new status byte */ + if (c & 0x80) + { + /* save new running status */ + if (c < 0xf8) + { + pMIDIStream->runningStatus = c; + pMIDIStream->byte3 = EAS_FALSE; + + /* deal with SysEx */ + if ((c == 0xf7) || (c == 0xf0)) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* inform the file parser that we're in the middle of a message */ + if ((c < 0xf4) || (c > 0xf6)) + pMIDIStream->pending = EAS_TRUE; + } + + /* real-time message - ignore it */ + return EAS_SUCCESS; + } + + /* 3rd byte of a 3-byte message? */ + if (pMIDIStream->byte3) + { + pMIDIStream->d2 = c; + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for status received */ + if (pMIDIStream->runningStatus) + { + + /* save new status and data byte */ + pMIDIStream->status = pMIDIStream->runningStatus; + + /* check for 3-byte messages */ + if (pMIDIStream->status < 0xc0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* check for 2-byte messages */ + if (pMIDIStream->status < 0xe0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for more 3-bytes message */ + if (pMIDIStream->status < 0xf0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* SysEx message? */ + if (pMIDIStream->status == 0xF0) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* remaining messages all clear running status */ + pMIDIStream->runningStatus = 0; + + /* F2 is 3-byte message */ + if (pMIDIStream->status == 0xf2) + { + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + } + + /* no status byte received, provide a warning, but we should be able to recover */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Received MIDI data without a valid status byte: %d\n",c); */ } + pMIDIStream->pending = EAS_FALSE; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessMIDIMessage() + *---------------------------------------------------------------------------- + * Purpose: + * This function processes a typical MIDI message. All of the data has been received, just need + * to take appropriate action. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode) +{ + EAS_U8 channel; + + channel = pMIDIStream->status & 0x0f; + switch (pMIDIStream->status & 0xf0) + { + case 0x80: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + case 0x90: + if (pMIDIStream->d2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOn: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + pMIDIStream->flags |= MIDI_FLAG_FIRST_NOTE; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + break; + + case 0xa0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PolyPres: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + break; + + case 0xb0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Control: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMControlChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); +#ifdef JET_INTERFACE + if (pMIDIStream->jetData & MIDI_FLAGS_JET_CB) + { + JET_Event(pEASData, pMIDIStream->jetData & (JET_EVENT_SEG_MASK | JET_EVENT_TRACK_MASK), + channel, pMIDIStream->d1, pMIDIStream->d2); + } +#endif + break; + + case 0xc0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Program: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode < eParserModeMute) + VMProgramChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1); + break; + + case 0xd0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"ChanPres: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode < eParserModeMute) + VMChannelPressure(pSynth, channel, pMIDIStream->d1); + break; + + case 0xe0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PBend: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMPitchBend(pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Unknown: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessSysExMessage() + *---------------------------------------------------------------------------- + * Purpose: + * Process a SysEx character byte from the MIDI stream. Since we cannot + * simply wait for the next character to arrive, we are forced to save + * state after each character. It would be easier to parse at the file + * level, but then we lose the nice feature of being able to support + * these messages in a real-time MIDI stream. + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * c - character to be processed + * locating - if true, the sequencer is relocating to a new position + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * These are the SysEx messages we can receive: + * + * SysEx messages + * { f0 7e 7f 09 01 f7 } GM 1 On + * { f0 7e 7f 09 02 f7 } GM 1/2 Off + * { f0 7e 7f 09 03 f7 } GM 2 On + * { f0 7f 7f 04 01 lsb msb } Master Volume + * { f0 7f 7f 0b 01 ch mip [ch mip ...] f7 } SP-MIDI + * { f0 00 01 3a 04 01 fdbk1 fdbk2 drive wet dry f7 } Enhancer + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for start byte */ + if (c == 0xf0) + { + pMIDIStream->sysExState = eSysEx; + } + /* check for end byte */ + else if (c == 0xf7) + { + /* if this was a MIP message, update the MIP table */ + if ((pMIDIStream->sysExState == eSysExSPMIDIchan) && (parserMode != eParserModeMetaData)) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + + /* process SysEx message */ + else + { + switch (pMIDIStream->sysExState) + { + case eSysEx: + + /* first byte, determine message class */ + switch (c) + { + case 0x7e: + pMIDIStream->sysExState = eSysExUnivNonRealTime; + break; + case 0x7f: + pMIDIStream->sysExState = eSysExUnivRealTime; + break; + case 0x00: + pMIDIStream->sysExState = eSysExMfgID1; + break; + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + break; + + /* process GM message */ + case eSysExUnivNonRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivNrtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivNrtTargetID: + if (c == 0x09) + pMIDIStream->sysExState = eSysExGMControl; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExGMControl: + if ((c == 1) || (c == 3)) + { + /* GM 1 or GM2 On, reset synth */ + if (parserMode != eParserModeMetaData) + { + pMIDIStream->flags |= MIDI_FLAG_GM_ON; + VMReset(pEASData->pVoiceMgr, pSynth, EAS_FALSE); + VMInitMIPTable(pSynth); + } + pMIDIStream->sysExState = eSysExEOX; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* Process Master Volume and SP-MIDI */ + case eSysExUnivRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivRtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivRtTargetID: + if (c == 0x04) + pMIDIStream->sysExState = eSysExDeviceControl; + else if (c == 0x0b) + pMIDIStream->sysExState = eSysExSPMIDI; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* process master volume */ + case eSysExDeviceControl: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMasterVolume; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMasterVolume: + /* save LSB */ + pMIDIStream->d1 = c; + pMIDIStream->sysExState = eSysExMasterVolLSB; + break; + + case eSysExMasterVolLSB: + if (parserMode != eParserModeMetaData) + { + EAS_I32 gain = ((EAS_I32) c << 8) | ((EAS_I32) pMIDIStream->d1 << 1); + gain = (gain * gain) >> 15; + VMSetVolume(pSynth, (EAS_U16) gain); + } + pMIDIStream->sysExState = eSysExEOX; + break; + + /* process SP-MIDI MIP message */ + case eSysExSPMIDI: + if (c == 0x01) + { + /* assume all channels are muted */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->d1 = 0; + pMIDIStream->sysExState = eSysExSPMIDIchan; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExSPMIDIchan: + if (c < NUM_SYNTH_CHANNELS) + { + pMIDIStream->d2 = c; + pMIDIStream->sysExState = eSysExSPMIDIMIP; + } + else + { + /* bad MIP message - unmute channels */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + break; + + case eSysExSPMIDIMIP: + /* process MIP entry here */ + if (parserMode != eParserModeMetaData) + VMSetMIPEntry(pEASData->pVoiceMgr, pSynth, pMIDIStream->d2, pMIDIStream->d1, c); + pMIDIStream->sysExState = eSysExSPMIDIchan; + + /* if 16 channels received, update MIP table */ + if (++pMIDIStream->d1 == NUM_SYNTH_CHANNELS) + { + if (parserMode != eParserModeMetaData) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExEOX; + } + break; + + /* process Enhancer */ + case eSysExMfgID1: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID2: + if (c == 0x3a) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID3: + if (c == 0x04) + pMIDIStream->sysExState = eSysExEnhancer; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancer: + if (c == 0x01) + pMIDIStream->sysExState = eSysExEnhancerSubID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancerSubID: + pMIDIStream->sysExState = eSysExEnhancerFeedback1; + break; + + case eSysExEnhancerFeedback1: + pMIDIStream->sysExState = eSysExEnhancerFeedback2; + break; + + case eSysExEnhancerFeedback2: + pMIDIStream->sysExState = eSysExEnhancerDrive; + break; + + case eSysExEnhancerDrive: + pMIDIStream->sysExState = eSysExEnhancerWet; + break; + + case eSysExEnhancerWet: + pMIDIStream->sysExState = eSysExEOX; + break; + + case eSysExEOX: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Expected F7, received %02x\n", c); */ } + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExIgnore: + break; + + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + } + + if (pMIDIStream->sysExState == eSysExIgnore) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Ignoring SysEx byte %02x\n", c); */ } + return EAS_SUCCESS; +} /* end ProcessSysExMessage */ + diff --git a/arm-fm-22k/lib_src/eas_midi.h b/arm-fm-22k/lib_src/eas_midi.h index 37a03ee..10649a0 100644 --- a/arm-fm-22k/lib_src/eas_midi.h +++ b/arm-fm-22k/lib_src/eas_midi.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_midi.h
- *
- * Contents and purpose:
- * Prototypes for MIDI stream parsing functions
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.h + * + * Contents and purpose: + * Prototypes for MIDI stream parsing functions + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,52 +20,52 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_MIDI_H
-#define _EAS_MIDI_H
-
-/*----------------------------------------------------------------------------
- * EAS_InitMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the MIDI stream state for parsing.
- *
- * Inputs:
- *
- * Outputs:
- * returns EAS_RESULT (EAS_SUCCESS is OK)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream);
-
-/*----------------------------------------------------------------------------
- * EAS_ParseMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled)
- * so the interface works equally well for both file and stream I/O.
- *
- * Inputs:
- * c - character from MIDI stream
- *
- * Outputs:
- * returns EAS_RESULT (EAS_SUCCESS is OK)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode);
-
-#endif /* #define _EAS_MIDI_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDI_H +#define _EAS_MIDI_H + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream); + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +#endif /* #define _EAS_MIDI_H */ + diff --git a/arm-fm-22k/lib_src/eas_midictrl.h b/arm-fm-22k/lib_src/eas_midictrl.h index 0c4217d..46fdc4f 100644 --- a/arm-fm-22k/lib_src/eas_midictrl.h +++ b/arm-fm-22k/lib_src/eas_midictrl.h @@ -1,15 +1,15 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_midictrl.h
- *
- * Contents and purpose:
- * MIDI controller definitions
- *
- * This header only contains declarations that are specific
- * to this implementation.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_midictrl.h + * + * Contents and purpose: + * MIDI controller definitions + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,43 +22,43 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_MIDICTRL_H
-#define _EAS_MIDICTRL_H
-
-/* define controller types */
-/*
- Note that these controller types are specified in base 10 (decimal)
- and not in hexadecimal. The above midi messages are specified
- in hexadecimal.
-*/
-#define MIDI_CONTROLLER_BANK_SELECT 0
-#define MIDI_CONTROLLER_BANK_SELECT_MSB 0
-#define MIDI_CONTROLLER_MOD_WHEEL 1
-#define MIDI_CONTROLLER_ENTER_DATA_MSB 6
-#define MIDI_CONTROLLER_VOLUME 7
-#define MIDI_CONTROLLER_PAN 10
-#define MIDI_CONTROLLER_EXPRESSION 11
-#define MIDI_CONTROLLER_BANK_SELECT_LSB 32
-#define MIDI_CONTROLLER_ENTER_DATA_LSB 38 /* 0x26 */
-#define MIDI_CONTROLLER_SUSTAIN_PEDAL 64
-#define MIDI_CONTROLLER_SELECT_NRPN_LSB 98
-#define MIDI_CONTROLLER_SELECT_NRPN_MSB 99
-#define MIDI_CONTROLLER_SELECT_RPN_LSB 100 /* 0x64 */
-#define MIDI_CONTROLLER_SELECT_RPN_MSB 101 /* 0x65 */
-#define MIDI_CONTROLLER_ALL_SOUND_OFF 120
-#define MIDI_CONTROLLER_RESET_CONTROLLERS 121
-#define MIDI_CONTROLLER_ALL_NOTES_OFF 123
-#define MIDI_CONTROLLER_OMNI_OFF 124
-#define MIDI_CONTROLLER_OMNI_ON 125
-#define MIDI_CONTROLLER_MONO_ON_POLY_OFF 126
-#define MIDI_CONTROLLER_POLY_ON_MONO_OFF 127
-
-#endif /* #ifndef _EAS_MIDICTRL_H */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDICTRL_H +#define _EAS_MIDICTRL_H + +/* define controller types */ +/* + Note that these controller types are specified in base 10 (decimal) + and not in hexadecimal. The above midi messages are specified + in hexadecimal. +*/ +#define MIDI_CONTROLLER_BANK_SELECT 0 +#define MIDI_CONTROLLER_BANK_SELECT_MSB 0 +#define MIDI_CONTROLLER_MOD_WHEEL 1 +#define MIDI_CONTROLLER_ENTER_DATA_MSB 6 +#define MIDI_CONTROLLER_VOLUME 7 +#define MIDI_CONTROLLER_PAN 10 +#define MIDI_CONTROLLER_EXPRESSION 11 +#define MIDI_CONTROLLER_BANK_SELECT_LSB 32 +#define MIDI_CONTROLLER_ENTER_DATA_LSB 38 /* 0x26 */ +#define MIDI_CONTROLLER_SUSTAIN_PEDAL 64 +#define MIDI_CONTROLLER_SELECT_NRPN_LSB 98 +#define MIDI_CONTROLLER_SELECT_NRPN_MSB 99 +#define MIDI_CONTROLLER_SELECT_RPN_LSB 100 /* 0x64 */ +#define MIDI_CONTROLLER_SELECT_RPN_MSB 101 /* 0x65 */ +#define MIDI_CONTROLLER_ALL_SOUND_OFF 120 +#define MIDI_CONTROLLER_RESET_CONTROLLERS 121 +#define MIDI_CONTROLLER_ALL_NOTES_OFF 123 +#define MIDI_CONTROLLER_OMNI_OFF 124 +#define MIDI_CONTROLLER_OMNI_ON 125 +#define MIDI_CONTROLLER_MONO_ON_POLY_OFF 126 +#define MIDI_CONTROLLER_POLY_ON_MONO_OFF 127 + +#endif /* #ifndef _EAS_MIDICTRL_H */ diff --git a/arm-fm-22k/lib_src/eas_mididata.c b/arm-fm-22k/lib_src/eas_mididata.c index 2ee907e..4463b7e 100644 --- a/arm-fm-22k/lib_src/eas_mididata.c +++ b/arm-fm-22k/lib_src/eas_mididata.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_mididata.c
- *
- * Contents and purpose:
- * Data module for MIDI stream interface
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_mididata.c + * + * Contents and purpose: + * Data module for MIDI stream interface + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,15 @@ * 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: 547 $
- * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_miditypes.h"
-
-S_INTERACTIVE_MIDI eas_MIDIData;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" + +S_INTERACTIVE_MIDI eas_MIDIData; + diff --git a/arm-fm-22k/lib_src/eas_miditypes.h b/arm-fm-22k/lib_src/eas_miditypes.h index 0b7f96e..015f08b 100644 --- a/arm-fm-22k/lib_src/eas_miditypes.h +++ b/arm-fm-22k/lib_src/eas_miditypes.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_miditypes.h
- *
- * Contents and purpose:
- * Contains declarations for the MIDI stream parser.
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_miditypes.h + * + * Contents and purpose: + * Contains declarations for the MIDI stream parser. + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,119 +20,119 @@ * 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: 778 $
- * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_MIDITYPES_H
-#define _EAS_MIDITYPES_H
-
-#include "eas_data.h"
-#include "eas_parser.h"
-
-/*----------------------------------------------------------------------------
- * S_MIDI_STREAM
- *
- * Maintains parser state for the MIDI stream parser
- *
- *----------------------------------------------------------------------------
-*/
-
-typedef struct s_midi_stream_tag
-{
- EAS_BOOL8 byte3; /* flag indicates 3rd byte expected */
- EAS_BOOL8 pending; /* flag indicates more data expected */
- EAS_U8 sysExState; /* maintains the SysEx state */
- EAS_U8 runningStatus; /* last running status received */
- EAS_U8 status; /* status byte */
- EAS_U8 d1; /* first data byte */
- EAS_U8 d2; /* second data byte */
- EAS_U8 flags; /* flags - see below for definition */
-#ifdef JET_INTERFACE
- EAS_U32 jetData; /* JET data */
-#endif
-} S_MIDI_STREAM;
-
-/* flags for S_MIDI_STREAM.flags */
-#define MIDI_FLAG_GM_ON 0x01 /* GM System On message received */
-#define MIDI_FLAG_FIRST_NOTE 0x02 /* first note received */
-
-/* flags for S_MIDI_STREAM.jetFlags */
-#define MIDI_FLAGS_JET_MUTE 0x00000001 /* track is muted */
-#define MIDI_FLAGS_JET_CB 0x00000002 /* JET callback enabled */
-
-/*----------------------------------------------------------------------------
- *
- * S_SMF_STREAM
- *
- * This structure contains data required to parse an SMF stream. For SMF0 files, there
- * will be a single instance of this per file. For SMF1 files, there will be multiple instance,
- * one for each separate stream in the file.
- *
- *----------------------------------------------------------------------------
-*/
-
-typedef struct s_smf_stream_tag
-{
- EAS_FILE_HANDLE fileHandle; /* host wrapper file handle */
- EAS_U32 ticks; /* time of next event in stream */
- EAS_I32 startFilePos; /* start location of track within file */
- S_MIDI_STREAM midiStream; /* MIDI stream state */
-} S_SMF_STREAM;
-
-/*----------------------------------------------------------------------------
- *
- * S_SMF_DATA
- *
- * This structure contains the instance data required to parse an SMF stream.
- *
- *----------------------------------------------------------------------------
-*/
-
-typedef struct s_smf_data_tag
-{
-#ifdef _CHECKED_BUILD
- EAS_U32 handleCheck; /* signature check for checked build */
-#endif
- S_SMF_STREAM *streams; /* pointer to individual streams in file */
- S_SMF_STREAM *nextStream; /* pointer to next stream with event */
- S_SYNTH *pSynth; /* pointer to synth */
- EAS_FILE_HANDLE fileHandle; /* file handle */
- S_METADATA_CB metadata; /* metadata callback */
- EAS_I32 fileOffset; /* for embedded files */
- EAS_I32 time; /* current time in milliseconds/256 */
- EAS_U16 numStreams; /* actual number of streams */
- EAS_U16 tickConv; /* current MIDI tick to msec conversion */
- EAS_U16 ppqn; /* ticks per quarter note */
- EAS_U8 state; /* current state EAS_STATE_XXXX */
- EAS_U8 flags; /* flags - see definitions below */
-} S_SMF_DATA;
-
-#define SMF_FLAGS_CHASE_MODE 0x01 /* chase mode - skip to first note */
-#define SMF_FLAGS_HAS_TIME_SIG 0x02 /* time signature encountered at time 0 */
-#define SMF_FLAGS_HAS_TEMPO 0x04 /* tempo encountered at time 0 */
-#define SMF_FLAGS_HAS_GM_ON 0x08 /* GM System On encountered at time 0 */
-#define SMF_FLAGS_JET_STREAM 0x80 /* JET in use - keep strict timing */
-
-/* combo flags indicate setup bar */
-#define SMF_FLAGS_SETUP_BAR (SMF_FLAGS_HAS_TIME_SIG | SMF_FLAGS_HAS_TEMPO | SMF_FLAGS_HAS_GM_ON)
-
-/*----------------------------------------------------------------------------
- * Interactive MIDI structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_interactive_midi_tag
-{
-#ifdef _CHECKED_BUILD
- EAS_U32 handleCheck; /* signature check for checked build */
-#endif
- S_SYNTH *pSynth; /* pointer to synth */
- S_MIDI_STREAM stream; /* stream data */
-} S_INTERACTIVE_MIDI;
-
-#endif /* #ifndef _EAS_MIDITYPES_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDITYPES_H +#define _EAS_MIDITYPES_H + +#include "eas_data.h" +#include "eas_parser.h" + +/*---------------------------------------------------------------------------- + * S_MIDI_STREAM + * + * Maintains parser state for the MIDI stream parser + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_midi_stream_tag +{ + EAS_BOOL8 byte3; /* flag indicates 3rd byte expected */ + EAS_BOOL8 pending; /* flag indicates more data expected */ + EAS_U8 sysExState; /* maintains the SysEx state */ + EAS_U8 runningStatus; /* last running status received */ + EAS_U8 status; /* status byte */ + EAS_U8 d1; /* first data byte */ + EAS_U8 d2; /* second data byte */ + EAS_U8 flags; /* flags - see below for definition */ +#ifdef JET_INTERFACE + EAS_U32 jetData; /* JET data */ +#endif +} S_MIDI_STREAM; + +/* flags for S_MIDI_STREAM.flags */ +#define MIDI_FLAG_GM_ON 0x01 /* GM System On message received */ +#define MIDI_FLAG_FIRST_NOTE 0x02 /* first note received */ + +/* flags for S_MIDI_STREAM.jetFlags */ +#define MIDI_FLAGS_JET_MUTE 0x00000001 /* track is muted */ +#define MIDI_FLAGS_JET_CB 0x00000002 /* JET callback enabled */ + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * This structure contains data required to parse an SMF stream. For SMF0 files, there + * will be a single instance of this per file. For SMF1 files, there will be multiple instance, + * one for each separate stream in the file. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_stream_tag +{ + EAS_FILE_HANDLE fileHandle; /* host wrapper file handle */ + EAS_U32 ticks; /* time of next event in stream */ + EAS_I32 startFilePos; /* start location of track within file */ + S_MIDI_STREAM midiStream; /* MIDI stream state */ +} S_SMF_STREAM; + +/*---------------------------------------------------------------------------- + * + * S_SMF_DATA + * + * This structure contains the instance data required to parse an SMF stream. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SMF_STREAM *streams; /* pointer to individual streams in file */ + S_SMF_STREAM *nextStream; /* pointer to next stream with event */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* for embedded files */ + EAS_I32 time; /* current time in milliseconds/256 */ + EAS_U16 numStreams; /* actual number of streams */ + EAS_U16 tickConv; /* current MIDI tick to msec conversion */ + EAS_U16 ppqn; /* ticks per quarter note */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 flags; /* flags - see definitions below */ +} S_SMF_DATA; + +#define SMF_FLAGS_CHASE_MODE 0x01 /* chase mode - skip to first note */ +#define SMF_FLAGS_HAS_TIME_SIG 0x02 /* time signature encountered at time 0 */ +#define SMF_FLAGS_HAS_TEMPO 0x04 /* tempo encountered at time 0 */ +#define SMF_FLAGS_HAS_GM_ON 0x08 /* GM System On encountered at time 0 */ +#define SMF_FLAGS_JET_STREAM 0x80 /* JET in use - keep strict timing */ + +/* combo flags indicate setup bar */ +#define SMF_FLAGS_SETUP_BAR (SMF_FLAGS_HAS_TIME_SIG | SMF_FLAGS_HAS_TEMPO | SMF_FLAGS_HAS_GM_ON) + +/*---------------------------------------------------------------------------- + * Interactive MIDI structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_interactive_midi_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SYNTH *pSynth; /* pointer to synth */ + S_MIDI_STREAM stream; /* stream data */ +} S_INTERACTIVE_MIDI; + +#endif /* #ifndef _EAS_MIDITYPES_H */ + diff --git a/arm-fm-22k/lib_src/eas_mixbuf.c b/arm-fm-22k/lib_src/eas_mixbuf.c index 73e969a..db5bd02 100644 --- a/arm-fm-22k/lib_src/eas_mixbuf.c +++ b/arm-fm-22k/lib_src/eas_mixbuf.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_mixbuf.c
- *
- * Contents and purpose:
- * Contains a data allocation for synthesizer
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_mixbuf.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,18 +19,18 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-// includes
-#include "eas_data.h"
-#include "eas_mixer.h"
-
-// globals
-EAS_I32 eas_MixBuffer[BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS];
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_mixer.h" + +// globals +EAS_I32 eas_MixBuffer[BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS]; + diff --git a/arm-fm-22k/lib_src/eas_mixer.c b/arm-fm-22k/lib_src/eas_mixer.c index c4a2f9f..0a839a8 100644 --- a/arm-fm-22k/lib_src/eas_mixer.c +++ b/arm-fm-22k/lib_src/eas_mixer.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_mixer.c
- *
- * Contents and purpose:
- * This file contains the critical components of the mix engine that
- * must be optimized for best performance.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.c + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,445 +20,445 @@ * 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: 706 $
- * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $
- *----------------------------------------------------------------------------
-*/
-
-//3 dls: This module is in the midst of being converted from a synth
-//3 specific module to a general purpose mix engine
-
-/*------------------------------------
- * includes
- *------------------------------------
-*/
-#include "eas_data.h"
-#include "eas_host.h"
-#include "eas_math.h"
-#include "eas_mixer.h"
-#include "eas_config.h"
-#include "eas_report.h"
-
-#ifdef _MAXIMIZER_ENABLED
-EAS_I32 MaximizerProcess (EAS_VOID_PTR pInstData, EAS_I32 *pSrc, EAS_I32 *pDst, EAS_I32 numSamples);
-#endif
-
-/*------------------------------------
- * defines
- *------------------------------------
-*/
-
-/* need to boost stereo by ~3dB to compensate for the panner */
-#define STEREO_3DB_GAIN_BOOST 512
-
-/*----------------------------------------------------------------------------
- * EAS_MixEngineInit()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepares the mix engine for work, allocates buffers, locates effects modules, etc.
- *
- * Inputs:
- * pEASData - instance data
- * pInstData - pointer to variable to receive instance data handle
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_MixEngineInit (S_EAS_DATA *pEASData)
-{
-
- /* check Configuration Module for mix buffer allocation */
- if (pEASData->staticMemoryModel)
- pEASData->pMixBuffer = EAS_CMEnumData(EAS_CM_MIX_BUFFER);
- else
- pEASData->pMixBuffer = EAS_HWMalloc(pEASData->hwInstData, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32));
- if (pEASData->pMixBuffer == NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate mix buffer memory\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
- EAS_HWMemSet((void *)(pEASData->pMixBuffer), 0, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32));
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_MixEnginePrep()
- *----------------------------------------------------------------------------
- * Purpose:
- * Performs prep before synthesize a buffer of audio, such as clearing
- * audio buffers, etc.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void EAS_MixEnginePrep (S_EAS_DATA *pEASData, EAS_I32 numSamples)
-{
-
- /* clear the mix buffer */
-#if (NUM_OUTPUT_CHANNELS == 2)
- EAS_HWMemSet(pEASData->pMixBuffer, 0, numSamples * (EAS_I32) sizeof(long) * 2);
-#else
- EAS_HWMemSet(pEASData->pMixBuffer, 0, (EAS_I32) numSamples * (EAS_I32) sizeof(long));
-#endif
-
- /* need to clear other side-chain effect buffers (chorus & reverb) */
-}
-
-/*----------------------------------------------------------------------------
- * EAS_MixEnginePost
- *----------------------------------------------------------------------------
- * Purpose:
- * This routine does the post-processing after all voices have been
- * synthesized. It calls any sweeteners and does the final mixdown to
- * the output buffer.
- *
- * Inputs:
- *
- * Outputs:
- *
- * Notes:
- *----------------------------------------------------------------------------
-*/
-void EAS_MixEnginePost (S_EAS_DATA *pEASData, EAS_I32 numSamples)
-{
- EAS_U16 gain;
-
-//3 dls: Need to restore the mix engine metrics
-
- /* calculate the gain multiplier */
-#ifdef _MAXIMIZER_ENABLED
- if (pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effect)
- {
- EAS_I32 temp;
- temp = MaximizerProcess(pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effectData, pEASData->pMixBuffer, pEASData->pMixBuffer, numSamples);
- temp = (temp * pEASData->masterGain) >> 15;
- if (temp > 32767)
- gain = 32767;
- else
- gain = (EAS_U16) temp;
- }
- else
- gain = (EAS_U16) pEASData->masterGain;
-#else
- gain = (EAS_U16) pEASData->masterGain;
-#endif
-
- /* Not using all the gain bits for now
- * Reduce the input to the compressor by 6dB to prevent saturation
- */
-#ifdef _COMPRESSOR_ENABLED
- if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData)
- gain = gain >> 5;
- else
- gain = gain >> 4;
-#else
- gain = gain >> 4;
-#endif
-
- /* convert 32-bit mix buffer to 16-bit output format */
-#if (NUM_OUTPUT_CHANNELS == 2)
- SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) ((EAS_U16) numSamples * 2));
-#else
- SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) numSamples);
-#endif
-
-#ifdef _ENHANCER_ENABLED
- /* enhancer effect */
- if (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData)
- (*pEASData->effectsModules[EAS_MODULE_ENHANCER].effect->pfProcess)
- (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData,
- pEASData->pOutputAudioBuffer,
- pEASData->pOutputAudioBuffer,
- numSamples);
-#endif
-
-#ifdef _GRAPHIC_EQ_ENABLED
- /* graphic EQ effect */
- if (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData)
- (*pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effect->pfProcess)
- (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData,
- pEASData->pOutputAudioBuffer,
- pEASData->pOutputAudioBuffer,
- numSamples);
-#endif
-
-#ifdef _COMPRESSOR_ENABLED
- /* compressor effect */
- if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData)
- (*pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effect->pfProcess)
- (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData,
- pEASData->pOutputAudioBuffer,
- pEASData->pOutputAudioBuffer,
- numSamples);
-#endif
-
-#ifdef _WOW_ENABLED
- /* WOW requires a 32-bit buffer, borrow the mix buffer and
- * pass it as the destination buffer
- */
- /*lint -e{740} temporarily passing a parameter through an existing I/F */
- if (pEASData->effectsModules[EAS_MODULE_WOW].effectData)
- (*pEASData->effectsModules[EAS_MODULE_WOW].effect->pfProcess)
- (pEASData->effectsModules[EAS_MODULE_WOW].effectData,
- pEASData->pOutputAudioBuffer,
- (EAS_PCM*) pEASData->pMixBuffer,
- numSamples);
-#endif
-
-#ifdef _TONECONTROLEQ_ENABLED
- /* ToneControlEQ effect */
- if (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData)
- (*pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effect->pfProcess)
- (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData,
- pEASData->pOutputAudioBuffer,
- pEASData->pOutputAudioBuffer,
- numSamples);
-#endif
-
-#ifdef _REVERB_ENABLED
- /* Reverb effect */
- if (pEASData->effectsModules[EAS_MODULE_REVERB].effectData)
- (*pEASData->effectsModules[EAS_MODULE_REVERB].effect->pfProcess)
- (pEASData->effectsModules[EAS_MODULE_REVERB].effectData,
- pEASData->pOutputAudioBuffer,
- pEASData->pOutputAudioBuffer,
- numSamples);
-#endif
-
-#ifdef _CHORUS_ENABLED
- /* Chorus effect */
- if (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData)
- (*pEASData->effectsModules[EAS_MODULE_CHORUS].effect->pfProcess)
- (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData,
- pEASData->pOutputAudioBuffer,
- pEASData->pOutputAudioBuffer,
- numSamples);
-#endif
-
-}
-
-#ifndef NATIVE_EAS_KERNEL
-/*----------------------------------------------------------------------------
- * SynthMasterGain
- *----------------------------------------------------------------------------
- * Purpose:
- * Mixes down audio from 32-bit to 16-bit target buffer
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void SynthMasterGain (long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 numSamples) {
-
- /* loop through the buffer */
- while (numSamples--) {
- long s;
-
- /* read a sample from the input buffer and add some guard bits */
- s = *pInputBuffer++;
-
- /* add some guard bits */
- /*lint -e{704} <avoid divide for performance>*/
- s = s >> 7;
-
- /* apply master gain */
- s *= (long) nGain;
-
- /* shift to lower 16-bits */
- /*lint -e{704} <avoid divide for performance>*/
- s = s >> 9;
-
- /* saturate */
- s = SATURATE(s);
-
- *pOutputBuffer++ = (EAS_PCM)s;
- }
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_MixEngineShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Shuts down effects modules and deallocates memory
- *
- * Inputs:
- * pEASData - instance data
- * pInstData - instance data handle
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData)
-{
-
- /* check Configuration Module for static memory allocation */
- if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL))
- EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer);
-
- return EAS_SUCCESS;
-}
-
-#ifdef UNIFIED_MIXER
-#ifndef NATIVE_MIX_STREAM
-/*----------------------------------------------------------------------------
- * EAS_MixStream
- *----------------------------------------------------------------------------
- * Mix a 16-bit stream into a 32-bit buffer
- *
- * pInputBuffer 16-bit input buffer
- * pMixBuffer 32-bit mix buffer
- * numSamples number of samples to mix
- * gainLeft initial gain left or mono
- * gainRight initial gain right
- * gainLeft left gain increment per sample
- * gainRight right gain increment per sample
- * flags bit 0 = stereo source
- * bit 1 = stereo output
- *----------------------------------------------------------------------------
-*/
-void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags)
-{
- EAS_I32 temp;
- EAS_INT src, dest;
-
- /* NOTE: There are a lot of optimizations that can be done
- * in the native implementations based on register
- * availability, etc. For example, it may make sense to
- * break this down into 8 separate routines:
- *
- * 1. Mono source to mono output
- * 2. Mono source to stereo output
- * 3. Stereo source to mono output
- * 4. Stereo source to stereo output
- * 5. Mono source to mono output - no gain change
- * 6. Mono source to stereo output - no gain change
- * 7. Stereo source to mono output - no gain change
- * 8. Stereo source to stereo output - no gain change
- *
- * Other possibilities include loop unrolling, skipping
- * a gain calculation every 2 or 4 samples, etc.
- */
-
- /* no gain change, use fast loops */
- if ((gainIncLeft == 0) && (gainIncRight == 0))
- {
- switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
- {
- /* mono to mono */
- case 0:
- gainLeft >>= 15;
- for (src = dest = 0; src < numSamples; src++, dest++)
- {
-
- pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
- }
- break;
-
- /* mono to stereo */
- case MIX_FLAGS_STEREO_OUTPUT:
- gainLeft >>= 15;
- gainRight >>= 15;
- for (src = dest = 0; src < numSamples; src++, dest+=2)
- {
- pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
- pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS;
- }
- break;
-
- /* stereo to mono */
- case MIX_FLAGS_STEREO_SOURCE:
- gainLeft >>= 15;
- gainRight >>= 15;
- for (src = dest = 0; src < numSamples; src+=2, dest++)
- {
- temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
- temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS);
- pMixBuffer[dest] += temp;
- }
- break;
-
- /* stereo to stereo */
- case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
- gainLeft >>= 15;
- gainRight >>= 15;
- for (src = dest = 0; src < numSamples; src+=2, dest+=2)
- {
- pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
- pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS;
- }
- break;
- }
- }
-
- /* gain change - do gain increment */
- else
- {
- switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
- {
- /* mono to mono */
- case 0:
- for (src = dest = 0; src < numSamples; src++, dest++)
- {
- gainLeft += gainIncLeft;
- pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
- }
- break;
-
- /* mono to stereo */
- case MIX_FLAGS_STEREO_OUTPUT:
- for (src = dest = 0; src < numSamples; src++, dest+=2)
- {
- gainLeft += gainIncLeft;
- gainRight += gainIncRight;
- pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
- pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
- }
- break;
-
- /* stereo to mono */
- case MIX_FLAGS_STEREO_SOURCE:
- for (src = dest = 0; src < numSamples; src+=2, dest++)
- {
- gainLeft += gainIncLeft;
- gainRight += gainIncRight;
- temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
- temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS);
- pMixBuffer[dest] += temp;
- }
- break;
-
- /* stereo to stereo */
- case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
- for (src = dest = 0; src < numSamples; src+=2, dest+=2)
- {
- gainLeft += gainIncLeft;
- gainRight += gainIncRight;
- pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
- pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
- }
- break;
- }
- }
-}
-#endif
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_data.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_mixer.h" +#include "eas_config.h" +#include "eas_report.h" + +#ifdef _MAXIMIZER_ENABLED +EAS_I32 MaximizerProcess (EAS_VOID_PTR pInstData, EAS_I32 *pSrc, EAS_I32 *pDst, EAS_I32 numSamples); +#endif + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* need to boost stereo by ~3dB to compensate for the panner */ +#define STEREO_3DB_GAIN_BOOST 512 + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for mix buffer allocation */ + if (pEASData->staticMemoryModel) + pEASData->pMixBuffer = EAS_CMEnumData(EAS_CM_MIX_BUFFER); + else + pEASData->pMixBuffer = EAS_HWMalloc(pEASData->hwInstData, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + if (pEASData->pMixBuffer == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate mix buffer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet((void *)(pEASData->pMixBuffer), 0, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + + /* clear the mix buffer */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_HWMemSet(pEASData->pMixBuffer, 0, numSamples * (EAS_I32) sizeof(long) * 2); +#else + EAS_HWMemSet(pEASData->pMixBuffer, 0, (EAS_I32) numSamples * (EAS_I32) sizeof(long)); +#endif + + /* need to clear other side-chain effect buffers (chorus & reverb) */ +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + EAS_U16 gain; + +//3 dls: Need to restore the mix engine metrics + + /* calculate the gain multiplier */ +#ifdef _MAXIMIZER_ENABLED + if (pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effect) + { + EAS_I32 temp; + temp = MaximizerProcess(pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effectData, pEASData->pMixBuffer, pEASData->pMixBuffer, numSamples); + temp = (temp * pEASData->masterGain) >> 15; + if (temp > 32767) + gain = 32767; + else + gain = (EAS_U16) temp; + } + else + gain = (EAS_U16) pEASData->masterGain; +#else + gain = (EAS_U16) pEASData->masterGain; +#endif + + /* Not using all the gain bits for now + * Reduce the input to the compressor by 6dB to prevent saturation + */ +#ifdef _COMPRESSOR_ENABLED + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + gain = gain >> 5; + else + gain = gain >> 4; +#else + gain = gain >> 4; +#endif + + /* convert 32-bit mix buffer to 16-bit output format */ +#if (NUM_OUTPUT_CHANNELS == 2) + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) ((EAS_U16) numSamples * 2)); +#else + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) numSamples); +#endif + +#ifdef _ENHANCER_ENABLED + /* enhancer effect */ + if (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData) + (*pEASData->effectsModules[EAS_MODULE_ENHANCER].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _GRAPHIC_EQ_ENABLED + /* graphic EQ effect */ + if (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _COMPRESSOR_ENABLED + /* compressor effect */ + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + (*pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _WOW_ENABLED + /* WOW requires a 32-bit buffer, borrow the mix buffer and + * pass it as the destination buffer + */ + /*lint -e{740} temporarily passing a parameter through an existing I/F */ + if (pEASData->effectsModules[EAS_MODULE_WOW].effectData) + (*pEASData->effectsModules[EAS_MODULE_WOW].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_WOW].effectData, + pEASData->pOutputAudioBuffer, + (EAS_PCM*) pEASData->pMixBuffer, + numSamples); +#endif + +#ifdef _TONECONTROLEQ_ENABLED + /* ToneControlEQ effect */ + if (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _REVERB_ENABLED + /* Reverb effect */ + if (pEASData->effectsModules[EAS_MODULE_REVERB].effectData) + (*pEASData->effectsModules[EAS_MODULE_REVERB].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_REVERB].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _CHORUS_ENABLED + /* Chorus effect */ + if (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData) + (*pEASData->effectsModules[EAS_MODULE_CHORUS].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +} + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * SynthMasterGain + *---------------------------------------------------------------------------- + * Purpose: + * Mixes down audio from 32-bit to 16-bit target buffer + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void SynthMasterGain (long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 numSamples) { + + /* loop through the buffer */ + while (numSamples--) { + long s; + + /* read a sample from the input buffer and add some guard bits */ + s = *pInputBuffer++; + + /* add some guard bits */ + /*lint -e{704} <avoid divide for performance>*/ + s = s >> 7; + + /* apply master gain */ + s *= (long) nGain; + + /* shift to lower 16-bits */ + /*lint -e{704} <avoid divide for performance>*/ + s = s >> 9; + + /* saturate */ + s = SATURATE(s); + + *pOutputBuffer++ = (EAS_PCM)s; + } +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL)) + EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer); + + return EAS_SUCCESS; +} + +#ifdef UNIFIED_MIXER +#ifndef NATIVE_MIX_STREAM +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags) +{ + EAS_I32 temp; + EAS_INT src, dest; + + /* NOTE: There are a lot of optimizations that can be done + * in the native implementations based on register + * availability, etc. For example, it may make sense to + * break this down into 8 separate routines: + * + * 1. Mono source to mono output + * 2. Mono source to stereo output + * 3. Stereo source to mono output + * 4. Stereo source to stereo output + * 5. Mono source to mono output - no gain change + * 6. Mono source to stereo output - no gain change + * 7. Stereo source to mono output - no gain change + * 8. Stereo source to stereo output - no gain change + * + * Other possibilities include loop unrolling, skipping + * a gain calculation every 2 or 4 samples, etc. + */ + + /* no gain change, use fast loops */ + if ((gainIncLeft == 0) && (gainIncRight == 0)) + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + gainLeft >>= 15; + for (src = dest = 0; src < numSamples; src++, dest++) + { + + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } + + /* gain change - do gain increment */ + else + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + for (src = dest = 0; src < numSamples; src++, dest++) + { + gainLeft += gainIncLeft; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } +} +#endif +#endif + diff --git a/arm-fm-22k/lib_src/eas_mixer.h b/arm-fm-22k/lib_src/eas_mixer.h index 2ba2d3d..b2eb33b 100644 --- a/arm-fm-22k/lib_src/eas_mixer.h +++ b/arm-fm-22k/lib_src/eas_mixer.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_mixer.h
- *
- * Contents and purpose:
- * This file contains the critical components of the mix engine that
- * must be optimized for best performance.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.h + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,118 +20,118 @@ * 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: 706 $
- * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_MIXER_H
-#define _EAS_MIXER_H
-
-//3 dls: This module is in the midst of being converted from a synth
-//3 specific module to a general purpose mix engine
-
-#define MIX_FLAGS_STEREO_SOURCE 1
-#define MIX_FLAGS_STEREO_OUTPUT 2
-#define NUM_MIXER_GUARD_BITS 4
-
-#include "eas_effects.h"
-
-extern void SynthMasterGain( long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 nNumLoopSamples);
-
-/*----------------------------------------------------------------------------
- * EAS_MixEngineInit()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepares the mix engine for work, allocates buffers, locates effects modules, etc.
- *
- * Inputs:
- * pEASData - instance data
- * pInstData - pointer to variable to receive instance data handle
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_MixEngineInit (EAS_DATA_HANDLE pEASData);
-
-/*----------------------------------------------------------------------------
- * EAS_MixEnginePrep()
- *----------------------------------------------------------------------------
- * Purpose:
- * Performs prep before synthesize a buffer of audio, such as clearing
- * audio buffers, etc.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void EAS_MixEnginePrep (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd);
-
-/*----------------------------------------------------------------------------
- * EAS_MixEnginePost
- *----------------------------------------------------------------------------
- * Purpose:
- * This routine does the post-processing after all voices have been
- * synthesized. It calls any sweeteners and does the final mixdown to
- * the output buffer.
- *
- * Inputs:
- *
- * Outputs:
- *
- * Notes:
- *----------------------------------------------------------------------------
-*/
-void EAS_MixEnginePost (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd);
-
-/*----------------------------------------------------------------------------
- * EAS_MixEngineShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Shuts down effects modules and deallocates memory
- *
- * Inputs:
- * pEASData - instance data
- * pInstData - instance data handle
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_MixEngineShutdown (EAS_DATA_HANDLE pEASData);
-
-#ifdef UNIFIED_MIXER
-/*----------------------------------------------------------------------------
- * EAS_MixStream
- *----------------------------------------------------------------------------
- * Mix a 16-bit stream into a 32-bit buffer
- *
- * pInputBuffer 16-bit input buffer
- * pMixBuffer 32-bit mix buffer
- * numSamples number of samples to mix
- * gainLeft initial gain left or mono
- * gainRight initial gain right
- * gainLeft left gain increment per sample
- * gainRight right gain increment per sample
- * flags bit 0 = stereo source
- * bit 1 = stereo output
- *----------------------------------------------------------------------------
-*/
-void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags);
-#endif
-
-#endif /* #ifndef _EAS_MIXER_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIXER_H +#define _EAS_MIXER_H + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +#define MIX_FLAGS_STEREO_SOURCE 1 +#define MIX_FLAGS_STEREO_OUTPUT 2 +#define NUM_MIXER_GUARD_BITS 4 + +#include "eas_effects.h" + +extern void SynthMasterGain( long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 nNumLoopSamples); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (EAS_DATA_HANDLE pEASData); + +#ifdef UNIFIED_MIXER +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags); +#endif + +#endif /* #ifndef _EAS_MIXER_H */ + diff --git a/arm-fm-22k/lib_src/eas_ota.c b/arm-fm-22k/lib_src/eas_ota.c index fb81d62..5bc9062 100644 --- a/arm-fm-22k/lib_src/eas_ota.c +++ b/arm-fm-22k/lib_src/eas_ota.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_ota.c
- *
- * Contents and purpose:
- * OTA parser
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_ota.c + * + * Contents and purpose: + * OTA parser + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,1059 +19,1059 @@ * 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: 795 $
- * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_miditypes.h"
-#include "eas_parser.h"
-#include "eas_report.h"
-#include "eas_host.h"
-#include "eas_midi.h"
-#include "eas_config.h"
-#include "eas_vm_protos.h"
-#include "eas_otadata.h"
-
-/* increase gain for mono ringtones */
-#define OTA_GAIN_OFFSET 8
-
-/* file definitions */
-#define OTA_RINGTONE 0x25
-#define OTA_SOUND 0x1d
-#define OTA_UNICODE 0x22
-
-/* song type definitions */
-#define OTA_BASIC_SONG_TYPE 0x01
-#define OTA_TEMPORARY_SONG_TYPE 0x02
-
-/* instruction ID coding */
-#define OTA_PATTERN_HEADER_ID 0x00
-#define OTA_NOTE_INST_ID 0x01
-#define OTA_SCALE_INST_ID 0x02
-#define OTA_STYLE_INST_ID 0x03
-#define OTA_TEMPO_INST_ID 0x04
-#define OTA_VOLUME_INST_ID 0x05
-
-/* note durations */
-#define OTA_NORMAL_DURATION 0x00
-#define OTA_DOTTED_NOTE 0x01
-#define OTA_DOUBLE_DOTTED_NOTE 0x02
-#define OTA_TRIPLET_NOTE 0x03
-
-/* loop count value for infinite loop */
-#define OTA_INFINITE_LOOP 0x0f
-
-/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */
-#define DEFAULT_TICK_CONV 30476
-
-/* default channel and program for OTA playback */
-#define OTA_CHANNEL 0
-#define OTA_PROGRAM 80
-#define OTA_VEL_MUL 4
-#define OTA_VEL_OFS 67
-#define OTA_VEL_DEFAULT 95
-
-/* multiplier for fixed point triplet conversion */
-#define TRIPLET_MULTIPLIER 683
-#define TRIPLET_SHIFT 10
-
-/* local prototypes */
-static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
-static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
-static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
-static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
-static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData);
-static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue);
-static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc);
-static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc);
-
-
-/*----------------------------------------------------------------------------
- *
- * EAS_OTA_Parser
- *
- * This structure contains the functional interface for the OTA parser
- *----------------------------------------------------------------------------
-*/
-const S_FILE_PARSER_INTERFACE EAS_OTA_Parser =
-{
- OTA_CheckFileType,
- OTA_Prepare,
- OTA_Time,
- OTA_Event,
- OTA_State,
- OTA_Close,
- OTA_Reset,
- OTA_Pause,
- OTA_Resume,
- NULL,
- OTA_SetData,
- OTA_GetData,
- NULL
-};
-
-/*----------------------------------------------------------------------------
- *
- * bpmTable
- *
- * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note
- *----------------------------------------------------------------------------
-*/
-static const EAS_U32 bpmTable[32] =
-{
- 76800, 68571, 61935, 54857,
- 48000, 42667, 38400, 34286,
- 30476, 27429, 24000, 21333,
- 19200, 17143, 15360, 13714,
- 12000, 10667, 9600, 8533,
- 7680, 6737, 6000, 5408,
- 4800, 4267, 3840, 3398,
- 3024, 2685, 2400, 2133
-};
-
-/*----------------------------------------------------------------------------
- * OTA_CheckFileType()
- *----------------------------------------------------------------------------
- * Purpose:
- * Check the file type to see if we can parse it
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
-{
- S_OTA_DATA* pData;
- EAS_RESULT result;
- EAS_INT cmdLen;
- EAS_INT state;
- EAS_U8 temp;
-
- /* read the first byte, should be command length */
- *ppHandle = NULL;
- if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS)
- return result;
-
- /* read all the commands */
- cmdLen = temp;
- state = 0;
- while (cmdLen--)
- {
-
- /* read the command, upper 7 bits */
- if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS)
- return result;
- temp = temp >> 1;
-
- if (state == 0)
- {
- if (temp != OTA_RINGTONE)
- break;
- state++;
- }
- else
- {
-
- if (temp == OTA_SOUND)
- {
-
- /* check for static memory allocation */
- if (pEASData->staticMemoryModel)
- pData = EAS_CMEnumData(EAS_CM_OTA_DATA);
- else
- pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA));
- if (!pData)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
- EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA));
-
- /* return a pointer to the instance data */
- pData->fileHandle = fileHandle;
- pData->fileOffset = offset;
- pData->state = EAS_STATE_OPEN;
- *ppHandle = pData;
- break;
- }
-
- if (temp != OTA_UNICODE)
- break;
- }
- }
-
- /* not recognized */
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_Prepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_OTA_DATA* pData;
- EAS_RESULT result;
-
- /* check for valid state */
- pData = (S_OTA_DATA*) pInstData;
- if (pData->state != EAS_STATE_OPEN)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* instantiate a synthesizer */
- if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ }
- return result;
- }
-
- pData->state = EAS_STATE_ERROR;
- if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS)
- return result;
-
- pData->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_Time()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the time of the next event in msecs
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pTime - pointer to variable to hold time of next event (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
-{
- S_OTA_DATA *pData;
-
- pData = (S_OTA_DATA*) pInstData;
-
- /* return time in milliseconds */
- /*lint -e{704} use shift instead of division */
- *pTime = pData->time >> 8;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_Event()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the next event in the file
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
-{
- S_OTA_DATA* pData;
- EAS_RESULT result;
- EAS_U32 duration;
- EAS_U8 temp;
-
- pData = (S_OTA_DATA*) pInstData;
- if (pData->state >= EAS_STATE_OPEN)
- return EAS_SUCCESS;
-
- /* initialize MIDI channel when the track starts playing */
- if (pData->time == 0)
- {
- /* set program to square lead */
- if (parserMode != eParserModeMetaData)
- VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM);
-
- /* set channel volume to max */
- if (parserMode != eParserModeMetaData)
- VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127);
- }
-
- /* check for end of note */
- if (pData->note)
- {
- /* stop the note */
- VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0);
- pData->note = 0;
-
- /* check for rest between notes */
- if (pData->restTicks)
- {
- pData->time += (EAS_I32) pData->restTicks;
- pData->restTicks = 0;
- return EAS_SUCCESS;
- }
- }
-
- /* if not in a pattern, read the pattern header */
- while (pData->current.patternLen == 0)
- {
-
- /* check for loop - don't do infinite loops when locating */
- if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP)))
- {
- /* if not infinite loop, decrement loop count */
- if (pData->loopCount != OTA_INFINITE_LOOP)
- pData->loopCount--;
-
- /* back to start of pattern*/
- if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS)
- return result;
- }
-
- /* if no previous position to restore, continue forward */
- else if (pData->restore.fileOffset < 0)
- {
-
- /* check for end of song */
- if (pData->numPatterns == 0)
- {
- pData->state = EAS_STATE_STOPPING;
- VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth);
- return EAS_SUCCESS;
- }
-
- /* read the next pattern header */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS)
- return result;
- if (temp != OTA_PATTERN_HEADER_ID)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* get the pattern ID */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS)
- return result;
-
- /* get the loop count */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS)
- return result;
-
- /* get the pattern length */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS)
- return result;
-
- /* if pattern definition, save the current position */
- if (pData->current.patternLen)
- {
- if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS)
- return result;
- }
-
- /* if pattern length is zero, repeat a previous pattern */
- else
- {
- /* make sure it's a valid pattern */
- if (pData->patterns[pData->currentPattern].fileOffset < 0)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* save current position and data */
- if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS)
- return result;
-
- /* seek to the pattern in the file */
- if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS)
- return result;
- }
-
- /* decrement pattern count */
- pData->numPatterns--;
- }
-
- /* restore previous position */
- else
- {
- if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS)
- return result;
- }
- }
-
- /* get the next event */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS)
- return result;
-
- switch (temp)
- {
- case OTA_NOTE_INST_ID:
- /* fetch note value */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS)
- return result;
-
- /* fetch note duration */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS)
- return result;
- duration = pData->tick * (0x20 >> temp);
-
- /* fetch note duration modifier */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS)
- return result;
- switch (temp)
- {
- case OTA_NORMAL_DURATION:
- break;
-
- case OTA_DOTTED_NOTE:
- duration += duration >> 1;
- break;
-
- case OTA_DOUBLE_DOTTED_NOTE:
- duration += (duration >> 1) + (duration >> 2);
- break;
-
- case OTA_TRIPLET_NOTE:
- duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT;
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ }
- break;
- }
-
- /* check for note */
- if (pData->note)
- {
-
- /* determine note length based on style */
- switch (pData->style)
- {
- case 0:
- pData->restTicks = duration >> 4;
- break;
- case 1:
- pData->restTicks = 0;
- break;
- case 2:
- pData->restTicks = duration >> 1;
- break;
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ }
- }
-
- /* add octave */
- pData->note += pData->octave;
- if (parserMode == eParserModePlay)
- VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity);
- pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks;
- }
-
- /* this is a rest */
- else
- pData->time += (EAS_I32) duration;
- break;
-
- case OTA_SCALE_INST_ID:
- /* fetch octave */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS)
- return result;
- pData->octave = (EAS_U8) (temp * 12 + 59);
- break;
-
- case OTA_STYLE_INST_ID:
- /* fetch note style */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS)
- return result;
- break;
-
- case OTA_TEMPO_INST_ID:
- /* fetch tempo */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS)
- return result;
- pData->tick = bpmTable[temp];
- break;
-
- case OTA_VOLUME_INST_ID:
- /* fetch volume */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS)
- return result;
- pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0;
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* decrement pattern length */
- pData->current.patternLen--;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_State()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
-{
- S_OTA_DATA* pData;
-
- /* establish pointer to instance data */
- pData = (S_OTA_DATA*) pInstData;
-
- /* if stopping, check to see if synth voices are active */
- if (pData->state == EAS_STATE_STOPPING)
- {
- if (VMActiveVoices(pData->pSynth) == 0)
- pData->state = EAS_STATE_STOPPED;
- }
-
- if (pData->state == EAS_STATE_PAUSING)
- {
- if (VMActiveVoices(pData->pSynth) == 0)
- pData->state = EAS_STATE_PAUSED;
- }
-
- /* return current state */
- *pState = pData->state;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_Close()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_OTA_DATA* pData;
- EAS_RESULT result;
-
- pData = (S_OTA_DATA*) pInstData;
-
- /* close the file */
- if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS)
- return result;
-
- /* free the synth */
- if (pData->pSynth != NULL)
- VMMIDIShutdown(pEASData, pData->pSynth);
-
- /* if using dynamic memory, free it */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pData);
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_Reset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_OTA_DATA* pData;
- EAS_RESULT result;
-
- pData = (S_OTA_DATA*) pInstData;
-
- /* reset the synth */
- VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE);
- pData->note = 0;
-
- /* reset file position and re-parse header */
- pData->state = EAS_STATE_ERROR;
- if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS)
- return result;
-
- pData->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_Pause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Pauses the sequencer. Mutes all voices and sets state to pause.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_OTA_DATA *pData;
-
- /* can't pause a stopped stream */
- pData = (S_OTA_DATA*) pInstData;
- if (pData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* mute the synthesizer */
- VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth);
- pData->state = EAS_STATE_PAUSING;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_Resume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume playing after a pause, sets state back to playing.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_OTA_DATA *pData;
-
- /* can't resume a stopped stream */
- pData = (S_OTA_DATA*) pInstData;
- if (pData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* nothing to do but resume playback */
- pData->state = EAS_STATE_PLAY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_SetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Return file type
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_OTA_DATA *pData;
-
- pData = (S_OTA_DATA *) pInstData;
- switch (param)
- {
-
- /* set metadata callback */
- case PARSER_DATA_METADATA_CB:
- EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB));
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_GetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Return file type
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
-static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_OTA_DATA *pData;
-
- pData = (S_OTA_DATA*) pInstData;
- switch (param)
- {
- /* return file type as OTA */
- case PARSER_DATA_FILE_TYPE:
- *pValue = EAS_FILE_OTA;
- break;
-
-#if 0
- /* set transposition */
- case PARSER_DATA_TRANSPOSITION:
- *pValue = pData->transposition;
- break;
-#endif
-
- case PARSER_DATA_SYNTH_HANDLE:
- *pValue = (EAS_I32) pData->pSynth;
- break;
-
- case PARSER_DATA_GAIN_OFFSET:
- *pValue = OTA_GAIN_OFFSET;
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_ParseHeader()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData)
-{
- EAS_RESULT result;
- EAS_INT i;
- EAS_INT state;
- EAS_U8 temp;
- EAS_U8 titleLen;
-
- /* initialize some data */
- pData->flags = 0;
- pData->time = 0;
- pData->tick = DEFAULT_TICK_CONV;
- pData->patterns[0].fileOffset = pData->patterns[1].fileOffset =
- pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1;
- pData->current.bitCount = 0;
- pData->current.patternLen = 0;
- pData->loopCount = 0;
- pData->restore.fileOffset = -1;
- pData->note = 0;
- pData->restTicks = 0;
- pData->velocity = OTA_VEL_DEFAULT;
- pData->style = 0;
- pData->octave = 59;
-
- /* seek to start of data */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS)
- return result;
-
- /* read the first byte, should be command length */
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS)
- return result;
-
- /* read all the commands */
- i = temp;
- state = 0;
- while (i--)
- {
-
- /* fetch command, always starts on byte boundary */
- pData->current.bitCount = 0;
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS)
- return result;
-
- if (state == 0)
- {
- if (temp != OTA_RINGTONE)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
- state++;
- }
- else
- {
-
- if (temp == OTA_SOUND)
- break;
-
- if (temp == OTA_UNICODE)
- pData->flags |= OTA_FLAGS_UNICODE;
- else
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
- }
- }
-
- /* get song type */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS)
- return result;
-
- /* check for basic song type */
- if (temp == OTA_BASIC_SONG_TYPE)
- {
- /* fetch title length */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS)
- return result;
-
- /* if unicode, double the length */
- if (pData->flags & OTA_FLAGS_UNICODE)
- titleLen = (EAS_U8) (titleLen << 1);
-
- /* zero the metadata buffer */
- if (pData->metadata.buffer)
- EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize);
-
- /* read the song title */
- for (i = 0; i < titleLen; i++)
- {
- /* fetch character */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS)
- return result;
-
- /* check for metadata callback */
- if (pData->metadata.callback)
- {
- if (i < (pData->metadata.bufferSize - 1))
- pData->metadata.buffer[i] = (char) temp;
- }
- }
-
- /* if host has registered callback, call it now */
- if (pData->metadata.callback)
- (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData);
- }
-
- /* must be temporary song */
- else if (temp != OTA_TEMPORARY_SONG_TYPE)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* get the song length */
- if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS)
- return result;
-
- /* sanity check */
- if (pData->numPatterns == 0)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* at start of first pattern */
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_FetchBitField()
- *----------------------------------------------------------------------------
- * Purpose:
- * Fetch a specified number of bits from the input stream
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue)
-{
- EAS_RESULT result;
- EAS_I32 bitsLeft;
- EAS_U8 value;
-
- value = 0;
-
- /* do we have enough bits? */
- bitsLeft = pData->current.bitCount - numBits;
-
- /* not enough bits, assemble them from 2 characters */
- if (bitsLeft < 0)
- {
- /* grab the remaining bits from the previous byte */
- if (pData->current.bitCount)
- /*lint -e{504,734} this is a legitimate shift operation */
- value = pData->current.dataByte << -bitsLeft;
-
- /* read the next byte */
- if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS)
- return result;
- bitsLeft += 8;
- }
-
- /* more bits than needed? */
- if (bitsLeft > 0)
- {
- value |= pData->current.dataByte >> bitsLeft;
- pData->current.bitCount = (EAS_U8) bitsLeft;
- pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft));
- }
-
- /* exactly the right number of bits */
- else
- {
- value |= pData->current.dataByte;
- pData->current.bitCount = 0;
- }
-
- *pValue = value;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * OTA_SavePosition()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc)
-{
- EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC));
- return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset);
-}
-
-/*----------------------------------------------------------------------------
- * OTA_RestorePosition()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc)
-{
- EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC));
- pData->restore.fileOffset = -1;
- return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset);
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_otadata.h" + +/* increase gain for mono ringtones */ +#define OTA_GAIN_OFFSET 8 + +/* file definitions */ +#define OTA_RINGTONE 0x25 +#define OTA_SOUND 0x1d +#define OTA_UNICODE 0x22 + +/* song type definitions */ +#define OTA_BASIC_SONG_TYPE 0x01 +#define OTA_TEMPORARY_SONG_TYPE 0x02 + +/* instruction ID coding */ +#define OTA_PATTERN_HEADER_ID 0x00 +#define OTA_NOTE_INST_ID 0x01 +#define OTA_SCALE_INST_ID 0x02 +#define OTA_STYLE_INST_ID 0x03 +#define OTA_TEMPO_INST_ID 0x04 +#define OTA_VOLUME_INST_ID 0x05 + +/* note durations */ +#define OTA_NORMAL_DURATION 0x00 +#define OTA_DOTTED_NOTE 0x01 +#define OTA_DOUBLE_DOTTED_NOTE 0x02 +#define OTA_TRIPLET_NOTE 0x03 + +/* loop count value for infinite loop */ +#define OTA_INFINITE_LOOP 0x0f + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 + +/* default channel and program for OTA playback */ +#define OTA_CHANNEL 0 +#define OTA_PROGRAM 80 +#define OTA_VEL_MUL 4 +#define OTA_VEL_OFS 67 +#define OTA_VEL_DEFAULT 95 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData); +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue); +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); + + +/*---------------------------------------------------------------------------- + * + * EAS_OTA_Parser + * + * This structure contains the functional interface for the OTA parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_OTA_Parser = +{ + OTA_CheckFileType, + OTA_Prepare, + OTA_Time, + OTA_Event, + OTA_State, + OTA_Close, + OTA_Reset, + OTA_Pause, + OTA_Resume, + NULL, + OTA_SetData, + OTA_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * + * bpmTable + * + * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note + *---------------------------------------------------------------------------- +*/ +static const EAS_U32 bpmTable[32] = +{ + 76800, 68571, 61935, 54857, + 48000, 42667, 38400, 34286, + 30476, 27429, 24000, 21333, + 19200, 17143, 15360, 13714, + 12000, 10667, 9600, 8533, + 7680, 6737, 6000, 5408, + 4800, 4267, 3840, 3398, + 3024, 2685, 2400, 2133 +}; + +/*---------------------------------------------------------------------------- + * OTA_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_INT cmdLen; + EAS_INT state; + EAS_U8 temp; + + /* read the first byte, should be command length */ + *ppHandle = NULL; + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + cmdLen = temp; + state = 0; + while (cmdLen--) + { + + /* read the command, upper 7 bits */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + temp = temp >> 1; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + break; + state++; + } + else + { + + if (temp == OTA_SOUND) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_OTA_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA)); + if (!pData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + break; + } + + if (temp != OTA_UNICODE) + break; + } + } + + /* not recognized */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_U32 duration; + EAS_U8 temp; + + pData = (S_OTA_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + if (parserMode != eParserModeMetaData) + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM); + + /* set channel volume to max */ + if (parserMode != eParserModeMetaData) + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += (EAS_I32) pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* if not in a pattern, read the pattern header */ + while (pData->current.patternLen == 0) + { + + /* check for loop - don't do infinite loops when locating */ + if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP))) + { + /* if not infinite loop, decrement loop count */ + if (pData->loopCount != OTA_INFINITE_LOOP) + pData->loopCount--; + + /* back to start of pattern*/ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if no previous position to restore, continue forward */ + else if (pData->restore.fileOffset < 0) + { + + /* check for end of song */ + if (pData->numPatterns == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* read the next pattern header */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + if (temp != OTA_PATTERN_HEADER_ID) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the pattern ID */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS) + return result; + + /* get the loop count */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS) + return result; + + /* get the pattern length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS) + return result; + + /* if pattern definition, save the current position */ + if (pData->current.patternLen) + { + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if pattern length is zero, repeat a previous pattern */ + else + { + /* make sure it's a valid pattern */ + if (pData->patterns[pData->currentPattern].fileOffset < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* save current position and data */ + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + + /* seek to the pattern in the file */ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* decrement pattern count */ + pData->numPatterns--; + } + + /* restore previous position */ + else + { + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + } + } + + /* get the next event */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + switch (temp) + { + case OTA_NOTE_INST_ID: + /* fetch note value */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS) + return result; + + /* fetch note duration */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + duration = pData->tick * (0x20 >> temp); + + /* fetch note duration modifier */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + switch (temp) + { + case OTA_NORMAL_DURATION: + break; + + case OTA_DOTTED_NOTE: + duration += duration >> 1; + break; + + case OTA_DOUBLE_DOTTED_NOTE: + duration += (duration >> 1) + (duration >> 2); + break; + + case OTA_TRIPLET_NOTE: + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ } + break; + } + + /* check for note */ + if (pData->note) + { + + /* determine note length based on style */ + switch (pData->style) + { + case 0: + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ } + } + + /* add octave */ + pData->note += pData->octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity); + pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks; + } + + /* this is a rest */ + else + pData->time += (EAS_I32) duration; + break; + + case OTA_SCALE_INST_ID: + /* fetch octave */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + pData->octave = (EAS_U8) (temp * 12 + 59); + break; + + case OTA_STYLE_INST_ID: + /* fetch note style */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS) + return result; + break; + + case OTA_TEMPO_INST_ID: + /* fetch tempo */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS) + return result; + pData->tick = bpmTable[temp]; + break; + + case OTA_VOLUME_INST_ID: + /* fetch volume */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS) + return result; + pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* decrement pattern length */ + pData->current.patternLen--; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_OTA_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_OTA_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + switch (param) + { + /* return file type as OTA */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_OTA; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = OTA_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData) +{ + EAS_RESULT result; + EAS_INT i; + EAS_INT state; + EAS_U8 temp; + EAS_U8 titleLen; + + /* initialize some data */ + pData->flags = 0; + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->patterns[0].fileOffset = pData->patterns[1].fileOffset = + pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1; + pData->current.bitCount = 0; + pData->current.patternLen = 0; + pData->loopCount = 0; + pData->restore.fileOffset = -1; + pData->note = 0; + pData->restTicks = 0; + pData->velocity = OTA_VEL_DEFAULT; + pData->style = 0; + pData->octave = 59; + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* read the first byte, should be command length */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + i = temp; + state = 0; + while (i--) + { + + /* fetch command, always starts on byte boundary */ + pData->current.bitCount = 0; + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS) + return result; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + state++; + } + else + { + + if (temp == OTA_SOUND) + break; + + if (temp == OTA_UNICODE) + pData->flags |= OTA_FLAGS_UNICODE; + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + } + } + + /* get song type */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + /* check for basic song type */ + if (temp == OTA_BASIC_SONG_TYPE) + { + /* fetch title length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS) + return result; + + /* if unicode, double the length */ + if (pData->flags & OTA_FLAGS_UNICODE) + titleLen = (EAS_U8) (titleLen << 1); + + /* zero the metadata buffer */ + if (pData->metadata.buffer) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the song title */ + for (i = 0; i < titleLen; i++) + { + /* fetch character */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS) + return result; + + /* check for metadata callback */ + if (pData->metadata.callback) + { + if (i < (pData->metadata.bufferSize - 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* if host has registered callback, call it now */ + if (pData->metadata.callback) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + } + + /* must be temporary song */ + else if (temp != OTA_TEMPORARY_SONG_TYPE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the song length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS) + return result; + + /* sanity check */ + if (pData->numPatterns == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* at start of first pattern */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_FetchBitField() + *---------------------------------------------------------------------------- + * Purpose: + * Fetch a specified number of bits from the input stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue) +{ + EAS_RESULT result; + EAS_I32 bitsLeft; + EAS_U8 value; + + value = 0; + + /* do we have enough bits? */ + bitsLeft = pData->current.bitCount - numBits; + + /* not enough bits, assemble them from 2 characters */ + if (bitsLeft < 0) + { + /* grab the remaining bits from the previous byte */ + if (pData->current.bitCount) + /*lint -e{504,734} this is a legitimate shift operation */ + value = pData->current.dataByte << -bitsLeft; + + /* read the next byte */ + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS) + return result; + bitsLeft += 8; + } + + /* more bits than needed? */ + if (bitsLeft > 0) + { + value |= pData->current.dataByte >> bitsLeft; + pData->current.bitCount = (EAS_U8) bitsLeft; + pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft)); + } + + /* exactly the right number of bits */ + else + { + value |= pData->current.dataByte; + pData->current.bitCount = 0; + } + + *pValue = value; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SavePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC)); + return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset); +} + +/*---------------------------------------------------------------------------- + * OTA_RestorePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC)); + pData->restore.fileOffset = -1; + return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset); +} + diff --git a/arm-fm-22k/lib_src/eas_otadata.c b/arm-fm-22k/lib_src/eas_otadata.c index 237f832..7463a0c 100644 --- a/arm-fm-22k/lib_src/eas_otadata.c +++ b/arm-fm-22k/lib_src/eas_otadata.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_otadata..c
- *
- * Contents and purpose:
- * OTA Stream Parser data module for static memory model
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata..c + * + * Contents and purpose: + * OTA Stream Parser data module for static memory model + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,23 +19,23 @@ * 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: 547 $
- * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_types.h"
-#include "eas_otadata.h"
-
-/*----------------------------------------------------------------------------
- *
- * eas_OTAData
- *
- * Static memory allocation for OTA parser
- *----------------------------------------------------------------------------
-*/
-S_OTA_DATA eas_OTAData;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_otadata.h" + +/*---------------------------------------------------------------------------- + * + * eas_OTAData + * + * Static memory allocation for OTA parser + *---------------------------------------------------------------------------- +*/ +S_OTA_DATA eas_OTAData; + diff --git a/arm-fm-22k/lib_src/eas_otadata.h b/arm-fm-22k/lib_src/eas_otadata.h index 63e963f..c06e3d3 100644 --- a/arm-fm-22k/lib_src/eas_otadata.h +++ b/arm-fm-22k/lib_src/eas_otadata.h @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_otadata.h
- *
- * Contents and purpose:
- * OTA File Parser
- *
- * This file contains data declarations for the OTA parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata.h + * + * Contents and purpose: + * OTA File Parser + * + * This file contains data declarations for the OTA parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,61 +21,61 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef EAS_OTADATA_H
-#define EAS_OTADATA_H
-
-#include "eas_data.h"
-
-/* definition for state flags */
-#define OTA_FLAGS_UNICODE 0x01 /* unicode text */
-
-/*----------------------------------------------------------------------------
- *
- * S_OTA_DATA
- *
- * This structure contains the state data for the OTA parser
- *----------------------------------------------------------------------------
-*/
-
-typedef struct
-{
- EAS_I32 fileOffset; /* offset to location in file */
- EAS_U8 patternLen; /* length of current pattern */
- EAS_U8 dataByte; /* previous char from file */
- EAS_U8 bitCount; /* bit count in char */
-} S_OTA_LOC;
-
-typedef struct
-{
- EAS_FILE_HANDLE fileHandle; /* file handle */
- S_SYNTH *pSynth; /* synth handle */
- EAS_I32 fileOffset; /* offset to start of data */
- EAS_I32 time; /* current time in 256ths of a msec */
- EAS_U32 tick; /* length of 32nd note in 256th of a msec */
- EAS_U32 restTicks; /* ticks to rest after current note */
- S_OTA_LOC patterns[4]; /* pattern locations */
- S_OTA_LOC current; /* current location */
- S_OTA_LOC restore; /* previous location */
- S_METADATA_CB metadata; /* metadata callback */
- EAS_U8 flags; /* bit flags */
- EAS_U8 numPatterns; /* number of patterns left in song */
- EAS_U8 currentPattern; /* current pattern for loop */
- EAS_U8 note; /* MIDI note number */
- EAS_U8 octave; /* octave modifier */
- EAS_U8 style; /* from STYLE */
- EAS_U8 velocity; /* current volume */
- EAS_U8 state; /* current state EAS_STATE_XXXX */
- EAS_U8 loopCount; /* loop count for pattern */
-} S_OTA_DATA;
-
-#endif
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_OTADATA_H +#define EAS_OTADATA_H + +#include "eas_data.h" + +/* definition for state flags */ +#define OTA_FLAGS_UNICODE 0x01 /* unicode text */ + +/*---------------------------------------------------------------------------- + * + * S_OTA_DATA + * + * This structure contains the state data for the OTA parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_I32 fileOffset; /* offset to location in file */ + EAS_U8 patternLen; /* length of current pattern */ + EAS_U8 dataByte; /* previous char from file */ + EAS_U8 bitCount; /* bit count in char */ +} S_OTA_LOC; + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synth handle */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_U32 tick; /* length of 32nd note in 256th of a msec */ + EAS_U32 restTicks; /* ticks to rest after current note */ + S_OTA_LOC patterns[4]; /* pattern locations */ + S_OTA_LOC current; /* current location */ + S_OTA_LOC restore; /* previous location */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_U8 flags; /* bit flags */ + EAS_U8 numPatterns; /* number of patterns left in song */ + EAS_U8 currentPattern; /* current pattern for loop */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* octave modifier */ + EAS_U8 style; /* from STYLE */ + EAS_U8 velocity; /* current volume */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 loopCount; /* loop count for pattern */ +} S_OTA_DATA; + +#endif + + diff --git a/arm-fm-22k/lib_src/eas_pan.c b/arm-fm-22k/lib_src/eas_pan.c index 373d90e..ae4c69d 100644 --- a/arm-fm-22k/lib_src/eas_pan.c +++ b/arm-fm-22k/lib_src/eas_pan.c @@ -1,16 +1,16 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_pan.c
- *
- * Contents and purpose:
- * Calculates left and right gain multipliers based on a pan value from -63 to +63
- *
- * NOTES:
- * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine
- * whether the parser works for those particular file formats.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.c + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,76 +23,76 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_pan.h"
-#include "eas_math.h"
-
-/*----------------------------------------------------------------------------
- * EAS_CalcPanControl()
- *----------------------------------------------------------------------------
- * Purpose:
- * Assign the left and right gain values corresponding to the given pan value.
- *
- * This routine uses sin/cos approximations for an equal power curve:
- *
- * sin(x) = (2-4*c)*x^2 + c + x
- * cos(x) = (2-4*c)*x^2 + c - x
- *
- * where c = 1/sqrt(2)
- * using the a0 + x*(a1 + x*a2) approach
- *
- * Inputs:
- * pan - pan value (-63 to + 63)
- *
- * Outputs:
- * pGainLeft linear gain multiplier for left channel (15-bit fraction)
- * pGainRight linear gain multiplier for left channel (15-bit fraction)
- *
- * Side Effects:
- *----------------------------------------------------------------------------
-*/
-void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight)
-{
- EAS_INT temp;
- EAS_INT netAngle;
-
- /* impose hard limit */
- if (pan < -63)
- netAngle = -63;
- else if (pan > 63)
- netAngle = 63;
- else
- netAngle = pan;
-
- /*lint -e{701} <avoid multiply for performance reasons>*/
- netAngle = netAngle << 8;
-
- /* calculate sin */
- temp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle);
- temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle);
-
- if (temp > SYNTH_FULL_SCALE_EG1_GAIN)
- temp = SYNTH_FULL_SCALE_EG1_GAIN;
- else if (temp < 0)
- temp = 0;
-
- *pGainRight = (EAS_I16) temp;
-
- /* calculate cos */
- temp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle);
- temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle);
- if (temp > SYNTH_FULL_SCALE_EG1_GAIN)
- temp = SYNTH_FULL_SCALE_EG1_GAIN;
- else if (temp < 0)
- temp = 0;
-
- *pGainLeft = (EAS_I16) temp;
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_pan.h" +#include "eas_math.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight) +{ + EAS_INT temp; + EAS_INT netAngle; + + /* impose hard limit */ + if (pan < -63) + netAngle = -63; + else if (pan > 63) + netAngle = 63; + else + netAngle = pan; + + /*lint -e{701} <avoid multiply for performance reasons>*/ + netAngle = netAngle << 8; + + /* calculate sin */ + temp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainRight = (EAS_I16) temp; + + /* calculate cos */ + temp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainLeft = (EAS_I16) temp; +} + diff --git a/arm-fm-22k/lib_src/eas_pan.h b/arm-fm-22k/lib_src/eas_pan.h index cefa650..cb0a90d 100644 --- a/arm-fm-22k/lib_src/eas_pan.h +++ b/arm-fm-22k/lib_src/eas_pan.h @@ -1,16 +1,16 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_pan.h
- *
- * Contents and purpose:
- * Calculates left and right gain multipliers based on a pan value from -63 to +63
- *
- * NOTES:
- * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine
- * whether the parser works for those particular file formats.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.h + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,44 +23,44 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef EAS_PAN_H
-#define _EAS_PAN_H
-
-#include "eas_types.h"
-
-/*----------------------------------------------------------------------------
- * EAS_CalcPanControl()
- *----------------------------------------------------------------------------
- * Purpose:
- * Assign the left and right gain values corresponding to the given pan value.
- *
- * This routine uses sin/cos approximations for an equal power curve:
- *
- * sin(x) = (2-4*c)*x^2 + c + x
- * cos(x) = (2-4*c)*x^2 + c - x
- *
- * where c = 1/sqrt(2)
- * using the a0 + x*(a1 + x*a2) approach
- *
- * Inputs:
- * pan - pan value (-63 to + 63)
- *
- * Outputs:
- * pGainLeft linear gain multiplier for left channel (15-bit fraction)
- * pGainRight linear gain multiplier for left channel (15-bit fraction)
- *
- * Side Effects:
- *----------------------------------------------------------------------------
-*/
-void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight);
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_PAN_H +#define _EAS_PAN_H + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight); + +#endif + diff --git a/arm-fm-22k/lib_src/eas_parser.h b/arm-fm-22k/lib_src/eas_parser.h index 5512c82..96ec35b 100644 --- a/arm-fm-22k/lib_src/eas_parser.h +++ b/arm-fm-22k/lib_src/eas_parser.h @@ -1,15 +1,15 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_parser.h
- *
- * Contents and purpose:
- * Interface declarations for the generic parser interface
- *
- * This header only contains declarations that are specific
- * to this implementation.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_parser.h + * + * Contents and purpose: + * Interface declarations for the generic parser interface + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,77 +22,77 @@ * 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: 767 $
- * $Date: 2007-07-19 13:47:31 -0700 (Thu, 19 Jul 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_PARSER_H
-#define _EAS_PARSER_H
-
-#include "eas_types.h"
-
-
-/* metadata callback */
-typedef struct s_metadata_cb_tag
-{
- EAS_METADATA_CBFUNC callback;
- char *buffer;
- EAS_VOID_PTR pUserData;
- EAS_I32 bufferSize;
-} S_METADATA_CB;
-
-/* generic parser interface */
-typedef struct
-{
- EAS_RESULT (* EAS_CONST pfCheckFileType)(struct s_eas_data_tag *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
- EAS_RESULT (* EAS_CONST pfPrepare)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData);
- EAS_RESULT (* EAS_CONST pfTime)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
- EAS_RESULT (* EAS_CONST pfEvent)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_INT parseMode);
- EAS_RESULT (* EAS_CONST pfState)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
- EAS_RESULT (* EAS_CONST pfClose)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData);
- EAS_RESULT (* EAS_CONST pfReset)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData);
- EAS_RESULT (* EAS_CONST pfPause)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData);
- EAS_RESULT (* EAS_CONST pfResume)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData);
- EAS_RESULT (* EAS_CONST pfLocate)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate);
- EAS_RESULT (* EAS_CONST pfSetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
- EAS_RESULT (* EAS_CONST pfGetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
- EAS_RESULT (* EAS_CONST pfGetMetaData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength);
-} S_FILE_PARSER_INTERFACE;
-
-typedef enum
-{
- eParserModePlay,
- eParserModeLocate,
- eParserModeMute,
- eParserModeMetaData
-} E_PARSE_MODE;
-
-typedef enum
-{
- PARSER_DATA_FILE_TYPE,
- PARSER_DATA_PLAYBACK_RATE,
- PARSER_DATA_TRANSPOSITION,
- PARSER_DATA_VOLUME,
- PARSER_DATA_SYNTH_HANDLE,
- PARSER_DATA_METADATA_CB,
- PARSER_DATA_DLS_COLLECTION,
- PARSER_DATA_EAS_LIBRARY,
- PARSER_DATA_POLYPHONY,
- PARSER_DATA_PRIORITY,
- PARSER_DATA_FORMAT,
- PARSER_DATA_MEDIA_LENGTH,
- PARSER_DATA_JET_CB,
- PARSER_DATA_MUTE_FLAGS,
- PARSER_DATA_SET_MUTE,
- PARSER_DATA_CLEAR_MUTE,
- PARSER_DATA_NOTE_COUNT,
- PARSER_DATA_MAX_PCM_STREAMS,
- PARSER_DATA_GAIN_OFFSET,
- PARSER_DATA_PLAY_MODE
-} E_PARSER_DATA;
-
-#endif /* #ifndef _EAS_PARSER_H */
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 767 $ + * $Date: 2007-07-19 13:47:31 -0700 (Thu, 19 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PARSER_H +#define _EAS_PARSER_H + +#include "eas_types.h" + + +/* metadata callback */ +typedef struct s_metadata_cb_tag +{ + EAS_METADATA_CBFUNC callback; + char *buffer; + EAS_VOID_PTR pUserData; + EAS_I32 bufferSize; +} S_METADATA_CB; + +/* generic parser interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfCheckFileType)(struct s_eas_data_tag *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); + EAS_RESULT (* EAS_CONST pfPrepare)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfTime)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); + EAS_RESULT (* EAS_CONST pfEvent)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_INT parseMode); + EAS_RESULT (* EAS_CONST pfState)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); + EAS_RESULT (* EAS_CONST pfClose)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfReset)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfPause)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfResume)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfLocate)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); + EAS_RESULT (* EAS_CONST pfSetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + EAS_RESULT (* EAS_CONST pfGetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (* EAS_CONST pfGetMetaData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); +} S_FILE_PARSER_INTERFACE; + +typedef enum +{ + eParserModePlay, + eParserModeLocate, + eParserModeMute, + eParserModeMetaData +} E_PARSE_MODE; + +typedef enum +{ + PARSER_DATA_FILE_TYPE, + PARSER_DATA_PLAYBACK_RATE, + PARSER_DATA_TRANSPOSITION, + PARSER_DATA_VOLUME, + PARSER_DATA_SYNTH_HANDLE, + PARSER_DATA_METADATA_CB, + PARSER_DATA_DLS_COLLECTION, + PARSER_DATA_EAS_LIBRARY, + PARSER_DATA_POLYPHONY, + PARSER_DATA_PRIORITY, + PARSER_DATA_FORMAT, + PARSER_DATA_MEDIA_LENGTH, + PARSER_DATA_JET_CB, + PARSER_DATA_MUTE_FLAGS, + PARSER_DATA_SET_MUTE, + PARSER_DATA_CLEAR_MUTE, + PARSER_DATA_NOTE_COUNT, + PARSER_DATA_MAX_PCM_STREAMS, + PARSER_DATA_GAIN_OFFSET, + PARSER_DATA_PLAY_MODE +} E_PARSER_DATA; + +#endif /* #ifndef _EAS_PARSER_H */ diff --git a/arm-fm-22k/lib_src/eas_pcm.c b/arm-fm-22k/lib_src/eas_pcm.c index 64b8f71..ff3f6f9 100644 --- a/arm-fm-22k/lib_src/eas_pcm.c +++ b/arm-fm-22k/lib_src/eas_pcm.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_pcm.c
- *
- * Contents and purpose:
- * Implements the PCM engine including ADPCM decode for SMAF and CMX audio playback.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.c + * + * Contents and purpose: + * Implements the PCM engine including ADPCM decode for SMAF and CMX audio playback. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,1464 +19,1464 @@ * 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: 849 $
- * $Date: 2007-08-28 08:59:11 -0700 (Tue, 28 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_report.h"
-#include "eas_host.h"
-#include "eas_config.h"
-#include "eas_parser.h"
-#include "eas_pcm.h"
-#include "eas_math.h"
-#include "eas_mixer.h"
-
-#define PCM_MIXER_GUARD_BITS (NUM_MIXER_GUARD_BITS + 1)
-
-/*----------------------------------------------------------------------------
- * Decoder interfaces
- *----------------------------------------------------------------------------
-*/
-
-static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
-static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time);
-
-static const S_DECODER_INTERFACE PCMDecoder =
-{
- NULL,
- LinearPCMDecode,
- LinearPCMLocate,
-};
-
-/* SMAF ADPCM decoder */
-#ifdef _SMAF_PARSER
-extern S_DECODER_INTERFACE SmafDecoder;
-#define SMAF_DECODER &SmafDecoder
-extern S_DECODER_INTERFACE Smaf7BitDecoder;
-#define SMAF_7BIT_DECODER &Smaf7BitDecoder
-#else
-#define SMAF_DECODER NULL
-#define SMAF_7BIT_DECODER NULL
-#endif
-
-/* IMA ADPCM decoder */
-#ifdef _IMA_DECODER
-extern S_DECODER_INTERFACE IMADecoder;
-#define IMA_DECODER &IMADecoder
-#else
-#define IMA_DECODER NULL
-#endif
-
-static const S_DECODER_INTERFACE * const decoders[] =
-{
- &PCMDecoder,
- SMAF_DECODER,
- IMA_DECODER,
- SMAF_7BIT_DECODER
-};
-
-/*----------------------------------------------------------------------------
- * Sample rate conversion
- *----------------------------------------------------------------------------
-*/
-
-#define SRC_RATE_MULTIPLER (0x40000000 / _OUTPUT_SAMPLE_RATE)
-
-#ifdef _LOOKUP_SAMPLE_RATE
-static const EAS_U32 srcConvRate[][2] =
-{
- 4000L, (4000L << 15) / _OUTPUT_SAMPLE_RATE,
- 8000L, (8000L << 15) / _OUTPUT_SAMPLE_RATE,
- 11025L, (11025L << 15) / _OUTPUT_SAMPLE_RATE,
- 12000L, (12000L << 15) / _OUTPUT_SAMPLE_RATE,
- 16000L, (16000L << 15) / _OUTPUT_SAMPLE_RATE,
- 22050L, (22050L << 15) / _OUTPUT_SAMPLE_RATE,
- 24000L, (24000L << 15) / _OUTPUT_SAMPLE_RATE,
- 32000L, (32000L << 15) / _OUTPUT_SAMPLE_RATE
-};
-static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate);
-#define SRC_CONV_RATE_ENTRIES (sizeof(srcConvRate)/sizeof(EAS_U32)/2)
-#endif
-
-
-/* interface prototypes */
-static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples);
-
-
-/* local prototypes */
-static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData);
-static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState);
-
-/*----------------------------------------------------------------------------
- * EAS_PEInit()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the PCM engine
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEInit (S_EAS_DATA *pEASData)
-{
- S_PCM_STATE *pState;
- EAS_INT i;
-
- /* check for static memory allocation */
- if (pEASData->staticMemoryModel)
- pEASData->pPCMStreams = EAS_CMEnumData(EAS_CM_PCM_DATA);
- /* allocate dynamic memory */
- else
- pEASData->pPCMStreams = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS);
-
- if (!pEASData->pPCMStreams)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate memory for PCM streams\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
-
- //zero the memory to insure complete initialization
- EAS_HWMemSet((void *)(pEASData->pPCMStreams),0, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS);
-
- /* initialize the state data */
- for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++)
- pState->fileHandle = NULL;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Shuts down the PCM engine
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEShutdown (S_EAS_DATA *pEASData)
-{
-
- /* free any dynamic memory */
- if (!pEASData->staticMemoryModel)
- {
- if (pEASData->pPCMStreams)
- {
- EAS_HWFree(pEASData->hwInstData, pEASData->pPCMStreams);
- pEASData->pPCMStreams = NULL;
- }
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PERender()
- *----------------------------------------------------------------------------
- * Purpose:
- * Render a buffer of PCM audio
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PERender (S_EAS_DATA* pEASData, EAS_I32 numSamples)
-{
- S_PCM_STATE *pState;
- EAS_RESULT result;
- EAS_INT i;
-
- /* render all the active streams */
- for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++)
- {
- if ((pState->fileHandle) && (pState->state != EAS_STATE_STOPPED) && (pState->state != EAS_STATE_PAUSED))
- if ((result = RenderPCMStream(pEASData, pState, numSamples)) != EAS_SUCCESS)
- return result;
- }
- return EAS_SUCCESS;
-}
-
-
-/*----------------------------------------------------------------------------
- * EAS_PEState()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes:
- * This interface is also exposed in the internal library for use by the other modules.
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEState (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pInstData, EAS_STATE *pState)
-{
- /* return current state */
- *pState = pInstData->state;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEClose()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEClose (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
-{
- EAS_RESULT result;
-
- if ((result = EAS_HWCloseFile(pEASData->hwInstData, pState->fileHandle)) != EAS_SUCCESS)
- return result;
-
- pState->fileHandle = NULL;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * PCM_Reset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEReset (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
-{
- EAS_RESULT result;
-
- /* reset file position to first byte of data in the stream */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d seeking to start of PCM file\n", result); */ }
- return result;
- }
-
- /* re-initialize stream */
- return InitPCMStream(pEASData, pState);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEOpenStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Starts up a PCM playback
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEOpenStream (S_EAS_DATA *pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle)
-{
- EAS_RESULT result;
- S_PCM_STATE *pState;
- EAS_I32 filePos;
-
- /* make sure we support this decoder */
- if (pParams->decoder >= NUM_DECODER_MODULES)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder selector out of range\n"); */ }
- return EAS_ERROR_PARAMETER_RANGE;
- }
- if (decoders[pParams->decoder] == NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder module not available\n"); */ }
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
- }
-
- /* find a slot for the new stream */
- if ((pState = FindSlot(pEASData, pParams->fileHandle, pParams->pCallbackFunc, pParams->cbInstData)) == NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to open ADPCM stream, too many streams open\n"); */ }
- return EAS_ERROR_MAX_PCM_STREAMS;
- }
-
- /* get the current file position */
- if ((result = EAS_HWFilePos(pEASData->hwInstData, pState->fileHandle, &filePos)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWFilePos returned %ld\n",result); */ }
- pState->fileHandle = NULL;
- return result;
- }
-
- pState->pDecoder = decoders[pParams->decoder];
- pState->startPos = filePos;
- pState->bytesLeftLoop = pState->byteCount = pParams->size;
- pState->loopStart = pParams->loopStart;
- pState->samplesTilLoop = (EAS_I32) pState->loopStart;
- pState->loopSamples = pParams->loopSamples;
- pState->samplesInLoop = 0;
- pState->blockSize = (EAS_U16) pParams->blockSize;
- pState->flags = pParams->flags;
- pState->envData = pParams->envData;
- pState->volume = pParams->volume;
- pState->sampleRate = (EAS_U16) pParams->sampleRate;
-
- /* set the base frequency */
- pState->basefreq = (SRC_RATE_MULTIPLER * (EAS_U32) pParams->sampleRate) >> 15;
-
- /* calculate shift for frequencies > 1.0 */
- pState->rateShift = 0;
- while (pState->basefreq > 32767)
- {
- pState->basefreq = pState->basefreq >> 1;
- pState->rateShift++;
- }
-
- /* initialize */
- if ((result = InitPCMStream(pEASData, pState)) != EAS_SUCCESS)
- return result;
-
- *pHandle = pState;
-
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PEOpenStream: StartPos=%d, byteCount = %d, loopSamples=%d\n",
- pState->startPos, pState->byteCount, pState->loopSamples); */ }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEContinueStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Continues a PCM stream
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -e{715} reserved for future use */
-EAS_RESULT EAS_PEContinueStream (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 size)
-{
-
- /* add new samples to count */
- pState->bytesLeft += size;
- if (pState->bytesLeft > 0)
- pState->flags &= ~PCM_FLAGS_EMPTY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEGetFileHandle()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the file handle of a stream
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEGetFileHandle (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_FILE_HANDLE *pFileHandle)
-{
- *pFileHandle = pState->fileHandle;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEUpdateParams()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the pitch and volume parameters for a PCM stream
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- * gainLeft - linear gain multipler in 1.15 fraction format
- * gainRight - linear gain multipler in 1.15 fraction format
- * pitch - pitch shift in cents
- * initial - initial settings, set current gain
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes
- * In mono mode, leftGain controls the output gain and rightGain is ignored
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-/*lint -esym(715, gainRight) used only in 2-channel version */
-EAS_RESULT EAS_PEUpdateParams (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight)
-{
-
- pState->gainLeft = gainLeft;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- pState->gainRight = gainRight;
-#endif
-
- pState->pitch = pitch;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PELocate()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function seeks to the requested place in the file. Accuracy
- * is dependent on the sample rate and block size.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pState - stream handle
- * time - media time in milliseconds
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PELocate (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 time)
-{
- if (pState->pDecoder->pfLocate == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- return pState->pDecoder->pfLocate(pEASData, pState, time);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEUpdateVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the volume parameters for a PCM stream
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- * gainLeft - linear gain multipler in 1.15 fraction format
- * gainRight - linear gain multipler in 1.15 fraction format
- * initial - initial settings, set current gain
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes
- * In mono mode, leftGain controls the output gain and rightGain is ignored
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEUpdateVolume (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume)
-{
- pState->volume = volume;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEUpdatePitch()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the pitch parameter for a PCM stream
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * pState - pointer to S_PCM_STATE for this stream
- * pitch - new pitch value in pitch cents
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEUpdatePitch (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch)
-{
- pState->pitch = pitch;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEPause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback
- * at the end of the next audio frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEPause (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
-{
- /* set state to stopping */
- pState->state = EAS_STATE_PAUSING;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PEResume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume rendering a PCM stream. Sets the gain target back to its
- * previous setting and restarts playback at the end of the next audio
- * frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEResume (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
-{
- /* set state to stopping */
- pState->state = EAS_STATE_PLAY;
- return EAS_SUCCESS;
-}
-
-EAS_U32 getDecayScale(EAS_U32 index)
-{
- EAS_U32 utemp;
-
- //envelope decay segment
- switch (index)
- {
- case 0: //no decay
- utemp = 512;//32768;
- break;
- case 1: //.0156 dB per update
- utemp = 511;//32709;
- break;
- case 2: //.03125
- utemp = 510;//32649;
- break;
- case 3: //.0625
- utemp = 508;//32532;
- break;
- case 4: //.125
- utemp = 505;//32298;
- break;
- case 5: //.25
- utemp = 497;//31835;
- break;
- case 6: //.5
- utemp = 483;//30929;
- break;
- case 7: //1.0
- utemp = 456;//29193;
- break;
- case 8: //2.0
- utemp = 406;//26008;
- break;
- case 9: //4.0
- utemp = 323;//20642;
- break;
- case 10: //8.0
- utemp = 203;//13004;
- break;
- case 11: //16.0
- utemp = 81;//5160;
- break;
- case 12: //32.0
- utemp = 13;//813;
- break;
- case 13: //64.0
- utemp = 0;//20;
- break;
- case 14: //128.0
- utemp = 0;
- break;
- case 15: //256.0
- default:
- utemp = 0;
- break;
- }
- //printf("getdecayscale returned %d\n",utemp);
- return utemp;
-}
-
-EAS_U32 getAttackIncrement(EAS_U32 index)
-{
- EAS_U32 utemp;
-
- //envelope decay segment
- switch (index)
- {
- case 0:
- utemp = 32;
- break;
- case 1:
- utemp = 64;
- break;
- case 2:
- utemp = 128;
- break;
- case 3:
- utemp = 256;
- break;
- case 4:
- utemp = 512;
- break;
- case 5:
- utemp = 1024;
- break;
- case 6:
- utemp = 2048;
- break;
- case 7:
- utemp = 4096;
- break;
- case 8:
- utemp = 8192;
- break;
- case 9:
- utemp = 16384;
- break;
- case 10:
- utemp = 32768;
- break;
- case 11:
- utemp = 65536;
- break;
- case 12:
- utemp = 65536;
- break;
- case 13:
- utemp = 65536;
- break;
- case 14:
- utemp = 65535;
- break;
- case 15:
- default:
- utemp = 0;
- break;
- }
- //printf("getattackincrement returned %d\n",utemp);
- return utemp;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PERelease()
- *----------------------------------------------------------------------------
- * Purpose:
- * Put the PCM stream envelope into release.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PERelease (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
-{
- EAS_U32 utemp;
-
- //printf("handling note-off part of envelope\n");
- /*if the note is not ignore release or sustained*/
- if (((pState->envData >> 24) & 0x0F)==0)
- {
- /* set envelope state to release */
- pState->envState = PCM_ENV_RELEASE;
- utemp = ((pState->envData >> 20) & 0x0F);
- pState->envScale = getDecayScale(utemp); //getReleaseScale(utemp);
- }
- else
- {
- /*else change envelope state to sustain */
- pState->envState = PCM_ENV_SUSTAIN;
- utemp = ((pState->envData >> 28) & 0x0F);
- pState->envScale = getDecayScale(utemp); //getSustainScale(utemp);
- }
- //since we are in release, don't let anything hang around too long
- //printf("checking env scale, val = %d\n",((S_PCM_STATE*) handle)->envScale);
- if (pState->envScale > 505)
- pState->envScale = 505;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * FindSlot()
- *----------------------------------------------------------------------------
- * Purpose:
- * Locates an empty stream slot and assigns the file handle
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * fileHandle - file handle
- * pCallbackFunc - function to be called back upon EAS_STATE_STOPPED
- *
- * Outputs:
- * returns handle to slot or NULL if all slots are used
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData)
-{
- EAS_INT i;
- S_PCM_STATE *pState;
-
-#ifndef NO_PCM_STEAL
- S_PCM_STATE *foundState = NULL;
- EAS_INT count = 0;
- EAS_U32 startOrder = 0xFFFFFFFF;
- S_PCM_STATE *stealState = NULL;
- EAS_U32 youngest = 0;
-
- /* find an empty slot, count total in use, and find oldest in use (lowest start order) */
- for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++)
- {
- /* if this one is available */
- if (pState->fileHandle == NULL)
- {
- foundState = pState;
- }
- /* else this one is in use, so see if it is the oldest, and count total in use */
- /* also find youngest */
- else
- {
- /*one more voice in use*/
- count++;
- /* is this the oldest? (lowest start order) */
- if ((pState->state != EAS_STATE_STOPPING) && (pState->startOrder < startOrder))
- {
- /* remember this one */
- stealState = pState;
- /* remember the oldest so far */
- startOrder = pState->startOrder;
- }
- /* is this the youngest? (highest start order) */
- if (pState->startOrder >= youngest)
- {
- youngest = pState->startOrder;
- }
- }
- }
-
- /* if there are too many voices active, stop the oldest one */
- if (count > PCM_STREAM_THRESHOLD)
- {
- //printf("stealing!!!\n");
- /* make sure we got one, although we should always have one at this point */
- if (stealState != NULL)
- {
- //flag this as stopping, so it will get shut off
- stealState->state = EAS_STATE_STOPPING;
- }
- }
-
- /* if there are no available open streams (we won't likely see this, due to stealing) */
- if (foundState == NULL)
- return NULL;
-
- /* save info */
- foundState->startOrder = youngest + 1;
- foundState->fileHandle = fileHandle;
- foundState->pCallback = pCallbackFunc;
- foundState->cbInstData = cbInstData;
- return foundState;
-#else
- /* find an empty slot*/
- for (i = 0; i < MAX_PCM_STREAMS; i++)
- {
- pState = &pEASData->pPCMStreams[i];
- if (pState->fileHandle != NULL)
- continue;
-
- pState->fileHandle = fileHandle;
- pState->pCallback = pCallbackFunc;
- pState->cbInstData = cbInstData;
- return pState;
- }
- return NULL;
-#endif
-}
-
-#ifdef _LOOKUP_SAMPLE_RATE
-/*----------------------------------------------------------------------------
- * CalcBaseFreq()
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculates the fractional phase increment for the sample rate converter
- *
- * Inputs:
- * sampleRate - sample rate in samples/sec
- *
- * Outputs:
- * Returns fractional sample rate with a 15-bit fraction
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate)
-{
- EAS_INT i;
-
- /* look up the conversion rate */
- for (i = 0; i < (EAS_INT)(SRC_CONV_RATE_ENTRIES); i ++)
- {
- if (srcConvRate[i][0] == sampleRate)
- return srcConvRate[i][1];
- }
-
- /* if not found in table, do it the long way */
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Sample rate %u not in table, calculating by division\n", sampleRate); */ }
-
- return (SRC_RATE_MULTIPLER * (EAS_U32) sampleRate) >> 15;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * InitPCMStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Start an ADPCM stream playback. Decodes the header, preps the engine.
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState)
-{
-
- /* initialize the data structure */
- pState->bytesLeft = pState->byteCount;
- pState->phase = 0;
- pState->srcByte = 0;
- pState->decoderL.acc = 0;
- pState->decoderL.output = 0;
- pState->decoderL.x0 = pState->decoderL.x1 = 0;
- pState->decoderL.step = 0;
- pState->decoderR.acc = 0;
- pState->decoderR.output = 0;
- pState->decoderR.x0 = pState->decoderR.x1 = 0;
- pState->decoderR.step = 0;
- pState->hiNibble = EAS_FALSE;
- pState->pitch = 0;
- pState->blockCount = 0;
- pState->gainLeft = PCM_DEFAULT_GAIN_SETTING;
-// pState->currentGainLeft = PCM_DEFAULT_GAIN_SETTING;
- pState->envValue = 0;
- pState->envState = PCM_ENV_START;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- pState->gainRight = PCM_DEFAULT_GAIN_SETTING;
-// pState->currentGainRight = PCM_DEFAULT_GAIN_SETTING;
-#endif
- pState->state = EAS_STATE_READY;
-
- /* initialize the decoder */
- if (pState->pDecoder->pfInit)
- return (*pState->pDecoder->pfInit)(pEASData, pState);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RenderPCMStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Decodes a buffer of ADPCM data.
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples)
-{
- EAS_RESULT result;
- EAS_U32 phaseInc;
- EAS_I32 gainLeft, gainIncLeft;
- EAS_I32 *pOut;
- EAS_I32 temp;
- EAS_U32 utemp;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- EAS_I32 gainRight, gainIncRight;
-#endif
-
-#if 0
- printf("env data: AR = %d, DR = %d, SL = %d, SR = %d, RR = %d\n",
- ((pState->envData >> 12) & 0x0F),
- ((pState->envData >> 16) & 0x0F),
- ((pState->envData >> 8) & 0x0F),
- ((pState->envData >> 28) & 0x0F),
- ((pState->envData >> 20) & 0x0F));
-#endif
-
- if (pState->envState == PCM_ENV_START)
- {
- //printf("env start\n");
- utemp = ((pState->envData >> 12) & 0x0F);
- //if fastest rate, attack is already completed
- //do the same for slowest rate, since that allows zero to be passed for default envelope
- if (utemp == 0x0F || utemp == 0x00)
- {
- //start envelope at full
- pState->envValue = (32768<<7);
- //jump right into decay
- utemp = ((pState->envData >> 16) & 0x0F);
- pState->envScale = getDecayScale(utemp);
- pState->envState = PCM_ENV_DECAY;
- pState->currentGainLeft = (EAS_I16) FMUL_15x15(pState->gainLeft, pState->volume);
- pState->currentGainRight = (EAS_I16) FMUL_15x15(pState->gainRight, pState->volume);
- }
- //else attack has a ramp
- else
- {
- //start the envelope very low
- pState->envValue = (2<<7);
- pState->currentGainLeft = 0;
- pState->currentGainRight = 0;
- //get envelope attack scaling value
- pState->envScale = getAttackIncrement(utemp);
- //go to attack state
- pState->envState = PCM_ENV_ATTACK;
- }
- }
- if (pState->envState == PCM_ENV_ATTACK)
- {
- //printf("env attack, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
- //update envelope value
- pState->envValue = pState->envValue + (pState->envScale << 7);
- //check envelope level and update state if needed
- if (pState->envValue >= (32768<<7))
- {
- pState->envValue = (32768<<7);
- utemp = ((pState->envData >> 16) & 0x0F);
- pState->envScale = getDecayScale(utemp);
- pState->envState = PCM_ENV_DECAY;
- }
- }
- else if (pState->envState == PCM_ENV_DECAY)
- {
- //printf("env decay, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
- //update envelope value
- pState->envValue = (pState->envValue * pState->envScale)>>9;
- //check envelope level against sustain level and update state if needed
- utemp = ((pState->envData >> 8) & 0x0F);
- if (utemp == (EAS_U32)0x0F)
- utemp = (2<<7);
- else
- {
- utemp = ((32769<<7) >> (utemp>>1));
- }
- if (pState->envValue <= utemp)
- {
- utemp = ((pState->envData >> 28) & 0x0F);
- pState->envScale = getDecayScale(utemp); //getSustainScale(utemp);
- pState->envState = PCM_ENV_SUSTAIN;
- }
- }
- else if (pState->envState == PCM_ENV_SUSTAIN)
- {
- //printf("env sustain, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
- //update envelope value
- pState->envValue = (pState->envValue * pState->envScale)>>9;
- //check envelope level against bottom level and update state if needed
- if (pState->envValue <= (2<<7))
- {
- //no more decay
- pState->envScale = 512;
- pState->envState = PCM_ENV_END;
- }
- }
- else if (pState->envState == PCM_ENV_RELEASE)
- {
- //printf("env release, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
- //update envelope value
- pState->envValue = (pState->envValue * pState->envScale)>>9;
- //check envelope level against bottom level and update state if needed
- if (pState->envValue <= (2<<7))
- {
- //no more decay
- pState->envScale = 512;
- pState->envState = PCM_ENV_END;
- }
- }
- else if (pState->envState == PCM_ENV_END)
- {
- //printf("env end\n");
- /* set state to stopping, already ramped down */
- pState->state = EAS_STATE_STOPPING;
- }
-
- //pState->gainLeft = (EAS_U16)((pState->gainLeft * (pState->envValue>>7))>>15);
- //pState->gainRight = (EAS_U16)((pState->gainRight * (pState->envValue>>7))>>15);
-
- /* gain to 32-bits to increase resolution on anti-zipper filter */
- /*lint -e{703} use shift for performance */
- gainLeft = (EAS_I32) pState->currentGainLeft << SYNTH_UPDATE_PERIOD_IN_BITS;
-#if (NUM_OUTPUT_CHANNELS == 2)
- /*lint -e{703} use shift for performance */
- gainRight = (EAS_I32) pState->currentGainRight << SYNTH_UPDATE_PERIOD_IN_BITS;
-#endif
-
- /* calculate a new gain increment, gain target is zero if pausing */
- if ((pState->state == EAS_STATE_PAUSING) || (pState->state == EAS_STATE_PAUSED))
- {
- gainIncLeft = -pState->currentGainLeft;
-#if (NUM_OUTPUT_CHANNELS == 2)
- gainIncRight= -pState->currentGainRight;
-#endif
- }
- else
- {
- EAS_I32 gain = FMUL_15x15(pState->envValue >> 7, pState->volume);
- gainIncLeft = FMUL_15x15(pState->gainLeft, gain) - pState->currentGainLeft;
-#if (NUM_OUTPUT_CHANNELS == 2)
- gainIncRight = FMUL_15x15(pState->gainRight, gain) - pState->currentGainRight;
-#endif
- }
-
- /* calculate phase increment */
- phaseInc = pState->basefreq;
-
- /* convert pitch cents to linear multiplier */
- if (pState->pitch)
- {
- temp = EAS_Calculate2toX(pState->pitch);
- phaseInc = FMUL_15x15(phaseInc, temp);
- }
- phaseInc = phaseInc << pState->rateShift;
-
- /* pointer to mix buffer */
- pOut = pEASData->pMixBuffer;
-
- /* render a buffer of samples */
- while (numSamples--)
- {
-
- /* interpolate an output sample */
- pState->decoderL.output = pState->decoderL.x0 + FMUL_15x15((pState->decoderL.x1 - pState->decoderL.x0), pState->phase & PHASE_FRAC_MASK);
-
- /* stereo output */
-#if (NUM_OUTPUT_CHANNELS == 2)
-
- /* stereo stream? */
- if (pState->flags & PCM_FLAGS_STEREO)
- pState->decoderR.output = pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK);
-
- /* gain scale and mix */
- /*lint -e{704} use shift instead of division */
- *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
- gainLeft += gainIncLeft;
-
- /*lint -e{704} use shift instead of division */
- if (pState->flags & PCM_FLAGS_STEREO)
- *pOut++ += (pState->decoderR.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
- else
- *pOut++ += (pState->decoderL.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
-
- gainRight += gainIncRight;
-
- /* mono output */
-#else
- /* if stereo stream, decode right channel and mix to mono */
- if (pState->flags & PCM_FLAGS_STEREO)
- {
- pState->decoderR.output= pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK);
-
- /* for mono, sum stereo ADPCM to mono */
- /*lint -e{704} use shift instead of division */
- *pOut++ += ((pState->decoderL.output + pState->decoderR.output) * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
- }
- else
- /*lint -e{704} use shift instead of division */
- *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
-
- gainLeft += gainIncLeft;
-#endif
-
- /* advance phase accumulator */
- pState->phase += phaseInc;
-
- /* if integer part of phase accumulator is non-zero, advance to next sample */
- while (pState->phase & ~PHASE_FRAC_MASK)
- {
- pState->decoderL.x0 = pState->decoderL.x1;
- pState->decoderR.x0 = pState->decoderR.x1;
-
- /* give the source a chance to continue the stream */
- if (!pState->bytesLeft && pState->pCallback && ((pState->flags & PCM_FLAGS_EMPTY) == 0))
- {
- pState->flags |= PCM_FLAGS_EMPTY;
- (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY);
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "RenderPCMStream: After empty callback, bytesLeft = %d\n", pState->bytesLeft); */ }
- }
-
- /* decode the next sample */
- if ((result = (*pState->pDecoder->pfDecodeSample)(pEASData, pState)) != EAS_SUCCESS)
- return result;
-
- /* adjust phase by one sample */
- pState->phase -= (1L << NUM_PHASE_FRAC_BITS);
- }
-
- }
-
- /* save new gain */
- /*lint -e{704} use shift instead of division */
- pState->currentGainLeft = (EAS_I16) (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS);
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- /*lint -e{704} use shift instead of division */
- pState->currentGainRight = (EAS_I16) (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS);
-#endif
-
- /* if pausing, set new state and notify */
- if (pState->state == EAS_STATE_PAUSING)
- {
- pState->state = EAS_STATE_PAUSED;
- if (pState->pCallback)
- (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state);
- }
-
- /* if out of data, set stopped state and notify */
- if (pState->bytesLeft == 0 || pState->state == EAS_STATE_STOPPING)
- {
- pState->state = EAS_STATE_STOPPED;
-
- /* do callback unless the file has already been closed */
- if (pState->pCallback && pState->fileHandle)
- (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state);
- }
-
- if (pState->state == EAS_STATE_READY)
- pState->state = EAS_STATE_PLAY;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * LinearPCMDecode()
- *----------------------------------------------------------------------------
- * Purpose:
- * Decodes a PCM sample
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState)
-{
- EAS_RESULT result;
- EAS_HW_DATA_HANDLE hwInstData;
-
- hwInstData = ((S_EAS_DATA*) pEASData)->hwInstData;
-
- /* if out of data, check for loop */
- if ((pState->bytesLeft == 0) && (pState->loopSamples != 0))
- {
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS)
- return result;
- pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop;
- pState->flags &= ~PCM_FLAGS_EMPTY;
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "LinearPCMDecode: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ }
- }
-
- if (pState->bytesLeft)
- {
-
- /* check format byte for 8-bit samples */
- if (pState->flags & PCM_FLAGS_8_BIT)
- {
- /* fetch left or mono sample */
- if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS)
- return result;
-
- /* if unsigned */
- if (pState->flags & PCM_FLAGS_UNSIGNED)
- {
- /*lint -e{734} converting unsigned 8-bit to signed 16-bit */
- pState->decoderL.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000);
- }
- else
- {
- /*lint -e{734} converting signed 8-bit to signed 16-bit */
- pState->decoderL.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8);
- }
- pState->bytesLeft--;
-
- /* fetch right sample */
- if(pState->flags & PCM_FLAGS_STEREO)
- {
- if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS)
- return result;
-
- /* if unsigned */
- if (pState->flags & PCM_FLAGS_UNSIGNED)
- {
- /*lint -e{734} converting unsigned 8-bit to signed 16-bit */
- pState->decoderR.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000);
- }
- else
- {
- /*lint -e{734} converting signed 8-bit to signed 16-bit */
- pState->decoderR.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8);
- }
- pState->bytesLeft--;
- }
- }
-
- /* must be 16-bit samples */
- else
- {
- //unsigned 16 bit currently not supported
- if (pState->flags & PCM_FLAGS_UNSIGNED)
- {
- return EAS_ERROR_INVALID_PCM_TYPE;
- }
-
- /* fetch left or mono sample */
- if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderL.x1, EAS_FALSE)) != EAS_SUCCESS)
- return result;
- pState->bytesLeft -= 2;
-
- /* fetch right sample */
- if(pState->flags & PCM_FLAGS_STEREO)
- {
- if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderR.x1, EAS_FALSE)) != EAS_SUCCESS)
- return result;
- pState->bytesLeft -= 2;
- }
- }
- }
-
- /* no more data, force zero samples */
- else
- pState->decoderL.x1 = pState->decoderR.x1 = 0;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * LinearPCMLocate()
- *----------------------------------------------------------------------------
- * Purpose:
- * Locate in a linear PCM stream
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time)
-{
- EAS_RESULT result;
- EAS_I32 temp;
- EAS_I32 secs, msecs;
- EAS_INT shift;
-
- /* calculate size of sample frame */
- if (pState->flags & PCM_FLAGS_8_BIT)
- shift = 0;
- else
- shift = 1;
- if (pState->flags & PCM_FLAGS_STEREO)
- shift++;
-
- /* break down into secs and msecs */
- secs = time / 1000;
- msecs = time - (secs * 1000);
-
- /* calculate sample number fraction from msecs */
- temp = (msecs * pState->sampleRate);
- temp = (temp >> 10) + ((temp * 49) >> 21);
-
- /* add integer sample count */
- temp += secs * pState->sampleRate;
-
- /* calculate the position based on sample frame size */
- /*lint -e{703} use shift for performance */
- temp <<= shift;
-
- /* past end of sample? */
- if (temp > (EAS_I32) pState->loopStart)
- {
- /* if not looped, flag error */
- if (pState->loopSamples == 0)
- {
- pState->bytesLeft = 0;
- pState->flags |= PCM_FLAGS_EMPTY;
- return EAS_ERROR_LOCATE_BEYOND_END;
- }
-
- /* looped sample - calculate position in loop */
- while (temp > (EAS_I32) pState->loopStart)
- temp -= (EAS_I32) pState->loopStart;
- }
-
- /* seek to new position */
- if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS)
- return result;
-
- /* reset state */
- if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED))
- pState->state = EAS_STATE_READY;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_PESeek
- *----------------------------------------------------------------------------
- * Purpose:
- * Locate to a particular byte in a PCM stream
- *----------------------------------------------------------------------------
- * This bit is tricky because the chunks may not be contiguous,
- * so we have to rely on the parser to position in the file. We
- * do this by seeking to the end of each chunk and simulating an
- * empty buffer condition until we get to where we want to go.
- *
- * A better solution would be a parser API for re-positioning,
- * but there isn't time at the moment to re-factor all the
- * parsers to support a new API.
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PESeek (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation)
-{
- EAS_RESULT result;
-
- /* seek to start of audio */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS)
- {
- pState->state = EAS_STATE_ERROR;
- return result;
- }
- pState->bytesLeft = pState->bytesLeftLoop;
-
- /* skip through chunks until we find the right chunk */
- while (*pLocation > (EAS_I32) pState->bytesLeft)
- {
- /* seek to end of audio chunk */
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", pState->bytesLeft); */ }
- if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, pState->bytesLeft)) != EAS_SUCCESS)
- {
- pState->state = EAS_STATE_ERROR;
- return result;
- }
- *pLocation -= pState->bytesLeft;
- pState->bytesLeft = 0;
- pState->flags |= PCM_FLAGS_EMPTY;
-
- /* retrieve more data */
- if (pState->pCallback)
- (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY);
-
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: bytesLeft=%d, byte location = %d\n", pState->bytesLeft, *pLocation); */ }
-
- /* no more samples */
- if (pState->bytesLeft == 0)
- return EAS_ERROR_LOCATE_BEYOND_END;
- }
-
- /* seek to new offset in current chunk */
- if (*pLocation > 0)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", *pLocation); */ }
- if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, *pLocation)) != EAS_SUCCESS)
- {
- pState->state = EAS_STATE_ERROR;
- return result;
- }
-
- /* if not streamed, calculate number of bytes left */
- if (pState->flags & PCM_FLAGS_STREAMING)
- pState->bytesLeft = 0x7fffffff;
- else
- pState->bytesLeft -= *pLocation;
- }
- return EAS_SUCCESS;
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 849 $ + * $Date: 2007-08-28 08:59:11 -0700 (Tue, 28 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_mixer.h" + +#define PCM_MIXER_GUARD_BITS (NUM_MIXER_GUARD_BITS + 1) + +/*---------------------------------------------------------------------------- + * Decoder interfaces + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +static const S_DECODER_INTERFACE PCMDecoder = +{ + NULL, + LinearPCMDecode, + LinearPCMLocate, +}; + +/* SMAF ADPCM decoder */ +#ifdef _SMAF_PARSER +extern S_DECODER_INTERFACE SmafDecoder; +#define SMAF_DECODER &SmafDecoder +extern S_DECODER_INTERFACE Smaf7BitDecoder; +#define SMAF_7BIT_DECODER &Smaf7BitDecoder +#else +#define SMAF_DECODER NULL +#define SMAF_7BIT_DECODER NULL +#endif + +/* IMA ADPCM decoder */ +#ifdef _IMA_DECODER +extern S_DECODER_INTERFACE IMADecoder; +#define IMA_DECODER &IMADecoder +#else +#define IMA_DECODER NULL +#endif + +static const S_DECODER_INTERFACE * const decoders[] = +{ + &PCMDecoder, + SMAF_DECODER, + IMA_DECODER, + SMAF_7BIT_DECODER +}; + +/*---------------------------------------------------------------------------- + * Sample rate conversion + *---------------------------------------------------------------------------- +*/ + +#define SRC_RATE_MULTIPLER (0x40000000 / _OUTPUT_SAMPLE_RATE) + +#ifdef _LOOKUP_SAMPLE_RATE +static const EAS_U32 srcConvRate[][2] = +{ + 4000L, (4000L << 15) / _OUTPUT_SAMPLE_RATE, + 8000L, (8000L << 15) / _OUTPUT_SAMPLE_RATE, + 11025L, (11025L << 15) / _OUTPUT_SAMPLE_RATE, + 12000L, (12000L << 15) / _OUTPUT_SAMPLE_RATE, + 16000L, (16000L << 15) / _OUTPUT_SAMPLE_RATE, + 22050L, (22050L << 15) / _OUTPUT_SAMPLE_RATE, + 24000L, (24000L << 15) / _OUTPUT_SAMPLE_RATE, + 32000L, (32000L << 15) / _OUTPUT_SAMPLE_RATE +}; +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate); +#define SRC_CONV_RATE_ENTRIES (sizeof(srcConvRate)/sizeof(EAS_U32)/2) +#endif + + +/* interface prototypes */ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples); + + +/* local prototypes */ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData); +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (S_EAS_DATA *pEASData) +{ + S_PCM_STATE *pState; + EAS_INT i; + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pEASData->pPCMStreams = EAS_CMEnumData(EAS_CM_PCM_DATA); + /* allocate dynamic memory */ + else + pEASData->pPCMStreams = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + if (!pEASData->pPCMStreams) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate memory for PCM streams\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + //zero the memory to insure complete initialization + EAS_HWMemSet((void *)(pEASData->pPCMStreams),0, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + /* initialize the state data */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + pState->fileHandle = NULL; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (S_EAS_DATA *pEASData) +{ + + /* free any dynamic memory */ + if (!pEASData->staticMemoryModel) + { + if (pEASData->pPCMStreams) + { + EAS_HWFree(pEASData->hwInstData, pEASData->pPCMStreams); + pEASData->pPCMStreams = NULL; + } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (S_EAS_DATA* pEASData, EAS_I32 numSamples) +{ + S_PCM_STATE *pState; + EAS_RESULT result; + EAS_INT i; + + /* render all the active streams */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + if ((pState->fileHandle) && (pState->state != EAS_STATE_STOPPED) && (pState->state != EAS_STATE_PAUSED)) + if ((result = RenderPCMStream(pEASData, pState, numSamples)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEState (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pInstData, EAS_STATE *pState) +{ + /* return current state */ + *pState = pInstData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pState->fileHandle)) != EAS_SUCCESS) + return result; + + pState->fileHandle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * PCM_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + /* reset file position to first byte of data in the stream */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d seeking to start of PCM file\n", result); */ } + return result; + } + + /* re-initialize stream */ + return InitPCMStream(pEASData, pState); +} + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (S_EAS_DATA *pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle) +{ + EAS_RESULT result; + S_PCM_STATE *pState; + EAS_I32 filePos; + + /* make sure we support this decoder */ + if (pParams->decoder >= NUM_DECODER_MODULES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder selector out of range\n"); */ } + return EAS_ERROR_PARAMETER_RANGE; + } + if (decoders[pParams->decoder] == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder module not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* find a slot for the new stream */ + if ((pState = FindSlot(pEASData, pParams->fileHandle, pParams->pCallbackFunc, pParams->cbInstData)) == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to open ADPCM stream, too many streams open\n"); */ } + return EAS_ERROR_MAX_PCM_STREAMS; + } + + /* get the current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pState->fileHandle, &filePos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWFilePos returned %ld\n",result); */ } + pState->fileHandle = NULL; + return result; + } + + pState->pDecoder = decoders[pParams->decoder]; + pState->startPos = filePos; + pState->bytesLeftLoop = pState->byteCount = pParams->size; + pState->loopStart = pParams->loopStart; + pState->samplesTilLoop = (EAS_I32) pState->loopStart; + pState->loopSamples = pParams->loopSamples; + pState->samplesInLoop = 0; + pState->blockSize = (EAS_U16) pParams->blockSize; + pState->flags = pParams->flags; + pState->envData = pParams->envData; + pState->volume = pParams->volume; + pState->sampleRate = (EAS_U16) pParams->sampleRate; + + /* set the base frequency */ + pState->basefreq = (SRC_RATE_MULTIPLER * (EAS_U32) pParams->sampleRate) >> 15; + + /* calculate shift for frequencies > 1.0 */ + pState->rateShift = 0; + while (pState->basefreq > 32767) + { + pState->basefreq = pState->basefreq >> 1; + pState->rateShift++; + } + + /* initialize */ + if ((result = InitPCMStream(pEASData, pState)) != EAS_SUCCESS) + return result; + + *pHandle = pState; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PEOpenStream: StartPos=%d, byteCount = %d, loopSamples=%d\n", + pState->startPos, pState->byteCount, pState->loopSamples); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{715} reserved for future use */ +EAS_RESULT EAS_PEContinueStream (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 size) +{ + + /* add new samples to count */ + pState->bytesLeft += size; + if (pState->bytesLeft > 0) + pState->flags &= ~PCM_FLAGS_EMPTY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEGetFileHandle (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_FILE_HANDLE *pFileHandle) +{ + *pFileHandle = pState->fileHandle; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * pitch - pitch shift in cents + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +/*lint -esym(715, gainRight) used only in 2-channel version */ +EAS_RESULT EAS_PEUpdateParams (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight) +{ + + pState->gainLeft = gainLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = gainRight; +#endif + + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 time) +{ + if (pState->pDecoder->pfLocate == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + return pState->pDecoder->pfLocate(pEASData, pState, time); +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume) +{ + pState->volume = volume; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch) +{ + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEPause (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEResume (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +EAS_U32 getDecayScale(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: //no decay + utemp = 512;//32768; + break; + case 1: //.0156 dB per update + utemp = 511;//32709; + break; + case 2: //.03125 + utemp = 510;//32649; + break; + case 3: //.0625 + utemp = 508;//32532; + break; + case 4: //.125 + utemp = 505;//32298; + break; + case 5: //.25 + utemp = 497;//31835; + break; + case 6: //.5 + utemp = 483;//30929; + break; + case 7: //1.0 + utemp = 456;//29193; + break; + case 8: //2.0 + utemp = 406;//26008; + break; + case 9: //4.0 + utemp = 323;//20642; + break; + case 10: //8.0 + utemp = 203;//13004; + break; + case 11: //16.0 + utemp = 81;//5160; + break; + case 12: //32.0 + utemp = 13;//813; + break; + case 13: //64.0 + utemp = 0;//20; + break; + case 14: //128.0 + utemp = 0; + break; + case 15: //256.0 + default: + utemp = 0; + break; + } + //printf("getdecayscale returned %d\n",utemp); + return utemp; +} + +EAS_U32 getAttackIncrement(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: + utemp = 32; + break; + case 1: + utemp = 64; + break; + case 2: + utemp = 128; + break; + case 3: + utemp = 256; + break; + case 4: + utemp = 512; + break; + case 5: + utemp = 1024; + break; + case 6: + utemp = 2048; + break; + case 7: + utemp = 4096; + break; + case 8: + utemp = 8192; + break; + case 9: + utemp = 16384; + break; + case 10: + utemp = 32768; + break; + case 11: + utemp = 65536; + break; + case 12: + utemp = 65536; + break; + case 13: + utemp = 65536; + break; + case 14: + utemp = 65535; + break; + case 15: + default: + utemp = 0; + break; + } + //printf("getattackincrement returned %d\n",utemp); + return utemp; +} + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PERelease (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_U32 utemp; + + //printf("handling note-off part of envelope\n"); + /*if the note is not ignore release or sustained*/ + if (((pState->envData >> 24) & 0x0F)==0) + { + /* set envelope state to release */ + pState->envState = PCM_ENV_RELEASE; + utemp = ((pState->envData >> 20) & 0x0F); + pState->envScale = getDecayScale(utemp); //getReleaseScale(utemp); + } + else + { + /*else change envelope state to sustain */ + pState->envState = PCM_ENV_SUSTAIN; + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + } + //since we are in release, don't let anything hang around too long + //printf("checking env scale, val = %d\n",((S_PCM_STATE*) handle)->envScale); + if (pState->envScale > 505) + pState->envScale = 505; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * FindSlot() + *---------------------------------------------------------------------------- + * Purpose: + * Locates an empty stream slot and assigns the file handle + * + * Inputs: + * pEASData - pointer to EAS library instance data + * fileHandle - file handle + * pCallbackFunc - function to be called back upon EAS_STATE_STOPPED + * + * Outputs: + * returns handle to slot or NULL if all slots are used + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData) +{ + EAS_INT i; + S_PCM_STATE *pState; + +#ifndef NO_PCM_STEAL + S_PCM_STATE *foundState = NULL; + EAS_INT count = 0; + EAS_U32 startOrder = 0xFFFFFFFF; + S_PCM_STATE *stealState = NULL; + EAS_U32 youngest = 0; + + /* find an empty slot, count total in use, and find oldest in use (lowest start order) */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + /* if this one is available */ + if (pState->fileHandle == NULL) + { + foundState = pState; + } + /* else this one is in use, so see if it is the oldest, and count total in use */ + /* also find youngest */ + else + { + /*one more voice in use*/ + count++; + /* is this the oldest? (lowest start order) */ + if ((pState->state != EAS_STATE_STOPPING) && (pState->startOrder < startOrder)) + { + /* remember this one */ + stealState = pState; + /* remember the oldest so far */ + startOrder = pState->startOrder; + } + /* is this the youngest? (highest start order) */ + if (pState->startOrder >= youngest) + { + youngest = pState->startOrder; + } + } + } + + /* if there are too many voices active, stop the oldest one */ + if (count > PCM_STREAM_THRESHOLD) + { + //printf("stealing!!!\n"); + /* make sure we got one, although we should always have one at this point */ + if (stealState != NULL) + { + //flag this as stopping, so it will get shut off + stealState->state = EAS_STATE_STOPPING; + } + } + + /* if there are no available open streams (we won't likely see this, due to stealing) */ + if (foundState == NULL) + return NULL; + + /* save info */ + foundState->startOrder = youngest + 1; + foundState->fileHandle = fileHandle; + foundState->pCallback = pCallbackFunc; + foundState->cbInstData = cbInstData; + return foundState; +#else + /* find an empty slot*/ + for (i = 0; i < MAX_PCM_STREAMS; i++) + { + pState = &pEASData->pPCMStreams[i]; + if (pState->fileHandle != NULL) + continue; + + pState->fileHandle = fileHandle; + pState->pCallback = pCallbackFunc; + pState->cbInstData = cbInstData; + return pState; + } + return NULL; +#endif +} + +#ifdef _LOOKUP_SAMPLE_RATE +/*---------------------------------------------------------------------------- + * CalcBaseFreq() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the fractional phase increment for the sample rate converter + * + * Inputs: + * sampleRate - sample rate in samples/sec + * + * Outputs: + * Returns fractional sample rate with a 15-bit fraction + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate) +{ + EAS_INT i; + + /* look up the conversion rate */ + for (i = 0; i < (EAS_INT)(SRC_CONV_RATE_ENTRIES); i ++) + { + if (srcConvRate[i][0] == sampleRate) + return srcConvRate[i][1]; + } + + /* if not found in table, do it the long way */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Sample rate %u not in table, calculating by division\n", sampleRate); */ } + + return (SRC_RATE_MULTIPLER * (EAS_U32) sampleRate) >> 15; +} +#endif + +/*---------------------------------------------------------------------------- + * InitPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Start an ADPCM stream playback. Decodes the header, preps the engine. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState) +{ + + /* initialize the data structure */ + pState->bytesLeft = pState->byteCount; + pState->phase = 0; + pState->srcByte = 0; + pState->decoderL.acc = 0; + pState->decoderL.output = 0; + pState->decoderL.x0 = pState->decoderL.x1 = 0; + pState->decoderL.step = 0; + pState->decoderR.acc = 0; + pState->decoderR.output = 0; + pState->decoderR.x0 = pState->decoderR.x1 = 0; + pState->decoderR.step = 0; + pState->hiNibble = EAS_FALSE; + pState->pitch = 0; + pState->blockCount = 0; + pState->gainLeft = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainLeft = PCM_DEFAULT_GAIN_SETTING; + pState->envValue = 0; + pState->envState = PCM_ENV_START; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainRight = PCM_DEFAULT_GAIN_SETTING; +#endif + pState->state = EAS_STATE_READY; + + /* initialize the decoder */ + if (pState->pDecoder->pfInit) + return (*pState->pDecoder->pfInit)(pEASData, pState); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RenderPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a buffer of ADPCM data. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples) +{ + EAS_RESULT result; + EAS_U32 phaseInc; + EAS_I32 gainLeft, gainIncLeft; + EAS_I32 *pOut; + EAS_I32 temp; + EAS_U32 utemp; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + +#if 0 + printf("env data: AR = %d, DR = %d, SL = %d, SR = %d, RR = %d\n", + ((pState->envData >> 12) & 0x0F), + ((pState->envData >> 16) & 0x0F), + ((pState->envData >> 8) & 0x0F), + ((pState->envData >> 28) & 0x0F), + ((pState->envData >> 20) & 0x0F)); +#endif + + if (pState->envState == PCM_ENV_START) + { + //printf("env start\n"); + utemp = ((pState->envData >> 12) & 0x0F); + //if fastest rate, attack is already completed + //do the same for slowest rate, since that allows zero to be passed for default envelope + if (utemp == 0x0F || utemp == 0x00) + { + //start envelope at full + pState->envValue = (32768<<7); + //jump right into decay + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + pState->currentGainLeft = (EAS_I16) FMUL_15x15(pState->gainLeft, pState->volume); + pState->currentGainRight = (EAS_I16) FMUL_15x15(pState->gainRight, pState->volume); + } + //else attack has a ramp + else + { + //start the envelope very low + pState->envValue = (2<<7); + pState->currentGainLeft = 0; + pState->currentGainRight = 0; + //get envelope attack scaling value + pState->envScale = getAttackIncrement(utemp); + //go to attack state + pState->envState = PCM_ENV_ATTACK; + } + } + if (pState->envState == PCM_ENV_ATTACK) + { + //printf("env attack, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = pState->envValue + (pState->envScale << 7); + //check envelope level and update state if needed + if (pState->envValue >= (32768<<7)) + { + pState->envValue = (32768<<7); + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + } + } + else if (pState->envState == PCM_ENV_DECAY) + { + //printf("env decay, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against sustain level and update state if needed + utemp = ((pState->envData >> 8) & 0x0F); + if (utemp == (EAS_U32)0x0F) + utemp = (2<<7); + else + { + utemp = ((32769<<7) >> (utemp>>1)); + } + if (pState->envValue <= utemp) + { + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + pState->envState = PCM_ENV_SUSTAIN; + } + } + else if (pState->envState == PCM_ENV_SUSTAIN) + { + //printf("env sustain, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_RELEASE) + { + //printf("env release, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_END) + { + //printf("env end\n"); + /* set state to stopping, already ramped down */ + pState->state = EAS_STATE_STOPPING; + } + + //pState->gainLeft = (EAS_U16)((pState->gainLeft * (pState->envValue>>7))>>15); + //pState->gainRight = (EAS_U16)((pState->gainRight * (pState->envValue>>7))>>15); + + /* gain to 32-bits to increase resolution on anti-zipper filter */ + /*lint -e{703} use shift for performance */ + gainLeft = (EAS_I32) pState->currentGainLeft << SYNTH_UPDATE_PERIOD_IN_BITS; +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{703} use shift for performance */ + gainRight = (EAS_I32) pState->currentGainRight << SYNTH_UPDATE_PERIOD_IN_BITS; +#endif + + /* calculate a new gain increment, gain target is zero if pausing */ + if ((pState->state == EAS_STATE_PAUSING) || (pState->state == EAS_STATE_PAUSED)) + { + gainIncLeft = -pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight= -pState->currentGainRight; +#endif + } + else + { + EAS_I32 gain = FMUL_15x15(pState->envValue >> 7, pState->volume); + gainIncLeft = FMUL_15x15(pState->gainLeft, gain) - pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight = FMUL_15x15(pState->gainRight, gain) - pState->currentGainRight; +#endif + } + + /* calculate phase increment */ + phaseInc = pState->basefreq; + + /* convert pitch cents to linear multiplier */ + if (pState->pitch) + { + temp = EAS_Calculate2toX(pState->pitch); + phaseInc = FMUL_15x15(phaseInc, temp); + } + phaseInc = phaseInc << pState->rateShift; + + /* pointer to mix buffer */ + pOut = pEASData->pMixBuffer; + + /* render a buffer of samples */ + while (numSamples--) + { + + /* interpolate an output sample */ + pState->decoderL.output = pState->decoderL.x0 + FMUL_15x15((pState->decoderL.x1 - pState->decoderL.x0), pState->phase & PHASE_FRAC_MASK); + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + + /* stereo stream? */ + if (pState->flags & PCM_FLAGS_STEREO) + pState->decoderR.output = pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* gain scale and mix */ + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + gainLeft += gainIncLeft; + + /*lint -e{704} use shift instead of division */ + if (pState->flags & PCM_FLAGS_STEREO) + *pOut++ += (pState->decoderR.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + else + *pOut++ += (pState->decoderL.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainRight += gainIncRight; + + /* mono output */ +#else + /* if stereo stream, decode right channel and mix to mono */ + if (pState->flags & PCM_FLAGS_STEREO) + { + pState->decoderR.output= pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* for mono, sum stereo ADPCM to mono */ + /*lint -e{704} use shift instead of division */ + *pOut++ += ((pState->decoderL.output + pState->decoderR.output) * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + } + else + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainLeft += gainIncLeft; +#endif + + /* advance phase accumulator */ + pState->phase += phaseInc; + + /* if integer part of phase accumulator is non-zero, advance to next sample */ + while (pState->phase & ~PHASE_FRAC_MASK) + { + pState->decoderL.x0 = pState->decoderL.x1; + pState->decoderR.x0 = pState->decoderR.x1; + + /* give the source a chance to continue the stream */ + if (!pState->bytesLeft && pState->pCallback && ((pState->flags & PCM_FLAGS_EMPTY) == 0)) + { + pState->flags |= PCM_FLAGS_EMPTY; + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "RenderPCMStream: After empty callback, bytesLeft = %d\n", pState->bytesLeft); */ } + } + + /* decode the next sample */ + if ((result = (*pState->pDecoder->pfDecodeSample)(pEASData, pState)) != EAS_SUCCESS) + return result; + + /* adjust phase by one sample */ + pState->phase -= (1L << NUM_PHASE_FRAC_BITS); + } + + } + + /* save new gain */ + /*lint -e{704} use shift instead of division */ + pState->currentGainLeft = (EAS_I16) (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS); + +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} use shift instead of division */ + pState->currentGainRight = (EAS_I16) (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS); +#endif + + /* if pausing, set new state and notify */ + if (pState->state == EAS_STATE_PAUSING) + { + pState->state = EAS_STATE_PAUSED; + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + /* if out of data, set stopped state and notify */ + if (pState->bytesLeft == 0 || pState->state == EAS_STATE_STOPPING) + { + pState->state = EAS_STATE_STOPPED; + + /* do callback unless the file has already been closed */ + if (pState->pCallback && pState->fileHandle) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + if (pState->state == EAS_STATE_READY) + pState->state = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMDecode() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a PCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_HW_DATA_HANDLE hwInstData; + + hwInstData = ((S_EAS_DATA*) pEASData)->hwInstData; + + /* if out of data, check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "LinearPCMDecode: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + if (pState->bytesLeft) + { + + /* check format byte for 8-bit samples */ + if (pState->flags & PCM_FLAGS_8_BIT) + { + /* fetch left or mono sample */ + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + } + } + + /* must be 16-bit samples */ + else + { + //unsigned 16 bit currently not supported + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + return EAS_ERROR_INVALID_PCM_TYPE; + } + + /* fetch left or mono sample */ + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderL.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderR.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + } + } + } + + /* no more data, force zero samples */ + else + pState->decoderL.x1 = pState->decoderR.x1 = 0; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate in a linear PCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 secs, msecs; + EAS_INT shift; + + /* calculate size of sample frame */ + if (pState->flags & PCM_FLAGS_8_BIT) + shift = 0; + else + shift = 1; + if (pState->flags & PCM_FLAGS_STEREO) + shift++; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + + /* calculate the position based on sample frame size */ + /*lint -e{703} use shift for performance */ + temp <<= shift; + + /* past end of sample? */ + if (temp > (EAS_I32) pState->loopStart) + { + /* if not looped, flag error */ + if (pState->loopSamples == 0) + { + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* looped sample - calculate position in loop */ + while (temp > (EAS_I32) pState->loopStart) + temp -= (EAS_I32) pState->loopStart; + } + + /* seek to new position */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + + /* reset state */ + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- + * This bit is tricky because the chunks may not be contiguous, + * so we have to rely on the parser to position in the file. We + * do this by seeking to the end of each chunk and simulating an + * empty buffer condition until we get to where we want to go. + * + * A better solution would be a parser API for re-positioning, + * but there isn't time at the moment to re-factor all the + * parsers to support a new API. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation) +{ + EAS_RESULT result; + + /* seek to start of audio */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + pState->bytesLeft = pState->bytesLeftLoop; + + /* skip through chunks until we find the right chunk */ + while (*pLocation > (EAS_I32) pState->bytesLeft) + { + /* seek to end of audio chunk */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", pState->bytesLeft); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, pState->bytesLeft)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + *pLocation -= pState->bytesLeft; + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + + /* retrieve more data */ + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: bytesLeft=%d, byte location = %d\n", pState->bytesLeft, *pLocation); */ } + + /* no more samples */ + if (pState->bytesLeft == 0) + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* seek to new offset in current chunk */ + if (*pLocation > 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", *pLocation); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, *pLocation)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + + /* if not streamed, calculate number of bytes left */ + if (pState->flags & PCM_FLAGS_STREAMING) + pState->bytesLeft = 0x7fffffff; + else + pState->bytesLeft -= *pLocation; + } + return EAS_SUCCESS; +} + diff --git a/arm-fm-22k/lib_src/eas_pcm.h b/arm-fm-22k/lib_src/eas_pcm.h index c161757..4fc77e9 100644 --- a/arm-fm-22k/lib_src/eas_pcm.h +++ b/arm-fm-22k/lib_src/eas_pcm.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_pcm.h
- *
- * Contents and purpose:
- * External function prototypes for eas_pcm.c module
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.h + * + * Contents and purpose: + * External function prototypes for eas_pcm.c module + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,340 +20,340 @@ * 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: 847 $
- * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_PCM_H
-#define _EAS_PCM_H
-
-/* default gain setting - roughly unity gain */
-#define PCM_DEFAULT_GAIN_SETTING 0x6000
-
-typedef struct s_pcm_state_tag *EAS_PCM_HANDLE;
-typedef void (*EAS_PCM_CALLBACK) (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR cbInstData, EAS_PCM_HANDLE pcmHandle, EAS_STATE state);
-
-/* parameters for EAS_PEOpenStream */
-typedef struct s_pcm_open_params_tag
-{
- EAS_FILE_HANDLE fileHandle;
- EAS_I32 decoder;
- EAS_U32 sampleRate;
- EAS_I32 size;
- EAS_U32 loopStart;
- EAS_U32 loopSamples;
- EAS_I32 blockSize;
- EAS_U32 flags;
- EAS_U32 envData;
- EAS_I16 volume;
- EAS_PCM_CALLBACK pCallbackFunc;
- EAS_VOID_PTR cbInstData;
- } S_PCM_OPEN_PARAMS;
-
-/*----------------------------------------------------------------------------
- * EAS_PEInit()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the PCM engine
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEInit (EAS_DATA_HANDLE pEASData);
-
-/*----------------------------------------------------------------------------
- * EAS_PEShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Shuts down the PCM engine
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEShutdown (EAS_DATA_HANDLE pEASData);
-
-/*----------------------------------------------------------------------------
- * EAS_PEOpenStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Starts up a PCM playback
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEOpenStream (EAS_DATA_HANDLE pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_PEContinueStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Continues a PCM stream
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEContinueStream (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_I32 size);
-
-/*----------------------------------------------------------------------------
- * EAS_PEGetFileHandle()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the file handle of a stream
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEGetFileHandle (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_FILE_HANDLE *pFileHandle);
-
-/*----------------------------------------------------------------------------
- * EAS_PERender()
- *----------------------------------------------------------------------------
- * Purpose:
- * Render a buffer of PCM audio
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PERender (EAS_DATA_HANDLE pEASData, EAS_I32 numSamples);
-
-/*----------------------------------------------------------------------------
- * EAS_PEUpdateParams()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the pitch and volume parameters using MIDI controls
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEUpdateParams (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight);
-
-/*----------------------------------------------------------------------------
- * EAS_PELocate()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function seeks to the requested place in the file. Accuracy
- * is dependent on the sample rate and block size.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pState - stream handle
- * time - media time in milliseconds
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PELocate (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I32 time);
-
-/*----------------------------------------------------------------------------
- * EAS_PEUpdateVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the volume parameters for a PCM stream
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- * gainLeft - linear gain multipler in 1.15 fraction format
- * gainRight - linear gain multipler in 1.15 fraction format
- * initial - initial settings, set current gain
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes
- * In mono mode, leftGain controls the output gain and rightGain is ignored
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEUpdateVolume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume);
-
-/*----------------------------------------------------------------------------
- * EAS_PEUpdatePitch()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the pitch parameter for a PCM stream
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * pState - pointer to S_PCM_STATE for this stream
- * pitch - new pitch value in pitch cents
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT EAS_PEUpdatePitch (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch);
-
-/*----------------------------------------------------------------------------
- * EAS_PEState()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes:
- * This interface is also exposed in the internal library for use by the other modules.
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEState (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_STATE *pState);
-
-/*----------------------------------------------------------------------------
- * EAS_PEClose()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEClose (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle);
-
-/*----------------------------------------------------------------------------
- * EAS_PEReset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEReset (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle);
-
-/*----------------------------------------------------------------------------
- * EAS_PEPause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Mute and pause rendering a PCM stream. Sets the gain target to zero and stops the playback
- * at the end of the next audio frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEPause (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle);
-
-/*----------------------------------------------------------------------------
- * EAS_PEResume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume rendering a PCM stream. Sets the gain target back to its
- * previous setting and restarts playback at the end of the next audio
- * frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PEResume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle);
-
-/*----------------------------------------------------------------------------
- * EAS_PERelease()
- *----------------------------------------------------------------------------
- * Purpose:
- * Put the PCM stream envelope into release.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_PCM_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PERelease (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle);
-
-#endif /* end _EAS_PCM_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCM_H +#define _EAS_PCM_H + +/* default gain setting - roughly unity gain */ +#define PCM_DEFAULT_GAIN_SETTING 0x6000 + +typedef struct s_pcm_state_tag *EAS_PCM_HANDLE; +typedef void (*EAS_PCM_CALLBACK) (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR cbInstData, EAS_PCM_HANDLE pcmHandle, EAS_STATE state); + +/* parameters for EAS_PEOpenStream */ +typedef struct s_pcm_open_params_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_I32 decoder; + EAS_U32 sampleRate; + EAS_I32 size; + EAS_U32 loopStart; + EAS_U32 loopSamples; + EAS_I32 blockSize; + EAS_U32 flags; + EAS_U32 envData; + EAS_I16 volume; + EAS_PCM_CALLBACK pCallbackFunc; + EAS_VOID_PTR cbInstData; + } S_PCM_OPEN_PARAMS; + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (EAS_DATA_HANDLE pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle); + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEContinueStream (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_I32 size); + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEGetFileHandle (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_FILE_HANDLE *pFileHandle); + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (EAS_DATA_HANDLE pEASData, EAS_I32 numSamples); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters using MIDI controls + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEUpdateParams (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight); + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch); + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEState (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and pause rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEPause (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEResume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERelease (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +#endif /* end _EAS_PCM_H */ + diff --git a/arm-fm-22k/lib_src/eas_pcmdata.c b/arm-fm-22k/lib_src/eas_pcmdata.c index 5649f07..2d85ac2 100644 --- a/arm-fm-22k/lib_src/eas_pcmdata.c +++ b/arm-fm-22k/lib_src/eas_pcmdata.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_pcmdata.c
- *
- * Contents and purpose:
- * Contains the static data for the PCM engine.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.c + * + * Contents and purpose: + * Contains the static data for the PCM engine. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,17 +19,17 @@ * 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: 547 $
- * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-
-/* static data allocation */
-S_PCM_STATE eas_PCMData[MAX_PCM_STREAMS];
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" + +/* static data allocation */ +S_PCM_STATE eas_PCMData[MAX_PCM_STREAMS]; + + diff --git a/arm-fm-22k/lib_src/eas_pcmdata.h b/arm-fm-22k/lib_src/eas_pcmdata.h index be2f8e5..ae18d6d 100644 --- a/arm-fm-22k/lib_src/eas_pcmdata.h +++ b/arm-fm-22k/lib_src/eas_pcmdata.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_pcmdata.h
- *
- * Contents and purpose:
- * Data declarations for the PCM engine
- *
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.h + * + * Contents and purpose: + * Data declarations for the PCM engine + * + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,138 +20,138 @@ * 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: 847 $
- * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_PCMDATA_H
-#define _EAS_PCMDATA_H
-
-/* sets the maximum number of simultaneous PCM streams */
-#ifndef MAX_PCM_STREAMS
-#define MAX_PCM_STREAMS 16
-#define PCM_STREAM_THRESHOLD (MAX_PCM_STREAMS - 4)
-#endif
-
-/* coefficents for high-pass filter in ADPCM */
-#define INTEGRATOR_COEFFICIENT 100 /* coefficient for leaky integrator */
-
-/* additional flags in S_PCM_STATE.flags used internal to module */
-#define PCM_FLAGS_EMPTY 0x01000000 /* unsigned format */
-
-/*----------------------------------------------------------------------------
- * S_PCM_STATE
- *
- * Retains state information for PCM streams.
- *----------------------------------------------------------------------------
-*/
-typedef struct s_decoder_state_tag
-{
- EAS_I32 output; /* last output for DC offset filter */
- EAS_I32 acc; /* accumulator for DC offset filter */
- EAS_I32 step; /* current ADPCM step size */
- EAS_PCM x1; /* current generated sample */
- EAS_PCM x0; /* previous generated sample */
-} S_DECODER_STATE;
-
-typedef enum
-{
- PCM_ENV_START = 0,
- PCM_ENV_ATTACK,
- PCM_ENV_DECAY,
- PCM_ENV_SUSTAIN,
- PCM_ENV_RELEASE,
- PCM_ENV_END
-} E_PCM_ENV_STATE;
-
-typedef struct s_pcm_state_tag
-{
-#ifdef _CHECKED_BUILD
- EAS_U32 handleCheck; /* signature check for checked build */
-#endif
- EAS_FILE_HANDLE fileHandle; /* pointer to input file */
- EAS_PCM_CALLBACK pCallback; /* pointer to callback function */
- EAS_VOID_PTR cbInstData; /* instance data for callback function */
- struct s_decoder_interface_tag EAS_CONST * pDecoder; /* pointer to decoder interface */
- EAS_STATE state; /* stream state */
- EAS_I32 time; /* media time */
- EAS_I32 startPos; /* start of PCM stream */
- EAS_I32 loopLocation; /* file location where loop starts */
- EAS_I32 byteCount; /* size of file */
- EAS_U32 loopStart; /* loop start, offset in samples from startPos */
- /* NOTE: For CMF, we use this to store total sample size */
- EAS_U32 loopSamples; /* total loop length, in samples, 0 means no loop */
- /* NOTE: For CMF, non-zero means looped */
- EAS_U32 samplesInLoop; /* samples left in the loop to play back */
- EAS_I32 samplesTilLoop; /* samples left to play until top of loop */
- EAS_I32 bytesLeft; /* count of bytes left in stream */
- EAS_I32 bytesLeftLoop; /* count of bytes left in stream, value at start of loop */
- EAS_U32 phase; /* current phase for interpolator */
- EAS_U32 basefreq; /* frequency multiplier */
- EAS_U32 flags; /* stream flags */
- EAS_U32 envData; /* envelope data (and LFO data) */
- EAS_U32 envValue; /* current envelope value */
- EAS_U32 envScale; /* current envelope scale */
- EAS_U32 startOrder; /* start order index, first is 0, next is 1, etc. */
- S_DECODER_STATE decoderL; /* left (mono) ADPCM state */
- S_DECODER_STATE decoderR; /* right ADPCM state */
- S_DECODER_STATE decoderLLoop; /* left (mono) ADPCM state, value at start of loop */
- S_DECODER_STATE decoderRLoop; /* right ADPCM state, value at start of loop */
- E_PCM_ENV_STATE envState; /* current envelope state */
- EAS_I16 volume; /* volume for stream */
- EAS_I16 pitch; /* relative pitch in cents - zero is unity playback */
- EAS_I16 gainLeft; /* requested gain */
- EAS_I16 gainRight; /* requested gain */
- EAS_I16 currentGainLeft; /* current gain for anti-zipper filter */
- EAS_I16 currentGainRight; /* current gain for anti-zipper filter */
- EAS_U16 blockSize; /* block size for ADPCM decoder */
- EAS_U16 blockCount; /* block counter for ADPCM decoder */
- EAS_U16 sampleRate; /* input sample rate */
- EAS_U8 srcByte; /* source byte */
- EAS_U8 msBitCount; /* count keeps track of MS bits */
- EAS_U8 msBitMask; /* mask keeps track of MS bits */
- EAS_U8 msBitValue; /* value keeps track of MS bits */
- EAS_U8 msBitCountLoop; /* count keeps track of MS bits, value at loop start */
- EAS_U8 msBitMaskLoop; /* mask keeps track of MS bits, value at loop start */
- EAS_U8 msBitValueLoop; /* value keeps track of MS bits, value at loop start */
- EAS_BOOL8 hiNibble; /* indicates high/low nibble is next */
- EAS_BOOL8 hiNibbleLoop; /* indicates high/low nibble is next, value loop start */
- EAS_U8 rateShift; /* for playback rate greater than 1.0 */
-} S_PCM_STATE;
-
-/*----------------------------------------------------------------------------
- * S_DECODER_INTERFACE
- *
- * Generic interface for audio decoders
- *----------------------------------------------------------------------------
-*/
-typedef struct s_decoder_interface_tag
-{
- EAS_RESULT (* EAS_CONST pfInit)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
- EAS_RESULT (* EAS_CONST pfDecodeSample)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
- EAS_RESULT (* EAS_CONST pfLocate)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time);
-} S_DECODER_INTERFACE;
-
-
-/* header chunk for SMAF ADPCM */
-#define TAG_YAMAHA_ADPCM 0x4d776100
-#define TAG_MASK 0xffffff00
-#define TAG_RIFF_FILE 0x52494646
-#define TAG_WAVE_CHUNK 0x57415645
-#define TAG_FMT_CHUNK 0x666d7420
-
-/*----------------------------------------------------------------------------
- * EAS_PESeek
- *----------------------------------------------------------------------------
- * Purpose:
- * Locate to a particular byte in a PCM stream
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_PESeek (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation);
-
-#endif /* _EAS_PCMDATA_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCMDATA_H +#define _EAS_PCMDATA_H + +/* sets the maximum number of simultaneous PCM streams */ +#ifndef MAX_PCM_STREAMS +#define MAX_PCM_STREAMS 16 +#define PCM_STREAM_THRESHOLD (MAX_PCM_STREAMS - 4) +#endif + +/* coefficents for high-pass filter in ADPCM */ +#define INTEGRATOR_COEFFICIENT 100 /* coefficient for leaky integrator */ + +/* additional flags in S_PCM_STATE.flags used internal to module */ +#define PCM_FLAGS_EMPTY 0x01000000 /* unsigned format */ + +/*---------------------------------------------------------------------------- + * S_PCM_STATE + * + * Retains state information for PCM streams. + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_state_tag +{ + EAS_I32 output; /* last output for DC offset filter */ + EAS_I32 acc; /* accumulator for DC offset filter */ + EAS_I32 step; /* current ADPCM step size */ + EAS_PCM x1; /* current generated sample */ + EAS_PCM x0; /* previous generated sample */ +} S_DECODER_STATE; + +typedef enum +{ + PCM_ENV_START = 0, + PCM_ENV_ATTACK, + PCM_ENV_DECAY, + PCM_ENV_SUSTAIN, + PCM_ENV_RELEASE, + PCM_ENV_END +} E_PCM_ENV_STATE; + +typedef struct s_pcm_state_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + EAS_FILE_HANDLE fileHandle; /* pointer to input file */ + EAS_PCM_CALLBACK pCallback; /* pointer to callback function */ + EAS_VOID_PTR cbInstData; /* instance data for callback function */ + struct s_decoder_interface_tag EAS_CONST * pDecoder; /* pointer to decoder interface */ + EAS_STATE state; /* stream state */ + EAS_I32 time; /* media time */ + EAS_I32 startPos; /* start of PCM stream */ + EAS_I32 loopLocation; /* file location where loop starts */ + EAS_I32 byteCount; /* size of file */ + EAS_U32 loopStart; /* loop start, offset in samples from startPos */ + /* NOTE: For CMF, we use this to store total sample size */ + EAS_U32 loopSamples; /* total loop length, in samples, 0 means no loop */ + /* NOTE: For CMF, non-zero means looped */ + EAS_U32 samplesInLoop; /* samples left in the loop to play back */ + EAS_I32 samplesTilLoop; /* samples left to play until top of loop */ + EAS_I32 bytesLeft; /* count of bytes left in stream */ + EAS_I32 bytesLeftLoop; /* count of bytes left in stream, value at start of loop */ + EAS_U32 phase; /* current phase for interpolator */ + EAS_U32 basefreq; /* frequency multiplier */ + EAS_U32 flags; /* stream flags */ + EAS_U32 envData; /* envelope data (and LFO data) */ + EAS_U32 envValue; /* current envelope value */ + EAS_U32 envScale; /* current envelope scale */ + EAS_U32 startOrder; /* start order index, first is 0, next is 1, etc. */ + S_DECODER_STATE decoderL; /* left (mono) ADPCM state */ + S_DECODER_STATE decoderR; /* right ADPCM state */ + S_DECODER_STATE decoderLLoop; /* left (mono) ADPCM state, value at start of loop */ + S_DECODER_STATE decoderRLoop; /* right ADPCM state, value at start of loop */ + E_PCM_ENV_STATE envState; /* current envelope state */ + EAS_I16 volume; /* volume for stream */ + EAS_I16 pitch; /* relative pitch in cents - zero is unity playback */ + EAS_I16 gainLeft; /* requested gain */ + EAS_I16 gainRight; /* requested gain */ + EAS_I16 currentGainLeft; /* current gain for anti-zipper filter */ + EAS_I16 currentGainRight; /* current gain for anti-zipper filter */ + EAS_U16 blockSize; /* block size for ADPCM decoder */ + EAS_U16 blockCount; /* block counter for ADPCM decoder */ + EAS_U16 sampleRate; /* input sample rate */ + EAS_U8 srcByte; /* source byte */ + EAS_U8 msBitCount; /* count keeps track of MS bits */ + EAS_U8 msBitMask; /* mask keeps track of MS bits */ + EAS_U8 msBitValue; /* value keeps track of MS bits */ + EAS_U8 msBitCountLoop; /* count keeps track of MS bits, value at loop start */ + EAS_U8 msBitMaskLoop; /* mask keeps track of MS bits, value at loop start */ + EAS_U8 msBitValueLoop; /* value keeps track of MS bits, value at loop start */ + EAS_BOOL8 hiNibble; /* indicates high/low nibble is next */ + EAS_BOOL8 hiNibbleLoop; /* indicates high/low nibble is next, value loop start */ + EAS_U8 rateShift; /* for playback rate greater than 1.0 */ +} S_PCM_STATE; + +/*---------------------------------------------------------------------------- + * S_DECODER_INTERFACE + * + * Generic interface for audio decoders + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_interface_tag +{ + EAS_RESULT (* EAS_CONST pfInit)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfDecodeSample)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfLocate)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); +} S_DECODER_INTERFACE; + + +/* header chunk for SMAF ADPCM */ +#define TAG_YAMAHA_ADPCM 0x4d776100 +#define TAG_MASK 0xffffff00 +#define TAG_RIFF_FILE 0x52494646 +#define TAG_WAVE_CHUNK 0x57415645 +#define TAG_FMT_CHUNK 0x666d7420 + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation); + +#endif /* _EAS_PCMDATA_H */ + diff --git a/arm-fm-22k/lib_src/eas_public.c b/arm-fm-22k/lib_src/eas_public.c index ac43261..394a9a1 100644 --- a/arm-fm-22k/lib_src/eas_public.c +++ b/arm-fm-22k/lib_src/eas_public.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_public.c
- *
- * Contents and purpose:
- * Contains EAS library public interface
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_public.c + * + * Contents and purpose: + * Contains EAS library public interface + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,2579 +19,2579 @@ * 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: 842 $
- * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_synthcfg.h"
-#include "eas.h"
-#include "eas_config.h"
-#include "eas_host.h"
-#include "eas_report.h"
-#include "eas_data.h"
-#include "eas_parser.h"
-#include "eas_pcm.h"
-#include "eas_midi.h"
-#include "eas_mixer.h"
-#include "eas_build.h"
-#include "eas_vm_protos.h"
-#include "eas_math.h"
-
-#ifdef JET_INTERFACE
-#include "jet_data.h"
-#endif
-
-#ifdef DLS_SYNTHESIZER
-#include "eas_mdls.h"
-#endif
-
-/* number of events to parse before calling EAS_HWYield function */
-#define YIELD_EVENT_COUNT 10
-
-/*----------------------------------------------------------------------------
- * easLibConfig
- *
- * This structure is available through the EAS public interface to allow
- * the user to check the configuration of the library.
- *----------------------------------------------------------------------------
-*/
-static const S_EAS_LIB_CONFIG easLibConfig =
-{
- LIB_VERSION,
-#ifdef _CHECKED_BUILD
- EAS_TRUE,
-#else
- EAS_FALSE,
-#endif
- MAX_SYNTH_VOICES,
- NUM_OUTPUT_CHANNELS,
- _OUTPUT_SAMPLE_RATE,
- BUFFER_SIZE_IN_MONO_SAMPLES,
-#ifdef _FILTER_ENABLED
- EAS_TRUE,
-#else
- EAS_FALSE,
-#endif
- _BUILD_TIME_,
- _BUILD_VERSION_
-};
-
-/* local prototypes */
-static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode);
-
-/*----------------------------------------------------------------------------
- * EAS_SetStreamParameter
- *----------------------------------------------------------------------------
- * Sets the specified parameter in the stream. Allows access to
- * customizable settings within the individual file parsers.
- *----------------------------------------------------------------------------
- * pEASData - pointer to EAS persistent data object
- * pStream - stream handle
- * param - enumerated parameter (see eas_parser.h)
- * value - new value
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
-
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule->pfSetData)
- return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value);
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetStreamParameter
- *----------------------------------------------------------------------------
- * Sets the specified parameter in the stream. Allows access to
- * customizable settings within the individual file parsers.
- *----------------------------------------------------------------------------
- * pEASData - pointer to EAS persistent data object
- * pStream - stream handle
- * param - enumerated parameter (see eas_parser.h)
- * pValue - pointer to variable to receive current setting
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
-
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule->pfGetData)
- return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue);
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_StreamReady()
- *----------------------------------------------------------------------------
- * This routine sets common parameters like transpose, volume, etc.
- * First, it attempts to use the parser EAS_SetStreamParameter interface. If that
- * fails, it attempts to get the synth handle from the parser and
- * set the parameter directly on the synth. This eliminates duplicate
- * code in the parser.
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_STATE state;
-
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS)
- return EAS_FALSE;
- return (state < EAS_STATE_OPEN);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_IntSetStrmParam()
- *----------------------------------------------------------------------------
- * This routine sets common parameters like transpose, volume, etc.
- * First, it attempts to use the parser EAS_SetStreamParameter interface. If that
- * fails, it attempts to get the synth handle from the parser and
- * set the parameter directly on the synth. This eliminates duplicate
- * code in the parser.
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value)
-{
- S_SYNTH *pSynth;
-
- /* try to set the parameter using stream interface */
- if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS)
- return EAS_SUCCESS;
-
- /* get a pointer to the synth object and set it directly */
- /*lint -e{740} we are cheating by passing a pointer through this interface */
- if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
- return EAS_ERROR_INVALID_PARAMETER;
-
- if (pSynth == NULL)
- return EAS_ERROR_INVALID_PARAMETER;
-
- switch (param)
- {
-
-#ifdef DLS_SYNTHESIZER
- case PARSER_DATA_DLS_COLLECTION:
- {
- EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value);
- if (result == EAS_SUCCESS)
- {
- DLSAddRef((S_DLS*) value);
- VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth);
- }
- return result;
- }
-#endif
-
- case PARSER_DATA_EAS_LIBRARY:
- return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value);
-
- case PARSER_DATA_POLYPHONY:
- return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value);
-
- case PARSER_DATA_PRIORITY:
- return VMSetPriority(pEASData->pVoiceMgr, pSynth, value);
-
- case PARSER_DATA_TRANSPOSITION:
- VMSetTranposition(pSynth, value);
- break;
-
- case PARSER_DATA_VOLUME:
- VMSetVolume(pSynth, (EAS_U16) value);
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ }
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_IntGetStrmParam()
- *----------------------------------------------------------------------------
- * This routine gets common parameters like transpose, volume, etc.
- * First, it attempts to use the parser EAS_GetStreamParameter interface. If that
- * fails, it attempts to get the synth handle from the parser and
- * get the parameter directly on the synth.
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_IntGetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 *pValue)
-{
- S_SYNTH *pSynth;
-
- /* try to set the parameter */
- if (EAS_GetStreamParameter(pEASData, pStream, param, pValue) == EAS_SUCCESS)
- return EAS_SUCCESS;
-
- /* get a pointer to the synth object and retrieve data directly */
- /*lint -e{740} we are cheating by passing a pointer through this interface */
- if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
- return EAS_ERROR_INVALID_PARAMETER;
-
- if (pSynth == NULL)
- return EAS_ERROR_INVALID_PARAMETER;
-
- switch (param)
- {
- case PARSER_DATA_POLYPHONY:
- return VMGetPolyphony(pEASData->pVoiceMgr, pSynth, pValue);
-
- case PARSER_DATA_PRIORITY:
- return VMGetPriority(pEASData->pVoiceMgr, pSynth, pValue);
-
- case PARSER_DATA_TRANSPOSITION:
- VMGetTranposition(pSynth, pValue);
- break;
-
- case PARSER_DATA_NOTE_COUNT:
- *pValue = VMGetNoteCount(pSynth);
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ }
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_AllocateStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Allocates a stream handle
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData)
-{
- EAS_INT streamNum;
-
- /* check for static allocation, only one stream allowed */
- if (pEASData->staticMemoryModel)
- {
- if (pEASData->streams[0].handle != NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ }
- return -1;
- }
- return 0;
- }
-
- /* dynamic model */
- for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
- if (pEASData->streams[streamNum].handle == NULL)
- break;
- if (streamNum == MAX_NUMBER_STREAMS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ }
- return -1;
- }
- return streamNum;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_InitStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initialize a stream
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle)
-{
- pStream->pParserModule = pParserModule;
- pStream->handle = streamHandle;
- pStream->time = 0;
- pStream->frameLength = AUDIO_FRAME_LENGTH;
- pStream->repeatCount = 0;
- pStream->volume = DEFAULT_STREAM_VOLUME;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Config()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns a pointer to a structure containing the configuration options
- * in this library build.
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void)
-{
- return &easLibConfig;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Init()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initialize the synthesizer library
- *
- * Inputs:
- * ppEASData - pointer to data handle variable for this instance
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData)
-{
- EAS_HW_DATA_HANDLE pHWInstData;
- EAS_RESULT result;
- S_EAS_DATA *pEASData;
- EAS_INT module;
- EAS_BOOL staticMemoryModel;
-
- /* get the memory model */
- staticMemoryModel = EAS_CMStaticMemoryModel();
-
- /* initialize the host wrapper interface */
- *ppEASData = NULL;
- if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS)
- return result;
-
- /* check Configuration Module for S_EAS_DATA allocation */
- if (staticMemoryModel)
- pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA);
- else
- pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA));
- if (!pEASData)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
-
- /* initialize some data */
- EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA));
- pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel;
- pEASData->hwInstData = pHWInstData;
- pEASData->renderTime = 0;
-
- /* set header search flag */
-#ifdef FILE_HEADER_SEARCH
- pEASData->searchHeaderFlag = EAS_TRUE;
-#endif
-
- /* initalize parameters */
- EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME);
-
-#ifdef _METRICS_ENABLED
- /* initalize the metrics module */
- pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS);
- if (pEASData->pMetricsModule != NULL)
- {
- if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ }
- return result;
- }
- }
-#endif
-
- /* initailize the voice manager & synthesizer */
- if ((result = VMInitialize(pEASData)) != EAS_SUCCESS)
- return result;
-
- /* initialize mix engine */
- if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ }
- return result;
- }
-
- /* initialize effects modules */
- for (module = 0; module < NUM_EFFECTS_MODULES; module++)
- {
- pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module);
- if (pEASData->effectsModules[module].effect != NULL)
- {
- if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ }
- return result;
- }
- }
- }
-
- /* initialize PCM engine */
- if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ }
- return result;
- }
-
- /* return instance data pointer to host */
- *ppEASData = pEASData;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Shutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Shuts down the library. Deallocates any memory associated with the
- * synthesizer (dynamic memory model only)
- *
- * Inputs:
- * pEASData - handle to data for this instance
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData)
-{
- EAS_HW_DATA_HANDLE hwInstData;
- EAS_RESULT result, reportResult;
- EAS_INT i;
-
- /* establish pointers */
- hwInstData = pEASData->hwInstData;
-
- /* check for NULL handle */
- if (!pEASData)
- return EAS_ERROR_HANDLE_INTEGRITY;
-
- /* if there are streams open, close them */
- reportResult = EAS_SUCCESS;
- for (i = 0; i < MAX_NUMBER_STREAMS; i++)
- {
- if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle)
- {
- if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ }
- reportResult = result;
- }
- }
- }
-
- /* shutdown PCM engine */
- if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ }
- if (reportResult == EAS_SUCCESS)
- reportResult = result;
- }
-
- /* shutdown mix engine */
- if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ }
- if (reportResult == EAS_SUCCESS)
- reportResult = result;
- }
-
- /* shutdown effects modules */
- for (i = 0; i < NUM_EFFECTS_MODULES; i++)
- {
- if (pEASData->effectsModules[i].effect)
- {
- if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ }
- if (reportResult == EAS_SUCCESS)
- reportResult = result;
- }
- }
- }
-
- /* shutdown the voice manager & synthesizer */
- VMShutdown(pEASData);
-
-#ifdef _METRICS_ENABLED
- /* shutdown the metrics module */
- if (pEASData->pMetricsModule != NULL)
- {
- if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ }
- if (reportResult == EAS_SUCCESS)
- reportResult = result;
- }
- }
-#endif
-
- /* release allocated memory */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(hwInstData, pEASData);
-
- /* shutdown host wrappers */
- if (hwInstData)
- {
- if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ }
- if (reportResult == EAS_SUCCESS)
- reportResult = result;
- }
- }
-
- return reportResult;
-}
-
-#ifdef JET_INTERFACE
-/*----------------------------------------------------------------------------
- * EAS_OpenJETStream()
- *----------------------------------------------------------------------------
- * Private interface for JET to open an SMF stream with an offset
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream)
-{
- EAS_RESULT result;
- EAS_VOID_PTR streamHandle;
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_INT streamNum;
-
- /* allocate a stream */
- if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
- return EAS_ERROR_MAX_STREAMS_OPEN;
-
- /* check Configuration Module for SMF parser */
- *ppStream = NULL;
- streamHandle = NULL;
- pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0);
- if (pParserModule == NULL)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* see if SMF parser recognizes the file */
- if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
- return result;
- }
-
- /* parser recognized the file, return the handle */
- if (streamHandle)
- {
- EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
- *ppStream = &pEASData->streams[streamNum];
- return EAS_SUCCESS;
- }
-
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_OpenFile()
- *----------------------------------------------------------------------------
- * Purpose:
- * Opens a file for audio playback.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pHandle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream)
-{
- EAS_RESULT result;
- EAS_FILE_HANDLE fileHandle;
- EAS_VOID_PTR streamHandle;
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_INT streamNum;
- EAS_INT moduleNum;
-
- /* open the file */
- if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS)
- return result;
-
- /* allocate a stream */
- if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
- return EAS_ERROR_MAX_STREAMS_OPEN;
-
- /* check Configuration Module for file parsers */
- pParserModule = NULL;
- *ppStream = NULL;
- streamHandle = NULL;
- for (moduleNum = 0; ; moduleNum++)
- {
- pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum);
- if (pParserModule == NULL)
- break;
-
- /* see if this parser recognizes it */
- if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
- return result;
- }
-
- /* parser recognized the file, return the handle */
- if (streamHandle)
- {
-
- /* save the parser pointer and file handle */
- EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
- *ppStream = &pEASData->streams[streamNum];
- return EAS_SUCCESS;
- }
-
- /* rewind the file for the next parser */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS)
- return result;
- }
-
- /* no parser was able to recognize the file, close it and return an error */
- EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ }
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-}
-
-#ifdef MMAPI_SUPPORT
-/*----------------------------------------------------------------------------
- * EAS_MMAPIToneControl()
- *----------------------------------------------------------------------------
- * Purpose:
- * Opens a ToneControl file for audio playback.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pHandle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream)
-{
- EAS_RESULT result;
- EAS_FILE_HANDLE fileHandle;
- EAS_VOID_PTR streamHandle;
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_INT streamNum;
-
- /* check if the tone control parser is available */
- *ppStream = NULL;
- streamHandle = NULL;
- pParserModule = EAS_CMEnumOptModules(EAS_MODULE_MMAPI_TONE_CONTROL);
- if (pParserModule == NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_MMAPIToneControl: ToneControl parser not available\n"); */ }
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
- }
-
- /* open the file */
- if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS)
- return result;
-
- /* allocate a stream */
- if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
- return EAS_ERROR_MAX_STREAMS_OPEN;
-
- /* see if ToneControl parser recognizes it */
- if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
- return result;
- }
-
- /* parser accepted the file, return the handle */
- if (streamHandle)
- {
-
- /* save the parser pointer and file handle */
- EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
- *ppStream = &pEASData->streams[streamNum];
- return EAS_SUCCESS;
- }
-
- /* parser did not recognize the file, close it and return an error */
- EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ }
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetWaveFmtChunk
- *----------------------------------------------------------------------------
- * Helper function to retrieve WAVE file fmt chunk for MMAPI
- *----------------------------------------------------------------------------
- * pEASData - pointer to EAS persistent data object
- * pStream - stream handle
- * pFmtChunk - pointer to variable to receive current setting
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_VOID_PTR *ppFmtChunk)
-{
- EAS_RESULT result;
- EAS_I32 value;
-
- if ((result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FORMAT, &value)) != EAS_SUCCESS)
- return result;
- *ppFmtChunk = (EAS_VOID_PTR) value;
- return EAS_SUCCESS;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_GetFileType
- *----------------------------------------------------------------------------
- * Returns the file type (see eas_types.h for enumerations)
- *----------------------------------------------------------------------------
- * pEASData - pointer to EAS persistent data object
- * pStream - stream handle
- * pFileType - pointer to variable to receive file type
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetFileType (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 *pFileType)
-{
- if (!EAS_StreamReady (pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FILE_TYPE, pFileType);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Prepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepares the synthesizer to play the file or stream. Parses the first
- * frame of data from the file and arms the synthesizer.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_STATE state;
- EAS_RESULT result;
-
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- /* check for valid state */
- result = pParserModule->pfState(pEASData, pStream->handle, &state);
- if (result == EAS_SUCCESS)
- {
- /* prepare the stream */
- if (state == EAS_STATE_OPEN)
- {
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- result = (*pParserModule->pfPrepare)(pEASData, pStream->handle);
-
- /* set volume */
- if (result == EAS_SUCCESS)
- result = EAS_SetVolume(pEASData, pStream, pStream->volume);
- }
- else
- result = EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- }
-
- return result;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Render()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the Midi data and render PCM audio data.
- *
- * Inputs:
- * pEASData - buffer for internal EAS data
- * pOut - output buffer pointer
- * nNumRequested - requested num samples to generate
- * pnNumGenerated - actual number of samples generated
- *
- * Outputs:
- * EAS_SUCCESS if PCM data was successfully rendered
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_RESULT result;
- EAS_I32 voicesRendered;
- EAS_STATE parserState;
- EAS_INT streamNum;
-
- /* assume no samples generated and reset workload */
- *pNumGenerated = 0;
- VMInitWorkload(pEASData->pVoiceMgr);
-
- /* no support for other buffer sizes yet */
- if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n",
- (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ }
- return EAS_BUFFER_SIZE_MISMATCH;
- }
-
-#ifdef _METRICS_ENABLED
- /* start performance counter */
- if (pEASData->pMetricsData)
- (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
-#endif
-
- /* prep the frame buffer, do mix engine prep only if TRUE */
-#ifdef _SPLIT_ARCHITECTURE
- if (VMStartFrame(pEASData))
- EAS_MixEnginePrep(pEASData, numRequested);
-#else
- /* prep the mix engine */
- EAS_MixEnginePrep(pEASData, numRequested);
-#endif
-
- /* save the output buffer pointer */
- pEASData->pOutputAudioBuffer = pOut;
-
-
-#ifdef _METRICS_ENABLED
- /* start performance counter */
- if (pEASData->pMetricsData)
- (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME);
-#endif
-
- /* if we haven't finished parsing from last time, do it now */
- /* need to parse another frame of events before we render again */
- for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
- {
- /* clear the locate flag */
- pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE;
-
- if (pEASData->streams[streamNum].pParserModule)
- {
-
- /* establish pointer to parser module */
- pParserModule = pEASData->streams[streamNum].pParserModule;
-
- /* handle pause */
- if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE)
- {
- if (pParserModule->pfPause)
- result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle);
- pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE;
- }
-
- /* get current state */
- if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS)
- return result;
-
- /* handle resume */
- if (parserState == EAS_STATE_PAUSED)
- {
- if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME)
- {
- if (pParserModule->pfResume)
- result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle);
- pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME;
- }
- }
-
- /* if necessary, parse stream */
- if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0)
- if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS)
- return result;
-
- /* check for an early abort */
- if ((pEASData->streams[streamNum].streamFlags) == 0)
- {
-
-#ifdef _METRICS_ENABLED
- /* stop performance counter */
- if (pEASData->pMetricsData)
- (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
-#endif
-
- return EAS_SUCCESS;
- }
-
- /* check for repeat */
- if (pEASData->streams[streamNum].repeatCount)
- {
-
- /* check for stopped state */
- if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS)
- return result;
- if (parserState == EAS_STATE_STOPPED)
- {
-
- /* decrement repeat count, unless it is negative */
- if (pEASData->streams[streamNum].repeatCount > 0)
- pEASData->streams[streamNum].repeatCount--;
-
- /* reset the parser */
- if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS)
- return result;
- pEASData->streams[streamNum].time = 0;
- }
- }
- }
- }
-
-#ifdef _METRICS_ENABLED
- /* stop performance counter */
- if (pEASData->pMetricsData)
- (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME);
-#endif
-
-#ifdef _METRICS_ENABLED
- /* start the render timer */
- if (pEASData->pMetricsData)
- (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME);
-#endif
-
- /* render audio */
- if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ }
- return result;
- }
-
-#ifdef _METRICS_ENABLED
- /* stop the render timer */
- if (pEASData->pMetricsData) {
- (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1);
- (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME);
- (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered);
- (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered);
- }
-#endif
-
- //2 Do we really need frameParsed?
- /* need to parse another frame of events before we render again */
- for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
- if (pEASData->streams[streamNum].pParserModule != NULL)
- pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED;
-
-#ifdef _METRICS_ENABLED
- /* start performance counter */
- if (pEASData->pMetricsData)
- (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME);
-#endif
-
- /* render PCM audio */
- if ((result = EAS_PERender(pEASData, numRequested)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_PERender returned error %ld\n", result); */ }
- return result;
- }
-
-#ifdef _METRICS_ENABLED
- /* stop the stream timer */
- if (pEASData->pMetricsData)
- (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME);
-#endif
-
-#ifdef _METRICS_ENABLED
- /* start the post timer */
- if (pEASData->pMetricsData)
- (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME);
-#endif
-
- /* for split architecture, send DSP vectors. Do post only if return is TRUE */
-#ifdef _SPLIT_ARCHITECTURE
- if (VMEndFrame(pEASData))
- {
- /* now do post-processing */
- EAS_MixEnginePost(pEASData, numRequested);
- *pNumGenerated = numRequested;
- }
-#else
- /* now do post-processing */
- EAS_MixEnginePost(pEASData, numRequested);
- *pNumGenerated = numRequested;
-#endif
-
-#ifdef _METRICS_ENABLED
- /* stop the post timer */
- if (pEASData->pMetricsData)
- (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME);
-#endif
-
- /* advance render time */
- pEASData->renderTime += AUDIO_FRAME_LENGTH;
-
-#if 0
- /* dump workload for debug */
- if (pEASData->pVoiceMgr->workload)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ }
-#endif
-
-#ifdef _METRICS_ENABLED
- /* stop performance counter */
- if (pEASData->pMetricsData)
- {
- PERF_TIMER temp;
- temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
-
- /* if max render time, record the number of voices and time */
- if ((*pEASData->pMetricsModule->pfRecordMaxValue)
- (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp))
- {
- (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered);
- (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8));
- }
- }
-#endif
-
-#ifdef JET_INTERFACE
- /* let JET to do its thing */
- if (pEASData->jetHandle != NULL)
- {
- result = JET_Process(pEASData);
- if (result != EAS_SUCCESS)
- return result;
- }
-#endif
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetRepeat()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the selected stream to repeat.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * handle - handle to stream
- * repeatCount - repeat count
- *
- * Outputs:
- *
- * Side Effects:
- *
- * Notes:
- * 0 = no repeat
- * 1 = repeat once, i.e. play through twice
- * -1 = repeat forever
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 repeatCount)
-{
- pStream->repeatCount = repeatCount;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetRepeat()
- *----------------------------------------------------------------------------
- * Purpose:
- * Gets the current repeat count for the selected stream.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * handle - handle to stream
- * pRrepeatCount - pointer to variable to hold repeat count
- *
- * Outputs:
- *
- * Side Effects:
- *
- * Notes:
- * 0 = no repeat
- * 1 = repeat once, i.e. play through twice
- * -1 = repeat forever
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pRepeatCount)
-{
- *pRepeatCount = pStream->repeatCount;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetPlaybackRate()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the playback rate.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * handle - handle to stream
- * rate - rate (28-bit fractional amount)
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U32 rate)
-{
-
- /* check range */
- if ((rate < (1 << 27)) || (rate > (1 << 29)))
- return EAS_ERROR_INVALID_PARAMETER;
-
- /* calculate new frame length
- *
- * NOTE: The maximum frame length we can accomodate based on a
- * maximum rate of 2.0 (2^28) is 2047 (2^13-1). To accomodate a
- * longer frame length or a higher maximum rate, the fixed point
- * divide below will need to be adjusted
- */
- pStream->frameLength = (AUDIO_FRAME_LENGTH * (rate >> 8)) >> 20;
-
- /* notify stream of new playback rate */
- EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_PLAYBACK_RATE, (EAS_I32) rate);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetTransposition)
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the key tranposition for the synthesizer. Transposes all
- * melodic instruments by the specified amount. Range is limited
- * to +/-12 semitones.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * handle - handle to stream
- * transposition - +/-12 semitones
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition)
-{
-
- /* check range */
- if ((transposition < -12) || (transposition > 12))
- return EAS_ERROR_INVALID_PARAMETER;
-
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_ParseEvents()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse events in the current streams until the desired time is reached.
- *
- * Inputs:
- * pEASData - buffer for internal EAS data
- * endTime - stop parsing if this time is reached
- * parseMode - play, locate, or metadata
- *
- * Outputs:
- * EAS_SUCCESS if PCM data was successfully rendered
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_RESULT result;
- EAS_I32 parserState;
- EAS_BOOL done;
- EAS_INT yieldCount = YIELD_EVENT_COUNT;
- EAS_U32 time = 0;
-
- /* does this parser have a time function? */
- pParserModule = pStream->pParserModule;
- if (pParserModule->pfTime == NULL)
- {
- /* check state */
- if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS)
- return result;
- /* if play state, advance time */
- if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING))
- pStream->time += pStream->frameLength;
- done = EAS_TRUE;
- }
-
- /* assume we're not done, in case we abort out */
- else
- {
- pStream->streamFlags &= ~STREAM_FLAGS_PARSED;
- done = EAS_FALSE;
- }
-
- while (!done)
- {
-
- /* check for stopped state */
- if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS)
- return result;
- if (parserState > EAS_STATE_PLAY)
- {
- /* save current time if we're not in play mode */
- if (parseMode != eParserModePlay)
- pStream->time = time << 8;
- done = EAS_TRUE;
- break;
- }
-
- /* get the next event time */
- if (pParserModule->pfTime)
- {
- if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS)
- return result;
-
- /* if next event is within this frame, parse it */
- if (time < (endTime >> 8))
- {
-
- /* parse the next event */
- if (pParserModule->pfEvent)
- if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS)
- return result;
- }
-
- /* no more events in this frame, advance time */
- else
- {
- pStream->time = endTime;
- done = EAS_TRUE;
- }
- }
-
- /* check for max workload exceeded */
- if (VMCheckWorkload(pEASData->pVoiceMgr))
- {
- /* stop even though we may not have parsed
- * all the events in this frame. The parser will try to
- * catch up on the next frame.
- */
- break;
- }
-
- /* give host a chance for an early abort */
- if (--yieldCount == 0)
- {
- if (EAS_HWYield(pEASData->hwInstData))
- break;
- yieldCount = YIELD_EVENT_COUNT;
- }
- }
-
- /* if no early abort, parsing is complete for this frame */
- if (done)
- pStream->streamFlags |= STREAM_FLAGS_PARSED;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_ParseMetaData()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- * playLength - pointer to variable to store the play length (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - resets the parser to the start of the file
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_RESULT result;
- EAS_STATE state;
-
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- /* check parser state */
- if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS)
- return result;
- if (state >= EAS_STATE_OPEN)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* if parser has metadata function, use that */
- if (pParserModule->pfGetMetaData != NULL)
- return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength);
-
- /* reset the parser to the beginning */
- if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS)
- return result;
-
- /* parse the file to end */
- pStream->time = 0;
- VMInitWorkload(pEASData->pVoiceMgr);
- if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS)
- return result;
-
- /* get the parser time */
- if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS)
- return result;
-
- /* reset the parser to the beginning */
- pStream->time = 0;
- return (*pParserModule->pfReset)(pEASData, pStream->handle);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_RegisterMetaDataCallback()
- *----------------------------------------------------------------------------
- * Purpose:
- * Registers a metadata callback function for parsed metadata.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- * cbFunc - pointer to host callback function
- * metaDataBuffer - pointer to metadata buffer
- * metaDataBufSize - maximum size of the metadata buffer
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback (
- EAS_DATA_HANDLE pEASData,
- EAS_HANDLE pStream,
- EAS_METADATA_CBFUNC cbFunc,
- char *metaDataBuffer,
- EAS_I32 metaDataBufSize,
- EAS_VOID_PTR pUserData)
-{
- S_METADATA_CB metadata;
-
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* register callback function */
- metadata.callback = cbFunc;
- metadata.buffer = metaDataBuffer;
- metadata.bufferSize = metaDataBufSize;
- metadata.pUserData = pUserData;
- return EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_METADATA_CB, (EAS_I32) &metadata);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetNoteCount ()
- *----------------------------------------------------------------------------
- * Returns the total number of notes played in this stream
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount)
-{
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_NOTE_COUNT, pNoteCount);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CloseFile()
- *----------------------------------------------------------------------------
- * Purpose:
- * Closes an audio file or stream. Playback should have either paused or
- * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_RESULT result;
-
- /* call the close function */
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- result = (*pParserModule->pfClose)(pEASData, pStream->handle);
-
- /* clear the handle and parser interface pointer */
- pStream->handle = NULL;
- pStream->pParserModule = NULL;
- return result;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_OpenMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pHandle - pointer to variable to hold file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *ppStream, EAS_HANDLE streamHandle)
-{
- EAS_RESULT result;
- S_INTERACTIVE_MIDI *pMIDIStream;
- EAS_INT streamNum;
-
- /* initialize some pointers */
- *ppStream = NULL;
-
- /* allocate a stream */
- if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
- return EAS_ERROR_MAX_STREAMS_OPEN;
-
- /* check Configuration Module for S_EAS_DATA allocation */
- if (pEASData->staticMemoryModel)
- pMIDIStream = EAS_CMEnumData(EAS_CM_MIDI_STREAM_DATA);
- else
- pMIDIStream = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_INTERACTIVE_MIDI));
-
- /* allocate dynamic memory */
- if (!pMIDIStream)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate MIDI stream data\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
-
- /* zero the memory to insure complete initialization */
- EAS_HWMemSet(pMIDIStream, 0, sizeof(S_INTERACTIVE_MIDI));
- EAS_InitStream(&pEASData->streams[streamNum], NULL, pMIDIStream);
-
- /* instantiate a new synthesizer */
- if (streamHandle == NULL)
- {
- result = VMInitMIDI(pEASData, &pMIDIStream->pSynth);
- }
-
- /* use an existing synthesizer */
- else
- {
- EAS_I32 value;
- result = EAS_GetStreamParameter(pEASData, streamHandle, PARSER_DATA_SYNTH_HANDLE, &value);
- pMIDIStream->pSynth = (S_SYNTH*) value;
- VMIncRefCount(pMIDIStream->pSynth);
- }
- if (result != EAS_SUCCESS)
- {
- EAS_CloseMIDIStream(pEASData, &pEASData->streams[streamNum]);
- return result;
- }
-
- /* initialize the MIDI stream data */
- EAS_InitMIDIStream(&pMIDIStream->stream);
-
- *ppStream = (EAS_HANDLE) &pEASData->streams[streamNum];
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_WriteMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Send data to the MIDI stream device
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - stream handle
- * pBuffer - pointer to buffer
- * count - number of bytes to write
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 *pBuffer, EAS_I32 count)
-{
- S_INTERACTIVE_MIDI *pMIDIStream;
- EAS_RESULT result;
-
- pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle;
-
- /* send the entire buffer */
- while (count--)
- {
- if ((result = EAS_ParseMIDIStream(pEASData, pMIDIStream->pSynth, &pMIDIStream->stream, *pBuffer++, eParserModePlay)) != EAS_SUCCESS)
- return result;
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_CloseMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Closes a raw MIDI stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
-{
- S_INTERACTIVE_MIDI *pMIDIStream;
-
- pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle;
-
- /* close synth */
- if (pMIDIStream->pSynth != NULL)
- {
- VMMIDIShutdown(pEASData, pMIDIStream->pSynth);
- pMIDIStream->pSynth = NULL;
- }
-
- /* release allocated memory */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(((S_EAS_DATA*) pEASData)->hwInstData, pMIDIStream);
-
- pStream->handle = NULL;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_State()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the state of an audio file or stream.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_RESULT result;
-
- /* call the parser to return state */
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS)
- return result;
-
- /* if repeat count is set for this parser, mask the stopped state from the application */
- if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED))
- *pState = EAS_STATE_PLAY;
-
- /* if we're not ready or playing, we don't need to hide state from host */
- if (*pState > EAS_STATE_PLAY)
- return EAS_SUCCESS;
-
- /* if stream is about to be paused, report it as paused */
- if (pStream->streamFlags & STREAM_FLAGS_PAUSE)
- {
- if (pStream->streamFlags & STREAM_FLAGS_LOCATE)
- *pState = EAS_STATE_PAUSED;
- else
- *pState = EAS_STATE_PAUSING;
- }
-
- /* if stream is about to resume, report it as playing */
- if (pStream->streamFlags & STREAM_FLAGS_RESUME)
- *pState = EAS_STATE_PLAY;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the polyphony of the stream. A value of 0 allows the stream
- * to use all voices (set by EAS_SetSynthPolyphony).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * polyphonyCount - the desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 polyphonyCount)
-{
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, polyphonyCount);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current polyphony setting of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * pPolyphonyCount - pointer to variable to receive polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPolyphonyCount)
-{
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, pPolyphonyCount);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the polyphony of the synth . Value must be >= 1 and <= the
- * maximum number of voices. This function will pin the polyphony
- * at those limits
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * synthNum - synthesizer number (0 = onboard, 1 = DSP)
- * polyphonyCount - the desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount)
-{
- return VMSetSynthPolyphony(pEASData->pVoiceMgr, synthNum, polyphonyCount);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current polyphony setting of the synth
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * synthNum - synthesizer number (0 = onboard, 1 = DSP)
- * pPolyphonyCount - pointer to variable to receive polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount)
-{
- return VMGetSynthPolyphony(pEASData->pVoiceMgr, synthNum, pPolyphonyCount);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the priority of the stream. Determines which stream's voices
- * are stolen when there are insufficient voices for all notes.
- * Value must be in the range of 1-15, lower values are higher
- * priority.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * polyphonyCount - the desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 priority)
-{
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, priority);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current priority setting of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * pPriority - pointer to variable to receive priority
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPriority)
-{
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, pPriority);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the master gain for the mix engine in 1dB increments
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * volume - the desired master gain (100 is max)
- * handle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- * overrides any previously set master volume from sysex
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume)
-{
- EAS_I16 gain;
-
- /* check range */
- if ((volume < 0) || (volume > EAS_MAX_VOLUME))
- return EAS_ERROR_PARAMETER_RANGE;
-
- /* stream volume */
- if (pStream != NULL)
- {
- EAS_I32 gainOffset;
- EAS_RESULT result;
-
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* get gain offset */
- pStream->volume = (EAS_U8) volume;
- result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset);
- if (result == EAS_SUCCESS)
- volume += gainOffset;
-
- /* set stream volume */
- gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM);
-
- /* convert to linear scalar */
- return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain);
- }
-
- /* master volume */
- pEASData->masterVolume = (EAS_U8) volume;
-#if (NUM_OUTPUT_CHANNELS == 1)
- /* leave 3dB headroom for mono output */
- volume -= 3;
-#endif
-
- gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM);
- pEASData->masterGain = gain;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the master volume for the synthesizer. The default volume setting is
- * 50. The volume range is 0 to 100;
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * volume - the desired master volume
- * handle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- * overrides any previously set master volume from sysex
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
-{
- if (pStream == NULL)
- return pEASData->masterVolume;
-
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return pStream->volume;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetMaxLoad()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the maximum workload the parsers will do in a single call to
- * EAS_Render. The units are currently arbitrary, but should correlate
- * well to the actual CPU cycles consumed. The primary effect is to
- * reduce the occasional peaks in CPU cycles consumed when parsing
- * dense parts of a MIDI score.
- *
- * Inputs:
- * pEASData - handle to data for this instance
- * maxLoad - the desired maximum workload
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad)
-{
- VMSetWorkload(pEASData->pVoiceMgr, maxLoad);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetMaxPCMStreams()
- *----------------------------------------------------------------------------
- * Sets the maximum number of PCM streams allowed in parsers that
- * use PCM streaming.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * streamHandle - handle returned by EAS_OpenFile
- * maxNumStreams - maximum number of PCM streams
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams)
-{
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_MAX_PCM_STREAMS, maxNumStreams);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Locate()
- *----------------------------------------------------------------------------
- * Purpose:
- * Locate into the file associated with the handle.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file handle
- * milliseconds - playback offset from start of file in milliseconds
- *
- * Outputs:
- *
- *
- * Side Effects:
- * the actual offset will be quantized to the closest update period, typically
- * a resolution of 5.9ms. Notes that are started prior to this time will not
- * sound. Any notes currently playing will be shut off.
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_RESULT result;
- EAS_U32 requestedTime;
- EAS_STATE state;
-
- /* get pointer to parser function table */
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS)
- return result;
- if (state >= EAS_STATE_OPEN)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* handle offset and limit to start of file */
- /*lint -e{704} use shift for performance*/
- if (offset)
- milliseconds += (EAS_I32) pStream->time >> 8;
- if (milliseconds < 0)
- milliseconds = 0;
-
- /* check to see if the request is different from the current time */
- requestedTime = (EAS_U32) milliseconds;
- if (requestedTime == (pStream->time >> 8))
- return EAS_SUCCESS;
-
- /* set the locate flag */
- pStream->streamFlags |= STREAM_FLAGS_LOCATE;
-
- /* use the parser locate function, if available */
- if (pParserModule->pfLocate != NULL)
- {
- EAS_BOOL parserLocate = EAS_FALSE;
- result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate);
- if (!parserLocate)
- {
- if (result == EAS_SUCCESS)
- pStream->time = requestedTime << 8;
- return result;
- }
- }
-
- /* if we were paused and not going to resume, set pause request flag */
- if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0))
- pStream->streamFlags |= STREAM_FLAGS_PAUSE;
-
- /* reset the synth and parser */
- if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS)
- return result;
- pStream->time = 0;
-
- /* locating forward, clear parsed flag and parse data until we get to the requested location */
- if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS)
- return result;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetLocation()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current playback offset
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file handle
- *
- * Outputs:
- * The offset in milliseconds from the start of the current sequence, quantized
- * to the nearest update period. Actual resolution is typically 5.9 ms.
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime)
-{
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- *pTime = pStream->time >> 8;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetRenderTime()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current playback offset
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Gets the render time clock in msecs.
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime)
-{
- *pTime = pEASData->renderTime >> 8;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Pause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Pauses the playback of the data associated with this handle. The audio
- * is gracefully ramped down to prevent clicks and pops. It may take several
- * buffers of audio before the audio is muted.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_STATE state;
- EAS_RESULT result;
-
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- /* check for valid state */
- result = pParserModule->pfState(pEASData, pStream->handle, &state);
- if (result == EAS_SUCCESS)
- {
- if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* make sure parser implements pause */
- if (pParserModule->pfPause == NULL)
- result = EAS_ERROR_NOT_IMPLEMENTED;
-
- /* clear resume flag */
- pStream->streamFlags &= ~STREAM_FLAGS_RESUME;
-
- /* set pause flag */
- pStream->streamFlags |= STREAM_FLAGS_PAUSE;
-
-#if 0
- /* pause the stream */
- if (pParserModule->pfPause)
- result = pParserModule->pfPause(pEASData, pStream->handle);
- else
- result = EAS_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
- return result;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_Resume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resumes the playback of the data associated with this handle. The audio
- * is gracefully ramped up to prevent clicks and pops.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
-{
- S_FILE_PARSER_INTERFACE *pParserModule;
- EAS_STATE state;
- EAS_RESULT result;
-
- pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
- if (pParserModule == NULL)
- return EAS_ERROR_FEATURE_NOT_AVAILABLE;
-
- /* check for valid state */
- result = pParserModule->pfState(pEASData, pStream->handle, &state);
- if (result == EAS_SUCCESS)
- {
- if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* make sure parser implements this function */
- if (pParserModule->pfResume == NULL)
- result = EAS_ERROR_NOT_IMPLEMENTED;
-
- /* clear pause flag */
- pStream->streamFlags &= ~STREAM_FLAGS_PAUSE;
-
- /* set resume flag */
- pStream->streamFlags |= STREAM_FLAGS_RESUME;
-
-#if 0
- /* resume the stream */
- if (pParserModule->pfResume)
- result = pParserModule->pfResume(pEASData, pStream->handle);
- else
- result = EAS_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
- return result;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetParameter()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the parameter of a module. See E_MODULES for a list of modules
- * and the header files of the modules for a list of parameters.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- * module - enumerated module number
- * param - enumerated parameter number
- * pValue - pointer to variable to receive parameter value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue)
-{
-
- if (module >= NUM_EFFECTS_MODULES)
- return EAS_ERROR_INVALID_MODULE;
-
- if (pEASData->effectsModules[module].effectData == NULL)
- return EAS_ERROR_INVALID_MODULE;
-
- return (*pEASData->effectsModules[module].effect->pFGetParam)
- (pEASData->effectsModules[module].effectData, param, pValue);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetParameter()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the parameter of a module. See E_MODULES for a list of modules
- * and the header files of the modules for a list of parameters.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- * module - enumerated module number
- * param - enumerated parameter number
- * value - new parameter value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value)
-{
-
- if (module >= NUM_EFFECTS_MODULES)
- return EAS_ERROR_INVALID_MODULE;
-
- if (pEASData->effectsModules[module].effectData == NULL)
- return EAS_ERROR_INVALID_MODULE;
-
- return (*pEASData->effectsModules[module].effect->pFSetParam)
- (pEASData->effectsModules[module].effectData, param, value);
-}
-
-#ifdef _METRICS_ENABLED
-/*----------------------------------------------------------------------------
- * EAS_MetricsReport()
- *----------------------------------------------------------------------------
- * Purpose:
- * Displays the current metrics through the metrics interface.
- *
- * Inputs:
- * p - instance data handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData)
-{
- if (!pEASData->pMetricsModule)
- return EAS_ERROR_INVALID_MODULE;
-
- return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_MetricsReset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resets the metrics.
- *
- * Inputs:
- * p - instance data handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData)
-{
-
- if (!pEASData->pMetricsModule)
- return EAS_ERROR_INVALID_MODULE;
-
- return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData);
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_SetSoundLibrary()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the location of the sound library.
- *
- * Inputs:
- * pEASData - instance data handle
- * pSoundLib - pointer to sound library
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_SNDLIB_HANDLE pSndLib)
-{
- if (pStream)
- {
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_EAS_LIBRARY, (EAS_I32) pSndLib);
- }
-
- return VMSetGlobalEASLib(pEASData->pVoiceMgr, pSndLib);
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetHeaderSearchFlag()
- *----------------------------------------------------------------------------
- * By default, when EAS_OpenFile is called, the parsers check the
- * first few bytes of the file looking for a specific header. Some
- * mobile devices may add a header to the start of a file, which
- * will prevent the parser from recognizing the file. If the
- * searchFlag is set to EAS_TRUE, the parser will search the entire
- * file looking for the header. This may enable EAS to recognize
- * some files that it would ordinarily reject. The negative is that
- * it make take slightly longer to process the EAS_OpenFile request.
- *
- * Inputs:
- * pEASData - instance data handle
- * searchFlag - search flag (EAS_TRUE or EAS_FALSE)
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag)
-{
- pEASData->searchHeaderFlag = (EAS_BOOL8) searchFlag;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_SetPlayMode()
- *----------------------------------------------------------------------------
- * Some file formats support special play modes, such as iMode partial
- * play mode. This call can be used to change the play mode. The
- * default play mode (usually straight playback) is always zero.
- *
- * Inputs:
- * pEASData - instance data handle
- * handle - file or stream handle
- * playMode - play mode (see file parser for specifics)
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode)
-{
- return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PLAY_MODE, playMode);
-}
-
-#ifdef DLS_SYNTHESIZER
-/*----------------------------------------------------------------------------
- * EAS_LoadDLSCollection()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the location of the sound library.
- *
- * Inputs:
- * pEASData - instance data handle
- * pSoundLib - pointer to sound library
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_FILE_LOCATOR locator)
-{
- EAS_FILE_HANDLE fileHandle;
- EAS_RESULT result;
- EAS_DLSLIB_HANDLE pDLS;
-
- if (pStream != NULL)
- {
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- }
-
- /* open the file */
- if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS)
- return result;
-
- /* parse the file */
- result = DLSParser(pEASData->hwInstData, fileHandle, 0, &pDLS);
- EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
-
- if (result == EAS_SUCCESS)
- {
-
- /* if a stream pStream is specified, point it to the DLS collection */
- if (pStream)
- result = EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_DLS_COLLECTION, (EAS_I32) pDLS);
-
- /* global DLS load */
- else
- result = VMSetGlobalDLSLib(pEASData, pDLS);
- }
-
- return result;
-}
-#endif
-
-#ifdef EXTERNAL_AUDIO
-/*----------------------------------------------------------------------------
- * EAS_RegExtAudioCallback()
- *----------------------------------------------------------------------------
- * Purpose:
- * Registers callback functions for audio events.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- * cbProgChgFunc - pointer to host callback function for program change
- * cbEventFunc - pointer to host callback functio for note events
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData,
- EAS_HANDLE pStream,
- EAS_VOID_PTR pInstData,
- EAS_EXT_PRG_CHG_FUNC cbProgChgFunc,
- EAS_EXT_EVENT_FUNC cbEventFunc)
-{
- S_SYNTH *pSynth;
-
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
- return EAS_ERROR_INVALID_PARAMETER;
-
- if (pSynth == NULL)
- return EAS_ERROR_INVALID_PARAMETER;
-
- VMRegExtAudioCallback(pSynth, pInstData, cbProgChgFunc, cbEventFunc);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_GetMIDIControllers()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of MIDI controllers on the requested channel.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - file or stream handle
- * pControl - pointer to structure to receive data
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl)
-{
- S_SYNTH *pSynth;
-
- if (!EAS_StreamReady(pEASData, pStream))
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
- return EAS_ERROR_INVALID_PARAMETER;
-
- if (pSynth == NULL)
- return EAS_ERROR_INVALID_PARAMETER;
-
- VMGetMIDIControllers(pSynth, channel, pControl);
- return EAS_SUCCESS;
-}
-#endif
-
-#ifdef _SPLIT_ARCHITECTURE
-/*----------------------------------------------------------------------------
- * EAS_SetFrameBuffer()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the frame buffer pointer passed to the IPC communications functions
- *
- * Inputs:
- * pEASData - instance data handle
- * locator - file locator
- *
- * Outputs:
- *
- *
- * Side Effects:
- * May overlay instruments in the GM sound set
- *
- *----------------------------------------------------------------------------
-*/
-EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
-{
- if (pEASData->pVoiceMgr)
- pEASData->pVoiceMgr->pFrameBuffer = pFrameBuffer;
- return EAS_SUCCESS;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS_SearchFile
- *----------------------------------------------------------------------------
- * Search file for specific sequence starting at current file
- * position. Returns offset to start of sequence.
- *
- * Inputs:
- * pEASData - pointer to EAS persistent data object
- * fileHandle - file handle
- * searchString - pointer to search sequence
- * len - length of search sequence
- * pOffset - pointer to variable to store offset to sequence
- *
- * Returns EAS_EOF if end-of-file is reached
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset)
-{
- EAS_RESULT result;
- EAS_INT index;
- EAS_U8 c;
-
- *pOffset = -1;
- index = 0;
- for (;;)
- {
- result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c);
- if (result != EAS_SUCCESS)
- return result;
- if (c == searchString[index])
- {
- index++;
- if (index == 4)
- {
- result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset);
- if (result != EAS_SUCCESS)
- return result;
- *pOffset -= len;
- break;
- }
- }
- else
- index = 0;
- }
- return EAS_SUCCESS;
-}
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" +#include "eas_data.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_midi.h" +#include "eas_mixer.h" +#include "eas_build.h" +#include "eas_vm_protos.h" +#include "eas_math.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +/* number of events to parse before calling EAS_HWYield function */ +#define YIELD_EVENT_COUNT 10 + +/*---------------------------------------------------------------------------- + * easLibConfig + * + * This structure is available through the EAS public interface to allow + * the user to check the configuration of the library. + *---------------------------------------------------------------------------- +*/ +static const S_EAS_LIB_CONFIG easLibConfig = +{ + LIB_VERSION, +#ifdef _CHECKED_BUILD + EAS_TRUE, +#else + EAS_FALSE, +#endif + MAX_SYNTH_VOICES, + NUM_OUTPUT_CHANNELS, + _OUTPUT_SAMPLE_RATE, + BUFFER_SIZE_IN_MONO_SAMPLES, +#ifdef _FILTER_ENABLED + EAS_TRUE, +#else + EAS_FALSE, +#endif + _BUILD_TIME_, + _BUILD_VERSION_ +}; + +/* local prototypes */ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode); + +/*---------------------------------------------------------------------------- + * EAS_SetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * value - new value + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfSetData) + return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_GetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * pValue - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfGetData) + return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_StreamReady() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS) + return EAS_FALSE; + return (state < EAS_STATE_OPEN); +} + +/*---------------------------------------------------------------------------- + * EAS_IntSetStrmParam() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value) +{ + S_SYNTH *pSynth; + + /* try to set the parameter using stream interface */ + if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and set it directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + +#ifdef DLS_SYNTHESIZER + case PARSER_DATA_DLS_COLLECTION: + { + EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value); + if (result == EAS_SUCCESS) + { + DLSAddRef((S_DLS*) value); + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + } + return result; + } +#endif + + case PARSER_DATA_EAS_LIBRARY: + return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value); + + case PARSER_DATA_POLYPHONY: + return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_PRIORITY: + return VMSetPriority(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_TRANSPOSITION: + VMSetTranposition(pSynth, value); + break; + + case PARSER_DATA_VOLUME: + VMSetVolume(pSynth, (EAS_U16) value); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_IntGetStrmParam() + *---------------------------------------------------------------------------- + * This routine gets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_GetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * get the parameter directly on the synth. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntGetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 *pValue) +{ + S_SYNTH *pSynth; + + /* try to set the parameter */ + if (EAS_GetStreamParameter(pEASData, pStream, param, pValue) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and retrieve data directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + case PARSER_DATA_POLYPHONY: + return VMGetPolyphony(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_PRIORITY: + return VMGetPriority(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_TRANSPOSITION: + VMGetTranposition(pSynth, pValue); + break; + + case PARSER_DATA_NOTE_COUNT: + *pValue = VMGetNoteCount(pSynth); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_AllocateStream() + *---------------------------------------------------------------------------- + * Purpose: + * Allocates a stream handle + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData) +{ + EAS_INT streamNum; + + /* check for static allocation, only one stream allowed */ + if (pEASData->staticMemoryModel) + { + if (pEASData->streams[0].handle != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ } + return -1; + } + return 0; + } + + /* dynamic model */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].handle == NULL) + break; + if (streamNum == MAX_NUMBER_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ } + return -1; + } + return streamNum; +} + +/*---------------------------------------------------------------------------- + * EAS_InitStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize a stream + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle) +{ + pStream->pParserModule = pParserModule; + pStream->handle = streamHandle; + pStream->time = 0; + pStream->frameLength = AUDIO_FRAME_LENGTH; + pStream->repeatCount = 0; + pStream->volume = DEFAULT_STREAM_VOLUME; +} + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void) +{ + return &easLibConfig; +} + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * ppEASData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData) +{ + EAS_HW_DATA_HANDLE pHWInstData; + EAS_RESULT result; + S_EAS_DATA *pEASData; + EAS_INT module; + EAS_BOOL staticMemoryModel; + + /* get the memory model */ + staticMemoryModel = EAS_CMStaticMemoryModel(); + + /* initialize the host wrapper interface */ + *ppEASData = NULL; + if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS) + return result; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (staticMemoryModel) + pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA); + else + pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA)); + if (!pEASData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* initialize some data */ + EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA)); + pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel; + pEASData->hwInstData = pHWInstData; + pEASData->renderTime = 0; + + /* set header search flag */ +#ifdef FILE_HEADER_SEARCH + pEASData->searchHeaderFlag = EAS_TRUE; +#endif + + /* initalize parameters */ + EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME); + +#ifdef _METRICS_ENABLED + /* initalize the metrics module */ + pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS); + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ } + return result; + } + } +#endif + + /* initailize the voice manager & synthesizer */ + if ((result = VMInitialize(pEASData)) != EAS_SUCCESS) + return result; + + /* initialize mix engine */ + if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ } + return result; + } + + /* initialize effects modules */ + for (module = 0; module < NUM_EFFECTS_MODULES; module++) + { + pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module); + if (pEASData->effectsModules[module].effect != NULL) + { + if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ } + return result; + } + } + } + + /* initialize PCM engine */ + if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ } + return result; + } + + /* return instance data pointer to host */ + *ppEASData = pEASData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData) +{ + EAS_HW_DATA_HANDLE hwInstData; + EAS_RESULT result, reportResult; + EAS_INT i; + + /* establish pointers */ + hwInstData = pEASData->hwInstData; + + /* check for NULL handle */ + if (!pEASData) + return EAS_ERROR_HANDLE_INTEGRITY; + + /* if there are streams open, close them */ + reportResult = EAS_SUCCESS; + for (i = 0; i < MAX_NUMBER_STREAMS; i++) + { + if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle) + { + if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ } + reportResult = result; + } + } + } + + /* shutdown PCM engine */ + if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown mix engine */ + if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown effects modules */ + for (i = 0; i < NUM_EFFECTS_MODULES; i++) + { + if (pEASData->effectsModules[i].effect) + { + if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + } + + /* shutdown the voice manager & synthesizer */ + VMShutdown(pEASData); + +#ifdef _METRICS_ENABLED + /* shutdown the metrics module */ + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } +#endif + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(hwInstData, pEASData); + + /* shutdown host wrappers */ + if (hwInstData) + { + if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + return reportResult; +} + +#ifdef JET_INTERFACE +/*---------------------------------------------------------------------------- + * EAS_OpenJETStream() + *---------------------------------------------------------------------------- + * Private interface for JET to open an SMF stream with an offset + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for SMF parser */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0); + if (pParserModule == NULL) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* see if SMF parser recognizes the file */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + EAS_INT moduleNum; + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for file parsers */ + pParserModule = NULL; + *ppStream = NULL; + streamHandle = NULL; + for (moduleNum = 0; ; moduleNum++) + { + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum); + if (pParserModule == NULL) + break; + + /* see if this parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* rewind the file for the next parser */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS) + return result; + } + + /* no parser was able to recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* check if the tone control parser is available */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = EAS_CMEnumOptModules(EAS_MODULE_MMAPI_TONE_CONTROL); + if (pParserModule == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_MMAPIToneControl: ToneControl parser not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* see if ToneControl parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser accepted the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* parser did not recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFmtChunk - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_VOID_PTR *ppFmtChunk) +{ + EAS_RESULT result; + EAS_I32 value; + + if ((result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FORMAT, &value)) != EAS_SUCCESS) + return result; + *ppFmtChunk = (EAS_VOID_PTR) value; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 *pFileType) +{ + if (!EAS_StreamReady (pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FILE_TYPE, pFileType); +} + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + /* prepare the stream */ + if (state == EAS_STATE_OPEN) + { + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + result = (*pParserModule->pfPrepare)(pEASData, pStream->handle); + + /* set volume */ + if (result == EAS_SUCCESS) + result = EAS_SetVolume(pEASData, pStream, pStream->volume); + } + else + result = EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 voicesRendered; + EAS_STATE parserState; + EAS_INT streamNum; + + /* assume no samples generated and reset workload */ + *pNumGenerated = 0; + VMInitWorkload(pEASData->pVoiceMgr); + + /* no support for other buffer sizes yet */ + if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n", + (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ } + return EAS_BUFFER_SIZE_MISMATCH; + } + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + /* prep the frame buffer, do mix engine prep only if TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMStartFrame(pEASData)) + EAS_MixEnginePrep(pEASData, numRequested); +#else + /* prep the mix engine */ + EAS_MixEnginePrep(pEASData, numRequested); +#endif + + /* save the output buffer pointer */ + pEASData->pOutputAudioBuffer = pOut; + + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + + /* if we haven't finished parsing from last time, do it now */ + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + { + /* clear the locate flag */ + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE; + + if (pEASData->streams[streamNum].pParserModule) + { + + /* establish pointer to parser module */ + pParserModule = pEASData->streams[streamNum].pParserModule; + + /* handle pause */ + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE) + { + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE; + } + + /* get current state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + + /* handle resume */ + if (parserState == EAS_STATE_PAUSED) + { + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME) + { + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME; + } + } + + /* if necessary, parse stream */ + if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0) + if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS) + return result; + + /* check for an early abort */ + if ((pEASData->streams[streamNum].streamFlags) == 0) + { + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + return EAS_SUCCESS; + } + + /* check for repeat */ + if (pEASData->streams[streamNum].repeatCount) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState == EAS_STATE_STOPPED) + { + + /* decrement repeat count, unless it is negative */ + if (pEASData->streams[streamNum].repeatCount > 0) + pEASData->streams[streamNum].repeatCount--; + + /* reset the parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS) + return result; + pEASData->streams[streamNum].time = 0; + } + } + } + } + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the render timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); +#endif + + /* render audio */ + if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the render timer */ + if (pEASData->pMetricsData) { + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1); + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered); + (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered); + } +#endif + + //2 Do we really need frameParsed? + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].pParserModule != NULL) + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED; + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + + /* render PCM audio */ + if ((result = EAS_PERender(pEASData, numRequested)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_PERender returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the stream timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the post timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* for split architecture, send DSP vectors. Do post only if return is TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMEndFrame(pEASData)) + { + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; + } +#else + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; +#endif + +#ifdef _METRICS_ENABLED + /* stop the post timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* advance render time */ + pEASData->renderTime += AUDIO_FRAME_LENGTH; + +#if 0 + /* dump workload for debug */ + if (pEASData->pVoiceMgr->workload) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ } +#endif + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + { + PERF_TIMER temp; + temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); + + /* if max render time, record the number of voices and time */ + if ((*pEASData->pMetricsModule->pfRecordMaxValue) + (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp)) + { + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered); + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8)); + } + } +#endif + +#ifdef JET_INTERFACE + /* let JET to do its thing */ + if (pEASData->jetHandle != NULL) + { + result = JET_Process(pEASData); + if (result != EAS_SUCCESS) + return result; + } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * repeatCount - repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 repeatCount) +{ + pStream->repeatCount = repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pRepeatCount) +{ + *pRepeatCount = pStream->repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U32 rate) +{ + + /* check range */ + if ((rate < (1 << 27)) || (rate > (1 << 29))) + return EAS_ERROR_INVALID_PARAMETER; + + /* calculate new frame length + * + * NOTE: The maximum frame length we can accomodate based on a + * maximum rate of 2.0 (2^28) is 2047 (2^13-1). To accomodate a + * longer frame length or a higher maximum rate, the fixed point + * divide below will need to be adjusted + */ + pStream->frameLength = (AUDIO_FRAME_LENGTH * (rate >> 8)) >> 20; + + /* notify stream of new playback rate */ + EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_PLAYBACK_RATE, (EAS_I32) rate); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition) +{ + + /* check range */ + if ((transposition < -12) || (transposition > 12)) + return EAS_ERROR_INVALID_PARAMETER; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition); +} + +/*---------------------------------------------------------------------------- + * EAS_ParseEvents() + *---------------------------------------------------------------------------- + * Purpose: + * Parse events in the current streams until the desired time is reached. + * + * Inputs: + * pEASData - buffer for internal EAS data + * endTime - stop parsing if this time is reached + * parseMode - play, locate, or metadata + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 parserState; + EAS_BOOL done; + EAS_INT yieldCount = YIELD_EVENT_COUNT; + EAS_U32 time = 0; + + /* does this parser have a time function? */ + pParserModule = pStream->pParserModule; + if (pParserModule->pfTime == NULL) + { + /* check state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + /* if play state, advance time */ + if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING)) + pStream->time += pStream->frameLength; + done = EAS_TRUE; + } + + /* assume we're not done, in case we abort out */ + else + { + pStream->streamFlags &= ~STREAM_FLAGS_PARSED; + done = EAS_FALSE; + } + + while (!done) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState > EAS_STATE_PLAY) + { + /* save current time if we're not in play mode */ + if (parseMode != eParserModePlay) + pStream->time = time << 8; + done = EAS_TRUE; + break; + } + + /* get the next event time */ + if (pParserModule->pfTime) + { + if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS) + return result; + + /* if next event is within this frame, parse it */ + if (time < (endTime >> 8)) + { + + /* parse the next event */ + if (pParserModule->pfEvent) + if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS) + return result; + } + + /* no more events in this frame, advance time */ + else + { + pStream->time = endTime; + done = EAS_TRUE; + } + } + + /* check for max workload exceeded */ + if (VMCheckWorkload(pEASData->pVoiceMgr)) + { + /* stop even though we may not have parsed + * all the events in this frame. The parser will try to + * catch up on the next frame. + */ + break; + } + + /* give host a chance for an early abort */ + if (--yieldCount == 0) + { + if (EAS_HWYield(pEASData->hwInstData)) + break; + yieldCount = YIELD_EVENT_COUNT; + } + } + + /* if no early abort, parsing is complete for this frame */ + if (done) + pStream->streamFlags |= STREAM_FLAGS_PARSED; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check parser state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* if parser has metadata function, use that */ + if (pParserModule->pfGetMetaData != NULL) + return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength); + + /* reset the parser to the beginning */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + + /* parse the file to end */ + pStream->time = 0; + VMInitWorkload(pEASData->pVoiceMgr); + if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS) + return result; + + /* get the parser time */ + if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS) + return result; + + /* reset the parser to the beginning */ + pStream->time = 0; + return (*pParserModule->pfReset)(pEASData, pStream->handle); +} + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData) +{ + S_METADATA_CB metadata; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* register callback function */ + metadata.callback = cbFunc; + metadata.buffer = metaDataBuffer; + metadata.bufferSize = metaDataBufSize; + metadata.pUserData = pUserData; + return EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_METADATA_CB, (EAS_I32) &metadata); +} + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_NOTE_COUNT, pNoteCount); +} + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the close function */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + result = (*pParserModule->pfClose)(pEASData, pStream->handle); + + /* clear the handle and parser interface pointer */ + pStream->handle = NULL; + pStream->pParserModule = NULL; + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to variable to hold file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *ppStream, EAS_HANDLE streamHandle) +{ + EAS_RESULT result; + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_INT streamNum; + + /* initialize some pointers */ + *ppStream = NULL; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (pEASData->staticMemoryModel) + pMIDIStream = EAS_CMEnumData(EAS_CM_MIDI_STREAM_DATA); + else + pMIDIStream = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_INTERACTIVE_MIDI)); + + /* allocate dynamic memory */ + if (!pMIDIStream) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate MIDI stream data\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet(pMIDIStream, 0, sizeof(S_INTERACTIVE_MIDI)); + EAS_InitStream(&pEASData->streams[streamNum], NULL, pMIDIStream); + + /* instantiate a new synthesizer */ + if (streamHandle == NULL) + { + result = VMInitMIDI(pEASData, &pMIDIStream->pSynth); + } + + /* use an existing synthesizer */ + else + { + EAS_I32 value; + result = EAS_GetStreamParameter(pEASData, streamHandle, PARSER_DATA_SYNTH_HANDLE, &value); + pMIDIStream->pSynth = (S_SYNTH*) value; + VMIncRefCount(pMIDIStream->pSynth); + } + if (result != EAS_SUCCESS) + { + EAS_CloseMIDIStream(pEASData, &pEASData->streams[streamNum]); + return result; + } + + /* initialize the MIDI stream data */ + EAS_InitMIDIStream(&pMIDIStream->stream); + + *ppStream = (EAS_HANDLE) &pEASData->streams[streamNum]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 *pBuffer, EAS_I32 count) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_RESULT result; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + /* send the entire buffer */ + while (count--) + { + if ((result = EAS_ParseMIDIStream(pEASData, pMIDIStream->pSynth, &pMIDIStream->stream, *pBuffer++, eParserModePlay)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + /* close synth */ + if (pMIDIStream->pSynth != NULL) + { + VMMIDIShutdown(pEASData, pMIDIStream->pSynth); + pMIDIStream->pSynth = NULL; + } + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(((S_EAS_DATA*) pEASData)->hwInstData, pMIDIStream); + + pStream->handle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the parser to return state */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS) + return result; + + /* if repeat count is set for this parser, mask the stopped state from the application */ + if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED)) + *pState = EAS_STATE_PLAY; + + /* if we're not ready or playing, we don't need to hide state from host */ + if (*pState > EAS_STATE_PLAY) + return EAS_SUCCESS; + + /* if stream is about to be paused, report it as paused */ + if (pStream->streamFlags & STREAM_FLAGS_PAUSE) + { + if (pStream->streamFlags & STREAM_FLAGS_LOCATE) + *pState = EAS_STATE_PAUSED; + else + *pState = EAS_STATE_PAUSING; + } + + /* if stream is about to resume, report it as playing */ + if (pStream->streamFlags & STREAM_FLAGS_RESUME) + *pState = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. A value of 0 allows the stream + * to use all voices (set by EAS_SetSynthPolyphony). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 polyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPolyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synth . Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount) +{ + return VMSetSynthPolyphony(pEASData->pVoiceMgr, synthNum, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synth + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount) +{ + return VMGetSynthPolyphony(pEASData->pVoiceMgr, synthNum, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-15, lower values are higher + * priority. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 priority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, priority); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPriority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, pPriority); +} + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master gain for the mix engine in 1dB increments + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master gain (100 is max) + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume) +{ + EAS_I16 gain; + + /* check range */ + if ((volume < 0) || (volume > EAS_MAX_VOLUME)) + return EAS_ERROR_PARAMETER_RANGE; + + /* stream volume */ + if (pStream != NULL) + { + EAS_I32 gainOffset; + EAS_RESULT result; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* get gain offset */ + pStream->volume = (EAS_U8) volume; + result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset); + if (result == EAS_SUCCESS) + volume += gainOffset; + + /* set stream volume */ + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + + /* convert to linear scalar */ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain); + } + + /* master volume */ + pEASData->masterVolume = (EAS_U8) volume; +#if (NUM_OUTPUT_CHANNELS == 1) + /* leave 3dB headroom for mono output */ + volume -= 3; +#endif + + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + pEASData->masterGain = gain; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the synthesizer. The default volume setting is + * 50. The volume range is 0 to 100; + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + if (pStream == NULL) + return pEASData->masterVolume; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return pStream->volume; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad) +{ + VMSetWorkload(pEASData->pVoiceMgr, maxLoad); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_MAX_PCM_STREAMS, maxNumStreams); +} + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_U32 requestedTime; + EAS_STATE state; + + /* get pointer to parser function table */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* handle offset and limit to start of file */ + /*lint -e{704} use shift for performance*/ + if (offset) + milliseconds += (EAS_I32) pStream->time >> 8; + if (milliseconds < 0) + milliseconds = 0; + + /* check to see if the request is different from the current time */ + requestedTime = (EAS_U32) milliseconds; + if (requestedTime == (pStream->time >> 8)) + return EAS_SUCCESS; + + /* set the locate flag */ + pStream->streamFlags |= STREAM_FLAGS_LOCATE; + + /* use the parser locate function, if available */ + if (pParserModule->pfLocate != NULL) + { + EAS_BOOL parserLocate = EAS_FALSE; + result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate); + if (!parserLocate) + { + if (result == EAS_SUCCESS) + pStream->time = requestedTime << 8; + return result; + } + } + + /* if we were paused and not going to resume, set pause request flag */ + if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + + /* reset the synth and parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + pStream->time = 0; + + /* locating forward, clear parsed flag and parse data until we get to the requested location */ + if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + *pTime = pStream->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime) +{ + *pTime = pEASData->renderTime >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements pause */ + if (pParserModule->pfPause == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear resume flag */ + pStream->streamFlags &= ~STREAM_FLAGS_RESUME; + + /* set pause flag */ + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + +#if 0 + /* pause the stream */ + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements this function */ + if (pParserModule->pfResume == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear pause flag */ + pStream->streamFlags &= ~STREAM_FLAGS_PAUSE; + + /* set resume flag */ + pStream->streamFlags |= STREAM_FLAGS_RESUME; + +#if 0 + /* resume the stream */ + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFGetParam) + (pEASData->effectsModules[module].effectData, param, pValue); +} + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFSetParam) + (pEASData->effectsModules[module].effectData, param, value); +} + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the metrics interface. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData) +{ + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData); +} + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Resets the metrics. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData) +{ + + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData); +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_SNDLIB_HANDLE pSndLib) +{ + if (pStream) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_EAS_LIBRARY, (EAS_I32) pSndLib); + } + + return VMSetGlobalEASLib(pEASData->pVoiceMgr, pSndLib); +} + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag) +{ + pEASData->searchHeaderFlag = (EAS_BOOL8) searchFlag; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see file parser for specifics) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode) +{ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PLAY_MODE, playMode); +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_FILE_LOCATOR locator) +{ + EAS_FILE_HANDLE fileHandle; + EAS_RESULT result; + EAS_DLSLIB_HANDLE pDLS; + + if (pStream != NULL) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* parse the file */ + result = DLSParser(pEASData->hwInstData, fileHandle, 0, &pDLS); + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + + if (result == EAS_SUCCESS) + { + + /* if a stream pStream is specified, point it to the DLS collection */ + if (pStream) + result = EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_DLS_COLLECTION, (EAS_I32) pDLS); + + /* global DLS load */ + else + result = VMSetGlobalDLSLib(pEASData, pDLS); + } + + return result; +} +#endif + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMRegExtAudioCallback(pSynth, pInstData, cbProgChgFunc, cbEventFunc); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMGetMIDIControllers(pSynth, channel, pControl); + return EAS_SUCCESS; +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + if (pEASData->pVoiceMgr) + pEASData->pVoiceMgr->pFrameBuffer = pFrameBuffer; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset) +{ + EAS_RESULT result; + EAS_INT index; + EAS_U8 c; + + *pOffset = -1; + index = 0; + for (;;) + { + result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c); + if (result != EAS_SUCCESS) + return result; + if (c == searchString[index]) + { + index++; + if (index == 4) + { + result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset); + if (result != EAS_SUCCESS) + return result; + *pOffset -= len; + break; + } + } + else + index = 0; + } + return EAS_SUCCESS; +} + + diff --git a/arm-fm-22k/lib_src/eas_reverb.c b/arm-fm-22k/lib_src/eas_reverb.c index 6d99862..cd5befe 100644 --- a/arm-fm-22k/lib_src/eas_reverb.c +++ b/arm-fm-22k/lib_src/eas_reverb.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_reverb.c
- *
- * Contents and purpose:
- * Contains the implementation of the Reverb effect.
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.c + * + * Contents and purpose: + * Contains the implementation of the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,1135 +20,1135 @@ * 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: 510 $
- * $Date: 2006-12-19 01:47:33 -0800 (Tue, 19 Dec 2006) $
- *----------------------------------------------------------------------------
-*/
-
-/*------------------------------------
- * includes
- *------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_effects.h"
-#include "eas_math.h"
-#include "eas_reverbdata.h"
-#include "eas_reverb.h"
-#include "eas_config.h"
-#include "eas_host.h"
-#include "eas_report.h"
-
-/* prototypes for effects interface */
-static EAS_RESULT ReverbInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData);
-static void ReverbProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples);
-static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-
-/* common effects interface for configuration module */
-const S_EFFECTS_INTERFACE EAS_Reverb =
-{
- ReverbInit,
- ReverbProcess,
- ReverbShutdown,
- ReverbGetParam,
- ReverbSetParam
-};
-
-
-
-/*----------------------------------------------------------------------------
- * InitializeReverb()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbInit(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData)
-{
- EAS_I32 i;
- EAS_U16 nOffset;
- EAS_INT temp;
-
- S_REVERB_OBJECT *pReverbData;
- S_REVERB_PRESET *pPreset;
-
- /* check Configuration Module for data allocation */
- if (pEASData->staticMemoryModel)
- pReverbData = EAS_CMEnumFXData(EAS_MODULE_REVERB);
-
- /* allocate dynamic memory */
- else
- pReverbData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_REVERB_OBJECT));
-
- if (pReverbData == NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Reverb memory\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
-
- /* clear the structure */
- EAS_HWMemSet(pReverbData, 0, sizeof(S_REVERB_OBJECT));
-
- ReverbReadInPresets(pReverbData);
-
- pReverbData->m_nMinSamplesToAdd = REVERB_UPDATE_PERIOD_IN_SAMPLES;
-
- pReverbData->m_nRevOutFbkR = 0;
- pReverbData->m_nRevOutFbkL = 0;
-
- pReverbData->m_sAp0.m_zApIn = AP0_IN;
- pReverbData->m_sAp0.m_zApOut = AP0_IN + DEFAULT_AP0_LENGTH;
- pReverbData->m_sAp0.m_nApGain = DEFAULT_AP0_GAIN;
-
- pReverbData->m_zD0In = DELAY0_IN;
-
- pReverbData->m_sAp1.m_zApIn = AP1_IN;
- pReverbData->m_sAp1.m_zApOut = AP1_IN + DEFAULT_AP1_LENGTH;
- pReverbData->m_sAp1.m_nApGain = DEFAULT_AP1_GAIN;
-
- pReverbData->m_zD1In = DELAY1_IN;
-
- pReverbData->m_zLpf0 = 0;
- pReverbData->m_zLpf1 = 0;
- pReverbData->m_nLpfFwd = 8837;
- pReverbData->m_nLpfFbk = 6494;
-
- pReverbData->m_nSin = 0;
- pReverbData->m_nCos = 0;
- pReverbData->m_nSinIncrement = 0;
- pReverbData->m_nCosIncrement = 0;
-
- // set xfade parameters
- pReverbData->m_nXfadeInterval = (EAS_U16)REVERB_XFADE_PERIOD_IN_SAMPLES;
- pReverbData->m_nXfadeCounter = pReverbData->m_nXfadeInterval + 1; // force update on first iteration
- pReverbData->m_nPhase = -32768;
- pReverbData->m_nPhaseIncrement = REVERB_XFADE_PHASE_INCREMENT;
-
- pReverbData->m_nNoise = (EAS_I16)0xABCD;
-
- pReverbData->m_nMaxExcursion = 0x007F;
-
- // set delay tap lengths
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion,
- &pReverbData->m_nNoise );
-
- pReverbData->m_zD1Cross =
- DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset;
-
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion,
- &pReverbData->m_nNoise );
-
- pReverbData->m_zD0Cross =
- DELAY1_OUT - pReverbData->m_nMaxExcursion - nOffset;
-
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion,
- &pReverbData->m_nNoise );
-
- pReverbData->m_zD0Self =
- DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset;
-
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion,
- &pReverbData->m_nNoise );
-
- pReverbData->m_zD1Self =
- DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset;
-
- // for debugging purposes, allow noise generator
- pReverbData->m_bUseNoise = EAS_FALSE;
-
- // for debugging purposes, allow bypass
- pReverbData->m_bBypass = EAS_TRUE; //EAS_FALSE;
-
- pReverbData->m_nNextRoom = 1;
-
- pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom + 1; // force update on first iteration
-
- pReverbData->m_nWet = REVERB_DEFAULT_WET;
-
- pReverbData->m_nDry = REVERB_DEFAULT_DRY;
-
- // set base index into circular buffer
- pReverbData->m_nBaseIndex = 0;
-
- // set the early reflections, L
- pReverbData->m_sEarlyL.m_nLpfFbk = 4915;
- pReverbData->m_sEarlyL.m_nLpfFwd = 27852;
- pReverbData->m_sEarlyL.m_zLpf = 0;
-
- for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++)
- {
- pReverbData->m_sEarlyL.m_nGain[i] = 0;
- pReverbData->m_sEarlyL.m_zDelay[i] = 0;
- }
-
- // set the early reflections, R
- pReverbData->m_sEarlyR.m_nLpfFbk = 4915;
- pReverbData->m_sEarlyR.m_nLpfFwd = 27852;
- pReverbData->m_sEarlyR.m_zLpf = 0;
-
- for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++)
- {
- pReverbData->m_sEarlyR.m_nGain[i] = 0;
- pReverbData->m_sEarlyR.m_zDelay[i] = 0;
- }
-
- // clear the reverb delay line
- for (i=0; i < REVERB_BUFFER_SIZE_IN_SAMPLES; i++)
- {
- pReverbData->m_nDelayLine[i] = 0;
- }
-
- ////////////////////////////////
- ///code from the EAS DEMO Reverb
- //now copy from the new preset into the reverb
- pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom];
-
- pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk;
- pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd;
-
- pReverbData->m_nEarly = pPreset->m_nEarly;
- pReverbData->m_nWet = pPreset->m_nWet;
- pReverbData->m_nDry = pPreset->m_nDry;
-
- pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion;
- //stored as time based, convert to sample based
- temp = pPreset->m_nXfadeInterval;
- /*lint -e{702} shift for performance */
- temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16;
- pReverbData->m_nXfadeInterval = (EAS_U16) temp;
- //gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval;
-
- pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain;
- //stored as time based, convert to absolute sample value
- temp = pPreset->m_nAp0_ApOut;
- /*lint -e{702} shift for performance */
- temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16;
- pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp);
- //gsReverbObject.m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut;
-
- pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain;
- //stored as time based, convert to absolute sample value
- temp = pPreset->m_nAp1_ApOut;
- /*lint -e{702} shift for performance */
- temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16;
- pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp);
- //gsReverbObject.m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut;
- ///code from the EAS DEMO Reverb
- ////////////////////////////////
-
- *pInstData = pReverbData;
-
- return EAS_SUCCESS;
-
-} /* end InitializeReverb */
-
-
-
-/*----------------------------------------------------------------------------
- * ReverbProcess()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reverberate the requested number of samples (block based processing)
- *
- * Inputs:
- * pInputBuffer - src buffer
- * pOutputBuffer - dst buffer
- * nNumSamplesToAdd - number of samples to write to buffer
- *
- * Outputs:
- * number of samples actually written to buffer
- *
- * Side Effects:
- * - samples are added to the presently free buffer
- *
- *----------------------------------------------------------------------------
-*/
-static void ReverbProcess(EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples)
-{
- S_REVERB_OBJECT *pReverbData;
-
- pReverbData = (S_REVERB_OBJECT*) pInstData;
-
- //if bypassed or the preset forces the signal to be completely dry
- if (pReverbData->m_bBypass ||
- (pReverbData->m_nWet == 0 && pReverbData->m_nDry == 32767))
- {
- if (pSrc != pDst)
- EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM));
- return;
- }
-
- if (pReverbData->m_nNextRoom != pReverbData->m_nCurrentRoom)
- {
- ReverbUpdateRoom(pReverbData);
- }
-
- ReverbUpdateXfade(pReverbData, numSamples);
-
- Reverb(pReverbData, numSamples, pDst, pSrc);
-
- /* check if update counter needs to be reset */
- if (pReverbData->m_nUpdateCounter >= REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES)
- {
- /* update interval has elapsed, so reset counter */
- pReverbData->m_nUpdateCounter = 0;
- } /* end if m_nUpdateCounter >= update interval */
-
- /* increment update counter */
- pReverbData->m_nUpdateCounter += (EAS_I16)numSamples;
-
-} /* end ComputeReverb */
-
-/*----------------------------------------------------------------------------
- * ReverbUpdateXfade
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the xfade parameters as required
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to write to buffer
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - xfade parameters will be changed
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd)
-{
- EAS_U16 nOffset;
- EAS_I16 tempCos;
- EAS_I16 tempSin;
-
- if (pReverbData->m_nXfadeCounter >= pReverbData->m_nXfadeInterval)
- {
- /* update interval has elapsed, so reset counter */
- pReverbData->m_nXfadeCounter = 0;
-
- // Pin the sin,cos values to min / max values to ensure that the
- // modulated taps' coefs are zero (thus no clicks)
- if (pReverbData->m_nPhaseIncrement > 0)
- {
- // if phase increment > 0, then sin -> 1, cos -> 0
- pReverbData->m_nSin = 32767;
- pReverbData->m_nCos = 0;
-
- // reset the phase to match the sin, cos values
- pReverbData->m_nPhase = 32767;
-
- // modulate the cross taps because their tap coefs are zero
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise );
-
- pReverbData->m_zD1Cross =
- DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset;
-
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise );
-
- pReverbData->m_zD0Cross =
- DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset;
- }
- else
- {
- // if phase increment < 0, then sin -> 0, cos -> 1
- pReverbData->m_nSin = 0;
- pReverbData->m_nCos = 32767;
-
- // reset the phase to match the sin, cos values
- pReverbData->m_nPhase = -32768;
-
- // modulate the self taps because their tap coefs are zero
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise );
-
- pReverbData->m_zD0Self =
- DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset;
-
- nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise );
-
- pReverbData->m_zD1Self =
- DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset;
-
- } // end if-else (pReverbData->m_nPhaseIncrement > 0)
-
- // Reverse the direction of the sin,cos so that the
- // tap whose coef was previously increasing now decreases
- // and vice versa
- pReverbData->m_nPhaseIncrement = -pReverbData->m_nPhaseIncrement;
-
- } // end if counter >= update interval
-
- //compute what phase will be next time
- pReverbData->m_nPhase += pReverbData->m_nPhaseIncrement;
-
- //calculate what the new sin and cos need to reach by the next update
- ReverbCalculateSinCos(pReverbData->m_nPhase, &tempSin, &tempCos);
-
- //calculate the per-sample increment required to get there by the next update
- /*lint -e{702} shift for performance */
- pReverbData->m_nSinIncrement =
- (tempSin - pReverbData->m_nSin) >> REVERB_UPDATE_PERIOD_IN_BITS;
-
- /*lint -e{702} shift for performance */
- pReverbData->m_nCosIncrement =
- (tempCos - pReverbData->m_nCos) >> REVERB_UPDATE_PERIOD_IN_BITS;
-
-
- /* increment update counter */
- pReverbData->m_nXfadeCounter += (EAS_U16) nNumSamplesToAdd;
-
- return EAS_SUCCESS;
-
-} /* end ReverbUpdateXfade */
-
-
-/*----------------------------------------------------------------------------
- * ReverbCalculateNoise
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate a noise sample and limit its value
- *
- * Inputs:
- * nMaxExcursion - noise value is limited to this value
- * pnNoise - return new noise sample in this (not limited)
- *
- * Outputs:
- * new limited noise value
- *
- * Side Effects:
- * - *pnNoise noise value is updated
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise)
-{
- // calculate new noise value
- *pnNoise = (EAS_I16) (*pnNoise * 5 + 1);
-
-#if 0 // 1xxx, test
- *pnNoise = 0;
-#endif // 1xxx, test
-
- // return the limited noise value
- return (nMaxExcursion & (*pnNoise));
-
-} /* end ReverbCalculateNoise */
-
-/*----------------------------------------------------------------------------
- * ReverbCalculateSinCos
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate a new sin and cosine value based on the given phase
- *
- * Inputs:
- * nPhase - phase angle
- * pnSin - input old value, output new value
- * pnCos - input old value, output new value
- *
- * Outputs:
- *
- * Side Effects:
- * - *pnSin, *pnCos are updated
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos)
-{
- EAS_I32 nTemp;
- EAS_I32 nNetAngle;
-
- // -1 <= nPhase < 1
- // However, for the calculation, we need a value
- // that ranges from -1/2 to +1/2, so divide the phase by 2
- /*lint -e{702} shift for performance */
- nNetAngle = nPhase >> 1;
-
- /*
- Implement the following
- sin(x) = (2-4*c)*x^2 + c + x
- cos(x) = (2-4*c)*x^2 + c - x
-
- where c = 1/sqrt(2)
- using the a0 + x*(a1 + x*a2) approach
- */
-
- /* limit the input "angle" to be between -0.5 and +0.5 */
- if (nNetAngle > EG1_HALF)
- {
- nNetAngle = EG1_HALF;
- }
- else if (nNetAngle < EG1_MINUS_HALF)
- {
- nNetAngle = EG1_MINUS_HALF;
- }
-
- /* calculate sin */
- nTemp = EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle);
- nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle);
- *pnSin = (EAS_I16) SATURATE_EG1(nTemp);
-
- /* calculate cos */
- nTemp = -EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle);
- nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle);
- *pnCos = (EAS_I16) SATURATE_EG1(nTemp);
-
- return EAS_SUCCESS;
-} /* end ReverbCalculateSinCos */
-
-/*----------------------------------------------------------------------------
- * Reverb
- *----------------------------------------------------------------------------
- * Purpose:
- * apply reverb to the given signal
- *
- * Inputs:
- * nNu
- * pnSin - input old value, output new value
- * pnCos - input old value, output new value
- *
- * Outputs:
- * number of samples actually reverberated
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT Reverb(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer)
-{
- EAS_I32 i;
- EAS_I32 nDelayOut;
- EAS_U16 nBase;
-
- EAS_U32 nAddr;
- EAS_I32 nTemp1;
- EAS_I32 nTemp2;
- EAS_I32 nApIn;
- EAS_I32 nApOut;
-
- EAS_I32 j;
- EAS_I32 nEarlyOut;
-
- EAS_I32 tempValue;
-
-
- // get the base address
- nBase = pReverbData->m_nBaseIndex;
-
- for (i=0; i < nNumSamplesToAdd; i++)
- {
- // ********** Left Allpass - start
- // left input = (left dry/4) + right feedback from previous period
- /*lint -e{702} use shift for performance */
- nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkR;
-// nApIn = *pInputBuffer++; // 1xxx test and debug ap
-
- // fetch allpass delay line out
- //nAddr = CIRCULAR(nBase, psAp0->m_zApOut, REVERB_BUFFER_MASK);
- nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApOut, REVERB_BUFFER_MASK);
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate allpass feedforward; subtract the feedforward result
- nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp0.m_nApGain);
- nApOut = SATURATE(nDelayOut - nTemp1); // allpass output
-
- // calculate allpass feedback; add the feedback result
- nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp0.m_nApGain);
- nTemp1 = SATURATE(nApIn + nTemp1);
-
- // inject into allpass delay
- nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApIn, REVERB_BUFFER_MASK);
- pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1;
-
- // inject allpass output into delay line
- nAddr = CIRCULAR(nBase, pReverbData->m_zD0In, REVERB_BUFFER_MASK);
- pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut;
-
- // ********** Left Allpass - end
-
- // ********** Right Allpass - start
- // right input = (right dry/4) + left feedback from previous period
- /*lint -e{702} use shift for performance */
- nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkL;
-// nApIn = *pInputBuffer++; // 1xxx test and debug ap
-
- // fetch allpass delay line out
- nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApOut, REVERB_BUFFER_MASK);
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate allpass feedforward; subtract the feedforward result
- nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp1.m_nApGain);
- nApOut = SATURATE(nDelayOut - nTemp1); // allpass output
-
- // calculate allpass feedback; add the feedback result
- nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp1.m_nApGain);
- nTemp1 = SATURATE(nApIn + nTemp1);
-
- // inject into allpass delay
- nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApIn, REVERB_BUFFER_MASK);
- pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1;
-
- // inject allpass output into delay line
- nAddr = CIRCULAR(nBase, pReverbData->m_zD1In, REVERB_BUFFER_MASK);
- pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut;
-
- // ********** Right Allpass - end
-
- // ********** D0 output - start
- // fetch delay line self out
- nAddr = CIRCULAR(nBase, pReverbData->m_zD0Self, REVERB_BUFFER_MASK);
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate delay line self out
- nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin);
-
- // fetch delay line cross out
- nAddr = CIRCULAR(nBase, pReverbData->m_zD1Cross, REVERB_BUFFER_MASK);
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate delay line self out
- nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos);
-
- // calculate unfiltered delay out
- nDelayOut = SATURATE(nTemp1 + nTemp2);
-
- // calculate lowpass filter (mixer scale factor included in LPF feedforward)
- nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd);
-
- nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf0, pReverbData->m_nLpfFbk);
-
- // calculate filtered delay out and simultaneously update LPF state variable
- // filtered delay output is stored in m_zLpf0
- pReverbData->m_zLpf0 = (EAS_PCM) SATURATE(nTemp1 + nTemp2);
-
- // ********** D0 output - end
-
- // ********** D1 output - start
- // fetch delay line self out
- nAddr = CIRCULAR(nBase, pReverbData->m_zD1Self, REVERB_BUFFER_MASK);
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate delay line self out
- nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin);
-
- // fetch delay line cross out
- nAddr = CIRCULAR(nBase, pReverbData->m_zD0Cross, REVERB_BUFFER_MASK);
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate delay line self out
- nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos);
-
- // calculate unfiltered delay out
- nDelayOut = SATURATE(nTemp1 + nTemp2);
-
- // calculate lowpass filter (mixer scale factor included in LPF feedforward)
- nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd);
-
- nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf1, pReverbData->m_nLpfFbk);
-
- // calculate filtered delay out and simultaneously update LPF state variable
- // filtered delay output is stored in m_zLpf1
- pReverbData->m_zLpf1 = (EAS_PCM)SATURATE(nTemp1 + nTemp2);
-
- // ********** D1 output - end
-
- // ********** mixer and feedback - start
- // sum is fedback to right input (R + L)
- pReverbData->m_nRevOutFbkL =
- (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 + (EAS_I32)pReverbData->m_zLpf0);
-
- // difference is feedback to left input (R - L)
- /*lint -e{685} lint complains that it can't saturate negative */
- pReverbData->m_nRevOutFbkR =
- (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 - (EAS_I32)pReverbData->m_zLpf0);
-
- // ********** mixer and feedback - end
-
- // ********** start early reflection generator, left
- //psEarly = &(pReverbData->m_sEarlyL);
-
- nEarlyOut = 0;
-
- for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
- {
- // fetch delay line out
- //nAddr = CIRCULAR(nBase, psEarly->m_zDelay[j], REVERB_BUFFER_MASK);
- nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyL.m_zDelay[j], REVERB_BUFFER_MASK);
-
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate reflection
- //nTemp1 = MULT_EG1_EG1(nDelayOut, psEarly->m_nGain[j]);
- nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyL.m_nGain[j]);
-
- nEarlyOut = SATURATE(nEarlyOut + nTemp1);
-
- } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
-
- // apply lowpass to early reflections
- //nTemp1 = MULT_EG1_EG1(nEarlyOut, psEarly->m_nLpfFwd);
- nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyL.m_nLpfFwd);
-
- //nTemp2 = MULT_EG1_EG1(psEarly->m_zLpf, psEarly->m_nLpfFbk);
- nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyL.m_zLpf, pReverbData->m_sEarlyL.m_nLpfFbk);
-
-
- // calculate filtered out and simultaneously update LPF state variable
- // filtered output is stored in m_zLpf1
- //psEarly->m_zLpf = SATURATE(nTemp1 + nTemp2);
- pReverbData->m_sEarlyL.m_zLpf = (EAS_PCM) SATURATE(nTemp1 + nTemp2);
-
- // combine filtered early and late reflections for output
- //*pOutputBuffer++ = inL;
- //tempValue = SATURATE(psEarly->m_zLpf + pReverbData->m_nRevOutFbkL);
- tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyL.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkL);
- //scale reverb output by wet level
- /*lint -e{701} use shift for performance */
- tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet<<1));
- //sum with output buffer
- tempValue += *pOutputBuffer;
- *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue);
-
- // ********** end early reflection generator, left
-
- // ********** start early reflection generator, right
- //psEarly = &(pReverbData->m_sEarlyR);
-
- nEarlyOut = 0;
-
- for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
- {
- // fetch delay line out
- nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyR.m_zDelay[j], REVERB_BUFFER_MASK);
- nDelayOut = pReverbData->m_nDelayLine[nAddr];
-
- // calculate reflection
- nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyR.m_nGain[j]);
-
- nEarlyOut = SATURATE(nEarlyOut + nTemp1);
-
- } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
-
- // apply lowpass to early reflections
- nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyR.m_nLpfFwd);
-
- nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyR.m_zLpf, pReverbData->m_sEarlyR.m_nLpfFbk);
-
- // calculate filtered out and simultaneously update LPF state variable
- // filtered output is stored in m_zLpf1
- pReverbData->m_sEarlyR.m_zLpf = (EAS_PCM)SATURATE(nTemp1 + nTemp2);
-
- // combine filtered early and late reflections for output
- //*pOutputBuffer++ = inR;
- tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyR.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkR);
- //scale reverb output by wet level
- /*lint -e{701} use shift for performance */
- tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet << 1));
- //sum with output buffer
- tempValue = tempValue + *pOutputBuffer;
- *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue);
-
- // ********** end early reflection generator, right
-
- // decrement base addr for next sample period
- nBase--;
-
- pReverbData->m_nSin += pReverbData->m_nSinIncrement;
- pReverbData->m_nCos += pReverbData->m_nCosIncrement;
-
- } // end for (i=0; i < nNumSamplesToAdd; i++)
-
- // store the most up to date version
- pReverbData->m_nBaseIndex = nBase;
-
- return EAS_SUCCESS;
-} /* end Reverb */
-
-
-
-/*----------------------------------------------------------------------------
- * ReverbShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the Reverb effect.
- *
- * Inputs:
- * pInstData - handle to instance data
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData)
-{
- /* check Configuration Module for static memory allocation */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pInstData);
- return EAS_SUCCESS;
-} /* end ReverbShutdown */
-
-/*----------------------------------------------------------------------------
- * ReverbGetParam()
- *----------------------------------------------------------------------------
- * Purpose:
- * Get a Reverb parameter
- *
- * Inputs:
- * pInstData - handle to instance data
- * param - parameter index
- * *pValue - pointer to variable to hold retrieved value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_REVERB_OBJECT *p;
-
- p = (S_REVERB_OBJECT*) pInstData;
-
- switch (param)
- {
- case EAS_PARAM_REVERB_BYPASS:
- *pValue = (EAS_I32) p->m_bBypass;
- break;
- case EAS_PARAM_REVERB_PRESET:
- *pValue = (EAS_I8) p->m_nCurrentRoom;
- break;
- case EAS_PARAM_REVERB_WET:
- *pValue = p->m_nWet;
- break;
- case EAS_PARAM_REVERB_DRY:
- *pValue = p->m_nDry;
- break;
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
- return EAS_SUCCESS;
-} /* end ReverbGetParam */
-
-
-/*----------------------------------------------------------------------------
- * ReverbSetParam()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set a Reverb parameter
- *
- * Inputs:
- * pInstData - handle to instance data
- * param - parameter index
- * *pValue - new paramter value
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_REVERB_OBJECT *p;
-
- p = (S_REVERB_OBJECT*) pInstData;
-
- switch (param)
- {
- case EAS_PARAM_REVERB_BYPASS:
- p->m_bBypass = (EAS_BOOL) value;
- break;
- case EAS_PARAM_REVERB_PRESET:
- if(value!=EAS_PARAM_REVERB_LARGE_HALL && value!=EAS_PARAM_REVERB_HALL &&
- value!=EAS_PARAM_REVERB_CHAMBER && value!=EAS_PARAM_REVERB_ROOM)
- return EAS_ERROR_INVALID_PARAMETER;
- p->m_nNextRoom = (EAS_I16)value;
- break;
- case EAS_PARAM_REVERB_WET:
- if(value>EAS_REVERB_WET_MAX || value<EAS_REVERB_WET_MIN)
- return EAS_ERROR_INVALID_PARAMETER;
- p->m_nWet = (EAS_I16)value;
- break;
- case EAS_PARAM_REVERB_DRY:
- if(value>EAS_REVERB_DRY_MAX || value<EAS_REVERB_DRY_MIN)
- return EAS_ERROR_INVALID_PARAMETER;
- p->m_nDry = (EAS_I16)value;
- break;
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
- return EAS_SUCCESS;
-} /* end ReverbSetParam */
-
-
-/*----------------------------------------------------------------------------
- * ReverbUpdateRoom
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the room's preset parameters as required
- *
- * Inputs:
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - reverb paramters (fbk, fwd, etc) will be changed
- * - m_nCurrentRoom := m_nNextRoom
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT *pReverbData)
-{
- EAS_INT temp;
-
- S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom];
-
- pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd;
- pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk;
-
- pReverbData->m_nEarly = pPreset->m_nEarly;
- pReverbData->m_nWet = pPreset->m_nWet;
- pReverbData->m_nDry = pPreset->m_nDry;
-
-
- pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion;
- //stored as time based, convert to sample based
- temp = pPreset->m_nXfadeInterval;
- /*lint -e{702} shift for performance */
- temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16;
- pReverbData->m_nXfadeInterval = (EAS_U16) temp;
- //gpsReverbObject->m_nXfadeInterval = pPreset->m_nXfadeInterval;
- pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain;
- //stored as time based, convert to absolute sample value
- temp = pPreset->m_nAp0_ApOut;
- /*lint -e{702} shift for performance */
- temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16;
- pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp);
- //gpsReverbObject->m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut;
- pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain;
- //stored as time based, convert to absolute sample value
- temp = pPreset->m_nAp1_ApOut;
- /*lint -e{702} shift for performance */
- temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16;
- pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp);
- //gpsReverbObject->m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut;
-
- pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom;
-
- return EAS_SUCCESS;
-
-} /* end ReverbUpdateRoom */
-
-
-/*----------------------------------------------------------------------------
- * ReverbReadInPresets()
- *----------------------------------------------------------------------------
- * Purpose: sets global reverb preset bank to defaults
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT *pReverbData)
-{
-
- int preset = 0;
- int defaultPreset = 0;
-
- //now init any remaining presets to defaults
- for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++)
- {
- S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[defaultPreset];
- if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE-1)
- {
- pPreset->m_nLpfFbk = 8307;
- pPreset->m_nLpfFwd = 14768;
- pPreset->m_nEarly = 0;
- pPreset->m_nWet = 27690;
- pPreset->m_nDry = 32767;
- pPreset->m_nEarlyL_LpfFbk = 3692;
- pPreset->m_nEarlyL_LpfFwd = 29075;
- pPreset->m_nEarlyL_Delay0 = 922;
- pPreset->m_nEarlyL_Gain0 = 22152;
- pPreset->m_nEarlyL_Delay1 = 1462;
- pPreset->m_nEarlyL_Gain1 = 17537;
- pPreset->m_nEarlyL_Delay2 = 0;
- pPreset->m_nEarlyL_Gain2 = 14768;
- pPreset->m_nEarlyL_Delay3 = 1221;
- pPreset->m_nEarlyL_Gain3 = 14307;
- pPreset->m_nEarlyL_Delay4 = 0;
- pPreset->m_nEarlyL_Gain4 = 13384;
- pPreset->m_nEarlyR_Delay0 = 502;
- pPreset->m_nEarlyR_Gain0 = 20306;
- pPreset->m_nEarlyR_Delay1 = 1762;
- pPreset->m_nEarlyR_Gain1 = 17537;
- pPreset->m_nEarlyR_Delay2 = 0;
- pPreset->m_nEarlyR_Gain2 = 14768;
- pPreset->m_nEarlyR_Delay3 = 0;
- pPreset->m_nEarlyR_Gain3 = 16153;
- pPreset->m_nEarlyR_Delay4 = 0;
- pPreset->m_nEarlyR_Gain4 = 13384;
- pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6388;
- pPreset->m_nAp0_ApGain = 15691;
- pPreset->m_nAp0_ApOut = 711;
- pPreset->m_nAp1_ApGain = 17999;
- pPreset->m_nAp1_ApOut = 1113;
- pPreset->m_rfu4 = 0;
- pPreset->m_rfu5 = 0;
- pPreset->m_rfu6 = 0;
- pPreset->m_rfu7 = 0;
- pPreset->m_rfu8 = 0;
- pPreset->m_rfu9 = 0;
- pPreset->m_rfu10 = 0;
- }
- else if (defaultPreset == 1)
- {
- pPreset->m_nLpfFbk = 6461;
- pPreset->m_nLpfFwd = 14307;
- pPreset->m_nEarly = 0;
- pPreset->m_nWet = 27690;
- pPreset->m_nDry = 32767;
- pPreset->m_nEarlyL_LpfFbk = 3692;
- pPreset->m_nEarlyL_LpfFwd = 29075;
- pPreset->m_nEarlyL_Delay0 = 922;
- pPreset->m_nEarlyL_Gain0 = 22152;
- pPreset->m_nEarlyL_Delay1 = 1462;
- pPreset->m_nEarlyL_Gain1 = 17537;
- pPreset->m_nEarlyL_Delay2 = 0;
- pPreset->m_nEarlyL_Gain2 = 14768;
- pPreset->m_nEarlyL_Delay3 = 1221;
- pPreset->m_nEarlyL_Gain3 = 14307;
- pPreset->m_nEarlyL_Delay4 = 0;
- pPreset->m_nEarlyL_Gain4 = 13384;
- pPreset->m_nEarlyR_Delay0 = 502;
- pPreset->m_nEarlyR_Gain0 = 20306;
- pPreset->m_nEarlyR_Delay1 = 1762;
- pPreset->m_nEarlyR_Gain1 = 17537;
- pPreset->m_nEarlyR_Delay2 = 0;
- pPreset->m_nEarlyR_Gain2 = 14768;
- pPreset->m_nEarlyR_Delay3 = 0;
- pPreset->m_nEarlyR_Gain3 = 16153;
- pPreset->m_nEarlyR_Delay4 = 0;
- pPreset->m_nEarlyR_Gain4 = 13384;
- pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6391;
- pPreset->m_nAp0_ApGain = 15230;
- pPreset->m_nAp0_ApOut = 708;
- pPreset->m_nAp1_ApGain = 9692;
- pPreset->m_nAp1_ApOut = 1113;
- pPreset->m_rfu4 = 0;
- pPreset->m_rfu5 = 0;
- pPreset->m_rfu6 = 0;
- pPreset->m_rfu7 = 0;
- pPreset->m_rfu8 = 0;
- pPreset->m_rfu9 = 0;
- pPreset->m_rfu10 = 0;
- }
- else if (defaultPreset == 2)
- {
- pPreset->m_nLpfFbk = 5077;
- pPreset->m_nLpfFwd = 12922;
- pPreset->m_nEarly = 0;
- pPreset->m_nWet = 24460;
- pPreset->m_nDry = 32767;
- pPreset->m_nEarlyL_LpfFbk = 3692;
- pPreset->m_nEarlyL_LpfFwd = 29075;
- pPreset->m_nEarlyL_Delay0 = 922;
- pPreset->m_nEarlyL_Gain0 = 22152;
- pPreset->m_nEarlyL_Delay1 = 1462;
- pPreset->m_nEarlyL_Gain1 = 17537;
- pPreset->m_nEarlyL_Delay2 = 0;
- pPreset->m_nEarlyL_Gain2 = 14768;
- pPreset->m_nEarlyL_Delay3 = 1221;
- pPreset->m_nEarlyL_Gain3 = 14307;
- pPreset->m_nEarlyL_Delay4 = 0;
- pPreset->m_nEarlyL_Gain4 = 13384;
- pPreset->m_nEarlyR_Delay0 = 502;
- pPreset->m_nEarlyR_Gain0 = 20306;
- pPreset->m_nEarlyR_Delay1 = 1762;
- pPreset->m_nEarlyR_Gain1 = 17537;
- pPreset->m_nEarlyR_Delay2 = 0;
- pPreset->m_nEarlyR_Gain2 = 14768;
- pPreset->m_nEarlyR_Delay3 = 0;
- pPreset->m_nEarlyR_Gain3 = 16153;
- pPreset->m_nEarlyR_Delay4 = 0;
- pPreset->m_nEarlyR_Gain4 = 13384;
- pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6449;
- pPreset->m_nAp0_ApGain = 15691;
- pPreset->m_nAp0_ApOut = 774;
- pPreset->m_nAp1_ApGain = 15691;
- pPreset->m_nAp1_ApOut = 1113;
- pPreset->m_rfu4 = 0;
- pPreset->m_rfu5 = 0;
- pPreset->m_rfu6 = 0;
- pPreset->m_rfu7 = 0;
- pPreset->m_rfu8 = 0;
- pPreset->m_rfu9 = 0;
- pPreset->m_rfu10 = 0;
- }
- else if (defaultPreset == 3)
- {
- pPreset->m_nLpfFbk = 5077;
- pPreset->m_nLpfFwd = 11076;
- pPreset->m_nEarly = 0;
- pPreset->m_nWet = 23075;
- pPreset->m_nDry = 32767;
- pPreset->m_nEarlyL_LpfFbk = 3692;
- pPreset->m_nEarlyL_LpfFwd = 29075;
- pPreset->m_nEarlyL_Delay0 = 922;
- pPreset->m_nEarlyL_Gain0 = 22152;
- pPreset->m_nEarlyL_Delay1 = 1462;
- pPreset->m_nEarlyL_Gain1 = 17537;
- pPreset->m_nEarlyL_Delay2 = 0;
- pPreset->m_nEarlyL_Gain2 = 14768;
- pPreset->m_nEarlyL_Delay3 = 1221;
- pPreset->m_nEarlyL_Gain3 = 14307;
- pPreset->m_nEarlyL_Delay4 = 0;
- pPreset->m_nEarlyL_Gain4 = 13384;
- pPreset->m_nEarlyR_Delay0 = 502;
- pPreset->m_nEarlyR_Gain0 = 20306;
- pPreset->m_nEarlyR_Delay1 = 1762;
- pPreset->m_nEarlyR_Gain1 = 17537;
- pPreset->m_nEarlyR_Delay2 = 0;
- pPreset->m_nEarlyR_Gain2 = 14768;
- pPreset->m_nEarlyR_Delay3 = 0;
- pPreset->m_nEarlyR_Gain3 = 16153;
- pPreset->m_nEarlyR_Delay4 = 0;
- pPreset->m_nEarlyR_Gain4 = 13384;
- pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6470; //6483;
- pPreset->m_nAp0_ApGain = 14768;
- pPreset->m_nAp0_ApOut = 792;
- pPreset->m_nAp1_ApGain = 15783;
- pPreset->m_nAp1_ApOut = 1113;
- pPreset->m_rfu4 = 0;
- pPreset->m_rfu5 = 0;
- pPreset->m_rfu6 = 0;
- pPreset->m_rfu7 = 0;
- pPreset->m_rfu8 = 0;
- pPreset->m_rfu9 = 0;
- pPreset->m_rfu10 = 0;
-
- }
- }
-
- return EAS_SUCCESS;
-}
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 510 $ + * $Date: 2006-12-19 01:47:33 -0800 (Tue, 19 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_reverbdata.h" +#include "eas_reverb.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ReverbInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ReverbProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Reverb = +{ + ReverbInit, + ReverbProcess, + ReverbShutdown, + ReverbGetParam, + ReverbSetParam +}; + + + +/*---------------------------------------------------------------------------- + * InitializeReverb() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbInit(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + EAS_I32 i; + EAS_U16 nOffset; + EAS_INT temp; + + S_REVERB_OBJECT *pReverbData; + S_REVERB_PRESET *pPreset; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pReverbData = EAS_CMEnumFXData(EAS_MODULE_REVERB); + + /* allocate dynamic memory */ + else + pReverbData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_REVERB_OBJECT)); + + if (pReverbData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Reverb memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pReverbData, 0, sizeof(S_REVERB_OBJECT)); + + ReverbReadInPresets(pReverbData); + + pReverbData->m_nMinSamplesToAdd = REVERB_UPDATE_PERIOD_IN_SAMPLES; + + pReverbData->m_nRevOutFbkR = 0; + pReverbData->m_nRevOutFbkL = 0; + + pReverbData->m_sAp0.m_zApIn = AP0_IN; + pReverbData->m_sAp0.m_zApOut = AP0_IN + DEFAULT_AP0_LENGTH; + pReverbData->m_sAp0.m_nApGain = DEFAULT_AP0_GAIN; + + pReverbData->m_zD0In = DELAY0_IN; + + pReverbData->m_sAp1.m_zApIn = AP1_IN; + pReverbData->m_sAp1.m_zApOut = AP1_IN + DEFAULT_AP1_LENGTH; + pReverbData->m_sAp1.m_nApGain = DEFAULT_AP1_GAIN; + + pReverbData->m_zD1In = DELAY1_IN; + + pReverbData->m_zLpf0 = 0; + pReverbData->m_zLpf1 = 0; + pReverbData->m_nLpfFwd = 8837; + pReverbData->m_nLpfFbk = 6494; + + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 0; + pReverbData->m_nSinIncrement = 0; + pReverbData->m_nCosIncrement = 0; + + // set xfade parameters + pReverbData->m_nXfadeInterval = (EAS_U16)REVERB_XFADE_PERIOD_IN_SAMPLES; + pReverbData->m_nXfadeCounter = pReverbData->m_nXfadeInterval + 1; // force update on first iteration + pReverbData->m_nPhase = -32768; + pReverbData->m_nPhaseIncrement = REVERB_XFADE_PHASE_INCREMENT; + + pReverbData->m_nNoise = (EAS_I16)0xABCD; + + pReverbData->m_nMaxExcursion = 0x007F; + + // set delay tap lengths + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + // for debugging purposes, allow noise generator + pReverbData->m_bUseNoise = EAS_FALSE; + + // for debugging purposes, allow bypass + pReverbData->m_bBypass = EAS_TRUE; //EAS_FALSE; + + pReverbData->m_nNextRoom = 1; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom + 1; // force update on first iteration + + pReverbData->m_nWet = REVERB_DEFAULT_WET; + + pReverbData->m_nDry = REVERB_DEFAULT_DRY; + + // set base index into circular buffer + pReverbData->m_nBaseIndex = 0; + + // set the early reflections, L + pReverbData->m_sEarlyL.m_nLpfFbk = 4915; + pReverbData->m_sEarlyL.m_nLpfFwd = 27852; + pReverbData->m_sEarlyL.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyL.m_nGain[i] = 0; + pReverbData->m_sEarlyL.m_zDelay[i] = 0; + } + + // set the early reflections, R + pReverbData->m_sEarlyR.m_nLpfFbk = 4915; + pReverbData->m_sEarlyR.m_nLpfFwd = 27852; + pReverbData->m_sEarlyR.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyR.m_nGain[i] = 0; + pReverbData->m_sEarlyR.m_zDelay[i] = 0; + } + + // clear the reverb delay line + for (i=0; i < REVERB_BUFFER_SIZE_IN_SAMPLES; i++) + { + pReverbData->m_nDelayLine[i] = 0; + } + + //////////////////////////////// + ///code from the EAS DEMO Reverb + //now copy from the new preset into the reverb + pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval; + + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gsReverbObject.m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gsReverbObject.m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + ///code from the EAS DEMO Reverb + //////////////////////////////// + + *pInstData = pReverbData; + + return EAS_SUCCESS; + +} /* end InitializeReverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbProcess() + *---------------------------------------------------------------------------- + * Purpose: + * Reverberate the requested number of samples (block based processing) + * + * Inputs: + * pInputBuffer - src buffer + * pOutputBuffer - dst buffer + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static void ReverbProcess(EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + S_REVERB_OBJECT *pReverbData; + + pReverbData = (S_REVERB_OBJECT*) pInstData; + + //if bypassed or the preset forces the signal to be completely dry + if (pReverbData->m_bBypass || + (pReverbData->m_nWet == 0 && pReverbData->m_nDry == 32767)) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pReverbData->m_nNextRoom != pReverbData->m_nCurrentRoom) + { + ReverbUpdateRoom(pReverbData); + } + + ReverbUpdateXfade(pReverbData, numSamples); + + Reverb(pReverbData, numSamples, pDst, pSrc); + + /* check if update counter needs to be reset */ + if (pReverbData->m_nUpdateCounter >= REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nUpdateCounter = 0; + } /* end if m_nUpdateCounter >= update interval */ + + /* increment update counter */ + pReverbData->m_nUpdateCounter += (EAS_I16)numSamples; + +} /* end ComputeReverb */ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd) +{ + EAS_U16 nOffset; + EAS_I16 tempCos; + EAS_I16 tempSin; + + if (pReverbData->m_nXfadeCounter >= pReverbData->m_nXfadeInterval) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nXfadeCounter = 0; + + // Pin the sin,cos values to min / max values to ensure that the + // modulated taps' coefs are zero (thus no clicks) + if (pReverbData->m_nPhaseIncrement > 0) + { + // if phase increment > 0, then sin -> 1, cos -> 0 + pReverbData->m_nSin = 32767; + pReverbData->m_nCos = 0; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = 32767; + + // modulate the cross taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + } + else + { + // if phase increment < 0, then sin -> 0, cos -> 1 + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 32767; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = -32768; + + // modulate the self taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + } // end if-else (pReverbData->m_nPhaseIncrement > 0) + + // Reverse the direction of the sin,cos so that the + // tap whose coef was previously increasing now decreases + // and vice versa + pReverbData->m_nPhaseIncrement = -pReverbData->m_nPhaseIncrement; + + } // end if counter >= update interval + + //compute what phase will be next time + pReverbData->m_nPhase += pReverbData->m_nPhaseIncrement; + + //calculate what the new sin and cos need to reach by the next update + ReverbCalculateSinCos(pReverbData->m_nPhase, &tempSin, &tempCos); + + //calculate the per-sample increment required to get there by the next update + /*lint -e{702} shift for performance */ + pReverbData->m_nSinIncrement = + (tempSin - pReverbData->m_nSin) >> REVERB_UPDATE_PERIOD_IN_BITS; + + /*lint -e{702} shift for performance */ + pReverbData->m_nCosIncrement = + (tempCos - pReverbData->m_nCos) >> REVERB_UPDATE_PERIOD_IN_BITS; + + + /* increment update counter */ + pReverbData->m_nXfadeCounter += (EAS_U16) nNumSamplesToAdd; + + return EAS_SUCCESS; + +} /* end ReverbUpdateXfade */ + + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise) +{ + // calculate new noise value + *pnNoise = (EAS_I16) (*pnNoise * 5 + 1); + +#if 0 // 1xxx, test + *pnNoise = 0; +#endif // 1xxx, test + + // return the limited noise value + return (nMaxExcursion & (*pnNoise)); + +} /* end ReverbCalculateNoise */ + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos) +{ + EAS_I32 nTemp; + EAS_I32 nNetAngle; + + // -1 <= nPhase < 1 + // However, for the calculation, we need a value + // that ranges from -1/2 to +1/2, so divide the phase by 2 + /*lint -e{702} shift for performance */ + nNetAngle = nPhase >> 1; + + /* + Implement the following + sin(x) = (2-4*c)*x^2 + c + x + cos(x) = (2-4*c)*x^2 + c - x + + where c = 1/sqrt(2) + using the a0 + x*(a1 + x*a2) approach + */ + + /* limit the input "angle" to be between -0.5 and +0.5 */ + if (nNetAngle > EG1_HALF) + { + nNetAngle = EG1_HALF; + } + else if (nNetAngle < EG1_MINUS_HALF) + { + nNetAngle = EG1_MINUS_HALF; + } + + /* calculate sin */ + nTemp = EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnSin = (EAS_I16) SATURATE_EG1(nTemp); + + /* calculate cos */ + nTemp = -EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnCos = (EAS_I16) SATURATE_EG1(nTemp); + + return EAS_SUCCESS; +} /* end ReverbCalculateSinCos */ + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Reverb(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer) +{ + EAS_I32 i; + EAS_I32 nDelayOut; + EAS_U16 nBase; + + EAS_U32 nAddr; + EAS_I32 nTemp1; + EAS_I32 nTemp2; + EAS_I32 nApIn; + EAS_I32 nApOut; + + EAS_I32 j; + EAS_I32 nEarlyOut; + + EAS_I32 tempValue; + + + // get the base address + nBase = pReverbData->m_nBaseIndex; + + for (i=0; i < nNumSamplesToAdd; i++) + { + // ********** Left Allpass - start + // left input = (left dry/4) + right feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkR; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + //nAddr = CIRCULAR(nBase, psAp0->m_zApOut, REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp0.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp0.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD0In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Left Allpass - end + + // ********** Right Allpass - start + // right input = (right dry/4) + left feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkL; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp1.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp1.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD1In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Right Allpass - end + + // ********** D0 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf0, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf0 + pReverbData->m_zLpf0 = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // ********** D0 output - end + + // ********** D1 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf1, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf1 + pReverbData->m_zLpf1 = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // ********** D1 output - end + + // ********** mixer and feedback - start + // sum is fedback to right input (R + L) + pReverbData->m_nRevOutFbkL = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 + (EAS_I32)pReverbData->m_zLpf0); + + // difference is feedback to left input (R - L) + /*lint -e{685} lint complains that it can't saturate negative */ + pReverbData->m_nRevOutFbkR = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 - (EAS_I32)pReverbData->m_zLpf0); + + // ********** mixer and feedback - end + + // ********** start early reflection generator, left + //psEarly = &(pReverbData->m_sEarlyL); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + //nAddr = CIRCULAR(nBase, psEarly->m_zDelay[j], REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyL.m_zDelay[j], REVERB_BUFFER_MASK); + + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + //nTemp1 = MULT_EG1_EG1(nDelayOut, psEarly->m_nGain[j]); + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyL.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + //nTemp1 = MULT_EG1_EG1(nEarlyOut, psEarly->m_nLpfFwd); + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyL.m_nLpfFwd); + + //nTemp2 = MULT_EG1_EG1(psEarly->m_zLpf, psEarly->m_nLpfFbk); + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyL.m_zLpf, pReverbData->m_sEarlyL.m_nLpfFbk); + + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + //psEarly->m_zLpf = SATURATE(nTemp1 + nTemp2); + pReverbData->m_sEarlyL.m_zLpf = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inL; + //tempValue = SATURATE(psEarly->m_zLpf + pReverbData->m_nRevOutFbkL); + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyL.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkL); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet<<1)); + //sum with output buffer + tempValue += *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, left + + // ********** start early reflection generator, right + //psEarly = &(pReverbData->m_sEarlyR); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyR.m_zDelay[j], REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyR.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyR.m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyR.m_zLpf, pReverbData->m_sEarlyR.m_nLpfFbk); + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + pReverbData->m_sEarlyR.m_zLpf = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inR; + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyR.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkR); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet << 1)); + //sum with output buffer + tempValue = tempValue + *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, right + + // decrement base addr for next sample period + nBase--; + + pReverbData->m_nSin += pReverbData->m_nSinIncrement; + pReverbData->m_nCos += pReverbData->m_nCosIncrement; + + } // end for (i=0; i < nNumSamplesToAdd; i++) + + // store the most up to date version + pReverbData->m_nBaseIndex = nBase; + + return EAS_SUCCESS; +} /* end Reverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Reverb effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ReverbShutdown */ + +/*---------------------------------------------------------------------------- + * ReverbGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + *pValue = (EAS_I32) p->m_bBypass; + break; + case EAS_PARAM_REVERB_PRESET: + *pValue = (EAS_I8) p->m_nCurrentRoom; + break; + case EAS_PARAM_REVERB_WET: + *pValue = p->m_nWet; + break; + case EAS_PARAM_REVERB_DRY: + *pValue = p->m_nDry; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbGetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + p->m_bBypass = (EAS_BOOL) value; + break; + case EAS_PARAM_REVERB_PRESET: + if(value!=EAS_PARAM_REVERB_LARGE_HALL && value!=EAS_PARAM_REVERB_HALL && + value!=EAS_PARAM_REVERB_CHAMBER && value!=EAS_PARAM_REVERB_ROOM) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextRoom = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_WET: + if(value>EAS_REVERB_WET_MAX || value<EAS_REVERB_WET_MIN) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nWet = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_DRY: + if(value>EAS_REVERB_DRY_MAX || value<EAS_REVERB_DRY_MIN) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nDry = (EAS_I16)value; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbSetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT *pReverbData) +{ + EAS_INT temp; + + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gpsReverbObject->m_nXfadeInterval = pPreset->m_nXfadeInterval; + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gpsReverbObject->m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gpsReverbObject->m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom; + + return EAS_SUCCESS; + +} /* end ReverbUpdateRoom */ + + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT *pReverbData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) + { + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE-1) + { + pPreset->m_nLpfFbk = 8307; + pPreset->m_nLpfFwd = 14768; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6388; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 711; + pPreset->m_nAp1_ApGain = 17999; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 1) + { + pPreset->m_nLpfFbk = 6461; + pPreset->m_nLpfFwd = 14307; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6391; + pPreset->m_nAp0_ApGain = 15230; + pPreset->m_nAp0_ApOut = 708; + pPreset->m_nAp1_ApGain = 9692; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 2) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 12922; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 24460; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6449; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 774; + pPreset->m_nAp1_ApGain = 15691; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 3) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 11076; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 23075; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6470; //6483; + pPreset->m_nAp0_ApGain = 14768; + pPreset->m_nAp0_ApOut = 792; + pPreset->m_nAp1_ApGain = 15783; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + + } + } + + return EAS_SUCCESS; +} diff --git a/arm-fm-22k/lib_src/eas_reverbdata.c b/arm-fm-22k/lib_src/eas_reverbdata.c index 5d48c1b..db34b48 100644 --- a/arm-fm-22k/lib_src/eas_reverbdata.c +++ b/arm-fm-22k/lib_src/eas_reverbdata.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_reverbdata.c
- *
- * Contents and purpose:
- * Contains the static data allocation for the Reverb effect
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,15 @@ * 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: 550 $
- * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_reverbdata.h"
-
-S_REVERB_OBJECT eas_ReverbData;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_reverbdata.h" + +S_REVERB_OBJECT eas_ReverbData; + diff --git a/arm-fm-22k/lib_src/eas_reverbdata.h b/arm-fm-22k/lib_src/eas_reverbdata.h index ef424da..926ea2e 100644 --- a/arm-fm-22k/lib_src/eas_reverbdata.h +++ b/arm-fm-22k/lib_src/eas_reverbdata.h @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_reverbdata.h
- *
- * Contents and purpose:
- * Contains the prototypes for the Reverb effect.
- *
- *
- * Copyright Sonic Network Inc. 2006
+/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.h + * + * Contents and purpose: + * Contains the prototypes for the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,467 +20,467 @@ * 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: 499 $
- * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_REVERBDATA_H
-#define _EAS_REVERBDATA_H
-
-#include "eas_types.h"
-#include "eas_audioconst.h"
-
-/*------------------------------------
- * defines
- *------------------------------------
-*/
-
-/*
-CIRCULAR() calculates the array index using modulo arithmetic.
-The "trick" is that modulo arithmetic is simplified by masking
-the effective address where the mask is (2^n)-1. This only works
-if the buffer size is a power of two.
-*/
-#define CIRCULAR(base,offset,size) (EAS_U32)( \
- ( \
- ((EAS_I32)(base)) + ((EAS_I32)(offset)) \
- ) \
- & size \
- )
-
-/* reverb parameters are updated every 2^(REVERB_UPDATE_PERIOD_IN_BITS) samples */
-#if defined (_SAMPLE_RATE_8000)
-
-#define REVERB_UPDATE_PERIOD_IN_BITS 5
-#define REVERB_BUFFER_SIZE_IN_SAMPLES 2048
-
-#elif defined (_SAMPLE_RATE_16000)
-
-#define REVERB_UPDATE_PERIOD_IN_BITS 6
-#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096
-
-#elif defined (_SAMPLE_RATE_22050)
-
-#define REVERB_UPDATE_PERIOD_IN_BITS 7
-#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096
-
-#elif defined (_SAMPLE_RATE_32000)
-
-#define REVERB_UPDATE_PERIOD_IN_BITS 7
-#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192
-
-#elif defined (_SAMPLE_RATE_44100)
-
-#define REVERB_UPDATE_PERIOD_IN_BITS 8
-#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192
-
-#elif defined (_SAMPLE_RATE_48000)
-
-#define REVERB_UPDATE_PERIOD_IN_BITS 8
-#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192
-
-#endif
-
-// Define a mask for circular addressing, so that array index
-// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1)
-// The buffer size MUST be a power of two
-#define REVERB_BUFFER_MASK (REVERB_BUFFER_SIZE_IN_SAMPLES -1)
-
-#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid
-#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel
-
-/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */
-#define REVERB_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << REVERB_UPDATE_PERIOD_IN_BITS)
-
-/*
-calculate the update counter by bitwise ANDING with this value to
-generate a 2^n modulo value
-*/
-#define REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(REVERB_UPDATE_PERIOD_IN_SAMPLES -1)
-
-/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SECONDS seconds */
-#define REVERB_UPDATE_PERIOD_IN_SECONDS (REVERB_UPDATE_PERIOD_IN_SAMPLES / _OUTPUT_SAMPLE_RATE)
-
-// xfade parameters
-#define REVERB_XFADE_PERIOD_IN_SECONDS (100.0 / 1000.0) // xfade once every this many seconds
-
-#define REVERB_XFADE_PERIOD_IN_SAMPLES (REVERB_XFADE_PERIOD_IN_SECONDS * _OUTPUT_SAMPLE_RATE)
-
-#define REVERB_XFADE_PHASE_INCREMENT (EAS_I16)(65536 / ((EAS_I16)REVERB_XFADE_PERIOD_IN_SAMPLES/(EAS_I16)REVERB_UPDATE_PERIOD_IN_SAMPLES))
-
-/**********/
-/* the entire synth uses various flags in a bit field */
-
-/* if flag is set, synth reset has been requested */
-#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */
-#define MASK_REVERB_RESET_IS_REQUESTED 0x01
-#define MASK_REVERB_RESET_IS_NOT_REQUESTED (EAS_U32)(~MASK_REVERB_RESET_IS_REQUESTED)
-
-/*
-by default, we always want to update ALL channel parameters
-when we reset the synth (e.g., during GM ON)
-*/
-#define DEFAULT_REVERB_FLAGS 0x0
-
-/* coefficients for generating sin, cos */
-#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */
-/*
-EAS_I32 nPanG1 = +1.0 for sin
-EAS_I32 nPanG1 = -1.0 for cos
-*/
-#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */
-
-/*************************************************************/
-// define the input injection points
-#define GUARD 5 // safety guard of this many samples
-
-#define MAX_AP_TIME (double) (20.0/1000.0) // delay time in milliseconds
-#define MAX_DELAY_TIME (double) (65.0/1000.0) // delay time in milliseconds
-
-#define MAX_AP_SAMPLES (int)(((double) MAX_AP_TIME) * ((double) _OUTPUT_SAMPLE_RATE))
-#define MAX_DELAY_SAMPLES (int)(((double) MAX_DELAY_TIME) * ((double) _OUTPUT_SAMPLE_RATE))
-
-#define AP0_IN 0
-#define AP1_IN (AP0_IN + MAX_AP_SAMPLES + GUARD)
-#define DELAY0_IN (AP1_IN + MAX_AP_SAMPLES + GUARD)
-#define DELAY1_IN (DELAY0_IN + MAX_DELAY_SAMPLES + GUARD)
-
-// Define the max offsets for the end points of each section
-// i.e., we don't expect a given section's taps to go beyond
-// the following limits
-#define AP0_OUT (AP0_IN + MAX_AP_SAMPLES -1)
-#define AP1_OUT (AP1_IN + MAX_AP_SAMPLES -1)
-#define DELAY0_OUT (DELAY0_IN + MAX_DELAY_SAMPLES -1)
-#define DELAY1_OUT (DELAY1_IN + MAX_DELAY_SAMPLES -1)
-
-#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number
-#define DEFAULT_AP0_LENGTH (int)(((double) (17.0/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE))
-#define DEFAULT_AP0_GAIN 19400
-#define DEFAULT_AP1_LENGTH (int)(((double) (16.5/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE))
-#define DEFAULT_AP1_GAIN -19400
-
-#define REVERB_DEFAULT_WET 32767
-#define REVERB_DEFAULT_DRY 0
-
-#define EAS_REVERB_WET_MAX 32767
-#define EAS_REVERB_WET_MIN 0
-#define EAS_REVERB_DRY_MAX 32767
-#define EAS_REVERB_DRY_MIN 0
-
-/* parameters for each allpass */
-typedef struct
-{
- EAS_U16 m_zApOut; // delay offset for ap out
-
- EAS_I16 m_nApGain; // gain for ap
-
- EAS_U16 m_zApIn; // delay offset for ap in
-
-} S_ALLPASS_OBJECT;
-
-
-/* parameters for each allpass */
-typedef struct
-{
- EAS_PCM m_zLpf; // actual state variable, not a length
-
- EAS_I16 m_nLpfFwd; // lpf forward gain
-
- EAS_I16 m_nLpfFbk; // lpf feedback gain
-
- EAS_U16 m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out
-
- EAS_I16 m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap
-
-} S_EARLY_REFLECTION_OBJECT;
-
-//demo
-typedef struct
-{
- EAS_I16 m_nLpfFbk;
- EAS_I16 m_nLpfFwd;
-
- EAS_I16 m_nEarly;
- EAS_I16 m_nWet;
- EAS_I16 m_nDry;
-
- EAS_I16 m_nEarlyL_LpfFbk;
- EAS_I16 m_nEarlyL_LpfFwd;
-
- EAS_I16 m_nEarlyL_Delay0; //8
- EAS_I16 m_nEarlyL_Gain0;
- EAS_I16 m_nEarlyL_Delay1;
- EAS_I16 m_nEarlyL_Gain1;
- EAS_I16 m_nEarlyL_Delay2;
- EAS_I16 m_nEarlyL_Gain2;
- EAS_I16 m_nEarlyL_Delay3;
- EAS_I16 m_nEarlyL_Gain3;
- EAS_I16 m_nEarlyL_Delay4;
- EAS_I16 m_nEarlyL_Gain4;
-
- EAS_I16 m_nEarlyR_Delay0; //18
- EAS_I16 m_nEarlyR_Gain0;
- EAS_I16 m_nEarlyR_Delay1;
- EAS_I16 m_nEarlyR_Gain1;
- EAS_I16 m_nEarlyR_Delay2;
- EAS_I16 m_nEarlyR_Gain2;
- EAS_I16 m_nEarlyR_Delay3;
- EAS_I16 m_nEarlyR_Gain3;
- EAS_I16 m_nEarlyR_Delay4;
- EAS_I16 m_nEarlyR_Gain4;
-
- EAS_U16 m_nMaxExcursion; //28
- EAS_I16 m_nXfadeInterval;
-
- EAS_I16 m_nAp0_ApGain; //30
- EAS_I16 m_nAp0_ApOut;
- EAS_I16 m_nAp1_ApGain;
- EAS_I16 m_nAp1_ApOut;
-
- EAS_I16 m_rfu4;
- EAS_I16 m_rfu5;
- EAS_I16 m_rfu6;
- EAS_I16 m_rfu7;
- EAS_I16 m_rfu8;
- EAS_I16 m_rfu9;
- EAS_I16 m_rfu10; //43
-
-} S_REVERB_PRESET;
-
-typedef struct
-{
- S_REVERB_PRESET m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets
-
-} S_REVERB_PRESET_BANK;
-
-/* parameters for each reverb */
-typedef struct
-{
- /* controls entire reverb playback volume */
- /* to conserve memory, use the MSB and ignore the LSB */
- EAS_U8 m_nMasterVolume;
-
- /* update counter keeps track of when synth params need updating */
- /* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */
- EAS_I16 m_nUpdateCounter;
-
- EAS_U16 m_nMinSamplesToAdd; /* ComputeReverb() generates this many samples */
-
- EAS_U8 m_nFlags; /* misc flags/bit fields */
-
- EAS_PCM *m_pOutputBuffer;
- EAS_PCM *m_pInputBuffer;
-
- EAS_U16 m_nNumSamplesInOutputBuffer;
- EAS_U16 m_nNumSamplesInInputBuffer;
-
- EAS_U16 m_nNumInputSamplesRead; // if m_nNumInputSamplesRead >= NumSamplesInInputBuffer
- // then get a new input buffer
- EAS_PCM *m_pNextInputSample;
-
- EAS_U16 m_nBaseIndex; // base index for circular buffer
-
- // reverb delay line offsets, allpass parameters, etc:
-
- EAS_PCM m_nRevOutFbkR; // combine feedback reverb right out with dry left in
-
- S_ALLPASS_OBJECT m_sAp0; // allpass 0 (left channel)
-
- EAS_U16 m_zD0In; // delay offset for delay line D0 in
-
- EAS_PCM m_nRevOutFbkL; // combine feedback reverb left out with dry right in
-
- S_ALLPASS_OBJECT m_sAp1; // allpass 1 (right channel)
-
- EAS_U16 m_zD1In; // delay offset for delay line D1 in
-
- // delay output taps, notice criss cross order
- EAS_U16 m_zD0Self; // self feeds forward d0 --> d0
-
- EAS_U16 m_zD1Cross; // cross feeds across d1 --> d0
-
- EAS_PCM m_zLpf0; // actual state variable, not a length
-
- EAS_U16 m_zD1Self; // self feeds forward d1 --> d1
-
- EAS_U16 m_zD0Cross; // cross feeds across d0 --> d1
-
- EAS_PCM m_zLpf1; // actual state variable, not a length
-
- EAS_I16 m_nSin; // gain for self taps
-
- EAS_I16 m_nCos; // gain for cross taps
-
- EAS_I16 m_nSinIncrement; // increment for gain
-
- EAS_I16 m_nCosIncrement; // increment for gain
-
- EAS_I16 m_nLpfFwd; // lpf forward gain (includes scaling for mixer)
-
- EAS_I16 m_nLpfFbk; // lpf feedback gain
-
- EAS_U16 m_nXfadeInterval; // update/xfade after this many samples
-
- EAS_U16 m_nXfadeCounter; // keep track of when to xfade
-
- EAS_I16 m_nPhase; // -1 <= m_nPhase < 1
- // but during sin,cos calculations
- // use m_nPhase/2
-
- EAS_I16 m_nPhaseIncrement; // add this to m_nPhase each frame
-
- EAS_I16 m_nNoise; // random noise sample
-
- EAS_U16 m_nMaxExcursion; // the taps can excurse +/- this amount
-
- EAS_BOOL m_bUseNoise; // if EAS_TRUE, use noise as input signal
-
- EAS_BOOL m_bBypass; // if EAS_TRUE, then bypass reverb and copy input to output
-
- EAS_I16 m_nCurrentRoom; // preset number for current room
-
- EAS_I16 m_nNextRoom; // preset number for next room
-
- EAS_I16 m_nWet; // gain for wet (processed) signal
-
- EAS_I16 m_nDry; // gain for dry (unprocessed) signal
-
- EAS_I16 m_nEarly; // gain for early (widen) signal
-
- S_EARLY_REFLECTION_OBJECT m_sEarlyL; // left channel early reflections
- S_EARLY_REFLECTION_OBJECT m_sEarlyR; // right channel early reflections
-
- EAS_PCM m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES]; // one large delay line for all reverb elements
-
- S_REVERB_PRESET pPreset;
-
- S_REVERB_PRESET_BANK m_sPreset;
-
- //EAS_I8 preset;
-
-} S_REVERB_OBJECT;
-
-
-/*------------------------------------
- * prototypes
- *------------------------------------
-*/
-
-/*----------------------------------------------------------------------------
- * ReverbUpdateXfade
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the xfade parameters as required
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to write to buffer
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - xfade parameters will be changed
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd);
-
-/*----------------------------------------------------------------------------
- * ReverbCalculateNoise
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate a noise sample and limit its value
- *
- * Inputs:
- * nMaxExcursion - noise value is limited to this value
- * pnNoise - return new noise sample in this (not limited)
- *
- * Outputs:
- * new limited noise value
- *
- * Side Effects:
- * - *pnNoise noise value is updated
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise);
-
-/*----------------------------------------------------------------------------
- * ReverbCalculateSinCos
- *----------------------------------------------------------------------------
- * Purpose:
- * Calculate a new sin and cosine value based on the given phase
- *
- * Inputs:
- * nPhase - phase angle
- * pnSin - input old value, output new value
- * pnCos - input old value, output new value
- *
- * Outputs:
- *
- * Side Effects:
- * - *pnSin, *pnCos are updated
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos);
-
-/*----------------------------------------------------------------------------
- * Reverb
- *----------------------------------------------------------------------------
- * Purpose:
- * apply reverb to the given signal
- *
- * Inputs:
- * nNu
- * pnSin - input old value, output new value
- * pnCos - input old value, output new value
- *
- * Outputs:
- * number of samples actually reverberated
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT Reverb(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer);
-
-/*----------------------------------------------------------------------------
- * ReverbReadInPresets()
- *----------------------------------------------------------------------------
- * Purpose: sets global reverb preset bank to defaults
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT* pReverbData);
-
-
-/*----------------------------------------------------------------------------
- * ReverbUpdateRoom
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the room's preset parameters as required
- *
- * Inputs:
- *
- * Outputs:
- *
- *
- * Side Effects:
- * - reverb paramters (fbk, fwd, etc) will be changed
- * - m_nCurrentRoom := m_nNextRoom
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT* pReverbData);
-
-#endif /* #ifndef _EAS_REVERBDATA_H */
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERBDATA_H +#define _EAS_REVERBDATA_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* +CIRCULAR() calculates the array index using modulo arithmetic. +The "trick" is that modulo arithmetic is simplified by masking +the effective address where the mask is (2^n)-1. This only works +if the buffer size is a power of two. +*/ +#define CIRCULAR(base,offset,size) (EAS_U32)( \ + ( \ + ((EAS_I32)(base)) + ((EAS_I32)(offset)) \ + ) \ + & size \ + ) + +/* reverb parameters are updated every 2^(REVERB_UPDATE_PERIOD_IN_BITS) samples */ +#if defined (_SAMPLE_RATE_8000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 5 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 2048 + +#elif defined (_SAMPLE_RATE_16000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 6 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_22050) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_32000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_44100) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_48000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#endif + +// Define a mask for circular addressing, so that array index +// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1) +// The buffer size MUST be a power of two +#define REVERB_BUFFER_MASK (REVERB_BUFFER_SIZE_IN_SAMPLES -1) + +#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid +#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define REVERB_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << REVERB_UPDATE_PERIOD_IN_BITS) + +/* +calculate the update counter by bitwise ANDING with this value to +generate a 2^n modulo value +*/ +#define REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(REVERB_UPDATE_PERIOD_IN_SAMPLES -1) + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SECONDS seconds */ +#define REVERB_UPDATE_PERIOD_IN_SECONDS (REVERB_UPDATE_PERIOD_IN_SAMPLES / _OUTPUT_SAMPLE_RATE) + +// xfade parameters +#define REVERB_XFADE_PERIOD_IN_SECONDS (100.0 / 1000.0) // xfade once every this many seconds + +#define REVERB_XFADE_PERIOD_IN_SAMPLES (REVERB_XFADE_PERIOD_IN_SECONDS * _OUTPUT_SAMPLE_RATE) + +#define REVERB_XFADE_PHASE_INCREMENT (EAS_I16)(65536 / ((EAS_I16)REVERB_XFADE_PERIOD_IN_SAMPLES/(EAS_I16)REVERB_UPDATE_PERIOD_IN_SAMPLES)) + +/**********/ +/* the entire synth uses various flags in a bit field */ + +/* if flag is set, synth reset has been requested */ +#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */ +#define MASK_REVERB_RESET_IS_REQUESTED 0x01 +#define MASK_REVERB_RESET_IS_NOT_REQUESTED (EAS_U32)(~MASK_REVERB_RESET_IS_REQUESTED) + +/* +by default, we always want to update ALL channel parameters +when we reset the synth (e.g., during GM ON) +*/ +#define DEFAULT_REVERB_FLAGS 0x0 + +/* coefficients for generating sin, cos */ +#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +/* +EAS_I32 nPanG1 = +1.0 for sin +EAS_I32 nPanG1 = -1.0 for cos +*/ +#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/*************************************************************/ +// define the input injection points +#define GUARD 5 // safety guard of this many samples + +#define MAX_AP_TIME (double) (20.0/1000.0) // delay time in milliseconds +#define MAX_DELAY_TIME (double) (65.0/1000.0) // delay time in milliseconds + +#define MAX_AP_SAMPLES (int)(((double) MAX_AP_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) +#define MAX_DELAY_SAMPLES (int)(((double) MAX_DELAY_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) + +#define AP0_IN 0 +#define AP1_IN (AP0_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY0_IN (AP1_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY1_IN (DELAY0_IN + MAX_DELAY_SAMPLES + GUARD) + +// Define the max offsets for the end points of each section +// i.e., we don't expect a given section's taps to go beyond +// the following limits +#define AP0_OUT (AP0_IN + MAX_AP_SAMPLES -1) +#define AP1_OUT (AP1_IN + MAX_AP_SAMPLES -1) +#define DELAY0_OUT (DELAY0_IN + MAX_DELAY_SAMPLES -1) +#define DELAY1_OUT (DELAY1_IN + MAX_DELAY_SAMPLES -1) + +#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number +#define DEFAULT_AP0_LENGTH (int)(((double) (17.0/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP0_GAIN 19400 +#define DEFAULT_AP1_LENGTH (int)(((double) (16.5/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP1_GAIN -19400 + +#define REVERB_DEFAULT_WET 32767 +#define REVERB_DEFAULT_DRY 0 + +#define EAS_REVERB_WET_MAX 32767 +#define EAS_REVERB_WET_MIN 0 +#define EAS_REVERB_DRY_MAX 32767 +#define EAS_REVERB_DRY_MIN 0 + +/* parameters for each allpass */ +typedef struct +{ + EAS_U16 m_zApOut; // delay offset for ap out + + EAS_I16 m_nApGain; // gain for ap + + EAS_U16 m_zApIn; // delay offset for ap in + +} S_ALLPASS_OBJECT; + + +/* parameters for each allpass */ +typedef struct +{ + EAS_PCM m_zLpf; // actual state variable, not a length + + EAS_I16 m_nLpfFwd; // lpf forward gain + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out + + EAS_I16 m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap + +} S_EARLY_REFLECTION_OBJECT; + +//demo +typedef struct +{ + EAS_I16 m_nLpfFbk; + EAS_I16 m_nLpfFwd; + + EAS_I16 m_nEarly; + EAS_I16 m_nWet; + EAS_I16 m_nDry; + + EAS_I16 m_nEarlyL_LpfFbk; + EAS_I16 m_nEarlyL_LpfFwd; + + EAS_I16 m_nEarlyL_Delay0; //8 + EAS_I16 m_nEarlyL_Gain0; + EAS_I16 m_nEarlyL_Delay1; + EAS_I16 m_nEarlyL_Gain1; + EAS_I16 m_nEarlyL_Delay2; + EAS_I16 m_nEarlyL_Gain2; + EAS_I16 m_nEarlyL_Delay3; + EAS_I16 m_nEarlyL_Gain3; + EAS_I16 m_nEarlyL_Delay4; + EAS_I16 m_nEarlyL_Gain4; + + EAS_I16 m_nEarlyR_Delay0; //18 + EAS_I16 m_nEarlyR_Gain0; + EAS_I16 m_nEarlyR_Delay1; + EAS_I16 m_nEarlyR_Gain1; + EAS_I16 m_nEarlyR_Delay2; + EAS_I16 m_nEarlyR_Gain2; + EAS_I16 m_nEarlyR_Delay3; + EAS_I16 m_nEarlyR_Gain3; + EAS_I16 m_nEarlyR_Delay4; + EAS_I16 m_nEarlyR_Gain4; + + EAS_U16 m_nMaxExcursion; //28 + EAS_I16 m_nXfadeInterval; + + EAS_I16 m_nAp0_ApGain; //30 + EAS_I16 m_nAp0_ApOut; + EAS_I16 m_nAp1_ApGain; + EAS_I16 m_nAp1_ApOut; + + EAS_I16 m_rfu4; + EAS_I16 m_rfu5; + EAS_I16 m_rfu6; + EAS_I16 m_rfu7; + EAS_I16 m_rfu8; + EAS_I16 m_rfu9; + EAS_I16 m_rfu10; //43 + +} S_REVERB_PRESET; + +typedef struct +{ + S_REVERB_PRESET m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets + +} S_REVERB_PRESET_BANK; + +/* parameters for each reverb */ +typedef struct +{ + /* controls entire reverb playback volume */ + /* to conserve memory, use the MSB and ignore the LSB */ + EAS_U8 m_nMasterVolume; + + /* update counter keeps track of when synth params need updating */ + /* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */ + EAS_I16 m_nUpdateCounter; + + EAS_U16 m_nMinSamplesToAdd; /* ComputeReverb() generates this many samples */ + + EAS_U8 m_nFlags; /* misc flags/bit fields */ + + EAS_PCM *m_pOutputBuffer; + EAS_PCM *m_pInputBuffer; + + EAS_U16 m_nNumSamplesInOutputBuffer; + EAS_U16 m_nNumSamplesInInputBuffer; + + EAS_U16 m_nNumInputSamplesRead; // if m_nNumInputSamplesRead >= NumSamplesInInputBuffer + // then get a new input buffer + EAS_PCM *m_pNextInputSample; + + EAS_U16 m_nBaseIndex; // base index for circular buffer + + // reverb delay line offsets, allpass parameters, etc: + + EAS_PCM m_nRevOutFbkR; // combine feedback reverb right out with dry left in + + S_ALLPASS_OBJECT m_sAp0; // allpass 0 (left channel) + + EAS_U16 m_zD0In; // delay offset for delay line D0 in + + EAS_PCM m_nRevOutFbkL; // combine feedback reverb left out with dry right in + + S_ALLPASS_OBJECT m_sAp1; // allpass 1 (right channel) + + EAS_U16 m_zD1In; // delay offset for delay line D1 in + + // delay output taps, notice criss cross order + EAS_U16 m_zD0Self; // self feeds forward d0 --> d0 + + EAS_U16 m_zD1Cross; // cross feeds across d1 --> d0 + + EAS_PCM m_zLpf0; // actual state variable, not a length + + EAS_U16 m_zD1Self; // self feeds forward d1 --> d1 + + EAS_U16 m_zD0Cross; // cross feeds across d0 --> d1 + + EAS_PCM m_zLpf1; // actual state variable, not a length + + EAS_I16 m_nSin; // gain for self taps + + EAS_I16 m_nCos; // gain for cross taps + + EAS_I16 m_nSinIncrement; // increment for gain + + EAS_I16 m_nCosIncrement; // increment for gain + + EAS_I16 m_nLpfFwd; // lpf forward gain (includes scaling for mixer) + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_nXfadeInterval; // update/xfade after this many samples + + EAS_U16 m_nXfadeCounter; // keep track of when to xfade + + EAS_I16 m_nPhase; // -1 <= m_nPhase < 1 + // but during sin,cos calculations + // use m_nPhase/2 + + EAS_I16 m_nPhaseIncrement; // add this to m_nPhase each frame + + EAS_I16 m_nNoise; // random noise sample + + EAS_U16 m_nMaxExcursion; // the taps can excurse +/- this amount + + EAS_BOOL m_bUseNoise; // if EAS_TRUE, use noise as input signal + + EAS_BOOL m_bBypass; // if EAS_TRUE, then bypass reverb and copy input to output + + EAS_I16 m_nCurrentRoom; // preset number for current room + + EAS_I16 m_nNextRoom; // preset number for next room + + EAS_I16 m_nWet; // gain for wet (processed) signal + + EAS_I16 m_nDry; // gain for dry (unprocessed) signal + + EAS_I16 m_nEarly; // gain for early (widen) signal + + S_EARLY_REFLECTION_OBJECT m_sEarlyL; // left channel early reflections + S_EARLY_REFLECTION_OBJECT m_sEarlyR; // right channel early reflections + + EAS_PCM m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES]; // one large delay line for all reverb elements + + S_REVERB_PRESET pPreset; + + S_REVERB_PRESET_BANK m_sPreset; + + //EAS_I8 preset; + +} S_REVERB_OBJECT; + + +/*------------------------------------ + * prototypes + *------------------------------------ +*/ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise); + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos); + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Reverb(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer); + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT* pReverbData); + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT* pReverbData); + +#endif /* #ifndef _EAS_REVERBDATA_H */ + + diff --git a/arm-fm-22k/lib_src/eas_rtttl.c b/arm-fm-22k/lib_src/eas_rtttl.c index 486ad60..d8253fb 100644 --- a/arm-fm-22k/lib_src/eas_rtttl.c +++ b/arm-fm-22k/lib_src/eas_rtttl.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_rtttl.c
- *
- * Contents and purpose:
- * RTTTL parser
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttl.c + * + * Contents and purpose: + * RTTTL parser + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,1179 +19,1179 @@ * 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: 795 $
- * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_miditypes.h"
-#include "eas_parser.h"
-#include "eas_report.h"
-#include "eas_host.h"
-#include "eas_midi.h"
-#include "eas_config.h"
-#include "eas_vm_protos.h"
-#include "eas_rtttldata.h"
-#include "eas_ctype.h"
-
-/* increase gain for mono ringtones */
-#define RTTTL_GAIN_OFFSET 8
-
-/* maximum title length including colon separator */
-#define RTTTL_MAX_TITLE_LEN 32
-#define RTTTL_INFINITE_LOOP 15
-
-/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */
-#define DEFAULT_TICK_CONV 30476
-#define TICK_CONVERT 1920000
-
-/* default channel and program for RTTTL playback */
-#define RTTTL_CHANNEL 0
-#define RTTTL_PROGRAM 80
-#define RTTTL_VELOCITY 127
-
-/* note used for rest */
-#define RTTTL_REST 1
-
-/* multiplier for fixed point triplet conversion */
-#define TRIPLET_MULTIPLIER 683
-#define TRIPLET_SHIFT 10
-
-/* local prototypes */
-static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
-static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
-static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
-static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
-static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData);
-static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration);
-static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave);
-static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData);
-static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue);
-static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData);
-static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue);
-static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue);
-
-/* inline functions */
-EAS_INLINE void RTTTL_PutBackChar (S_RTTTL_DATA *pData, EAS_I8 value) { pData->dataByte = value; }
-
-
-/* lookup table for note values */
-static const EAS_U8 noteTable[] = { 21, 23, 12, 14, 16, 17, 19, 23 };
-
-/*----------------------------------------------------------------------------
- *
- * EAS_RTTTL_Parser
- *
- * This structure contains the functional interface for the iMelody parser
- *----------------------------------------------------------------------------
-*/
-const S_FILE_PARSER_INTERFACE EAS_RTTTL_Parser =
-{
- RTTTL_CheckFileType,
- RTTTL_Prepare,
- RTTTL_Time,
- RTTTL_Event,
- RTTTL_State,
- RTTTL_Close,
- RTTTL_Reset,
- RTTTL_Pause,
- RTTTL_Resume,
- NULL,
- RTTTL_SetData,
- RTTTL_GetData,
- NULL
-};
-
-/*----------------------------------------------------------------------------
- * RTTTL_CheckFileType()
- *----------------------------------------------------------------------------
- * Purpose:
- * Check the file type to see if we can parse it
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
-{
- S_RTTTL_DATA data;
- S_RTTTL_DATA *pData;
-
- /* see if we can parse the header */
- data.fileHandle = fileHandle;
- data.fileOffset = offset;
- *ppHandle= NULL;
- if (RTTTL_ParseHeader (pEASData, &data, EAS_FALSE) == EAS_SUCCESS)
- {
-
- /* check for static memory allocation */
- if (pEASData->staticMemoryModel)
- pData = EAS_CMEnumData(EAS_CM_RTTTL_DATA);
- else
- pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_RTTTL_DATA));
- if (!pData)
- return EAS_ERROR_MALLOC_FAILED;
- EAS_HWMemSet(pData, 0, sizeof(S_RTTTL_DATA));
-
- /* return a pointer to the instance data */
- pData->fileHandle = fileHandle;
- pData->fileOffset = offset;
- pData->state = EAS_STATE_OPEN;
- *ppHandle = pData;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_Prepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_RTTTL_DATA* pData;
- EAS_RESULT result;
-
- /* check for valid state */
- pData = (S_RTTTL_DATA*) pInstData;
- if (pData->state != EAS_STATE_OPEN)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* instantiate a synthesizer */
- if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ }
- return result;
- }
-
- pData->state = EAS_STATE_ERROR;
- if ((result = RTTTL_ParseHeader (pEASData, pData, (EAS_BOOL) (pData->metadata.callback != NULL))) != EAS_SUCCESS)
- {
- /* if using dynamic memory, free it */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pData);
- return result;
- }
-
- pData->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_Time()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the time of the next event in msecs
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pTime - pointer to variable to hold time of next event (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
-{
- S_RTTTL_DATA *pData;
-
- pData = (S_RTTTL_DATA*) pInstData;
-
- /* return time in milliseconds */
- /*lint -e{704} use shift instead of division */
- *pTime = pData->time >> 8;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_Event()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the next event in the file
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
-{
- S_RTTTL_DATA* pData;
- EAS_RESULT result;
- EAS_I32 ticks;
- EAS_I32 temp;
- EAS_I8 c;
- EAS_U8 note;
- EAS_U8 octave;
-
- pData = (S_RTTTL_DATA*) pInstData;
- if (pData->state >= EAS_STATE_OPEN)
- return EAS_SUCCESS;
-
- /* initialize MIDI channel when the track starts playing */
- if (pData->time == 0)
- {
- /* set program to square lead */
- VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, RTTTL_PROGRAM);
-
- /* set channel volume to max */
- VMControlChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, 7, 127);
- }
-
- /* check for end of note */
- if (pData->note)
- {
- /* stop the note */
- VMStopNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, 0);
- pData->note = 0;
-
- /* check for rest between notes */
- if (pData->restTicks)
- {
- pData->time += pData->restTicks;
- pData->restTicks = 0;
- return EAS_SUCCESS;
- }
- }
-
- /* parse the next event */
- octave = pData->octave;
- note = 0;
- ticks = pData->duration * pData->tick;
- for (;;)
- {
-
- /* get next character */
- if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS)
- {
- if (result != EAS_EOF)
- return result;
-
- /* end of file, if no notes to process, check for looping */
- if (!note)
- {
- /* if no loop set state to stopping */
- if (pData->repeatCount == 0)
- {
- pData->state = EAS_STATE_STOPPING;
- VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth);
- return EAS_SUCCESS;
- }
-
- /* decrement loop count */
- if (pData->repeatCount != RTTTL_INFINITE_LOOP)
- pData->repeatCount--;
-
- /* if locating, ignore infinite loops */
- else if (parserMode != eParserModePlay)
- {
- pData->state = EAS_STATE_STOPPING;
- VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth);
- return EAS_SUCCESS;
- }
-
- /* loop back to start of notes */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS)
- return result;
- continue;
- }
-
- /* still have a note to process */
- else
- c = ',';
- }
-
- /* bpm */
- if (c == 'b')
- {
- /* peek at next character */
- if ((result = RTTTL_PeekNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS)
- return result;
-
- /* if a number, must be octave or tempo */
- if (IsDigit(c))
- {
- if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS)
- return result;
-
- /* check for octave first */
- if ((temp >= 4) && (temp <= 7))
- {
- octave = (EAS_U8) temp;
- }
-
- /* check for tempo */
- else if ((temp >= 25) && (temp <= 900))
- {
- pData->tick = TICK_CONVERT / (EAS_U32) temp;
- }
-
- /* don't know what it was */
- else
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* must be a note */
- else
- {
- note = noteTable[1];
- }
- }
-
- /* octave */
- else if (c == 'o')
- {
- if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS)
- return result;
- }
-
- /* style */
- else if (c == 's')
- {
- if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS)
- return result;
- }
-
- /* duration or octave */
- else if (IsDigit(c))
- {
- RTTTL_PutBackChar(pData, c);
-
- /* duration comes before note */
- if (!note)
- {
- if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS)
- return result;
- ticks = c * pData->tick;
- }
-
- /* octave comes after note */
- else
- {
- if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &octave)) != EAS_SUCCESS)
- return result;
- }
- }
-
- /* note or rest */
- else if ((c >= 'a') && (c <= 'h'))
- {
- note = noteTable[c - 'a'];
- }
-
- else if (c == 'p')
- {
- note = RTTTL_REST;
- }
-
- /* dotted note */
- else if (c == '.')
- {
- /*lint -e{704} shift for performance */
- ticks += ticks >> 1;
- }
-
- /* accidental */
- else if (c == '#')
- {
- if (note)
- note++;
- }
-
- /* end of event */
- else if ((c == ',') && note)
- {
-
- /* handle note events */
- if (note != RTTTL_REST)
- {
-
- /* save note and start it */
- pData->note = note + octave;
- if (parserMode == eParserModePlay)
- VMStartNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, RTTTL_VELOCITY);
-
- /* determine note length */
- switch (pData->style)
- {
- /* natural */
- case 'n':
- /*lint -e{704} shift for performance */
- pData->restTicks = ticks >> 4;
- break;
- /* continuous */
-
- case 'c':
- pData->restTicks = 0;
- break;
-
- /* staccato */
- case 's':
- /*lint -e{704} shift for performance */
- pData->restTicks = ticks >> 1;
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "RTTTL_Event: Unexpected style type %c\n", pData->style); */ }
- break;
- }
-
- /* next event is at end of this note */
- pData->time += ticks - pData->restTicks;
- }
-
- /* rest */
- else
- pData->time += ticks;
-
- /* event found, return to caller */
- break;
- }
- }
-
- pData->state = EAS_STATE_PLAY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_State()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
-{
- S_RTTTL_DATA* pData;
-
- /* establish pointer to instance data */
- pData = (S_RTTTL_DATA*) pInstData;
-
- /* if stopping, check to see if synth voices are active */
- if (pData->state == EAS_STATE_STOPPING)
- {
- if (VMActiveVoices(pData->pSynth) == 0)
- pData->state = EAS_STATE_STOPPED;
- }
-
- if (pData->state == EAS_STATE_PAUSING)
- {
- if (VMActiveVoices(pData->pSynth) == 0)
- pData->state = EAS_STATE_PAUSED;
- }
-
- /* return current state */
- *pState = pData->state;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_Close()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_RTTTL_DATA* pData;
- EAS_RESULT result;
-
- pData = (S_RTTTL_DATA*) pInstData;
-
- /* close the file */
- if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS)
- return result;
-
- /* free the synth */
- if (pData->pSynth != NULL)
- VMMIDIShutdown(pEASData, pData->pSynth);
-
- /* if using dynamic memory, free it */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pData);
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_Reset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_RTTTL_DATA* pData;
- EAS_RESULT result;
-
- pData = (S_RTTTL_DATA*) pInstData;
-
- /* reset the synth */
- VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE);
-
- /* reset time to zero */
- pData->time = 0;
- pData->note = 0;
-
- /* reset file position and re-parse header */
- pData->state = EAS_STATE_ERROR;
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS)
- return result;
- if ((result = RTTTL_ParseHeader (pEASData, pData, EAS_TRUE)) != EAS_SUCCESS)
- return result;
-
- pData->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_Pause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Pauses the sequencer. Mutes all voices and sets state to pause.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_RTTTL_DATA *pData;
-
- /* can't pause a stopped stream */
- pData = (S_RTTTL_DATA*) pInstData;
- if (pData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* mute the synthesizer */
- VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth);
- pData->state = EAS_STATE_PAUSING;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_Resume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume playing after a pause, sets state back to playing.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_RTTTL_DATA *pData;
-
- /* can't resume a stopped stream */
- pData = (S_RTTTL_DATA*) pInstData;
- if (pData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* nothing to do but resume playback */
- pData->state = EAS_STATE_PLAY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_SetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Return file type
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_RTTTL_DATA *pData;
-
- pData = (S_RTTTL_DATA *) pInstData;
- switch (param)
- {
-
- /* set metadata callback */
- case PARSER_DATA_METADATA_CB:
- EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB));
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_GetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Return file type
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_RTTTL_DATA *pData;
-
- pData = (S_RTTTL_DATA *) pInstData;
- switch (param)
- {
- /* return file type as RTTTL */
- case PARSER_DATA_FILE_TYPE:
- *pValue = EAS_FILE_RTTTL;
- break;
-
-#if 0
- /* set transposition */
- case PARSER_DATA_TRANSPOSITION:
- *pValue = pData->transposition;
- break;
-#endif
-
- case PARSER_DATA_SYNTH_HANDLE:
- *pValue = (EAS_I32) pData->pSynth;
- break;
-
- case PARSER_DATA_GAIN_OFFSET:
- *pValue = RTTTL_GAIN_OFFSET;
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_GetStyle()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData)
-{
- EAS_RESULT result;
- EAS_I8 style;
-
- /* get style */
- if ((result = RTTTL_GetNextChar(hwInstData, pData, &style)) != EAS_SUCCESS)
- return result;
-
- if ((style != 's') && (style != 'n') && (style != 'c'))
- return EAS_ERROR_FILE_FORMAT;
-
- pData->style = style;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_GetDuration()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration)
-{
- EAS_RESULT result;
- EAS_I32 duration;
- EAS_I8 temp;
-
- /* get the duration */
- if ((result = RTTTL_GetNumber(hwInstData, pData, &duration)) != EAS_SUCCESS)
- return result;
-
- if ((duration != 1) && (duration != 2) && (duration != 4) && (duration != 8) && (duration != 16) && (duration != 32))
- return EAS_ERROR_FILE_FORMAT;
-
- temp = 64;
- while (duration)
- {
- /*lint -e{704} shift for performance */
- duration = duration >> 1;
- /*lint -e{702} use shift for performance */
- temp = temp >> 1;
- }
-
- *pDuration = temp;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_GetOctave()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave)
-{
- EAS_RESULT result;
- EAS_I32 octave;
-
- /* get the tempo */
- if ((result = RTTTL_GetNumber(hwInstData, pData, &octave)) != EAS_SUCCESS)
- return result;
-
- if ((octave < 4) || (octave > 7))
- return EAS_ERROR_FILE_FORMAT;
-
- *pOctave = (EAS_U8) (octave * 12);
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_GetTempo()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData)
-{
- EAS_RESULT result;
- EAS_I32 tempo;
-
- /* get the tempo */
- if ((result = RTTTL_GetNumber(hwInstData, pData, &tempo)) != EAS_SUCCESS)
- return result;
-
- if ((tempo < 25) || (tempo > 900))
- return EAS_ERROR_FILE_FORMAT;
-
- pData->tick = TICK_CONVERT / (EAS_U32) tempo;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_GetNumber()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue)
-{
- EAS_RESULT result;
- EAS_INT temp;
- EAS_I8 c;
-
- *pValue = -1;
- temp = 0;
- for (;;)
- {
- if ((result = RTTTL_PeekNextChar(hwInstData, pData, &c)) != EAS_SUCCESS)
- {
- if ((result == EAS_EOF) && (*pValue != -1))
- return EAS_SUCCESS;
- return result;
- }
-
- if (IsDigit(c))
- {
- pData->dataByte = 0;
- temp = temp * 10 + c - '0';
- *pValue = temp;
- }
- else
- return EAS_SUCCESS;
- }
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_ParseHeader()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData)
-{
- EAS_RESULT result;
- EAS_I32 i;
- EAS_I8 temp;
- EAS_I8 control;
-
- /* initialize some defaults */
- pData->time = 0;
- pData->tick = DEFAULT_TICK_CONV;
- pData->note = 0;
- pData->duration = 4;
- pData ->restTicks = 0;
- pData->octave = 60;
- pData->repeatOffset = -1;
- pData->repeatCount = 0;
- pData->style = 'n';
- pData->dataByte = 0;
-
- metaData = metaData && (pData->metadata.buffer != NULL) && (pData->metadata.callback != NULL);
-
- /* seek to start of data */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS)
- return result;
-
- /* zero the metadata buffer */
- if (metaData)
- EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize);
-
- /* read the title */
- for (i = 0; i < RTTTL_MAX_TITLE_LEN; i++)
- {
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS)
- return result;
-
- if (temp == ':')
- break;
-
- /* pass along metadata */
- if (metaData)
- {
- if (i < (pData->metadata.bufferSize- 1))
- pData->metadata.buffer[i] = (char) temp;
- }
- }
-
- /* check for error in title */
- if (i == RTTTL_MAX_TITLE_LEN)
- return EAS_ERROR_FILE_FORMAT;
-
- /* pass along metadata */
- if (metaData)
- (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData);
-
- /* control fields */
- for (;;)
- {
-
- /* get control type */
- if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &control)) != EAS_SUCCESS)
- return result;
-
- /* next char should be equal sign */
- if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS)
- return result;
- if (temp != '=')
- return EAS_ERROR_FILE_FORMAT;
-
- /* get the control value */
- switch (control)
- {
-
- /* bpm */
- case 'b':
- if ((result = RTTTL_GetTempo(pEASData->hwInstData, pData)) != EAS_SUCCESS)
- return result;
- break;
-
- /* duration */
- case 'd':
- if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS)
- return result;
- pData->duration = temp;
- break;
-
- /* loop */
- case 'l':
- if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &i)) != EAS_SUCCESS)
- return result;
- if ((i < 0) || (i > 15))
- return EAS_ERROR_FILE_FORMAT;
- pData->repeatCount = (EAS_U8) i;
- break;
-
- /* octave */
- case 'o':
- if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS)
- return result;
- break;
-
- /* get style */
- case 's':
- if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS)
- return result;
- break;
-
- /* unrecognized control */
- default:
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* next character should be comma or colon */
- if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS)
- return result;
-
- /* check for end of control field */
- if (temp == ':')
- break;
-
- /* must be a comma */
- if (temp != ',')
- return EAS_ERROR_FILE_FORMAT;
- }
-
- /* should be at the start of the music block */
- if ((result = EAS_HWFilePos(pEASData->hwInstData, pData->fileHandle, &pData->repeatOffset)) != EAS_SUCCESS)
- return result;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_GetNextChar()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue)
-{
- EAS_RESULT result;
- EAS_I8 temp;
-
- *pValue = 0;
- for(;;)
- {
-
- /* check for character that has been put back */
- if (pData->dataByte)
- {
- temp = pData->dataByte;
- pData->dataByte = 0;
- }
- else
- {
- if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS)
- return result;
- }
-
- /* ignore white space */
- if (!IsSpace(temp))
- {
- *pValue = ToLower(temp);
- return EAS_SUCCESS;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * RTTTL_PeekNextChar()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue)
-{
- EAS_RESULT result;
- EAS_I8 temp;
-
- *pValue = 0;
- for(;;)
- {
-
- /* read a character from the file, if necessary */
- if (!pData->dataByte)
- {
- if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->dataByte)) != EAS_SUCCESS)
- return result;
-
- }
- temp = pData->dataByte;
-
- /* ignore white space */
- if (!IsSpace(temp))
- {
- *pValue = ToLower(temp);
- return EAS_SUCCESS;
- }
- pData->dataByte = 0;
- }
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_rtttldata.h" +#include "eas_ctype.h" + +/* increase gain for mono ringtones */ +#define RTTTL_GAIN_OFFSET 8 + +/* maximum title length including colon separator */ +#define RTTTL_MAX_TITLE_LEN 32 +#define RTTTL_INFINITE_LOOP 15 + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 +#define TICK_CONVERT 1920000 + +/* default channel and program for RTTTL playback */ +#define RTTTL_CHANNEL 0 +#define RTTTL_PROGRAM 80 +#define RTTTL_VELOCITY 127 + +/* note used for rest */ +#define RTTTL_REST 1 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration); +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave); +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue); +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData); +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); + +/* inline functions */ +EAS_INLINE void RTTTL_PutBackChar (S_RTTTL_DATA *pData, EAS_I8 value) { pData->dataByte = value; } + + +/* lookup table for note values */ +static const EAS_U8 noteTable[] = { 21, 23, 12, 14, 16, 17, 19, 23 }; + +/*---------------------------------------------------------------------------- + * + * EAS_RTTTL_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_RTTTL_Parser = +{ + RTTTL_CheckFileType, + RTTTL_Prepare, + RTTTL_Time, + RTTTL_Event, + RTTTL_State, + RTTTL_Close, + RTTTL_Reset, + RTTTL_Pause, + RTTTL_Resume, + NULL, + RTTTL_SetData, + RTTTL_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * RTTTL_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_RTTTL_DATA data; + S_RTTTL_DATA *pData; + + /* see if we can parse the header */ + data.fileHandle = fileHandle; + data.fileOffset = offset; + *ppHandle= NULL; + if (RTTTL_ParseHeader (pEASData, &data, EAS_FALSE) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_RTTTL_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_RTTTL_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_RTTTL_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = RTTTL_ParseHeader (pEASData, pData, (EAS_BOOL) (pData->metadata.callback != NULL))) != EAS_SUCCESS) + { + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + return result; + } + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + EAS_I32 ticks; + EAS_I32 temp; + EAS_I8 c; + EAS_U8 note; + EAS_U8 octave; + + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, RTTTL_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + octave = pData->octave; + note = 0; + ticks = pData->duration * pData->tick; + for (;;) + { + + /* get next character */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + { + if (result != EAS_EOF) + return result; + + /* end of file, if no notes to process, check for looping */ + if (!note) + { + /* if no loop set state to stopping */ + if (pData->repeatCount == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* decrement loop count */ + if (pData->repeatCount != RTTTL_INFINITE_LOOP) + pData->repeatCount--; + + /* if locating, ignore infinite loops */ + else if (parserMode != eParserModePlay) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* loop back to start of notes */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + continue; + } + + /* still have a note to process */ + else + c = ','; + } + + /* bpm */ + if (c == 'b') + { + /* peek at next character */ + if ((result = RTTTL_PeekNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + + /* if a number, must be octave or tempo */ + if (IsDigit(c)) + { + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for octave first */ + if ((temp >= 4) && (temp <= 7)) + { + octave = (EAS_U8) temp; + } + + /* check for tempo */ + else if ((temp >= 25) && (temp <= 900)) + { + pData->tick = TICK_CONVERT / (EAS_U32) temp; + } + + /* don't know what it was */ + else + return EAS_ERROR_FILE_FORMAT; + } + + /* must be a note */ + else + { + note = noteTable[1]; + } + } + + /* octave */ + else if (c == 'o') + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + } + + /* style */ + else if (c == 's') + { + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + } + + /* duration or octave */ + else if (IsDigit(c)) + { + RTTTL_PutBackChar(pData, c); + + /* duration comes before note */ + if (!note) + { + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + ticks = c * pData->tick; + } + + /* octave comes after note */ + else + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + } + } + + /* note or rest */ + else if ((c >= 'a') && (c <= 'h')) + { + note = noteTable[c - 'a']; + } + + else if (c == 'p') + { + note = RTTTL_REST; + } + + /* dotted note */ + else if (c == '.') + { + /*lint -e{704} shift for performance */ + ticks += ticks >> 1; + } + + /* accidental */ + else if (c == '#') + { + if (note) + note++; + } + + /* end of event */ + else if ((c == ',') && note) + { + + /* handle note events */ + if (note != RTTTL_REST) + { + + /* save note and start it */ + pData->note = note + octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, RTTTL_VELOCITY); + + /* determine note length */ + switch (pData->style) + { + /* natural */ + case 'n': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 4; + break; + /* continuous */ + + case 'c': + pData->restTicks = 0; + break; + + /* staccato */ + case 's': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 1; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "RTTTL_Event: Unexpected style type %c\n", pData->style); */ } + break; + } + + /* next event is at end of this note */ + pData->time += ticks - pData->restTicks; + } + + /* rest */ + else + pData->time += ticks; + + /* event found, return to caller */ + break; + } + } + + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_RTTTL_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_RTTTL_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = RTTTL_ParseHeader (pEASData, pData, EAS_TRUE)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + /* return file type as RTTTL */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_RTTTL; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = RTTTL_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetStyle() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I8 style; + + /* get style */ + if ((result = RTTTL_GetNextChar(hwInstData, pData, &style)) != EAS_SUCCESS) + return result; + + if ((style != 's') && (style != 'n') && (style != 'c')) + return EAS_ERROR_FILE_FORMAT; + + pData->style = style; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration) +{ + EAS_RESULT result; + EAS_I32 duration; + EAS_I8 temp; + + /* get the duration */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &duration)) != EAS_SUCCESS) + return result; + + if ((duration != 1) && (duration != 2) && (duration != 4) && (duration != 8) && (duration != 16) && (duration != 32)) + return EAS_ERROR_FILE_FORMAT; + + temp = 64; + while (duration) + { + /*lint -e{704} shift for performance */ + duration = duration >> 1; + /*lint -e{702} use shift for performance */ + temp = temp >> 1; + } + + *pDuration = temp; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetOctave() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave) +{ + EAS_RESULT result; + EAS_I32 octave; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + + if ((octave < 4) || (octave > 7)) + return EAS_ERROR_FILE_FORMAT; + + *pOctave = (EAS_U8) (octave * 12); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetTempo() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I32 tempo; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &tempo)) != EAS_SUCCESS) + return result; + + if ((tempo < 25) || (tempo > 900)) + return EAS_ERROR_FILE_FORMAT; + + pData->tick = TICK_CONVERT / (EAS_U32) tempo; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue) +{ + EAS_RESULT result; + EAS_INT temp; + EAS_I8 c; + + *pValue = -1; + temp = 0; + for (;;) + { + if ((result = RTTTL_PeekNextChar(hwInstData, pData, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (*pValue != -1)) + return EAS_SUCCESS; + return result; + } + + if (IsDigit(c)) + { + pData->dataByte = 0; + temp = temp * 10 + c - '0'; + *pValue = temp; + } + else + return EAS_SUCCESS; + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_I8 temp; + EAS_I8 control; + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->duration = 4; + pData ->restTicks = 0; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = 0; + pData->style = 'n'; + pData->dataByte = 0; + + metaData = metaData && (pData->metadata.buffer != NULL) && (pData->metadata.callback != NULL); + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* zero the metadata buffer */ + if (metaData) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the title */ + for (i = 0; i < RTTTL_MAX_TITLE_LEN; i++) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + if (temp == ':') + break; + + /* pass along metadata */ + if (metaData) + { + if (i < (pData->metadata.bufferSize- 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* check for error in title */ + if (i == RTTTL_MAX_TITLE_LEN) + return EAS_ERROR_FILE_FORMAT; + + /* pass along metadata */ + if (metaData) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + + /* control fields */ + for (;;) + { + + /* get control type */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &control)) != EAS_SUCCESS) + return result; + + /* next char should be equal sign */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + if (temp != '=') + return EAS_ERROR_FILE_FORMAT; + + /* get the control value */ + switch (control) + { + + /* bpm */ + case 'b': + if ((result = RTTTL_GetTempo(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* duration */ + case 'd': + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + pData->duration = temp; + break; + + /* loop */ + case 'l': + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &i)) != EAS_SUCCESS) + return result; + if ((i < 0) || (i > 15)) + return EAS_ERROR_FILE_FORMAT; + pData->repeatCount = (EAS_U8) i; + break; + + /* octave */ + case 'o': + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + break; + + /* get style */ + case 's': + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* unrecognized control */ + default: + return EAS_ERROR_FILE_FORMAT; + } + + /* next character should be comma or colon */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for end of control field */ + if (temp == ':') + break; + + /* must be a comma */ + if (temp != ',') + return EAS_ERROR_FILE_FORMAT; + } + + /* should be at the start of the music block */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pData->fileHandle, &pData->repeatOffset)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* check for character that has been put back */ + if (pData->dataByte) + { + temp = pData->dataByte; + pData->dataByte = 0; + } + else + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + } + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_PeekNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* read a character from the file, if necessary */ + if (!pData->dataByte) + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->dataByte)) != EAS_SUCCESS) + return result; + + } + temp = pData->dataByte; + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + pData->dataByte = 0; + } +} + diff --git a/arm-fm-22k/lib_src/eas_rtttldata.c b/arm-fm-22k/lib_src/eas_rtttldata.c index 7a500bd..708a1d9 100644 --- a/arm-fm-22k/lib_src/eas_rtttldata.c +++ b/arm-fm-22k/lib_src/eas_rtttldata.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_rtttldata.c
- *
- * Contents and purpose:
- * RTTTL File Parser data module for static memory models
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.c + * + * Contents and purpose: + * RTTTL File Parser data module for static memory models + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,23 +19,23 @@ * 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: 547 $
- * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_types.h"
-#include "eas_rtttldata.h"
-
-/*----------------------------------------------------------------------------
- *
- * eas_RTTTLData
- *
- * Static memory allocation for RTTTL parser
- *----------------------------------------------------------------------------
-*/
-S_RTTTL_DATA eas_RTTTLData;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_rtttldata.h" + +/*---------------------------------------------------------------------------- + * + * eas_RTTTLData + * + * Static memory allocation for RTTTL parser + *---------------------------------------------------------------------------- +*/ +S_RTTTL_DATA eas_RTTTLData; + diff --git a/arm-fm-22k/lib_src/eas_rtttldata.h b/arm-fm-22k/lib_src/eas_rtttldata.h index bf4c38b..31dd522 100644 --- a/arm-fm-22k/lib_src/eas_rtttldata.h +++ b/arm-fm-22k/lib_src/eas_rtttldata.h @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_rtttldata.h
- *
- * Contents and purpose:
- * SMF File Parser
- *
- * This file contains data declarations for the RTTTL parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the RTTTL parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,50 +21,50 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef EAS_RTTTLDATA_H
-#define EAS_RTTTLDATA_H
-
-#include "eas_data.h"
-
-
-/* maximum line size as specified in iMelody V1.2 spec */
-#define MAX_LINE_SIZE 75
-
-/*----------------------------------------------------------------------------
- *
- * S_RTTTL_DATA
- *
- * This structure contains the state data for the iMelody parser
- *----------------------------------------------------------------------------
-*/
-
-typedef struct
-{
- EAS_FILE_HANDLE fileHandle; /* file handle */
- S_SYNTH *pSynth; /* synthesizer handle */
- S_METADATA_CB metadata; /* metadata callback */
- EAS_I32 fileOffset; /* offset to start of data */
- EAS_I32 time; /* current time in 256ths of a msec */
- EAS_I32 tick; /* length of 32nd note in 256th of a msec */
- EAS_I32 restTicks; /* ticks to rest after current note */
- EAS_I32 repeatOffset; /* file offset to start of repeat section */
- EAS_U8 repeatCount; /* repeat counter */
- EAS_I8 dataByte; /* storage for characters that are "put back" */
- EAS_U8 state; /* current state EAS_STATE_XXXX */
- EAS_I8 style; /* from STYLE */
- EAS_U8 note; /* MIDI note number */
- EAS_U8 octave; /* decault octave prefix */
- EAS_I8 duration; /* default note duration */
-} S_RTTTL_DATA;
-
-#endif
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_RTTTLDATA_H +#define EAS_RTTTLDATA_H + +#include "eas_data.h" + + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_RTTTL_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synthesizer handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tick; /* length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + EAS_U8 repeatCount; /* repeat counter */ + EAS_I8 dataByte; /* storage for characters that are "put back" */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_I8 style; /* from STYLE */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* decault octave prefix */ + EAS_I8 duration; /* default note duration */ +} S_RTTTL_DATA; + +#endif + + diff --git a/arm-fm-22k/lib_src/eas_smf.c b/arm-fm-22k/lib_src/eas_smf.c index 7b56e97..e609583 100644 --- a/arm-fm-22k/lib_src/eas_smf.c +++ b/arm-fm-22k/lib_src/eas_smf.c @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_smf.c
- *
- * Contents and purpose:
- * SMF Type 0 and 1 File Parser
- *
- * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls".
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.c + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls". + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,1183 +21,1183 @@ * 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: 803 $
- * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_miditypes.h"
-#include "eas_parser.h"
-#include "eas_report.h"
-#include "eas_host.h"
-#include "eas_midi.h"
-#include "eas_config.h"
-#include "eas_vm_protos.h"
-#include "eas_smfdata.h"
-#include "eas_smf.h"
-
-#ifdef JET_INTERFACE
-#include "jet_data.h"
-#endif
-
-//3 dls: The timebase for this module is adequate to keep MIDI and
-//3 digital audio synchronized for only a few minutes. It should be
-//3 sufficient for most mobile applications. If better accuracy is
-//3 required, more fractional bits should be added to the timebase.
-
-static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' };
-
-/* local prototypes */
-static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData);
-static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream);
-static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode);
-static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode);
-static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream);
-static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks);
-
-
-/*----------------------------------------------------------------------------
- *
- * SMF_Parser
- *
- * This structure contains the functional interface for the SMF parser
- *----------------------------------------------------------------------------
-*/
-const S_FILE_PARSER_INTERFACE EAS_SMF_Parser =
-{
- SMF_CheckFileType,
- SMF_Prepare,
- SMF_Time,
- SMF_Event,
- SMF_State,
- SMF_Close,
- SMF_Reset,
- SMF_Pause,
- SMF_Resume,
- NULL,
- SMF_SetData,
- SMF_GetData,
- NULL
-};
-
-/*----------------------------------------------------------------------------
- * SMF_CheckFileType()
- *----------------------------------------------------------------------------
- * Purpose:
- * Check the file type to see if we can parse it
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
-{
- S_SMF_DATA* pSMFData;
- EAS_RESULT result;
-
- /* seek to starting offset - usually 0 */
- *ppHandle = NULL;
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS)
- return result;
-
- /* search through file for header - slow method */
- if (pEASData->searchHeaderFlag)
- {
- result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset);
- if (result != EAS_SUCCESS)
- return (result == EAS_EOF) ? EAS_SUCCESS : result;
- }
-
- /* read the first 4 bytes of the file - quick method */
- else {
- EAS_U8 header[4];
- EAS_I32 count;
- if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS)
- return result;
-
- /* check for 'MTrk' - return if no match */
- if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd'))
- return EAS_SUCCESS;
- }
-
- /* check for static memory allocation */
- if (pEASData->staticMemoryModel)
- pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA);
- else
- {
- pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA));
- EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA));
- }
- if (!pSMFData)
- return EAS_ERROR_MALLOC_FAILED;
-
- /* initialize some critical data */
- pSMFData->fileHandle = fileHandle;
- pSMFData->fileOffset = offset;
- pSMFData->pSynth = NULL;
- pSMFData->time = 0;
- pSMFData->state = EAS_STATE_OPEN;
- *ppHandle = pSMFData;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_Prepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file. Allocates instance data (or uses static allocation for
- * static memory model).
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_SMF_DATA* pSMFData;
- EAS_RESULT result;
-
- /* check for valid state */
- pSMFData = (S_SMF_DATA *) pInstData;
- if (pSMFData->state != EAS_STATE_OPEN)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* instantiate a synthesizer */
- if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ }
- return result;
- }
-
- /* parse the file header and setup the individual stream parsers */
- if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS)
- return result;
-
- /* ready to play */
- pSMFData->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_Time()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the time of the next event in msecs
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pTime - pointer to variable to hold time of next event (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
-{
- S_SMF_DATA *pSMFData;
-
- pSMFData = (S_SMF_DATA*) pInstData;
-
- /* sanity check */
-#ifdef _CHECKED_BUILD
- if (pSMFData->state == EAS_STATE_STOPPED)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ }
- }
-
- if (pSMFData->nextStream == NULL)
- {
- { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ }
- }
-#endif
-
-#if 0
- /* return time in milliseconds */
- /* if chase mode, lie about time */
- if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
- *pTime = 0;
-
- else
-#endif
-
- /*lint -e{704} use shift instead of division */
- *pTime = pSMFData->time >> 8;
-
- *pTime = pSMFData->time >> 8;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_Event()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the next event in the file
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
-{
- S_SMF_DATA* pSMFData;
- EAS_RESULT result;
- EAS_I32 i;
- EAS_U32 ticks;
- EAS_U32 temp;
-
- /* establish pointer to instance data */
- pSMFData = (S_SMF_DATA*) pInstData;
- if (pSMFData->state >= EAS_STATE_OPEN)
- return EAS_SUCCESS;
-
- /* get current ticks */
- ticks = pSMFData->nextStream->ticks;
-
- /* assume that an error occurred */
- pSMFData->state = EAS_STATE_ERROR;
-
-#ifdef JET_INTERFACE
- /* if JET has track muted, set parser mode to mute */
- if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE)
- parserMode = eParserModeMute;
-#endif
-
- /* parse the next event from all the streams */
- if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS)
- {
- /* check for unexpected end-of-file */
- if (result != EAS_EOF)
- return result;
-
- /* indicate end of track for this stream */
- pSMFData->nextStream->ticks = SMF_END_OF_TRACK;
- }
-
- /* get next delta time, unless already at end of track */
- else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK)
- {
- if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS)
- {
- /* check for unexpected end-of-file */
- if (result != EAS_EOF)
- return result;
-
- /* indicate end of track for this stream */
- pSMFData->nextStream->ticks = SMF_END_OF_TRACK;
- }
-
- /* if zero delta to next event, stay with this stream */
- else if (pSMFData->nextStream->ticks == ticks)
- {
- pSMFData->state = EAS_STATE_PLAY;
- return EAS_SUCCESS;
- }
- }
-
- /* find next event in all streams */
- temp = 0x7ffffff;
- pSMFData->nextStream = NULL;
- for (i = 0; i < pSMFData->numStreams; i++)
- {
- if (pSMFData->streams[i].ticks < temp)
- {
- temp = pSMFData->streams[i].ticks;
- pSMFData->nextStream = &pSMFData->streams[i];
- }
- }
-
- /* are there any more events to parse? */
- if (pSMFData->nextStream)
- {
- pSMFData->state = EAS_STATE_PLAY;
-
- /* update the time of the next event */
- SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks);
- }
- else
- {
- pSMFData->state = EAS_STATE_STOPPING;
- VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth);
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_State()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
-{
- S_SMF_DATA* pSMFData;
-
- /* establish pointer to instance data */
- pSMFData = (S_SMF_DATA*) pInstData;
-
- /* if stopping, check to see if synth voices are active */
- if (pSMFData->state == EAS_STATE_STOPPING)
- {
- if (VMActiveVoices(pSMFData->pSynth) == 0)
- pSMFData->state = EAS_STATE_STOPPED;
- }
-
- if (pSMFData->state == EAS_STATE_PAUSING)
- {
- if (VMActiveVoices(pSMFData->pSynth) == 0)
- pSMFData->state = EAS_STATE_PAUSED;
- }
-
- /* return current state */
- *pState = pSMFData->state;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_Close()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_SMF_DATA* pSMFData;
- EAS_I32 i;
- EAS_RESULT result;
-
- pSMFData = (S_SMF_DATA*) pInstData;
-
- /* close all the streams */
- for (i = 0; i < pSMFData->numStreams; i++)
- {
- if (pSMFData->streams[i].fileHandle != NULL)
- {
- if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS)
- return result;
- }
- }
- if (pSMFData->fileHandle != NULL)
- if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS)
- return result;
-
- /* free the synth */
- if (pSMFData->pSynth != NULL)
- VMMIDIShutdown(pEASData, pSMFData->pSynth);
-
- /* if using dynamic memory, free it */
- if (!pEASData->staticMemoryModel)
- {
- if (pSMFData->streams)
- EAS_HWFree(pEASData->hwInstData, pSMFData->streams);
-
- /* free the instance data */
- EAS_HWFree(pEASData->hwInstData, pSMFData);
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_Reset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_SMF_DATA* pSMFData;
- EAS_I32 i;
- EAS_RESULT result;
- EAS_U32 ticks;
-
- pSMFData = (S_SMF_DATA*) pInstData;
-
- /* reset time to zero */
- pSMFData->time = 0;
-
- /* reset the synth */
- VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE);
-
- /* find the start of each track */
- ticks = 0x7fffffffL;
- pSMFData->nextStream = NULL;
- for (i = 0; i < pSMFData->numStreams; i++)
- {
-
- /* reset file position to first byte of data in track */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS)
- return result;
-
- /* initalize some data */
- pSMFData->streams[i].ticks = 0;
-
- /* initalize the MIDI parser data */
- EAS_InitMIDIStream(&pSMFData->streams[i].midiStream);
-
- /* parse the first delta time in each stream */
- if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS)
- return result;
- if (pSMFData->streams[i].ticks < ticks)
- {
- ticks = pSMFData->streams[i].ticks;
- pSMFData->nextStream = &pSMFData->streams[i];
- }
- }
-
-
- pSMFData->state = EAS_STATE_READY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_Pause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Pauses the sequencer. Mutes all voices and sets state to pause.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_SMF_DATA *pSMFData;
-
- /* can't pause a stopped stream */
- pSMFData = (S_SMF_DATA*) pInstData;
- if (pSMFData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* mute the synthesizer */
- VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth);
- pSMFData->state = EAS_STATE_PAUSING;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_Resume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume playing after a pause, sets state back to playing.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_SMF_DATA *pSMFData;
-
- /* can't resume a stopped stream */
- pSMFData = (S_SMF_DATA*) pInstData;
- if (pSMFData->state == EAS_STATE_STOPPED)
- return EAS_ERROR_ALREADY_STOPPED;
-
- /* nothing to do but resume playback */
- pSMFData->state = EAS_STATE_PLAY;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_SetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets parser parameters
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_SMF_DATA *pSMFData;
-
- pSMFData = (S_SMF_DATA*) pInstData;
- switch (param)
- {
-
- /* set metadata callback */
- case PARSER_DATA_METADATA_CB:
- EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB));
- break;
-
-#ifdef JET_INTERFACE
- /* set jet segment and track ID of all tracks for callback function */
- case PARSER_DATA_JET_CB:
- {
- EAS_U32 i;
- EAS_U32 bit = (EAS_U32) value;
- bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK;
- for (i = 0; i < pSMFData->numStreams; i++)
- pSMFData->streams[i].midiStream.jetData =
- (pSMFData->streams[i].midiStream.jetData &
- ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) |
- i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB;
- pSMFData->flags |= SMF_FLAGS_JET_STREAM;
- }
- break;
-
- /* set state of all mute flags at once */
- case PARSER_DATA_MUTE_FLAGS:
- {
- EAS_INT i;
- EAS_U32 bit = (EAS_U32) value;
- for (i = 0; i < pSMFData->numStreams; i++)
- {
- if (bit & 1)
- pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE;
- else
- pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE;
- bit >>= 1;
- }
- }
- break;
-
- /* set track mute */
- case PARSER_DATA_SET_MUTE:
- if (value < pSMFData->numStreams)
- pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE;
- else
- return EAS_ERROR_PARAMETER_RANGE;
- break;
-
- /* clear track mute */
- case PARSER_DATA_CLEAR_MUTE:
- if (value < pSMFData->numStreams)
- pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE;
- else
- return EAS_ERROR_PARAMETER_RANGE;
- break;
-#endif
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_GetData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Retrieves parser parameters
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_SMF_DATA *pSMFData;
-
- pSMFData = (S_SMF_DATA*) pInstData;
- switch (param)
- {
- /* return file type */
- case PARSER_DATA_FILE_TYPE:
- if (pSMFData->numStreams == 1)
- *pValue = EAS_FILE_SMF0;
- else
- *pValue = EAS_FILE_SMF1;
- break;
-
-/* now handled in eas_public.c */
-#if 0
- case PARSER_DATA_POLYPHONY:
- if (pSMFData->pSynth)
- VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue);
- else
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
- break;
-
- case PARSER_DATA_PRIORITY:
- if (pSMFData->pSynth)
- VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue);
- break;
-
- /* set transposition */
- case PARSER_DATA_TRANSPOSITION:
- *pValue = pSMFData->transposition;
- break;
-#endif
-
- case PARSER_DATA_SYNTH_HANDLE:
- *pValue = (EAS_I32) pSMFData->pSynth;
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_GetVarLenData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reads a varible length quantity from an SMF file
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData)
-{
- EAS_RESULT result;
- EAS_U32 data;
- EAS_U8 c;
-
- /* read until bit 7 is zero */
- data = 0;
- do
- {
- if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS)
- return result;
- data = (data << 7) | (c & 0x7f);
- } while (c & 0x80);
- *pData = data;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_GetDeltaTime()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reads a varible length quantity from an SMF file
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream)
-{
- EAS_RESULT result;
- EAS_U32 ticks;
-
- if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS)
- return result;
-
- pSMFStream->ticks += ticks;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_ParseMetaEvent()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reads a varible length quantity from an SMF file
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream)
-{
- EAS_RESULT result;
- EAS_U32 len;
- EAS_I32 pos;
- EAS_U32 temp;
- EAS_U8 c;
-
- /* get the meta-event type */
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
- return result;
-
- /* get the length */
- if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS)
- return result;
-
- /* get the current file position so we can skip the event */
- if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS)
- return result;
- pos += (EAS_I32) len;
-
- /* end of track? */
- if (c == SMF_META_END_OF_TRACK)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ }
- pSMFStream->ticks = SMF_END_OF_TRACK;
- }
-
- /* tempo event? */
- else if (c == SMF_META_TEMPO)
- {
- /* read the 3-byte timebase value */
- temp = 0;
- while (len--)
- {
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
- return result;
- temp = (temp << 8) | c;
- }
-
- pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000);
- pSMFData->flags |= SMF_FLAGS_HAS_TEMPO;
- }
-
- /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */
- else if (c == SMF_META_TIME_SIGNATURE)
- {
- pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG;
- }
-
- /* if the host has registered a metadata callback return the metadata */
- else if (pSMFData->metadata.callback)
- {
- EAS_I32 readLen;
- E_EAS_METADATA_TYPE metaType;
-
- metaType = EAS_METADATA_UNKNOWN;
-
- /* only process title on the first track */
- if (c == SMF_META_SEQTRK_NAME)
- metaType = EAS_METADATA_TITLE;
- else if (c == SMF_META_TEXT)
- metaType = EAS_METADATA_TEXT;
- else if (c == SMF_META_COPYRIGHT)
- metaType = EAS_METADATA_COPYRIGHT;
- else if (c == SMF_META_LYRIC)
- metaType = EAS_METADATA_LYRIC;
-
- if (metaType != EAS_METADATA_UNKNOWN)
- {
- readLen = pSMFData->metadata.bufferSize - 1;
- if ((EAS_I32) len < readLen)
- readLen = (EAS_I32) len;
- if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS)
- return result;
- pSMFData->metadata.buffer[readLen] = 0;
- pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData);
- }
- }
-
- /* position file to next event - in case we ignored all or part of the meta-event */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS)
- return result;
-
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_ParseSysEx()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reads a varible length quantity from an SMF file
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode)
-{
- EAS_RESULT result;
- EAS_U32 len;
- EAS_U8 c;
-
- /* get the length */
- if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS)
- return result;
-
- /* start of SysEx message? */
- if (f0 == 0xf0)
- {
- if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS)
- return result;
- }
-
- /* feed the SysEx to the stream parser */
- while (len--)
- {
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
- return result;
- if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
- return result;
-
- /* check for GM system ON */
- if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON)
- pSMFData->flags |= SMF_FLAGS_HAS_GM_ON;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_ParseEvent()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reads a varible length quantity from an SMF file
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode)
-{
- EAS_RESULT result;
- EAS_U8 c;
-
- /* get the event type */
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
- return result;
-
- /* parse meta-event */
- if (c == 0xff)
- {
- if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS)
- return result;
- }
-
- /* parse SysEx */
- else if ((c == 0xf0) || (c == 0xf7))
- {
- if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS)
- return result;
- }
-
- /* parse MIDI message */
- else
- {
- if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
- return result;
-
- /* keep streaming data to the MIDI parser until the message is complete */
- while (pSMFStream->midiStream.pending)
- {
- if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
- return result;
- if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
- return result;
- }
-
- }
-
- /* chase mode logic */
- if (pSMFData->time == 0)
- {
- if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
- {
- if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE)
- pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE;
- }
- else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR)
- pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_ParseHeader()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parses the header of an SMF file, allocates memory the stream parsers and initializes the
- * stream parsers.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * pSMFData - pointer to parser instance data
- * fileHandle - file handle
- * fileOffset - offset in the file where the header data starts, usually 0
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */
-EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData)
-{
- EAS_RESULT result;
- EAS_I32 i;
- EAS_U16 division;
- EAS_U32 chunkSize;
- EAS_U32 chunkStart;
- EAS_U32 temp;
- EAS_U32 ticks;
-
- /* rewind the file and find the end of the header chunk */
- if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS)
- goto ReadError;
- if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS)
- goto ReadError;
-
- /* determine the number of tracks */
- if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS)
- goto ReadError;
- if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS)
- goto ReadError;
-
- /* limit the number of tracks */
- if (pSMFData->numStreams > MAX_SMF_STREAMS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ }
- pSMFData->numStreams = MAX_SMF_STREAMS;
- }
-
- /* get the time division */
- if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS)
- goto ReadError;
-
- /* setup default timebase for 120 bpm */
- pSMFData->ppqn = 192;
- if (division & 0x8000)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ }
- else
- pSMFData->ppqn = (division & 0x7fff);
- pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000);
-
- /* dynamic memory allocation, allocate memory for streams */
- if (pSMFData->streams == NULL)
- {
- pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams);
- if (pSMFData->streams == NULL)
- return EAS_ERROR_MALLOC_FAILED;
-
- /* zero the memory to insure complete initialization */
- EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams);
- }
-
- /* find the start of each track */
- chunkStart = (EAS_U32) pSMFData->fileOffset;
- ticks = 0x7fffffffL;
- pSMFData->nextStream = NULL;
- for (i = 0; i < pSMFData->numStreams; i++)
- {
-
- for (;;)
- {
-
- /* calculate start of next chunk - checking for errors */
- temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize;
- if (temp <= chunkStart)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ }
- return EAS_ERROR_FILE_FORMAT;
- }
- chunkStart = temp;
-
- /* seek to the start of the next chunk */
- if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS)
- goto ReadError;
-
- /* read the chunk identifier */
- if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS)
- goto ReadError;
-
- /* read the chunk size */
- if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS)
- goto ReadError;
-
- /* make sure this is an 'MTrk' chunk */
- if (temp == SMF_CHUNK_TYPE_TRACK)
- break;
-
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ }
- }
-
- /* initalize some data */
- pSMFData->streams[i].ticks = 0;
- pSMFData->streams[i].fileHandle = pSMFData->fileHandle;
-
- /* NULL the file handle so we don't try to close it twice */
- pSMFData->fileHandle = NULL;
-
- /* save this file position as the start of the track */
- pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE;
-
- /* initalize the MIDI parser data */
- EAS_InitMIDIStream(&pSMFData->streams[i].midiStream);
-
- /* parse the first delta time in each stream */
- if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS)
- goto ReadError;
-
- if (pSMFData->streams[i].ticks < ticks)
- {
- ticks = pSMFData->streams[i].ticks;
- pSMFData->nextStream = &pSMFData->streams[i];
- }
-
- /* more tracks to do, create a duplicate file handle */
- if (i < (pSMFData->numStreams - 1))
- {
- if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS)
- goto ReadError;
- }
- }
-
- /* update the time of the next event */
- if (pSMFData->nextStream)
- SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks);
-
- return EAS_SUCCESS;
-
- /* ugly goto: but simpler than structured */
- ReadError:
- if (result == EAS_EOF)
- return EAS_ERROR_FILE_FORMAT;
- return result;
-}
-
-/*----------------------------------------------------------------------------
- * SMF_UpdateTime()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the millisecond time base by converting the ticks into millieconds
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks)
-{
- EAS_U32 temp1, temp2;
-
- if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
- return;
-
- temp1 = (ticks >> 10) * pSMFData->tickConv;
- temp2 = (ticks & 0x3ff) * pSMFData->tickConv;
- pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2));
-}
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 803 $ + * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_smfdata.h" +#include "eas_smf.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +//3 dls: The timebase for this module is adequate to keep MIDI and +//3 digital audio synchronized for only a few minutes. It should be +//3 sufficient for most mobile applications. If better accuracy is +//3 required, more fractional bits should be added to the timebase. + +static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' }; + +/* local prototypes */ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData); +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream); +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode); +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode); +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream); +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks); + + +/*---------------------------------------------------------------------------- + * + * SMF_Parser + * + * This structure contains the functional interface for the SMF parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_SMF_Parser = +{ + SMF_CheckFileType, + SMF_Prepare, + SMF_Time, + SMF_Event, + SMF_State, + SMF_Close, + SMF_Reset, + SMF_Pause, + SMF_Resume, + NULL, + SMF_SetData, + SMF_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * SMF_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* seek to starting offset - usually 0 */ + *ppHandle = NULL; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) + return result; + + /* search through file for header - slow method */ + if (pEASData->searchHeaderFlag) + { + result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset); + if (result != EAS_SUCCESS) + return (result == EAS_EOF) ? EAS_SUCCESS : result; + } + + /* read the first 4 bytes of the file - quick method */ + else { + EAS_U8 header[4]; + EAS_I32 count; + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS) + return result; + + /* check for 'MTrk' - return if no match */ + if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd')) + return EAS_SUCCESS; + } + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA); + else + { + pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA)); + EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA)); + } + if (!pSMFData) + return EAS_ERROR_MALLOC_FAILED; + + /* initialize some critical data */ + pSMFData->fileHandle = fileHandle; + pSMFData->fileOffset = offset; + pSMFData->pSynth = NULL; + pSMFData->time = 0; + pSMFData->state = EAS_STATE_OPEN; + *ppHandle = pSMFData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* check for valid state */ + pSMFData = (S_SMF_DATA *) pInstData; + if (pSMFData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the file header and setup the individual stream parsers */ + if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS) + return result; + + /* ready to play */ + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* sanity check */ +#ifdef _CHECKED_BUILD + if (pSMFData->state == EAS_STATE_STOPPED) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ } + } + + if (pSMFData->nextStream == NULL) + { + { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ } + } +#endif + +#if 0 + /* return time in milliseconds */ + /* if chase mode, lie about time */ + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + *pTime = 0; + + else +#endif + + /*lint -e{704} use shift instead of division */ + *pTime = pSMFData->time >> 8; + + *pTime = pSMFData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + EAS_I32 i; + EAS_U32 ticks; + EAS_U32 temp; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* get current ticks */ + ticks = pSMFData->nextStream->ticks; + + /* assume that an error occurred */ + pSMFData->state = EAS_STATE_ERROR; + +#ifdef JET_INTERFACE + /* if JET has track muted, set parser mode to mute */ + if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE) + parserMode = eParserModeMute; +#endif + + /* parse the next event from all the streams */ + if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* get next delta time, unless already at end of track */ + else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK) + { + if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* if zero delta to next event, stay with this stream */ + else if (pSMFData->nextStream->ticks == ticks) + { + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; + } + } + + /* find next event in all streams */ + temp = 0x7ffffff; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].ticks < temp) + { + temp = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + /* are there any more events to parse? */ + if (pSMFData->nextStream) + { + pSMFData->state = EAS_STATE_PLAY; + + /* update the time of the next event */ + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks); + } + else + { + pSMFData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_SMF_DATA* pSMFData; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pSMFData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_STOPPED; + } + + if (pSMFData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pSMFData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* close all the streams */ + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].fileHandle != NULL) + { + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS) + return result; + } + } + if (pSMFData->fileHandle != NULL) + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pSMFData->pSynth != NULL) + VMMIDIShutdown(pEASData, pSMFData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + if (pSMFData->streams) + EAS_HWFree(pEASData->hwInstData, pSMFData->streams); + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pSMFData); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + EAS_U32 ticks; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* reset time to zero */ + pSMFData->time = 0; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE); + + /* find the start of each track */ + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + /* reset file position to first byte of data in track */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS) + return result; + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS) + return result; + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't pause a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + pSMFData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't resume a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Sets parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + +#ifdef JET_INTERFACE + /* set jet segment and track ID of all tracks for callback function */ + case PARSER_DATA_JET_CB: + { + EAS_U32 i; + EAS_U32 bit = (EAS_U32) value; + bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK; + for (i = 0; i < pSMFData->numStreams; i++) + pSMFData->streams[i].midiStream.jetData = + (pSMFData->streams[i].midiStream.jetData & + ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) | + i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB; + pSMFData->flags |= SMF_FLAGS_JET_STREAM; + } + break; + + /* set state of all mute flags at once */ + case PARSER_DATA_MUTE_FLAGS: + { + EAS_INT i; + EAS_U32 bit = (EAS_U32) value; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (bit & 1) + pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + bit >>= 1; + } + } + break; + + /* set track mute */ + case PARSER_DATA_SET_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; + + /* clear track mute */ + case PARSER_DATA_CLEAR_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; +#endif + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Retrieves parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + /* return file type */ + case PARSER_DATA_FILE_TYPE: + if (pSMFData->numStreams == 1) + *pValue = EAS_FILE_SMF0; + else + *pValue = EAS_FILE_SMF1; + break; + +/* now handled in eas_public.c */ +#if 0 + case PARSER_DATA_POLYPHONY: + if (pSMFData->pSynth) + VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + else + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + break; + + case PARSER_DATA_PRIORITY: + if (pSMFData->pSynth) + VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + break; + + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pSMFData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pSMFData->pSynth; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetVarLenData() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData) +{ + EAS_RESULT result; + EAS_U32 data; + EAS_U8 c; + + /* read until bit 7 is zero */ + data = 0; + do + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS) + return result; + data = (data << 7) | (c & 0x7f); + } while (c & 0x80); + *pData = data; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetDeltaTime() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 ticks; + + if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS) + return result; + + pSMFStream->ticks += ticks; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseMetaEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_I32 pos; + EAS_U32 temp; + EAS_U8 c; + + /* get the meta-event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* get the current file position so we can skip the event */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS) + return result; + pos += (EAS_I32) len; + + /* end of track? */ + if (c == SMF_META_END_OF_TRACK) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ } + pSMFStream->ticks = SMF_END_OF_TRACK; + } + + /* tempo event? */ + else if (c == SMF_META_TEMPO) + { + /* read the 3-byte timebase value */ + temp = 0; + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + temp = (temp << 8) | c; + } + + pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000); + pSMFData->flags |= SMF_FLAGS_HAS_TEMPO; + } + + /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */ + else if (c == SMF_META_TIME_SIGNATURE) + { + pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG; + } + + /* if the host has registered a metadata callback return the metadata */ + else if (pSMFData->metadata.callback) + { + EAS_I32 readLen; + E_EAS_METADATA_TYPE metaType; + + metaType = EAS_METADATA_UNKNOWN; + + /* only process title on the first track */ + if (c == SMF_META_SEQTRK_NAME) + metaType = EAS_METADATA_TITLE; + else if (c == SMF_META_TEXT) + metaType = EAS_METADATA_TEXT; + else if (c == SMF_META_COPYRIGHT) + metaType = EAS_METADATA_COPYRIGHT; + else if (c == SMF_META_LYRIC) + metaType = EAS_METADATA_LYRIC; + + if (metaType != EAS_METADATA_UNKNOWN) + { + readLen = pSMFData->metadata.bufferSize - 1; + if ((EAS_I32) len < readLen) + readLen = (EAS_I32) len; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS) + return result; + pSMFData->metadata.buffer[readLen] = 0; + pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData); + } + } + + /* position file to next event - in case we ignored all or part of the meta-event */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS) + return result; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseSysEx() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_U8 c; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* start of SysEx message? */ + if (f0 == 0xf0) + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS) + return result; + } + + /* feed the SysEx to the stream parser */ + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* check for GM system ON */ + if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON) + pSMFData->flags |= SMF_FLAGS_HAS_GM_ON; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U8 c; + + /* get the event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* parse meta-event */ + if (c == 0xff) + { + if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS) + return result; + } + + /* parse SysEx */ + else if ((c == 0xf0) || (c == 0xf7)) + { + if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + /* parse MIDI message */ + else + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* keep streaming data to the MIDI parser until the message is complete */ + while (pSMFStream->midiStream.pending) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + } + + /* chase mode logic */ + if (pSMFData->time == 0) + { + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + { + if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE) + pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE; + } + else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR) + pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parses the header of an SMF file, allocates memory the stream parsers and initializes the + * stream parsers. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pSMFData - pointer to parser instance data + * fileHandle - file handle + * fileOffset - offset in the file where the header data starts, usually 0 + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */ +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_U16 division; + EAS_U32 chunkSize; + EAS_U32 chunkStart; + EAS_U32 temp; + EAS_U32 ticks; + + /* rewind the file and find the end of the header chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* determine the number of tracks */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* limit the number of tracks */ + if (pSMFData->numStreams > MAX_SMF_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ } + pSMFData->numStreams = MAX_SMF_STREAMS; + } + + /* get the time division */ + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* setup default timebase for 120 bpm */ + pSMFData->ppqn = 192; + if (division & 0x8000) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ } + else + pSMFData->ppqn = (division & 0x7fff); + pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000); + + /* dynamic memory allocation, allocate memory for streams */ + if (pSMFData->streams == NULL) + { + pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams); + if (pSMFData->streams == NULL) + return EAS_ERROR_MALLOC_FAILED; + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams); + } + + /* find the start of each track */ + chunkStart = (EAS_U32) pSMFData->fileOffset; + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + for (;;) + { + + /* calculate start of next chunk - checking for errors */ + temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize; + if (temp <= chunkStart) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ } + return EAS_ERROR_FILE_FORMAT; + } + chunkStart = temp; + + /* seek to the start of the next chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk identifier */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk size */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* make sure this is an 'MTrk' chunk */ + if (temp == SMF_CHUNK_TYPE_TRACK) + break; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ } + } + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + pSMFData->streams[i].fileHandle = pSMFData->fileHandle; + + /* NULL the file handle so we don't try to close it twice */ + pSMFData->fileHandle = NULL; + + /* save this file position as the start of the track */ + pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS) + goto ReadError; + + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + + /* more tracks to do, create a duplicate file handle */ + if (i < (pSMFData->numStreams - 1)) + { + if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS) + goto ReadError; + } + } + + /* update the time of the next event */ + if (pSMFData->nextStream) + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks); + + return EAS_SUCCESS; + + /* ugly goto: but simpler than structured */ + ReadError: + if (result == EAS_EOF) + return EAS_ERROR_FILE_FORMAT; + return result; +} + +/*---------------------------------------------------------------------------- + * SMF_UpdateTime() + *---------------------------------------------------------------------------- + * Purpose: + * Update the millisecond time base by converting the ticks into millieconds + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks) +{ + EAS_U32 temp1, temp2; + + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + return; + + temp1 = (ticks >> 10) * pSMFData->tickConv; + temp2 = (ticks & 0x3ff) * pSMFData->tickConv; + pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2)); +} + diff --git a/arm-fm-22k/lib_src/eas_smf.h b/arm-fm-22k/lib_src/eas_smf.h index 9f66ab9..37c0790 100644 --- a/arm-fm-22k/lib_src/eas_smf.h +++ b/arm-fm-22k/lib_src/eas_smf.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_smf.h
- *
- * Contents and purpose:
- * SMF Type 0 and 1 File Parser
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.h + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,31 +19,31 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_SMF_H
-#define _EAS_SMF_H
-
-/* prototypes for private interface to SMF parser */
-EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
-EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
-EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
-EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
-EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData);
-
-#endif /* end _EAS_SMF_H */
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_H +#define _EAS_SMF_H + +/* prototypes for private interface to SMF parser */ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData); + +#endif /* end _EAS_SMF_H */ + + diff --git a/arm-fm-22k/lib_src/eas_smfdata.c b/arm-fm-22k/lib_src/eas_smfdata.c index 5c27551..383d7f3 100644 --- a/arm-fm-22k/lib_src/eas_smfdata.c +++ b/arm-fm-22k/lib_src/eas_smfdata.c @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_smfdata.c
- *
- * Contents and purpose:
- * SMF File Parser
- *
- * This file contains data definitions for the SMF parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,46 +21,46 @@ * 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: 778 $
- * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_miditypes.h"
-#include "eas_smfdata.h"
-
-/*----------------------------------------------------------------------------
- *
- * S_SMF_STREAM
- *
- * Static memory allocation for SMF parser
- *----------------------------------------------------------------------------
-*/
-static S_SMF_STREAM eas_SMFStreams[MAX_SMF_STREAMS];
-
-/*----------------------------------------------------------------------------
- *
- * eas_SMFData
- *
- * Static memory allocation for SMF parser
- *----------------------------------------------------------------------------
-*/
-S_SMF_DATA eas_SMFData =
-{
- eas_SMFStreams, /* pointer to individual streams in file */
- 0, /* pointer to next stream with event */
- 0, /* pointer to synth */
- 0, /* file handle */
- { 0, 0, 0, 0}, /* metadata callback */
- 0, /* file offset */
- 0, /* current time in milliseconds/256 */
- 0, /* actual number of streams */
- 0, /* current MIDI tick to msec conversion */
- 0, /* ticks per quarter note */
- 0, /* current state EAS_STATE_XXXX */
- 0 /* flags */
-};
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" +#include "eas_smfdata.h" + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +static S_SMF_STREAM eas_SMFStreams[MAX_SMF_STREAMS]; + +/*---------------------------------------------------------------------------- + * + * eas_SMFData + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +S_SMF_DATA eas_SMFData = +{ + eas_SMFStreams, /* pointer to individual streams in file */ + 0, /* pointer to next stream with event */ + 0, /* pointer to synth */ + 0, /* file handle */ + { 0, 0, 0, 0}, /* metadata callback */ + 0, /* file offset */ + 0, /* current time in milliseconds/256 */ + 0, /* actual number of streams */ + 0, /* current MIDI tick to msec conversion */ + 0, /* ticks per quarter note */ + 0, /* current state EAS_STATE_XXXX */ + 0 /* flags */ +}; + diff --git a/arm-fm-22k/lib_src/eas_smfdata.h b/arm-fm-22k/lib_src/eas_smfdata.h index cf59cdc..8861d90 100644 --- a/arm-fm-22k/lib_src/eas_smfdata.h +++ b/arm-fm-22k/lib_src/eas_smfdata.h @@ -1,14 +1,14 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_smfdata.h
- *
- * Contents and purpose:
- * SMF File Parser
- *
- * This file contains data definitions for the SMF parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,46 +21,46 @@ * 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: 686 $
- * $Date: 2007-05-03 14:10:54 -0700 (Thu, 03 May 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_SMF_DATA_H
-#define _EAS_SMF_DATA_H
-
-#ifndef MAX_SMF_STREAMS
-#define MAX_SMF_STREAMS 17
-#endif
-
-/* offsets in to the SMF file */
-#define SMF_OFS_HEADER_SIZE 4
-#define SMF_OFS_FILE_TYPE 8
-#define SMF_OFS_NUM_TRACKS 10
-
-/* size of chunk info (chunk ID + chunk size) */
-#define SMF_CHUNK_INFO_SIZE 8
-
-/* 'MTrk' track chunk ID */
-#define SMF_CHUNK_TYPE_TRACK 0x4d54726bL
-
-/* some useful meta-events */
-#define SMF_META_TEXT 0x01
-#define SMF_META_COPYRIGHT 0x02
-#define SMF_META_SEQTRK_NAME 0x03
-#define SMF_META_LYRIC 0x05
-#define SMF_META_END_OF_TRACK 0x2f
-#define SMF_META_TEMPO 0x51
-#define SMF_META_TIME_SIGNATURE 0x58
-
-/* default timebase (120BPM) */
-#define SMF_DEFAULT_TIMEBASE 500000L
-
-/* value for pSMFStream->ticks to signify end of track */
-#define SMF_END_OF_TRACK 0xffffffff
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 686 $ + * $Date: 2007-05-03 14:10:54 -0700 (Thu, 03 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_DATA_H +#define _EAS_SMF_DATA_H + +#ifndef MAX_SMF_STREAMS +#define MAX_SMF_STREAMS 17 +#endif + +/* offsets in to the SMF file */ +#define SMF_OFS_HEADER_SIZE 4 +#define SMF_OFS_FILE_TYPE 8 +#define SMF_OFS_NUM_TRACKS 10 + +/* size of chunk info (chunk ID + chunk size) */ +#define SMF_CHUNK_INFO_SIZE 8 + +/* 'MTrk' track chunk ID */ +#define SMF_CHUNK_TYPE_TRACK 0x4d54726bL + +/* some useful meta-events */ +#define SMF_META_TEXT 0x01 +#define SMF_META_COPYRIGHT 0x02 +#define SMF_META_SEQTRK_NAME 0x03 +#define SMF_META_LYRIC 0x05 +#define SMF_META_END_OF_TRACK 0x2f +#define SMF_META_TEMPO 0x51 +#define SMF_META_TIME_SIGNATURE 0x58 + +/* default timebase (120BPM) */ +#define SMF_DEFAULT_TIMEBASE 500000L + +/* value for pSMFStream->ticks to signify end of track */ +#define SMF_END_OF_TRACK 0xffffffff + +#endif + diff --git a/arm-fm-22k/lib_src/eas_sndlib.h b/arm-fm-22k/lib_src/eas_sndlib.h index e05bee0..416be6e 100644 --- a/arm-fm-22k/lib_src/eas_sndlib.h +++ b/arm-fm-22k/lib_src/eas_sndlib.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_sndlib.h
- *
- * Contents and purpose:
- * Declarations for the sound library
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_sndlib.h + * + * Contents and purpose: + * Declarations for the sound library + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,388 +19,388 @@ * 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: 550 $
- * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_SNDLIB_H
-#define _EAS_SNDLIB_H
-
-#include "eas_types.h"
-#include "eas_synthcfg.h"
-
-#ifdef _WT_SYNTH
-#include "eas_wtengine.h"
-#endif
-
-/*----------------------------------------------------------------------------
- * This is bit of a hack to allow us to keep the same structure
- * declarations for the DLS parser. Normally, the data is located
- * in read-only memory, but for DLS, we store the data in RW
- * memory.
- *----------------------------------------------------------------------------
-*/
-#ifndef SCNST
-#define SCNST const
-#endif
-
-/*----------------------------------------------------------------------------
- * sample size
- *----------------------------------------------------------------------------
-*/
-#ifdef _16_BIT_SAMPLES
-typedef EAS_I16 EAS_SAMPLE;
-#else
-typedef EAS_I8 EAS_SAMPLE;
-#endif
-
-/*----------------------------------------------------------------------------
- * EAS Library ID - quick check for valid library and version
- *----------------------------------------------------------------------------
-*/
-#define _EAS_LIBRARY_VERSION 0x01534145
-
-#define NUM_PROGRAMS_IN_BANK 128
-#define INVALID_REGION_INDEX 0xffff
-
-/* this bit in region index indicates that region is for secondary synth */
-#define FLAG_RGN_IDX_FM_SYNTH 0x8000
-#define FLAG_RGN_IDX_DLS_SYNTH 0x4000
-#define REGION_INDEX_MASK 0x3fff
-
-/*----------------------------------------------------------------------------
- * Generic region data structure
- *
- * This must be the first element in each region structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_region_tag
-{
- EAS_U16 keyGroupAndFlags;
- EAS_U8 rangeLow;
- EAS_U8 rangeHigh;
-} S_REGION;
-
-/*
- * Bit fields for m_nKeyGroupAndFlags
- * Bits 0-2 are mode bits in FM synth
- * Bits 8-11 are the key group
- */
-#define REGION_FLAG_IS_LOOPED 0x01
-#define REGION_FLAG_USE_WAVE_GENERATOR 0x02
-#define REGION_FLAG_USE_ADPCM 0x04
-#define REGION_FLAG_ONE_SHOT 0x08
-#define REGION_FLAG_SQUARE_WAVE 0x10
-#define REGION_FLAG_OFF_CHIP 0x20
-#define REGION_FLAG_NON_SELF_EXCLUSIVE 0x40
-#define REGION_FLAG_LAST_REGION 0x8000
-
-/*----------------------------------------------------------------------------
- * Envelope data structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_envelope_tag
-{
- EAS_I16 attackTime;
- EAS_I16 decayTime;
- EAS_I16 sustainLevel;
- EAS_I16 releaseTime;
-} S_ENVELOPE;
-
-/*----------------------------------------------------------------------------
- * DLS envelope data structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_dls_envelope_tag
-{
- EAS_I16 delayTime;
- EAS_I16 attackTime;
- EAS_I16 holdTime;
- EAS_I16 decayTime;
- EAS_I16 sustainLevel;
- EAS_I16 releaseTime;
- EAS_I16 velToAttack;
- EAS_I16 keyNumToDecay;
- EAS_I16 keyNumToHold;
-} S_DLS_ENVELOPE;
-
-/*----------------------------------------------------------------------------
- * LFO data structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_lfo_params_tag
-{
- EAS_I16 lfoFreq;
- EAS_I16 lfoDelay;
-} S_LFO_PARAMS;
-
-/*----------------------------------------------------------------------------
- * Articulation data structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_articulation_tag
-{
- S_ENVELOPE eg1;
- S_ENVELOPE eg2;
- EAS_I16 lfoToPitch;
- EAS_I16 lfoDelay;
- EAS_I16 lfoFreq;
- EAS_I16 eg2ToPitch;
- EAS_I16 eg2ToFc;
- EAS_I16 filterCutoff;
- EAS_I8 lfoToGain;
- EAS_U8 filterQ;
- EAS_I8 pan;
-} S_ARTICULATION;
-
-/*----------------------------------------------------------------------------
- * DLS articulation data structure
- *----------------------------------------------------------------------------
-*/
-
-typedef struct s_dls_articulation_tag
-{
- S_LFO_PARAMS modLFO;
- S_LFO_PARAMS vibLFO;
-
- S_DLS_ENVELOPE eg1;
- S_DLS_ENVELOPE eg2;
-
- EAS_I16 eg1ShutdownTime;
-
- EAS_I16 filterCutoff;
- EAS_I16 modLFOToFc;
- EAS_I16 modLFOCC1ToFc;
- EAS_I16 modLFOChanPressToFc;
- EAS_I16 eg2ToFc;
- EAS_I16 velToFc;
- EAS_I16 keyNumToFc;
-
- EAS_I16 modLFOToGain;
- EAS_I16 modLFOCC1ToGain;
- EAS_I16 modLFOChanPressToGain;
-
- EAS_I16 tuning;
- EAS_I16 keyNumToPitch;
- EAS_I16 vibLFOToPitch;
- EAS_I16 vibLFOCC1ToPitch;
- EAS_I16 vibLFOChanPressToPitch;
- EAS_I16 modLFOToPitch;
- EAS_I16 modLFOCC1ToPitch;
- EAS_I16 modLFOChanPressToPitch;
- EAS_I16 eg2ToPitch;
-
- /* pad to 4-byte boundary */
- EAS_U16 pad;
-
- EAS_I8 pan;
- EAS_U8 filterQandFlags;
-
-#ifdef _REVERB
- EAS_I16 reverbSend;
- EAS_I16 cc91ToReverbSend;
-#endif
-
-#ifdef _CHORUS
- EAS_I16 chorusSend;
- EAS_I16 cc93ToChorusSend;
-#endif
-} S_DLS_ARTICULATION;
-
-/* flags in filterQandFlags
- * NOTE: Q is stored in bottom 5 bits
- */
-#define FLAG_DLS_VELOCITY_SENSITIVE 0x80
-#define FILTER_Q_MASK 0x1f
-
-/*----------------------------------------------------------------------------
- * Wavetable region data structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_wt_region_tag
-{
- S_REGION region;
- EAS_I16 tuning;
- EAS_I16 gain;
- EAS_U32 loopStart;
- EAS_U32 loopEnd;
- EAS_U16 waveIndex;
- EAS_U16 artIndex;
-} S_WT_REGION;
-
-/*----------------------------------------------------------------------------
- * DLS region data structure
- *----------------------------------------------------------------------------
-*/
-typedef struct s_dls_region_tag
-{
- S_WT_REGION wtRegion;
- EAS_U8 velLow;
- EAS_U8 velHigh;
-} S_DLS_REGION;
-
-/*----------------------------------------------------------------------------
- * FM synthesizer data structures
- *----------------------------------------------------------------------------
-*/
-typedef struct s_fm_oper_tag
-{
- EAS_I16 tuning;
- EAS_U8 attackDecay;
- EAS_U8 velocityRelease;
- EAS_U8 egKeyScale;
- EAS_U8 sustain;
- EAS_U8 gain;
- EAS_U8 flags;
-} S_FM_OPER;
-
-/* defines for S_FM_OPER.m_nFlags */
-#define FM_OPER_FLAG_MONOTONE 0x01
-#define FM_OPER_FLAG_NO_VIBRATO 0x02
-#define FM_OPER_FLAG_NOISE 0x04
-#define FM_OPER_FLAG_LINEAR_VELOCITY 0x08
-
-/* NOTE: The first two structure elements are common with S_WT_REGION
- * and we will rely on that in the voice management code and must
- * remain there unless the voice management code is revisited.
- */
-typedef struct s_fm_region_tag
-{
- S_REGION region;
- EAS_U8 vibTrem;
- EAS_U8 lfoFreqDelay;
- EAS_U8 feedback;
- EAS_I8 pan;
- S_FM_OPER oper[4];
-} S_FM_REGION;
-
-/*----------------------------------------------------------------------------
- * Common data structures
- *----------------------------------------------------------------------------
-*/
-
-/*----------------------------------------------------------------------------
- * Program data structure
- * Used for individual programs not stored as a complete bank.
- *----------------------------------------------------------------------------
-*/
-typedef struct s_program_tag
-{
- EAS_U32 locale;
- EAS_U16 regionIndex;
-} S_PROGRAM;
-
-/*----------------------------------------------------------------------------
- * Bank data structure
- *
- * A bank always consists of 128 programs. If a bank is less than 128
- * programs, it should be stored as a spare matrix in the pPrograms
- * array.
- *
- * bankNum: MSB/LSB of MIDI bank select controller
- * regionIndex: Index of first region in program
- *----------------------------------------------------------------------------
-*/
-typedef struct s_bank_tag
-{
- EAS_U16 locale;
- EAS_U16 regionIndex[NUM_PROGRAMS_IN_BANK];
-} S_BANK;
-
-
-/* defines for libFormat field
- * bits 0-17 are the sample rate
- * bit 18 is true if wavetable is present
- * bit 19 is true if FM is present
- * bit 20 is true if filter is enabled
- * bit 21 is sample depth (0 = 8-bits, 1 = 16-bits)
- * bits 22-31 are reserved
- */
-#define LIBFORMAT_SAMPLE_RATE_MASK 0x0003ffff
-#define LIB_FORMAT_TYPE_MASK 0x000c0000
-#define LIB_FORMAT_WAVETABLE 0x00000000
-#define LIB_FORMAT_FM 0x00040000
-#define LIB_FORMAT_HYBRID 0x00080000
-#define LIB_FORMAT_FILTER_ENABLED 0x00100000
-#define LIB_FORMAT_16_BIT_SAMPLES 0x00200000
-
-#ifdef DLS_SYNTHESIZER
-/*----------------------------------------------------------------------------
- * DLS data structure
- *
- * pDLSPrograms pointer to array of DLS programs
- * pDLSRegions pointer to array of DLS regions
- * pDLSArticulations pointer to array of DLS articulations
- * pSampleLen pointer to array of sample lengths
- * ppSamples pointer to array of sample pointers
- * numDLSPrograms number of DLS programs
- * numDLSRegions number of DLS regions
- * numDLSArticulations number of DLS articulations
- * numDLSSamples number of DLS samples
- *----------------------------------------------------------------------------
-*/
-typedef struct s_eas_dls_tag
-{
- S_PROGRAM *pDLSPrograms;
- S_DLS_REGION *pDLSRegions;
- S_DLS_ARTICULATION *pDLSArticulations;
- EAS_U32 *pDLSSampleLen;
- EAS_U32 *pDLSSampleOffsets;
- EAS_SAMPLE *pDLSSamples;
- EAS_U16 numDLSPrograms;
- EAS_U16 numDLSRegions;
- EAS_U16 numDLSArticulations;
- EAS_U16 numDLSSamples;
- EAS_U8 refCount;
-} S_DLS;
-#endif
-
-/*----------------------------------------------------------------------------
- * Sound library data structure
- *
- * pBanks pointer to array of banks
- * pPrograms pointer to array of programs
- * pWTRegions pointer to array of wavetable regions
- * pFMRegions pointer to array of FM regions
- * pArticulations pointer to array of articulations
- * pSampleLen pointer to array of sample lengths
- * ppSamples pointer to array of sample pointers
- * numBanks number of banks
- * numPrograms number of individual program
- * numRegions number of regions
- * numArticulations number of articulations
- * numSamples number of samples
- *----------------------------------------------------------------------------
-*/
-typedef struct s_eas_sndlib_tag
-{
- SCNST EAS_U32 identifier;
- SCNST EAS_U32 libAttr;
-
- SCNST S_BANK *pBanks;
- SCNST S_PROGRAM *pPrograms;
-
- SCNST S_WT_REGION *pWTRegions;
- SCNST S_ARTICULATION *pArticulations;
- SCNST EAS_U32 *pSampleLen;
- SCNST EAS_U32 *pSampleOffsets;
- SCNST EAS_SAMPLE *pSamples;
-
- SCNST S_FM_REGION *pFMRegions;
-
- SCNST EAS_U16 numBanks;
- SCNST EAS_U16 numPrograms;
-
- SCNST EAS_U16 numWTRegions;
- SCNST EAS_U16 numArticulations;
- SCNST EAS_U16 numSamples;
-
- SCNST EAS_U16 numFMRegions;
-} S_EAS;
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SNDLIB_H +#define _EAS_SNDLIB_H + +#include "eas_types.h" +#include "eas_synthcfg.h" + +#ifdef _WT_SYNTH +#include "eas_wtengine.h" +#endif + +/*---------------------------------------------------------------------------- + * This is bit of a hack to allow us to keep the same structure + * declarations for the DLS parser. Normally, the data is located + * in read-only memory, but for DLS, we store the data in RW + * memory. + *---------------------------------------------------------------------------- +*/ +#ifndef SCNST +#define SCNST const +#endif + +/*---------------------------------------------------------------------------- + * sample size + *---------------------------------------------------------------------------- +*/ +#ifdef _16_BIT_SAMPLES +typedef EAS_I16 EAS_SAMPLE; +#else +typedef EAS_I8 EAS_SAMPLE; +#endif + +/*---------------------------------------------------------------------------- + * EAS Library ID - quick check for valid library and version + *---------------------------------------------------------------------------- +*/ +#define _EAS_LIBRARY_VERSION 0x01534145 + +#define NUM_PROGRAMS_IN_BANK 128 +#define INVALID_REGION_INDEX 0xffff + +/* this bit in region index indicates that region is for secondary synth */ +#define FLAG_RGN_IDX_FM_SYNTH 0x8000 +#define FLAG_RGN_IDX_DLS_SYNTH 0x4000 +#define REGION_INDEX_MASK 0x3fff + +/*---------------------------------------------------------------------------- + * Generic region data structure + * + * This must be the first element in each region structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_region_tag +{ + EAS_U16 keyGroupAndFlags; + EAS_U8 rangeLow; + EAS_U8 rangeHigh; +} S_REGION; + +/* + * Bit fields for m_nKeyGroupAndFlags + * Bits 0-2 are mode bits in FM synth + * Bits 8-11 are the key group + */ +#define REGION_FLAG_IS_LOOPED 0x01 +#define REGION_FLAG_USE_WAVE_GENERATOR 0x02 +#define REGION_FLAG_USE_ADPCM 0x04 +#define REGION_FLAG_ONE_SHOT 0x08 +#define REGION_FLAG_SQUARE_WAVE 0x10 +#define REGION_FLAG_OFF_CHIP 0x20 +#define REGION_FLAG_NON_SELF_EXCLUSIVE 0x40 +#define REGION_FLAG_LAST_REGION 0x8000 + +/*---------------------------------------------------------------------------- + * Envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_envelope_tag +{ + EAS_I16 attackTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; +} S_ENVELOPE; + +/*---------------------------------------------------------------------------- + * DLS envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_envelope_tag +{ + EAS_I16 delayTime; + EAS_I16 attackTime; + EAS_I16 holdTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; + EAS_I16 velToAttack; + EAS_I16 keyNumToDecay; + EAS_I16 keyNumToHold; +} S_DLS_ENVELOPE; + +/*---------------------------------------------------------------------------- + * LFO data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_lfo_params_tag +{ + EAS_I16 lfoFreq; + EAS_I16 lfoDelay; +} S_LFO_PARAMS; + +/*---------------------------------------------------------------------------- + * Articulation data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_articulation_tag +{ + S_ENVELOPE eg1; + S_ENVELOPE eg2; + EAS_I16 lfoToPitch; + EAS_I16 lfoDelay; + EAS_I16 lfoFreq; + EAS_I16 eg2ToPitch; + EAS_I16 eg2ToFc; + EAS_I16 filterCutoff; + EAS_I8 lfoToGain; + EAS_U8 filterQ; + EAS_I8 pan; +} S_ARTICULATION; + +/*---------------------------------------------------------------------------- + * DLS articulation data structure + *---------------------------------------------------------------------------- +*/ + +typedef struct s_dls_articulation_tag +{ + S_LFO_PARAMS modLFO; + S_LFO_PARAMS vibLFO; + + S_DLS_ENVELOPE eg1; + S_DLS_ENVELOPE eg2; + + EAS_I16 eg1ShutdownTime; + + EAS_I16 filterCutoff; + EAS_I16 modLFOToFc; + EAS_I16 modLFOCC1ToFc; + EAS_I16 modLFOChanPressToFc; + EAS_I16 eg2ToFc; + EAS_I16 velToFc; + EAS_I16 keyNumToFc; + + EAS_I16 modLFOToGain; + EAS_I16 modLFOCC1ToGain; + EAS_I16 modLFOChanPressToGain; + + EAS_I16 tuning; + EAS_I16 keyNumToPitch; + EAS_I16 vibLFOToPitch; + EAS_I16 vibLFOCC1ToPitch; + EAS_I16 vibLFOChanPressToPitch; + EAS_I16 modLFOToPitch; + EAS_I16 modLFOCC1ToPitch; + EAS_I16 modLFOChanPressToPitch; + EAS_I16 eg2ToPitch; + + /* pad to 4-byte boundary */ + EAS_U16 pad; + + EAS_I8 pan; + EAS_U8 filterQandFlags; + +#ifdef _REVERB + EAS_I16 reverbSend; + EAS_I16 cc91ToReverbSend; +#endif + +#ifdef _CHORUS + EAS_I16 chorusSend; + EAS_I16 cc93ToChorusSend; +#endif +} S_DLS_ARTICULATION; + +/* flags in filterQandFlags + * NOTE: Q is stored in bottom 5 bits + */ +#define FLAG_DLS_VELOCITY_SENSITIVE 0x80 +#define FILTER_Q_MASK 0x1f + +/*---------------------------------------------------------------------------- + * Wavetable region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_region_tag +{ + S_REGION region; + EAS_I16 tuning; + EAS_I16 gain; + EAS_U32 loopStart; + EAS_U32 loopEnd; + EAS_U16 waveIndex; + EAS_U16 artIndex; +} S_WT_REGION; + +/*---------------------------------------------------------------------------- + * DLS region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_region_tag +{ + S_WT_REGION wtRegion; + EAS_U8 velLow; + EAS_U8 velHigh; +} S_DLS_REGION; + +/*---------------------------------------------------------------------------- + * FM synthesizer data structures + *---------------------------------------------------------------------------- +*/ +typedef struct s_fm_oper_tag +{ + EAS_I16 tuning; + EAS_U8 attackDecay; + EAS_U8 velocityRelease; + EAS_U8 egKeyScale; + EAS_U8 sustain; + EAS_U8 gain; + EAS_U8 flags; +} S_FM_OPER; + +/* defines for S_FM_OPER.m_nFlags */ +#define FM_OPER_FLAG_MONOTONE 0x01 +#define FM_OPER_FLAG_NO_VIBRATO 0x02 +#define FM_OPER_FLAG_NOISE 0x04 +#define FM_OPER_FLAG_LINEAR_VELOCITY 0x08 + +/* NOTE: The first two structure elements are common with S_WT_REGION + * and we will rely on that in the voice management code and must + * remain there unless the voice management code is revisited. + */ +typedef struct s_fm_region_tag +{ + S_REGION region; + EAS_U8 vibTrem; + EAS_U8 lfoFreqDelay; + EAS_U8 feedback; + EAS_I8 pan; + S_FM_OPER oper[4]; +} S_FM_REGION; + +/*---------------------------------------------------------------------------- + * Common data structures + *---------------------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- + * Program data structure + * Used for individual programs not stored as a complete bank. + *---------------------------------------------------------------------------- +*/ +typedef struct s_program_tag +{ + EAS_U32 locale; + EAS_U16 regionIndex; +} S_PROGRAM; + +/*---------------------------------------------------------------------------- + * Bank data structure + * + * A bank always consists of 128 programs. If a bank is less than 128 + * programs, it should be stored as a spare matrix in the pPrograms + * array. + * + * bankNum: MSB/LSB of MIDI bank select controller + * regionIndex: Index of first region in program + *---------------------------------------------------------------------------- +*/ +typedef struct s_bank_tag +{ + EAS_U16 locale; + EAS_U16 regionIndex[NUM_PROGRAMS_IN_BANK]; +} S_BANK; + + +/* defines for libFormat field + * bits 0-17 are the sample rate + * bit 18 is true if wavetable is present + * bit 19 is true if FM is present + * bit 20 is true if filter is enabled + * bit 21 is sample depth (0 = 8-bits, 1 = 16-bits) + * bits 22-31 are reserved + */ +#define LIBFORMAT_SAMPLE_RATE_MASK 0x0003ffff +#define LIB_FORMAT_TYPE_MASK 0x000c0000 +#define LIB_FORMAT_WAVETABLE 0x00000000 +#define LIB_FORMAT_FM 0x00040000 +#define LIB_FORMAT_HYBRID 0x00080000 +#define LIB_FORMAT_FILTER_ENABLED 0x00100000 +#define LIB_FORMAT_16_BIT_SAMPLES 0x00200000 + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * DLS data structure + * + * pDLSPrograms pointer to array of DLS programs + * pDLSRegions pointer to array of DLS regions + * pDLSArticulations pointer to array of DLS articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numDLSPrograms number of DLS programs + * numDLSRegions number of DLS regions + * numDLSArticulations number of DLS articulations + * numDLSSamples number of DLS samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_dls_tag +{ + S_PROGRAM *pDLSPrograms; + S_DLS_REGION *pDLSRegions; + S_DLS_ARTICULATION *pDLSArticulations; + EAS_U32 *pDLSSampleLen; + EAS_U32 *pDLSSampleOffsets; + EAS_SAMPLE *pDLSSamples; + EAS_U16 numDLSPrograms; + EAS_U16 numDLSRegions; + EAS_U16 numDLSArticulations; + EAS_U16 numDLSSamples; + EAS_U8 refCount; +} S_DLS; +#endif + +/*---------------------------------------------------------------------------- + * Sound library data structure + * + * pBanks pointer to array of banks + * pPrograms pointer to array of programs + * pWTRegions pointer to array of wavetable regions + * pFMRegions pointer to array of FM regions + * pArticulations pointer to array of articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numBanks number of banks + * numPrograms number of individual program + * numRegions number of regions + * numArticulations number of articulations + * numSamples number of samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_sndlib_tag +{ + SCNST EAS_U32 identifier; + SCNST EAS_U32 libAttr; + + SCNST S_BANK *pBanks; + SCNST S_PROGRAM *pPrograms; + + SCNST S_WT_REGION *pWTRegions; + SCNST S_ARTICULATION *pArticulations; + SCNST EAS_U32 *pSampleLen; + SCNST EAS_U32 *pSampleOffsets; + SCNST EAS_SAMPLE *pSamples; + + SCNST S_FM_REGION *pFMRegions; + + SCNST EAS_U16 numBanks; + SCNST EAS_U16 numPrograms; + + SCNST EAS_U16 numWTRegions; + SCNST EAS_U16 numArticulations; + SCNST EAS_U16 numSamples; + + SCNST EAS_U16 numFMRegions; +} S_EAS; + +#endif + diff --git a/arm-fm-22k/lib_src/eas_synth.h b/arm-fm-22k/lib_src/eas_synth.h index b242b03..6274b7d 100644 --- a/arm-fm-22k/lib_src/eas_synth.h +++ b/arm-fm-22k/lib_src/eas_synth.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_synth.h
- *
- * Contents and purpose:
- * Declarations, interfaces, and prototypes for synth.
- *
- * Copyright Sonic Network Inc. 2004, 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_synth.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004, 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,377 +19,377 @@ * 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: 718 $
- * $Date: 2007-06-08 16:43:16 -0700 (Fri, 08 Jun 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_SYNTH_H
-#define _EAS_SYNTH_H
-
-#include "eas_types.h"
-#include "eas_sndlib.h"
-
-#ifdef _WT_SYNTH
-#include "eas_wtsynth.h"
-#endif
-
-#ifdef _FM_SYNTH
-#include "eas_fmsynth.h"
-#endif
-
-#ifndef NUM_OUTPUT_CHANNELS
-#define NUM_OUTPUT_CHANNELS 2
-#endif
-
-#ifndef MAX_SYNTH_VOICES
-#define MAX_SYNTH_VOICES 64
-#endif
-
-#ifndef MAX_VIRTUAL_SYNTHESIZERS
-#define MAX_VIRTUAL_SYNTHESIZERS 4
-#endif
-
-/* defines */
-#ifndef NUM_PRIMARY_VOICES
-#define NUM_PRIMARY_VOICES MAX_SYNTH_VOICES
-#elif !defined(NUM_SECONDARY_VOICES)
-#define NUM_SECONDARY_VOICES (MAX_SYNTH_VOICES - NUM_PRIMARY_VOICES)
-#endif
-
-#if defined(EAS_WT_SYNTH)
-#define NUM_WT_VOICES MAX_SYNTH_VOICES
-
-/* FM on MCU */
-#elif defined(EAS_FM_SYNTH)
-#define NUM_FM_VOICES MAX_SYNTH_VOICES
-
-/* wavetable drums on MCU, wavetable melodic on DSP */
-#elif defined(EAS_SPLIT_WT_SYNTH)
-#define NUM_WT_VOICES MAX_SYNTH_VOICES
-
-/* wavetable drums and FM melodic on MCU */
-#elif defined(EAS_HYBRID_SYNTH)
-#define NUM_WT_VOICES NUM_PRIMARY_VOICES
-#define NUM_FM_VOICES NUM_SECONDARY_VOICES
-
-/* wavetable drums on MCU, FM melodic on DSP */
-#elif defined(EAS_SPLIT_HYBRID_SYNTH)
-#define NUM_WT_VOICES NUM_PRIMARY_VOICES
-#define NUM_FM_VOICES NUM_SECONDARY_VOICES
-
-/* FM synth on DSP */
-#elif defined(EAS_SPLIT_FM_SYNTH)
-#define NUM_FM_VOICES MAX_SYNTH_VOICES
-
-#else
-#error "Unrecognized architecture option"
-#endif
-
-#define NUM_SYNTH_CHANNELS 16
-
-#define DEFAULT_SYNTH_VOICES MAX_SYNTH_VOICES
-
-/* use the following values to specify unassigned channels or voices */
-#define UNASSIGNED_SYNTH_CHANNEL NUM_SYNTH_CHANNELS
-#define UNASSIGNED_SYNTH_VOICE MAX_SYNTH_VOICES
-
-
-/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */
-#define SYNTH_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << SYNTH_UPDATE_PERIOD_IN_BITS)
-
-/* stealing weighting factors */
-#define NOTE_AGE_STEAL_WEIGHT 1
-#define NOTE_GAIN_STEAL_WEIGHT 4
-#define CHANNEL_POLY_STEAL_WEIGHT 12
-#define CHANNEL_PRIORITY_STEAL_WEIGHT 2
-#define NOTE_MATCH_PENALTY 128
-#define SYNTH_PRIORITY_WEIGHT 8
-
-/* default synth master volume */
-#define DEFAULT_SYNTH_MASTER_VOLUME 0x7fff
-
-#define DEFAULT_SYNTH_PRIORITY 5
-
-/* default tuning values */
-#define DEFAULT_PITCH_BEND_SENSITIVITY 200 /* 2 semitones */
-#define DEFAULT_FINE_PITCH 0 /* 0 cents */
-#define DEFAULT_COARSE_PITCH 0 /* 0 semitones */
-
-/* default drum channel is 10, but is internally 9 due to unit offset */
-#define DEFAULT_DRUM_CHANNEL 9
-
-/* drum channel can simultaneously play this many voices at most */
-#define DEFAULT_CHANNEL_POLYPHONY_LIMIT 2
-
-/* default instrument is acoustic piano */
-#define DEFAULT_MELODY_BANK_MSB 0x79
-#define DEFAULT_RHYTHM_BANK_MSB 0x78
-#define DEFAULT_MELODY_BANK_NUMBER (DEFAULT_MELODY_BANK_MSB << 8)
-#define DEFAULT_RHYTHM_BANK_NUMBER (DEFAULT_RHYTHM_BANK_MSB << 8)
-#define DEFAULT_SYNTH_PROGRAM_NUMBER 0
-
-#define DEFAULT_PITCH_BEND 0x2000 /* 0x2000 == (0x40 << 7) | 0x00 */
-#define DEFAULT_MOD_WHEEL 0
-#define DEFAULT_CHANNEL_VOLUME 0x64
-#define DEFAULT_PAN 0x40 /* decimal 64, center */
-
-#ifdef _REVERB
-#define DEFAULT_REVERB_SEND 40 /* some reverb */
-#endif
-
-#ifdef _CHORUS
-#define DEFAULT_CHORUS_SEND 0 /* no chorus */
-#endif
-
-#define DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY 0 /* EAS synth uses a different default */
-#define DEFAULT_FILTER_RESONANCE 0
-#define DEFAULT_EXPRESSION 0x7F
-
-#define DEFAULT_CHANNEL_PRESSURE 0
-
-#define DEFAULT_REGISTERED_PARAM 0x3FFF
-
-#define DEFAULT_CHANNEL_STATIC_GAIN 0
-#define DEFAULT_CHANNEL_STATIC_PITCH 0
-
-#define DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS 50
-#define DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS 50
-
-#define DEFAULT_KEY_NUMBER 0x69
-#define DEFAULT_VELOCITY 0x64
-#define DEFAULT_REGION_INDEX 0
-#define DEFAULT_ARTICULATION_INDEX 0
-#define DEFAULT_VOICE_GAIN 0
-#define DEFAULT_AGE 0
-#define DEFAULT_SP_MIDI_PRIORITY 16
-
-
-/* filter defines */
-#define DEFAULT_FILTER_ZERO 0
-#define FILTER_CUTOFF_MAX_PITCH_CENTS 1919
-#define FILTER_CUTOFF_MIN_PITCH_CENTS -4467
-#define A5_PITCH_OFFSET_IN_CENTS 6900
-
-/*------------------------------------
- * S_SYNTH_CHANNEL data structure
- *------------------------------------
-*/
-
-/* S_SYNTH_CHANNEL.m_nFlags */
-#define CHANNEL_FLAG_SUSTAIN_PEDAL 0x01
-#define CHANNEL_FLAG_MUTE 0x02
-#define CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS 0x04
-#define CHANNEL_FLAG_RHYTHM_CHANNEL 0x08
-#define CHANNEL_FLAG_EXTERNAL_AUDIO 0x10
-#define DEFAULT_CHANNEL_FLAGS 0
-
-/* macros for extracting virtual synth and channel numbers */
-#define GET_VSYNTH(a) ((a) >> 4)
-#define GET_CHANNEL(a) ((a) & 15)
-
-typedef struct s_synth_channel_tag
-{
- /* use static channel parameters to reduce MIPs */
- /* parameters shared by multiple voices assigned to same channel */
- EAS_I32 staticPitch; /* (pitch bend * pitch sens) + fine pitch */
- EAS_I16 staticGain; /* (CC7 * CC11 * master vol)^2 */
-
- EAS_U16 regionIndex; /* index of first region in program */
-
- EAS_U16 bankNum; /* play programs from this bank */
- EAS_I16 pitchBend; /* pitch wheel value */
- EAS_I16 pitchBendSensitivity;
- EAS_I16 registeredParam; /* currently selected registered param */
-
-
-#if defined(_FM_SYNTH)
- EAS_I16 lfoAmt; /* amount of LFO to apply to voice */
-#endif
-
- EAS_U8 programNum; /* play this instrument number */
- EAS_U8 modWheel; /* CC1 */
- EAS_U8 volume; /* CC7 */
- EAS_U8 pan; /* CC10 */
-
- EAS_U8 expression; /* CC11 */
-
- /* the following parameters are controlled by RPNs */
- EAS_I8 finePitch;
- EAS_I8 coarsePitch;
-
- EAS_U8 channelPressure; /* applied to all voices on a given channel */
-
- EAS_U8 channelFlags; /* bit field channelFlags for */
- /* CC64, SP-MIDI channel masking */
-
- EAS_U8 pool; /* SPMIDI channel voice pool */
- EAS_U8 mip; /* SPMIDI MIP setting */
-
-#ifdef _REVERB
- EAS_U8 reverbSend; /* CC91 */
-#endif
-
-#ifdef _CHORUS
- EAS_U8 chorusSend; /* CC93 */
-#endif
-} S_SYNTH_CHANNEL;
-
-/*------------------------------------
- * S_SYNTH_VOICE data structure
- *------------------------------------
-*/
-
-/* S_SYNTH_VOICE.m_nFlags */
-#define VOICE_FLAG_UPDATE_VOICE_PARAMETERS 0x01
-#define VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF 0x02
-#define VOICE_FLAG_DEFER_MIDI_NOTE_OFF 0x04
-#define VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET 0x08
-#define VOICE_FLAG_DEFER_MUTE 0x40
-#define DEFAULT_VOICE_FLAGS 0
-
-/* S_SYNTH_VOICE.m_eState */
-typedef enum {
-
- eVoiceStateFree = 0,
- eVoiceStateStart,
- eVoiceStatePlay,
- eVoiceStateRelease,
- eVoiceStateMuting,
- eVoiceStateStolen,
- eVoiceStateInvalid /* should never be in this state! */
-
-} E_VOICE_STATE;
-#define DEFAULT_VOICE_STATE eVoiceStateFree
-
-typedef struct s_synth_voice_tag
-{
-
-/* These parameters are common to both wavetable and FM
- * synthesizers. The voice manager should only access this data.
- * Any other data should be manipulated by the code that is
- * specific to that synthesizer and reflected back through the
- * common state data available here.
- */
- EAS_U16 regionIndex; /* index to wave and playback params */
- EAS_I16 gain; /* current gain */
- EAS_U16 age; /* large value means old note */
- EAS_U16 nextRegionIndex; /* index to wave and playback params */
- EAS_U8 voiceState; /* current voice state */
- EAS_U8 voiceFlags; /* misc flags/bit fields */
- EAS_U8 channel; /* this voice plays on this synth channel */
- EAS_U8 note; /* 12 <= key number <= 108 */
- EAS_U8 velocity; /* 0 <= velocity <= 127 */
- EAS_U8 nextChannel; /* play stolen voice on this channel */
- EAS_U8 nextNote; /* 12 <= key number <= 108 */
- EAS_U8 nextVelocity; /* 0 <= velocity <= 127 */
-} S_SYNTH_VOICE;
-
-/*------------------------------------
- * S_SYNTH data structure
- *
- * One instance for each MIDI stream
- *------------------------------------
-*/
-
-/* S_SYNTH.m_nFlags */
-#define SYNTH_FLAG_RESET_IS_REQUESTED 0x01
-#define SYNTH_FLAG_SP_MIDI_ON 0x02
-#define SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS 0x04
-#define SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING 0x08
-#define DEFAULT_SYNTH_FLAGS SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS
-
-typedef struct s_synth_tag
-{
- struct s_eas_data_tag *pEASData;
- const S_EAS *pEAS;
-
-#ifdef DLS_SYNTHESIZER
- S_DLS *pDLS;
-#endif
-
-#ifdef EXTERNAL_AUDIO
- EAS_EXT_PRG_CHG_FUNC cbProgChgFunc;
- EAS_EXT_EVENT_FUNC cbEventFunc;
- EAS_VOID_PTR *pExtAudioInstData;
-#endif
-
- S_SYNTH_CHANNEL channels[NUM_SYNTH_CHANNELS];
- EAS_I32 totalNoteCount;
- EAS_U16 maxPolyphony;
- EAS_U16 numActiveVoices;
- EAS_U16 masterVolume;
- EAS_U8 channelsByPriority[NUM_SYNTH_CHANNELS];
- EAS_U8 poolCount[NUM_SYNTH_CHANNELS];
- EAS_U8 poolAlloc[NUM_SYNTH_CHANNELS];
- EAS_U8 synthFlags;
- EAS_I8 globalTranspose;
- EAS_U8 vSynthNum;
- EAS_U8 refCount;
- EAS_U8 priority;
-} S_SYNTH;
-
-/*------------------------------------
- * S_VOICE_MGR data structure
- *
- * One instance for each EAS library instance
- *------------------------------------
-*/
-typedef struct s_voice_mgr_tag
-{
- S_SYNTH *pSynth[MAX_VIRTUAL_SYNTHESIZERS];
- EAS_PCM voiceBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES];
-
-#ifdef _FM_SYNTH
- EAS_PCM operMixBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES];
- S_FM_VOICE fmVoices[NUM_FM_VOICES];
-#endif
-
-#ifdef _WT_SYNTH
- S_WT_VOICE wtVoices[NUM_WT_VOICES];
-#endif
-
-#ifdef _REVERB
- EAS_PCM reverbSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES];
-#endif
-
-#ifdef _CHORUS
- EAS_PCM chorusSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES];
-#endif
- S_SYNTH_VOICE voices[MAX_SYNTH_VOICES];
-
- EAS_SNDLIB_HANDLE pGlobalEAS;
-
-#ifdef DLS_SYNTHESIZER
- S_DLS *pGlobalDLS;
-#endif
-
-#ifdef _SPLIT_ARCHITECTURE
- EAS_FRAME_BUFFER_HANDLE pFrameBuffer;
-#endif
-
-#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
- EAS_U16 maxPolyphonyPrimary;
- EAS_U16 maxPolyphonySecondary;
-#endif
-
- EAS_I32 workload;
- EAS_I32 maxWorkLoad;
-
- EAS_U16 activeVoices;
- EAS_U16 maxPolyphony;
-
- EAS_U16 age;
-
-/* limits the number of voice starts in a frame for split architecture */
-#ifdef MAX_VOICE_STARTS
- EAS_U16 numVoiceStarts;
-#endif
-} S_VOICE_MGR;
-
-#endif /* #ifdef _EAS_SYNTH_H */
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 718 $ + * $Date: 2007-06-08 16:43:16 -0700 (Fri, 08 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_H +#define _EAS_SYNTH_H + +#include "eas_types.h" +#include "eas_sndlib.h" + +#ifdef _WT_SYNTH +#include "eas_wtsynth.h" +#endif + +#ifdef _FM_SYNTH +#include "eas_fmsynth.h" +#endif + +#ifndef NUM_OUTPUT_CHANNELS +#define NUM_OUTPUT_CHANNELS 2 +#endif + +#ifndef MAX_SYNTH_VOICES +#define MAX_SYNTH_VOICES 64 +#endif + +#ifndef MAX_VIRTUAL_SYNTHESIZERS +#define MAX_VIRTUAL_SYNTHESIZERS 4 +#endif + +/* defines */ +#ifndef NUM_PRIMARY_VOICES +#define NUM_PRIMARY_VOICES MAX_SYNTH_VOICES +#elif !defined(NUM_SECONDARY_VOICES) +#define NUM_SECONDARY_VOICES (MAX_SYNTH_VOICES - NUM_PRIMARY_VOICES) +#endif + +#if defined(EAS_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +#else +#error "Unrecognized architecture option" +#endif + +#define NUM_SYNTH_CHANNELS 16 + +#define DEFAULT_SYNTH_VOICES MAX_SYNTH_VOICES + +/* use the following values to specify unassigned channels or voices */ +#define UNASSIGNED_SYNTH_CHANNEL NUM_SYNTH_CHANNELS +#define UNASSIGNED_SYNTH_VOICE MAX_SYNTH_VOICES + + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define SYNTH_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << SYNTH_UPDATE_PERIOD_IN_BITS) + +/* stealing weighting factors */ +#define NOTE_AGE_STEAL_WEIGHT 1 +#define NOTE_GAIN_STEAL_WEIGHT 4 +#define CHANNEL_POLY_STEAL_WEIGHT 12 +#define CHANNEL_PRIORITY_STEAL_WEIGHT 2 +#define NOTE_MATCH_PENALTY 128 +#define SYNTH_PRIORITY_WEIGHT 8 + +/* default synth master volume */ +#define DEFAULT_SYNTH_MASTER_VOLUME 0x7fff + +#define DEFAULT_SYNTH_PRIORITY 5 + +/* default tuning values */ +#define DEFAULT_PITCH_BEND_SENSITIVITY 200 /* 2 semitones */ +#define DEFAULT_FINE_PITCH 0 /* 0 cents */ +#define DEFAULT_COARSE_PITCH 0 /* 0 semitones */ + +/* default drum channel is 10, but is internally 9 due to unit offset */ +#define DEFAULT_DRUM_CHANNEL 9 + +/* drum channel can simultaneously play this many voices at most */ +#define DEFAULT_CHANNEL_POLYPHONY_LIMIT 2 + +/* default instrument is acoustic piano */ +#define DEFAULT_MELODY_BANK_MSB 0x79 +#define DEFAULT_RHYTHM_BANK_MSB 0x78 +#define DEFAULT_MELODY_BANK_NUMBER (DEFAULT_MELODY_BANK_MSB << 8) +#define DEFAULT_RHYTHM_BANK_NUMBER (DEFAULT_RHYTHM_BANK_MSB << 8) +#define DEFAULT_SYNTH_PROGRAM_NUMBER 0 + +#define DEFAULT_PITCH_BEND 0x2000 /* 0x2000 == (0x40 << 7) | 0x00 */ +#define DEFAULT_MOD_WHEEL 0 +#define DEFAULT_CHANNEL_VOLUME 0x64 +#define DEFAULT_PAN 0x40 /* decimal 64, center */ + +#ifdef _REVERB +#define DEFAULT_REVERB_SEND 40 /* some reverb */ +#endif + +#ifdef _CHORUS +#define DEFAULT_CHORUS_SEND 0 /* no chorus */ +#endif + +#define DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY 0 /* EAS synth uses a different default */ +#define DEFAULT_FILTER_RESONANCE 0 +#define DEFAULT_EXPRESSION 0x7F + +#define DEFAULT_CHANNEL_PRESSURE 0 + +#define DEFAULT_REGISTERED_PARAM 0x3FFF + +#define DEFAULT_CHANNEL_STATIC_GAIN 0 +#define DEFAULT_CHANNEL_STATIC_PITCH 0 + +#define DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS 50 +#define DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS 50 + +#define DEFAULT_KEY_NUMBER 0x69 +#define DEFAULT_VELOCITY 0x64 +#define DEFAULT_REGION_INDEX 0 +#define DEFAULT_ARTICULATION_INDEX 0 +#define DEFAULT_VOICE_GAIN 0 +#define DEFAULT_AGE 0 +#define DEFAULT_SP_MIDI_PRIORITY 16 + + +/* filter defines */ +#define DEFAULT_FILTER_ZERO 0 +#define FILTER_CUTOFF_MAX_PITCH_CENTS 1919 +#define FILTER_CUTOFF_MIN_PITCH_CENTS -4467 +#define A5_PITCH_OFFSET_IN_CENTS 6900 + +/*------------------------------------ + * S_SYNTH_CHANNEL data structure + *------------------------------------ +*/ + +/* S_SYNTH_CHANNEL.m_nFlags */ +#define CHANNEL_FLAG_SUSTAIN_PEDAL 0x01 +#define CHANNEL_FLAG_MUTE 0x02 +#define CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS 0x04 +#define CHANNEL_FLAG_RHYTHM_CHANNEL 0x08 +#define CHANNEL_FLAG_EXTERNAL_AUDIO 0x10 +#define DEFAULT_CHANNEL_FLAGS 0 + +/* macros for extracting virtual synth and channel numbers */ +#define GET_VSYNTH(a) ((a) >> 4) +#define GET_CHANNEL(a) ((a) & 15) + +typedef struct s_synth_channel_tag +{ + /* use static channel parameters to reduce MIPs */ + /* parameters shared by multiple voices assigned to same channel */ + EAS_I32 staticPitch; /* (pitch bend * pitch sens) + fine pitch */ + EAS_I16 staticGain; /* (CC7 * CC11 * master vol)^2 */ + + EAS_U16 regionIndex; /* index of first region in program */ + + EAS_U16 bankNum; /* play programs from this bank */ + EAS_I16 pitchBend; /* pitch wheel value */ + EAS_I16 pitchBendSensitivity; + EAS_I16 registeredParam; /* currently selected registered param */ + + +#if defined(_FM_SYNTH) + EAS_I16 lfoAmt; /* amount of LFO to apply to voice */ +#endif + + EAS_U8 programNum; /* play this instrument number */ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + + EAS_U8 expression; /* CC11 */ + + /* the following parameters are controlled by RPNs */ + EAS_I8 finePitch; + EAS_I8 coarsePitch; + + EAS_U8 channelPressure; /* applied to all voices on a given channel */ + + EAS_U8 channelFlags; /* bit field channelFlags for */ + /* CC64, SP-MIDI channel masking */ + + EAS_U8 pool; /* SPMIDI channel voice pool */ + EAS_U8 mip; /* SPMIDI MIP setting */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_SYNTH_CHANNEL; + +/*------------------------------------ + * S_SYNTH_VOICE data structure + *------------------------------------ +*/ + +/* S_SYNTH_VOICE.m_nFlags */ +#define VOICE_FLAG_UPDATE_VOICE_PARAMETERS 0x01 +#define VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF 0x02 +#define VOICE_FLAG_DEFER_MIDI_NOTE_OFF 0x04 +#define VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET 0x08 +#define VOICE_FLAG_DEFER_MUTE 0x40 +#define DEFAULT_VOICE_FLAGS 0 + +/* S_SYNTH_VOICE.m_eState */ +typedef enum { + + eVoiceStateFree = 0, + eVoiceStateStart, + eVoiceStatePlay, + eVoiceStateRelease, + eVoiceStateMuting, + eVoiceStateStolen, + eVoiceStateInvalid /* should never be in this state! */ + +} E_VOICE_STATE; +#define DEFAULT_VOICE_STATE eVoiceStateFree + +typedef struct s_synth_voice_tag +{ + +/* These parameters are common to both wavetable and FM + * synthesizers. The voice manager should only access this data. + * Any other data should be manipulated by the code that is + * specific to that synthesizer and reflected back through the + * common state data available here. + */ + EAS_U16 regionIndex; /* index to wave and playback params */ + EAS_I16 gain; /* current gain */ + EAS_U16 age; /* large value means old note */ + EAS_U16 nextRegionIndex; /* index to wave and playback params */ + EAS_U8 voiceState; /* current voice state */ + EAS_U8 voiceFlags; /* misc flags/bit fields */ + EAS_U8 channel; /* this voice plays on this synth channel */ + EAS_U8 note; /* 12 <= key number <= 108 */ + EAS_U8 velocity; /* 0 <= velocity <= 127 */ + EAS_U8 nextChannel; /* play stolen voice on this channel */ + EAS_U8 nextNote; /* 12 <= key number <= 108 */ + EAS_U8 nextVelocity; /* 0 <= velocity <= 127 */ +} S_SYNTH_VOICE; + +/*------------------------------------ + * S_SYNTH data structure + * + * One instance for each MIDI stream + *------------------------------------ +*/ + +/* S_SYNTH.m_nFlags */ +#define SYNTH_FLAG_RESET_IS_REQUESTED 0x01 +#define SYNTH_FLAG_SP_MIDI_ON 0x02 +#define SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS 0x04 +#define SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING 0x08 +#define DEFAULT_SYNTH_FLAGS SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS + +typedef struct s_synth_tag +{ + struct s_eas_data_tag *pEASData; + const S_EAS *pEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pDLS; +#endif + +#ifdef EXTERNAL_AUDIO + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc; + EAS_EXT_EVENT_FUNC cbEventFunc; + EAS_VOID_PTR *pExtAudioInstData; +#endif + + S_SYNTH_CHANNEL channels[NUM_SYNTH_CHANNELS]; + EAS_I32 totalNoteCount; + EAS_U16 maxPolyphony; + EAS_U16 numActiveVoices; + EAS_U16 masterVolume; + EAS_U8 channelsByPriority[NUM_SYNTH_CHANNELS]; + EAS_U8 poolCount[NUM_SYNTH_CHANNELS]; + EAS_U8 poolAlloc[NUM_SYNTH_CHANNELS]; + EAS_U8 synthFlags; + EAS_I8 globalTranspose; + EAS_U8 vSynthNum; + EAS_U8 refCount; + EAS_U8 priority; +} S_SYNTH; + +/*------------------------------------ + * S_VOICE_MGR data structure + * + * One instance for each EAS library instance + *------------------------------------ +*/ +typedef struct s_voice_mgr_tag +{ + S_SYNTH *pSynth[MAX_VIRTUAL_SYNTHESIZERS]; + EAS_PCM voiceBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + +#ifdef _FM_SYNTH + EAS_PCM operMixBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + S_FM_VOICE fmVoices[NUM_FM_VOICES]; +#endif + +#ifdef _WT_SYNTH + S_WT_VOICE wtVoices[NUM_WT_VOICES]; +#endif + +#ifdef _REVERB + EAS_PCM reverbSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + +#ifdef _CHORUS + EAS_PCM chorusSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + S_SYNTH_VOICE voices[MAX_SYNTH_VOICES]; + + EAS_SNDLIB_HANDLE pGlobalEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pGlobalDLS; +#endif + +#ifdef _SPLIT_ARCHITECTURE + EAS_FRAME_BUFFER_HANDLE pFrameBuffer; +#endif + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + EAS_U16 maxPolyphonyPrimary; + EAS_U16 maxPolyphonySecondary; +#endif + + EAS_I32 workload; + EAS_I32 maxWorkLoad; + + EAS_U16 activeVoices; + EAS_U16 maxPolyphony; + + EAS_U16 age; + +/* limits the number of voice starts in a frame for split architecture */ +#ifdef MAX_VOICE_STARTS + EAS_U16 numVoiceStarts; +#endif +} S_VOICE_MGR; + +#endif /* #ifdef _EAS_SYNTH_H */ + + diff --git a/arm-fm-22k/lib_src/eas_synth_protos.h b/arm-fm-22k/lib_src/eas_synth_protos.h index a2ef10d..b03af0f 100644 --- a/arm-fm-22k/lib_src/eas_synth_protos.h +++ b/arm-fm-22k/lib_src/eas_synth_protos.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_synth_protos.h
- *
- * Contents and purpose:
- * Declarations, interfaces, and prototypes for synth.
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_synth_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,42 +19,42 @@ * 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: 82 $
- * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_SYNTH_PROTOS_H
-#define _EAS_SYNTH_PROTOS_H
-
-/* includes */
-#include "eas_data.h"
-#include "eas_sndlib.h"
-
-#ifdef _SPLIT_ARCHITECTURE
-typedef struct s_frame_interface_tag
-{
- EAS_BOOL (* EAS_CONST pfStartFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
- EAS_BOOL (* EAS_CONST pfEndFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain);
-} S_FRAME_INTERFACE;
-#endif
-
-/* generic synthesizer interface */
-typedef struct
-{
- EAS_RESULT (* EAS_CONST pfInitialize)(S_VOICE_MGR *pVoiceMgr);
- EAS_RESULT (* EAS_CONST pfStartVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex);
- EAS_BOOL (* EAS_CONST pfUpdateVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples);
- void (* EAS_CONST pfReleaseVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
- void (* EAS_CONST pfMuteVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
- void (* EAS_CONST pfSustainPedal)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum);
- void (* EAS_CONST pfUpdateChannel)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
-} S_SYNTH_INTERFACE;
-
-#endif
-
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_PROTOS_H +#define _EAS_SYNTH_PROTOS_H + +/* includes */ +#include "eas_data.h" +#include "eas_sndlib.h" + +#ifdef _SPLIT_ARCHITECTURE +typedef struct s_frame_interface_tag +{ + EAS_BOOL (* EAS_CONST pfStartFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + EAS_BOOL (* EAS_CONST pfEndFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +} S_FRAME_INTERFACE; +#endif + +/* generic synthesizer interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfInitialize)(S_VOICE_MGR *pVoiceMgr); + EAS_RESULT (* EAS_CONST pfStartVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); + EAS_BOOL (* EAS_CONST pfUpdateVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); + void (* EAS_CONST pfReleaseVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfMuteVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfSustainPedal)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); + void (* EAS_CONST pfUpdateChannel)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); +} S_SYNTH_INTERFACE; + +#endif + + + diff --git a/arm-fm-22k/lib_src/eas_synthcfg.h b/arm-fm-22k/lib_src/eas_synthcfg.h index 2491e6d..78a4178 100644 --- a/arm-fm-22k/lib_src/eas_synthcfg.h +++ b/arm-fm-22k/lib_src/eas_synthcfg.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_synthcfg.h
- *
- * Contents and purpose:
- * Defines for various synth configurations
- *
- * Copyright Sonic Network Inc. 2004, 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_synthcfg.h + * + * Contents and purpose: + * Defines for various synth configurations + * + * Copyright Sonic Network Inc. 2004, 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,52 +19,52 @@ * 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: 664 $
- * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_SYNTHCFG_H
-#define _EAS_SYNTHCFG_H
-
-#if defined(EAS_WT_SYNTH)
-#define _WT_SYNTH
-
-/* FM on MCU */
-#elif defined(EAS_FM_SYNTH)
-#define _FM_SYNTH
-
-/* wavetable drums and FM melodic on MCU */
-#elif defined(EAS_HYBRID_SYNTH)
-#define _WT_SYNTH
-#define _FM_SYNTH
-#define _SECONDARY_SYNTH
-#define _HYBRID_SYNTH
-
-/* wavetable drums on MCU, wavetable melodic on DSP */
-#elif defined(EAS_SPLIT_WT_SYNTH)
-#define _WT_SYNTH
-#define _SPLIT_ARCHITECTURE
-
-/* wavetable drums on MCU, FM melodic on DSP */
-#elif defined(EAS_SPLIT_HYBRID_SYNTH)
-#define _WT_SYNTH
-#define _FM_SYNTH
-#define _SECONDARY_SYNTH
-#define _SPLIT_ARCHITECTURE
-#define _HYBRID_SYNTH
-
-/* FM synth on DSP */
-#elif defined(EAS_SPLIT_FM_SYNTH)
-#define _FM_SYNTH
-#define _SPLIT_ARCHITECTURE
-
-#else
-#error "Unrecognized architecture option"
-#endif
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 664 $ + * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTHCFG_H +#define _EAS_SYNTHCFG_H + +#if defined(EAS_WT_SYNTH) +#define _WT_SYNTH + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define _FM_SYNTH + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _HYBRID_SYNTH + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define _WT_SYNTH +#define _SPLIT_ARCHITECTURE + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _SPLIT_ARCHITECTURE +#define _HYBRID_SYNTH + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define _FM_SYNTH +#define _SPLIT_ARCHITECTURE + +#else +#error "Unrecognized architecture option" +#endif + +#endif + diff --git a/arm-fm-22k/lib_src/eas_vm_protos.h b/arm-fm-22k/lib_src/eas_vm_protos.h index eb49ba8..20f7c09 100644 --- a/arm-fm-22k/lib_src/eas_vm_protos.h +++ b/arm-fm-22k/lib_src/eas_vm_protos.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_vm_protos.h
- *
- * Contents and purpose:
- * Declarations, interfaces, and prototypes for voice manager.
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_vm_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for voice manager. + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,1068 +19,1068 @@ * 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: 736 $
- * $Date: 2007-06-22 13:51:24 -0700 (Fri, 22 Jun 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_VM_PROTOS_H
-#define _EAS_VM_PROTOS_H
-
-// includes
-#include "eas_data.h"
-#include "eas_sndlib.h"
-
-/*----------------------------------------------------------------------------
- * VMInitialize()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMInitialize (S_EAS_DATA *pEASData);
-
-/*----------------------------------------------------------------------------
- * VMInitMIDI()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth);
-
-/*----------------------------------------------------------------------------
- * VMInitializeAllChannels()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMResetControllers()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void VMResetControllers (S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMInitMIPTable()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initialize the SP-MIDI MIP table
- *
- * Inputs:
- * pEASData - pointer to synthesizer instance data
- * mute - EAS_FALSE to unmute channels, EAS_TRUE to mute
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMInitMIPTable (S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMSetMIPEntry()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the priority and MIP level for a MIDI channel
- *
- * Inputs:
- * pEASData - pointer to synthesizer instance data
- * channel - MIDI channel number
- * priority - priority (0-15 with 0 = highest priority)
- * mip - maximum instantaneous polyphony
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip);
-
-/*----------------------------------------------------------------------------
- * VMUpdateMIPTable()
- *----------------------------------------------------------------------------
- * Purpose:
- * This routine is called when the polyphony count in the synthesizer changes
- *
- * Inputs:
- * pEASData - pointer to synthesizer instance data
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMInitializeAllVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum);
-
-/*----------------------------------------------------------------------------
- * VMStartNote()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the synth's state to play the requested note on the requested
- * channel if possible.
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nKeyNumber - the MIDI key number for this note
- * nNoteVelocity - the key velocity for this note
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity);
-
-/*----------------------------------------------------------------------------
- * VMCheckKeyGroup()
- *----------------------------------------------------------------------------
- * Purpose:
- * If the note that we've been asked to start is in the same key group as
- * any currently playing notes, then we must shut down the currently playing
- * note in the same key group and then start the newly requested note.
- *
- * Inputs:
- * nChannel - synth channel that wants to start a new note
- * nKeyNumber - new note's midi note number
- * nRegionIndex - calling routine finds this index and gives to us
- * nNoteVelocity - new note's velocity
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pbVoiceStealingRequired - flag: this routine sets true if we needed to
- * steal a voice
- *
- * Side Effects:
- * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber may be assigned
- * gsSynthObject.m_sVoice[free voice num].m_nVelocity may be assigned
- *----------------------------------------------------------------------------
-*/
-void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel);
-
-/*----------------------------------------------------------------------------
- * VMCheckPolyphonyLimiting()
- *----------------------------------------------------------------------------
- * Purpose:
- * We only play at most 2 of the same note on a MIDI channel.
- * E.g., if we are asked to start note 36, and there are already two voices
- * that are playing note 36, then we must steal the voice playing
- * the oldest note 36 and use that stolen voice to play the new note 36.
- *
- * Inputs:
- * nChannel - synth channel that wants to start a new note
- * nKeyNumber - new note's midi note number
- * nNoteVelocity - new note's velocity
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pbVoiceStealingRequired - flag: this routine sets true if we needed to
- * steal a voice
- * *
- * Side Effects:
- * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned
- * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice);
-
-/*----------------------------------------------------------------------------
- * VMStopNote()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the synth's state to end the requested note on the requested
- * channel.
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nKeyNumber - the key number of the note to stop
- * nNoteVelocity - the note-off velocity
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * gsSynthObject.m_sVoice[free voice num].m_nSynthChannel may be assigned
- * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber is assigned
- * gsSynthObject.m_sVoice[free voice num].m_nVelocity is assigned
- *----------------------------------------------------------------------------
-*/
-void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 key, EAS_U8 velocity);
-
-/*----------------------------------------------------------------------------
- * VMFindAvailableVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Find an available voice and return the voice number if available.
- *
- * Inputs:
- * pnVoiceNumber - really an output, see below
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pnVoiceNumber - returns the voice number of available voice if found
- * success - if there is an available voice
- * failure - otherwise
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice);
-
-/*----------------------------------------------------------------------------
- * VMStealVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Steal a voice and return the voice number
- *
- * Stealing algorithm: steal the best choice with minimal work, taking into
- * account SP-Midi channel priorities and polyphony allocation.
- *
- * In one pass through all the voices, figure out which voice to steal
- * taking into account a number of different factors:
- * Priority of the voice's MIDI channel
- * Number of voices over the polyphony allocation for voice's MIDI channel
- * Amplitude of the voice
- * Note age
- * Key velocity (for voices that haven't been started yet)
- * If any matching notes are found
- *
- * Inputs:
- * nChannel - the channel that this voice wants to be started on
- * nKeyNumber - the key number for this new voice
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pnVoiceNumber - voice stolen
- * EAS_RESULT EAS_SUCCESS - always successful
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice);
-
-/*----------------------------------------------------------------------------
- * VMAddSamples()
- *----------------------------------------------------------------------------
- * Purpose:
- * Synthesize the requested number of samples.
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to write to buffer
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * number of samples actually written to buffer
- *
- * Side Effects:
- * - samples are added to the presently free buffer
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamplesToAdd);
-
-/*----------------------------------------------------------------------------
- * VMProgramChange()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the instrument (program) for the given channel.
- *
- * Depending on the program number, and the bank selected for this channel, the
- * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or
- * Alternate wavetable (from mobile DLS or other DLS file)
- *
- * This function figures out what wavetable should be used, and sets it up as the
- * wavetable to use for this channel. Also the channel may switch from a melodic
- * channel to a rhythm channel, or vice versa.
- *
- * Inputs:
- *
- * Outputs:
- * Side Effects:
- * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed
- * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed
- * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed
- *
- *----------------------------------------------------------------------------
-*/
-void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program);
-
-/*----------------------------------------------------------------------------
- * VMChannelPressure()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the channel pressure for the given channel
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nVelocity - the channel pressure value
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * gsSynthObject.m_sChannel[nChannel].m_nChannelPressure is updated
- *----------------------------------------------------------------------------
-*/
-void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value);
-
-/*----------------------------------------------------------------------------
- * VMPitchBend()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the pitch wheel value for the given channel.
- * This routine constructs the proper 14-bit argument when the calling routine
- * passes the pitch LSB and MSB.
- *
- * Note: some midi disassemblers display a bipolar pitch bend value.
- * We can display the bipolar value using
- * if m_nPitchBend >= 0x2000
- * bipolar pitch bend = postive (m_nPitchBend - 0x2000)
- * else
- * bipolar pitch bend = negative (0x2000 - m_nPitchBend)
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nPitchLSB - the LSB byte from the pitch bend message
- * nPitchMSB - the MSB byte from the message
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * gsSynthObject.m_sChannel[nChannel].m_nPitchBend is changed
- *
- *----------------------------------------------------------------------------
-*/
-void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 pitchLSB, EAS_U8 pitchMSB);
-
-/*----------------------------------------------------------------------------
- * VMControlChange()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the controller (or mode) for the given channel.
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nControllerNumber - the controller number
- * nControlValue - the controller number for this control change
- * nControlValue - the value for this control change
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * gsSynthObject.m_sChannel[nChannel] controller is changed
- *
- *----------------------------------------------------------------------------
-*/
-void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value);
-
-/*----------------------------------------------------------------------------
- * VMUpdateRPNStateMachine()
- *----------------------------------------------------------------------------
- * Purpose:
- * Call this function when we want to parse a stream of RPN messages.
- * NOTE: The synth has only one set of global RPN data instead of RPN data
- * per channel.
- * So actually, we don't really need to look at the nChannel parameter,
- * but we pass it to facilitate future upgrades. Furthermore, we only
- * support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and
- * RPN2 (coarse tuning). Any other RPNs are rejected.
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nControllerNumber - the RPN controller number
- * nControlValue - the value for this control change
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * gsSynthObject.m_RPN0 (or m_RPN1 or m_RPN2) may be updated if the
- * proper RPN message sequence is parsed.
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value);
-
-/*----------------------------------------------------------------------------
- * VMUpdateStaticChannelParameters()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update all of the static channel parameters for channels that have had
- * a controller change values
- * Or if the synth has signalled that all channels must forcibly
- * be updated
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * none
- *
- * Side Effects:
- * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch
- * are updated for channels whose controller values have changed
- * or if the synth has signalled that all channels must forcibly
- * be updated
- *----------------------------------------------------------------------------
-*/
-void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMReleaseAllDeferredNoteOffs()
- *----------------------------------------------------------------------------
- * Purpose:
- * Call this functin when the sustain flag is presently set but
- * we are now transitioning from damper pedal on to
- * damper pedal off. This means all notes in this channel
- * that received a note off while the damper pedal was on, and
- * had their note-off requests deferred, should now proceed to
- * the release state.
- *
- * Inputs:
- * nChannel - this channel has its sustain pedal transitioning from on to off
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * any voice with deferred note offs on this channel are updated such that
- *
- *
- *----------------------------------------------------------------------------
-*/
-void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
-
-/*----------------------------------------------------------------------------
- * VMCatchNotesForSustainPedal()
- *----------------------------------------------------------------------------
- * Purpose:
- * Call this function when the sustain flag is presently clear and
- * the damper pedal is off and we are transitioning from damper pedal OFF to
- * damper pedal ON. Currently sounding notes should be left
- * unchanged. However, we should try to "catch" notes if possible.
- * If any notes have levels >= sustain level, catch them,
- * otherwise, let them continue to release.
- *
- * Inputs:
- * nChannel - this channel has its sustain pedal transitioning from on to off
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * any voice with deferred note offs on this channel are updated such that
- * psVoice->m_sEG1.m_eState = eEnvelopeStateSustainPedal
- *----------------------------------------------------------------------------
-*/
-void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
-
-/*----------------------------------------------------------------------------
- * VMUpdateAllNotesAge()
- *----------------------------------------------------------------------------
- * Purpose:
- * Increment the note age for all voices older than the age of the voice
- * that is stopping, effectively making the voices "younger".
- *
- * Inputs:
- * nAge - age of voice that is going away
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * m_nAge for some voices is incremented
- *----------------------------------------------------------------------------
-*/
-void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 nAge);
-
-/*----------------------------------------------------------------------------
- * VMFindRegionIndex()
- *----------------------------------------------------------------------------
- * Purpose:
- * Find the region index for the given instrument using the midi key number
- * and the RPN2 (coarse tuning) value. By using RPN2 as part of the
- * region selection process, we reduce the amount a given sample has
- * to be transposed by selecting the closest recorded root instead.
- *
- * Inputs:
- * nChannel - current channel for this note
- * nKeyNumber - current midi note number
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pnRegionIndex - valid only if we returned success
- * success if we found the region index number, otherwise
- * failure
- *
- * Side Effects:
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMFindRegionIndex (S_VOICE_MGR *pVoiceMgr, EAS_U8 channel, EAS_U8 note, EAS_U16 *pRegionIndex);
-
-/*----------------------------------------------------------------------------
- * VMIncRefCount()
- *----------------------------------------------------------------------------
- * Increment reference count for virtual synth
- *----------------------------------------------------------------------------
-*/
-void VMIncRefCount (S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMReset()
- *----------------------------------------------------------------------------
- * Purpose:
- * We call this routine to start the process of reseting the synth.
- * This routine sets a flag for the entire synth indicating that we want
- * to reset.
- * We also force all voices to mute quickly.
- * However, we do not actually perform any synthesis in this routine. That
- * is, we do not ramp the voices down from this routine, but instead, we
- * let the "regular" synth processing steps take care of adding the ramp
- * down samples to the output buffer. After we are sure that all voices
- * have completed ramping down, we continue the process of resetting the
- * synth (from another routine).
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - set a flag (in gsSynthObject.m_nFlags) indicating synth reset requested.
- * - force all voices to update their envelope states to mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force);
-
-/*----------------------------------------------------------------------------
- * VMMuteAllVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- * We call this in an emergency reset situation.
- * This forces all voices to mute quickly.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - forces all voices to update their envelope states to mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum);
-void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMReleaseAllVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- * We call this after we've encountered the end of the Midi file.
- * This ensures all voice are either in release (because we received their
- * note off already) or forces them to mute quickly.
- * We use this as a safety to prevent bad midi files from playing forever.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - forces all voices to update their envelope states to release or mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMAllNotesOff()
- *----------------------------------------------------------------------------
- * Purpose:
- * Quickly mute all notes on the given channel.
- *
- * Inputs:
- * nChannel - quickly turn off all notes on this channel
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - forces all voices on this channel to update their envelope states to mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
-
-/*----------------------------------------------------------------------------
- * VMDeferredStopNote()
- *----------------------------------------------------------------------------
- * Purpose:
- * Stop the notes that had deferred note-off requests.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * None.
- *
- * Side Effects:
- * voices that have had deferred note-off requests are now put into release
- * gsSynthObject.m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF
- * cleared
- *----------------------------------------------------------------------------
-*/
-void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMSetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the synth to a new polyphony value. Value must be >= 1 and
- * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * synth synthesizer number (0 = onboard, 1 = DSP)
- * polyphonyCount desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount);
-
-/*----------------------------------------------------------------------------
- * VMGetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the synth to a new polyphony value. Value must be >= 1 and
- * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * synth synthesizer number (0 = onboard, 1 = DSP)
- * polyphonyCount desired polyphony count
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount);
-
-/*----------------------------------------------------------------------------
- * VMSetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the virtual synth polyphony. 0 = no limit (i.e. can use
- * all available voices).
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * polyphonyCount desired polyphony count
- * pSynth pointer to virtual synth
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount);
-
-/*----------------------------------------------------------------------------
- * VMGetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current polyphony setting
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * pSynth pointer to virtual synth
- * pPolyphonyCount pointer to variable to receive data
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount);
-
-/*----------------------------------------------------------------------------
- * VMSetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the virtual synth priority
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * priority new priority
- * pSynth pointer to virtual synth
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority);
-
-/*----------------------------------------------------------------------------
- * VMGetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Get the virtual synth priority
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * pPriority pointer to variable to hold priority
- * pSynth pointer to virtual synth
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority);
-
-/*----------------------------------------------------------------------------
- * VMSetVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the master volume for this sequence
- *
- * Inputs:
- * nSynthVolume - the desired master volume
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- * overrides any previously set master volume from sysex
- *
- *----------------------------------------------------------------------------
-*/
-void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume);
-
-/*----------------------------------------------------------------------------
- * VMSetPitchBendRange()
- *----------------------------------------------------------------------------
- * Set the pitch bend range for the given channel.
- *----------------------------------------------------------------------------
-*/
-void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange);
-
-/*----------------------------------------------------------------------------
- * VMSetEASLib()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the pointer to the sound library
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS);
-EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS);
-
-#ifdef DLS_SYNTHESIZER
-/*----------------------------------------------------------------------------
- * VMSetDLSLib()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the pointer to the sound library
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS);
-EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS);
-#endif
-
-/*----------------------------------------------------------------------------
- * VMSetTranposition()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the global key transposition used by the synthesizer.
- * Transposes all melodic instruments up or down by the specified
- * amount. Range is limited to +/-12 semitones.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * transposition - transpose amount (+/-12)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition);
-
-/*----------------------------------------------------------------------------
- * VMGetTranposition()
- *----------------------------------------------------------------------------
- * Purpose:
- * Gets the global key transposition used by the synthesizer.
- * Transposes all melodic instruments up or down by the specified
- * amount. Range is limited to +/-12 semitones.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition);
-
-/*----------------------------------------------------------------------------
- * VMGetNoteCount()
- *----------------------------------------------------------------------------
-* Returns the total note count
-*----------------------------------------------------------------------------
-*/
-EAS_I32 VMGetNoteCount (S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMRender()
- *----------------------------------------------------------------------------
- * Purpose:
- * This routine renders a frame of audio
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pVoicesRendered - number of voices rendered this frame
- *
- * Side Effects:
- * sets psMidiObject->m_nMaxWorkloadPerFrame
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered);
-
-/*----------------------------------------------------------------------------
- * VMInitWorkload()
- *----------------------------------------------------------------------------
- * Purpose:
- * Clears the workload counter
- *
- * Inputs:
- * pVoiceMgr - pointer to instance data
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMInitWorkload (S_VOICE_MGR *pVoiceMgr);
-
-/*----------------------------------------------------------------------------
- * VMSetWorkload()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the max workload for a single frame.
- *
- * Inputs:
- * pVoiceMgr - pointer to instance data
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad);
-
-/*----------------------------------------------------------------------------
- * VMCheckWorkload()
- *----------------------------------------------------------------------------
- * Purpose:
- * Checks to see if work load has been exceeded on this frame.
- *
- * Inputs:
- * pVoiceMgr - pointer to instance data
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr);
-
-/*----------------------------------------------------------------------------
- * VMActiveVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the number of active voices in the synthesizer.
- *
- * Inputs:
- * pEASData - pointer to instance data
- *
- * Outputs:
- * Returns the number of active voices
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 VMActiveVoices (S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMMIDIShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Clean up any Synth related system issues.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * None
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth);
-
-/*----------------------------------------------------------------------------
- * VMShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Clean up any Synth related system issues.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * None
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMShutdown (S_EAS_DATA *pEASData);
-
-#ifdef EXTERNAL_AUDIO
-/*----------------------------------------------------------------------------
- * EAS_RegExtAudioCallback()
- *----------------------------------------------------------------------------
- * Register a callback for external audio processing
- *----------------------------------------------------------------------------
-*/
-void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc);
-
-/*----------------------------------------------------------------------------
- * VMGetMIDIControllers()
- *----------------------------------------------------------------------------
- * Returns the MIDI controller values on the specified channel
- *----------------------------------------------------------------------------
-*/
-void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl);
-#endif
-
-#ifdef _SPLIT_ARCHITECTURE
-/*----------------------------------------------------------------------------
- * VMStartFrame()
- *----------------------------------------------------------------------------
- * Purpose:
- * Starts an audio frame
- *
- * Inputs:
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData);
-
-/*----------------------------------------------------------------------------
- * VMEndFrame()
- *----------------------------------------------------------------------------
- * Purpose:
- * Stops an audio frame
- *
- * Inputs:
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData);
-#endif
-
-#endif /* #ifdef _EAS_VM_PROTOS_H */
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 736 $ + * $Date: 2007-06-22 13:51:24 -0700 (Fri, 22 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_VM_PROTOS_H +#define _EAS_VM_PROTOS_H + +// includes +#include "eas_data.h" +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the SP-MIDI MIP table + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * mute - EAS_FALSE to unmute channels, EAS_TRUE to mute + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the priority and MIP level for a MIDI channel + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * channel - MIDI channel number + * priority - priority (0-15 with 0 = highest priority) + * mip - maximum instantaneous polyphony + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip); + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * This routine is called when the polyphony count in the synthesizer changes + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum); + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the MIDI key number for this note + * nNoteVelocity - the key velocity for this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * Purpose: + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group and then start the newly requested note. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nRegionIndex - calling routine finds this index and gives to us + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the key number of the note to stop + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nSynthChannel may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber is assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 key, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, see below + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - returns the voice number of available voice if found + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples. + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamplesToAdd); + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program); + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte from the pitch bend message + * nPitchMSB - the MSB byte from the message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 pitchLSB, EAS_U8 pitchMSB); + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the controller number + * nControlValue - the controller number for this control change + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse a stream of RPN messages. + * NOTE: The synth has only one set of global RPN data instead of RPN data + * per channel. + * So actually, we don't really need to look at the nChannel parameter, + * but we pass it to facilitate future upgrades. Furthermore, we only + * support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs are rejected. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the RPN controller number + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_RPN0 (or m_RPN1 or m_RPN2) may be updated if the + * proper RPN message sequence is parsed. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * psVoice->m_sEG1.m_eState = eEnvelopeStateSustainPedal + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all voices older than the age of the voice + * that is stopping, effectively making the voices "younger". + * + * Inputs: + * nAge - age of voice that is going away + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for some voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 nAge); + +/*---------------------------------------------------------------------------- + * VMFindRegionIndex() + *---------------------------------------------------------------------------- + * Purpose: + * Find the region index for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * Inputs: + * nChannel - current channel for this note + * nKeyNumber - current midi note number + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnRegionIndex - valid only if we returned success + * success if we found the region index number, otherwise + * failure + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindRegionIndex (S_VOICE_MGR *pVoiceMgr, EAS_U8 channel, EAS_U8 note, EAS_U16 *pRegionIndex); + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - set a flag (in gsSynthObject.m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force); + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum); +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voice are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * gsSynthObject.m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pSynth pointer to virtual synth + * pPolyphonyCount pointer to variable to receive data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this sequence + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume); + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange); + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS); +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS); +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS); +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * transposition - transpose amount (+/-12) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition); + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition); + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * sets psMidiObject->m_nMaxWorkloadPerFrame + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered); + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad); + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData); +#endif + +#endif /* #ifdef _EAS_VM_PROTOS_H */ + diff --git a/arm-fm-22k/lib_src/eas_voicemgt.c b/arm-fm-22k/lib_src/eas_voicemgt.c index 873f29d..ab0b776 100644 --- a/arm-fm-22k/lib_src/eas_voicemgt.c +++ b/arm-fm-22k/lib_src/eas_voicemgt.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_voicemgt.c
- *
- * Contents and purpose:
- * Implements the synthesizer functions.
- *
- * Copyright Sonic Network Inc. 2004
+/*---------------------------------------------------------------------------- + * + * File: + * eas_voicemgt.c + * + * Contents and purpose: + * Implements the synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,3953 +19,3953 @@ * 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: 794 $
- * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-/* includes */
-#include "eas.h"
-#include "eas_data.h"
-#include "eas_config.h"
-#include "eas_report.h"
-#include "eas_midictrl.h"
-#include "eas_host.h"
-#include "eas_synth_protos.h"
-#include "eas_vm_protos.h"
-
-#ifdef DLS_SYNTHESIZER
-#include "eas_mdls.h"
-#endif
-
-// #define _DEBUG_VM
-
-/* some defines for workload */
-#define WORKLOAD_AMOUNT_SMALL_INCREMENT 5
-#define WORKLOAD_AMOUNT_START_NOTE 10
-#define WORKLOAD_AMOUNT_STOP_NOTE 10
-#define WORKLOAD_AMOUNT_KEY_GROUP 10
-#define WORKLOAD_AMOUNT_POLY_LIMIT 10
-
-/* pointer to base sound library */
-extern S_EAS easSoundLib;
-
-#ifdef TEST_HARNESS
-extern S_EAS easTestLib;
-EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum)
-{
- switch (libNum)
- {
- case 0:
- return &easSoundLib;
-#ifdef _WT_SYNTH
- case 1:
- return &easTestLib;
-#endif
- default:
- return NULL;
- }
-}
-#endif
-
-/* pointer to synthesizer interface(s) */
-#ifdef _WT_SYNTH
-extern const S_SYNTH_INTERFACE wtSynth;
-#endif
-
-#ifdef _FM_SYNTH
-extern const S_SYNTH_INTERFACE fmSynth;
-#endif
-
-typedef S_SYNTH_INTERFACE *S_SYNTH_INTERFACE_HANDLE;
-
-/* wavetable on MCU */
-#if defined(EAS_WT_SYNTH)
-const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
-
-/* FM on MCU */
-#elif defined(EAS_FM_SYNTH)
-const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth;
-
-/* wavetable drums on MCU, FM melodic on DSP */
-#elif defined(EAS_HYBRID_SYNTH)
-const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
-const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth;
-
-/* wavetable drums on MCU, wavetable melodic on DSP */
-#elif defined(EAS_SPLIT_WT_SYNTH)
-const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
-extern const S_FRAME_INTERFACE wtFrameInterface;
-const S_FRAME_INTERFACE *const pFrameInterface = &wtFrameInterface;
-
-/* wavetable drums on MCU, FM melodic on DSP */
-#elif defined(EAS_SPLIT_HYBRID_SYNTH)
-const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
-const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth;
-extern const S_FRAME_INTERFACE fmFrameInterface;
-const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface;
-
-/* FM on DSP */
-#elif defined(EAS_SPLIT_FM_SYNTH)
-const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth;
-extern const S_FRAME_INTERFACE fmFrameInterface;
-const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface;
-
-#else
-#error "Undefined architecture option"
-#endif
-
-/*----------------------------------------------------------------------------
- * inline functions
- *----------------------------------------------------------------------------
-*/
-EAS_INLINE const S_REGION* GetRegionPtr (S_SYNTH *pSynth, EAS_U16 regionIndex)
-{
-#if defined(DLS_SYNTHESIZER)
- if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
- return &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK].wtRegion.region;
-#endif
-#if defined(_HYBRID_SYNTH)
- if (regionIndex & FLAG_RGN_IDX_FM_SYNTH)
- return &pSynth->pEAS->pFMRegions[regionIndex & REGION_INDEX_MASK].region;
- else
- return &pSynth->pEAS->pWTRegions[regionIndex].region;
-#elif defined(_WT_SYNTH)
- return &pSynth->pEAS->pWTRegions[regionIndex].region;
-#elif defined(_FM_SYNTH)
- return &pSynth->pEAS->pFMRegions[regionIndex].region;
-#endif
-}
-
-/*lint -esym(715, voiceNum) used in some implementation */
-EAS_INLINE const S_SYNTH_INTERFACE* GetSynthPtr (EAS_INT voiceNum)
-{
-#if defined(_HYBRID_SYNTH)
- if (voiceNum < NUM_PRIMARY_VOICES)
- return pPrimarySynth;
- else
- return pSecondarySynth;
-#else
- return pPrimarySynth;
-#endif
-}
-
-EAS_INLINE EAS_INT GetAdjustedVoiceNum (EAS_INT voiceNum)
-{
-#if defined(_HYBRID_SYNTH)
- if (voiceNum >= NUM_PRIMARY_VOICES)
- return voiceNum - NUM_PRIMARY_VOICES;
-#endif
- return voiceNum;
-}
-
-EAS_INLINE EAS_U8 VSynthToChannel (S_SYNTH *pSynth, EAS_U8 channel)
-{
- /*lint -e{734} synthNum is always 0-15 */
- return channel | (pSynth->vSynthNum << 4);
-}
-
-/*----------------------------------------------------------------------------
- * InitVoice()
- *----------------------------------------------------------------------------
- * Initialize a synthesizer voice
- *----------------------------------------------------------------------------
-*/
-void InitVoice (S_SYNTH_VOICE *pVoice)
-{
- pVoice->channel = UNASSIGNED_SYNTH_CHANNEL;
- pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL;
- pVoice->note = pVoice->nextNote = DEFAULT_KEY_NUMBER;
- pVoice->velocity = pVoice->nextVelocity = DEFAULT_VELOCITY;
- pVoice->regionIndex = DEFAULT_REGION_INDEX;
- pVoice->age = DEFAULT_AGE;
- pVoice->voiceFlags = DEFAULT_VOICE_FLAGS;
- pVoice->voiceState = DEFAULT_VOICE_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * IncVoicePoolCount()
- *----------------------------------------------------------------------------
- * Updates the voice pool count when a voice changes state
- *----------------------------------------------------------------------------
-*/
-static void IncVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice)
-{
- S_SYNTH *pSynth;
- EAS_INT pool;
-
- /* ignore muting voices */
- if (pVoice->voiceState == eVoiceStateMuting)
- return;
-
- if (pVoice->voiceState == eVoiceStateStolen)
- {
- pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)];
- pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool;
- }
- else
- {
- pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
- pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool;
- }
-
- pSynth->poolCount[pool]++;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IncVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ }
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * DecVoicePoolCount()
- *----------------------------------------------------------------------------
- * Updates the voice pool count when a voice changes state
- *----------------------------------------------------------------------------
-*/
-static void DecVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice)
-{
- S_SYNTH *pSynth;
- EAS_INT pool;
-
- /* ignore muting voices */
- if (pVoice->voiceState == eVoiceStateMuting)
- return;
-
- if (pVoice->voiceState == eVoiceStateStolen)
- {
- pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)];
- pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool;
- }
- else
- {
- pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
- pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool;
- }
-
- pSynth->poolCount[pool]--;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "DecVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ }
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * VMInitialize()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMInitialize (S_EAS_DATA *pEASData)
-{
- S_VOICE_MGR *pVoiceMgr;
- EAS_INT i;
-
- /* check Configuration Module for data allocation */
- if (pEASData->staticMemoryModel)
- pVoiceMgr = EAS_CMEnumData(EAS_CM_SYNTH_DATA);
- else
- pVoiceMgr = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_VOICE_MGR));
- if (!pVoiceMgr)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitialize: Failed to allocate synthesizer memory\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
- EAS_HWMemSet(pVoiceMgr, 0, sizeof(S_VOICE_MGR));
-
- /* initialize non-zero variables */
- pVoiceMgr->pGlobalEAS = (S_EAS*) &easSoundLib;
- pVoiceMgr->maxPolyphony = (EAS_U16) MAX_SYNTH_VOICES;
-
-#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
- pVoiceMgr->maxPolyphonyPrimary = NUM_PRIMARY_VOICES;
- pVoiceMgr->maxPolyphonySecondary = NUM_SECONDARY_VOICES;
-#endif
-
- /* set max workload to zero */
- pVoiceMgr->maxWorkLoad = 0;
-
- /* initialize the voice manager parameters */
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- InitVoice(&pVoiceMgr->voices[i]);
-
- /* initialize the synth */
- /*lint -e{522} return unused at this time */
- pPrimarySynth->pfInitialize(pVoiceMgr);
-
- /* initialize the off-chip synth */
-#ifdef _HYBRID_SYNTH
- /*lint -e{522} return unused at this time */
- pSecondarySynth->pfInitialize(pVoiceMgr);
-#endif
-
- pEASData->pVoiceMgr = pVoiceMgr;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMInitMIDI()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth)
-{
- EAS_RESULT result;
- S_SYNTH *pSynth;
- EAS_INT virtualSynthNum;
-
- *ppSynth = NULL;
-
- /* static memory model only allows one synth */
- if (pEASData->staticMemoryModel)
- {
- if (pEASData->pVoiceMgr->pSynth[0] != NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: No virtual synthesizer support for static memory model\n"); */ }
- return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER;
- }
-
- /* check Configuration Module for data allocation */
- pSynth = EAS_CMEnumData(EAS_CM_MIDI_DATA);
- virtualSynthNum = 0;
- }
-
- /* dynamic memory model */
- else
- {
- for (virtualSynthNum = 0; virtualSynthNum < MAX_VIRTUAL_SYNTHESIZERS; virtualSynthNum++)
- if (pEASData->pVoiceMgr->pSynth[virtualSynthNum] == NULL)
- break;
- if (virtualSynthNum == MAX_VIRTUAL_SYNTHESIZERS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Exceeded number of active virtual synthesizers"); */ }
- return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER;
- }
- pSynth = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SYNTH));
- }
-
- /* make sure we have a valid memory pointer */
- if (pSynth == NULL)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Failed to allocate synthesizer memory\n"); */ }
- return EAS_ERROR_MALLOC_FAILED;
- }
- EAS_HWMemSet(pSynth, 0, sizeof(S_SYNTH));
-
- /* set the sound library pointer */
- if ((result = VMSetEASLib(pSynth, pEASData->pVoiceMgr->pGlobalEAS)) != EAS_SUCCESS)
- {
- VMMIDIShutdown(pEASData, pSynth);
- return result;
- }
-
- /* link in DLS bank if downloaded */
-#ifdef DLS_SYNTHESIZER
- if (pEASData->pVoiceMgr->pGlobalDLS)
- {
- pSynth->pDLS = pEASData->pVoiceMgr->pGlobalDLS;
- DLSAddRef(pSynth->pDLS);
- }
-#endif
-
- /* initialize MIDI state variables */
- pSynth->synthFlags = DEFAULT_SYNTH_FLAGS;
- pSynth->masterVolume = DEFAULT_SYNTH_MASTER_VOLUME;
- pSynth->refCount = 1;
- pSynth->priority = DEFAULT_SYNTH_PRIORITY;
- pSynth->poolAlloc[0] = (EAS_U8) pEASData->pVoiceMgr->maxPolyphony;
-
- VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth);
-
- pSynth->vSynthNum = (EAS_U8) virtualSynthNum;
- pEASData->pVoiceMgr->pSynth[virtualSynthNum] = pSynth;
-
- *ppSynth = pSynth;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMIncRefCount()
- *----------------------------------------------------------------------------
- * Increment reference count for virtual synth
- *----------------------------------------------------------------------------
-*/
-void VMIncRefCount (S_SYNTH *pSynth)
-{
- pSynth->refCount++;
-}
-
-/*----------------------------------------------------------------------------
- * VMReset()
- *----------------------------------------------------------------------------
- * Purpose:
- * We call this routine to start the process of reseting the synth.
- * This routine sets a flag for the entire synth indicating that we want
- * to reset.
- * We also force all voices to mute quickly.
- * However, we do not actually perform any synthesis in this routine. That
- * is, we do not ramp the voices down from this routine, but instead, we
- * let the "regular" synth processing steps take care of adding the ramp
- * down samples to the output buffer. After we are sure that all voices
- * have completed ramping down, we continue the process of resetting the
- * synth (from another routine).
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- * force - force reset even if voices are active
- *
- * Outputs:
- *
- * Side Effects:
- * - set a flag (in psSynthObject->m_nFlags) indicating synth reset requested.
- * - force all voices to update their envelope states to mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force)
-{
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: request to reset synth. Force = %d\n", force); */ }
-#endif
-
- /* force voices to off state - may cause audio artifacts */
- if (force)
- {
- pVoiceMgr->activeVoices -= pSynth->numActiveVoices;
- pSynth->numActiveVoices = 0;
- VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum);
- }
- else
- VMMuteAllVoices(pVoiceMgr, pSynth);
-
- /* don't reset if voices are still playing */
- if (pSynth->numActiveVoices == 0)
- {
- EAS_INT i;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: complete the reset process\n"); */ }
-#endif
-
- VMInitializeAllChannels(pVoiceMgr, pSynth);
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
- pSynth->poolCount[i] = 0;
-
- /* set polyphony */
- if (pSynth->maxPolyphony < pVoiceMgr->maxPolyphony)
- pSynth->poolAlloc[0] = (EAS_U8) pVoiceMgr->maxPolyphony;
- else
- pSynth->poolAlloc[0] = (EAS_U8) pSynth->maxPolyphony;
-
- /* clear reset flag */
- pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED;
- }
-
- /* handle reset after voices are muted */
- else
- pSynth->synthFlags |= SYNTH_FLAG_RESET_IS_REQUESTED;
-}
-
-/*----------------------------------------------------------------------------
- * VMInitializeAllChannels()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
-{
- S_SYNTH_CHANNEL *pChannel;
- EAS_INT i;
-
- VMResetControllers(pSynth);
-
- /* init each channel */
- pChannel = pSynth->channels;
-
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++)
- {
- pChannel->channelFlags = DEFAULT_CHANNEL_FLAGS;
- pChannel->staticGain = DEFAULT_CHANNEL_STATIC_GAIN;
- pChannel->staticPitch = DEFAULT_CHANNEL_STATIC_PITCH;
- pChannel->pool = 0;
-
- /* the drum channel needs a different init */
- if (i == DEFAULT_DRUM_CHANNEL)
- {
- pChannel->bankNum = DEFAULT_RHYTHM_BANK_NUMBER;
- pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL;
- }
- else
- pChannel->bankNum = DEFAULT_MELODY_BANK_NUMBER;
-
- VMProgramChange(pVoiceMgr, pSynth, (EAS_U8) i, DEFAULT_SYNTH_PROGRAM_NUMBER);
- }
-
-}
-
-/*----------------------------------------------------------------------------
- * VMResetControllers()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void VMResetControllers (S_SYNTH *pSynth)
-{
- S_SYNTH_CHANNEL *pChannel;
- EAS_INT i;
-
- pChannel = pSynth->channels;
-
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++)
- {
- pChannel->pitchBend = DEFAULT_PITCH_BEND;
- pChannel->modWheel = DEFAULT_MOD_WHEEL;
- pChannel->volume = DEFAULT_CHANNEL_VOLUME;
- pChannel->pan = DEFAULT_PAN;
- pChannel->expression = DEFAULT_EXPRESSION;
-
-#ifdef _REVERB
- pSynth->channels[i].reverbSend = DEFAULT_REVERB_SEND;
-#endif
-
-#ifdef _CHORUS
- pSynth->channels[i].chorusSend = DEFAULT_CHORUS_SEND;
-#endif
-
- pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE;
- pChannel->registeredParam = DEFAULT_REGISTERED_PARAM;
- pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY;
- pChannel->finePitch = DEFAULT_FINE_PITCH;
- pChannel->coarsePitch = DEFAULT_COARSE_PITCH;
-
- /* update all voices on this channel */
- pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMInitializeAllVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum)
-{
- EAS_INT i;
-
- /* initialize the voice manager parameters */
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
- if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen)
- {
- if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == vSynthNum)
- InitVoice(&pVoiceMgr->voices[i]);
- }
- else
- {
- if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == vSynthNum)
- InitVoice(&pVoiceMgr->voices[i]);
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMMuteVoice()
- *----------------------------------------------------------------------------
- * Mute the selected voice
- *----------------------------------------------------------------------------
-*/
-void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum)
-{
- S_SYNTH *pSynth;
- S_SYNTH_VOICE *pVoice;
-
- /* take no action if voice is already muted */
- pVoice = &pVoiceMgr->voices[voiceNum];
- if ((pVoice->voiceState == eVoiceStateMuting) || (pVoice->voiceState == eVoiceStateFree))
- return;
-
- /* one less voice in pool */
- DecVoicePoolCount(pVoiceMgr, pVoice);
-
- pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
- GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum));
- pVoice->voiceState = eVoiceStateMuting;
-
-}
-
-/*----------------------------------------------------------------------------
- * VMReleaseVoice()
- *----------------------------------------------------------------------------
- * Release the selected voice
- *----------------------------------------------------------------------------
-*/
-void VMReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum)
-{
- S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum];
-
- /* take no action if voice is already free, muting, or releasing */
- if (( pVoice->voiceState == eVoiceStateMuting) ||
- (pVoice->voiceState == eVoiceStateFree) ||
- (pVoice->voiceState == eVoiceStateRelease))
- return;
-
- /* stolen voices should just be muted */
- if (pVoice->voiceState == eVoiceStateStolen)
- VMMuteVoice(pVoiceMgr, voiceNum);
-
- /* release this voice */
- GetSynthPtr(voiceNum)->pfReleaseVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum));
- pVoice->voiceState = eVoiceStateRelease;
-}
-
-/*----------------------------------------------------------------------------
- * VMInitMIPTable()
- *----------------------------------------------------------------------------
- * Initialize the SP-MIDI MIP table in preparation for receiving MIP message
- *----------------------------------------------------------------------------
-*/
-void VMInitMIPTable (S_SYNTH *pSynth)
-{
- EAS_INT i;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMInitMIPTable\n"); */ }
-#endif
-
- /* clear SP-MIDI flag */
- pSynth->synthFlags &= ~SYNTH_FLAG_SP_MIDI_ON;
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
- {
- pSynth->channels[i].pool = 0;
- pSynth->channels[i].mip = 0;
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMSetMIPEntry()
- *----------------------------------------------------------------------------
- * Sets the priority and MIP level for a MIDI channel
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pVoiceMgr) reserved for future use */
-void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip)
-{
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMSetMIPEntry: channel=%d, priority=%d, MIP=%d\n", channel, priority, mip); */ }
-#endif
-
- /* save data for use by MIP message processing */
- if (priority < NUM_SYNTH_CHANNELS)
- {
- pSynth->channels[channel].pool = priority;
- pSynth->channels[channel].mip = mip;
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMMIPUpdateChannelMuting()
- *----------------------------------------------------------------------------
- * This routine is called after an SP-MIDI message is received and
- * any time the allocated polyphony changes. It mutes or unmutes
- * channels based on polyphony.
- *----------------------------------------------------------------------------
-*/
-void VMMIPUpdateChannelMuting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
-{
- EAS_INT i;
- EAS_INT maxPolyphony;
- EAS_INT channel;
- EAS_INT vSynthNum;
- EAS_INT pool;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ }
-#endif
-
- /* determine max polyphony */
- if (pSynth->maxPolyphony)
- maxPolyphony = pSynth->maxPolyphony;
- else
- maxPolyphony = pVoiceMgr->maxPolyphony;
-
- /* process channels */
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
- {
-
- /* channel must be in MIP message and must meet allocation target */
- if ((pSynth->channels[i].mip != 0) && (pSynth->channels[i].mip <= maxPolyphony))
- pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_MUTE;
- else
- pSynth->channels[i].channelFlags |= CHANNEL_FLAG_MUTE;
-
- /* reset voice pool count */
- pSynth->poolCount[i] = 0;
- }
-
- /* mute any voices on muted channels, and count unmuted voices */
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
-
- /* ignore free voices */
- if (pVoiceMgr->voices[i].voiceState == eVoiceStateFree)
- continue;
-
- /* get channel and virtual synth */
- if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen)
- {
- vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].channel);
- channel = GET_CHANNEL(pVoiceMgr->voices[i].channel);
- }
- else
- {
- vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].nextChannel);
- channel = GET_CHANNEL(pVoiceMgr->voices[i].nextChannel);
- }
-
- /* ignore voices on other synths */
- if (vSynthNum != pSynth->vSynthNum)
- continue;
-
- /* count voices */
- pool = pSynth->channels[channel].pool;
-
- /* deal with muted channels */
- if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_MUTE)
- {
- /* mute stolen voices scheduled to play on this channel */
- if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen)
- pVoiceMgr->voices[i].voiceState = eVoiceStateMuting;
-
- /* release voices that aren't already muting */
- else if (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)
- {
- VMReleaseVoice(pVoiceMgr, pSynth, i);
- pSynth->poolCount[pool]++;
- }
- }
-
- /* not muted, count this voice */
- else
- pSynth->poolCount[pool]++;
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMUpdateMIPTable()
- *----------------------------------------------------------------------------
- * This routine is called at the end of the SysEx message to allow
- * the Voice Manager to complete the initialization of the MIP
- * table. It assigns channels to the appropriate voice pool based
- * on the MIP setting and calculates the voices allocated for each
- * pool.
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pVoiceMgr) reserved for future use */
-void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
-{
- S_SYNTH_CHANNEL *pChannel;
- EAS_INT i;
- EAS_INT currentMIP;
- EAS_INT currentPool;
- EAS_INT priority[NUM_SYNTH_CHANNELS];
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ }
-#endif
-
- /* set SP-MIDI flag */
- pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON;
-
- /* sort channels into priority order */
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
- priority[i] = -1;
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
- {
- if (pSynth->channels[i].pool != DEFAULT_SP_MIDI_PRIORITY)
- priority[pSynth->channels[i].pool] = i;
- }
-
- /* process channels in priority order */
- currentMIP = 0;
- currentPool = -1;
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
- {
- /* stop when we run out of channels */
- if (priority[i] == -1)
- break;
-
- pChannel = &pSynth->channels[priority[i]];
-
- /* when 2 or more channels have the same MIP setting, they
- * share a common voice pool
- */
- if (pChannel->mip == currentMIP)
- pChannel->pool = (EAS_U8) currentPool;
-
- /* new voice pool */
- else
- {
- currentPool++;
- pSynth->poolAlloc[currentPool] = (EAS_U8) (pChannel->mip - currentMIP);
- currentMIP = pChannel->mip;
- }
- }
-
- /* set SP-MIDI flag */
- pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON;
-
- /* update channel muting */
- VMMIPUpdateChannelMuting (pVoiceMgr, pSynth);
-}
-
-/*----------------------------------------------------------------------------
- * VMMuteAllVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- * We call this in an emergency reset situation.
- * This forces all voices to mute quickly.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - forces all voices to update their envelope states to mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
-{
- EAS_INT i;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMMuteAllVoices: about to mute all voices!!\n"); */ }
-#endif
-
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
- /* for stolen voices, check new channel */
- if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen)
- {
- if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum)
- VMMuteVoice(pVoiceMgr, i);
- }
-
- else if (pSynth->vSynthNum == GET_VSYNTH(pVoiceMgr->voices[i].channel))
- VMMuteVoice(pVoiceMgr, i);
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMReleaseAllVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- * We call this after we've encountered the end of the Midi file.
- * This ensures all voices are either in release (because we received their
- * note off already) or forces them to mute quickly.
- * We use this as a safety to prevent bad midi files from playing forever.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - forces all voices to update their envelope states to release or mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
-{
- EAS_INT i;
-
- /* release sustain pedal on all channels */
- for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
- {
- if (pSynth->channels[ i ].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
- {
- VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, (EAS_U8) i);
- pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL;
- }
- }
-
- /* release all voices */
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
-
- switch (pVoiceMgr->voices[i].voiceState)
- {
- case eVoiceStateStart:
- case eVoiceStatePlay:
- /* only release voices on this synth */
- if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == pSynth->vSynthNum)
- VMReleaseVoice(pVoiceMgr, pSynth, i);
- break;
-
- case eVoiceStateStolen:
- if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum)
- VMMuteVoice(pVoiceMgr, i);
- break;
-
- case eVoiceStateFree:
- case eVoiceStateRelease:
- case eVoiceStateMuting:
- break;
-
- case eVoiceStateInvalid:
- default:
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllVoices: error, %d is an unrecognized state\n",
- pVoiceMgr->voices[i].voiceState); */ }
-#endif
- break;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMAllNotesOff()
- *----------------------------------------------------------------------------
- * Purpose:
- * Quickly mute all notes on the given channel.
- *
- * Inputs:
- * nChannel - quickly turn off all notes on this channel
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * - forces all voices on this channel to update their envelope states to mute
- *
- *----------------------------------------------------------------------------
-*/
-void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
-{
- EAS_INT voiceNum;
- S_SYNTH_VOICE *pVoice;
-
-#ifdef _DEBUG_VM
- if (channel >= NUM_SYNTH_CHANNELS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAllNotesOff: error, %d invalid channel number\n",
- channel); */ }
- return;
- }
-#endif
-
- /* increment workload */
- pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT;
-
- /* check each voice */
- channel = VSynthToChannel(pSynth, channel);
- for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
- {
- pVoice = &pVoiceMgr->voices[voiceNum];
- if (pVoice->voiceState != eVoiceStateFree)
- {
- if (((pVoice->voiceState != eVoiceStateStolen) && (channel == pVoice->channel)) ||
- ((pVoice->voiceState == eVoiceStateStolen) && (channel == pVoice->nextChannel)))
- {
- /* this voice is assigned to the requested channel */
- GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum));
- pVoice->voiceState = eVoiceStateMuting;
- }
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMDeferredStopNote()
- *----------------------------------------------------------------------------
- * Purpose:
- * Stop the notes that had deferred note-off requests.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * None.
- *
- * Side Effects:
- * voices that have had deferred note-off requests are now put into release
- * psSynthObject->m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF
- * cleared
- *----------------------------------------------------------------------------
-*/
-void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
-{
- EAS_INT voiceNum;
- EAS_INT channel;
- EAS_BOOL deferredNoteOff;
-
- deferredNoteOff = EAS_FALSE;
-
- /* check each voice to see if it requires a deferred note off */
- for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
- {
- if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF)
- {
- /* check if this voice was stolen */
- if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen)
- {
- /*
- This voice was stolen, AND it also has a deferred note-off.
- The stolen note must be completely ramped down at this point.
- The note that caused the stealing to occur, however, must
- have received a note-off request before the note that caused
- stealing ever had a chance to even start. We want to give
- the note that caused the stealing a chance to play, so we
- start it on the next update interval, and we defer sending
- the note-off request until the subsequent update interval.
- So do not send the note-off request for this voice because
- this voice was stolen and should have completed ramping down,
- Also, do not clear the global flag nor this voice's flag
- because we must indicate that the subsequent update interval,
- after the note that caused stealing has started, should
- then send the deferred note-off request.
- */
- deferredNoteOff = EAS_TRUE;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: defer request to stop voice %d (channel=%d note=%d) - voice not started\n",
- voiceNum,
- pVoiceMgr->voices[voiceNum].nextChannel,
- pVoiceMgr->voices[voiceNum].note); */ }
-
- /* sanity check: this stolen voice better be ramped to zero */
- if (0 != pVoiceMgr->voices[voiceNum].gain)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: warning, this voice did not complete its ramp to zero\n"); */ }
- }
-#endif // #ifdef _DEBUG_VM
-
- }
- else
- {
- /* clear the flag using exor */
- pVoiceMgr->voices[voiceNum].voiceFlags ^=
- VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: Stop voice %d (channel=%d note=%d)\n",
- voiceNum,
- pVoiceMgr->voices[voiceNum].nextChannel,
- pVoiceMgr->voices[voiceNum].note); */ }
-#endif
-
- channel = pVoiceMgr->voices[voiceNum].channel & 15;
-
- /* check if sustain pedal is on */
- if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
- {
- GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum));
- }
-
- /* release this voice */
- else
- VMReleaseVoice(pVoiceMgr, pSynth, voiceNum);
-
- }
-
- }
-
- }
-
- /* clear the deferred note-off flag, unless there's another one pending */
- if (deferredNoteOff == EAS_FALSE)
- pSynth->synthFlags ^= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING;
-}
-
-/*----------------------------------------------------------------------------
- * VMReleaseAllDeferredNoteOffs()
- *----------------------------------------------------------------------------
- * Purpose:
- * Call this functin when the sustain flag is presently set but
- * we are now transitioning from damper pedal on to
- * damper pedal off. This means all notes in this channel
- * that received a note off while the damper pedal was on, and
- * had their note-off requests deferred, should now proceed to
- * the release state.
- *
- * Inputs:
- * nChannel - this channel has its sustain pedal transitioning from on to off
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * any voice with deferred note offs on this channel are updated such that
- * pVoice->m_sEG1.m_eState = eEnvelopeStateRelease
- * pVoice->m_sEG1.m_nIncrement = release increment
- * pVoice->m_nFlags = clear the deferred note off flag
- *----------------------------------------------------------------------------
-*/
-void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
-{
- S_SYNTH_VOICE *pVoice;
- EAS_INT voiceNum;
-
-#ifdef _DEBUG_VM
- if (channel >= NUM_SYNTH_CHANNELS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllDeferredNoteOffs: error, %d invalid channel number\n",
- channel); */ }
- return;
- }
-#endif /* #ifdef _DEBUG_VM */
-
- /* increment workload */
- pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT;
-
- /* find all the voices assigned to this channel */
- channel = VSynthToChannel(pSynth, channel);
- for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
- {
-
- pVoice = &pVoiceMgr->voices[voiceNum];
- if (channel == pVoice->channel)
- {
-
- /* does this voice have a deferred note off? */
- if (pVoice->voiceFlags & VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF)
- {
- /* release voice */
- VMReleaseVoice(pVoiceMgr, pSynth, voiceNum);
-
- /* use exor to flip bit, clear the flag */
- pVoice->voiceFlags &= ~VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
-
- }
-
- }
- }
-
- return;
-}
-
-/*----------------------------------------------------------------------------
- * VMCatchNotesForSustainPedal()
- *----------------------------------------------------------------------------
- * Purpose:
- * Call this function when the sustain flag is presently clear and
- * the damper pedal is off and we are transitioning from damper pedal OFF to
- * damper pedal ON. Currently sounding notes should be left
- * unchanged. However, we should try to "catch" notes if possible.
- * If any notes are in release and have levels >= sustain level, catch them,
- * otherwise, let them continue to release.
- *
- * Inputs:
- * nChannel - this channel has its sustain pedal transitioning from on to off
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *----------------------------------------------------------------------------
-*/
-void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
-{
- EAS_INT voiceNum;
-
-#ifdef _DEBUG_VM
- if (channel >= NUM_SYNTH_CHANNELS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCatchNotesForSustainPedal: error, %d invalid channel number\n",
- channel); */ }
- return;
- }
-#endif
-
- pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT;
- channel = VSynthToChannel(pSynth, channel);
-
- /* find all the voices assigned to this channel */
- for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
- {
- if (channel == pVoiceMgr->voices[voiceNum].channel)
- {
- if (eVoiceStateRelease == pVoiceMgr->voices[voiceNum].voiceState)
- GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum));
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMUpdateAllNotesAge()
- *----------------------------------------------------------------------------
- * Purpose:
- * Increment the note age for all of the active voices.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * m_nAge for all voices is incremented
- *----------------------------------------------------------------------------
-*/
-void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 age)
-{
- EAS_INT i;
-
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
- if (age - pVoiceMgr->voices[i].age > 0)
- pVoiceMgr->voices[i].age++;
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMStolenVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * The selected voice is being stolen. Sets the parameters so that the
- * voice will begin playing the new sound on the next buffer.
- *
- * Inputs:
- * pVoice - pointer to voice to steal
- * nChannel - the channel to start a note on
- * nKeyNumber - the key number to start a note for
- * nNoteVelocity - the key velocity from this note
- *
- * Outputs:
- * None
- *----------------------------------------------------------------------------
-*/
-static void VMStolenVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex)
-{
- S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum];
-
- /* one less voice in old pool */
- DecVoicePoolCount(pVoiceMgr, pVoice);
-
- /* mute the sound that is currently playing */
- GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)], &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum));
- pVoice->voiceState = eVoiceStateStolen;
-
- /* set new note data */
- pVoice->nextChannel = VSynthToChannel(pSynth, channel);
- pVoice->nextNote = note;
- pVoice->nextVelocity = velocity;
- pVoice->nextRegionIndex = regionIndex;
-
- /* one more voice in new pool */
- IncVoicePoolCount(pVoiceMgr, pVoice);
-
- /* clear the deferred flags */
- pVoice->voiceFlags &=
- ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
- VOICE_FLAG_DEFER_MUTE |
- VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF);
-
- /* all notes older than this one get "younger" */
- VMUpdateAllNotesAge(pVoiceMgr, pVoice->age);
-
- /* assign current age to this note and increment for the next note */
- pVoice->age = pVoiceMgr->age++;
-}
-
-/*----------------------------------------------------------------------------
- * VMFreeVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * The selected voice is done playing and being returned to the
- * pool of free voices
- *
- * Inputs:
- * pVoice - pointer to voice to free
- *
- * Outputs:
- * None
- *----------------------------------------------------------------------------
-*/
-static void VMFreeVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
-{
-
- /* do nothing if voice is already free */
- if (pVoice->voiceState == eVoiceStateFree)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMFreeVoice: Attempt to free voice that is already free\n"); */ }
- return;
- }
-
- /* if we jump directly to free without passing muting stage,
- * we need to adjust the voice count */
- DecVoicePoolCount(pVoiceMgr, pVoice);
-
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMFreeVoice: Synth=%d\n", pSynth->vSynthNum); */ }
-#endif
-
- /* return to free voice pool */
- pVoiceMgr->activeVoices--;
- pSynth->numActiveVoices--;
- InitVoice(pVoice);
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFreeVoice: free voice %d\n", pVoice - pVoiceMgr->voices); */ }
-#endif
-
- /* all notes older than this one get "younger" */
- VMUpdateAllNotesAge(pVoiceMgr, pVoice->age);
- }
-
-/*----------------------------------------------------------------------------
- * VMRetargetStolenVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * The selected voice has been stolen and needs to be initalized with
- * the paramters of its new note.
- *
- * Inputs:
- * pVoice - pointer to voice to retarget
- *
- * Outputs:
- * None
- *----------------------------------------------------------------------------
-*/
-static EAS_BOOL VMRetargetStolenVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum)
-{
- EAS_U8 flags;
- S_SYNTH_CHANNEL *pMIDIChannel;
- S_SYNTH_VOICE *pVoice;
- S_SYNTH *pSynth;
- S_SYNTH *pNextSynth;
-
- /* establish some pointers */
- pVoice = &pVoiceMgr->voices[voiceNum];
- pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
- pMIDIChannel = &pSynth->channels[pVoice->channel & 15];
- pNextSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)];
-
-#ifdef _DEBUG_VM
-{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: retargeting stolen voice %d on channel %d\n",
- voiceNum, pVoice->channel); */ }
-
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\to channel %d note: %d velocity: %d\n",
- pVoice->nextChannel, pVoice->nextNote, pVoice->nextVelocity); */ }
-#endif
-
- /* make sure new channel hasn't been muted by SP-MIDI since the voice was stolen */
- if ((pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) &&
- (pMIDIChannel->channelFlags & CHANNEL_FLAG_MUTE))
- {
- VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]);
- return EAS_FALSE;
- }
-
- /* if assigned to a new synth, correct the active voice count */
- if (pVoice->channel != pVoice->nextChannel)
- {
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: Note assigned to different virtual synth, adjusting numActiveVoices\n"); */ }
-#endif
- pSynth->numActiveVoices--;
- pNextSynth->numActiveVoices++;
- }
-
- /* assign new channel number, and increase channel voice count */
- pVoice->channel = pVoice->nextChannel;
- pMIDIChannel = &pNextSynth->channels[pVoice->channel & 15];
-
- /* assign other data */
- pVoice->note = pVoice->nextNote;
- pVoice->velocity = pVoice->nextVelocity;
- pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL;
- pVoice->regionIndex = pVoice->nextRegionIndex;
-
- /* save the flags, pfStartVoice() will clear them */
- flags = pVoice->voiceFlags;
-
- /* keep track of the note-start related workload */
- pVoiceMgr->workload += WORKLOAD_AMOUNT_START_NOTE;
-
- /* setup the voice parameters */
- pVoice->voiceState = eVoiceStateStart;
-
- /*lint -e{522} return not used at this time */
- GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pNextSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pVoice->regionIndex);
-
- /* did the new note already receive a MIDI note-off request? */
- if (flags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF)
- {
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetVoice: stolen note note-off request deferred\n"); */ }
-#endif
- pVoice->voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
- pNextSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING;
- }
-
- return EAS_TRUE;
-}
-
-/*----------------------------------------------------------------------------
- * VMCheckKeyGroup()
- *----------------------------------------------------------------------------
- * If the note that we've been asked to start is in the same key group as
- * any currently playing notes, then we must shut down the currently playing
- * note in the same key group
- *----------------------------------------------------------------------------
-*/
-void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel)
-{
- const S_REGION *pRegion;
- EAS_INT voiceNum;
-
- /* increment frame workload */
- pVoiceMgr->workload += WORKLOAD_AMOUNT_KEY_GROUP;
-
- /* need to check all voices in case this is a layered sound */
- channel = VSynthToChannel(pSynth, channel);
- for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
- {
- if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen)
- {
- /* voice must be on the same channel */
- if (channel == pVoiceMgr->voices[voiceNum].channel)
- {
- /* check key group */
- pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].regionIndex);
- if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00))
- {
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ }
-#endif
-
- /* if this voice was just started, set it to mute on the next buffer */
- if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
- pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE;
-
- /* mute immediately */
- else
- VMMuteVoice(pVoiceMgr, voiceNum);
- }
- }
- }
-
- /* for stolen voice, check new values */
- else
- {
- /* voice must be on the same channel */
- if (channel == pVoiceMgr->voices[voiceNum].nextChannel)
- {
- /* check key group */
- pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].nextRegionIndex);
- if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00))
- {
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ }
-#endif
-
- /* if this voice was just started, set it to mute on the next buffer */
- if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
- pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE;
-
- /* mute immediately */
- else
- VMMuteVoice(pVoiceMgr, voiceNum);
- }
- }
-
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMCheckPolyphonyLimiting()
- *----------------------------------------------------------------------------
- * Purpose:
- * We only play at most 2 of the same note on a MIDI channel.
- * E.g., if we are asked to start note 36, and there are already two voices
- * that are playing note 36, then we must steal the voice playing
- * the oldest note 36 and use that stolen voice to play the new note 36.
- *
- * Inputs:
- * nChannel - synth channel that wants to start a new note
- * nKeyNumber - new note's midi note number
- * nNoteVelocity - new note's velocity
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pbVoiceStealingRequired - flag: this routine sets true if we needed to
- * steal a voice
- * *
- * Side Effects:
- * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned
- * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice)
-{
- EAS_INT voiceNum;
- EAS_INT oldestVoiceNum;
- EAS_INT numVoicesPlayingNote;
- EAS_U16 age;
- EAS_U16 oldestNoteAge;
-
- pVoiceMgr->workload += WORKLOAD_AMOUNT_POLY_LIMIT;
-
- numVoicesPlayingNote = 0;
- oldestVoiceNum = MAX_SYNTH_VOICES;
- oldestNoteAge = 0;
- channel = VSynthToChannel(pSynth, channel);
-
- /* examine each voice on this channel playing this note */
- for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++)
- {
- /* check stolen notes separately */
- if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen)
- {
-
- /* same channel and note ? */
- if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note))
- {
- numVoicesPlayingNote++;
- age = pVoiceMgr->age - pVoiceMgr->voices[voiceNum].age;
-
- /* is this the oldest voice for this note? */
- if (age >= oldestNoteAge)
- {
- oldestNoteAge = age;
- oldestVoiceNum = voiceNum;
- }
- }
- }
-
- /* handle stolen voices */
- else
- {
- /* same channel and note ? */
- if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote))
- {
- numVoicesPlayingNote++;
- }
- }
- }
-
- /* check to see if we exceeded poly limit */
- if (numVoicesPlayingNote < DEFAULT_CHANNEL_POLYPHONY_LIMIT)
- return EAS_FALSE;
-
- /* make sure we have a voice to steal */
- if (oldestVoiceNum != MAX_SYNTH_VOICES)
- {
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckPolyphonyLimiting: voice %d has the oldest note\n", oldestVoiceNum); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMCheckPolyphonyLimiting: polyphony limiting requires shutting down note %d \n", pVoiceMgr->voices[oldestVoiceNum].note); */ }
-#endif
- VMStolenVoice(pVoiceMgr, pSynth, oldestVoiceNum, channel, note, velocity, regionIndex);
- return EAS_TRUE;
- }
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMCheckPolyphonyLimiting: No oldest voice to steal\n"); */ }
-#endif
- return EAS_FALSE;
-}
-
-/*----------------------------------------------------------------------------
- * VMStartVoice()
- *----------------------------------------------------------------------------
- * Starts a voice given a region index
- *----------------------------------------------------------------------------
-*/
-void VMStartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex)
-{
- const S_REGION *pRegion;
- S_SYNTH_CHANNEL *pChannel;
- EAS_INT voiceNum;
- EAS_INT maxSynthPoly;
- EAS_I32 lowVoice, highVoice;
- EAS_U16 keyGroup;
-
- pChannel = &pSynth->channels[channel];
- pRegion = GetRegionPtr(pSynth, regionIndex);
-
- /* select correct synth */
-#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
- {
-#ifdef EAS_SPLIT_WT_SYNTH
- if ((pRegion->keyGroupAndFlags & REGION_FLAG_OFF_CHIP) == 0)
-#else
- if ((regionIndex & FLAG_RGN_IDX_FM_SYNTH) == 0)
-#endif
- {
- lowVoice = 0;
- highVoice = NUM_PRIMARY_VOICES - 1;
- }
- else
- {
- lowVoice = NUM_PRIMARY_VOICES;
- highVoice = MAX_SYNTH_VOICES - 1;
- }
- }
-#else
- lowVoice = 0;
- highVoice = MAX_SYNTH_VOICES - 1;
-#endif
-
- /* keep track of the note-start related workload */
- pVoiceMgr->workload+= WORKLOAD_AMOUNT_START_NOTE;
-
- /* other voices in pool, check for key group and poly limiting */
- if (pSynth->poolCount[pChannel->pool] != 0)
- {
-
- /* check for key group exclusivity */
- keyGroup = pRegion->keyGroupAndFlags & 0x0f00;
- if (keyGroup!= 0)
- VMCheckKeyGroup(pVoiceMgr, pSynth, keyGroup, channel);
-
- /* check polyphony limit and steal a voice if necessary */
- if ((pRegion->keyGroupAndFlags & REGION_FLAG_NON_SELF_EXCLUSIVE) == 0)
- {
- if (VMCheckPolyphonyLimiting(pVoiceMgr, pSynth, channel, note, velocity, regionIndex, lowVoice, highVoice) == EAS_TRUE)
- return;
- }
- }
-
- /* check max poly allocation */
- if ((pSynth->maxPolyphony == 0) || (pVoiceMgr->maxPolyphony < pSynth->maxPolyphony))
- maxSynthPoly = pVoiceMgr->maxPolyphony;
- else
- maxSynthPoly = pSynth->maxPolyphony;
-
- /* any free voices? */
- if ((pVoiceMgr->activeVoices < pVoiceMgr->maxPolyphony) &&
- (pSynth->numActiveVoices < maxSynthPoly) &&
- (EAS_SUCCESS == VMFindAvailableVoice(pVoiceMgr, &voiceNum, lowVoice, highVoice)))
- {
- S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum];
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMStartVoice: Synth=%d\n", pSynth->vSynthNum); */ }
-#endif
-
- /* bump voice counts */
- pVoiceMgr->activeVoices++;
- pSynth->numActiveVoices++;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: voice %d assigned to channel %d note %d velocity %d\n",
- voiceNum, channel, note, velocity); */ }
-#endif
-
- /* save parameters */
- pVoiceMgr->voices[voiceNum].channel = VSynthToChannel(pSynth, channel);
- pVoiceMgr->voices[voiceNum].note = note;
- pVoiceMgr->voices[voiceNum].velocity = velocity;
-
- /* establish note age for voice stealing */
- pVoiceMgr->voices[voiceNum].age = pVoiceMgr->age++;
-
- /* setup the synthesis parameters */
- pVoiceMgr->voices[voiceNum].voiceState = eVoiceStateStart;
-
- /* increment voice pool count */
- IncVoicePoolCount(pVoiceMgr, pVoice);
-
- /* start voice on correct synth */
- /*lint -e{522} return not used at this time */
- GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), regionIndex);
- return;
- }
-
- /* no free voices, we have to steal one using appropriate algorithm */
- if (VMStealVoice(pVoiceMgr, pSynth, &voiceNum, channel, note, lowVoice, highVoice) == EAS_SUCCESS)
- VMStolenVoice(pVoiceMgr, pSynth, voiceNum, channel, note, velocity, regionIndex);
-
-#ifdef _DEBUG_VM
- else
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: Could not steal a voice for channel %d note %d velocity %d\n",
- channel, note, velocity); */ }
- }
-#endif
-
- return;
-}
-
-/*----------------------------------------------------------------------------
- * VMStartNote()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the synth's state to play the requested note on the requested
- * channel if possible.
- *
- * Inputs:
- * nChannel - the channel to start a note on
- * nKeyNumber - the key number to start a note for
- * nNoteVelocity - the key velocity from this note
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * psSynthObject->m_nNumActiveVoices may be incremented
- * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned
- * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned
- * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned
- *----------------------------------------------------------------------------
-*/
-void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity)
-{
- S_SYNTH_CHANNEL *pChannel;
- EAS_U16 regionIndex;
- EAS_I16 adjustedNote;
-
- /* bump note count */
- pSynth->totalNoteCount++;
-
- pChannel = &pSynth->channels[channel];
-
- /* check channel mute */
- if (pChannel->channelFlags & CHANNEL_FLAG_MUTE)
- return;
-
-#ifdef EXTERNAL_AUDIO
- /* pass event to external audio when requested */
- if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL))
- {
- S_EXT_AUDIO_EVENT event;
- event.channel = channel;
- event.note = note;
- event.velocity = velocity;
- event.noteOn = EAS_TRUE;
- if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event))
- return;
- }
-#endif
-
- /* start search at first region */
- regionIndex = pChannel->regionIndex;
-
- /* handle transposition */
- adjustedNote = note;
- if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)
- adjustedNote += pChannel->coarsePitch;
- else
- adjustedNote += pChannel->coarsePitch + pSynth->globalTranspose;
-
- /* limit adjusted key number so it does not wraparound, over/underflow */
- if (adjustedNote < 0)
- {
- adjustedNote = 0;
- }
- else if (adjustedNote > 127)
- {
- adjustedNote = 127;
- }
-
-#if defined(DLS_SYNTHESIZER)
- if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
- {
- /* DLS voice */
- for (;;)
- {
- /*lint -e{740,826} cast OK, we know this is actually a DLS region */
- const S_DLS_REGION *pDLSRegion = (S_DLS_REGION*) GetRegionPtr(pSynth, regionIndex);
-
- /* check key against this region's key and velocity range */
- if (((adjustedNote >= pDLSRegion->wtRegion.region.rangeLow) && (adjustedNote <= pDLSRegion->wtRegion.region.rangeHigh)) &&
- ((velocity >= pDLSRegion->velLow) && (velocity <= pDLSRegion->velHigh)))
- {
- VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex);
- }
-
- /* last region in program? */
- if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_LAST_REGION)
- break;
-
- /* advance to next region */
- regionIndex++;
- }
- }
- else
-#endif
-
- /* braces here for #if clause */
- {
- /* EAS voice */
- for (;;)
- {
- const S_REGION *pRegion = GetRegionPtr(pSynth, regionIndex);
-
- /* check key against this region's keyrange */
- if ((adjustedNote >= pRegion->rangeLow) && (adjustedNote <= pRegion->rangeHigh))
- {
- VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex);
- break;
- }
-
- /* last region in program? */
- if (pRegion->keyGroupAndFlags & REGION_FLAG_LAST_REGION)
- break;
-
- /* advance to next region */
- regionIndex++;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMStopNote()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update the synth's state to end the requested note on the requested
- * channel.
- *
- * Inputs:
- * nChannel - the channel to stop a note on
- * nKeyNumber - the key number for this note off
- * nNoteVelocity - the note-off velocity
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned
- * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned
- * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, velocity) reserved for future use */
-void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity)
-{
- S_SYNTH_CHANNEL *pChannel;
- EAS_INT voiceNum;
-
- pChannel = &(pSynth->channels[channel]);
-
-#ifdef EXTERNAL_AUDIO
- if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL))
- {
- S_EXT_AUDIO_EVENT event;
- event.channel = channel;
- event.note = note;
- event.velocity = velocity;
- event.noteOn = EAS_FALSE;
- if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event))
- return;
- }
-#endif
-
- /* keep track of the note-start workload */
- pVoiceMgr->workload += WORKLOAD_AMOUNT_STOP_NOTE;
-
- channel = VSynthToChannel(pSynth, channel);
-
- for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
- {
-
- /* stolen notes are handled separately */
- if (eVoiceStateStolen != pVoiceMgr->voices[voiceNum].voiceState)
- {
-
- /* channel and key number must match */
- if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note))
- {
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n",
- voiceNum, channel, note); */ }
-#endif
-
- /* if sustain pedal is down, set deferred note-off flag */
- if (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
- {
- pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
- continue;
- }
-
- /* if this note just started, wait before we stop it */
- if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
- {
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tDeferred: Not started yet\n"); */ }
-#endif
- pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
- pSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING;
- }
-
- /* release voice */
- else
- VMReleaseVoice(pVoiceMgr, pSynth, voiceNum);
-
- }
- }
-
- /* process stolen notes, new channel and key number must match */
- else if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote))
- {
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n\tDeferred: Stolen voice\n",
- voiceNum, channel, note); */ }
-#endif
- pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * VMFindAvailableVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Find an available voice and return the voice number if available.
- *
- * Inputs:
- * pnVoiceNumber - really an output, returns the voice number found
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * success - if there is an available voice
- * failure - otherwise
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice)
-{
- EAS_INT voiceNum;
-
- /* Check each voice to see if it has been assigned to a synth channel */
- for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++)
- {
- /* check if this voice has been assigned to a synth channel */
- if ( pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateFree)
- {
- *pVoiceNumber = voiceNum; /* this voice is available */
- return EAS_SUCCESS;
- }
- }
-
- /* if we reach here, we have not found a free voice */
- *pVoiceNumber = UNASSIGNED_SYNTH_VOICE;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFindAvailableVoice: error, could not find an available voice\n"); */ }
-#endif
- return EAS_FAILURE;
-}
-
-/*----------------------------------------------------------------------------
- * VMStealVoice()
- *----------------------------------------------------------------------------
- * Purpose:
- * Steal a voice and return the voice number
- *
- * Stealing algorithm: steal the best choice with minimal work, taking into
- * account SP-Midi channel priorities and polyphony allocation.
- *
- * In one pass through all the voices, figure out which voice to steal
- * taking into account a number of different factors:
- * Priority of the voice's MIDI channel
- * Number of voices over the polyphony allocation for voice's MIDI channel
- * Amplitude of the voice
- * Note age
- * Key velocity (for voices that haven't been started yet)
- * If any matching notes are found
- *
- * Inputs:
- * pnVoiceNumber - really an output, see below
- * nChannel - the channel that this voice wants to be started on
- * nKeyNumber - the key number for this new voice
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pnVoiceNumber - voice number of the voice that was stolen
- * EAS_RESULT EAS_SUCCESS - always successful
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice)
-{
- S_SYNTH_VOICE *pCurrVoice;
- S_SYNTH *pCurrSynth;
- EAS_INT voiceNum;
- EAS_INT bestCandidate;
- EAS_U8 currChannel;
- EAS_U8 currNote;
- EAS_I32 bestPriority;
- EAS_I32 currentPriority;
-
- /* determine which voice to steal */
- bestPriority = 0;
- bestCandidate = MAX_SYNTH_VOICES;
-
- for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++)
- {
- pCurrVoice = &pVoiceMgr->voices[voiceNum];
-
- /* ignore free voices */
- if (pCurrVoice->voiceState == eVoiceStateFree)
- continue;
-
- /* for stolen voices, use the new parameters, not the old */
- if (pCurrVoice->voiceState == eVoiceStateStolen)
- {
- pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->nextChannel)];
- currChannel = pCurrVoice->nextChannel;
- currNote = pCurrVoice->nextNote;
- }
- else
- {
- pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->channel)];
- currChannel = pCurrVoice->channel;
- currNote = pCurrVoice->note;
- }
-
- /* ignore voices that are higher priority */
- if (pSynth->priority > pCurrSynth->priority)
- continue;
-#ifdef _DEBUG_VM
-// { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: New priority = %d exceeds old priority = %d\n", pSynth->priority, pCurrSynth->priority); */ }
-#endif
-
- /* if voice is stolen or just started, reduce the likelihood it will be stolen */
- if (( pCurrVoice->voiceState == eVoiceStateStolen) || (pCurrVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET))
- {
- currentPriority = 128 - pCurrVoice->nextVelocity;
- }
- else
- {
- /* compute the priority of this voice, higher means better for stealing */
- /* use not age */
- currentPriority = (EAS_I32) pCurrVoice->age << NOTE_AGE_STEAL_WEIGHT;
-
- /* include note gain -higher gain is lower steal value */
- /*lint -e{704} use shift for performance */
- currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) -
- ((EAS_I32) pCurrVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT));
- }
-
- /* in SP-MIDI mode, include over poly allocation and channel priority */
- if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON)
- {
- S_SYNTH_CHANNEL *pChannel = &pCurrSynth->channels[GET_CHANNEL(currChannel)];
- /*lint -e{701} use shift for performance */
- if (pSynth->poolCount[pChannel->pool] >= pSynth->poolAlloc[pChannel->pool])
- currentPriority += (pSynth->poolCount[pChannel->pool] -pSynth->poolAlloc[pChannel->pool] + 1) << CHANNEL_POLY_STEAL_WEIGHT;
-
- /* include channel priority */
- currentPriority += (EAS_I32)(pChannel->pool << CHANNEL_PRIORITY_STEAL_WEIGHT);
- }
-
- /* if a note is already playing that matches this note, consider stealing it more readily */
- if ((note == currNote) && (channel == currChannel))
- currentPriority += NOTE_MATCH_PENALTY;
-
- /* is this the best choice so far? */
- if (currentPriority >= bestPriority)
- {
- bestPriority = currentPriority;
- bestCandidate = voiceNum;
- }
- }
-
- /* may happen if all voices are allocated to a higher priority virtual synth */
- if (bestCandidate == MAX_SYNTH_VOICES)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Unable to allocate a voice\n"); */ }
- return EAS_ERROR_NO_VOICE_ALLOCATED;
- }
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Voice %d stolen\n", bestCandidate); */ }
-
- /* are we stealing a stolen voice? */
- if (pVoiceMgr->voices[bestCandidate].voiceState == eVoiceStateStolen)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMStealVoice: Voice %d is already marked as stolen and was scheduled to play ch: %d note: %d vel: %d\n",
- bestCandidate,
- pVoiceMgr->voices[bestCandidate].nextChannel,
- pVoiceMgr->voices[bestCandidate].nextNote,
- pVoiceMgr->voices[bestCandidate].nextVelocity); */ }
- }
-#endif
-
- *pVoiceNumber = (EAS_U16) bestCandidate;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMChannelPressure()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the channel pressure for the given channel
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nVelocity - the channel pressure value
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * psSynthObject->m_sChannel[nChannel].m_nChannelPressure is updated
- *----------------------------------------------------------------------------
-*/
-void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value)
-{
- S_SYNTH_CHANNEL *pChannel;
-
- pChannel = &(pSynth->channels[channel]);
- pChannel->channelPressure = value;
-
- /*
- set a channel flag to request parameter updates
- for all the voices associated with this channel
- */
- pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
-}
-
-/*----------------------------------------------------------------------------
- * VMPitchBend()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the pitch wheel value for the given channel.
- * This routine constructs the proper 14-bit argument when the calling routine
- * passes the pitch LSB and MSB.
- *
- * Note: some midi disassemblers display a bipolar pitch bend value.
- * We can display the bipolar value using
- * if m_nPitchBend >= 0x2000
- * bipolar pitch bend = postive (m_nPitchBend - 0x2000)
- * else
- * bipolar pitch bend = negative (0x2000 - m_nPitchBend)
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nPitchLSB - the LSB byte of the pitch bend message
- * nPitchMSB - the MSB byte of the pitch bend message
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- * Side Effects:
- * psSynthObject->m_sChannel[nChannel].m_nPitchBend is changed
- *
- *----------------------------------------------------------------------------
-*/
-void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 nPitchLSB, EAS_U8 nPitchMSB)
-{
- S_SYNTH_CHANNEL *pChannel;
-
- pChannel = &(pSynth->channels[channel]);
- pChannel->pitchBend = (EAS_I16) ((nPitchMSB << 7) | nPitchLSB);
-
- /*
- set a channel flag to request parameter updates
- for all the voices associated with this channel
- */
- pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
-}
-
-/*----------------------------------------------------------------------------
- * VMControlChange()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the controller (or mode) for the given channel.
- *
- * Inputs:
- * nChannel - the MIDI channel
- * nControllerNumber - the MIDI controller number
- * nControlValue - the value for this controller message
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * Side Effects:
- * psSynthObject->m_sChannel[nChannel] controller is changed
- *
- *----------------------------------------------------------------------------
-*/
-void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value)
-{
- S_SYNTH_CHANNEL *pChannel;
-
- pChannel = &(pSynth->channels[channel]);
-
- /*
- set a channel flag to request parameter updates
- for all the voices associated with this channel
- */
- pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
-
- switch ( controller )
- {
- case MIDI_CONTROLLER_BANK_SELECT_MSB:
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select MSB: msb 0x%X\n", value); */ }
-#endif
- /* use this MSB with a zero LSB, until we get an LSB message */
- pChannel->bankNum = value << 8;
- break;
-
- case MIDI_CONTROLLER_MOD_WHEEL:
- /* we treat mod wheel as a 7-bit controller and only use the MSB */
- pChannel->modWheel = value;
- break;
-
- case MIDI_CONTROLLER_VOLUME:
- /* we treat volume as a 7-bit controller and only use the MSB */
- pChannel->volume = value;
- break;
-
- case MIDI_CONTROLLER_PAN:
- /* we treat pan as a 7-bit controller and only use the MSB */
- pChannel->pan = value;
- break;
-
- case MIDI_CONTROLLER_EXPRESSION:
- /* we treat expression as a 7-bit controller and only use the MSB */
- pChannel->expression = value;
- break;
-
- case MIDI_CONTROLLER_BANK_SELECT_LSB:
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select LSB: lsb 0x%X\n", value); */ }
-#endif
- /*
- construct bank number as 7-bits (stored as 8) of existing MSB
- and 7-bits of new LSB (also stored as 8(
- */
- pChannel->bankNum =
- (pChannel->bankNum & 0xFF00) | value;
-
- break;
-
- case MIDI_CONTROLLER_SUSTAIN_PEDAL:
- /* we treat sustain pedal as a boolean on/off bit flag */
- if (value < 64)
- {
- /*
- we are requested to turn the pedal off, but first check
- if the pedal is already on
- */
- if (0 !=
- (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
- )
- {
- /*
- The sustain flag is presently set and the damper pedal is on.
- We are therefore transitioning from damper pedal ON to
- damper pedal OFF. This means all notes in this channel
- that received a note off while the damper pedal was on, and
- had their note-off requests deferred, should now proceed to
- the release state.
- */
- VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, channel);
- } /* end if sustain pedal is already on */
-
- /* turn the sustain pedal off */
- pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL;
- }
- else
- {
- /*
- we are requested to turn the pedal on, but first check
- if the pedal is already off
- */
- if (0 ==
- (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
- )
- {
- /*
- The sustain flag is presently clear and the damper pedal is off.
- We are therefore transitioning from damper pedal OFF to
- damper pedal ON. Currently sounding notes should be left
- unchanged. However, we should try to "catch" notes if possible.
- If any notes have levels >= sustain level, catch them,
- otherwise, let them continue to release.
- */
- VMCatchNotesForSustainPedal(pVoiceMgr, pSynth, channel);
- }
-
- /* turn the sustain pedal on */
- pChannel->channelFlags |= CHANNEL_FLAG_SUSTAIN_PEDAL;
- }
-
- break;
-#ifdef _REVERB
- case MIDI_CONTROLLER_REVERB_SEND:
- /* we treat send as a 7-bit controller and only use the MSB */
- pSynth->channels[channel].reverbSend = value;
- break;
-#endif
-#ifdef _CHORUS
- case MIDI_CONTROLLER_CHORUS_SEND:
- /* we treat send as a 7-bit controller and only use the MSB */
- pSynth->channels[channel].chorusSend = value;
- break;
-#endif
- case MIDI_CONTROLLER_RESET_CONTROLLERS:
- /* despite the Midi message name, not ALL controllers are reset */
- pChannel->modWheel = DEFAULT_MOD_WHEEL;
- pChannel->expression = DEFAULT_EXPRESSION;
-
- /* turn the sustain pedal off as default/reset */
- pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL;
- pChannel->pitchBend = DEFAULT_PITCH_BEND;
-
- /* reset channel pressure */
- pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE;
-
- /* reset RPN values */
- pChannel->registeredParam = DEFAULT_REGISTERED_PARAM;
- pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY;
- pChannel->finePitch = DEFAULT_FINE_PITCH;
- pChannel->coarsePitch = DEFAULT_COARSE_PITCH;
-
- /*
- program change, bank select, channel volume CC7, pan CC10
- are NOT reset
- */
- break;
-
- /*
- For logical reasons, the RPN data entry are grouped together.
- However, keep in mind that these cases are not necessarily in
- ascending order.
- e.g., MIDI_CONTROLLER_DATA_ENTRY_MSB == 6,
- whereas MIDI_CONTROLLER_SUSTAIN_PEDAL == 64.
- So arrange these case statements in whatever manner is more efficient for
- the processor / compiler.
- */
- case MIDI_CONTROLLER_ENTER_DATA_MSB:
- case MIDI_CONTROLLER_ENTER_DATA_LSB:
- case MIDI_CONTROLLER_SELECT_RPN_LSB:
- case MIDI_CONTROLLER_SELECT_RPN_MSB:
- case MIDI_CONTROLLER_SELECT_NRPN_MSB:
- case MIDI_CONTROLLER_SELECT_NRPN_LSB:
- VMUpdateRPNStateMachine(pSynth, channel, controller, value);
- break;
-
- case MIDI_CONTROLLER_ALL_SOUND_OFF:
- case MIDI_CONTROLLER_ALL_NOTES_OFF:
- case MIDI_CONTROLLER_OMNI_OFF:
- case MIDI_CONTROLLER_OMNI_ON:
- case MIDI_CONTROLLER_MONO_ON_POLY_OFF:
- case MIDI_CONTROLLER_POLY_ON_MONO_OFF:
- /* NOTE: we treat all sounds off the same as all notes off */
- VMAllNotesOff(pVoiceMgr, pSynth, channel);
- break;
-
- default:
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: controller %d not yet implemented\n", controller); */ }
-#endif
- break;
-
- }
-
- return;
-}
-
-/*----------------------------------------------------------------------------
- * VMUpdateRPNStateMachine()
- *----------------------------------------------------------------------------
- * Purpose:
- * Call this function when we want to parse RPN related controller messages.
- * We only support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and
- * RPN2 (coarse tuning). Any other RPNs or NRPNs are ignored for now.
- *.
- * Supports any order, so not a state machine anymore. This function was
- * rewritten to work correctly regardless of order.
- *
- * Inputs:
- * nChannel - the channel this controller message is coming from
- * nControllerNumber - which RPN related controller
- * nControlValue - the value of the RPN related controller
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * returns EAS_RESULT, which is typically EAS_SUCCESS, since there are
- * few possible errors
- *
- * Side Effects:
- * gsSynthObject.m_sChannel[nChannel].m_nPitchBendSensitivity
- * (or m_nFinePitch or m_nCoarsePitch)
- * will be updated if the proper RPN message is received.
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value)
-{
- S_SYNTH_CHANNEL *pChannel;
-
-#ifdef _DEBUG_VM
- if (channel >= NUM_SYNTH_CHANNELS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateRPNStateMachines: error, %d invalid channel number\n",
- channel); */ }
- return EAS_FAILURE;
- }
-#endif
-
- pChannel = &(pSynth->channels[channel]);
-
- switch (controller)
- {
- case MIDI_CONTROLLER_SELECT_NRPN_MSB:
- case MIDI_CONTROLLER_SELECT_NRPN_LSB:
- pChannel->registeredParam = DEFAULT_REGISTERED_PARAM;
- break;
- case MIDI_CONTROLLER_SELECT_RPN_MSB:
- pChannel->registeredParam =
- (pChannel->registeredParam & 0x7F) | (value<<7);
- break;
- case MIDI_CONTROLLER_SELECT_RPN_LSB:
- pChannel->registeredParam =
- (pChannel->registeredParam & 0x7F00) | value;
- break;
- case MIDI_CONTROLLER_ENTER_DATA_MSB:
- switch (pChannel->registeredParam)
- {
- case 0:
- pChannel->pitchBendSensitivity = value * 100;
- break;
- case 1:
- /*lint -e{702} <avoid division for performance reasons>*/
- pChannel->finePitch = (EAS_I8)((((value << 7) - 8192) * 100) >> 13);
- break;
- case 2:
- pChannel->coarsePitch = (EAS_I8)(value - 64);
- break;
- default:
- break;
- }
- break;
- case MIDI_CONTROLLER_ENTER_DATA_LSB:
- switch (pChannel->registeredParam)
- {
- case 0:
- //ignore lsb
- break;
- case 1:
- //ignore lsb
- break;
- case 2:
- //ignore lsb
- break;
- default:
- break;
- }
- break;
- default:
- return EAS_FAILURE; //not a RPN related controller
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMUpdateStaticChannelParameters()
- *----------------------------------------------------------------------------
- * Purpose:
- * Update all of the static channel parameters for channels that have had
- * a controller change values
- * Or if the synth has signalled that all channels must forcibly
- * be updated
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * none
- *
- * Side Effects:
- * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch
- * are updated for channels whose controller values have changed
- * or if the synth has signalled that all channels must forcibly
- * be updated
- *----------------------------------------------------------------------------
-*/
-void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
-{
- EAS_INT channel;
-
- if (pSynth->synthFlags & SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS)
- {
- /*
- the synth wants us to forcibly update all channel
- parameters. This event occurs when we are about to
- finish resetting the synth
- */
- for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++)
- {
-#ifdef _HYBRID_SYNTH
- if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH)
- pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
- else
- pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
-#else
- pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
-#endif
- }
-
- /*
- clear the flag to indicates we have now forcibly
- updated all channel parameters
- */
- pSynth->synthFlags &= ~SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS;
- }
- else
- {
-
- /* only update channel params if signalled by a channel flag */
- for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++)
- {
- if ( 0 != (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS))
- {
-#ifdef _HYBRID_SYNTH
- if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH)
- pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
- else
- pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
-#else
- pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
-#endif
- }
- }
-
- }
-
- return;
-}
-
-/*----------------------------------------------------------------------------
- * VMFindProgram()
- *----------------------------------------------------------------------------
- * Purpose:
- * Look up an individual program in sound library. This function
- * searches the bank list for a program, then the individual program
- * list.
- *
- * Inputs:
- *
- * Outputs:
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT VMFindProgram (const S_EAS *pEAS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex)
-{
- EAS_U32 locale;
- const S_PROGRAM *p;
- EAS_U16 i;
- EAS_U16 regionIndex;
-
- /* make sure we have a valid sound library */
- if (pEAS == NULL)
- return EAS_FAILURE;
-
- /* search the banks */
- for (i = 0; i < pEAS->numBanks; i++)
- {
- if (bank == (EAS_U32) pEAS->pBanks[i].locale)
- {
- regionIndex = pEAS->pBanks[i].regionIndex[programNum];
- if (regionIndex != INVALID_REGION_INDEX)
- {
- *pRegionIndex = regionIndex;
- return EAS_SUCCESS;
- }
- break;
- }
- }
-
- /* establish locale */
- locale = ( bank << 8) | programNum;
-
- /* search for program */
- for (i = 0, p = pEAS->pPrograms; i < pEAS->numPrograms; i++, p++)
- {
- if (p->locale == locale)
- {
- *pRegionIndex = p->regionIndex;
- return EAS_SUCCESS;
- }
- }
-
- return EAS_FAILURE;
-}
-
-#ifdef DLS_SYNTHESIZER
-/*----------------------------------------------------------------------------
- * VMFindDLSProgram()
- *----------------------------------------------------------------------------
- * Purpose:
- * Look up an individual program in sound library. This function
- * searches the bank list for a program, then the individual program
- * list.
- *
- * Inputs:
- *
- * Outputs:
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT VMFindDLSProgram (const S_DLS *pDLS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex)
-{
- EAS_U32 locale;
- const S_PROGRAM *p;
- EAS_U16 i;
-
- /* make sure we have a valid sound library */
- if (pDLS == NULL)
- return EAS_FAILURE;
-
- /* establish locale */
- locale = (bank << 8) | programNum;
-
- /* search for program */
- for (i = 0, p = pDLS->pDLSPrograms; i < pDLS->numDLSPrograms; i++, p++)
- {
- if (p->locale == locale)
- {
- *pRegionIndex = p->regionIndex;
- return EAS_SUCCESS;
- }
- }
-
- return EAS_FAILURE;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * VMProgramChange()
- *----------------------------------------------------------------------------
- * Purpose:
- * Change the instrument (program) for the given channel.
- *
- * Depending on the program number, and the bank selected for this channel, the
- * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or
- * Alternate wavetable (from mobile DLS or other DLS file)
- *
- * This function figures out what wavetable should be used, and sets it up as the
- * wavetable to use for this channel. Also the channel may switch from a melodic
- * channel to a rhythm channel, or vice versa.
- *
- * Inputs:
- *
- * Outputs:
- * Side Effects:
- * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed
- * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed
- * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pVoiceMgr) reserved for future use */
-void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program)
-{
- S_SYNTH_CHANNEL *pChannel;
- EAS_U32 bank;
- EAS_U16 regionIndex;
-
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMProgramChange: vSynthNum=%d, channel=%d, program=%d\n", pSynth->vSynthNum, channel, program); */ }
-#endif
-
- /* setup pointer to MIDI channel data */
- pChannel = &pSynth->channels[channel];
- bank = pChannel->bankNum;
-
- /* allow channels to switch between being melodic or rhythm channels, using GM2 CC values */
- if ((bank & 0xFF00) == DEFAULT_RHYTHM_BANK_NUMBER)
- {
- /* make it a rhythm channel */
- pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL;
- }
- else if ((bank & 0xFF00) == DEFAULT_MELODY_BANK_NUMBER)
- {
- /* make it a melody channel */
- pChannel->channelFlags &= ~CHANNEL_FLAG_RHYTHM_CHANNEL;
- }
-
- regionIndex = DEFAULT_REGION_INDEX;
-
-#ifdef EXTERNAL_AUDIO
- /* give the external audio interface a chance to handle it */
- if (pSynth->cbProgChgFunc != NULL)
- {
- S_EXT_AUDIO_PRG_CHG prgChg;
- prgChg.channel = channel;
- prgChg.bank = (EAS_U16) bank;
- prgChg.program = program;
- if (pSynth->cbProgChgFunc(pSynth->pExtAudioInstData, &prgChg))
- pChannel->channelFlags |= CHANNEL_FLAG_EXTERNAL_AUDIO;
- }
-
-#endif
-
-
-#ifdef DLS_SYNTHESIZER
- /* first check for DLS program that may overlay the internal instrument */
- if (VMFindDLSProgram(pSynth->pDLS, bank, program, ®ionIndex) != EAS_SUCCESS)
-#endif
-
- /* braces to support 'if' clause above */
- {
-
- /* look in the internal banks */
- if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS)
-
- /* fall back to default bank */
- {
- if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)
- bank = DEFAULT_RHYTHM_BANK_NUMBER;
- else
- bank = DEFAULT_MELODY_BANK_NUMBER;
-
- if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS)
-
- /* switch to program 0 in the default bank */
- {
- if (VMFindProgram(pSynth->pEAS, bank, 0, ®ionIndex) != EAS_SUCCESS)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMProgramChange: No program @ %03d:%03d:%03d\n",
- (bank >> 8) & 0x7f, bank & 0x7f, program); */ }
- }
- }
- }
-
- /* we have our new program change for this channel */
- pChannel->programNum = program;
- pChannel->regionIndex = regionIndex;
-
- /*
- set a channel flag to request parameter updates
- for all the voices associated with this channel
- */
- pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
-
- return;
-}
-
-/*----------------------------------------------------------------------------
- * VMAddSamples()
- *----------------------------------------------------------------------------
- * Purpose:
- * Synthesize the requested number of samples (block based processing)
- *
- * Inputs:
- * nNumSamplesToAdd - number of samples to write to buffer
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * number of voices rendered
- *
- * Side Effects:
- * - samples are added to the presently free buffer
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamples)
-{
- S_SYNTH *pSynth;
- EAS_INT voicesRendered;
- EAS_INT voiceNum;
- EAS_BOOL done;
-
-#ifdef _REVERB
- EAS_PCM *pReverbSendBuffer;
-#endif // ifdef _REVERB
-
-#ifdef _CHORUS
- EAS_PCM *pChorusSendBuffer;
-#endif // ifdef _CHORUS
-
- voicesRendered = 0;
- for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
- {
-
- /* retarget stolen voices */
- if ((pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) && (pVoiceMgr->voices[voiceNum].gain <= 0))
- VMRetargetStolenVoice(pVoiceMgr, voiceNum);
-
- /* get pointer to virtual synth */
- pSynth = pVoiceMgr->pSynth[pVoiceMgr->voices[voiceNum].channel >> 4];
-
- /* synthesize active voices */
- if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateFree)
- {
- done = GetSynthPtr(voiceNum)->pfUpdateVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pMixBuffer, numSamples);
- voicesRendered++;
-
- /* voice is finished */
- if (done == EAS_TRUE)
- {
- /* set gain of stolen voice to zero so it will be restarted */
- if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen)
- pVoiceMgr->voices[voiceNum].gain = 0;
-
- /* or return it to the free voice pool */
- else
- VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]);
- }
-
- /* if this voice is scheduled to be muted, set the mute flag */
- if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MUTE)
- {
- pVoiceMgr->voices[voiceNum].voiceFlags &= ~(VOICE_FLAG_DEFER_MUTE | VOICE_FLAG_DEFER_MIDI_NOTE_OFF);
- VMMuteVoice(pVoiceMgr, voiceNum);
- }
-
- /* if voice just started, advance state to play */
- if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStart)
- pVoiceMgr->voices[voiceNum].voiceState = eVoiceStatePlay;
- }
- }
-
- return voicesRendered;
-}
-
-/*----------------------------------------------------------------------------
- * VMRender()
- *----------------------------------------------------------------------------
- * Purpose:
- * This routine renders a frame of audio
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * pVoicesRendered - number of voices rendered this frame
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered)
-{
- S_SYNTH *pSynth;
- EAS_INT i;
- EAS_INT channel;
-
-#ifdef _CHECKED_BUILD
- SanityCheck(pVoiceMgr);
-#endif
-
- /* update MIDI channel parameters */
- *pVoicesRendered = 0;
- for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
- {
- if (pVoiceMgr->pSynth[i] != NULL)
- VMUpdateStaticChannelParameters(pVoiceMgr, pVoiceMgr->pSynth[i]);
- }
-
- /* synthesize a buffer of audio */
- *pVoicesRendered = VMAddSamples(pVoiceMgr, pMixBuffer, numSamples);
-
- /*
- * check for deferred note-off messages
- * If flag is set, that means one or more voices are expecting deferred
- * midi note-off messages because the midi note-on and corresponding midi
- * note-off requests occurred during the same update interval. The goal
- * is the defer the note-off request so that the note can at least start.
- */
- for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
- {
- pSynth = pVoiceMgr->pSynth[i];
-
- if (pSynth== NULL)
- continue;
-
- if (pSynth->synthFlags & SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING)
- VMDeferredStopNote(pVoiceMgr, pSynth);
-
- /* check if we need to reset the synth */
- if ((pSynth->synthFlags & SYNTH_FLAG_RESET_IS_REQUESTED) &&
- (pSynth->numActiveVoices == 0))
- {
- /*
- complete the process of resetting the synth now that
- all voices have muted
- */
-#ifdef _DEBUG_VM
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAddSamples: complete the reset process\n"); */ }
-#endif
-
- VMInitializeAllChannels(pVoiceMgr, pSynth);
- VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum);
-
- /* clear the reset flag */
- pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED;
- }
-
- /* clear channel update flags */
- for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++)
- pSynth->channels[channel].channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
-
- }
-
-#ifdef _CHECKED_BUILD
- SanityCheck(pVoiceMgr);
-#endif
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMInitWorkload()
- *----------------------------------------------------------------------------
- * Purpose:
- * Clears the workload counter
- *
- * Inputs:
- * pVoiceMgr - pointer to instance data
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMInitWorkload (S_VOICE_MGR *pVoiceMgr)
-{
- pVoiceMgr->workload = 0;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetWorkload()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the max workload for a single frame.
- *
- * Inputs:
- * pVoiceMgr - pointer to instance data
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad)
-{
- pVoiceMgr->maxWorkLoad = maxWorkLoad;
-}
-
-/*----------------------------------------------------------------------------
- * VMCheckWorkload()
- *----------------------------------------------------------------------------
- * Purpose:
- * Checks to see if work load has been exceeded on this frame.
- *
- * Inputs:
- * pVoiceMgr - pointer to instance data
- *
- * Outputs:
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr)
-{
- if (pVoiceMgr->maxWorkLoad > 0)
- return (EAS_BOOL) (pVoiceMgr->workload >= pVoiceMgr->maxWorkLoad);
- return EAS_FALSE;
-}
-
-/*----------------------------------------------------------------------------
- * VMActiveVoices()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the number of active voices in the synthesizer.
- *
- * Inputs:
- * pEASData - pointer to instance data
- *
- * Outputs:
- * Returns the number of active voices
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_I32 VMActiveVoices (S_SYNTH *pSynth)
-{
- return pSynth->numActiveVoices;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the synth to a new polyphony value. Value must be >= 1 and
- * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * polyphonyCount desired polyphony count
- * synth synthesizer number (0 = onboard, 1 = DSP)
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount)
-{
- EAS_INT i;
- EAS_INT activeVoices;
-
- /* lower limit */
- if (polyphonyCount < 1)
- polyphonyCount = 1;
-
- /* split architecture */
-#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
- if (synth == EAS_MCU_SYNTH)
- {
- if (polyphonyCount > NUM_PRIMARY_VOICES)
- polyphonyCount = NUM_PRIMARY_VOICES;
- if (pVoiceMgr->maxPolyphonyPrimary == polyphonyCount)
- return EAS_SUCCESS;
- pVoiceMgr->maxPolyphonyPrimary = (EAS_U16) polyphonyCount;
- }
- else if (synth == EAS_DSP_SYNTH)
- {
- if (polyphonyCount > NUM_SECONDARY_VOICES)
- polyphonyCount = NUM_SECONDARY_VOICES;
- if (pVoiceMgr->maxPolyphonySecondary == polyphonyCount)
- return EAS_SUCCESS;
- pVoiceMgr->maxPolyphonySecondary = (EAS_U16) polyphonyCount;
- }
- else
- return EAS_ERROR_PARAMETER_RANGE;
-
- /* setting for SP-MIDI */
- pVoiceMgr->maxPolyphony = pVoiceMgr->maxPolyphonyPrimary + pVoiceMgr->maxPolyphonySecondary;
-
- /* standard architecture */
-#else
- if (synth != EAS_MCU_SYNTH)
- return EAS_ERROR_PARAMETER_RANGE;
-
- /* pin desired value to possible limits */
- if (polyphonyCount > MAX_SYNTH_VOICES)
- polyphonyCount = MAX_SYNTH_VOICES;
-
- /* set polyphony, if value is different than current value */
- if (pVoiceMgr->maxPolyphony == polyphonyCount)
- return EAS_SUCCESS;
-
- pVoiceMgr->maxPolyphony = (EAS_U16) polyphonyCount;
-#endif
-
- /* if SPMIDI enabled, update channel masking based on new polyphony */
- for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
- {
- if (pVoiceMgr->pSynth[i])
- {
- if (pVoiceMgr->pSynth[i]->synthFlags & SYNTH_FLAG_SP_MIDI_ON)
- VMMIPUpdateChannelMuting(pVoiceMgr, pVoiceMgr->pSynth[i]);
- else
- pVoiceMgr->pSynth[i]->poolAlloc[0] = (EAS_U8) polyphonyCount;
- }
- }
-
- /* are we under polyphony limit? */
- if (pVoiceMgr->activeVoices <= polyphonyCount)
- return EAS_SUCCESS;
-
- /* count the number of active voices */
- activeVoices = 0;
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
-
- /* is voice active? */
- if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting))
- activeVoices++;
- }
-
- /* we may have to mute voices to reach new target */
- while (activeVoices > polyphonyCount)
- {
- S_SYNTH *pSynth;
- S_SYNTH_VOICE *pVoice;
- EAS_I32 currentPriority, bestPriority;
- EAS_INT bestCandidate;
-
- /* find the lowest priority voice */
- bestPriority = bestCandidate = -1;
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
-
- pVoice = &pVoiceMgr->voices[i];
-
- /* ignore free and muting voices */
- if ((pVoice->voiceState == eVoiceStateFree) || (pVoice->voiceState == eVoiceStateMuting))
- continue;
-
- pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
-
- /* if voice is stolen or just started, reduce the likelihood it will be stolen */
- if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET))
- {
- /* include velocity */
- currentPriority = 128 - pVoice->nextVelocity;
-
- /* include channel priority */
- currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
- }
- else
- {
- /* include age */
- currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT;
-
- /* include note gain -higher gain is lower steal value */
- /*lint -e{704} use shift for performance */
- currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) -
- ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT));
-
- /* include channel priority */
- currentPriority += pSynth->channels[GET_CHANNEL(pVoice->channel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
- }
-
- /* include synth priority */
- currentPriority += pSynth->priority << SYNTH_PRIORITY_WEIGHT;
-
- /* is this the best choice so far? */
- if (currentPriority > bestPriority)
- {
- bestPriority = currentPriority;
- bestCandidate = i;
- }
- }
-
- /* shutdown best candidate */
- if (bestCandidate < 0)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ }
- break;
- }
-
- /* shut down this voice */
- /*lint -e{771} pSynth is initialized if bestCandidate >= 0 */
- VMMuteVoice(pVoiceMgr, bestCandidate);
- activeVoices--;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMGetSynthPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current polyphony setting
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * synth synthesizer number (0 = onboard, 1 = DSP)
- *
- * Outputs:
- * Returns actual polyphony value set, as pinned by limits
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount)
-{
-
-#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
- if (synth == EAS_MCU_SYNTH)
- *pPolyphonyCount = pVoiceMgr->maxPolyphonyPrimary;
- else if (synth == EAS_DSP_SYNTH)
- *pPolyphonyCount = pVoiceMgr->maxPolyphonySecondary;
- else
- return EAS_ERROR_PARAMETER_RANGE;
-#else
- if (synth != EAS_MCU_SYNTH)
- return EAS_ERROR_PARAMETER_RANGE;
- *pPolyphonyCount = pVoiceMgr->maxPolyphony;
-#endif
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the virtual synth polyphony. 0 = no limit (i.e. can use
- * all available voices).
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * polyphonyCount desired polyphony count
- * pSynth pointer to virtual synth
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount)
-{
- EAS_INT i;
- EAS_INT activeVoices;
-
- /* check limits */
- if (polyphonyCount < 0)
- return EAS_ERROR_PARAMETER_RANGE;
-
- /* zero is max polyphony */
- if ((polyphonyCount == 0) || (polyphonyCount > MAX_SYNTH_VOICES))
- {
- pSynth->maxPolyphony = 0;
- return EAS_SUCCESS;
- }
-
- /* set new polyphony */
- pSynth->maxPolyphony = (EAS_U16) polyphonyCount;
-
- /* max polyphony is minimum of virtual synth and actual synth */
- if (polyphonyCount > pVoiceMgr->maxPolyphony)
- polyphonyCount = pVoiceMgr->maxPolyphony;
-
- /* if SP-MIDI mode, update the channel muting */
- if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON)
- VMMIPUpdateChannelMuting(pVoiceMgr, pSynth);
- else
- pSynth->poolAlloc[0] = (EAS_U8) polyphonyCount;
-
- /* are we under polyphony limit? */
- if (pSynth->numActiveVoices <= polyphonyCount)
- return EAS_SUCCESS;
-
- /* count the number of active voices */
- activeVoices = 0;
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
- /* this synth? */
- if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) != pSynth->vSynthNum)
- continue;
-
- /* is voice active? */
- if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting))
- activeVoices++;
- }
-
- /* we may have to mute voices to reach new target */
- while (activeVoices > polyphonyCount)
- {
- S_SYNTH_VOICE *pVoice;
- EAS_I32 currentPriority, bestPriority;
- EAS_INT bestCandidate;
-
- /* find the lowest priority voice */
- bestPriority = bestCandidate = -1;
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
- pVoice = &pVoiceMgr->voices[i];
-
- /* this synth? */
- if (GET_VSYNTH(pVoice->nextChannel) != pSynth->vSynthNum)
- continue;
-
- /* if voice is stolen or just started, reduce the likelihood it will be stolen */
- if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET))
- {
- /* include velocity */
- currentPriority = 128 - pVoice->nextVelocity;
-
- /* include channel priority */
- currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
- }
- else
- {
- /* include age */
- currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT;
-
- /* include note gain -higher gain is lower steal value */
- /*lint -e{704} use shift for performance */
- currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) -
- ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT));
-
- /* include channel priority */
- currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
- }
-
- /* is this the best choice so far? */
- if (currentPriority > bestPriority)
- {
- bestPriority = currentPriority;
- bestCandidate = i;
- }
- }
-
- /* shutdown best candidate */
- if (bestCandidate < 0)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ }
- break;
- }
-
- /* shut down this voice */
- VMMuteVoice(pVoiceMgr, bestCandidate);
- activeVoices--;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMGetPolyphony()
- *----------------------------------------------------------------------------
- * Purpose:
- * Get the virtual synth polyphony
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * pPolyphonyCount pointer to variable to hold polyphony count
- * pSynth pointer to virtual synth
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pVoiceMgr) reserved for future use */
-EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount)
-{
- *pPolyphonyCount = (EAS_U16) pSynth->maxPolyphony;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the virtual synth priority
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * priority new priority
- * pSynth pointer to virtual synth
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pVoiceMgr) reserved for future use */
-EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority)
-{
- pSynth->priority = (EAS_U8) priority ;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMGetPriority()
- *----------------------------------------------------------------------------
- * Purpose:
- * Get the virtual synth priority
- *
- * Inputs:
- * pVoiceMgr pointer to synthesizer data
- * pPriority pointer to variable to hold priority
- * pSynth pointer to virtual synth
- *
- * Outputs:
- * Returns error code
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pVoiceMgr) reserved for future use */
-EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority)
-{
- *pPriority = pSynth->priority;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetVolume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Set the master volume for this synthesizer for this sequence.
- *
- * Inputs:
- * nSynthVolume - the desired master volume
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- * overrides any previously set master volume from sysex
- *
- *----------------------------------------------------------------------------
-*/
-void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume)
-{
- pSynth->masterVolume = masterVolume;
- pSynth->synthFlags |= SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetPitchBendRange()
- *----------------------------------------------------------------------------
- * Set the pitch bend range for the given channel.
- *----------------------------------------------------------------------------
-*/
-void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange)
-{
- pSynth->channels[channel].pitchBendSensitivity = pitchBendRange;
-}
-
-/*----------------------------------------------------------------------------
- * VMValidateEASLib()
- *----------------------------------------------------------------------------
- * Validates an EAS library
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMValidateEASLib (EAS_SNDLIB_HANDLE pEAS)
-{
- /* validate the sound library */
- if (pEAS)
- {
- if (pEAS->identifier != _EAS_LIBRARY_VERSION)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sound library mismatch in sound library: Read 0x%08x, expected 0x%08x\n",
- pEAS->identifier, _EAS_LIBRARY_VERSION); */ }
- return EAS_ERROR_SOUND_LIBRARY;
- }
-
- /* check sample rate */
- if ((pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK) != _OUTPUT_SAMPLE_RATE)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sample rate mismatch in sound library: Read %lu, expected %lu\n",
- pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ }
- return EAS_ERROR_SOUND_LIBRARY;
- }
-
-#ifdef _WT_SYNTH
- /* check sample bit depth */
-#ifdef _8_BIT_SAMPLES
- if (pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 8-bit samples and found 16-bit\n",
- pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ }
- return EAS_ERROR_SOUND_LIBRARY;
- }
-#endif
-#ifdef _16_BIT_SAMPLES
- if ((pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) == 0)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 16-bit samples and found 8-bit\n",
- pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ }
- return EAS_ERROR_SOUND_LIBRARY;
- }
-#endif
-#endif
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetGlobalEASLib()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the EAS library to be used by the synthesizer
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS)
-{
- EAS_RESULT result;
-
- result = VMValidateEASLib(pEAS);
- if (result != EAS_SUCCESS)
- return result;
-
- pVoiceMgr->pGlobalEAS = pEAS;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetEASLib()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the EAS library to be used by the synthesizer
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS)
-{
- EAS_RESULT result;
-
- result = VMValidateEASLib(pEAS);
- if (result != EAS_SUCCESS)
- return result;
-
- pSynth->pEAS = pEAS;
- return EAS_SUCCESS;
-}
-
-#ifdef DLS_SYNTHESIZER
-/*----------------------------------------------------------------------------
- * VMSetGlobalDLSLib()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the DLS library to be used by the synthesizer
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS)
-{
-
- if (pEASData->pVoiceMgr->pGlobalDLS)
- DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS);
-
- pEASData->pVoiceMgr->pGlobalDLS = pDLS;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * VMSetDLSLib()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the DLS library to be used by the synthesizer
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS)
-{
- pSynth->pDLS = pDLS;
- return EAS_SUCCESS;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * VMSetTranposition()
- *----------------------------------------------------------------------------
- * Purpose:
- * Sets the global key transposition used by the synthesizer.
- * Transposes all melodic instruments up or down by the specified
- * amount. Range is limited to +/-12 semitones.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition)
-{
- pSynth->globalTranspose = (EAS_I8) transposition;
-}
-
-/*----------------------------------------------------------------------------
- * VMGetTranposition()
- *----------------------------------------------------------------------------
- * Purpose:
- * Gets the global key transposition used by the synthesizer.
- * Transposes all melodic instruments up or down by the specified
- * amount. Range is limited to +/-12 semitones.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition)
-{
- *pTransposition = pSynth->globalTranspose;
-}
-
-/*----------------------------------------------------------------------------
- * VMGetNoteCount()
- *----------------------------------------------------------------------------
-* Returns the total note count
-*----------------------------------------------------------------------------
-*/
-EAS_I32 VMGetNoteCount (S_SYNTH *pSynth)
-{
- return pSynth->totalNoteCount;
-}
-
-/*----------------------------------------------------------------------------
- * VMMIDIShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Clean up any Synth related system issues.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * None
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth)
-{
- EAS_INT vSynthNum;
-
- /* decrement reference count, free if all references are gone */
- if (--pSynth->refCount > 0)
- return;
-
- vSynthNum = pSynth->vSynthNum;
-
- /* cleanup DLS load */
-#ifdef DLS_SYNTHESIZER
- /*lint -e{550} result used only in debugging code */
- if (pSynth->pDLS != NULL)
- {
- EAS_RESULT result;
- if ((result = DLSCleanup(pEASData->hwInstData, pSynth->pDLS)) != EAS_SUCCESS)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMMIDIShutdown: Error %ld cleaning up DLS collection\n", result); */ }
- pSynth->pDLS = NULL;
- }
-#endif
-
- VMReset(pEASData->pVoiceMgr, pSynth, EAS_TRUE);
-
- /* check Configuration Module for static memory allocation */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pSynth);
-
- /* clear pointer to MIDI state */
- pEASData->pVoiceMgr->pSynth[vSynthNum] = NULL;
-}
-
-/*----------------------------------------------------------------------------
- * VMShutdown()
- *----------------------------------------------------------------------------
- * Purpose:
- * Clean up any Synth related system issues.
- *
- * Inputs:
- * psEASData - pointer to overall EAS data structure
- *
- * Outputs:
- * None
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void VMShutdown (S_EAS_DATA *pEASData)
-{
-
- /* don't free a NULL pointer */
- if (pEASData->pVoiceMgr == NULL)
- return;
-
-#ifdef DLS_SYNTHESIZER
- /* if we have a global DLS collection, clean it up */
- if (pEASData->pVoiceMgr->pGlobalDLS)
- {
- DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS);
- pEASData->pVoiceMgr->pGlobalDLS = NULL;
- }
-#endif
-
- /* check Configuration Module for static memory allocation */
- if (!pEASData->staticMemoryModel)
- EAS_HWFree(pEASData->hwInstData, pEASData->pVoiceMgr);
- pEASData->pVoiceMgr = NULL;
-}
-
-#ifdef EXTERNAL_AUDIO
-/*----------------------------------------------------------------------------
- * EAS_RegExtAudioCallback()
- *----------------------------------------------------------------------------
- * Register a callback for external audio processing
- *----------------------------------------------------------------------------
-*/
-void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc)
-{
- pSynth->pExtAudioInstData = pInstData;
- pSynth->cbProgChgFunc = cbProgChgFunc;
- pSynth->cbEventFunc = cbEventFunc;
-}
-
-/*----------------------------------------------------------------------------
- * VMGetMIDIControllers()
- *----------------------------------------------------------------------------
- * Returns the MIDI controller values on the specified channel
- *----------------------------------------------------------------------------
-*/
-void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl)
-{
- pControl->modWheel = pSynth->channels[channel].modWheel;
- pControl->volume = pSynth->channels[channel].volume;
- pControl->pan = pSynth->channels[channel].pan;
- pControl->expression = pSynth->channels[channel].expression;
- pControl->channelPressure = pSynth->channels[channel].channelPressure;
-
-#ifdef _REVERB
- pControl->reverbSend = pSynth->channels[channel].reverbSend;
-#endif
-
-#ifdef _CHORUSE
- pControl->chorusSend = pSynth->channels[channel].chorusSend;
-#endif
-}
-#endif
-
-#ifdef _SPLIT_ARCHITECTURE
-/*----------------------------------------------------------------------------
- * VMStartFrame()
- *----------------------------------------------------------------------------
- * Purpose:
- * Starts an audio frame
- *
- * Inputs:
- *
- * Outputs:
- * Returns true if EAS_MixEnginePrep should be called (onboard mixing)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData)
-{
-
- /* init counter for voices starts in split architecture */
-#ifdef MAX_VOICE_STARTS
- pVoiceMgr->numVoiceStarts = 0;
-#endif
-
- return pFrameInterface->pfStartFrame(pEASData->pVoiceMgr->pFrameBuffer);
-}
-
-/*----------------------------------------------------------------------------
- * VMEndFrame()
- *----------------------------------------------------------------------------
- * Purpose:
- * Stops an audio frame
- *
- * Inputs:
- *
- * Outputs:
- * Returns true if EAS_MixEnginePost should be called (onboard mixing)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData)
-{
-
- return pFrameInterface->pfEndFrame(pEASData->pVoiceMgr->pFrameBuffer, pEASData->pMixBuffer, pEASData->masterGain);
-}
-#endif
-
-#ifdef TEST_HARNESS
-/*----------------------------------------------------------------------------
- * SanityCheck()
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT VMSanityCheck (EAS_DATA_HANDLE pEASData)
-{
- S_SYNTH_VOICE *pVoice;
- S_SYNTH *pSynth;
- EAS_INT i;
- EAS_INT j;
- EAS_INT freeVoices;
- EAS_INT activeVoices;
- EAS_INT playingVoices;
- EAS_INT stolenVoices;
- EAS_INT releasingVoices;
- EAS_INT mutingVoices;
- EAS_INT poolCount[MAX_VIRTUAL_SYNTHESIZERS][NUM_SYNTH_CHANNELS];
- EAS_INT vSynthNum;
- EAS_RESULT result = EAS_SUCCESS;
-
- /* initialize counts */
- EAS_HWMemSet(poolCount, 0, sizeof(poolCount));
- freeVoices = activeVoices = playingVoices = stolenVoices = releasingVoices = mutingVoices = 0;
-
- /* iterate through all voices */
- for (i = 0; i < MAX_SYNTH_VOICES; i++)
- {
- pVoice = &pEASData->pVoiceMgr->voices[i];
- if (pVoice->voiceState != eVoiceStateFree)
- {
- vSynthNum = GET_VSYNTH(pVoice->channel);
- if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ }
- result = EAS_FAILURE;
- continue;
- }
- pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum];
-
- switch (pVoice->voiceState)
- {
- case eVoiceStateMuting:
- activeVoices++;
- mutingVoices++;
- break;
-
- case eVoiceStateStolen:
- vSynthNum = GET_VSYNTH(pVoice->nextChannel);
- if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ }
- result = EAS_FAILURE;
- continue;
- }
- pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum];
- activeVoices++;
- stolenVoices++;
- poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool]++;
- break;
-
- case eVoiceStateStart:
- case eVoiceStatePlay:
- activeVoices++;
- playingVoices++;
- poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++;
- break;
-
- case eVoiceStateRelease:
- activeVoices++;
- releasingVoices++;
- poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++;
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck : voice %d in invalid state\n", i); */ }
- result = EAS_FAILURE;
- break;
- }
- }
-
- /* count free voices */
- else
- freeVoices++;
- }
-
- /* dump state info */
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d free\n", freeVoices); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d active\n", activeVoices); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d playing\n", playingVoices); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d releasing\n", releasingVoices); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d muting\n", mutingVoices); */ }
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d stolen\n", stolenVoices); */ }
-
- if (pEASData->pVoiceMgr->activeVoices != activeVoices)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Active voice mismatch was %d should be %d\n",
- pEASData->pVoiceMgr->activeVoices, activeVoices); */ }
- result = EAS_FAILURE;
- }
-
- /* check virtual synth status */
- for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
- {
- if (pEASData->pVoiceMgr->pSynth[i] == NULL)
- continue;
-
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Synth %d numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ }
- if (pEASData->pVoiceMgr->pSynth[i]->numActiveVoices > MAX_SYNTH_VOICES)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Synth %d illegal count for numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ }
- result = EAS_FAILURE;
- }
- for (j = 0; j < NUM_SYNTH_CHANNELS; j++)
- {
- if (poolCount[i][j] != pEASData->pVoiceMgr->pSynth[i]->poolCount[j])
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Pool count mismatch synth %d pool %d, was %d, should be %d\n",
- i, j, pEASData->pVoiceMgr->pSynth[i]->poolCount[j], poolCount[i][j]); */ }
- result = EAS_FAILURE;
- }
- }
- }
-
- return result;
-}
-#endif
-
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* includes */ +#include "eas.h" +#include "eas_data.h" +#include "eas_config.h" +#include "eas_report.h" +#include "eas_midictrl.h" +#include "eas_host.h" +#include "eas_synth_protos.h" +#include "eas_vm_protos.h" + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +// #define _DEBUG_VM + +/* some defines for workload */ +#define WORKLOAD_AMOUNT_SMALL_INCREMENT 5 +#define WORKLOAD_AMOUNT_START_NOTE 10 +#define WORKLOAD_AMOUNT_STOP_NOTE 10 +#define WORKLOAD_AMOUNT_KEY_GROUP 10 +#define WORKLOAD_AMOUNT_POLY_LIMIT 10 + +/* pointer to base sound library */ +extern S_EAS easSoundLib; + +#ifdef TEST_HARNESS +extern S_EAS easTestLib; +EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum) +{ + switch (libNum) + { + case 0: + return &easSoundLib; +#ifdef _WT_SYNTH + case 1: + return &easTestLib; +#endif + default: + return NULL; + } +} +#endif + +/* pointer to synthesizer interface(s) */ +#ifdef _WT_SYNTH +extern const S_SYNTH_INTERFACE wtSynth; +#endif + +#ifdef _FM_SYNTH +extern const S_SYNTH_INTERFACE fmSynth; +#endif + +typedef S_SYNTH_INTERFACE *S_SYNTH_INTERFACE_HANDLE; + +/* wavetable on MCU */ +#if defined(EAS_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +extern const S_FRAME_INTERFACE wtFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &wtFrameInterface; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +/* FM on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +#else +#error "Undefined architecture option" +#endif + +/*---------------------------------------------------------------------------- + * inline functions + *---------------------------------------------------------------------------- +*/ +EAS_INLINE const S_REGION* GetRegionPtr (S_SYNTH *pSynth, EAS_U16 regionIndex) +{ +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK].wtRegion.region; +#endif +#if defined(_HYBRID_SYNTH) + if (regionIndex & FLAG_RGN_IDX_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex & REGION_INDEX_MASK].region; + else + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_WT_SYNTH) + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex].region; +#endif +} + +/*lint -esym(715, voiceNum) used in some implementation */ +EAS_INLINE const S_SYNTH_INTERFACE* GetSynthPtr (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum < NUM_PRIMARY_VOICES) + return pPrimarySynth; + else + return pSecondarySynth; +#else + return pPrimarySynth; +#endif +} + +EAS_INLINE EAS_INT GetAdjustedVoiceNum (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum >= NUM_PRIMARY_VOICES) + return voiceNum - NUM_PRIMARY_VOICES; +#endif + return voiceNum; +} + +EAS_INLINE EAS_U8 VSynthToChannel (S_SYNTH *pSynth, EAS_U8 channel) +{ + /*lint -e{734} synthNum is always 0-15 */ + return channel | (pSynth->vSynthNum << 4); +} + +/*---------------------------------------------------------------------------- + * InitVoice() + *---------------------------------------------------------------------------- + * Initialize a synthesizer voice + *---------------------------------------------------------------------------- +*/ +void InitVoice (S_SYNTH_VOICE *pVoice) +{ + pVoice->channel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->note = pVoice->nextNote = DEFAULT_KEY_NUMBER; + pVoice->velocity = pVoice->nextVelocity = DEFAULT_VELOCITY; + pVoice->regionIndex = DEFAULT_REGION_INDEX; + pVoice->age = DEFAULT_AGE; + pVoice->voiceFlags = DEFAULT_VOICE_FLAGS; + pVoice->voiceState = DEFAULT_VOICE_STATE; +} + +/*---------------------------------------------------------------------------- + * IncVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void IncVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IncVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * DecVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void DecVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]--; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "DecVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData) +{ + S_VOICE_MGR *pVoiceMgr; + EAS_INT i; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pVoiceMgr = EAS_CMEnumData(EAS_CM_SYNTH_DATA); + else + pVoiceMgr = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_VOICE_MGR)); + if (!pVoiceMgr) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitialize: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pVoiceMgr, 0, sizeof(S_VOICE_MGR)); + + /* initialize non-zero variables */ + pVoiceMgr->pGlobalEAS = (S_EAS*) &easSoundLib; + pVoiceMgr->maxPolyphony = (EAS_U16) MAX_SYNTH_VOICES; + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + pVoiceMgr->maxPolyphonyPrimary = NUM_PRIMARY_VOICES; + pVoiceMgr->maxPolyphonySecondary = NUM_SECONDARY_VOICES; +#endif + + /* set max workload to zero */ + pVoiceMgr->maxWorkLoad = 0; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + InitVoice(&pVoiceMgr->voices[i]); + + /* initialize the synth */ + /*lint -e{522} return unused at this time */ + pPrimarySynth->pfInitialize(pVoiceMgr); + + /* initialize the off-chip synth */ +#ifdef _HYBRID_SYNTH + /*lint -e{522} return unused at this time */ + pSecondarySynth->pfInitialize(pVoiceMgr); +#endif + + pEASData->pVoiceMgr = pVoiceMgr; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth) +{ + EAS_RESULT result; + S_SYNTH *pSynth; + EAS_INT virtualSynthNum; + + *ppSynth = NULL; + + /* static memory model only allows one synth */ + if (pEASData->staticMemoryModel) + { + if (pEASData->pVoiceMgr->pSynth[0] != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: No virtual synthesizer support for static memory model\n"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + + /* check Configuration Module for data allocation */ + pSynth = EAS_CMEnumData(EAS_CM_MIDI_DATA); + virtualSynthNum = 0; + } + + /* dynamic memory model */ + else + { + for (virtualSynthNum = 0; virtualSynthNum < MAX_VIRTUAL_SYNTHESIZERS; virtualSynthNum++) + if (pEASData->pVoiceMgr->pSynth[virtualSynthNum] == NULL) + break; + if (virtualSynthNum == MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Exceeded number of active virtual synthesizers"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + pSynth = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SYNTH)); + } + + /* make sure we have a valid memory pointer */ + if (pSynth == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pSynth, 0, sizeof(S_SYNTH)); + + /* set the sound library pointer */ + if ((result = VMSetEASLib(pSynth, pEASData->pVoiceMgr->pGlobalEAS)) != EAS_SUCCESS) + { + VMMIDIShutdown(pEASData, pSynth); + return result; + } + + /* link in DLS bank if downloaded */ +#ifdef DLS_SYNTHESIZER + if (pEASData->pVoiceMgr->pGlobalDLS) + { + pSynth->pDLS = pEASData->pVoiceMgr->pGlobalDLS; + DLSAddRef(pSynth->pDLS); + } +#endif + + /* initialize MIDI state variables */ + pSynth->synthFlags = DEFAULT_SYNTH_FLAGS; + pSynth->masterVolume = DEFAULT_SYNTH_MASTER_VOLUME; + pSynth->refCount = 1; + pSynth->priority = DEFAULT_SYNTH_PRIORITY; + pSynth->poolAlloc[0] = (EAS_U8) pEASData->pVoiceMgr->maxPolyphony; + + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + + pSynth->vSynthNum = (EAS_U8) virtualSynthNum; + pEASData->pVoiceMgr->pSynth[virtualSynthNum] = pSynth; + + *ppSynth = pSynth; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth) +{ + pSynth->refCount++; +} + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * force - force reset even if voices are active + * + * Outputs: + * + * Side Effects: + * - set a flag (in psSynthObject->m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: request to reset synth. Force = %d\n", force); */ } +#endif + + /* force voices to off state - may cause audio artifacts */ + if (force) + { + pVoiceMgr->activeVoices -= pSynth->numActiveVoices; + pSynth->numActiveVoices = 0; + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + } + else + VMMuteAllVoices(pVoiceMgr, pSynth); + + /* don't reset if voices are still playing */ + if (pSynth->numActiveVoices == 0) + { + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + pSynth->poolCount[i] = 0; + + /* set polyphony */ + if (pSynth->maxPolyphony < pVoiceMgr->maxPolyphony) + pSynth->poolAlloc[0] = (EAS_U8) pVoiceMgr->maxPolyphony; + else + pSynth->poolAlloc[0] = (EAS_U8) pSynth->maxPolyphony; + + /* clear reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* handle reset after voices are muted */ + else + pSynth->synthFlags |= SYNTH_FLAG_RESET_IS_REQUESTED; +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + VMResetControllers(pSynth); + + /* init each channel */ + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->channelFlags = DEFAULT_CHANNEL_FLAGS; + pChannel->staticGain = DEFAULT_CHANNEL_STATIC_GAIN; + pChannel->staticPitch = DEFAULT_CHANNEL_STATIC_PITCH; + pChannel->pool = 0; + + /* the drum channel needs a different init */ + if (i == DEFAULT_DRUM_CHANNEL) + { + pChannel->bankNum = DEFAULT_RHYTHM_BANK_NUMBER; + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else + pChannel->bankNum = DEFAULT_MELODY_BANK_NUMBER; + + VMProgramChange(pVoiceMgr, pSynth, (EAS_U8) i, DEFAULT_SYNTH_PROGRAM_NUMBER); + } + +} + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->pitchBend = DEFAULT_PITCH_BEND; + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->volume = DEFAULT_CHANNEL_VOLUME; + pChannel->pan = DEFAULT_PAN; + pChannel->expression = DEFAULT_EXPRESSION; + +#ifdef _REVERB + pSynth->channels[i].reverbSend = DEFAULT_REVERB_SEND; +#endif + +#ifdef _CHORUS + pSynth->channels[i].chorusSend = DEFAULT_CHORUS_SEND; +#endif + + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* update all voices on this channel */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + } +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum) +{ + EAS_INT i; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + else + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + } +} + +/*---------------------------------------------------------------------------- + * VMMuteVoice() + *---------------------------------------------------------------------------- + * Mute the selected voice + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + + /* take no action if voice is already muted */ + pVoice = &pVoiceMgr->voices[voiceNum]; + if ((pVoice->voiceState == eVoiceStateMuting) || (pVoice->voiceState == eVoiceStateFree)) + return; + + /* one less voice in pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + +} + +/*---------------------------------------------------------------------------- + * VMReleaseVoice() + *---------------------------------------------------------------------------- + * Release the selected voice + *---------------------------------------------------------------------------- +*/ +void VMReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* take no action if voice is already free, muting, or releasing */ + if (( pVoice->voiceState == eVoiceStateMuting) || + (pVoice->voiceState == eVoiceStateFree) || + (pVoice->voiceState == eVoiceStateRelease)) + return; + + /* stolen voices should just be muted */ + if (pVoice->voiceState == eVoiceStateStolen) + VMMuteVoice(pVoiceMgr, voiceNum); + + /* release this voice */ + GetSynthPtr(voiceNum)->pfReleaseVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateRelease; +} + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Initialize the SP-MIDI MIP table in preparation for receiving MIP message + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMInitMIPTable\n"); */ } +#endif + + /* clear SP-MIDI flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_SP_MIDI_ON; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + pSynth->channels[i].pool = 0; + pSynth->channels[i].mip = 0; + } +} + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Sets the priority and MIP level for a MIDI channel + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMSetMIPEntry: channel=%d, priority=%d, MIP=%d\n", channel, priority, mip); */ } +#endif + + /* save data for use by MIP message processing */ + if (priority < NUM_SYNTH_CHANNELS) + { + pSynth->channels[channel].pool = priority; + pSynth->channels[channel].mip = mip; + } +} + +/*---------------------------------------------------------------------------- + * VMMIPUpdateChannelMuting() + *---------------------------------------------------------------------------- + * This routine is called after an SP-MIDI message is received and + * any time the allocated polyphony changes. It mutes or unmutes + * channels based on polyphony. + *---------------------------------------------------------------------------- +*/ +void VMMIPUpdateChannelMuting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + EAS_INT maxPolyphony; + EAS_INT channel; + EAS_INT vSynthNum; + EAS_INT pool; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* determine max polyphony */ + if (pSynth->maxPolyphony) + maxPolyphony = pSynth->maxPolyphony; + else + maxPolyphony = pVoiceMgr->maxPolyphony; + + /* process channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + + /* channel must be in MIP message and must meet allocation target */ + if ((pSynth->channels[i].mip != 0) && (pSynth->channels[i].mip <= maxPolyphony)) + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_MUTE; + else + pSynth->channels[i].channelFlags |= CHANNEL_FLAG_MUTE; + + /* reset voice pool count */ + pSynth->poolCount[i] = 0; + } + + /* mute any voices on muted channels, and count unmuted voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* ignore free voices */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateFree) + continue; + + /* get channel and virtual synth */ + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].channel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].channel); + } + else + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].nextChannel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].nextChannel); + } + + /* ignore voices on other synths */ + if (vSynthNum != pSynth->vSynthNum) + continue; + + /* count voices */ + pool = pSynth->channels[channel].pool; + + /* deal with muted channels */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_MUTE) + { + /* mute stolen voices scheduled to play on this channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[i].voiceState = eVoiceStateMuting; + + /* release voices that aren't already muting */ + else if (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting) + { + VMReleaseVoice(pVoiceMgr, pSynth, i); + pSynth->poolCount[pool]++; + } + } + + /* not muted, count this voice */ + else + pSynth->poolCount[pool]++; + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * This routine is called at the end of the SysEx message to allow + * the Voice Manager to complete the initialization of the MIP + * table. It assigns channels to the appropriate voice pool based + * on the MIP setting and calculates the voices allocated for each + * pool. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + EAS_INT currentMIP; + EAS_INT currentPool; + EAS_INT priority[NUM_SYNTH_CHANNELS]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* sort channels into priority order */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + priority[i] = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[i].pool != DEFAULT_SP_MIDI_PRIORITY) + priority[pSynth->channels[i].pool] = i; + } + + /* process channels in priority order */ + currentMIP = 0; + currentPool = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + /* stop when we run out of channels */ + if (priority[i] == -1) + break; + + pChannel = &pSynth->channels[priority[i]]; + + /* when 2 or more channels have the same MIP setting, they + * share a common voice pool + */ + if (pChannel->mip == currentMIP) + pChannel->pool = (EAS_U8) currentPool; + + /* new voice pool */ + else + { + currentPool++; + pSynth->poolAlloc[currentPool] = (EAS_U8) (pChannel->mip - currentMIP); + currentMIP = pChannel->mip; + } + } + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* update channel muting */ + VMMIPUpdateChannelMuting (pVoiceMgr, pSynth); +} + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMMuteAllVoices: about to mute all voices!!\n"); */ } +#endif + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* for stolen voices, check new channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + } + + else if (pSynth->vSynthNum == GET_VSYNTH(pVoiceMgr->voices[i].channel)) + VMMuteVoice(pVoiceMgr, i); + } +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voices are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + + /* release sustain pedal on all channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[ i ].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, (EAS_U8) i); + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + } + + /* release all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + switch (pVoiceMgr->voices[i].voiceState) + { + case eVoiceStateStart: + case eVoiceStatePlay: + /* only release voices on this synth */ + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == pSynth->vSynthNum) + VMReleaseVoice(pVoiceMgr, pSynth, i); + break; + + case eVoiceStateStolen: + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + break; + + case eVoiceStateFree: + case eVoiceStateRelease: + case eVoiceStateMuting: + break; + + case eVoiceStateInvalid: + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllVoices: error, %d is an unrecognized state\n", + pVoiceMgr->voices[i].voiceState); */ } +#endif + break; + } + } +} + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + S_SYNTH_VOICE *pVoice; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAllNotesOff: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* check each voice */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + pVoice = &pVoiceMgr->voices[voiceNum]; + if (pVoice->voiceState != eVoiceStateFree) + { + if (((pVoice->voiceState != eVoiceStateStolen) && (channel == pVoice->channel)) || + ((pVoice->voiceState == eVoiceStateStolen) && (channel == pVoice->nextChannel))) + { + /* this voice is assigned to the requested channel */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + } + } + } +} + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * psSynthObject->m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT voiceNum; + EAS_INT channel; + EAS_BOOL deferredNoteOff; + + deferredNoteOff = EAS_FALSE; + + /* check each voice to see if it requires a deferred note off */ + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { + /* check if this voice was stolen */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + { + /* + This voice was stolen, AND it also has a deferred note-off. + The stolen note must be completely ramped down at this point. + The note that caused the stealing to occur, however, must + have received a note-off request before the note that caused + stealing ever had a chance to even start. We want to give + the note that caused the stealing a chance to play, so we + start it on the next update interval, and we defer sending + the note-off request until the subsequent update interval. + So do not send the note-off request for this voice because + this voice was stolen and should have completed ramping down, + Also, do not clear the global flag nor this voice's flag + because we must indicate that the subsequent update interval, + after the note that caused stealing has started, should + then send the deferred note-off request. + */ + deferredNoteOff = EAS_TRUE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: defer request to stop voice %d (channel=%d note=%d) - voice not started\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } + + /* sanity check: this stolen voice better be ramped to zero */ + if (0 != pVoiceMgr->voices[voiceNum].gain) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: warning, this voice did not complete its ramp to zero\n"); */ } + } +#endif // #ifdef _DEBUG_VM + + } + else + { + /* clear the flag using exor */ + pVoiceMgr->voices[voiceNum].voiceFlags ^= + VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: Stop voice %d (channel=%d note=%d)\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } +#endif + + channel = pVoiceMgr->voices[voiceNum].channel & 15; + + /* check if sustain pedal is on */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + + /* release this voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + + } + + } + + /* clear the deferred note-off flag, unless there's another one pending */ + if (deferredNoteOff == EAS_FALSE) + pSynth->synthFlags ^= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * pVoice->m_sEG1.m_eState = eEnvelopeStateRelease + * pVoice->m_sEG1.m_nIncrement = release increment + * pVoice->m_nFlags = clear the deferred note off flag + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + S_SYNTH_VOICE *pVoice; + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllDeferredNoteOffs: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif /* #ifdef _DEBUG_VM */ + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* find all the voices assigned to this channel */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + pVoice = &pVoiceMgr->voices[voiceNum]; + if (channel == pVoice->channel) + { + + /* does this voice have a deferred note off? */ + if (pVoice->voiceFlags & VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF) + { + /* release voice */ + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + /* use exor to flip bit, clear the flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + + } + + } + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes are in release and have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCatchNotesForSustainPedal: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + channel = VSynthToChannel(pSynth, channel); + + /* find all the voices assigned to this channel */ + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + if (eVoiceStateRelease == pVoiceMgr->voices[voiceNum].voiceState) + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all of the active voices. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for all voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 age) +{ + EAS_INT i; + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (age - pVoiceMgr->voices[i].age > 0) + pVoiceMgr->voices[i].age++; + } +} + +/*---------------------------------------------------------------------------- + * VMStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being stolen. Sets the parameters so that the + * voice will begin playing the new sound on the next buffer. + * + * Inputs: + * pVoice - pointer to voice to steal + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMStolenVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* one less voice in old pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + /* mute the sound that is currently playing */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)], &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateStolen; + + /* set new note data */ + pVoice->nextChannel = VSynthToChannel(pSynth, channel); + pVoice->nextNote = note; + pVoice->nextVelocity = velocity; + pVoice->nextRegionIndex = regionIndex; + + /* one more voice in new pool */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* clear the deferred flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF); + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + + /* assign current age to this note and increment for the next note */ + pVoice->age = pVoiceMgr->age++; +} + +/*---------------------------------------------------------------------------- + * VMFreeVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is done playing and being returned to the + * pool of free voices + * + * Inputs: + * pVoice - pointer to voice to free + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMFreeVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ + + /* do nothing if voice is already free */ + if (pVoice->voiceState == eVoiceStateFree) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMFreeVoice: Attempt to free voice that is already free\n"); */ } + return; + } + + /* if we jump directly to free without passing muting stage, + * we need to adjust the voice count */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMFreeVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* return to free voice pool */ + pVoiceMgr->activeVoices--; + pSynth->numActiveVoices--; + InitVoice(pVoice); + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFreeVoice: free voice %d\n", pVoice - pVoiceMgr->voices); */ } +#endif + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + } + +/*---------------------------------------------------------------------------- + * VMRetargetStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice has been stolen and needs to be initalized with + * the paramters of its new note. + * + * Inputs: + * pVoice - pointer to voice to retarget + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL VMRetargetStolenVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + EAS_U8 flags; + S_SYNTH_CHANNEL *pMIDIChannel; + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + S_SYNTH *pNextSynth; + + /* establish some pointers */ + pVoice = &pVoiceMgr->voices[voiceNum]; + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pMIDIChannel = &pSynth->channels[pVoice->channel & 15]; + pNextSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + +#ifdef _DEBUG_VM +{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: retargeting stolen voice %d on channel %d\n", + voiceNum, pVoice->channel); */ } + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\to channel %d note: %d velocity: %d\n", + pVoice->nextChannel, pVoice->nextNote, pVoice->nextVelocity); */ } +#endif + + /* make sure new channel hasn't been muted by SP-MIDI since the voice was stolen */ + if ((pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) && + (pMIDIChannel->channelFlags & CHANNEL_FLAG_MUTE)) + { + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + return EAS_FALSE; + } + + /* if assigned to a new synth, correct the active voice count */ + if (pVoice->channel != pVoice->nextChannel) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: Note assigned to different virtual synth, adjusting numActiveVoices\n"); */ } +#endif + pSynth->numActiveVoices--; + pNextSynth->numActiveVoices++; + } + + /* assign new channel number, and increase channel voice count */ + pVoice->channel = pVoice->nextChannel; + pMIDIChannel = &pNextSynth->channels[pVoice->channel & 15]; + + /* assign other data */ + pVoice->note = pVoice->nextNote; + pVoice->velocity = pVoice->nextVelocity; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->regionIndex = pVoice->nextRegionIndex; + + /* save the flags, pfStartVoice() will clear them */ + flags = pVoice->voiceFlags; + + /* keep track of the note-start related workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_START_NOTE; + + /* setup the voice parameters */ + pVoice->voiceState = eVoiceStateStart; + + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pNextSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pVoice->regionIndex); + + /* did the new note already receive a MIDI note-off request? */ + if (flags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetVoice: stolen note note-off request deferred\n"); */ } +#endif + pVoice->voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pNextSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel) +{ + const S_REGION *pRegion; + EAS_INT voiceNum; + + /* increment frame workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_KEY_GROUP; + + /* need to check all voices in case this is a layered sound */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].regionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + } + + /* for stolen voice, check new values */ + else + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].nextChannel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].nextRegionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + + } + } +} + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + EAS_INT oldestVoiceNum; + EAS_INT numVoicesPlayingNote; + EAS_U16 age; + EAS_U16 oldestNoteAge; + + pVoiceMgr->workload += WORKLOAD_AMOUNT_POLY_LIMIT; + + numVoicesPlayingNote = 0; + oldestVoiceNum = MAX_SYNTH_VOICES; + oldestNoteAge = 0; + channel = VSynthToChannel(pSynth, channel); + + /* examine each voice on this channel playing this note */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check stolen notes separately */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { + numVoicesPlayingNote++; + age = pVoiceMgr->age - pVoiceMgr->voices[voiceNum].age; + + /* is this the oldest voice for this note? */ + if (age >= oldestNoteAge) + { + oldestNoteAge = age; + oldestVoiceNum = voiceNum; + } + } + } + + /* handle stolen voices */ + else + { + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + numVoicesPlayingNote++; + } + } + } + + /* check to see if we exceeded poly limit */ + if (numVoicesPlayingNote < DEFAULT_CHANNEL_POLYPHONY_LIMIT) + return EAS_FALSE; + + /* make sure we have a voice to steal */ + if (oldestVoiceNum != MAX_SYNTH_VOICES) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckPolyphonyLimiting: voice %d has the oldest note\n", oldestVoiceNum); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMCheckPolyphonyLimiting: polyphony limiting requires shutting down note %d \n", pVoiceMgr->voices[oldestVoiceNum].note); */ } +#endif + VMStolenVoice(pVoiceMgr, pSynth, oldestVoiceNum, channel, note, velocity, regionIndex); + return EAS_TRUE; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMCheckPolyphonyLimiting: No oldest voice to steal\n"); */ } +#endif + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMStartVoice() + *---------------------------------------------------------------------------- + * Starts a voice given a region index + *---------------------------------------------------------------------------- +*/ +void VMStartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + const S_REGION *pRegion; + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + EAS_INT maxSynthPoly; + EAS_I32 lowVoice, highVoice; + EAS_U16 keyGroup; + + pChannel = &pSynth->channels[channel]; + pRegion = GetRegionPtr(pSynth, regionIndex); + + /* select correct synth */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + { +#ifdef EAS_SPLIT_WT_SYNTH + if ((pRegion->keyGroupAndFlags & REGION_FLAG_OFF_CHIP) == 0) +#else + if ((regionIndex & FLAG_RGN_IDX_FM_SYNTH) == 0) +#endif + { + lowVoice = 0; + highVoice = NUM_PRIMARY_VOICES - 1; + } + else + { + lowVoice = NUM_PRIMARY_VOICES; + highVoice = MAX_SYNTH_VOICES - 1; + } + } +#else + lowVoice = 0; + highVoice = MAX_SYNTH_VOICES - 1; +#endif + + /* keep track of the note-start related workload */ + pVoiceMgr->workload+= WORKLOAD_AMOUNT_START_NOTE; + + /* other voices in pool, check for key group and poly limiting */ + if (pSynth->poolCount[pChannel->pool] != 0) + { + + /* check for key group exclusivity */ + keyGroup = pRegion->keyGroupAndFlags & 0x0f00; + if (keyGroup!= 0) + VMCheckKeyGroup(pVoiceMgr, pSynth, keyGroup, channel); + + /* check polyphony limit and steal a voice if necessary */ + if ((pRegion->keyGroupAndFlags & REGION_FLAG_NON_SELF_EXCLUSIVE) == 0) + { + if (VMCheckPolyphonyLimiting(pVoiceMgr, pSynth, channel, note, velocity, regionIndex, lowVoice, highVoice) == EAS_TRUE) + return; + } + } + + /* check max poly allocation */ + if ((pSynth->maxPolyphony == 0) || (pVoiceMgr->maxPolyphony < pSynth->maxPolyphony)) + maxSynthPoly = pVoiceMgr->maxPolyphony; + else + maxSynthPoly = pSynth->maxPolyphony; + + /* any free voices? */ + if ((pVoiceMgr->activeVoices < pVoiceMgr->maxPolyphony) && + (pSynth->numActiveVoices < maxSynthPoly) && + (EAS_SUCCESS == VMFindAvailableVoice(pVoiceMgr, &voiceNum, lowVoice, highVoice))) + { + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMStartVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* bump voice counts */ + pVoiceMgr->activeVoices++; + pSynth->numActiveVoices++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: voice %d assigned to channel %d note %d velocity %d\n", + voiceNum, channel, note, velocity); */ } +#endif + + /* save parameters */ + pVoiceMgr->voices[voiceNum].channel = VSynthToChannel(pSynth, channel); + pVoiceMgr->voices[voiceNum].note = note; + pVoiceMgr->voices[voiceNum].velocity = velocity; + + /* establish note age for voice stealing */ + pVoiceMgr->voices[voiceNum].age = pVoiceMgr->age++; + + /* setup the synthesis parameters */ + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStateStart; + + /* increment voice pool count */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* start voice on correct synth */ + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), regionIndex); + return; + } + + /* no free voices, we have to steal one using appropriate algorithm */ + if (VMStealVoice(pVoiceMgr, pSynth, &voiceNum, channel, note, lowVoice, highVoice) == EAS_SUCCESS) + VMStolenVoice(pVoiceMgr, pSynth, voiceNum, channel, note, velocity, regionIndex); + +#ifdef _DEBUG_VM + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: Could not steal a voice for channel %d note %d velocity %d\n", + channel, note, velocity); */ } + } +#endif + + return; +} + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_nNumActiveVoices may be incremented + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U16 regionIndex; + EAS_I16 adjustedNote; + + /* bump note count */ + pSynth->totalNoteCount++; + + pChannel = &pSynth->channels[channel]; + + /* check channel mute */ + if (pChannel->channelFlags & CHANNEL_FLAG_MUTE) + return; + +#ifdef EXTERNAL_AUDIO + /* pass event to external audio when requested */ + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_TRUE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* start search at first region */ + regionIndex = pChannel->regionIndex; + + /* handle transposition */ + adjustedNote = note; + if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + adjustedNote += pChannel->coarsePitch; + else + adjustedNote += pChannel->coarsePitch + pSynth->globalTranspose; + + /* limit adjusted key number so it does not wraparound, over/underflow */ + if (adjustedNote < 0) + { + adjustedNote = 0; + } + else if (adjustedNote > 127) + { + adjustedNote = 127; + } + +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + /* DLS voice */ + for (;;) + { + /*lint -e{740,826} cast OK, we know this is actually a DLS region */ + const S_DLS_REGION *pDLSRegion = (S_DLS_REGION*) GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's key and velocity range */ + if (((adjustedNote >= pDLSRegion->wtRegion.region.rangeLow) && (adjustedNote <= pDLSRegion->wtRegion.region.rangeHigh)) && + ((velocity >= pDLSRegion->velLow) && (velocity <= pDLSRegion->velHigh))) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + } + + /* last region in program? */ + if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } + else +#endif + + /* braces here for #if clause */ + { + /* EAS voice */ + for (;;) + { + const S_REGION *pRegion = GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's keyrange */ + if ((adjustedNote >= pRegion->rangeLow) && (adjustedNote <= pRegion->rangeHigh)) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + break; + } + + /* last region in program? */ + if (pRegion->keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } +} + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the channel to stop a note on + * nKeyNumber - the key number for this note off + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, velocity) reserved for future use */ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + + pChannel = &(pSynth->channels[channel]); + +#ifdef EXTERNAL_AUDIO + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_FALSE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* keep track of the note-start workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_STOP_NOTE; + + channel = VSynthToChannel(pSynth, channel); + + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* stolen notes are handled separately */ + if (eVoiceStateStolen != pVoiceMgr->voices[voiceNum].voiceState) + { + + /* channel and key number must match */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n", + voiceNum, channel, note); */ } +#endif + + /* if sustain pedal is down, set deferred note-off flag */ + if (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + continue; + } + + /* if this note just started, wait before we stop it */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tDeferred: Not started yet\n"); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + /* release voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + } + + /* process stolen notes, new channel and key number must match */ + else if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n\tDeferred: Stolen voice\n", + voiceNum, channel, note); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + } + } +} + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, returns the voice number found + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + + /* Check each voice to see if it has been assigned to a synth channel */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check if this voice has been assigned to a synth channel */ + if ( pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateFree) + { + *pVoiceNumber = voiceNum; /* this voice is available */ + return EAS_SUCCESS; + } + } + + /* if we reach here, we have not found a free voice */ + *pVoiceNumber = UNASSIGNED_SYNTH_VOICE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFindAvailableVoice: error, could not find an available voice\n"); */ } +#endif + return EAS_FAILURE; +} + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * pnVoiceNumber - really an output, see below + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice number of the voice that was stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + S_SYNTH_VOICE *pCurrVoice; + S_SYNTH *pCurrSynth; + EAS_INT voiceNum; + EAS_INT bestCandidate; + EAS_U8 currChannel; + EAS_U8 currNote; + EAS_I32 bestPriority; + EAS_I32 currentPriority; + + /* determine which voice to steal */ + bestPriority = 0; + bestCandidate = MAX_SYNTH_VOICES; + + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + pCurrVoice = &pVoiceMgr->voices[voiceNum]; + + /* ignore free voices */ + if (pCurrVoice->voiceState == eVoiceStateFree) + continue; + + /* for stolen voices, use the new parameters, not the old */ + if (pCurrVoice->voiceState == eVoiceStateStolen) + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->nextChannel)]; + currChannel = pCurrVoice->nextChannel; + currNote = pCurrVoice->nextNote; + } + else + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->channel)]; + currChannel = pCurrVoice->channel; + currNote = pCurrVoice->note; + } + + /* ignore voices that are higher priority */ + if (pSynth->priority > pCurrSynth->priority) + continue; +#ifdef _DEBUG_VM +// { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: New priority = %d exceeds old priority = %d\n", pSynth->priority, pCurrSynth->priority); */ } +#endif + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pCurrVoice->voiceState == eVoiceStateStolen) || (pCurrVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + currentPriority = 128 - pCurrVoice->nextVelocity; + } + else + { + /* compute the priority of this voice, higher means better for stealing */ + /* use not age */ + currentPriority = (EAS_I32) pCurrVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pCurrVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + } + + /* in SP-MIDI mode, include over poly allocation and channel priority */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + { + S_SYNTH_CHANNEL *pChannel = &pCurrSynth->channels[GET_CHANNEL(currChannel)]; + /*lint -e{701} use shift for performance */ + if (pSynth->poolCount[pChannel->pool] >= pSynth->poolAlloc[pChannel->pool]) + currentPriority += (pSynth->poolCount[pChannel->pool] -pSynth->poolAlloc[pChannel->pool] + 1) << CHANNEL_POLY_STEAL_WEIGHT; + + /* include channel priority */ + currentPriority += (EAS_I32)(pChannel->pool << CHANNEL_PRIORITY_STEAL_WEIGHT); + } + + /* if a note is already playing that matches this note, consider stealing it more readily */ + if ((note == currNote) && (channel == currChannel)) + currentPriority += NOTE_MATCH_PENALTY; + + /* is this the best choice so far? */ + if (currentPriority >= bestPriority) + { + bestPriority = currentPriority; + bestCandidate = voiceNum; + } + } + + /* may happen if all voices are allocated to a higher priority virtual synth */ + if (bestCandidate == MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Unable to allocate a voice\n"); */ } + return EAS_ERROR_NO_VOICE_ALLOCATED; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Voice %d stolen\n", bestCandidate); */ } + + /* are we stealing a stolen voice? */ + if (pVoiceMgr->voices[bestCandidate].voiceState == eVoiceStateStolen) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMStealVoice: Voice %d is already marked as stolen and was scheduled to play ch: %d note: %d vel: %d\n", + bestCandidate, + pVoiceMgr->voices[bestCandidate].nextChannel, + pVoiceMgr->voices[bestCandidate].nextNote, + pVoiceMgr->voices[bestCandidate].nextVelocity); */ } + } +#endif + + *pVoiceNumber = (EAS_U16) bestCandidate; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->channelPressure = value; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte of the pitch bend message + * nPitchMSB - the MSB byte of the pitch bend message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 nPitchLSB, EAS_U8 nPitchMSB) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->pitchBend = (EAS_I16) ((nPitchMSB << 7) | nPitchLSB); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the MIDI controller number + * nControlValue - the value for this controller message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + switch ( controller ) + { + case MIDI_CONTROLLER_BANK_SELECT_MSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select MSB: msb 0x%X\n", value); */ } +#endif + /* use this MSB with a zero LSB, until we get an LSB message */ + pChannel->bankNum = value << 8; + break; + + case MIDI_CONTROLLER_MOD_WHEEL: + /* we treat mod wheel as a 7-bit controller and only use the MSB */ + pChannel->modWheel = value; + break; + + case MIDI_CONTROLLER_VOLUME: + /* we treat volume as a 7-bit controller and only use the MSB */ + pChannel->volume = value; + break; + + case MIDI_CONTROLLER_PAN: + /* we treat pan as a 7-bit controller and only use the MSB */ + pChannel->pan = value; + break; + + case MIDI_CONTROLLER_EXPRESSION: + /* we treat expression as a 7-bit controller and only use the MSB */ + pChannel->expression = value; + break; + + case MIDI_CONTROLLER_BANK_SELECT_LSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select LSB: lsb 0x%X\n", value); */ } +#endif + /* + construct bank number as 7-bits (stored as 8) of existing MSB + and 7-bits of new LSB (also stored as 8( + */ + pChannel->bankNum = + (pChannel->bankNum & 0xFF00) | value; + + break; + + case MIDI_CONTROLLER_SUSTAIN_PEDAL: + /* we treat sustain pedal as a boolean on/off bit flag */ + if (value < 64) + { + /* + we are requested to turn the pedal off, but first check + if the pedal is already on + */ + if (0 != + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently set and the damper pedal is on. + We are therefore transitioning from damper pedal ON to + damper pedal OFF. This means all notes in this channel + that received a note off while the damper pedal was on, and + had their note-off requests deferred, should now proceed to + the release state. + */ + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, channel); + } /* end if sustain pedal is already on */ + + /* turn the sustain pedal off */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + else + { + /* + we are requested to turn the pedal on, but first check + if the pedal is already off + */ + if (0 == + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently clear and the damper pedal is off. + We are therefore transitioning from damper pedal OFF to + damper pedal ON. Currently sounding notes should be left + unchanged. However, we should try to "catch" notes if possible. + If any notes have levels >= sustain level, catch them, + otherwise, let them continue to release. + */ + VMCatchNotesForSustainPedal(pVoiceMgr, pSynth, channel); + } + + /* turn the sustain pedal on */ + pChannel->channelFlags |= CHANNEL_FLAG_SUSTAIN_PEDAL; + } + + break; +#ifdef _REVERB + case MIDI_CONTROLLER_REVERB_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].reverbSend = value; + break; +#endif +#ifdef _CHORUS + case MIDI_CONTROLLER_CHORUS_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].chorusSend = value; + break; +#endif + case MIDI_CONTROLLER_RESET_CONTROLLERS: + /* despite the Midi message name, not ALL controllers are reset */ + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->expression = DEFAULT_EXPRESSION; + + /* turn the sustain pedal off as default/reset */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + pChannel->pitchBend = DEFAULT_PITCH_BEND; + + /* reset channel pressure */ + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + + /* reset RPN values */ + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* + program change, bank select, channel volume CC7, pan CC10 + are NOT reset + */ + break; + + /* + For logical reasons, the RPN data entry are grouped together. + However, keep in mind that these cases are not necessarily in + ascending order. + e.g., MIDI_CONTROLLER_DATA_ENTRY_MSB == 6, + whereas MIDI_CONTROLLER_SUSTAIN_PEDAL == 64. + So arrange these case statements in whatever manner is more efficient for + the processor / compiler. + */ + case MIDI_CONTROLLER_ENTER_DATA_MSB: + case MIDI_CONTROLLER_ENTER_DATA_LSB: + case MIDI_CONTROLLER_SELECT_RPN_LSB: + case MIDI_CONTROLLER_SELECT_RPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + VMUpdateRPNStateMachine(pSynth, channel, controller, value); + break; + + case MIDI_CONTROLLER_ALL_SOUND_OFF: + case MIDI_CONTROLLER_ALL_NOTES_OFF: + case MIDI_CONTROLLER_OMNI_OFF: + case MIDI_CONTROLLER_OMNI_ON: + case MIDI_CONTROLLER_MONO_ON_POLY_OFF: + case MIDI_CONTROLLER_POLY_ON_MONO_OFF: + /* NOTE: we treat all sounds off the same as all notes off */ + VMAllNotesOff(pVoiceMgr, pSynth, channel); + break; + + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: controller %d not yet implemented\n", controller); */ } +#endif + break; + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse RPN related controller messages. + * We only support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs or NRPNs are ignored for now. + *. + * Supports any order, so not a state machine anymore. This function was + * rewritten to work correctly regardless of order. + * + * Inputs: + * nChannel - the channel this controller message is coming from + * nControllerNumber - which RPN related controller + * nControlValue - the value of the RPN related controller + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * returns EAS_RESULT, which is typically EAS_SUCCESS, since there are + * few possible errors + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBendSensitivity + * (or m_nFinePitch or m_nCoarsePitch) + * will be updated if the proper RPN message is received. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateRPNStateMachines: error, %d invalid channel number\n", + channel); */ } + return EAS_FAILURE; + } +#endif + + pChannel = &(pSynth->channels[channel]); + + switch (controller) + { + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + break; + case MIDI_CONTROLLER_SELECT_RPN_MSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F) | (value<<7); + break; + case MIDI_CONTROLLER_SELECT_RPN_LSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F00) | value; + break; + case MIDI_CONTROLLER_ENTER_DATA_MSB: + switch (pChannel->registeredParam) + { + case 0: + pChannel->pitchBendSensitivity = value * 100; + break; + case 1: + /*lint -e{702} <avoid division for performance reasons>*/ + pChannel->finePitch = (EAS_I8)((((value << 7) - 8192) * 100) >> 13); + break; + case 2: + pChannel->coarsePitch = (EAS_I8)(value - 64); + break; + default: + break; + } + break; + case MIDI_CONTROLLER_ENTER_DATA_LSB: + switch (pChannel->registeredParam) + { + case 0: + //ignore lsb + break; + case 1: + //ignore lsb + break; + case 2: + //ignore lsb + break; + default: + break; + } + break; + default: + return EAS_FAILURE; //not a RPN related controller + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT channel; + + if (pSynth->synthFlags & SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS) + { + /* + the synth wants us to forcibly update all channel + parameters. This event occurs when we are about to + finish resetting the synth + */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + + /* + clear the flag to indicates we have now forcibly + updated all channel parameters + */ + pSynth->synthFlags &= ~SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; + } + else + { + + /* only update channel params if signalled by a channel flag */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { + if ( 0 != (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + } + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMFindProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindProgram (const S_EAS *pEAS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + EAS_U16 regionIndex; + + /* make sure we have a valid sound library */ + if (pEAS == NULL) + return EAS_FAILURE; + + /* search the banks */ + for (i = 0; i < pEAS->numBanks; i++) + { + if (bank == (EAS_U32) pEAS->pBanks[i].locale) + { + regionIndex = pEAS->pBanks[i].regionIndex[programNum]; + if (regionIndex != INVALID_REGION_INDEX) + { + *pRegionIndex = regionIndex; + return EAS_SUCCESS; + } + break; + } + } + + /* establish locale */ + locale = ( bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pEAS->pPrograms; i < pEAS->numPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMFindDLSProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindDLSProgram (const S_DLS *pDLS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + + /* make sure we have a valid sound library */ + if (pDLS == NULL) + return EAS_FAILURE; + + /* establish locale */ + locale = (bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pDLS->pDLSPrograms; i < pDLS->numDLSPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} +#endif + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U32 bank; + EAS_U16 regionIndex; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMProgramChange: vSynthNum=%d, channel=%d, program=%d\n", pSynth->vSynthNum, channel, program); */ } +#endif + + /* setup pointer to MIDI channel data */ + pChannel = &pSynth->channels[channel]; + bank = pChannel->bankNum; + + /* allow channels to switch between being melodic or rhythm channels, using GM2 CC values */ + if ((bank & 0xFF00) == DEFAULT_RHYTHM_BANK_NUMBER) + { + /* make it a rhythm channel */ + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else if ((bank & 0xFF00) == DEFAULT_MELODY_BANK_NUMBER) + { + /* make it a melody channel */ + pChannel->channelFlags &= ~CHANNEL_FLAG_RHYTHM_CHANNEL; + } + + regionIndex = DEFAULT_REGION_INDEX; + +#ifdef EXTERNAL_AUDIO + /* give the external audio interface a chance to handle it */ + if (pSynth->cbProgChgFunc != NULL) + { + S_EXT_AUDIO_PRG_CHG prgChg; + prgChg.channel = channel; + prgChg.bank = (EAS_U16) bank; + prgChg.program = program; + if (pSynth->cbProgChgFunc(pSynth->pExtAudioInstData, &prgChg)) + pChannel->channelFlags |= CHANNEL_FLAG_EXTERNAL_AUDIO; + } + +#endif + + +#ifdef DLS_SYNTHESIZER + /* first check for DLS program that may overlay the internal instrument */ + if (VMFindDLSProgram(pSynth->pDLS, bank, program, ®ionIndex) != EAS_SUCCESS) +#endif + + /* braces to support 'if' clause above */ + { + + /* look in the internal banks */ + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* fall back to default bank */ + { + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + bank = DEFAULT_RHYTHM_BANK_NUMBER; + else + bank = DEFAULT_MELODY_BANK_NUMBER; + + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* switch to program 0 in the default bank */ + { + if (VMFindProgram(pSynth->pEAS, bank, 0, ®ionIndex) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMProgramChange: No program @ %03d:%03d:%03d\n", + (bank >> 8) & 0x7f, bank & 0x7f, program); */ } + } + } + } + + /* we have our new program change for this channel */ + pChannel->programNum = program; + pChannel->regionIndex = regionIndex; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + return; +} + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples (block based processing) + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of voices rendered + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_SYNTH *pSynth; + EAS_INT voicesRendered; + EAS_INT voiceNum; + EAS_BOOL done; + +#ifdef _REVERB + EAS_PCM *pReverbSendBuffer; +#endif // ifdef _REVERB + +#ifdef _CHORUS + EAS_PCM *pChorusSendBuffer; +#endif // ifdef _CHORUS + + voicesRendered = 0; + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* retarget stolen voices */ + if ((pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) && (pVoiceMgr->voices[voiceNum].gain <= 0)) + VMRetargetStolenVoice(pVoiceMgr, voiceNum); + + /* get pointer to virtual synth */ + pSynth = pVoiceMgr->pSynth[pVoiceMgr->voices[voiceNum].channel >> 4]; + + /* synthesize active voices */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateFree) + { + done = GetSynthPtr(voiceNum)->pfUpdateVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pMixBuffer, numSamples); + voicesRendered++; + + /* voice is finished */ + if (done == EAS_TRUE) + { + /* set gain of stolen voice to zero so it will be restarted */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[voiceNum].gain = 0; + + /* or return it to the free voice pool */ + else + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + } + + /* if this voice is scheduled to be muted, set the mute flag */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MUTE) + { + pVoiceMgr->voices[voiceNum].voiceFlags &= ~(VOICE_FLAG_DEFER_MUTE | VOICE_FLAG_DEFER_MIDI_NOTE_OFF); + VMMuteVoice(pVoiceMgr, voiceNum); + } + + /* if voice just started, advance state to play */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStart) + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStatePlay; + } + } + + return voicesRendered; +} + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered) +{ + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT channel; + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + /* update MIDI channel parameters */ + *pVoicesRendered = 0; + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i] != NULL) + VMUpdateStaticChannelParameters(pVoiceMgr, pVoiceMgr->pSynth[i]); + } + + /* synthesize a buffer of audio */ + *pVoicesRendered = VMAddSamples(pVoiceMgr, pMixBuffer, numSamples); + + /* + * check for deferred note-off messages + * If flag is set, that means one or more voices are expecting deferred + * midi note-off messages because the midi note-on and corresponding midi + * note-off requests occurred during the same update interval. The goal + * is the defer the note-off request so that the note can at least start. + */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + pSynth = pVoiceMgr->pSynth[i]; + + if (pSynth== NULL) + continue; + + if (pSynth->synthFlags & SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING) + VMDeferredStopNote(pVoiceMgr, pSynth); + + /* check if we need to reset the synth */ + if ((pSynth->synthFlags & SYNTH_FLAG_RESET_IS_REQUESTED) && + (pSynth->numActiveVoices == 0)) + { + /* + complete the process of resetting the synth now that + all voices have muted + */ +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAddSamples: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + + /* clear the reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* clear channel update flags */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + pSynth->channels[channel].channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + } + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr) +{ + pVoiceMgr->workload = 0; +} + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad) +{ + pVoiceMgr->maxWorkLoad = maxWorkLoad; +} + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr) +{ + if (pVoiceMgr->maxWorkLoad > 0) + return (EAS_BOOL) (pVoiceMgr->workload >= pVoiceMgr->maxWorkLoad); + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth) +{ + return pSynth->numActiveVoices; +} + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* lower limit */ + if (polyphonyCount < 1) + polyphonyCount = 1; + + /* split architecture */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + { + if (polyphonyCount > NUM_PRIMARY_VOICES) + polyphonyCount = NUM_PRIMARY_VOICES; + if (pVoiceMgr->maxPolyphonyPrimary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonyPrimary = (EAS_U16) polyphonyCount; + } + else if (synth == EAS_DSP_SYNTH) + { + if (polyphonyCount > NUM_SECONDARY_VOICES) + polyphonyCount = NUM_SECONDARY_VOICES; + if (pVoiceMgr->maxPolyphonySecondary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonySecondary = (EAS_U16) polyphonyCount; + } + else + return EAS_ERROR_PARAMETER_RANGE; + + /* setting for SP-MIDI */ + pVoiceMgr->maxPolyphony = pVoiceMgr->maxPolyphonyPrimary + pVoiceMgr->maxPolyphonySecondary; + + /* standard architecture */ +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + + /* pin desired value to possible limits */ + if (polyphonyCount > MAX_SYNTH_VOICES) + polyphonyCount = MAX_SYNTH_VOICES; + + /* set polyphony, if value is different than current value */ + if (pVoiceMgr->maxPolyphony == polyphonyCount) + return EAS_SUCCESS; + + pVoiceMgr->maxPolyphony = (EAS_U16) polyphonyCount; +#endif + + /* if SPMIDI enabled, update channel masking based on new polyphony */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i]) + { + if (pVoiceMgr->pSynth[i]->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pVoiceMgr->pSynth[i]); + else + pVoiceMgr->pSynth[i]->poolAlloc[0] = (EAS_U8) polyphonyCount; + } + } + + /* are we under polyphony limit? */ + if (pVoiceMgr->activeVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + pVoice = &pVoiceMgr->voices[i]; + + /* ignore free and muting voices */ + if ((pVoice->voiceState == eVoiceStateFree) || (pVoice->voiceState == eVoiceStateMuting)) + continue; + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->channel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* include synth priority */ + currentPriority += pSynth->priority << SYNTH_PRIORITY_WEIGHT; + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + /*lint -e{771} pSynth is initialized if bestCandidate >= 0 */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns actual polyphony value set, as pinned by limits + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount) +{ + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonyPrimary; + else if (synth == EAS_DSP_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonySecondary; + else + return EAS_ERROR_PARAMETER_RANGE; +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + *pPolyphonyCount = pVoiceMgr->maxPolyphony; +#endif + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* check limits */ + if (polyphonyCount < 0) + return EAS_ERROR_PARAMETER_RANGE; + + /* zero is max polyphony */ + if ((polyphonyCount == 0) || (polyphonyCount > MAX_SYNTH_VOICES)) + { + pSynth->maxPolyphony = 0; + return EAS_SUCCESS; + } + + /* set new polyphony */ + pSynth->maxPolyphony = (EAS_U16) polyphonyCount; + + /* max polyphony is minimum of virtual synth and actual synth */ + if (polyphonyCount > pVoiceMgr->maxPolyphony) + polyphonyCount = pVoiceMgr->maxPolyphony; + + /* if SP-MIDI mode, update the channel muting */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pSynth); + else + pSynth->poolAlloc[0] = (EAS_U8) polyphonyCount; + + /* are we under polyphony limit? */ + if (pSynth->numActiveVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* this synth? */ + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) != pSynth->vSynthNum) + continue; + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pVoiceMgr->voices[i]; + + /* this synth? */ + if (GET_VSYNTH(pVoice->nextChannel) != pSynth->vSynthNum) + continue; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth polyphony + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPolyphonyCount pointer to variable to hold polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount) +{ + *pPolyphonyCount = (EAS_U16) pSynth->maxPolyphony; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority) +{ + pSynth->priority = (EAS_U8) priority ; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority) +{ + *pPriority = pSynth->priority; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this synthesizer for this sequence. + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume) +{ + pSynth->masterVolume = masterVolume; + pSynth->synthFlags |= SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange) +{ + pSynth->channels[channel].pitchBendSensitivity = pitchBendRange; +} + +/*---------------------------------------------------------------------------- + * VMValidateEASLib() + *---------------------------------------------------------------------------- + * Validates an EAS library + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMValidateEASLib (EAS_SNDLIB_HANDLE pEAS) +{ + /* validate the sound library */ + if (pEAS) + { + if (pEAS->identifier != _EAS_LIBRARY_VERSION) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sound library mismatch in sound library: Read 0x%08x, expected 0x%08x\n", + pEAS->identifier, _EAS_LIBRARY_VERSION); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + + /* check sample rate */ + if ((pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK) != _OUTPUT_SAMPLE_RATE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sample rate mismatch in sound library: Read %lu, expected %lu\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + +#ifdef _WT_SYNTH + /* check sample bit depth */ +#ifdef _8_BIT_SAMPLES + if (pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 8-bit samples and found 16-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#ifdef _16_BIT_SAMPLES + if ((pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 16-bit samples and found 8-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#endif + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetGlobalEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pVoiceMgr->pGlobalEAS = pEAS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pSynth->pEAS = pEAS; + return EAS_SUCCESS; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetGlobalDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS) +{ + + if (pEASData->pVoiceMgr->pGlobalDLS) + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + + pEASData->pVoiceMgr->pGlobalDLS = pDLS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS) +{ + pSynth->pDLS = pDLS; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition) +{ + pSynth->globalTranspose = (EAS_I8) transposition; +} + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition) +{ + *pTransposition = pSynth->globalTranspose; +} + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth) +{ + return pSynth->totalNoteCount; +} + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth) +{ + EAS_INT vSynthNum; + + /* decrement reference count, free if all references are gone */ + if (--pSynth->refCount > 0) + return; + + vSynthNum = pSynth->vSynthNum; + + /* cleanup DLS load */ +#ifdef DLS_SYNTHESIZER + /*lint -e{550} result used only in debugging code */ + if (pSynth->pDLS != NULL) + { + EAS_RESULT result; + if ((result = DLSCleanup(pEASData->hwInstData, pSynth->pDLS)) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMMIDIShutdown: Error %ld cleaning up DLS collection\n", result); */ } + pSynth->pDLS = NULL; + } +#endif + + VMReset(pEASData->pVoiceMgr, pSynth, EAS_TRUE); + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pSynth); + + /* clear pointer to MIDI state */ + pEASData->pVoiceMgr->pSynth[vSynthNum] = NULL; +} + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData) +{ + + /* don't free a NULL pointer */ + if (pEASData->pVoiceMgr == NULL) + return; + +#ifdef DLS_SYNTHESIZER + /* if we have a global DLS collection, clean it up */ + if (pEASData->pVoiceMgr->pGlobalDLS) + { + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + pEASData->pVoiceMgr->pGlobalDLS = NULL; + } +#endif + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pEASData->pVoiceMgr); + pEASData->pVoiceMgr = NULL; +} + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc) +{ + pSynth->pExtAudioInstData = pInstData; + pSynth->cbProgChgFunc = cbProgChgFunc; + pSynth->cbEventFunc = cbEventFunc; +} + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + pControl->modWheel = pSynth->channels[channel].modWheel; + pControl->volume = pSynth->channels[channel].volume; + pControl->pan = pSynth->channels[channel].pan; + pControl->expression = pSynth->channels[channel].expression; + pControl->channelPressure = pSynth->channels[channel].channelPressure; + +#ifdef _REVERB + pControl->reverbSend = pSynth->channels[channel].reverbSend; +#endif + +#ifdef _CHORUSE + pControl->chorusSend = pSynth->channels[channel].chorusSend; +#endif +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePrep should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData) +{ + + /* init counter for voices starts in split architecture */ +#ifdef MAX_VOICE_STARTS + pVoiceMgr->numVoiceStarts = 0; +#endif + + return pFrameInterface->pfStartFrame(pEASData->pVoiceMgr->pFrameBuffer); +} + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePost should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData) +{ + + return pFrameInterface->pfEndFrame(pEASData->pVoiceMgr->pFrameBuffer, pEASData->pMixBuffer, pEASData->masterGain); +} +#endif + +#ifdef TEST_HARNESS +/*---------------------------------------------------------------------------- + * SanityCheck() + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSanityCheck (EAS_DATA_HANDLE pEASData) +{ + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT j; + EAS_INT freeVoices; + EAS_INT activeVoices; + EAS_INT playingVoices; + EAS_INT stolenVoices; + EAS_INT releasingVoices; + EAS_INT mutingVoices; + EAS_INT poolCount[MAX_VIRTUAL_SYNTHESIZERS][NUM_SYNTH_CHANNELS]; + EAS_INT vSynthNum; + EAS_RESULT result = EAS_SUCCESS; + + /* initialize counts */ + EAS_HWMemSet(poolCount, 0, sizeof(poolCount)); + freeVoices = activeVoices = playingVoices = stolenVoices = releasingVoices = mutingVoices = 0; + + /* iterate through all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pEASData->pVoiceMgr->voices[i]; + if (pVoice->voiceState != eVoiceStateFree) + { + vSynthNum = GET_VSYNTH(pVoice->channel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + + switch (pVoice->voiceState) + { + case eVoiceStateMuting: + activeVoices++; + mutingVoices++; + break; + + case eVoiceStateStolen: + vSynthNum = GET_VSYNTH(pVoice->nextChannel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + activeVoices++; + stolenVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool]++; + break; + + case eVoiceStateStart: + case eVoiceStatePlay: + activeVoices++; + playingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + case eVoiceStateRelease: + activeVoices++; + releasingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck : voice %d in invalid state\n", i); */ } + result = EAS_FAILURE; + break; + } + } + + /* count free voices */ + else + freeVoices++; + } + + /* dump state info */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d free\n", freeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d active\n", activeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d playing\n", playingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d releasing\n", releasingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d muting\n", mutingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d stolen\n", stolenVoices); */ } + + if (pEASData->pVoiceMgr->activeVoices != activeVoices) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Active voice mismatch was %d should be %d\n", + pEASData->pVoiceMgr->activeVoices, activeVoices); */ } + result = EAS_FAILURE; + } + + /* check virtual synth status */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pEASData->pVoiceMgr->pSynth[i] == NULL) + continue; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Synth %d numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + if (pEASData->pVoiceMgr->pSynth[i]->numActiveVoices > MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Synth %d illegal count for numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + result = EAS_FAILURE; + } + for (j = 0; j < NUM_SYNTH_CHANNELS; j++) + { + if (poolCount[i][j] != pEASData->pVoiceMgr->pSynth[i]->poolCount[j]) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Pool count mismatch synth %d pool %d, was %d, should be %d\n", + i, j, pEASData->pVoiceMgr->pSynth[i]->poolCount[j], poolCount[i][j]); */ } + result = EAS_FAILURE; + } + } + } + + return result; +} +#endif + + diff --git a/arm-fm-22k/lib_src/eas_wavefile.c b/arm-fm-22k/lib_src/eas_wavefile.c index d3f3ba0..f24bde2 100644 --- a/arm-fm-22k/lib_src/eas_wavefile.c +++ b/arm-fm-22k/lib_src/eas_wavefile.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_wavefile.c
- *
- * Contents and purpose:
- * This file implements the wave file parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.c + * + * Contents and purpose: + * This file implements the wave file parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,849 +19,849 @@ * 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: 852 $
- * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_report.h"
-#include "eas_host.h"
-#include "eas_config.h"
-#include "eas_parser.h"
-#include "eas_pcm.h"
-#include "eas_wavefile.h"
-
-/* lint is choking on the ARM math.h file, so we declare the log10 function here */
-extern double log10(double x);
-
-/* increase gain to compensate for loss in mixer */
-#define WAVE_GAIN_OFFSET 6
-
-/* constant for 1200 / log10(2.0) */
-#define PITCH_CENTS_CONVERSION 3986.313714
-
-/*----------------------------------------------------------------------------
- * WAVE file defines
- *----------------------------------------------------------------------------
-*/
-/* RIFF chunks */
-#define CHUNK_TYPE(a,b,c,d) ( \
- ( ((EAS_U32)(a) & 0xFF) << 24 ) \
- + ( ((EAS_U32)(b) & 0xFF) << 16 ) \
- + ( ((EAS_U32)(c) & 0xFF) << 8 ) \
- + ( ((EAS_U32)(d) & 0xFF) ) )
-
-#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F')
-#define CHUNK_WAVE CHUNK_TYPE('W','A','V','E')
-#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ')
-#define CHUNK_DATA CHUNK_TYPE('d','a','t','a')
-#define CHUNK_LIST CHUNK_TYPE('L','I','S','T')
-#define CHUNK_INFO CHUNK_TYPE('I','N','F','O')
-#define CHUNK_INAM CHUNK_TYPE('I','N','A','M')
-#define CHUNK_ICOP CHUNK_TYPE('I','C','O','P')
-#define CHUNK_IART CHUNK_TYPE('I','A','R','T')
-
-/* wave file format identifiers */
-#define WAVE_FORMAT_PCM 0x0001
-#define WAVE_FORMAT_IMA_ADPCM 0x0011
-
-/* file size for streamed file */
-#define FILE_SIZE_STREAMING 0x80000000
-
-/*----------------------------------------------------------------------------
- * prototypes
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset);
-static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
-static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate);
-static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData);
-static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength);
-
-#ifdef MMAPI_SUPPORT
-static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 size);
-#endif
-
-/*----------------------------------------------------------------------------
- *
- * EAS_Wave_Parser
- *
- * This structure contains the functional interface for the Wave file parser
- *----------------------------------------------------------------------------
-*/
-const S_FILE_PARSER_INTERFACE EAS_Wave_Parser =
-{
- WaveCheckFileType,
- WavePrepare,
- NULL,
- NULL,
- WaveState,
- WaveClose,
- WaveReset,
- WavePause,
- WaveResume,
- WaveLocate,
- WaveSetData,
- WaveGetData,
- WaveGetMetaData
-};
-
-/*----------------------------------------------------------------------------
- * WaveCheckFileType()
- *----------------------------------------------------------------------------
- * Purpose:
- * Check the file type to see if we can parse it
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset)
-{
- S_WAVE_STATE *pWaveData;
-
- /* zero the memory to insure complete initialization */
- *pHandle = NULL;
-
- /* read the file header */
- if (WaveParseHeader(pEASData, fileHandle, NULL) == EAS_SUCCESS)
- {
-
- /* check for static memory allocation */
- if (pEASData->staticMemoryModel)
- pWaveData = EAS_CMEnumData(EAS_CM_WAVE_DATA);
- else
- pWaveData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_WAVE_STATE));
- if (!pWaveData)
- return EAS_ERROR_MALLOC_FAILED;
- EAS_HWMemSet(pWaveData, 0, sizeof(S_WAVE_STATE));
-
- /* return a pointer to the instance data */
- pWaveData->fileHandle = fileHandle;
- pWaveData->fileOffset = offset;
- *pHandle = pWaveData;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WavePrepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_WAVE_STATE *pWaveData;
- EAS_RESULT result;
-
- /* validate parser state */
- pWaveData = (S_WAVE_STATE*) pInstData;
- if (pWaveData->streamHandle != NULL)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* back to start of file */
- pWaveData->time = 0;
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->fileOffset)) != EAS_SUCCESS)
- return result;
-
- /* parse the file header */
- if ((result = WaveParseHeader(pEASData, pWaveData->fileHandle, pWaveData)) != EAS_SUCCESS)
- return result;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveState()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes:
- * This interface is also exposed in the internal library for use by the other modules.
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState)
-{
- S_WAVE_STATE *pWaveData;
-
- /* return current state */
- pWaveData = (S_WAVE_STATE*) pInstData;
- if (pWaveData->streamHandle)
- return EAS_PEState(pEASData, pWaveData->streamHandle, pState);
-
- /* if no stream handle, and time is not zero, we are done */
- if (pWaveData->time > 0)
- *pState = EAS_STATE_STOPPED;
- else
- *pState = EAS_STATE_OPEN;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveClose()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_WAVE_STATE *pWaveData;
- EAS_RESULT result;
-
- pWaveData = (S_WAVE_STATE*) pInstData;
-
- /* close the stream */
- if (pWaveData->streamHandle)
- {
- if ((result = EAS_PEClose(pEASData, pWaveData->streamHandle)) != EAS_SUCCESS)
- return result;
- pWaveData->streamHandle = NULL;
- }
-
- /* if using dynamic memory, free it */
- if (!pEASData->staticMemoryModel)
- {
-
-#ifdef MMAPI_SUPPORT
- /* need to free the fmt chunk */
- if (pWaveData->fmtChunk != NULL)
- EAS_HWFree(pEASData->hwInstData, pWaveData->fmtChunk);
-#endif
-
- /* free the instance data */
- EAS_HWFree(pEASData->hwInstData, pWaveData);
-
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveReset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* reset to first byte of data in the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PEReset(pEASData, streamHandle);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WaveLocate()
- *----------------------------------------------------------------------------
- * Purpose:
- * Rewind/fast-forward in file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * time - time (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pParserLocate) reserved for future use */
-static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* reset to first byte of data in the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PELocate(pEASData, streamHandle, time);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WavePause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback
- * at the end of the next audio frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* pause the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PEPause(pEASData, streamHandle);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WaveResume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume rendering a PCM stream. Sets the gain target back to its
- * previous setting and restarts playback at the end of the next audio
- * frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* resume the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PEResume(pEASData, streamHandle);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WaveSetData()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_WAVE_STATE *pWaveData = (S_WAVE_STATE*) pInstData;
-
- switch (param)
- {
- /* set metadata callback */
- case PARSER_DATA_METADATA_CB:
- EAS_HWMemCpy(&pWaveData->metadata, (void*) value, sizeof(S_METADATA_CB));
- return EAS_SUCCESS;
-
- case PARSER_DATA_PLAYBACK_RATE:
- value = (EAS_I32) (PITCH_CENTS_CONVERSION * log10((double) value / (double) (1 << 28)));
- return EAS_PEUpdatePitch(pEASData, pWaveData->streamHandle, (EAS_I16) value);
-
- case PARSER_DATA_VOLUME:
- return EAS_PEUpdateVolume(pEASData, pWaveData->streamHandle, (EAS_I16) value);
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-}
-
-/*----------------------------------------------------------------------------
- * WaveGetData()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_WAVE_STATE *pWaveData;
-
- pWaveData = (S_WAVE_STATE*) pInstData;
- switch (param)
- {
- /* return file type as WAVE */
- case PARSER_DATA_FILE_TYPE:
- *pValue = pWaveData->fileType;
- break;
-
-#ifdef MMAPI_SUPPORT
- /* return pointer to 'fmt' chunk */
- case PARSER_DATA_FORMAT:
- *pValue = (EAS_I32) pWaveData->fmtChunk;
- break;
-#endif
-
- case PARSER_DATA_GAIN_OFFSET:
- *pValue = WAVE_GAIN_OFFSET;
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveParseHeader()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the WAVE file header.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData)
-{
- S_PCM_OPEN_PARAMS params;
- EAS_RESULT result;
- EAS_U32 tag;
- EAS_U32 fileSize;
- EAS_U32 size;
- EAS_I32 pos;
- EAS_I32 audioOffset;
- EAS_U16 usTemp;
- EAS_BOOL parseDone;
- EAS_U32 avgBytesPerSec;
-
- /* init some data (and keep lint happy) */
- params.sampleRate = 0;
- params.size = 0;
- audioOffset = 0;
- params.decoder = 0;
- params.blockSize = 0;
- params.pCallbackFunc = NULL;
- params.cbInstData = NULL;
- params.loopSamples = 0;
- params.fileHandle = fileHandle;
- params.volume = 0x7fff;
- params.envData = 0;
- avgBytesPerSec = 8000;
-
- /* check for 'RIFF' tag */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if (tag != CHUNK_RIFF)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* get size */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &fileSize, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* check for 'WAVE' tag */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if (tag != CHUNK_WAVE)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* this is enough to say we recognize the file */
- if (pWaveData == NULL)
- return EAS_SUCCESS;
-
- /* check for streaming mode */
- pWaveData->flags = 0;
- pWaveData->mediaLength = -1;
- pWaveData->infoChunkPos = -1;
- pWaveData->infoChunkSize = -1;
- if (fileSize== FILE_SIZE_STREAMING)
- {
- pWaveData->flags |= PCM_FLAGS_STREAMING;
- fileSize = 0x7fffffff;
- }
-
- /* find out where we're at */
- if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS)
- return result;
- fileSize -= 4;
-
- parseDone = EAS_FALSE;
- for (;;)
- {
- /* get tag and size for next chunk */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &size, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* process chunk */
- pos += 8;
- switch (tag)
- {
- case CHUNK_FMT:
-
-#ifdef MMAPI_SUPPORT
- if ((result = SaveFmtChunk(pEASData, fileHandle, pWaveData, (EAS_I32) size)) != EAS_SUCCESS)
- return result;
-#endif
-
- /* get audio format */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
- if (usTemp == WAVE_FORMAT_PCM)
- {
- params.decoder = EAS_DECODER_PCM;
- pWaveData->fileType = EAS_FILE_WAVE_PCM;
- }
- else if (usTemp == WAVE_FORMAT_IMA_ADPCM)
- {
- params.decoder = EAS_DECODER_IMA_ADPCM;
- pWaveData->fileType = EAS_FILE_WAVE_IMA_ADPCM;
- }
- else
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* get number of channels */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
- if (usTemp == 2)
- pWaveData->flags |= PCM_FLAGS_STEREO;
- else if (usTemp != 1)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* get sample rate */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, ¶ms.sampleRate, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* get stream rate */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &avgBytesPerSec, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* get block alignment */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
- params.blockSize = usTemp;
-
- /* get bits per sample */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* PCM, must be 8 or 16 bit samples */
- if (params.decoder == EAS_DECODER_PCM)
- {
- if (usTemp == 8)
- pWaveData->flags |= PCM_FLAGS_8_BIT | PCM_FLAGS_UNSIGNED;
- else if (usTemp != 16)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
- }
-
- /* for IMA ADPCM, we only support mono 4-bit ADPCM */
- else
- {
- if ((usTemp != 4) || (pWaveData->flags & PCM_FLAGS_STEREO))
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
- }
-
- break;
-
- case CHUNK_DATA:
- audioOffset = pos;
- if (pWaveData->flags & PCM_FLAGS_STREAMING)
- {
- params.size = 0x7fffffff;
- parseDone = EAS_TRUE;
- }
- else
- {
- params.size = (EAS_I32) size;
- params.loopStart = size;
- /* use more accurate method if possible */
- if (size <= (0x7fffffff / 1000))
- pWaveData->mediaLength = (EAS_I32) ((size * 1000) / avgBytesPerSec);
- else
- pWaveData->mediaLength = (EAS_I32) (size / (avgBytesPerSec / 1000));
- }
- break;
-
- case CHUNK_LIST:
- /* get the list type */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if (tag == CHUNK_INFO)
- {
- pWaveData->infoChunkPos = pos + 4;
- pWaveData->infoChunkSize = (EAS_I32) size - 4;
- }
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n",
- (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
- break;
- }
-
- if (parseDone)
- break;
-
- /* subtract header size */
- fileSize -= 8;
-
- /* account for zero-padding on odd length chunks */
- if (size & 1)
- size++;
-
- /* this check works for files with odd length last chunk and no zero-pad */
- if (size >= fileSize)
- {
- if (size > fileSize)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: '%c%c%c%c' chunk size exceeds length of file or is not zero-padded\n",
- (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
- break;
- }
-
- /* subtract size of data chunk (including any zero-pad) */
- fileSize -= size;
-
- /* seek to next chunk */
- pos += (EAS_I32) size;
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos)) != EAS_SUCCESS)
- return result;
- }
-
- /* check for valid header */
- if ((params.sampleRate == 0) || (params.size == 0))
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* save the pertinent information */
- pWaveData->audioOffset = audioOffset;
- params.flags = pWaveData->flags;
-
- /* seek to data */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, audioOffset)) != EAS_SUCCESS)
- return result;
-
- /* open a stream in the PCM engine */
- return EAS_PEOpenStream(pEASData, ¶ms, &pWaveData->streamHandle);
-}
-
-/*----------------------------------------------------------------------------
- * WaveGetMetaData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Process the INFO chunk and return metadata to host
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength)
-{
- S_WAVE_STATE *pWaveData;
- EAS_RESULT result;
- EAS_I32 pos;
- EAS_U32 size;
- EAS_I32 infoSize;
- EAS_U32 tag;
- EAS_I32 restorePos;
- E_EAS_METADATA_TYPE metaType;
- EAS_I32 metaLen;
-
- /* get current position so we can restore it */
- pWaveData = (S_WAVE_STATE*) pInstData;
-
- /* return media length */
- *pMediaLength = pWaveData->mediaLength;
-
- /* did we encounter an INFO chunk? */
- if (pWaveData->infoChunkPos < 0)
- return EAS_SUCCESS;
-
- if ((result = EAS_HWFilePos(pEASData->hwInstData, pWaveData->fileHandle, &restorePos)) != EAS_SUCCESS)
- return result;
-
- /* offset to start of first chunk in INFO chunk */
- pos = pWaveData->infoChunkPos;
- infoSize = pWaveData->infoChunkSize;
-
- /* read all the chunks in the INFO chunk */
- for (;;)
- {
-
- /* seek to next chunk */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pos)) != EAS_SUCCESS)
- return result;
-
- /* get tag and size for next chunk */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &size, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* process chunk */
- pos += 8;
- metaType = EAS_METADATA_UNKNOWN;
- switch (tag)
- {
- case CHUNK_INAM:
- metaType = EAS_METADATA_TITLE;
- break;
-
- case CHUNK_IART:
- metaType = EAS_METADATA_AUTHOR;
- break;
-
- case CHUNK_ICOP:
- metaType = EAS_METADATA_COPYRIGHT;
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n",
- (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
- break;
- }
-
- /* process known metadata */
- if (metaType != EAS_METADATA_UNKNOWN)
- {
- metaLen = pWaveData->metadata.bufferSize - 1;
- if (metaLen > (EAS_I32) size)
- metaLen = (EAS_I32) size;
- if ((result = EAS_HWReadFile(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->metadata.buffer, metaLen, &metaLen)) != EAS_SUCCESS)
- return result;
- pWaveData->metadata.buffer[metaLen] = 0;
- pWaveData->metadata.callback(metaType, pWaveData->metadata.buffer, pWaveData->metadata.pUserData);
- }
-
- /* subtract this block */
- if (size & 1)
- size++;
- infoSize -= (EAS_I32) size + 8;
- if (infoSize == 0)
- break;
- pos += (EAS_I32) size;
- }
-
-
- /* restore original position */
- return EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, restorePos);
-}
-
-#ifdef MMAPI_SUPPORT
-/*----------------------------------------------------------------------------
- * SaveFmtChunk()
- *----------------------------------------------------------------------------
- * Purpose:
- * Save the fmt chunk for the MMAPI library
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 fmtSize)
-{
- EAS_RESULT result;
- EAS_I32 pos;
- EAS_I32 count;
-
- /* save current file position */
- if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS)
- return result;
-
- /* allocate a chunk of memory */
- pWaveData->fmtChunk = EAS_HWMalloc(pEASData->hwInstData, fmtSize);
- if (!pWaveData->fmtChunk)
- return EAS_ERROR_MALLOC_FAILED;
-
- /* read the fmt chunk into memory */
- if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, pWaveData->fmtChunk, fmtSize, &count)) != EAS_SUCCESS)
- return result;
- if (count != fmtSize)
- return EAS_ERROR_FILE_READ_FAILED;
-
- /* restore file position */
- return EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos);
-}
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_wavefile.h" + +/* lint is choking on the ARM math.h file, so we declare the log10 function here */ +extern double log10(double x); + +/* increase gain to compensate for loss in mixer */ +#define WAVE_GAIN_OFFSET 6 + +/* constant for 1200 / log10(2.0) */ +#define PITCH_CENTS_CONVERSION 3986.313714 + +/*---------------------------------------------------------------------------- + * WAVE file defines + *---------------------------------------------------------------------------- +*/ +/* RIFF chunks */ +#define CHUNK_TYPE(a,b,c,d) ( \ + ( ((EAS_U32)(a) & 0xFF) << 24 ) \ + + ( ((EAS_U32)(b) & 0xFF) << 16 ) \ + + ( ((EAS_U32)(c) & 0xFF) << 8 ) \ + + ( ((EAS_U32)(d) & 0xFF) ) ) + +#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F') +#define CHUNK_WAVE CHUNK_TYPE('W','A','V','E') +#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ') +#define CHUNK_DATA CHUNK_TYPE('d','a','t','a') +#define CHUNK_LIST CHUNK_TYPE('L','I','S','T') +#define CHUNK_INFO CHUNK_TYPE('I','N','F','O') +#define CHUNK_INAM CHUNK_TYPE('I','N','A','M') +#define CHUNK_ICOP CHUNK_TYPE('I','C','O','P') +#define CHUNK_IART CHUNK_TYPE('I','A','R','T') + +/* wave file format identifiers */ +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_IMA_ADPCM 0x0011 + +/* file size for streamed file */ +#define FILE_SIZE_STREAMING 0x80000000 + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset); +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData); +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); + +#ifdef MMAPI_SUPPORT +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 size); +#endif + +/*---------------------------------------------------------------------------- + * + * EAS_Wave_Parser + * + * This structure contains the functional interface for the Wave file parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_Wave_Parser = +{ + WaveCheckFileType, + WavePrepare, + NULL, + NULL, + WaveState, + WaveClose, + WaveReset, + WavePause, + WaveResume, + WaveLocate, + WaveSetData, + WaveGetData, + WaveGetMetaData +}; + +/*---------------------------------------------------------------------------- + * WaveCheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset) +{ + S_WAVE_STATE *pWaveData; + + /* zero the memory to insure complete initialization */ + *pHandle = NULL; + + /* read the file header */ + if (WaveParseHeader(pEASData, fileHandle, NULL) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pWaveData = EAS_CMEnumData(EAS_CM_WAVE_DATA); + else + pWaveData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_WAVE_STATE)); + if (!pWaveData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pWaveData, 0, sizeof(S_WAVE_STATE)); + + /* return a pointer to the instance data */ + pWaveData->fileHandle = fileHandle; + pWaveData->fileOffset = offset; + *pHandle = pWaveData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WavePrepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + /* validate parser state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle != NULL) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* back to start of file */ + pWaveData->time = 0; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->fileOffset)) != EAS_SUCCESS) + return result; + + /* parse the file header */ + if ((result = WaveParseHeader(pEASData, pWaveData->fileHandle, pWaveData)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState) +{ + S_WAVE_STATE *pWaveData; + + /* return current state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle) + return EAS_PEState(pEASData, pWaveData->streamHandle, pState); + + /* if no stream handle, and time is not zero, we are done */ + if (pWaveData->time > 0) + *pState = EAS_STATE_STOPPED; + else + *pState = EAS_STATE_OPEN; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + pWaveData = (S_WAVE_STATE*) pInstData; + + /* close the stream */ + if (pWaveData->streamHandle) + { + if ((result = EAS_PEClose(pEASData, pWaveData->streamHandle)) != EAS_SUCCESS) + return result; + pWaveData->streamHandle = NULL; + } + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + +#ifdef MMAPI_SUPPORT + /* need to free the fmt chunk */ + if (pWaveData->fmtChunk != NULL) + EAS_HWFree(pEASData->hwInstData, pWaveData->fmtChunk); +#endif + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pWaveData); + + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEReset(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Rewind/fast-forward in file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * time - time (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pParserLocate) reserved for future use */ +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PELocate(pEASData, streamHandle, time); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WavePause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* pause the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEPause(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* resume the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEResume(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveSetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_WAVE_STATE *pWaveData = (S_WAVE_STATE*) pInstData; + + switch (param) + { + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pWaveData->metadata, (void*) value, sizeof(S_METADATA_CB)); + return EAS_SUCCESS; + + case PARSER_DATA_PLAYBACK_RATE: + value = (EAS_I32) (PITCH_CENTS_CONVERSION * log10((double) value / (double) (1 << 28))); + return EAS_PEUpdatePitch(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + case PARSER_DATA_VOLUME: + return EAS_PEUpdateVolume(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + default: + return EAS_ERROR_INVALID_PARAMETER; + } +} + +/*---------------------------------------------------------------------------- + * WaveGetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_WAVE_STATE *pWaveData; + + pWaveData = (S_WAVE_STATE*) pInstData; + switch (param) + { + /* return file type as WAVE */ + case PARSER_DATA_FILE_TYPE: + *pValue = pWaveData->fileType; + break; + +#ifdef MMAPI_SUPPORT + /* return pointer to 'fmt' chunk */ + case PARSER_DATA_FORMAT: + *pValue = (EAS_I32) pWaveData->fmtChunk; + break; +#endif + + case PARSER_DATA_GAIN_OFFSET: + *pValue = WAVE_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the WAVE file header. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData) +{ + S_PCM_OPEN_PARAMS params; + EAS_RESULT result; + EAS_U32 tag; + EAS_U32 fileSize; + EAS_U32 size; + EAS_I32 pos; + EAS_I32 audioOffset; + EAS_U16 usTemp; + EAS_BOOL parseDone; + EAS_U32 avgBytesPerSec; + + /* init some data (and keep lint happy) */ + params.sampleRate = 0; + params.size = 0; + audioOffset = 0; + params.decoder = 0; + params.blockSize = 0; + params.pCallbackFunc = NULL; + params.cbInstData = NULL; + params.loopSamples = 0; + params.fileHandle = fileHandle; + params.volume = 0x7fff; + params.envData = 0; + avgBytesPerSec = 8000; + + /* check for 'RIFF' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_RIFF) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get size */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &fileSize, EAS_FALSE)) != EAS_FALSE) + return result; + + /* check for 'WAVE' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_WAVE) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* this is enough to say we recognize the file */ + if (pWaveData == NULL) + return EAS_SUCCESS; + + /* check for streaming mode */ + pWaveData->flags = 0; + pWaveData->mediaLength = -1; + pWaveData->infoChunkPos = -1; + pWaveData->infoChunkSize = -1; + if (fileSize== FILE_SIZE_STREAMING) + { + pWaveData->flags |= PCM_FLAGS_STREAMING; + fileSize = 0x7fffffff; + } + + /* find out where we're at */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + fileSize -= 4; + + parseDone = EAS_FALSE; + for (;;) + { + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + switch (tag) + { + case CHUNK_FMT: + +#ifdef MMAPI_SUPPORT + if ((result = SaveFmtChunk(pEASData, fileHandle, pWaveData, (EAS_I32) size)) != EAS_SUCCESS) + return result; +#endif + + /* get audio format */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == WAVE_FORMAT_PCM) + { + params.decoder = EAS_DECODER_PCM; + pWaveData->fileType = EAS_FILE_WAVE_PCM; + } + else if (usTemp == WAVE_FORMAT_IMA_ADPCM) + { + params.decoder = EAS_DECODER_IMA_ADPCM; + pWaveData->fileType = EAS_FILE_WAVE_IMA_ADPCM; + } + else + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get number of channels */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == 2) + pWaveData->flags |= PCM_FLAGS_STEREO; + else if (usTemp != 1) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get sample rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, ¶ms.sampleRate, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get stream rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &avgBytesPerSec, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get block alignment */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + params.blockSize = usTemp; + + /* get bits per sample */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + + /* PCM, must be 8 or 16 bit samples */ + if (params.decoder == EAS_DECODER_PCM) + { + if (usTemp == 8) + pWaveData->flags |= PCM_FLAGS_8_BIT | PCM_FLAGS_UNSIGNED; + else if (usTemp != 16) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* for IMA ADPCM, we only support mono 4-bit ADPCM */ + else + { + if ((usTemp != 4) || (pWaveData->flags & PCM_FLAGS_STEREO)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + break; + + case CHUNK_DATA: + audioOffset = pos; + if (pWaveData->flags & PCM_FLAGS_STREAMING) + { + params.size = 0x7fffffff; + parseDone = EAS_TRUE; + } + else + { + params.size = (EAS_I32) size; + params.loopStart = size; + /* use more accurate method if possible */ + if (size <= (0x7fffffff / 1000)) + pWaveData->mediaLength = (EAS_I32) ((size * 1000) / avgBytesPerSec); + else + pWaveData->mediaLength = (EAS_I32) (size / (avgBytesPerSec / 1000)); + } + break; + + case CHUNK_LIST: + /* get the list type */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag == CHUNK_INFO) + { + pWaveData->infoChunkPos = pos + 4; + pWaveData->infoChunkSize = (EAS_I32) size - 4; + } + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + if (parseDone) + break; + + /* subtract header size */ + fileSize -= 8; + + /* account for zero-padding on odd length chunks */ + if (size & 1) + size++; + + /* this check works for files with odd length last chunk and no zero-pad */ + if (size >= fileSize) + { + if (size > fileSize) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: '%c%c%c%c' chunk size exceeds length of file or is not zero-padded\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* subtract size of data chunk (including any zero-pad) */ + fileSize -= size; + + /* seek to next chunk */ + pos += (EAS_I32) size; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos)) != EAS_SUCCESS) + return result; + } + + /* check for valid header */ + if ((params.sampleRate == 0) || (params.size == 0)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* save the pertinent information */ + pWaveData->audioOffset = audioOffset; + params.flags = pWaveData->flags; + + /* seek to data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, audioOffset)) != EAS_SUCCESS) + return result; + + /* open a stream in the PCM engine */ + return EAS_PEOpenStream(pEASData, ¶ms, &pWaveData->streamHandle); +} + +/*---------------------------------------------------------------------------- + * WaveGetMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Process the INFO chunk and return metadata to host + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + EAS_I32 pos; + EAS_U32 size; + EAS_I32 infoSize; + EAS_U32 tag; + EAS_I32 restorePos; + E_EAS_METADATA_TYPE metaType; + EAS_I32 metaLen; + + /* get current position so we can restore it */ + pWaveData = (S_WAVE_STATE*) pInstData; + + /* return media length */ + *pMediaLength = pWaveData->mediaLength; + + /* did we encounter an INFO chunk? */ + if (pWaveData->infoChunkPos < 0) + return EAS_SUCCESS; + + if ((result = EAS_HWFilePos(pEASData->hwInstData, pWaveData->fileHandle, &restorePos)) != EAS_SUCCESS) + return result; + + /* offset to start of first chunk in INFO chunk */ + pos = pWaveData->infoChunkPos; + infoSize = pWaveData->infoChunkSize; + + /* read all the chunks in the INFO chunk */ + for (;;) + { + + /* seek to next chunk */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + metaType = EAS_METADATA_UNKNOWN; + switch (tag) + { + case CHUNK_INAM: + metaType = EAS_METADATA_TITLE; + break; + + case CHUNK_IART: + metaType = EAS_METADATA_AUTHOR; + break; + + case CHUNK_ICOP: + metaType = EAS_METADATA_COPYRIGHT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* process known metadata */ + if (metaType != EAS_METADATA_UNKNOWN) + { + metaLen = pWaveData->metadata.bufferSize - 1; + if (metaLen > (EAS_I32) size) + metaLen = (EAS_I32) size; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->metadata.buffer, metaLen, &metaLen)) != EAS_SUCCESS) + return result; + pWaveData->metadata.buffer[metaLen] = 0; + pWaveData->metadata.callback(metaType, pWaveData->metadata.buffer, pWaveData->metadata.pUserData); + } + + /* subtract this block */ + if (size & 1) + size++; + infoSize -= (EAS_I32) size + 8; + if (infoSize == 0) + break; + pos += (EAS_I32) size; + } + + + /* restore original position */ + return EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, restorePos); +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * SaveFmtChunk() + *---------------------------------------------------------------------------- + * Purpose: + * Save the fmt chunk for the MMAPI library + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 fmtSize) +{ + EAS_RESULT result; + EAS_I32 pos; + EAS_I32 count; + + /* save current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + + /* allocate a chunk of memory */ + pWaveData->fmtChunk = EAS_HWMalloc(pEASData->hwInstData, fmtSize); + if (!pWaveData->fmtChunk) + return EAS_ERROR_MALLOC_FAILED; + + /* read the fmt chunk into memory */ + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, pWaveData->fmtChunk, fmtSize, &count)) != EAS_SUCCESS) + return result; + if (count != fmtSize) + return EAS_ERROR_FILE_READ_FAILED; + + /* restore file position */ + return EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos); +} +#endif + diff --git a/arm-fm-22k/lib_src/eas_wavefile.h b/arm-fm-22k/lib_src/eas_wavefile.h index b8b76df..f8814a8 100644 --- a/arm-fm-22k/lib_src/eas_wavefile.h +++ b/arm-fm-22k/lib_src/eas_wavefile.h @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_wavefile.h
- *
- * Contents and purpose:
- * Static data block for wave file parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.h + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,45 +19,45 @@ * 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: 439 $
- * $Date: 2006-10-26 11:53:18 -0700 (Thu, 26 Oct 2006) $
- *----------------------------------------------------------------------------
-*/
-
-#ifndef _EAS_WAVEFILE_H
-#define _EAS_WAVEFILE_H
-
-#include "eas_data.h"
-#include "eas_pcm.h"
-
-/*----------------------------------------------------------------------------
- *
- * S_WAVE_STATE
- *
- * This structure contains the WAVE file parser state information
- *----------------------------------------------------------------------------
-*/
-typedef struct s_wave_state_tag
-{
- EAS_FILE_HANDLE fileHandle;
- EAS_PCM_HANDLE streamHandle;
- S_METADATA_CB metadata;
- EAS_U32 time;
- EAS_I32 fileOffset;
- EAS_I32 audioOffset;
- EAS_I32 mediaLength;
- EAS_U32 audioSize;
- EAS_U32 flags;
- EAS_I16 fileType;
-#ifdef MMAPI_SUPPORT
- EAS_VOID_PTR fmtChunk;
-#endif
- EAS_I32 infoChunkPos;
- EAS_I32 infoChunkSize;
-} S_WAVE_STATE;
-
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 439 $ + * $Date: 2006-10-26 11:53:18 -0700 (Thu, 26 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WAVEFILE_H +#define _EAS_WAVEFILE_H + +#include "eas_data.h" +#include "eas_pcm.h" + +/*---------------------------------------------------------------------------- + * + * S_WAVE_STATE + * + * This structure contains the WAVE file parser state information + *---------------------------------------------------------------------------- +*/ +typedef struct s_wave_state_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_PCM_HANDLE streamHandle; + S_METADATA_CB metadata; + EAS_U32 time; + EAS_I32 fileOffset; + EAS_I32 audioOffset; + EAS_I32 mediaLength; + EAS_U32 audioSize; + EAS_U32 flags; + EAS_I16 fileType; +#ifdef MMAPI_SUPPORT + EAS_VOID_PTR fmtChunk; +#endif + EAS_I32 infoChunkPos; + EAS_I32 infoChunkSize; +} S_WAVE_STATE; + +#endif + diff --git a/arm-fm-22k/lib_src/eas_wavefiledata.c b/arm-fm-22k/lib_src/eas_wavefiledata.c index 3742aa6..c224a6c 100644 --- a/arm-fm-22k/lib_src/eas_wavefiledata.c +++ b/arm-fm-22k/lib_src/eas_wavefiledata.c @@ -1,12 +1,12 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_wavefiledata.c
- *
- * Contents and purpose:
- * Static data block for wave file parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefiledata.c + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,15 @@ * 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: 547 $
- * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_wavefile.h"
-
-S_WAVE_STATE eas_WaveData;
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_wavefile.h" + +S_WAVE_STATE eas_WaveData; + |