From 7df30109963092559d3760c0661a020f9daf1030 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:30:38 -0800 Subject: auto import from //depot/cupcake/@135843 --- arm-wt-22k/lib_src/eas_mdls.c | 2668 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2668 insertions(+) create mode 100644 arm-wt-22k/lib_src/eas_mdls.c (limited to 'arm-wt-22k/lib_src/eas_mdls.c') diff --git a/arm-wt-22k/lib_src/eas_mdls.c b/arm-wt-22k/lib_src/eas_mdls.c new file mode 100644 index 0000000..3da3b06 --- /dev/null +++ b/arm-wt-22k/lib_src/eas_mdls.c @@ -0,0 +1,2668 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mdls.c + * + * Contents and purpose: + * This file contains DLS to EAS converter. + * + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* + * NOTES: + * + * Processor Endian-ness: + * + * We use the EAS_HWGetDWord() and EAS_HWGetWord () functions + * extensively in this module. It would probably be faster to read + * an entire data structure, but this introduces the problem of + * sensitivity to processor endian-ness to the parser. By utlilizing + * the host wrapper functions, we avoid having to flip bytes around + * for big-endian processors. The default host wrapper versions of + * these functions are insensitive to processor endian-ness due to + * the fact that they read the file as a byte stream. + * + * Dynamic Memory: + * + * Dynamic memory allocation is a risky proposition in a mobile + * device. The memory can become fragmented, resulting in an + * inability to allocate a memory block, or garbage collection + * routines can use many CPU cycles. Either can contribute to + * failures of critical systems. Therefore, we try to minimize the + * number of memory allocations we make. + * + * We allocate a single large block of memory for the entire + * converted DLS collection, including the articulation data and + * samples. This block is then sub-allocated for the various + * data structures. + * + * Parser Overview: + * + * We make two passes through the file, the first pass to count the + * number of instruments, regions, etc. and allocate memory for + * them. The second pass parses the data into the allocated data + * structures. + * + * Conditional chunks are challenging in that they can occur + * anywhere in the list chunk that contains them. To simplify, we + * parse the blocks in a list in specific order, no matter which + * order they appear in the file. This way we don't allocate memory + * and parse a block that we end up throwing away later due to + * a conditional chunk. + * + * Assumptions that may bite us in the future: + * + * We make some assumptions to simplify things. The most fundamental + * assumption is that there will be no more than one of any type of + * chunk in a list. While this is consistent with the block diagram + * of the file layout in the mDLS spec, there is nothing in the + * spec that precludes having mulitple lar2 or rgn2 chunks, with + * conditional blocks that dictate their usage. + * + * DLS -> EAS Conversion Process: + * + * Another challenge is that the DLS structure does not map well to + * the current EAS sound library structure. Not all DLS constructs + * are supported, and data from DLS structures must sometimes be + * mapped to multiple EAS data structures. To simplify the process, + * the EAS region, articulation, and envelopes are treated as a + * single combined unit. Thus for each region, there must be one + * articulation element and two envelope elements. + * + * The sample processing is also a multi-step process. First the + * ptbl chunk is pre-parsed to determine the number of samples + * in the collection. The next step is to parse the instrument data + * to determine which samples are actually used by instruments. + * Some samples may not be used because they are used only in + * conditional blocks that the synthesizer cannot parse, or the + * author neglected to remove unused samples from the collection. + * In the next step, the active samples are read into memory and + * converted to the appropriate playback format. Finally, as the + * instruments are processed, the links are made to the samples and + * wsmp data is extracted for the region and articulation data + * structures. +*/ + +#ifndef _FILTER_ENABLED +#error "Filter must be enabled if DLS_SYNTHESIZER is enabled" +#endif + +/*------------------------------------ + * includes + *------------------------------------ +*/ + +/* this define allows us to use the sndlib.h structures as RW memory */ +#define SCNST + +#include "eas_data.h" +#include "eas_host.h" +#include "eas_mdls.h" +#include "eas_math.h" +#include "dls.h" +#include "dls2.h" +#include "eas_report.h" + +//2 we should replace log10() function with fixed point routine in ConvertSampleRate() +/* lint is choking on the ARM math.h file, so we declare the log10 function here */ +extern double log10(double x); + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +// #define _DEBUG_DLS + +#define DLS_MAX_WAVE_COUNT 1024 +#define DLS_MAX_ART_COUNT 2048 +#define DLS_MAX_REGION_COUNT 2048 +#define DLS_MAX_INST_COUNT 256 +#define MAX_DLS_WAVE_SIZE (1024*1024) + +/*------------------------------------ + * typedefs + *------------------------------------ +*/ + +/* offsets to articulation data */ +typedef enum +{ + PARAM_MODIFIED = 0, + PARAM_MOD_LFO_FREQ, + PARAM_MOD_LFO_DELAY, + + PARAM_VIB_LFO_FREQ, + PARAM_VIB_LFO_DELAY, + + PARAM_VOL_EG_DELAY, + PARAM_VOL_EG_ATTACK, + PARAM_VOL_EG_HOLD, + PARAM_VOL_EG_DECAY, + PARAM_VOL_EG_SUSTAIN, + PARAM_VOL_EG_RELEASE, + PARAM_VOL_EG_SHUTDOWN, + PARAM_VOL_EG_VEL_TO_ATTACK, + PARAM_VOL_EG_KEY_TO_DECAY, + PARAM_VOL_EG_KEY_TO_HOLD, + + PARAM_MOD_EG_DELAY, + PARAM_MOD_EG_ATTACK, + PARAM_MOD_EG_HOLD, + PARAM_MOD_EG_DECAY, + PARAM_MOD_EG_SUSTAIN, + PARAM_MOD_EG_RELEASE, + PARAM_MOD_EG_VEL_TO_ATTACK, + PARAM_MOD_EG_KEY_TO_DECAY, + PARAM_MOD_EG_KEY_TO_HOLD, + + PARAM_INITIAL_FC, + PARAM_INITIAL_Q, + PARAM_MOD_LFO_TO_FC, + PARAM_MOD_LFO_CC1_TO_FC, + PARAM_MOD_LFO_CHAN_PRESS_TO_FC, + PARAM_MOD_EG_TO_FC, + PARAM_VEL_TO_FC, + PARAM_KEYNUM_TO_FC, + + PARAM_MOD_LFO_TO_GAIN, + PARAM_MOD_LFO_CC1_TO_GAIN, + PARAM_MOD_LFO_CHAN_PRESS_TO_GAIN, + PARAM_VEL_TO_GAIN, + + PARAM_TUNING, + PARAM_KEYNUM_TO_PITCH, + PARAM_VIB_LFO_TO_PITCH, + PARAM_VIB_LFO_CC1_TO_PITCH, + PARAM_VIB_LFO_CHAN_PRESS_TO_PITCH, + PARAM_MOD_LFO_TO_PITCH, + PARAM_MOD_LFO_CC1_TO_PITCH, + PARAM_MOD_LFO_CHAN_PRESS_TO_PITCH, + PARAM_MOD_EG_TO_PITCH, + + PARAM_DEFAULT_PAN, + PARAM_MIDI_CC91_TO_REVERB_SEND, + PARAM_DEFAULT_REVERB_SEND, + PARAM_MIDI_CC93_TO_CHORUS_SEND, + PARAM_DEFAULT_CHORUS_SEND, + PARAM_TABLE_SIZE +} E_ART_INDEX; + +/* temporary data structure combining region, articulation, and envelope data */ +typedef struct s_art_dls_tag +{ + EAS_I16 values[PARAM_TABLE_SIZE]; +} S_DLS_ART_VALUES; + +/* temporary data structure for wlnk chunk data */ +typedef struct +{ + EAS_I32 gain; + EAS_U32 loopStart; + EAS_U32 loopLength; + EAS_U32 sampleRate; + EAS_U16 bitsPerSample; + EAS_I16 fineTune; + EAS_U8 unityNote; +} S_WSMP_DATA; + +/* temporary data structure used while parsing a DLS file */ +typedef struct +{ + S_DLS *pDLS; + EAS_HW_DATA_HANDLE hwInstData; + EAS_FILE_HANDLE fileHandle; + S_WSMP_DATA *wsmpData; + EAS_U32 instCount; + EAS_U32 regionCount; + EAS_U32 artCount; + EAS_U32 waveCount; + EAS_U32 wavePoolSize; + EAS_U32 wavePoolOffset; + EAS_BOOL bigEndian; + EAS_BOOL filterUsed; +} SDLS_SYNTHESIZER_DATA; + +/* connection lookup table */ +typedef struct s_connection_tag +{ + EAS_U16 source; + EAS_U16 control; + EAS_U16 destination; + EAS_U16 connection; +} S_CONNECTION; + +static const S_CONNECTION connTable[] = +{ + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_FREQUENCY, PARAM_MOD_LFO_FREQ }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_STARTDELAY, PARAM_MOD_LFO_DELAY}, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_VIB_FREQUENCY, PARAM_VIB_LFO_FREQ }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_VIB_STARTDELAY, PARAM_VIB_LFO_DELAY }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_DELAYTIME, PARAM_VOL_EG_DELAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_ATTACKTIME, PARAM_VOL_EG_ATTACK }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_HOLDTIME, PARAM_VOL_EG_HOLD }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_DECAYTIME, PARAM_VOL_EG_DECAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_SUSTAINLEVEL, PARAM_VOL_EG_SUSTAIN }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_RELEASETIME, PARAM_VOL_EG_RELEASE }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_SHUTDOWNTIME, PARAM_VOL_EG_SHUTDOWN }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_EG1_ATTACKTIME, PARAM_VOL_EG_VEL_TO_ATTACK }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG1_DECAYTIME, PARAM_VOL_EG_KEY_TO_DECAY }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG1_HOLDTIME, PARAM_VOL_EG_KEY_TO_HOLD }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_DELAYTIME, PARAM_MOD_EG_DELAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_ATTACKTIME, PARAM_MOD_EG_ATTACK }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_HOLDTIME, PARAM_MOD_EG_HOLD }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_DECAYTIME, PARAM_MOD_EG_DECAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_SUSTAINLEVEL, PARAM_MOD_EG_SUSTAIN }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_RELEASETIME, PARAM_MOD_EG_RELEASE }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_EG2_ATTACKTIME, PARAM_MOD_EG_VEL_TO_ATTACK }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG2_DECAYTIME, PARAM_MOD_EG_KEY_TO_DECAY }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG2_HOLDTIME, PARAM_MOD_EG_KEY_TO_HOLD }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_INITIAL_FC }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_FILTER_Q, PARAM_INITIAL_Q }, + { CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_MOD_LFO_TO_FC }, + { CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_FILTER_CUTOFF, PARAM_MOD_LFO_CC1_TO_FC }, + { CONN_SRC_LFO, CONN_SRC_CHANNELPRESSURE, CONN_DST_FILTER_CUTOFF, PARAM_MOD_LFO_CHAN_PRESS_TO_FC }, + { CONN_SRC_EG2, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_MOD_EG_TO_FC }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_VEL_TO_FC }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_KEYNUM_TO_FC }, + + { CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_GAIN, PARAM_MOD_LFO_TO_GAIN }, + { CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_GAIN, PARAM_MOD_LFO_CC1_TO_GAIN }, + { CONN_SRC_LFO, CONN_SRC_CHANNELPRESSURE, CONN_DST_GAIN, PARAM_MOD_LFO_CHAN_PRESS_TO_GAIN }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_GAIN, PARAM_VEL_TO_GAIN }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_TUNING }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_KEYNUM_TO_PITCH }, + { CONN_SRC_VIBRATO, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_VIB_LFO_TO_PITCH }, + { CONN_SRC_VIBRATO, CONN_SRC_CC1, CONN_DST_PITCH, PARAM_VIB_LFO_CC1_TO_PITCH }, + { CONN_SRC_VIBRATO, CONN_SRC_CHANNELPRESSURE, CONN_DST_PITCH, PARAM_VIB_LFO_CHAN_PRESS_TO_PITCH }, + { CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_MOD_LFO_TO_PITCH }, + { CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_PITCH, PARAM_MOD_LFO_CC1_TO_PITCH }, + { CONN_SRC_LFO, CONN_SRC_CHANNELPRESSURE, CONN_DST_PITCH, PARAM_MOD_LFO_CHAN_PRESS_TO_PITCH }, + { CONN_SRC_EG2, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_MOD_EG_TO_PITCH }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_PAN, PARAM_DEFAULT_PAN }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_REVERB, PARAM_DEFAULT_REVERB_SEND }, + { CONN_SRC_CC91, CONN_SRC_NONE, CONN_DST_REVERB, PARAM_MIDI_CC91_TO_REVERB_SEND }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_CHORUS, PARAM_DEFAULT_CHORUS_SEND }, + { CONN_SRC_CC93, CONN_SRC_NONE, CONN_DST_REVERB, PARAM_MIDI_CC93_TO_CHORUS_SEND } +}; +#define ENTRIES_IN_CONN_TABLE (sizeof(connTable)/sizeof(S_CONNECTION)) + +static const S_DLS_ART_VALUES defaultArt = +{ + 0, /* not modified */ + -851, /* Mod LFO frequency: 5 Hz */ + -7973, /* Mod LFO delay: 10 milliseconds */ + + -851, /* Vib LFO frequency: 5 Hz */ + -7973, /* Vib LFO delay: 10 milliseconds */ + + -32768, /* EG1 delay time: 0 secs */ + -32768, /* EG1 attack time: 0 secs */ + -32768, /* EG1 hold time: 0 secs */ + -32768, /* EG1 decay time: 0 secs */ + 1000, /* EG1 sustain level: 100.0% */ + -32768, /* EG1 release time: 0 secs */ + -7271, /* EG1 shutdown time: 15 msecs */ + 0, /* EG1 velocity to attack: 0 time cents */ + 0, /* EG1 key number to decay: 0 time cents */ + 0, /* EG1 key number to hold: 0 time cents */ + + -32768, /* EG2 delay time: 0 secs */ + -32768, /* EG2 attack time: 0 secs */ + -32768, /* EG2 hold time: 0 secs */ + -32768, /* EG2 decay time: 0 secs */ + 1000, /* EG2 sustain level: 100.0% */ + -32768, /* EG2 release time: 0 secs */ + 0, /* EG2 velocity to attack: 0 time cents */ + 0, /* EG2 key number to decay: 0 time cents */ + 0, /* EG2 key number to hold: 0 time cents */ + + 0x7fff, /* Initial Fc: Disabled */ + 0, /* Initial Q: 0 dB */ + 0, /* Mod LFO to Fc: 0 cents */ + 0, /* Mod LFO CC1 to Fc: 0 cents */ + 0, /* Mod LFO channel pressure to Fc: 0 cents */ + 0, /* EG2 to Fc: 0 cents */ + 0, /* Velocity to Fc: 0 cents */ + 0, /* Key number to Fc: 0 cents */ + + 0, /* Mod LFO to gain: 0 dB */ + 0, /* Mod LFO CC1 to gain: 0 dB */ + 0, /* Mod LFO channel pressure to gain: 0 dB */ + 960, /* Velocity to gain: 96 dB */ + + 0, /* Tuning: 0 cents */ + 12800, /* Key number to pitch: 12,800 cents */ + 0, /* Vibrato to pitch: 0 cents */ + 0, /* Vibrato CC1 to pitch: 0 cents */ + 0, /* Vibrato channel pressure to pitch: 0 cents */ + 0, /* Mod LFO to pitch: 0 cents */ + 0, /* Mod LFO CC1 to pitch: 0 cents */ + 0, /* Mod LFO channel pressure to pitch: 0 cents */ + 0, /* Mod EG to pitch: 0 cents */ + + 0, /* Default pan: 0.0% */ + 0, /* Default reverb send: 0.0% */ + 1000, /* Default CC91 to reverb send: 100.0% */ + 0, /* Default chorus send: 0.0% */ + 1000 /* Default CC93 to chorus send: 100.0% */ +}; + +/*------------------------------------ + * local variables + *------------------------------------ +*/ + +#if defined(_8_BIT_SAMPLES) +static const EAS_INT bitDepth = 8; +#elif defined(_16_BIT_SAMPLES) +static const EAS_INT bitDepth = 16; +#else +#error "Must define _8_BIT_SAMPLES or _16_BIT_SAMPLES" +#endif + +static const EAS_U32 outputSampleRate = _OUTPUT_SAMPLE_RATE; +static const EAS_I32 dlsRateConvert = DLS_RATE_CONVERT; +static const EAS_I32 dlsLFOFrequencyConvert = DLS_LFO_FREQUENCY_CONVERT; + +/*------------------------------------ + * inline functions + *------------------------------------ +*/ +EAS_INLINE void *PtrOfs (void *p, EAS_I32 offset) +{ + return (void*) (((EAS_U8*) p) + offset); +} + +/*------------------------------------ + * prototypes + *------------------------------------ +*/ +static EAS_RESULT NextChunk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 *pPos, EAS_U32 *pChunkType, EAS_I32 *pSize); +static EAS_RESULT Parse_ptbl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 wsmpPos, EAS_I32 wsmpSize); +static EAS_RESULT Parse_wave (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U16 waveIndex); +static EAS_RESULT Parse_wsmp (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p); +static EAS_RESULT Parse_fmt (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p); +static EAS_RESULT Parse_data (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_WSMP_DATA *p, EAS_SAMPLE *pSample); +static EAS_RESULT Parse_lins(SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size); +static EAS_RESULT Parse_ins (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size); +static EAS_RESULT Parse_insh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pRgnCount, EAS_U32 *pLocale); +static EAS_RESULT Parse_lrgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex, EAS_U32 numRegions); +static EAS_RESULT Parse_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex); +static EAS_RESULT Parse_rgnh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_REGION *pRgn); +static EAS_RESULT Parse_lart (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_DLS_ART_VALUES *pArt); +static EAS_RESULT Parse_art (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_ART_VALUES *pArt); +static EAS_RESULT Parse_wlnk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pWaveIndex); +static EAS_RESULT Parse_cdl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 size, EAS_U32 *pValue); +static void Convert_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_U16 regionIndex, EAS_U16 artIndex, EAS_U16 waveIndex, S_WSMP_DATA *pWsmp); +static void Convert_art (SDLS_SYNTHESIZER_DATA *pDLSData, const S_DLS_ART_VALUES *pDLSArt, EAS_U16 artIndex); +static EAS_I16 ConvertSampleRate (EAS_U32 sampleRate); +static EAS_I16 ConvertSustain (EAS_I32 sustain); +static EAS_I16 ConvertLFOPhaseIncrement (EAS_I32 pitchCents); +static EAS_I8 ConvertPan (EAS_I32 pan); +static EAS_U8 ConvertQ (EAS_I32 q); + +#ifdef _DEBUG_DLS +static void DumpDLS (S_EAS *pEAS); +#endif + + +/*---------------------------------------------------------------------------- + * DLSParser () + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to over EAS data instance + * fileHandle - file handle for input file + * offset - offset into file where DLS data starts + * + * Outputs: + * EAS_RESULT + * ppEAS - address of pointer to alternate EAS wavetable + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_DLSLIB_HANDLE *ppDLS) +{ + EAS_RESULT result; + SDLS_SYNTHESIZER_DATA dls; + EAS_U32 temp; + EAS_I32 pos; + EAS_I32 chunkPos; + EAS_I32 size; + EAS_I32 instSize; + EAS_I32 rgnPoolSize; + EAS_I32 artPoolSize; + EAS_I32 waveLenSize; + EAS_I32 endDLS; + EAS_I32 wvplPos; + EAS_I32 wvplSize; + EAS_I32 linsPos; + EAS_I32 linsSize; + EAS_I32 ptblPos; + EAS_I32 ptblSize; + void *p; + + /* zero counts and pointers */ + EAS_HWMemSet(&dls, 0, sizeof(dls)); + + /* save file handle and hwInstData to save copying pointers around */ + dls.hwInstData = hwInstData; + dls.fileHandle = fileHandle; + + /* NULL return value in case of error */ + *ppDLS = NULL; + + /* seek to start of DLS and read in RIFF tag and set processor endian flag */ + if ((result = EAS_HWFileSeek(dls.hwInstData, dls.fileHandle, offset)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWReadFile(dls.hwInstData, dls.fileHandle, &temp, sizeof(temp), &size)) != EAS_SUCCESS) + return result; + + /* check for processor endian-ness */ + dls.bigEndian = (temp == CHUNK_RIFF); + + /* first chunk should be DLS */ + pos = offset; + if ((result = NextChunk(&dls, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + if (temp != CHUNK_DLS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected DLS chunk, got %08lx\n", temp); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* no instrument or wavepool chunks */ + linsSize = wvplSize = ptblSize = linsPos = wvplPos = ptblPos = 0; + + /* scan the chunks in the DLS list */ + endDLS = offset + size; + pos = offset + 12; + while (pos < endDLS) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(&dls, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_CDL: + if ((result = Parse_cdl(&dls, size, &temp)) != EAS_SUCCESS) + return result; + if (!temp) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + break; + + case CHUNK_LINS: + linsPos = chunkPos + 12; + linsSize = size - 4; + break; + + case CHUNK_WVPL: + wvplPos = chunkPos + 12; + wvplSize = size - 4; + break; + + case CHUNK_PTBL: + ptblPos = chunkPos + 8; + ptblSize = size - 4; + break; + + default: + break; + } + } + + /* must have a lins chunk */ + if (linsSize == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No lins chunk found"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a wvpl chunk */ + if (wvplSize == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No wvpl chunk found"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a ptbl chunk */ + if ((ptblSize == 0) || (ptblSize > DLS_MAX_WAVE_COUNT * sizeof(POOLCUE) + sizeof(POOLTABLE))) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No ptbl chunk found"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* pre-parse the wave pool chunk */ + if ((result = Parse_ptbl(&dls, ptblPos, wvplPos, wvplSize)) != EAS_SUCCESS) + return result; + + /* limit check */ + if ((dls.waveCount == 0) || (dls.waveCount > DLS_MAX_WAVE_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #waves [%u]\n", dls.waveCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* allocate memory for wsmp data */ + dls.wsmpData = EAS_HWMalloc(dls.hwInstData, (EAS_I32) (sizeof(S_WSMP_DATA) * dls.waveCount)); + if (dls.wsmpData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWMalloc for wsmp data failed\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(dls.wsmpData, 0, (EAS_I32) (sizeof(S_WSMP_DATA) * dls.waveCount)); + + /* pre-parse the lins chunk */ + result = Parse_lins(&dls, linsPos, linsSize); + if (result == EAS_SUCCESS) + { + + /* limit check */ + if ((dls.regionCount == 0) || (dls.regionCount > DLS_MAX_REGION_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #regions [%u]\n", dls.regionCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* limit check */ + if ((dls.artCount == 0) || (dls.artCount > DLS_MAX_ART_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #articulations [%u]\n", dls.regionCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* limit check */ + if ((dls.instCount == 0) || (dls.instCount > DLS_MAX_INST_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #instruments [%u]\n", dls.instCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* Allocate memory for the converted DLS data */ + /* calculate size of instrument data */ + instSize = (EAS_I32) (sizeof(S_PROGRAM) * dls.instCount); + + /* calculate size of region pool */ + rgnPoolSize = (EAS_I32) (sizeof(S_DLS_REGION) * dls.regionCount); + + /* calculate size of articulation pool, add one for default articulation */ + dls.artCount++; + artPoolSize = (EAS_I32) (sizeof(S_DLS_ARTICULATION) * dls.artCount); + + /* calculate size of wave length and offset arrays */ + waveLenSize = (EAS_I32) (dls.waveCount * sizeof(EAS_U32)); + + /* calculate final memory size */ + size = (EAS_I32) sizeof(S_EAS) + instSize + rgnPoolSize + artPoolSize + (2 * waveLenSize) + (EAS_I32) dls.wavePoolSize; + if (size <= 0) { + return EAS_ERROR_FILE_FORMAT; + } + + /* allocate the main EAS chunk */ + dls.pDLS = EAS_HWMalloc(dls.hwInstData, size); + if (dls.pDLS == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWMalloc failed for DLS memory allocation size %ld\n", size); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(dls.pDLS, 0, size); + dls.pDLS->refCount = 1; + p = PtrOfs(dls.pDLS, sizeof(S_EAS)); + + /* setup pointer to programs */ + dls.pDLS->numDLSPrograms = (EAS_U16) dls.instCount; + dls.pDLS->pDLSPrograms = p; + p = PtrOfs(p, instSize); + + /* setup pointer to regions */ + dls.pDLS->pDLSRegions = p; + dls.pDLS->numDLSRegions = (EAS_U16) dls.regionCount; + p = PtrOfs(p, rgnPoolSize); + + /* setup pointer to articulations */ + dls.pDLS->numDLSArticulations = (EAS_U16) dls.artCount; + dls.pDLS->pDLSArticulations = p; + p = PtrOfs(p, artPoolSize); + + /* setup pointer to wave length table */ + dls.pDLS->numDLSSamples = (EAS_U16) dls.waveCount; + dls.pDLS->pDLSSampleLen = p; + p = PtrOfs(p, waveLenSize); + + /* setup pointer to wave offsets table */ + dls.pDLS->pDLSSampleOffsets = p; + p = PtrOfs(p, waveLenSize); + + /* setup pointer to wave pool */ + dls.pDLS->pDLSSamples = p; + + /* clear filter flag */ + dls.filterUsed = EAS_FALSE; + + /* parse the wave pool and load samples */ + result = Parse_ptbl(&dls, ptblPos, wvplPos, wvplSize); + } + + /* create the default articulation */ + Convert_art(&dls, &defaultArt, 0); + dls.artCount = 1; + + /* parse the lins chunk and load instruments */ + dls.regionCount = dls.instCount = 0; + if (result == EAS_SUCCESS) + result = Parse_lins(&dls, linsPos, linsSize); + + /* clean up any temporary objects that were allocated */ + if (dls.wsmpData) + EAS_HWFree(dls.hwInstData, dls.wsmpData); + + /* if successful, return a pointer to the EAS collection */ + if (result == EAS_SUCCESS) + { + *ppDLS = dls.pDLS; +#ifdef _DEBUG_DLS + DumpDLS(dls.pDLS); +#endif + } + + /* something went wrong, deallocate the EAS collection */ + else + DLSCleanup(dls.hwInstData, dls.pDLS); + + return result; +} + +/*---------------------------------------------------------------------------- + * DLSCleanup () + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to over EAS data instance + * pEAS - pointer to alternate EAS wavetable + * + * Outputs: + * EAS_RESULT + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT DLSCleanup (EAS_HW_DATA_HANDLE hwInstData, S_DLS *pDLS) +{ + + /* free the allocated memory */ + if (pDLS) + { + if (pDLS->refCount) + { + if (--pDLS->refCount == 0) + EAS_HWFree(hwInstData, pDLS); + } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * DLSAddRef () + *---------------------------------------------------------------------------- + * Increment reference count + *---------------------------------------------------------------------------- +*/ +void DLSAddRef (S_DLS *pDLS) +{ + if (pDLS) + pDLS->refCount++; +} + +/*---------------------------------------------------------------------------- + * NextChunk () + *---------------------------------------------------------------------------- + * Purpose: + * Returns the type and size of the next chunk in the file + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT NextChunk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 *pPos, EAS_U32 *pChunkType, EAS_I32 *pSize) +{ + EAS_RESULT result; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, *pPos)) != EAS_SUCCESS) + return result; + + /* read the chunk type */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pChunkType, EAS_TRUE)) != EAS_SUCCESS) + return result; + + /* read the chunk size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pSize, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get form type for RIFF and LIST types */ + if ((*pChunkType == CHUNK_RIFF) || (*pChunkType == CHUNK_LIST)) + { + + /* read the form type */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pChunkType, EAS_TRUE)) != EAS_SUCCESS) + return result; + + } + + /* calculate start of next chunk */ + *pPos += *pSize + 8; + + /* adjust to word boundary */ + if (*pPos & 1) + (*pPos)++; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_ptbl () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_ptbl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 wtblPos, EAS_I32 wtblSize) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_FILE_HANDLE tempFile; + EAS_U16 waveIndex; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &temp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get the number of waves */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSData->waveCount, EAS_FALSE)) != EAS_SUCCESS) + return result; + +#if 0 + /* just need the wave count on the first pass */ + if (!pDLSData->pDLS) + return EAS_SUCCESS; +#endif + + /* open duplicate file handle */ + if ((result = EAS_HWDupHandle(pDLSData->hwInstData, pDLSData->fileHandle, &tempFile)) != EAS_SUCCESS) + return result; + + /* read to end of chunk */ + for (waveIndex = 0; waveIndex < pDLSData->waveCount; waveIndex++) + { + + /* get the offset to the wave and make sure it is within the wtbl chunk */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, tempFile, &temp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (temp > (EAS_U32) wtblSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Ptbl offset exceeds size of wtbl\n"); */ } + EAS_HWCloseFile(pDLSData->hwInstData, tempFile); + return EAS_ERROR_FILE_FORMAT; + } + + /* parse the wave */ + if ((result = Parse_wave(pDLSData, wtblPos +(EAS_I32) temp, waveIndex)) != EAS_SUCCESS) + return result; + } + + /* close the temporary handle and return */ + EAS_HWCloseFile(pDLSData->hwInstData, tempFile); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_wave () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_wave (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U16 waveIndex) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 size; + EAS_I32 endChunk; + EAS_I32 chunkPos; + EAS_I32 wsmpPos = 0; + EAS_I32 fmtPos = 0; + EAS_I32 dataPos = 0; + EAS_I32 dataSize = 0; + S_WSMP_DATA *p; + void *pSample; + S_WSMP_DATA wsmp; + + /* seek to start of chunk */ + chunkPos = pos + 12; + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* make sure it is a wave chunk */ + if (temp != CHUNK_WAVE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Offset in ptbl does not point to wave chunk\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* read to end of chunk */ + pos = chunkPos; + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_WSMP: + wsmpPos = chunkPos + 8; + break; + + case CHUNK_FMT: + fmtPos = chunkPos + 8; + break; + + case CHUNK_DATA: + dataPos = chunkPos + 8; + dataSize = size; + break; + + default: + break; + } + } + + // limit to reasonable size + if (dataSize > MAX_DLS_WAVE_SIZE) + { + return EAS_ERROR_SOUND_LIBRARY; + } + + /* for first pass, use temporary variable */ + if (pDLSData->pDLS == NULL) + p = &wsmp; + else + p = &pDLSData->wsmpData[waveIndex]; + + /* set the defaults */ + p->fineTune = 0; + p->unityNote = 60; + p->gain = 0; + p->loopStart = 0; + p->loopLength = 0; + + /* must have a fmt chunk */ + if (!fmtPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS wave chunk has no fmt chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a data chunk */ + if (!dataPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS wave chunk has no data chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* parse the wsmp chunk */ + if (wsmpPos) + { + if ((result = Parse_wsmp(pDLSData, wsmpPos, p)) != EAS_SUCCESS) + return result; + } + + /* parse the fmt chunk */ + if ((result = Parse_fmt(pDLSData, fmtPos, p)) != EAS_SUCCESS) + return result; + + /* calculate the size of the wavetable needed. We need only half + * the memory for 16-bit samples when in 8-bit mode, and we need + * double the memory for 8-bit samples in 16-bit mode. For + * unlooped samples, we may use ADPCM. If so, we need only 1/4 + * the memory. + * + * We also need to add one for looped samples to allow for + * the first sample to be copied to the end of the loop. + */ + + /* use ADPCM encode for unlooped 16-bit samples if ADPCM is enabled */ + /*lint -e{506} -e{774} groundwork for future version to support 8 & 16 bit */ + if (bitDepth == 8) + { + if (p->bitsPerSample == 8) + size = dataSize; + else + /*lint -e{704} use shift for performance */ + size = dataSize >> 1; + if (p->loopLength) + size++; + } + + else + { + if (p->bitsPerSample == 16) + size = dataSize; + else + /*lint -e{703} use shift for performance */ + size = dataSize << 1; + if (p->loopLength) + size += 2; + } + + /* for first pass, add size to wave pool size and return */ + if (pDLSData->pDLS == NULL) + { + pDLSData->wavePoolSize += (EAS_U32) size; + return EAS_SUCCESS; + } + + /* allocate memory and read in the sample data */ + pSample = pDLSData->pDLS->pDLSSamples + pDLSData->wavePoolOffset; + pDLSData->pDLS->pDLSSampleOffsets[waveIndex] = pDLSData->wavePoolOffset; + pDLSData->pDLS->pDLSSampleLen[waveIndex] = (EAS_U32) size; + pDLSData->wavePoolOffset += (EAS_U32) size; + if (pDLSData->wavePoolOffset > pDLSData->wavePoolSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Wave pool exceeded allocation\n"); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + + if ((result = Parse_data(pDLSData, dataPos, dataSize, p, pSample)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_wsmp () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_wsmp (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p) +{ + EAS_RESULT result; + EAS_U16 wtemp; + EAS_U32 ltemp; + EAS_U32 cbSize; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &cbSize, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get unity note */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (wtemp <= 127) + p->unityNote = (EAS_U8) wtemp; + else + { + p->unityNote = 60; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid unity note [%u] in DLS wsmp ignored, set to 60\n", wtemp); */ } + } + + /* get fine tune */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->fineTune, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get gain */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->gain, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (p->gain > 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Positive gain [%ld] in DLS wsmp ignored, set to 0dB\n", p->gain); */ } + p->gain = 0; + } + + /* option flags */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* sample loops */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* if looped sample, get loop data */ + if (ltemp) + { + + if (ltemp > 1) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS sample with %lu loops, ignoring extra loops\n", ltemp); */ } + + /* skip ahead to loop data */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos + (EAS_I32) cbSize)) != EAS_SUCCESS) + return result; + + /* get structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get loop type */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get loop start */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->loopStart, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get loop length */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->loopLength, EAS_FALSE)) != EAS_SUCCESS) + return result; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_fmt () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_fmt (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p) +{ + EAS_RESULT result; + EAS_U16 wtemp; + EAS_U32 ltemp; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get format tag */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (wtemp != WAVE_FORMAT_PCM) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unsupported DLS sample format %04x\n", wtemp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* get number of channels */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (wtemp != 1) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No support for DLS multi-channel samples\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* get sample rate */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->sampleRate, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* bytes/sec */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* block align */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* bits/sample */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->bitsPerSample, EAS_FALSE)) != EAS_SUCCESS) + return result; + + if ((p->bitsPerSample != 8) && (p->bitsPerSample != 16)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unsupported DLS bits-per-sample %d\n", p->bitsPerSample); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + return EAS_SUCCESS; +} + +#if defined( _8_BIT_SAMPLES) +/*---------------------------------------------------------------------------- + * Parse_data () + *---------------------------------------------------------------------------- + * Purpose: + * + * NOTE: The optimized assembly versions of the interpolator require + * an extra sample at the end of the loop - a copy of the first + * sample. This routine must allocate an extra sample of data and + * copy the first sample of the loop to the end. + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_data (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_WSMP_DATA *pWsmp, EAS_SAMPLE *pSample) +{ + EAS_RESULT result; + EAS_U8 convBuf[SAMPLE_CONVERT_CHUNK_SIZE]; + EAS_I32 count; + EAS_I32 i; + EAS_I8 *p; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* 8-bit samples in an 8-bit synth, just copy the data, and flip bit 7 */ + p = pSample; + if (pWsmp->bitsPerSample == 8) + { + if ((result = EAS_HWReadFile(pDLSData->hwInstData, pDLSData->fileHandle, pSample, size, &count)) != EAS_SUCCESS) + return result; + for (i = 0; i < size; i++) + /*lint -e{734} convert from unsigned to signed audio */ + *p++ ^= 0x80; + } + + /* 16-bit samples, need to convert to 8-bit or ADPCM */ + else + { + + while (size) + { + EAS_I8 *pInput; + + /* for undithered conversion, we're just copying the 8-bit data */ + if (pDLSData->bigEndian) + pInput = (EAS_I8*) convBuf; + else + pInput = (EAS_I8*) convBuf + 1; + + /* read a small chunk of data and convert it */ + count = (size < SAMPLE_CONVERT_CHUNK_SIZE ? size : SAMPLE_CONVERT_CHUNK_SIZE); + if ((result = EAS_HWReadFile(pDLSData->hwInstData, pDLSData->fileHandle, convBuf, count, &count)) != EAS_SUCCESS) + return result; + size -= count; + /*lint -e{704} use shift for performance */ + count = count >> 1; + + while (count--) + { + *p++ = *pInput; + pInput += 2; + } + } + } + + /* for looped samples, copy the last sample to the end */ + if (pWsmp->loopLength) + pSample[pWsmp->loopStart + pWsmp->loopLength] = pSample[pWsmp->loopStart]; + + return EAS_SUCCESS; +} +#elif defined(_16_BIT_SAMPLES) +#error "16-bit DLS conversion not implemented yet" +#else +#error "Must specifiy _8_BIT_SAMPLES or _16_BIT_SAMPLES" +#endif + +/*---------------------------------------------------------------------------- + * Parse_lins () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_lins (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 endChunk; + EAS_I32 chunkPos; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* only instrument chunks are useful */ + if (temp != CHUNK_INS) + continue; + + if ((result = Parse_ins(pDLSData, chunkPos + 12, size)) != EAS_SUCCESS) + return result; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_ins () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_ins (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 chunkPos; + EAS_I32 endChunk; + EAS_I32 lrgnPos; + EAS_I32 lrgnSize; + EAS_I32 lartPos; + EAS_I32 lartSize; + EAS_I32 lar2Pos; + EAS_I32 lar2Size; + EAS_I32 inshPos; + EAS_U32 regionCount; + EAS_U32 locale; + S_DLS_ART_VALUES art; + S_PROGRAM *pProgram; + EAS_U16 artIndex; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* no chunks yet */ + lrgnPos = lrgnSize = lartPos = lartSize = lar2Pos = lar2Size = inshPos = artIndex = 0; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_INSH: + inshPos = chunkPos + 8; + break; + + case CHUNK_LART: + lartPos = chunkPos + 12; + lartSize = size; + break; + + case CHUNK_LAR2: + lar2Pos = chunkPos + 12; + lar2Size = size; + break; + + case CHUNK_LRGN: + lrgnPos = chunkPos + 12; + lrgnSize = size; + break; + + default: + break; + } + } + + /* must have an lrgn to be useful */ + if (!lrgnPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS ins chunk has no lrgn chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have an insh to be useful */ + if (!inshPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS ins chunk has no insh chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* parse the instrument header */ + if ((result = Parse_insh(pDLSData, inshPos, ®ionCount, &locale)) != EAS_SUCCESS) + return result; + + /* initialize and parse the global data first */ + EAS_HWMemCpy(&art, &defaultArt, sizeof(S_DLS_ART_VALUES)); + if (lartPos) + if ((result = Parse_lart(pDLSData, lartPos, lartSize, &art)) != EAS_SUCCESS) + return result; + if (lar2Pos) + if ((result = Parse_lart(pDLSData, lar2Pos, lar2Size, &art)) != EAS_SUCCESS) + return result; + + if (art.values[PARAM_MODIFIED]) + { + artIndex = (EAS_U16) pDLSData->artCount; + pDLSData->artCount++; + } + + /* convert data on second pass */ + if (pDLSData->pDLS) + { + + if (art.values[PARAM_MODIFIED]) + Convert_art(pDLSData, &art, artIndex); + + /* setup pointers */ + pProgram = &pDLSData->pDLS->pDLSPrograms[pDLSData->instCount]; + + /* initialize instrument */ + pProgram->locale = locale; + pProgram->regionIndex = (EAS_U16) pDLSData->regionCount | FLAG_RGN_IDX_DLS_SYNTH; + + } + + /* parse the region data */ + if ((result = Parse_lrgn(pDLSData, lrgnPos, lrgnSize, artIndex, regionCount)) != EAS_SUCCESS) + return result; + + /* bump instrument count */ + pDLSData->instCount++; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_insh () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_insh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pRgnCount, EAS_U32 *pLocale) +{ + EAS_RESULT result; + EAS_U32 bank; + EAS_U32 program; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the region count and locale */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pRgnCount, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &bank, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &program, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* verify the parameters are valid */ + if (bank & 0x7fff8080) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS bank number is out of range: %08lx\n", bank); */ } + bank &= 0xff7f; + } + if (program > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS program number is out of range: %08lx\n", program); */ } + program &= 0x7f; + } + + /* save the program number */ + *pLocale = (bank << 8) | program; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_lrgn () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_lrgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex, EAS_U32 numRegions) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 chunkPos; + EAS_I32 endChunk; + EAS_U16 regionCount; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* read to end of chunk */ + regionCount = 0; + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + if ((temp == CHUNK_RGN) || (temp == CHUNK_RGN2)) + { + if (regionCount == numRegions) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS region count exceeded cRegions value in insh, extra region ignored\n"); */ } + return EAS_SUCCESS; + } + if ((result = Parse_rgn(pDLSData, chunkPos + 12, size, artIndex)) != EAS_SUCCESS) + return result; + regionCount++; + } + } + + /* set a flag in the last region */ + if ((pDLSData->pDLS != NULL) && (regionCount > 0)) + pDLSData->pDLS->pDLSRegions[pDLSData->regionCount - 1].wtRegion.region.keyGroupAndFlags |= REGION_FLAG_LAST_REGION; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_rgn () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 chunkPos; + EAS_I32 endChunk; + EAS_I32 rgnhPos; + EAS_I32 lartPos; + EAS_I32 lartSize; + EAS_I32 lar2Pos; + EAS_I32 lar2Size; + EAS_I32 wlnkPos; + EAS_I32 wsmpPos; + EAS_U32 waveIndex; + S_DLS_ART_VALUES art; + S_WSMP_DATA wsmp; + S_WSMP_DATA *pWsmp; + EAS_U16 regionIndex; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* no chunks found yet */ + rgnhPos = lartPos = lartSize = lar2Pos = lar2Size = wsmpPos = wlnkPos = 0; + regionIndex = (EAS_U16) pDLSData->regionCount; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_CDL: + if ((result = Parse_cdl(pDLSData, size, &temp)) != EAS_SUCCESS) + return result; + + /* if conditional chunk evaluates false, skip this list */ + if (!temp) + return EAS_SUCCESS; + break; + + case CHUNK_RGNH: + rgnhPos = chunkPos + 8; + break; + + case CHUNK_WLNK: + wlnkPos = chunkPos + 8; + break; + + case CHUNK_WSMP: + wsmpPos = chunkPos + 8; + break; + + case CHUNK_LART: + lartPos = chunkPos + 12; + lartSize = size; + break; + + case CHUNK_LAR2: + lar2Pos = chunkPos + 12; + lar2Size = size; + break; + + default: + break; + } + } + + /* must have a rgnh chunk to be useful */ + if (!rgnhPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS rgn chunk has no rgnh chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a wlnk chunk to be useful */ + if (!wlnkPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS rgn chunk has no wlnk chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* parse wlnk chunk */ + if ((result = Parse_wlnk(pDLSData, wlnkPos, &waveIndex)) != EAS_SUCCESS) + return result; + pWsmp = &pDLSData->wsmpData[waveIndex]; + + /* if there is any articulation data, parse it */ + EAS_HWMemCpy(&art, &defaultArt, sizeof(S_DLS_ART_VALUES)); + if (lartPos) + { + if ((result = Parse_lart(pDLSData, lartPos, lartSize, &art)) != EAS_SUCCESS) + return result; + } + + if (lar2Pos) + { + if ((result = Parse_lart(pDLSData, lar2Pos, lar2Size, &art)) != EAS_SUCCESS) + return result; + } + + /* if second pass, process region header */ + if (pDLSData->pDLS) + { + + /* if local data was found convert it */ + if (art.values[PARAM_MODIFIED] == EAS_TRUE) + { + Convert_art(pDLSData, &art, (EAS_U16) pDLSData->artCount); + artIndex = (EAS_U16) pDLSData->artCount; + } + + /* parse region header */ + if ((result = Parse_rgnh(pDLSData, rgnhPos, &pDLSData->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK])) != EAS_SUCCESS) + return result; + + /* parse wsmp chunk, copying parameters from original first */ + if (wsmpPos) + { + EAS_HWMemCpy(&wsmp, pWsmp, sizeof(wsmp)); + if ((result = Parse_wsmp(pDLSData, wsmpPos, &wsmp)) != EAS_SUCCESS) + return result; + + pWsmp = &wsmp; + } + + Convert_rgn(pDLSData, regionIndex, artIndex, (EAS_U16) waveIndex, pWsmp); + } + + /* if local articulation, bump count */ + if (art.values[PARAM_MODIFIED]) + pDLSData->artCount++; + + /* increment region count */ + pDLSData->regionCount++; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_rgnh () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_rgnh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_REGION *pRgn) +{ + EAS_RESULT result; + EAS_U16 lowKey; + EAS_U16 highKey; + EAS_U16 lowVel; + EAS_U16 highVel; + EAS_U16 optionFlags; + EAS_U16 keyGroup; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the key range */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &lowKey, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &highKey, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* check the range */ + if (lowKey > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: Low key out of range [%u]\n", lowKey); */ } + lowKey = 127; + } + if (highKey > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: High key out of range [%u]\n", lowKey); */ } + highKey = 127; + } + + /* get the velocity range */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &lowVel, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &highVel, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* check the range */ + if (lowVel > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: Low velocity out of range [%u]\n", lowVel); */ } + lowVel = 127; + } + if (highVel > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: High velocity out of range [%u]\n", highVel); */ } + highVel = 127; + } + + /* get the option flags */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &optionFlags, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get the key group */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &keyGroup, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* save the key range and key group */ + pRgn->wtRegion.region.rangeLow = (EAS_U8) lowKey; + pRgn->wtRegion.region.rangeHigh = (EAS_U8) highKey; + + /*lint -e{734} keyGroup will always be from 0-15 */ + pRgn->wtRegion.region.keyGroupAndFlags = keyGroup << 8; + pRgn->velLow = (EAS_U8) lowVel; + pRgn->velHigh = (EAS_U8) highVel; + if (optionFlags & F_RGN_OPTION_SELFNONEXCLUSIVE) + pRgn->wtRegion.region.keyGroupAndFlags |= REGION_FLAG_NON_SELF_EXCLUSIVE; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_lart () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_lart (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_DLS_ART_VALUES *pArt) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 endChunk; + EAS_I32 chunkPos; + EAS_I32 art1Pos; + EAS_I32 art2Pos; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* no articulation chunks yet */ + art1Pos = art2Pos = 0; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_CDL: + if ((result = Parse_cdl(pDLSData, size, &temp)) != EAS_SUCCESS) + return result; + + /* if conditional chunk evaluates false, skip this list */ + if (!temp) + return EAS_SUCCESS; + break; + + case CHUNK_ART1: + art1Pos = chunkPos + 8; + break; + + case CHUNK_ART2: + art2Pos = chunkPos + 8; + break; + + default: + break; + + } + } + + if (art1Pos) + { + if ((result = Parse_art(pDLSData, art1Pos, pArt)) != EAS_SUCCESS) + return result; + } + + if (art2Pos) + { + if ((result = Parse_art(pDLSData, art2Pos, pArt)) != EAS_SUCCESS) + return result; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_art() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_art (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_ART_VALUES *pArt) +{ + EAS_RESULT result; + EAS_U32 structSize; + EAS_U32 numConnections; + EAS_U16 source; + EAS_U16 control; + EAS_U16 destination; + EAS_U16 transform; + EAS_I32 scale; + EAS_INT i; + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &structSize, EAS_FALSE)) != EAS_SUCCESS) + return result; + pos += (EAS_I32) structSize; + + /* get the number of connections */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &numConnections, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* skip to start of connections */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + while (numConnections--) + { + + /* read the connection data */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &source, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &control, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &destination, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &transform, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &scale, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* look up the connection */ + for (i = 0; i < (EAS_INT) ENTRIES_IN_CONN_TABLE; i++) + { + if ((connTable[i].source == source) && + (connTable[i].destination == destination) && + (connTable[i].control == control)) + { + /*lint -e{704} use shift for performance */ + pArt->values[connTable[i].connection] = (EAS_I16) (scale >> 16); + pArt->values[PARAM_MODIFIED] = EAS_TRUE; + break; + } + } + if (i == PARAM_TABLE_SIZE) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "WARN: Unsupported parameter in DLS file\n"); */ } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_wlnk () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_wlnk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pWaveIndex) +{ + EAS_RESULT result; + + /* we only care about the the index */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos + 8)) != EAS_SUCCESS) + return result; + + /* read the index */ + return EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle,pWaveIndex, EAS_FALSE); +} + +/*---------------------------------------------------------------------------- + * PopcdlStack () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT PopcdlStack (EAS_U32 *pStack, EAS_INT *pStackPtr, EAS_U32 *pValue) +{ + + /* stack underflow, cdl block has an errorr */ + if (*pStackPtr < 0) + return EAS_ERROR_FILE_FORMAT; + + /* pop the value off the stack */ + *pValue = pStack[*pStackPtr]; + *pStackPtr = *pStackPtr - 1; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * PushcdlStack () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT PushcdlStack (EAS_U32 *pStack, EAS_INT *pStackPtr, EAS_U32 value) +{ + + /* stack overflow, return an error */ + if (*pStackPtr >= CDL_STACK_SIZE) + return EAS_ERROR_FILE_FORMAT; + + /* push the value onto the stack */ + *pStackPtr = *pStackPtr + 1; + pStack[*pStackPtr] = value; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * QueryGUID () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL QueryGUID (const DLSID *pGUID, EAS_U32 *pValue) +{ + + /* assume false */ + *pValue = 0; + if (EAS_HWMemCmp(&DLSID_GMInHardware, pGUID, sizeof(DLSID)) == 0) + { + *pValue = 0xffffffff; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_GSInHardware, pGUID, sizeof(DLSID)) == 0) + return EAS_TRUE; + + if (EAS_HWMemCmp(&DLSID_XGInHardware, pGUID, sizeof(DLSID)) == 0) + return EAS_TRUE; + + if (EAS_HWMemCmp(&DLSID_SupportsDLS1, pGUID, sizeof(DLSID)) == 0) + { + *pValue = 0xffffffff; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_SupportsDLS2, pGUID, sizeof(DLSID)) == 0) + return EAS_TRUE; + + if (EAS_HWMemCmp(&DLSID_SampleMemorySize, pGUID, sizeof(DLSID)) == 0) + { + *pValue = MAX_DLS_MEMORY; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_ManufacturersID, pGUID, sizeof(DLSID)) == 0) + { + *pValue = 0x0000013A; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_ProductID, pGUID, sizeof(DLSID)) == 0) + { + *pValue = LIB_VERSION; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_SamplePlaybackRate, pGUID, sizeof(DLSID)) == 0) + { + *pValue = (EAS_U32) outputSampleRate; + return EAS_TRUE; + } + + /* unrecognized DLSID */ + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * ReadDLSID () + *---------------------------------------------------------------------------- + * Purpose: + * Reads a DLSID in a manner that is not sensitive to processor endian-ness + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReadDLSID (SDLS_SYNTHESIZER_DATA *pDLSData, DLSID *pDLSID) +{ + EAS_RESULT result; + EAS_I32 n; + + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSID->Data1, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSID->Data2, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSID->Data3, EAS_FALSE)) != EAS_SUCCESS) + return result; + return EAS_HWReadFile(pDLSData->hwInstData, pDLSData->fileHandle, pDLSID->Data4, sizeof(pDLSID->Data4), &n); +} + +/*---------------------------------------------------------------------------- + * Parse_cdl () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_cdl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 size, EAS_U32 *pValue) +{ + EAS_RESULT result; + EAS_U32 stack[CDL_STACK_SIZE]; + EAS_U16 opcode; + EAS_INT stackPtr; + EAS_U32 x, y; + DLSID dlsid; + + stackPtr = -1; + *pValue = 0; + x = 0; + while (size) + { + /* read the opcode */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &opcode, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* handle binary opcodes */ + if (opcode <= DLS_CDL_EQ) + { + /* pop X and Y */ + if ((result = PopcdlStack(stack, &stackPtr, &x)) != EAS_SUCCESS) + return result; + if ((result = PopcdlStack(stack, &stackPtr, &y)) != EAS_SUCCESS) + return result; + switch (opcode) + { + case DLS_CDL_AND: + x = x & y; + break; + case DLS_CDL_OR: + x = x | y; + break; + case DLS_CDL_XOR: + x = x ^ y; + break; + case DLS_CDL_ADD: + x = x + y; + break; + case DLS_CDL_SUBTRACT: + x = x - y; + break; + case DLS_CDL_MULTIPLY: + x = x * y; + break; + case DLS_CDL_DIVIDE: + if (!y) + return EAS_ERROR_FILE_FORMAT; + x = x / y; + break; + case DLS_CDL_LOGICAL_AND: + x = (x && y); + break; + case DLS_CDL_LOGICAL_OR: + x = (x || y); + break; + case DLS_CDL_LT: + x = (x < y); + break; + case DLS_CDL_LE: + x = (x <= y); + break; + case DLS_CDL_GT: + x = (x > y); + break; + case DLS_CDL_GE: + x = (x >= y); + break; + case DLS_CDL_EQ: + x = (x == y); + break; + default: + break; + } + } + + else if (opcode == DLS_CDL_NOT) + { + if ((result = PopcdlStack(stack, &stackPtr, &x)) != EAS_SUCCESS) + return result; + x = !x; + } + + else if (opcode == DLS_CDL_CONST) + { + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &x, EAS_FALSE)) != EAS_SUCCESS) + return result; + } + + else if (opcode == DLS_CDL_QUERY) + { + if ((result = ReadDLSID(pDLSData, &dlsid)) != EAS_SUCCESS) + return result; + QueryGUID(&dlsid, &x); + } + + else if (opcode == DLS_CDL_QUERYSUPPORTED) + { + if ((result = ReadDLSID(pDLSData, &dlsid)) != EAS_SUCCESS) + return result; + x = QueryGUID(&dlsid, &y); + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported opcode %d in DLS file\n", opcode); */ } + + /* push the result on the stack */ + if ((result = PushcdlStack(stack, &stackPtr, x)) != EAS_SUCCESS) + return result; + } + + /* pop the last result off the stack */ + return PopcdlStack(stack, &stackPtr, pValue); +} + +/*---------------------------------------------------------------------------- + * Convert_rgn() + *---------------------------------------------------------------------------- + * Purpose: + * Convert region data from DLS to EAS + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static void Convert_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_U16 regionIndex, EAS_U16 artIndex, EAS_U16 waveIndex, S_WSMP_DATA *pWsmp) +{ + S_DLS_REGION *pRgn; + + /* setup pointers to data structures */ + pRgn = &pDLSData->pDLS->pDLSRegions[regionIndex]; + + /* intiailize indices */ + pRgn->wtRegion.artIndex = artIndex; + pRgn->wtRegion.waveIndex = waveIndex; + + /* convert region data */ + /*lint -e{704} use shift for performance */ + pRgn->wtRegion.gain = (EAS_I16) (pWsmp->gain >> 16); + pRgn->wtRegion.loopStart = pWsmp->loopStart; + pRgn->wtRegion.loopEnd = (pWsmp->loopStart + pWsmp->loopLength); + pRgn->wtRegion.tuning = pWsmp->fineTune -(pWsmp->unityNote * 100) + ConvertSampleRate(pWsmp->sampleRate); + if (pWsmp->loopLength != 0) + pRgn->wtRegion.region.keyGroupAndFlags |= REGION_FLAG_IS_LOOPED; +} + +/*---------------------------------------------------------------------------- + * Convert_art() + *---------------------------------------------------------------------------- + * Purpose: + * Convert articulation data from DLS to EAS + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static void Convert_art (SDLS_SYNTHESIZER_DATA *pDLSData, const S_DLS_ART_VALUES *pDLSArt, EAS_U16 artIndex) +{ + S_DLS_ARTICULATION *pArt; + + /* setup pointers to data structures */ + pArt = &pDLSData->pDLS->pDLSArticulations[artIndex]; + + /* LFO parameters */ + pArt->modLFO.lfoFreq = ConvertLFOPhaseIncrement(pDLSArt->values[PARAM_MOD_LFO_FREQ]); + pArt->modLFO.lfoDelay = -ConvertDelay(pDLSArt->values[PARAM_MOD_LFO_DELAY]); + pArt->vibLFO.lfoFreq = ConvertLFOPhaseIncrement(pDLSArt->values[PARAM_VIB_LFO_FREQ]); + pArt->vibLFO.lfoDelay = -ConvertDelay(pDLSArt->values[PARAM_VIB_LFO_DELAY]); + + /* EG1 parameters */ + pArt->eg1.delayTime = ConvertDelay(pDLSArt->values[PARAM_VOL_EG_DELAY]); + pArt->eg1.attackTime = pDLSArt->values[PARAM_VOL_EG_ATTACK]; + pArt->eg1.holdTime = pDLSArt->values[PARAM_VOL_EG_HOLD]; + pArt->eg1.decayTime = pDLSArt->values[PARAM_VOL_EG_DECAY]; + pArt->eg1.sustainLevel = ConvertSustain(pDLSArt->values[PARAM_VOL_EG_SUSTAIN]); + pArt->eg1.releaseTime = ConvertRate(pDLSArt->values[PARAM_VOL_EG_RELEASE]); + pArt->eg1.velToAttack = pDLSArt->values[PARAM_VOL_EG_VEL_TO_ATTACK]; + pArt->eg1.keyNumToDecay = pDLSArt->values[PARAM_VOL_EG_KEY_TO_DECAY]; + pArt->eg1.keyNumToHold = pDLSArt->values[PARAM_VOL_EG_KEY_TO_HOLD]; + pArt->eg1ShutdownTime = ConvertRate(pDLSArt->values[PARAM_VOL_EG_SHUTDOWN]); + + /* EG2 parameters */ + pArt->eg2.delayTime = ConvertDelay(pDLSArt->values[PARAM_MOD_EG_DELAY]); + pArt->eg2.attackTime = pDLSArt->values[PARAM_MOD_EG_ATTACK]; + pArt->eg2.holdTime = pDLSArt->values[PARAM_MOD_EG_HOLD]; + pArt->eg2.decayTime = pDLSArt->values[PARAM_MOD_EG_DECAY]; + pArt->eg2.sustainLevel = ConvertSustain(pDLSArt->values[PARAM_MOD_EG_SUSTAIN]); + pArt->eg2.releaseTime = ConvertRate(pDLSArt->values[PARAM_MOD_EG_RELEASE]); + pArt->eg2.velToAttack = pDLSArt->values[PARAM_MOD_EG_VEL_TO_ATTACK]; + pArt->eg2.keyNumToDecay = pDLSArt->values[PARAM_MOD_EG_KEY_TO_DECAY]; + pArt->eg2.keyNumToHold = pDLSArt->values[PARAM_MOD_EG_KEY_TO_HOLD]; + + /* filter parameters */ + pArt->filterCutoff = pDLSArt->values[PARAM_INITIAL_FC]; + pArt->filterQandFlags = ConvertQ(pDLSArt->values[PARAM_INITIAL_Q]); + pArt->modLFOToFc = pDLSArt->values[PARAM_MOD_LFO_TO_FC]; + pArt->modLFOCC1ToFc = pDLSArt->values[PARAM_MOD_LFO_CC1_TO_FC]; + pArt->modLFOChanPressToFc = pDLSArt->values[PARAM_MOD_LFO_CHAN_PRESS_TO_FC]; + pArt->eg2ToFc = pDLSArt->values[PARAM_MOD_EG_TO_FC]; + pArt->velToFc = pDLSArt->values[PARAM_VEL_TO_FC]; + pArt->keyNumToFc = pDLSArt->values[PARAM_KEYNUM_TO_FC]; + + /* gain parameters */ + pArt->modLFOToGain = pDLSArt->values[PARAM_MOD_LFO_TO_GAIN]; + pArt->modLFOCC1ToGain = pDLSArt->values[PARAM_MOD_LFO_CC1_TO_GAIN]; + pArt->modLFOChanPressToGain = pDLSArt->values[PARAM_MOD_LFO_CHAN_PRESS_TO_GAIN]; + + /* pitch parameters */ + pArt->tuning = pDLSArt->values[PARAM_TUNING]; + pArt->keyNumToPitch = pDLSArt->values[PARAM_KEYNUM_TO_PITCH]; + pArt->vibLFOToPitch = pDLSArt->values[PARAM_VIB_LFO_TO_PITCH]; + pArt->vibLFOCC1ToPitch = pDLSArt->values[PARAM_VIB_LFO_CC1_TO_PITCH]; + pArt->vibLFOChanPressToPitch = pDLSArt->values[PARAM_VIB_LFO_CHAN_PRESS_TO_PITCH]; + pArt->modLFOToPitch = pDLSArt->values[PARAM_MOD_LFO_TO_PITCH]; + pArt->modLFOCC1ToPitch = pDLSArt->values[PARAM_MOD_LFO_CC1_TO_PITCH]; + pArt->modLFOChanPressToPitch = pDLSArt->values[PARAM_MOD_LFO_CHAN_PRESS_TO_PITCH]; + pArt->eg2ToPitch = pDLSArt->values[PARAM_MOD_EG_TO_PITCH]; + + /* output parameters */ + pArt->pan = ConvertPan(pDLSArt->values[PARAM_DEFAULT_PAN]); + + if (pDLSArt->values[PARAM_VEL_TO_GAIN] != 0) + pArt->filterQandFlags |= FLAG_DLS_VELOCITY_SENSITIVE; + +#ifdef _REVERB + pArt->reverbSend = pDLSArt->values[PARAM_DEFAULT_REVERB_SEND]; + pArt->cc91ToReverbSend = pDLSArt->values[PARAM_MIDI_CC91_TO_REVERB_SEND]; +#endif + +#ifdef _CHORUS + pArt->chorusSend = pDLSArt->values[PARAM_DEFAULT_CHORUS_SEND]; + pArt->cc93ToChorusSend = pDLSArt->values[PARAM_MIDI_CC93_TO_CHORUS_SEND]; +#endif +} + +/*---------------------------------------------------------------------------- + * ConvertSampleRate() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_I16 ConvertSampleRate (EAS_U32 sampleRate) +{ + return (EAS_I16) (1200.0 * log10((double) sampleRate / (double) outputSampleRate) / log10(2.0)); +} + +/*---------------------------------------------------------------------------- + * ConvertSustainEG2() + *---------------------------------------------------------------------------- + * Convert sustain level to pitch/Fc multipler for EG2 + *---------------------------------------------------------------------------- +*/ +static EAS_I16 ConvertSustain (EAS_I32 sustain) +{ + /* check for sustain level of zero */ + if (sustain == 0) + return 0; + + /* convert to log2 factor */ + /*lint -e{704} use shift for performance */ + sustain = (sustain * SUSTAIN_LINEAR_CONVERSION_FACTOR) >> 15; + + if (sustain > SYNTH_FULL_SCALE_EG1_GAIN) + return SYNTH_FULL_SCALE_EG1_GAIN; + return (EAS_I16) sustain; +} + +/*---------------------------------------------------------------------------- + * ConvertDelay () + *---------------------------------------------------------------------------- + * Converts timecents to frame count. Used for LFO and envelope + * delay times. + *---------------------------------------------------------------------------- +*/ +EAS_I16 ConvertDelay (EAS_I32 timeCents) +{ + EAS_I32 temp; + + if (timeCents == ZERO_TIME_IN_CENTS) + return 0; + + /* divide time by secs per frame to get number of frames */ + temp = timeCents - dlsRateConvert; + + /* convert from time cents to 10-bit fraction */ + temp = FMUL_15x15(temp, TIME_CENTS_TO_LOG2); + + /* convert to frame count */ + temp = EAS_LogToLinear16(temp - (15 << 10)); + + if (temp < SYNTH_FULL_SCALE_EG1_GAIN) + return (EAS_I16) temp; + return SYNTH_FULL_SCALE_EG1_GAIN; +} + +/*---------------------------------------------------------------------------- + * ConvertRate () + *---------------------------------------------------------------------------- + * Convert timecents to rate + *---------------------------------------------------------------------------- +*/ +EAS_I16 ConvertRate (EAS_I32 timeCents) +{ + EAS_I32 temp; + + if (timeCents == ZERO_TIME_IN_CENTS) + return SYNTH_FULL_SCALE_EG1_GAIN; + + /* divide frame rate by time in log domain to get rate */ + temp = dlsRateConvert - timeCents; + +#if 1 + temp = EAS_Calculate2toX(temp); +#else + /* convert from time cents to 10-bit fraction */ + temp = FMUL_15x15(temp, TIME_CENTS_TO_LOG2); + + /* convert to rate */ + temp = EAS_LogToLinear16(temp); +#endif + + if (temp < SYNTH_FULL_SCALE_EG1_GAIN) + return (EAS_I16) temp; + return SYNTH_FULL_SCALE_EG1_GAIN; +} + + +/*---------------------------------------------------------------------------- + * ConvertLFOPhaseIncrement() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_I16 ConvertLFOPhaseIncrement (EAS_I32 pitchCents) +{ + + /* check range */ + if (pitchCents > MAX_LFO_FREQUENCY_IN_PITCHCENTS) + pitchCents = MAX_LFO_FREQUENCY_IN_PITCHCENTS; + if (pitchCents < MIN_LFO_FREQUENCY_IN_PITCHCENTS) + pitchCents = MIN_LFO_FREQUENCY_IN_PITCHCENTS; + + /* double the rate and divide by frame rate by subtracting in log domain */ + pitchCents = pitchCents - dlsLFOFrequencyConvert; + + /* convert to phase increment */ + return (EAS_I16) EAS_Calculate2toX(pitchCents); +} + +/*---------------------------------------------------------------------------- + * ConvertPan() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_I8 ConvertPan (EAS_I32 pan) +{ + + /* multiply by conversion factor */ + pan = FMUL_15x15 (PAN_CONVERSION_FACTOR, pan); + if (pan < MIN_PAN_VALUE) + return MIN_PAN_VALUE; + if (pan > MAX_PAN_VALUE) + return MAX_PAN_VALUE; + return (EAS_I8) pan; +} + +/*---------------------------------------------------------------------------- + * ConvertQ() + *---------------------------------------------------------------------------- + * Convert the DLS filter resonance to an index value used by the synth + * that accesses tables of coefficients based on the Q. + *---------------------------------------------------------------------------- +*/ +static EAS_U8 ConvertQ (EAS_I32 q) +{ + + /* apply limits */ + if (q <= 0) + return 0; + + /* convert to table index */ + /*lint -e{704} use shift for performance */ + q = (FILTER_Q_CONVERSION_FACTOR * q + 0x4000) >> 15; + + /* apply upper limit */ + if (q >= FILTER_RESONANCE_NUM_ENTRIES) + q = FILTER_RESONANCE_NUM_ENTRIES - 1; + return (EAS_U8) q; +} + +#ifdef _DEBUG_DLS +/*---------------------------------------------------------------------------- + * DumpDLS() + *---------------------------------------------------------------------------- +*/ +static void DumpDLS (S_EAS *pEAS) +{ + S_DLS_ARTICULATION *pArt; + S_DLS_REGION *pRegion; + EAS_INT i; + EAS_INT j; + + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000022 , pEAS->numPrograms); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000023 , pEAS->numWTRegions); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000024 , pEAS->numDLSArticulations); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000025 , pEAS->numSamples); + + /* dump the instruments */ + for (i = 0; i < pEAS->numPrograms; i++) + { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000026 , + pEAS->pPrograms[i].locale >> 16, + (pEAS->pPrograms[i].locale >> 8) & 0x7f, + pEAS->pPrograms[i].locale & 0x7f); + + for (j = pEAS->pPrograms[i].regionIndex; ; j++) + { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000027 , j); + pRegion = &pEAS->pWTRegions[j]; + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000028 , pRegion->gain); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000029 , pRegion->region.rangeLow, pRegion->region.rangeHigh); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002a , pRegion->region.keyGroupAndFlags); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002b , pRegion->loopStart); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002c , pRegion->loopEnd); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002d , pRegion->tuning); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002e , pRegion->artIndex); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002f , pRegion->waveIndex); + + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + } + + } + + /* dump the articulation data */ + for (i = 0; i < pEAS->numDLSArticulations; i++) + { + /* articulation data */ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000030 , i); + pArt = &pEAS->pDLSArticulations[i]; + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000031 , pArt->m_nEG2toFilterDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000032 , pArt->m_nEG2toPitchDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000033 , pArt->m_nFilterCutoffFrequency); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000034 , pArt->m_nFilterResonance); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000035 , pArt->m_nLFOAmplitudeDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000036 , pArt->m_nLFODelayTime); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000037 , pArt->m_nLFOFrequency); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000038 , pArt->m_nLFOPitchDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000039 , pArt->m_nPan); + + /* EG1 data */ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003a , pArt->m_sEG1.m_nAttack); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003b , pArt->m_sEG1.m_nDecay); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003c , pArt->m_sEG1.m_nSustain); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003d , pArt->m_sEG1.m_nRelease); + + /* EG2 data */ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003e , pArt->m_sEG2.m_nAttack); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003f , pArt->m_sEG2.m_nDecay); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000040 , pArt->m_sEG2.m_nSustain); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000041 , pArt->m_sEG2.m_nRelease); + + } + + /* dump the waves */ + for (i = 0; i < pEAS->numSamples; i++) + { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000042 , i); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000043 , pEAS->pSampleLen[i]); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000044 , pEAS->ppSamples[i]); + } + +} +#endif + -- cgit v1.2.3