From a8c89077d78769bf4840fa91609edc51fe2fa02d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 12 Nov 2009 18:45:37 -0800 Subject: eclair snapshot --- arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc | 306 +- arm-hybrid-22k/lib_src/eas_audioconst.h | 170 +- arm-hybrid-22k/lib_src/eas_chorus.c | 1184 +-- arm-hybrid-22k/lib_src/eas_chorusdata.c | 44 +- arm-hybrid-22k/lib_src/eas_chorusdata.h | 296 +- arm-hybrid-22k/lib_src/eas_ctype.h | 58 +- arm-hybrid-22k/lib_src/eas_data.c | 50 +- arm-hybrid-22k/lib_src/eas_data.h | 238 +- arm-hybrid-22k/lib_src/eas_effects.h | 98 +- arm-hybrid-22k/lib_src/eas_fmengine.c | 1546 +-- arm-hybrid-22k/lib_src/eas_fmengine.h | 218 +- arm-hybrid-22k/lib_src/eas_fmsynth.c | 1796 ++-- arm-hybrid-22k/lib_src/eas_fmsynth.h | 138 +- arm-hybrid-22k/lib_src/eas_fmtables.c | 712 +- arm-hybrid-22k/lib_src/eas_ima_tables.c | 84 +- arm-hybrid-22k/lib_src/eas_imaadpcm.c | 712 +- arm-hybrid-22k/lib_src/eas_imelody.c | 3452 +++---- arm-hybrid-22k/lib_src/eas_imelodydata.c | 62 +- arm-hybrid-22k/lib_src/eas_imelodydata.h | 122 +- arm-hybrid-22k/lib_src/eas_math.c | 312 +- arm-hybrid-22k/lib_src/eas_math.h | 800 +- arm-hybrid-22k/lib_src/eas_midi.c | 1114 +- arm-hybrid-22k/lib_src/eas_midi.h | 118 +- arm-hybrid-22k/lib_src/eas_midictrl.h | 104 +- arm-hybrid-22k/lib_src/eas_mididata.c | 44 +- arm-hybrid-22k/lib_src/eas_miditypes.h | 252 +- arm-hybrid-22k/lib_src/eas_mixbuf.c | 48 +- arm-hybrid-22k/lib_src/eas_mixer.c | 904 +- arm-hybrid-22k/lib_src/eas_mixer.h | 250 +- arm-hybrid-22k/lib_src/eas_ota.c | 2130 ++-- arm-hybrid-22k/lib_src/eas_otadata.c | 58 +- arm-hybrid-22k/lib_src/eas_otadata.h | 138 +- arm-hybrid-22k/lib_src/eas_pan.c | 172 +- arm-hybrid-22k/lib_src/eas_pan.h | 108 +- arm-hybrid-22k/lib_src/eas_parser.h | 172 +- arm-hybrid-22k/lib_src/eas_pcm.c | 2940 +++--- arm-hybrid-22k/lib_src/eas_pcm.h | 694 +- arm-hybrid-22k/lib_src/eas_pcmdata.c | 46 +- arm-hybrid-22k/lib_src/eas_pcmdata.h | 290 +- arm-hybrid-22k/lib_src/eas_public.c | 5170 +++++----- arm-hybrid-22k/lib_src/eas_reverb.c | 2284 ++--- arm-hybrid-22k/lib_src/eas_reverbdata.c | 44 +- arm-hybrid-22k/lib_src/eas_reverbdata.h | 948 +- arm-hybrid-22k/lib_src/eas_rtttl.c | 2370 ++--- arm-hybrid-22k/lib_src/eas_rtttldata.c | 58 +- arm-hybrid-22k/lib_src/eas_rtttldata.h | 116 +- arm-hybrid-22k/lib_src/eas_smf.c | 2382 ++--- arm-hybrid-22k/lib_src/eas_smf.h | 74 +- arm-hybrid-22k/lib_src/eas_smfdata.c | 108 +- arm-hybrid-22k/lib_src/eas_smfdata.h | 108 +- arm-hybrid-22k/lib_src/eas_sndlib.h | 788 +- arm-hybrid-22k/lib_src/eas_synth.h | 766 +- arm-hybrid-22k/lib_src/eas_synth_protos.h | 96 +- arm-hybrid-22k/lib_src/eas_synthcfg.h | 116 +- arm-hybrid-22k/lib_src/eas_vm_protos.h | 2148 ++-- arm-hybrid-22k/lib_src/eas_voicemgt.c | 7918 +++++++------- arm-hybrid-22k/lib_src/eas_wavefile.c | 1710 +-- arm-hybrid-22k/lib_src/eas_wavefile.h | 102 +- arm-hybrid-22k/lib_src/eas_wavefiledata.c | 42 +- arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h | 140 +- arm-hybrid-22k/lib_src/eas_wtengine.c | 1298 +-- arm-hybrid-22k/lib_src/eas_wtengine.h | 318 +- arm-hybrid-22k/lib_src/eas_wtsynth.c | 2478 ++--- arm-hybrid-22k/lib_src/eas_wtsynth.h | 108 +- arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c | 10274 +++++++++---------- 65 files changed, 31972 insertions(+), 31972 deletions(-) (limited to 'arm-hybrid-22k/lib_src') diff --git a/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc b/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc index b4cd29a..c0f8df3 100644 --- a/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc +++ b/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc @@ -1,153 +1,153 @@ -@*********************************************************** -@ File: ARM_synth_constants.inc -@ Processor: ARM -@ Description: Contains constants and defines, most of which -@ are mirrored in synth.h -@ -@ Copyright Sonic Network Inc. 2004 -@**************************************************************** -@ Revision Control: -@ $Revision: 741 $ -@ $Date: 2007-06-22 16:39:21 -0700 (Fri, 22 Jun 2007) $ -@**************************************************************** - - - .ifdef SAMPLE_RATE_8000 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 5 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 32 - .endif - - .ifdef SAMPLE_RATE_16000 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 6 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 64 - .endif - - .ifdef SAMPLE_RATE_20000 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 - .endif - - .ifdef SAMPLE_RATE_22050 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 - .endif - - .ifdef SAMPLE_RATE_24000 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 - .endif - - .ifdef SAMPLE_RATE_32000 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 - .endif - - .ifdef SAMPLE_RATE_44100 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 - .endif - - .ifdef SAMPLE_RATE_48000 - .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 - .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 - .endif - - -@ if the OUTPUT PCM sample is 16-bits, then when using indexed addressing, -@ the next sample is this many bytes away - .equ NEXT_OUTPUT_PCM, 2 - -@**************************************************************************** -@/* macros for fractional phase accumulator */ - .equ NUM_PHASE_FRAC_BITS, 15 - - .equ PHASE_FRAC_MASK, 0x7FFF - -@ shift for phase accumulator when fraction carries over - .ifdef SAMPLES_8_BIT - .equ NEXT_INPUT_PCM_SHIFT, 0 - .endif - - .ifdef SAMPLES_16_BIT - .equ NEXT_INPUT_PCM_SHIFT, 1 - .endif - -@**************************************************************************** - .equ NUM_MIXER_GUARD_BITS, 4 - -@**************************************************************************** -@/* Envelope 1 (EG1) calculation macros */ - .equ NUM_EG1_FRAC_BITS, 15 - -@**************************************************************************** - - .equ NUM_ENHANCER_FILTER_COEF_FRAC_BITS, 5 - -@**************************************************************************** - -@ -@ I've temporarily given up on the idea of getting ADS/RV and gcc to -@ handle a struct in a compatible fashion. Switching to old fashion EQU -@ - - .if FILTER_ENABLED -@************************************** -@ typedef struct s_filter_tag - .equ m_z1, 0 - .equ m_z2, 2 - .endif - -@************************************** -@ typedef struct s_wt_frame_tag - .equ m_gainTarget, 0 - .equ m_phaseIncrement, 4 - - .if FILTER_ENABLED - .equ m_k, 8 - .equ m_b1, 12 - .equ m_b2, 16 - .equ m_pAudioBuffer, 20 - .equ m_pMixBuffer, 24 - .equ m_numSamples, 28 - .equ m_prevGain, 32 - .else - .equ m_pAudioBuffer, 8 - .equ m_pMixBuffer, 12 - .equ m_numSamples, 16 - .equ m_prevGain, 20 - .endif - - -@************************************** -@ typedef struct s_wt_voice_tag - .equ m_pLoopEnd, 0 @ /* points to last PCM sample (not 1 beyond last) */ - .equ m_pLoopStart, 4 @ /* points to first sample at start of loop */ - .equ m_pPhaseAccum, 8 @ /* points to first sample at start of loop */ - .equ m_phaseFrac, 12 @ /* points to first sample at start of loop */ - - .if STEREO_OUTPUT - .equ m_gainLeft, 16 @ /* current gain, left ch */ - .equ m_gainRight, 18 @ /* current gain, right ch */ - .endif - - -@**************************************************************************** -@ enhancer - .equ m_nEnhancerFeedForward1, 0 - .equ m_nEnhancerFeedback1, 1 - .equ m_nDriveCoef, 2 - .equ m_nEnhancerFeedback2, 3 - .equ m_nWet, 4 - .equ m_nDry, 5 - - .equ m_zF0L, 6 @ filter 1 zero state var, left - .equ m_zF1L, 8 @ filter 1 pole state var, left - .equ m_zF2L, 10 @ filter 2 zero state var, left - .equ m_zF0R, 12 @ filter 1 zero state var, right - .equ m_zF1R, 14 @ filter 1 pole state var, right - .equ m_zF2R, 16 @ filter 2 zero state var, right - -@**************************************************************************** - - - +@*********************************************************** +@ File: ARM_synth_constants.inc +@ Processor: ARM +@ Description: Contains constants and defines, most of which +@ are mirrored in synth.h +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 741 $ +@ $Date: 2007-06-22 16:39:21 -0700 (Fri, 22 Jun 2007) $ +@**************************************************************** + + + .ifdef SAMPLE_RATE_8000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 5 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 32 + .endif + + .ifdef SAMPLE_RATE_16000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 6 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 64 + .endif + + .ifdef SAMPLE_RATE_20000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_22050 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_24000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_32000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_44100 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 + .endif + + .ifdef SAMPLE_RATE_48000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 + .endif + + +@ if the OUTPUT PCM sample is 16-bits, then when using indexed addressing, +@ the next sample is this many bytes away + .equ NEXT_OUTPUT_PCM, 2 + +@**************************************************************************** +@/* macros for fractional phase accumulator */ + .equ NUM_PHASE_FRAC_BITS, 15 + + .equ PHASE_FRAC_MASK, 0x7FFF + +@ shift for phase accumulator when fraction carries over + .ifdef SAMPLES_8_BIT + .equ NEXT_INPUT_PCM_SHIFT, 0 + .endif + + .ifdef SAMPLES_16_BIT + .equ NEXT_INPUT_PCM_SHIFT, 1 + .endif + +@**************************************************************************** + .equ NUM_MIXER_GUARD_BITS, 4 + +@**************************************************************************** +@/* Envelope 1 (EG1) calculation macros */ + .equ NUM_EG1_FRAC_BITS, 15 + +@**************************************************************************** + + .equ NUM_ENHANCER_FILTER_COEF_FRAC_BITS, 5 + +@**************************************************************************** + +@ +@ I've temporarily given up on the idea of getting ADS/RV and gcc to +@ handle a struct in a compatible fashion. Switching to old fashion EQU +@ + + .if FILTER_ENABLED +@************************************** +@ typedef struct s_filter_tag + .equ m_z1, 0 + .equ m_z2, 2 + .endif + +@************************************** +@ typedef struct s_wt_frame_tag + .equ m_gainTarget, 0 + .equ m_phaseIncrement, 4 + + .if FILTER_ENABLED + .equ m_k, 8 + .equ m_b1, 12 + .equ m_b2, 16 + .equ m_pAudioBuffer, 20 + .equ m_pMixBuffer, 24 + .equ m_numSamples, 28 + .equ m_prevGain, 32 + .else + .equ m_pAudioBuffer, 8 + .equ m_pMixBuffer, 12 + .equ m_numSamples, 16 + .equ m_prevGain, 20 + .endif + + +@************************************** +@ typedef struct s_wt_voice_tag + .equ m_pLoopEnd, 0 @ /* points to last PCM sample (not 1 beyond last) */ + .equ m_pLoopStart, 4 @ /* points to first sample at start of loop */ + .equ m_pPhaseAccum, 8 @ /* points to first sample at start of loop */ + .equ m_phaseFrac, 12 @ /* points to first sample at start of loop */ + + .if STEREO_OUTPUT + .equ m_gainLeft, 16 @ /* current gain, left ch */ + .equ m_gainRight, 18 @ /* current gain, right ch */ + .endif + + +@**************************************************************************** +@ enhancer + .equ m_nEnhancerFeedForward1, 0 + .equ m_nEnhancerFeedback1, 1 + .equ m_nDriveCoef, 2 + .equ m_nEnhancerFeedback2, 3 + .equ m_nWet, 4 + .equ m_nDry, 5 + + .equ m_zF0L, 6 @ filter 1 zero state var, left + .equ m_zF1L, 8 @ filter 1 pole state var, left + .equ m_zF2L, 10 @ filter 2 zero state var, left + .equ m_zF0R, 12 @ filter 1 zero state var, right + .equ m_zF1R, 14 @ filter 1 pole state var, right + .equ m_zF2R, 16 @ filter 2 zero state var, right + +@**************************************************************************** + + + diff --git a/arm-hybrid-22k/lib_src/eas_audioconst.h b/arm-hybrid-22k/lib_src/eas_audioconst.h index 1cfa404..066148e 100644 --- a/arm-hybrid-22k/lib_src/eas_audioconst.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_chorus.c b/arm-hybrid-22k/lib_src/eas_chorus.c index bc42237..4a2c8d0 100644 --- a/arm-hybrid-22k/lib_src/eas_chorus.c +++ b/arm-hybrid-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(valueEAS_CHORUS_RATE_MAX) - return EAS_ERROR_INVALID_PARAMETER; - p->m_nRate = (EAS_I16) value; - break; - case EAS_PARAM_CHORUS_DEPTH: - if(valueEAS_CHORUS_DEPTH_MAX) - return EAS_ERROR_INVALID_PARAMETER; - p->m_nDepth = (EAS_I16) value; - break; - case EAS_PARAM_CHORUS_LEVEL: - if(valueEAS_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(valueEAS_CHORUS_RATE_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nRate = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_DEPTH: + if(valueEAS_CHORUS_DEPTH_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nDepth = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_LEVEL: + if(valueEAS_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-hybrid-22k/lib_src/eas_chorusdata.c b/arm-hybrid-22k/lib_src/eas_chorusdata.c index caee1ed..ec71ff8 100644 --- a/arm-hybrid-22k/lib_src/eas_chorusdata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_chorusdata.h b/arm-hybrid-22k/lib_src/eas_chorusdata.h index 4420ddd..ec8daa4 100644 --- a/arm-hybrid-22k/lib_src/eas_chorusdata.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_ctype.h b/arm-hybrid-22k/lib_src/eas_ctype.h index 8503870..14fa96f 100644 --- a/arm-hybrid-22k/lib_src/eas_ctype.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_data.c b/arm-hybrid-22k/lib_src/eas_data.c index bb60ef2..31a4e6a 100644 --- a/arm-hybrid-22k/lib_src/eas_data.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_data.h b/arm-hybrid-22k/lib_src/eas_data.h index 0a47d04..e2fcb1a 100644 --- a/arm-hybrid-22k/lib_src/eas_data.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_effects.h b/arm-hybrid-22k/lib_src/eas_effects.h index 01e64c0..86dedac 100644 --- a/arm-hybrid-22k/lib_src/eas_effects.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_fmengine.c b/arm-hybrid-22k/lib_src/eas_fmengine.c index 9c3da66..ea7f69c 100644 --- a/arm-hybrid-22k/lib_src/eas_fmengine.c +++ b/arm-hybrid-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} */ - 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} */ - 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} */ - 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} */ - nGain = (EAS_I32) p->voiceGain << 16; - - /* calculate gain increment */ - /*lint -e{703} */ - 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} */ - nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT; - - /*lint -e{704} */ - { - 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} */ - 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} */ + 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} */ + 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} */ + 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} */ + nGain = (EAS_I32) p->voiceGain << 16; + + /* calculate gain increment */ + /*lint -e{703} */ + 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} */ + nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT; + + /*lint -e{704} */ + { + 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} */ + 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-hybrid-22k/lib_src/eas_fmengine.h b/arm-hybrid-22k/lib_src/eas_fmengine.h index 4ddc12b..dd248f8 100644 --- a/arm-hybrid-22k/lib_src/eas_fmengine.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_fmsynth.c b/arm-hybrid-22k/lib_src/eas_fmsynth.c index 83f0087..629506a 100644 --- a/arm-hybrid-22k/lib_src/eas_fmsynth.c +++ b/arm-hybrid-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} */ - pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7); - - /* check for linear velocity flag */ - /*lint -e{703} */ - 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} */ - 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} */ - 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} */ - 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} */ - 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} */ + pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7); + + /* check for linear velocity flag */ + /*lint -e{703} */ + 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} */ + 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} */ + 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} */ + 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} */ + 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-hybrid-22k/lib_src/eas_fmsynth.h b/arm-hybrid-22k/lib_src/eas_fmsynth.h index 76f8adc..8ceda46 100644 --- a/arm-hybrid-22k/lib_src/eas_fmsynth.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_fmtables.c b/arm-hybrid-22k/lib_src/eas_fmtables.c index 25c6961..a8ff0a2 100644 --- a/arm-hybrid-22k/lib_src/eas_fmtables.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_ima_tables.c b/arm-hybrid-22k/lib_src/eas_ima_tables.c index 56bd1eb..b03b4d4 100644 --- a/arm-hybrid-22k/lib_src/eas_ima_tables.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_imaadpcm.c b/arm-hybrid-22k/lib_src/eas_imaadpcm.c index 68bf257..41280b5 100644 --- a/arm-hybrid-22k/lib_src/eas_imaadpcm.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_imelody.c b/arm-hybrid-22k/lib_src/eas_imelody.c index 9f4d541..698c7df 100644 --- a/arm-hybrid-22k/lib_src/eas_imelody.c +++ b/arm-hybrid-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 -#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 +#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-hybrid-22k/lib_src/eas_imelodydata.c b/arm-hybrid-22k/lib_src/eas_imelodydata.c index e72dc0b..9437e08 100644 --- a/arm-hybrid-22k/lib_src/eas_imelodydata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_imelodydata.h b/arm-hybrid-22k/lib_src/eas_imelodydata.h index 303b8f6..57c1ed0 100644 --- a/arm-hybrid-22k/lib_src/eas_imelodydata.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_math.c b/arm-hybrid-22k/lib_src/eas_math.c index 12d788e..dc85051 100644 --- a/arm-hybrid-22k/lib_src/eas_math.c +++ b/arm-hybrid-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} */ - 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} */ + 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-hybrid-22k/lib_src/eas_math.h b/arm-hybrid-22k/lib_src/eas_math.h index 719270b..f240b51 100644 --- a/arm-hybrid-22k/lib_src/eas_math.h +++ b/arm-hybrid-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) */ \ - (((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) */ \ - (((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) */ \ - (((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) */ \ - (((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 */ \ - (EAS_I32)( \ - ( \ - ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ - ) \ - >> NUM_PHASE_FRAC_BITS \ - ) \ - /* lint +704 */ - -/* 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) */ \ - (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) */ \ - (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) */ \ - (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) */ \ - (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 */ \ - (EAS_I32)( \ - ( \ - ((EAS_I32)(dents)) * ((EAS_I32)(coef)) \ - ) \ - >> NUM_DENTS_FRAC_BITS \ - ) \ - /* lint +e704 */ - -/* 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) */ \ - (EAS_I32) ( \ - ( \ - ((EAS_I32)(audio)) * ((EAS_I32)(drive)) \ - ) \ - >> NUM_DRIVE_COEF_FRAC_BITS \ - ) - -#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) */ \ - (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) */ \ + (((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) */ \ + (((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) */ \ + (((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) */ \ + (((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 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_PHASE_FRAC_BITS \ + ) \ + /* lint +704 */ + +/* 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) */ \ + (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) */ \ + (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) */ \ + (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) */ \ + (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 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(dents)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_DENTS_FRAC_BITS \ + ) \ + /* lint +e704 */ + +/* 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) */ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(drive)) \ + ) \ + >> NUM_DRIVE_COEF_FRAC_BITS \ + ) + +#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) */ \ + (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-hybrid-22k/lib_src/eas_midi.c b/arm-hybrid-22k/lib_src/eas_midi.c index 08aed72..2c0c793 100644 --- a/arm-hybrid-22k/lib_src/eas_midi.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_midi.h b/arm-hybrid-22k/lib_src/eas_midi.h index 37a03ee..10649a0 100644 --- a/arm-hybrid-22k/lib_src/eas_midi.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_midictrl.h b/arm-hybrid-22k/lib_src/eas_midictrl.h index 0c4217d..46fdc4f 100644 --- a/arm-hybrid-22k/lib_src/eas_midictrl.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_mididata.c b/arm-hybrid-22k/lib_src/eas_mididata.c index 2ee907e..4463b7e 100644 --- a/arm-hybrid-22k/lib_src/eas_mididata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_miditypes.h b/arm-hybrid-22k/lib_src/eas_miditypes.h index 0b7f96e..015f08b 100644 --- a/arm-hybrid-22k/lib_src/eas_miditypes.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_mixbuf.c b/arm-hybrid-22k/lib_src/eas_mixbuf.c index 73e969a..db5bd02 100644 --- a/arm-hybrid-22k/lib_src/eas_mixbuf.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_mixer.c b/arm-hybrid-22k/lib_src/eas_mixer.c index c4a2f9f..0a839a8 100644 --- a/arm-hybrid-22k/lib_src/eas_mixer.c +++ b/arm-hybrid-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} */ - s = s >> 7; - - /* apply master gain */ - s *= (long) nGain; - - /* shift to lower 16-bits */ - /*lint -e{704} */ - 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} */ + s = s >> 7; + + /* apply master gain */ + s *= (long) nGain; + + /* shift to lower 16-bits */ + /*lint -e{704} */ + 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-hybrid-22k/lib_src/eas_mixer.h b/arm-hybrid-22k/lib_src/eas_mixer.h index 2ba2d3d..b2eb33b 100644 --- a/arm-hybrid-22k/lib_src/eas_mixer.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_ota.c b/arm-hybrid-22k/lib_src/eas_ota.c index fb81d62..5bc9062 100644 --- a/arm-hybrid-22k/lib_src/eas_ota.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_otadata.c b/arm-hybrid-22k/lib_src/eas_otadata.c index 237f832..7463a0c 100644 --- a/arm-hybrid-22k/lib_src/eas_otadata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_otadata.h b/arm-hybrid-22k/lib_src/eas_otadata.h index 63e963f..c06e3d3 100644 --- a/arm-hybrid-22k/lib_src/eas_otadata.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_pan.c b/arm-hybrid-22k/lib_src/eas_pan.c index 373d90e..ae4c69d 100644 --- a/arm-hybrid-22k/lib_src/eas_pan.c +++ b/arm-hybrid-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} */ - 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} */ + 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-hybrid-22k/lib_src/eas_pan.h b/arm-hybrid-22k/lib_src/eas_pan.h index cefa650..cb0a90d 100644 --- a/arm-hybrid-22k/lib_src/eas_pan.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_parser.h b/arm-hybrid-22k/lib_src/eas_parser.h index 5512c82..96ec35b 100644 --- a/arm-hybrid-22k/lib_src/eas_parser.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_pcm.c b/arm-hybrid-22k/lib_src/eas_pcm.c index 64b8f71..ff3f6f9 100644 --- a/arm-hybrid-22k/lib_src/eas_pcm.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_pcm.h b/arm-hybrid-22k/lib_src/eas_pcm.h index c161757..4fc77e9 100644 --- a/arm-hybrid-22k/lib_src/eas_pcm.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_pcmdata.c b/arm-hybrid-22k/lib_src/eas_pcmdata.c index 5649f07..2d85ac2 100644 --- a/arm-hybrid-22k/lib_src/eas_pcmdata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_pcmdata.h b/arm-hybrid-22k/lib_src/eas_pcmdata.h index be2f8e5..ae18d6d 100644 --- a/arm-hybrid-22k/lib_src/eas_pcmdata.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_public.c b/arm-hybrid-22k/lib_src/eas_public.c index ac43261..394a9a1 100644 --- a/arm-hybrid-22k/lib_src/eas_public.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_reverb.c b/arm-hybrid-22k/lib_src/eas_reverb.c index 6d99862..cd5befe 100644 --- a/arm-hybrid-22k/lib_src/eas_reverb.c +++ b/arm-hybrid-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 || valuem_nWet = (EAS_I16)value; - break; - case EAS_PARAM_REVERB_DRY: - if(value>EAS_REVERB_DRY_MAX || valuem_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 || valuem_nWet = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_DRY: + if(value>EAS_REVERB_DRY_MAX || valuem_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-hybrid-22k/lib_src/eas_reverbdata.c b/arm-hybrid-22k/lib_src/eas_reverbdata.c index 5d48c1b..db34b48 100644 --- a/arm-hybrid-22k/lib_src/eas_reverbdata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_reverbdata.h b/arm-hybrid-22k/lib_src/eas_reverbdata.h index ef424da..926ea2e 100644 --- a/arm-hybrid-22k/lib_src/eas_reverbdata.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_rtttl.c b/arm-hybrid-22k/lib_src/eas_rtttl.c index 486ad60..d8253fb 100644 --- a/arm-hybrid-22k/lib_src/eas_rtttl.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_rtttldata.c b/arm-hybrid-22k/lib_src/eas_rtttldata.c index 7a500bd..708a1d9 100644 --- a/arm-hybrid-22k/lib_src/eas_rtttldata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_rtttldata.h b/arm-hybrid-22k/lib_src/eas_rtttldata.h index bf4c38b..31dd522 100644 --- a/arm-hybrid-22k/lib_src/eas_rtttldata.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_smf.c b/arm-hybrid-22k/lib_src/eas_smf.c index 7b56e97..e609583 100644 --- a/arm-hybrid-22k/lib_src/eas_smf.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_smf.h b/arm-hybrid-22k/lib_src/eas_smf.h index 9f66ab9..37c0790 100644 --- a/arm-hybrid-22k/lib_src/eas_smf.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_smfdata.c b/arm-hybrid-22k/lib_src/eas_smfdata.c index 5c27551..383d7f3 100644 --- a/arm-hybrid-22k/lib_src/eas_smfdata.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_smfdata.h b/arm-hybrid-22k/lib_src/eas_smfdata.h index cf59cdc..8861d90 100644 --- a/arm-hybrid-22k/lib_src/eas_smfdata.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_sndlib.h b/arm-hybrid-22k/lib_src/eas_sndlib.h index e05bee0..416be6e 100644 --- a/arm-hybrid-22k/lib_src/eas_sndlib.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_synth.h b/arm-hybrid-22k/lib_src/eas_synth.h index b242b03..6274b7d 100644 --- a/arm-hybrid-22k/lib_src/eas_synth.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_synth_protos.h b/arm-hybrid-22k/lib_src/eas_synth_protos.h index a2ef10d..b03af0f 100644 --- a/arm-hybrid-22k/lib_src/eas_synth_protos.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_synthcfg.h b/arm-hybrid-22k/lib_src/eas_synthcfg.h index 2491e6d..78a4178 100644 --- a/arm-hybrid-22k/lib_src/eas_synthcfg.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_vm_protos.h b/arm-hybrid-22k/lib_src/eas_vm_protos.h index eb49ba8..20f7c09 100644 --- a/arm-hybrid-22k/lib_src/eas_vm_protos.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_voicemgt.c b/arm-hybrid-22k/lib_src/eas_voicemgt.c index 873f29d..ab0b776 100644 --- a/arm-hybrid-22k/lib_src/eas_voicemgt.c +++ b/arm-hybrid-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} */ - 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} */ + 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-hybrid-22k/lib_src/eas_wavefile.c b/arm-hybrid-22k/lib_src/eas_wavefile.c index d3f3ba0..f24bde2 100644 --- a/arm-hybrid-22k/lib_src/eas_wavefile.c +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_wavefile.h b/arm-hybrid-22k/lib_src/eas_wavefile.h index b8b76df..f8814a8 100644 --- a/arm-hybrid-22k/lib_src/eas_wavefile.h +++ b/arm-hybrid-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-hybrid-22k/lib_src/eas_wavefiledata.c b/arm-hybrid-22k/lib_src/eas_wavefiledata.c index 3742aa6..c224a6c 100644 --- a/arm-hybrid-22k/lib_src/eas_wavefiledata.c +++ b/arm-hybrid-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; + diff --git a/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h b/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h index 376fd3a..29d77aa 100644 --- a/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h +++ b/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h @@ -1,21 +1,21 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_wt_IPC_frame.h - * - * Contents and purpose: - * This module contains data definitions for the interprocessor - * communications framework for a split-architecture synthesizer. - * - * This sample version writes IPC data to a file that can be used - * as a test vector for the DSP simulator. For a real-time system - * the file I/O is replaced with an IPC protocol in the hardware. - * - * Synchronization with the DSP is accomplished at the API level, - * i.e. the host code should call EAS_Render when it is ready to - * buffer another block of data for transmission to the DSP. - * - * Copyright Sonic Network Inc. 2005 +/*---------------------------------------------------------------------------- + * + * File: + * eas_wt_IPC_frame.h + * + * Contents and purpose: + * This module contains data definitions for the interprocessor + * communications framework for a split-architecture synthesizer. + * + * This sample version writes IPC data to a file that can be used + * as a test vector for the DSP simulator. For a real-time system + * the file I/O is replaced with an IPC protocol in the hardware. + * + * Synchronization with the DSP is accomplished at the API level, + * i.e. the host code should call EAS_Render when it is ready to + * buffer another block of data for transmission to the DSP. + * + * 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. @@ -28,55 +28,55 @@ * 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) $ - *---------------------------------------------------------------------------- -*/ - -#ifndef _EAS_WT_IPC_FRAME_H -#define _EAS_WT_IPC_FRAME_H - -/*---------------------------------------------------------------------------- - * S_WT_FRAME - * - * This structure contains the common parameters that are updated - *for each frame of audio. - *---------------------------------------------------------------------------- -*/ -typedef struct s_wt_frame_tag -{ - EAS_I32 gainTarget; - EAS_I32 phaseIncrement; - -#if defined(_FILTER_ENABLED) - EAS_I32 k; - EAS_I32 b1; - EAS_I32 b2; -#endif -} S_WT_FRAME; - -/*---------------------------------------------------------------------------- - * S_WT_CONFIG - * - * This structure contains state data for the wavetable engine - *---------------------------------------------------------------------------- -*/ -typedef struct s_wt_config_tag -{ - EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ - EAS_U32 loopStart; /* points to first sample at start of loop */ - EAS_U32 phaseAccum; /* current sample, integer portion of phase */ - -#if (NUM_OUTPUT_CHANNELS == 2) - EAS_I16 gainLeft; /* left channel gain */ - EAS_I16 gainRight; /* right channel gain */ -#endif - - EAS_I16 gain; /* current voice gain */ -} S_WT_CONFIG; - -#endif - + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WT_IPC_FRAME_H +#define _EAS_WT_IPC_FRAME_H + +/*---------------------------------------------------------------------------- + * S_WT_FRAME + * + * This structure contains the common parameters that are updated + *for each frame of audio. + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_frame_tag +{ + EAS_I32 gainTarget; + EAS_I32 phaseIncrement; + +#if defined(_FILTER_ENABLED) + EAS_I32 k; + EAS_I32 b1; + EAS_I32 b2; +#endif +} S_WT_FRAME; + +/*---------------------------------------------------------------------------- + * S_WT_CONFIG + * + * This structure contains state data for the wavetable engine + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_config_tag +{ + EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ + EAS_U32 loopStart; /* points to first sample at start of loop */ + EAS_U32 phaseAccum; /* current sample, integer portion of phase */ + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I16 gainLeft; /* left channel gain */ + EAS_I16 gainRight; /* right channel gain */ +#endif + + EAS_I16 gain; /* current voice gain */ +} S_WT_CONFIG; + +#endif + diff --git a/arm-hybrid-22k/lib_src/eas_wtengine.c b/arm-hybrid-22k/lib_src/eas_wtengine.c index 4215924..8407634 100644 --- a/arm-hybrid-22k/lib_src/eas_wtengine.c +++ b/arm-hybrid-22k/lib_src/eas_wtengine.c @@ -1,13 +1,13 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_wtengine.c - * - * Contents and purpose: - * This file contains the critical synthesizer components that need to - * be optimized for best performance. - * - * Copyright Sonic Network Inc. 2004-2005 +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtengine.c + * + * Contents and purpose: + * This file contains the critical synthesizer components that need to + * be optimized for best performance. + * + * 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. @@ -20,642 +20,642 @@ * 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: 844 $ - * $Date: 2007-08-23 14:33:32 -0700 (Thu, 23 Aug 2007) $ - *---------------------------------------------------------------------------- -*/ - -/*------------------------------------ - * includes - *------------------------------------ -*/ -#include "eas_types.h" -#include "eas_math.h" -#include "eas_audioconst.h" -#include "eas_sndlib.h" -#include "eas_wtengine.h" -#include "eas_mixer.h" - -/*---------------------------------------------------------------------------- - * prototypes - *---------------------------------------------------------------------------- -*/ -extern void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); -extern void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); - -#if defined(_OPTIMIZED_MONO) -extern void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); -#else -extern void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); -extern void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); -#endif - -#if defined(_FILTER_ENABLED) -extern void WT_VoiceFilter (S_FILTER_CONTROL*pFilter, S_WT_INT_FRAME *pWTIntFrame); -#endif - -#if defined(_OPTIMIZED_MONO) || !defined(NATIVE_EAS_KERNEL) -/*---------------------------------------------------------------------------- - * WT_VoiceGain - *---------------------------------------------------------------------------- - * Purpose: - * Output gain for individual voice - * - * Inputs: - * - * Outputs: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pWTVoice) reserved for future use */ -void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) -{ - EAS_I32 *pMixBuffer; - EAS_PCM *pInputBuffer; - EAS_I32 gain; - EAS_I32 gainIncrement; - EAS_I32 tmp0; - EAS_I32 tmp1; - EAS_I32 tmp2; - EAS_I32 numSamples; - -#if (NUM_OUTPUT_CHANNELS == 2) - EAS_I32 gainLeft, gainRight; -#endif - - /* initialize some local variables */ - numSamples = pWTIntFrame->numSamples; - pMixBuffer = pWTIntFrame->pMixBuffer; - pInputBuffer = pWTIntFrame->pAudioBuffer; - - /*lint -e{703} */ - gainIncrement = (pWTIntFrame->frame.gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); - if (gainIncrement < 0) - gainIncrement++; - /*lint -e{703} */ - gain = pWTIntFrame->prevGain << 16; - -#if (NUM_OUTPUT_CHANNELS == 2) - gainLeft = pWTVoice->gainLeft; - gainRight = pWTVoice->gainRight; -#endif - - while (numSamples--) { - - /* incremental gain step to prevent zipper noise */ - tmp0 = *pInputBuffer++; - gain += gainIncrement; - /*lint -e{704} */ - tmp2 = gain >> 16; - - /* scale sample by gain */ - tmp2 *= tmp0; - - - /* stereo output */ -#if (NUM_OUTPUT_CHANNELS == 2) - /*lint -e{704} */ - tmp2 = tmp2 >> 14; - - /* get the current sample in the final mix buffer */ - tmp1 = *pMixBuffer; - - /* left channel */ - tmp0 = tmp2 * gainLeft; - /*lint -e{704} */ - tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; - tmp1 += tmp0; - *pMixBuffer++ = tmp1; - - /* get the current sample in the final mix buffer */ - tmp1 = *pMixBuffer; - - /* right channel */ - tmp0 = tmp2 * gainRight; - /*lint -e{704} */ - tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; - tmp1 += tmp0; - *pMixBuffer++ = tmp1; - - /* mono output */ -#else - - /* get the current sample in the final mix buffer */ - tmp1 = *pMixBuffer; - /*lint -e{704} */ - tmp2 = tmp2 >> (NUM_MIXER_GUARD_BITS - 1); - tmp1 += tmp2; - *pMixBuffer++ = tmp1; -#endif - - } -} -#endif - -#ifndef NATIVE_EAS_KERNEL -/*---------------------------------------------------------------------------- - * WT_Interpolate - *---------------------------------------------------------------------------- - * Purpose: - * Interpolation engine for wavetable synth - * - * Inputs: - * - * Outputs: - * - *---------------------------------------------------------------------------- -*/ -void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) -{ - EAS_PCM *pOutputBuffer; - EAS_I32 phaseInc; - EAS_I32 phaseFrac; - EAS_I32 acc0; - const EAS_SAMPLE *pSamples; - const EAS_SAMPLE *loopEnd; - EAS_I32 samp1; - EAS_I32 samp2; - EAS_I32 numSamples; - - /* initialize some local variables */ - numSamples = pWTIntFrame->numSamples; - pOutputBuffer = pWTIntFrame->pAudioBuffer; - - loopEnd = (const EAS_SAMPLE*) pWTVoice->loopEnd + 1; - pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; - /*lint -e{713} truncation is OK */ - phaseFrac = pWTVoice->phaseFrac; - phaseInc = pWTIntFrame->frame.phaseIncrement; - - /* fetch adjacent samples */ -#if defined(_8_BIT_SAMPLES) - /*lint -e{701} */ - samp1 = pSamples[0] << 8; - /*lint -e{701} */ - samp2 = pSamples[1] << 8; -#else - samp1 = pSamples[0]; - samp2 = pSamples[1]; -#endif - - while (numSamples--) { - - /* linear interpolation */ - acc0 = samp2 - samp1; - acc0 = acc0 * phaseFrac; - /*lint -e{704} */ - acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); - - /* save new output sample in buffer */ - /*lint -e{704} */ - *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); - - /* increment phase */ - phaseFrac += phaseInc; - /*lint -e{704} */ - acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; - - /* next sample */ - if (acc0 > 0) { - - /* advance sample pointer */ - pSamples += acc0; - phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); - - /* check for loop end */ - acc0 = (EAS_I32) (pSamples - loopEnd); - if (acc0 >= 0) - pSamples = (const EAS_SAMPLE*) pWTVoice->loopStart + acc0; - - /* fetch new samples */ -#if defined(_8_BIT_SAMPLES) - /*lint -e{701} */ - samp1 = pSamples[0] << 8; - /*lint -e{701} */ - samp2 = pSamples[1] << 8; -#else - samp1 = pSamples[0]; - samp2 = pSamples[1]; -#endif - } - } - - /* save pointer and phase */ - pWTVoice->phaseAccum = (EAS_U32) pSamples; - pWTVoice->phaseFrac = (EAS_U32) phaseFrac; -} -#endif - -#ifndef NATIVE_EAS_KERNEL -/*---------------------------------------------------------------------------- - * WT_InterpolateNoLoop - *---------------------------------------------------------------------------- - * Purpose: - * Interpolation engine for wavetable synth - * - * Inputs: - * - * Outputs: - * - *---------------------------------------------------------------------------- -*/ -void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) -{ - EAS_PCM *pOutputBuffer; - EAS_I32 phaseInc; - EAS_I32 phaseFrac; - EAS_I32 acc0; - const EAS_SAMPLE *pSamples; - EAS_I32 samp1; - EAS_I32 samp2; - EAS_I32 numSamples; - - /* initialize some local variables */ - numSamples = pWTIntFrame->numSamples; - pOutputBuffer = pWTIntFrame->pAudioBuffer; - - phaseInc = pWTIntFrame->frame.phaseIncrement; - pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; - phaseFrac = (EAS_I32)pWTVoice->phaseFrac; - - /* fetch adjacent samples */ -#if defined(_8_BIT_SAMPLES) - /*lint -e{701} */ - samp1 = pSamples[0] << 8; - /*lint -e{701} */ - samp2 = pSamples[1] << 8; -#else - samp1 = pSamples[0]; - samp2 = pSamples[1]; -#endif - - while (numSamples--) { - - - /* linear interpolation */ - acc0 = samp2 - samp1; - acc0 = acc0 * phaseFrac; - /*lint -e{704} */ - acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); - - /* save new output sample in buffer */ - /*lint -e{704} */ - *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); - - /* increment phase */ - phaseFrac += phaseInc; - /*lint -e{704} */ - acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; - - /* next sample */ - if (acc0 > 0) { - - /* advance sample pointer */ - pSamples += acc0; - phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); - - /* fetch new samples */ -#if defined(_8_BIT_SAMPLES) - /*lint -e{701} */ - samp1 = pSamples[0] << 8; - /*lint -e{701} */ - samp2 = pSamples[1] << 8; -#else - samp1 = pSamples[0]; - samp2 = pSamples[1]; -#endif - } - } - - /* save pointer and phase */ - pWTVoice->phaseAccum = (EAS_U32) pSamples; - pWTVoice->phaseFrac = (EAS_U32) phaseFrac; -} -#endif - -#if defined(_FILTER_ENABLED) && !defined(NATIVE_EAS_KERNEL) -/*---------------------------------------------------------------------------- - * WT_VoiceFilter - *---------------------------------------------------------------------------- - * Purpose: - * Implements a 2-pole filter - * - * Inputs: - * - * Outputs: - * - *---------------------------------------------------------------------------- -*/ -void WT_VoiceFilter (S_FILTER_CONTROL *pFilter, S_WT_INT_FRAME *pWTIntFrame) -{ - EAS_PCM *pAudioBuffer; - EAS_I32 k; - EAS_I32 b1; - EAS_I32 b2; - EAS_I32 z1; - EAS_I32 z2; - EAS_I32 acc0; - EAS_I32 acc1; - EAS_I32 numSamples; - - /* initialize some local variables */ - numSamples = pWTIntFrame->numSamples; - pAudioBuffer = pWTIntFrame->pAudioBuffer; - - z1 = pFilter->z1; - z2 = pFilter->z2; - b1 = -pWTIntFrame->frame.b1; - - /*lint -e{702} */ - b2 = -pWTIntFrame->frame.b2 >> 1; - - /*lint -e{702} */ - k = pWTIntFrame->frame.k >> 1; - - while (numSamples--) - { - - /* do filter calculations */ - acc0 = *pAudioBuffer; - acc1 = z1 * b1; - acc1 += z2 * b2; - acc0 = acc1 + k * acc0; - z2 = z1; - - /*lint -e{702} */ - z1 = acc0 >> 14; - *pAudioBuffer++ = (EAS_I16) z1; - } - - /* save delay values */ - pFilter->z1 = (EAS_I16) z1; - pFilter->z2 = (EAS_I16) z2; -} -#endif - -/*---------------------------------------------------------------------------- - * WT_NoiseGenerator - *---------------------------------------------------------------------------- - * Purpose: - * Generate pseudo-white noise using PRNG and interpolation engine - * - * Inputs: - * - * Outputs: - * - * Notes: - * This output is scaled -12dB to prevent saturation in the filter. For a - * high quality synthesizer, the output can be set to full scale, however - * if the filter is used, it can overflow with certain coefficients. In this - * case, either a saturation operation should take in the filter before - * scaling back to 16 bits or the signal path should be increased to 18 bits - * or more. - *---------------------------------------------------------------------------- -*/ - void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) - { - EAS_PCM *pOutputBuffer; - EAS_I32 phaseInc; - EAS_I32 tmp0; - EAS_I32 tmp1; - EAS_I32 nInterpolatedSample; - EAS_I32 numSamples; - - /* initialize some local variables */ - numSamples = pWTIntFrame->numSamples; - pOutputBuffer = pWTIntFrame->pAudioBuffer; - phaseInc = pWTIntFrame->frame.phaseIncrement; - - /* get last two samples generated */ - /*lint -e{704} */ - tmp0 = (EAS_I32) (pWTVoice->phaseAccum) >> 18; - /*lint -e{704} */ - tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; - - /* generate a buffer of noise */ - while (numSamples--) { - nInterpolatedSample = MULT_AUDIO_COEF( tmp0, (PHASE_ONE - pWTVoice->phaseFrac)); - nInterpolatedSample += MULT_AUDIO_COEF( tmp1, pWTVoice->phaseFrac); - *pOutputBuffer++ = (EAS_PCM) nInterpolatedSample; - - /* update PRNG */ - pWTVoice->phaseFrac += (EAS_U32) phaseInc; - if (GET_PHASE_INT_PART(pWTVoice->phaseFrac)) { - tmp0 = tmp1; - pWTVoice->phaseAccum = pWTVoice->loopEnd; - pWTVoice->loopEnd = (5 * pWTVoice->loopEnd + 1); - tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; - pWTVoice->phaseFrac = GET_PHASE_FRAC_PART(pWTVoice->phaseFrac); - } - - } -} - -#ifndef _OPTIMIZED_MONO -/*---------------------------------------------------------------------------- - * WT_ProcessVoice - *---------------------------------------------------------------------------- - * Purpose: - * This routine does the block processing for one voice. It is isolated - * from the main synth code to allow for various implementation-specific - * optimizations. It calls the interpolator, filter, and gain routines - * appropriate for a particular configuration. - * - * Inputs: - * - * Outputs: - * - * Notes: - *---------------------------------------------------------------------------- -*/ -void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) -{ - - /* use noise generator */ - if (pWTVoice->loopStart == WT_NOISE_GENERATOR) - WT_NoiseGenerator(pWTVoice, pWTIntFrame); - - /* generate interpolated samples for looped waves */ - else if (pWTVoice->loopStart != pWTVoice->loopEnd) - WT_Interpolate(pWTVoice, pWTIntFrame); - - /* generate interpolated samples for unlooped waves */ - else - { - WT_InterpolateNoLoop(pWTVoice, pWTIntFrame); - } - -#ifdef _FILTER_ENABLED - if (pWTIntFrame->frame.k != 0) - WT_VoiceFilter(&pWTVoice->filter, pWTIntFrame); -#endif - -//2 TEST NEW MIXER FUNCTION -#ifdef UNIFIED_MIXER - { - EAS_I32 gainLeft, gainIncLeft; - -#if (NUM_OUTPUT_CHANNELS == 2) - EAS_I32 gainRight, gainIncRight; -#endif - - gainLeft = (pWTIntFrame->prevGain * pWTVoice->gainLeft) << 1; - gainIncLeft = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainLeft) << 1) - gainLeft) >> SYNTH_UPDATE_PERIOD_IN_BITS; - -#if (NUM_OUTPUT_CHANNELS == 2) - gainRight = (pWTIntFrame->prevGain * pWTVoice->gainRight) << 1; - gainIncRight = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainRight) << 1) - gainRight) >> SYNTH_UPDATE_PERIOD_IN_BITS; - EAS_MixStream( - pWTIntFrame->pAudioBuffer, - pWTIntFrame->pMixBuffer, - pWTIntFrame->numSamples, - gainLeft, - gainRight, - gainIncLeft, - gainIncRight, - MIX_FLAGS_STEREO_OUTPUT); - -#else - EAS_MixStream( - pWTIntFrame->pAudioBuffer, - pWTIntFrame->pMixBuffer, - pWTIntFrame->numSamples, - gainLeft, - 0, - gainIncLeft, - 0, - 0); -#endif - } - -#else - /* apply gain, and left and right gain */ - WT_VoiceGain(pWTVoice, pWTIntFrame); -#endif -} -#endif - -#if defined(_OPTIMIZED_MONO) && !defined(NATIVE_EAS_KERNEL) -/*---------------------------------------------------------------------------- - * WT_InterpolateMono - *---------------------------------------------------------------------------- - * Purpose: - * A C version of the sample interpolation + gain routine, optimized for mono. - * It's not pretty, but it matches the assembly code exactly. - * - * Inputs: - * - * Outputs: - * - * Notes: - *---------------------------------------------------------------------------- -*/ -void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) -{ - EAS_I32 *pMixBuffer; - const EAS_I8 *pLoopEnd; - const EAS_I8 *pCurrentPhaseInt; - EAS_I32 numSamples; - EAS_I32 gain; - EAS_I32 gainIncrement; - EAS_I32 currentPhaseFrac; - EAS_I32 phaseInc; - EAS_I32 tmp0; - EAS_I32 tmp1; - EAS_I32 tmp2; - EAS_I8 *pLoopStart; - - numSamples = pWTIntFrame->numSamples; - pMixBuffer = pWTIntFrame->pMixBuffer; - - /* calculate gain increment */ - gainIncrement = (pWTIntFrame->gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); - if (gainIncrement < 0) - gainIncrement++; - gain = pWTIntFrame->prevGain << 16; - - pCurrentPhaseInt = pWTVoice->pPhaseAccum; - currentPhaseFrac = pWTVoice->phaseFrac; - phaseInc = pWTIntFrame->phaseIncrement; - - pLoopStart = pWTVoice->pLoopStart; - pLoopEnd = pWTVoice->pLoopEnd + 1; - -InterpolationLoop: - tmp0 = (EAS_I32)(pCurrentPhaseInt - pLoopEnd); - if (tmp0 >= 0) - pCurrentPhaseInt = pLoopStart + tmp0; - - tmp0 = *pCurrentPhaseInt; - tmp1 = *(pCurrentPhaseInt + 1); - - tmp2 = phaseInc + currentPhaseFrac; - - tmp1 = tmp1 - tmp0; - tmp1 = tmp1 * currentPhaseFrac; - - tmp1 = tmp0 + (tmp1 >> NUM_EG1_FRAC_BITS); - - pCurrentPhaseInt += (tmp2 >> NUM_PHASE_FRAC_BITS); - currentPhaseFrac = tmp2 & PHASE_FRAC_MASK; - - gain += gainIncrement; - tmp2 = (gain >> SYNTH_UPDATE_PERIOD_IN_BITS); - - tmp0 = *pMixBuffer; - tmp2 = tmp1 * tmp2; - tmp2 = (tmp2 >> 9); - tmp0 = tmp2 + tmp0; - *pMixBuffer++ = tmp0; - - numSamples--; - if (numSamples) - goto InterpolationLoop; - - pWTVoice->pPhaseAccum = pCurrentPhaseInt; - pWTVoice->phaseFrac = currentPhaseFrac; - /*lint -e{702} */ - pWTVoice->gain = (EAS_I16)(gain >> SYNTH_UPDATE_PERIOD_IN_BITS); -} -#endif - -#ifdef _OPTIMIZED_MONO -/*---------------------------------------------------------------------------- - * WT_ProcessVoice - *---------------------------------------------------------------------------- - * Purpose: - * This routine does the block processing for one voice. It is isolated - * from the main synth code to allow for various implementation-specific - * optimizations. It calls the interpolator, filter, and gain routines - * appropriate for a particular configuration. - * - * Inputs: - * - * Outputs: - * - * Notes: - * This special version works handles an optimized mono-only signal - * without filters - *---------------------------------------------------------------------------- -*/ -void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) -{ - - /* use noise generator */ - if (pWTVoice->loopStart== WT_NOISE_GENERATOR) - { - WT_NoiseGenerator(pWTVoice, pWTIntFrame); - WT_VoiceGain(pWTVoice, pWTIntFrame); - } - - /* or generate interpolated samples */ - else - { - WT_InterpolateMono(pWTVoice, pWTIntFrame); - } -} -#endif - + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 844 $ + * $Date: 2007-08-23 14:33:32 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_types.h" +#include "eas_math.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_wtengine.h" +#include "eas_mixer.h" + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +extern void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); + +#if defined(_OPTIMIZED_MONO) +extern void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#else +extern void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_FILTER_ENABLED) +extern void WT_VoiceFilter (S_FILTER_CONTROL*pFilter, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_OPTIMIZED_MONO) || !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceGain + *---------------------------------------------------------------------------- + * Purpose: + * Output gain for individual voice + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pWTVoice) reserved for future use */ +void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + EAS_PCM *pInputBuffer; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I32 numSamples; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainLeft, gainRight; +#endif + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + pInputBuffer = pWTIntFrame->pAudioBuffer; + + /*lint -e{703} */ + gainIncrement = (pWTIntFrame->frame.gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + /*lint -e{703} */ + gain = pWTIntFrame->prevGain << 16; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainLeft = pWTVoice->gainLeft; + gainRight = pWTVoice->gainRight; +#endif + + while (numSamples--) { + + /* incremental gain step to prevent zipper noise */ + tmp0 = *pInputBuffer++; + gain += gainIncrement; + /*lint -e{704} */ + tmp2 = gain >> 16; + + /* scale sample by gain */ + tmp2 *= tmp0; + + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} */ + tmp2 = tmp2 >> 14; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* left channel */ + tmp0 = tmp2 * gainLeft; + /*lint -e{704} */ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* right channel */ + tmp0 = tmp2 * gainRight; + /*lint -e{704} */ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* mono output */ +#else + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + /*lint -e{704} */ + tmp2 = tmp2 >> (NUM_MIXER_GUARD_BITS - 1); + tmp1 += tmp2; + *pMixBuffer++ = tmp1; +#endif + + } +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_Interpolate + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + const EAS_SAMPLE *loopEnd; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + loopEnd = (const EAS_SAMPLE*) pWTVoice->loopEnd + 1; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + /*lint -e{713} truncation is OK */ + phaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} */ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} */ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} */ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* check for loop end */ + acc0 = (EAS_I32) (pSamples - loopEnd); + if (acc0 >= 0) + pSamples = (const EAS_SAMPLE*) pWTVoice->loopStart + acc0; + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_InterpolateNoLoop + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + phaseInc = pWTIntFrame->frame.phaseIncrement; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + phaseFrac = (EAS_I32)pWTVoice->phaseFrac; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} */ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} */ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} */ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#if defined(_FILTER_ENABLED) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceFilter + *---------------------------------------------------------------------------- + * Purpose: + * Implements a 2-pole filter + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_VoiceFilter (S_FILTER_CONTROL *pFilter, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pAudioBuffer; + EAS_I32 k; + EAS_I32 b1; + EAS_I32 b2; + EAS_I32 z1; + EAS_I32 z2; + EAS_I32 acc0; + EAS_I32 acc1; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pAudioBuffer = pWTIntFrame->pAudioBuffer; + + z1 = pFilter->z1; + z2 = pFilter->z2; + b1 = -pWTIntFrame->frame.b1; + + /*lint -e{702} */ + b2 = -pWTIntFrame->frame.b2 >> 1; + + /*lint -e{702} */ + k = pWTIntFrame->frame.k >> 1; + + while (numSamples--) + { + + /* do filter calculations */ + acc0 = *pAudioBuffer; + acc1 = z1 * b1; + acc1 += z2 * b2; + acc0 = acc1 + k * acc0; + z2 = z1; + + /*lint -e{702} */ + z1 = acc0 >> 14; + *pAudioBuffer++ = (EAS_I16) z1; + } + + /* save delay values */ + pFilter->z1 = (EAS_I16) z1; + pFilter->z2 = (EAS_I16) z2; +} +#endif + +/*---------------------------------------------------------------------------- + * WT_NoiseGenerator + *---------------------------------------------------------------------------- + * Purpose: + * Generate pseudo-white noise using PRNG and interpolation engine + * + * Inputs: + * + * Outputs: + * + * Notes: + * This output is scaled -12dB to prevent saturation in the filter. For a + * high quality synthesizer, the output can be set to full scale, however + * if the filter is used, it can overflow with certain coefficients. In this + * case, either a saturation operation should take in the filter before + * scaling back to 16 bits or the signal path should be increased to 18 bits + * or more. + *---------------------------------------------------------------------------- +*/ + void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) + { + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 nInterpolatedSample; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* get last two samples generated */ + /*lint -e{704} */ + tmp0 = (EAS_I32) (pWTVoice->phaseAccum) >> 18; + /*lint -e{704} */ + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + + /* generate a buffer of noise */ + while (numSamples--) { + nInterpolatedSample = MULT_AUDIO_COEF( tmp0, (PHASE_ONE - pWTVoice->phaseFrac)); + nInterpolatedSample += MULT_AUDIO_COEF( tmp1, pWTVoice->phaseFrac); + *pOutputBuffer++ = (EAS_PCM) nInterpolatedSample; + + /* update PRNG */ + pWTVoice->phaseFrac += (EAS_U32) phaseInc; + if (GET_PHASE_INT_PART(pWTVoice->phaseFrac)) { + tmp0 = tmp1; + pWTVoice->phaseAccum = pWTVoice->loopEnd; + pWTVoice->loopEnd = (5 * pWTVoice->loopEnd + 1); + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + pWTVoice->phaseFrac = GET_PHASE_FRAC_PART(pWTVoice->phaseFrac); + } + + } +} + +#ifndef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart == WT_NOISE_GENERATOR) + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for looped waves */ + else if (pWTVoice->loopStart != pWTVoice->loopEnd) + WT_Interpolate(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for unlooped waves */ + else + { + WT_InterpolateNoLoop(pWTVoice, pWTIntFrame); + } + +#ifdef _FILTER_ENABLED + if (pWTIntFrame->frame.k != 0) + WT_VoiceFilter(&pWTVoice->filter, pWTIntFrame); +#endif + +//2 TEST NEW MIXER FUNCTION +#ifdef UNIFIED_MIXER + { + EAS_I32 gainLeft, gainIncLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + + gainLeft = (pWTIntFrame->prevGain * pWTVoice->gainLeft) << 1; + gainIncLeft = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainLeft) << 1) - gainLeft) >> SYNTH_UPDATE_PERIOD_IN_BITS; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainRight = (pWTIntFrame->prevGain * pWTVoice->gainRight) << 1; + gainIncRight = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainRight) << 1) - gainRight) >> SYNTH_UPDATE_PERIOD_IN_BITS; + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + gainRight, + gainIncLeft, + gainIncRight, + MIX_FLAGS_STEREO_OUTPUT); + +#else + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + 0, + gainIncLeft, + 0, + 0); +#endif + } + +#else + /* apply gain, and left and right gain */ + WT_VoiceGain(pWTVoice, pWTIntFrame); +#endif +} +#endif + +#if defined(_OPTIMIZED_MONO) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_InterpolateMono + *---------------------------------------------------------------------------- + * Purpose: + * A C version of the sample interpolation + gain routine, optimized for mono. + * It's not pretty, but it matches the assembly code exactly. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + const EAS_I8 *pLoopEnd; + const EAS_I8 *pCurrentPhaseInt; + EAS_I32 numSamples; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 currentPhaseFrac; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I8 *pLoopStart; + + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + + /* calculate gain increment */ + gainIncrement = (pWTIntFrame->gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + gain = pWTIntFrame->prevGain << 16; + + pCurrentPhaseInt = pWTVoice->pPhaseAccum; + currentPhaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->phaseIncrement; + + pLoopStart = pWTVoice->pLoopStart; + pLoopEnd = pWTVoice->pLoopEnd + 1; + +InterpolationLoop: + tmp0 = (EAS_I32)(pCurrentPhaseInt - pLoopEnd); + if (tmp0 >= 0) + pCurrentPhaseInt = pLoopStart + tmp0; + + tmp0 = *pCurrentPhaseInt; + tmp1 = *(pCurrentPhaseInt + 1); + + tmp2 = phaseInc + currentPhaseFrac; + + tmp1 = tmp1 - tmp0; + tmp1 = tmp1 * currentPhaseFrac; + + tmp1 = tmp0 + (tmp1 >> NUM_EG1_FRAC_BITS); + + pCurrentPhaseInt += (tmp2 >> NUM_PHASE_FRAC_BITS); + currentPhaseFrac = tmp2 & PHASE_FRAC_MASK; + + gain += gainIncrement; + tmp2 = (gain >> SYNTH_UPDATE_PERIOD_IN_BITS); + + tmp0 = *pMixBuffer; + tmp2 = tmp1 * tmp2; + tmp2 = (tmp2 >> 9); + tmp0 = tmp2 + tmp0; + *pMixBuffer++ = tmp0; + + numSamples--; + if (numSamples) + goto InterpolationLoop; + + pWTVoice->pPhaseAccum = pCurrentPhaseInt; + pWTVoice->phaseFrac = currentPhaseFrac; + /*lint -e{702} */ + pWTVoice->gain = (EAS_I16)(gain >> SYNTH_UPDATE_PERIOD_IN_BITS); +} +#endif + +#ifdef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + * This special version works handles an optimized mono-only signal + * without filters + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart== WT_NOISE_GENERATOR) + { + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + WT_VoiceGain(pWTVoice, pWTIntFrame); + } + + /* or generate interpolated samples */ + else + { + WT_InterpolateMono(pWTVoice, pWTIntFrame); + } +} +#endif + diff --git a/arm-hybrid-22k/lib_src/eas_wtengine.h b/arm-hybrid-22k/lib_src/eas_wtengine.h index 6401322..bba7a5e 100644 --- a/arm-hybrid-22k/lib_src/eas_wtengine.h +++ b/arm-hybrid-22k/lib_src/eas_wtengine.h @@ -1,12 +1,12 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_wtengine.h - * - * Contents and purpose: - * This file defines the interface for wavetable synthesis engine - * - * Copyright Sonic Network Inc. 2004 +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtengine.h + * + * Contents and purpose: + * This file defines the interface for wavetable synthesis engine + * + * 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,153 +19,153 @@ * 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) $ - *---------------------------------------------------------------------------- -*/ - -#ifndef _EAS_WTENGINE_H -#define _EAS_WTENGINE_H - -/* option sanity check */ -#if defined(_OPTIMIZED_MONO) && defined(_FILTER_ENABLED) -#error "Incompatible build settings: _OPTIMIZED_MONO cannot be used with _FILTER_ENABLED" -#endif - -#if defined(_OPTIMIZED_MONO) && (NUM_OUTPUT_CHANNELS != 1) -#error "Incompatible build settings: _OPTIMIZED_MONO can only be used with NUM_OUTPUT_CHANNELS = 1" -#endif - -#include "eas_wt_IPC_frame.h" - -/*---------------------------------------------------------------------------- - * defines - *---------------------------------------------------------------------------- -*/ -#define WT_NOISE_GENERATOR 0xffffffff - -/*---------------------------------------------------------------------------- - * typedefs - *---------------------------------------------------------------------------- -*/ - -/*---------------------------------------------------------------------------- - * S_WT_INT_FRAME - * - * This structure includes S_WT_FRAME plus the bus mixing - * parameters for the internal voices. - *---------------------------------------------------------------------------- -*/ -typedef struct s_wt_int_frame_tag -{ - S_WT_FRAME frame; - EAS_PCM *pAudioBuffer; - EAS_I32 *pMixBuffer; - EAS_I32 numSamples; - EAS_I32 prevGain; -} S_WT_INT_FRAME; - -#if defined(_FILTER_ENABLED) -/*---------------------------------------------------------------------------- - * S_FILTER_CONTROL data structure - *---------------------------------------------------------------------------- -*/ -typedef struct s_filter_control_tag -{ - EAS_I16 z1; /* 1 sample delay state variable */ - EAS_I16 z2; /* 2 sample delay state variable */ -} S_FILTER_CONTROL; -#endif - -/*------------------------------------ - * S_LFO_CONTROL data structure - *------------------------------------ -*/ -typedef struct s_lfo_control_tag -{ - EAS_I16 lfoValue; /* LFO current output value */ - EAS_I16 lfoPhase; /* LFO current phase */ -} S_LFO_CONTROL; - -/* bit definitions for S_WT_VOICE:flags */ -#define WT_FLAGS_ADPCM_NIBBLE 1 /* high/low nibble flag */ -#define WT_FLAGS_ADPCM_READY 2 /* first 2 samples are decoded */ -#define WT_FLAGS_USE_ADPCM 4 /* sample is ADPCM encoded */ - -/* eg1State and eg2State */ -typedef enum { - eEnvelopeStateInit = 0, - eEnvelopeStateDelay, - eEnvelopeStateAttack, - eEnvelopeStateHold, - eEnvelopeStateDecay, - eEnvelopeStateSustain, - eEnvelopeStateRelease, - eEnvelopeStateMuting, - eEnvelopeStateMuted, - eEnvelopeStateInvalid /* should never be in this state! */ -} E_ENVELOPE_STATE; - -#define DEFAULT_EG1_STATE eEnvelopeStateAttack -#define DEFAULT_EG1_VALUE 0 -#define DEFAULT_EG1_INCREMENT 0 -#define DEFAULT_EG2_STATE eEnvelopeStateAttack -#define DEFAULT_EG2_VALUE 0 -#define DEFAULT_EG2_INCREMENT 0 - -/*---------------------------------------------------------------------------- - * S_WT_VOICE - * - * This structure contains state data for the wavetable engine - *---------------------------------------------------------------------------- -*/ -typedef struct s_wt_voice_tag -{ - EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ - EAS_U32 loopStart; /* points to first sample at start of loop */ - EAS_U32 phaseAccum; /* current sample, integer portion of phase */ - EAS_U32 phaseFrac; /* fractional portion of phase */ - -#if (NUM_OUTPUT_CHANNELS == 2) - EAS_I16 gainLeft; /* current gain, left ch */ - EAS_I16 gainRight; /* current gain, right ch */ -#endif - -#if defined(_FILTER_ENABLED) - S_FILTER_CONTROL filter; /* low pass filter */ -#endif - - S_LFO_CONTROL modLFO; /* modulator LFO */ - -#ifdef DLS_SYNTHESIZER - S_LFO_CONTROL vibLFO; /* vibrato LFO */ -#endif - - /* envelope control */ - EAS_I16 eg1Value; - EAS_I16 eg2Value; - EAS_I16 eg1Increment; - EAS_I16 eg2Increment; - EAS_U8 eg1State; - EAS_U8 eg2State; - - EAS_U16 artIndex; /* index to articulation params */ - -} S_WT_VOICE; - -/*---------------------------------------------------------------------------- - * prototypes - *---------------------------------------------------------------------------- -*/ -EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update); -void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); - -#ifdef EAS_SPLIT_WT_SYNTH -void WTE_ConfigVoice (EAS_I32 voiceNum, S_WT_CONFIG *pWTConfig, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); -void WTE_ProcessVoice (EAS_I32 voiceNum, S_WT_FRAME *pWTParams, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); -#endif - -#endif + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WTENGINE_H +#define _EAS_WTENGINE_H + +/* option sanity check */ +#if defined(_OPTIMIZED_MONO) && defined(_FILTER_ENABLED) +#error "Incompatible build settings: _OPTIMIZED_MONO cannot be used with _FILTER_ENABLED" +#endif + +#if defined(_OPTIMIZED_MONO) && (NUM_OUTPUT_CHANNELS != 1) +#error "Incompatible build settings: _OPTIMIZED_MONO can only be used with NUM_OUTPUT_CHANNELS = 1" +#endif + +#include "eas_wt_IPC_frame.h" + +/*---------------------------------------------------------------------------- + * defines + *---------------------------------------------------------------------------- +*/ +#define WT_NOISE_GENERATOR 0xffffffff + +/*---------------------------------------------------------------------------- + * typedefs + *---------------------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- + * S_WT_INT_FRAME + * + * This structure includes S_WT_FRAME plus the bus mixing + * parameters for the internal voices. + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_int_frame_tag +{ + S_WT_FRAME frame; + EAS_PCM *pAudioBuffer; + EAS_I32 *pMixBuffer; + EAS_I32 numSamples; + EAS_I32 prevGain; +} S_WT_INT_FRAME; + +#if defined(_FILTER_ENABLED) +/*---------------------------------------------------------------------------- + * S_FILTER_CONTROL data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_filter_control_tag +{ + EAS_I16 z1; /* 1 sample delay state variable */ + EAS_I16 z2; /* 2 sample delay state variable */ +} S_FILTER_CONTROL; +#endif + +/*------------------------------------ + * S_LFO_CONTROL data structure + *------------------------------------ +*/ +typedef struct s_lfo_control_tag +{ + EAS_I16 lfoValue; /* LFO current output value */ + EAS_I16 lfoPhase; /* LFO current phase */ +} S_LFO_CONTROL; + +/* bit definitions for S_WT_VOICE:flags */ +#define WT_FLAGS_ADPCM_NIBBLE 1 /* high/low nibble flag */ +#define WT_FLAGS_ADPCM_READY 2 /* first 2 samples are decoded */ +#define WT_FLAGS_USE_ADPCM 4 /* sample is ADPCM encoded */ + +/* eg1State and eg2State */ +typedef enum { + eEnvelopeStateInit = 0, + eEnvelopeStateDelay, + eEnvelopeStateAttack, + eEnvelopeStateHold, + eEnvelopeStateDecay, + eEnvelopeStateSustain, + eEnvelopeStateRelease, + eEnvelopeStateMuting, + eEnvelopeStateMuted, + eEnvelopeStateInvalid /* should never be in this state! */ +} E_ENVELOPE_STATE; + +#define DEFAULT_EG1_STATE eEnvelopeStateAttack +#define DEFAULT_EG1_VALUE 0 +#define DEFAULT_EG1_INCREMENT 0 +#define DEFAULT_EG2_STATE eEnvelopeStateAttack +#define DEFAULT_EG2_VALUE 0 +#define DEFAULT_EG2_INCREMENT 0 + +/*---------------------------------------------------------------------------- + * S_WT_VOICE + * + * This structure contains state data for the wavetable engine + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_voice_tag +{ + EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ + EAS_U32 loopStart; /* points to first sample at start of loop */ + EAS_U32 phaseAccum; /* current sample, integer portion of phase */ + EAS_U32 phaseFrac; /* fractional portion of phase */ + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I16 gainLeft; /* current gain, left ch */ + EAS_I16 gainRight; /* current gain, right ch */ +#endif + +#if defined(_FILTER_ENABLED) + S_FILTER_CONTROL filter; /* low pass filter */ +#endif + + S_LFO_CONTROL modLFO; /* modulator LFO */ + +#ifdef DLS_SYNTHESIZER + S_LFO_CONTROL vibLFO; /* vibrato LFO */ +#endif + + /* envelope control */ + EAS_I16 eg1Value; + EAS_I16 eg2Value; + EAS_I16 eg1Increment; + EAS_I16 eg2Increment; + EAS_U8 eg1State; + EAS_U8 eg2State; + + EAS_U16 artIndex; /* index to articulation params */ + +} S_WT_VOICE; + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update); +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); + +#ifdef EAS_SPLIT_WT_SYNTH +void WTE_ConfigVoice (EAS_I32 voiceNum, S_WT_CONFIG *pWTConfig, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +void WTE_ProcessVoice (EAS_I32 voiceNum, S_WT_FRAME *pWTParams, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +#endif + +#endif diff --git a/arm-hybrid-22k/lib_src/eas_wtsynth.c b/arm-hybrid-22k/lib_src/eas_wtsynth.c index 8098e09..788b34f 100644 --- a/arm-hybrid-22k/lib_src/eas_wtsynth.c +++ b/arm-hybrid-22k/lib_src/eas_wtsynth.c @@ -1,12 +1,12 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_wtsynth.c - * - * Contents and purpose: - * Implements the synthesizer functions. - * - * Copyright Sonic Network Inc. 2004 +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtsynth.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,1233 +19,1233 @@ * 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_data.h" -#include "eas_report.h" -#include "eas_host.h" -#include "eas_math.h" -#include "eas_synth_protos.h" -#include "eas_wtsynth.h" -#include "eas_pan.h" - -#ifdef DLS_SYNTHESIZER -#include "eas_dlssynth.h" -#endif - -#ifdef _METRICS_ENABLED -#include "eas_perf.h" -#endif - -/* local prototypes */ -static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr); -static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); -static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); -static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); -static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); -static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); -static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); -static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents); -static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain); -static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); -static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); - -#ifdef EAS_SPLIT_WT_SYNTH -extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); -extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); -#endif - -#ifdef _FILTER_ENABLED -static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt); -#endif - -#ifdef _STATS -extern double statsPhaseIncrement; -extern double statsMaxPhaseIncrement; -extern long statsPhaseSampleCount; -extern double statsSampleSize; -extern long statsSampleCount; -#endif - -/*---------------------------------------------------------------------------- - * Synthesizer interface - *---------------------------------------------------------------------------- -*/ - -const S_SYNTH_INTERFACE wtSynth = -{ - WT_Initialize, - WT_StartVoice, - WT_UpdateVoice, - WT_ReleaseVoice, - WT_MuteVoice, - WT_SustainPedal, - WT_UpdateChannel -}; - -#ifdef EAS_SPLIT_WT_SYNTH -const S_FRAME_INTERFACE wtFrameInterface = -{ - WTE_StartFrame, - WTE_EndFrame -}; -#endif - -/*---------------------------------------------------------------------------- - * WT_Initialize() - *---------------------------------------------------------------------------- - * Purpose: - * - * Inputs: - * pVoice - pointer to voice to initialize - * - * Outputs: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT WT_Initialize (S_VOICE_MGR *pVoiceMgr) -{ - EAS_INT i; - - for (i = 0; i < NUM_WT_VOICES; i++) - { - - pVoiceMgr->wtVoices[i].artIndex = DEFAULT_ARTICULATION_INDEX; - - pVoiceMgr->wtVoices[i].eg1State = DEFAULT_EG1_STATE; - pVoiceMgr->wtVoices[i].eg1Value = DEFAULT_EG1_VALUE; - pVoiceMgr->wtVoices[i].eg1Increment = DEFAULT_EG1_INCREMENT; - - pVoiceMgr->wtVoices[i].eg2State = DEFAULT_EG2_STATE; - pVoiceMgr->wtVoices[i].eg2Value = DEFAULT_EG2_VALUE; - pVoiceMgr->wtVoices[i].eg2Increment = DEFAULT_EG2_INCREMENT; - - /* left and right gain values are needed only if stereo output */ -#if (NUM_OUTPUT_CHANNELS == 2) - pVoiceMgr->wtVoices[i].gainLeft = DEFAULT_VOICE_GAIN; - pVoiceMgr->wtVoices[i].gainRight = DEFAULT_VOICE_GAIN; -#endif - - pVoiceMgr->wtVoices[i].phaseFrac = DEFAULT_PHASE_FRAC; - pVoiceMgr->wtVoices[i].phaseAccum = DEFAULT_PHASE_INT; - -#ifdef _FILTER_ENABLED - pVoiceMgr->wtVoices[i].filter.z1 = DEFAULT_FILTER_ZERO; - pVoiceMgr->wtVoices[i].filter.z2 = DEFAULT_FILTER_ZERO; -#endif - } - - return EAS_TRUE; -} - -/*---------------------------------------------------------------------------- - * WT_ReleaseVoice() - *---------------------------------------------------------------------------- - * Purpose: - * The selected voice is being released. - * - * Inputs: - * pEASData - pointer to S_EAS_DATA - * pVoice - pointer to voice to release - * - * Outputs: - * None - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pVoice) used in some implementations */ -static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) -{ - S_WT_VOICE *pWTVoice; - const S_ARTICULATION *pArticulation; - -#ifdef DLS_SYNTHESIZER - if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) - { - DLS_ReleaseVoice(pVoiceMgr, pSynth, pVoice, voiceNum); - return; - } -#endif - - pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; - pArticulation = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; - - /* release EG1 */ - pWTVoice->eg1State = eEnvelopeStateRelease; - pWTVoice->eg1Increment = pArticulation->eg1.releaseTime; - - /* - The spec says we should release EG2, but doing so with the current - voicing is causing clicks. This fix will need to be coordinated with - a new sound library release - */ - - /* release EG2 */ - pWTVoice->eg2State = eEnvelopeStateRelease; - pWTVoice->eg2Increment = pArticulation->eg2.releaseTime; -} - -/*---------------------------------------------------------------------------- - * WT_MuteVoice() - *---------------------------------------------------------------------------- - * Purpose: - * The selected voice is being muted. - * - * Inputs: - * pVoice - pointer to voice to release - * - * Outputs: - * None - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pSynth) used in some implementations */ -static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) -{ - -#ifdef DLS_SYNTHESIZER - if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) - { - DLS_MuteVoice(pVoiceMgr, pSynth, pVoice, voiceNum); - return; - } -#endif - - /* clear deferred action flags */ - pVoice->voiceFlags &= - ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | - VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | - VOICE_FLAG_DEFER_MUTE); - - /* set the envelope state */ - pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateMuted; - pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateMuted; -} - -/*---------------------------------------------------------------------------- - * WT_SustainPedal() - *---------------------------------------------------------------------------- - * Purpose: - * The selected voice is held due to sustain pedal - * - * Inputs: - * pVoice - pointer to voice to sustain - * - * Outputs: - * None - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pChannel) used in some implementations */ -static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) -{ - S_WT_VOICE *pWTVoice; - -#ifdef DLS_SYNTHESIZER - if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) - { - DLS_SustainPedal(pVoiceMgr, pSynth, pVoice, pChannel, voiceNum); - return; - } -#endif - - /* don't catch the voice if below the sustain level */ - pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; - if (pWTVoice->eg1Value < pSynth->pEAS->pArticulations[pWTVoice->artIndex].eg1.sustainLevel) - return; - - /* sustain flag is set, damper pedal is on */ - /* defer releasing this note until the damper pedal is off */ - pWTVoice->eg1State = eEnvelopeStateDecay; - pVoice->voiceState = eVoiceStatePlay; - - /* - because sustain pedal is on, this voice - should defer releasing its note - */ - pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; - -#ifdef _DEBUG_SYNTH - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_SustainPedal: defer note off because sustain pedal is on\n"); */ } -#endif -} - -/*---------------------------------------------------------------------------- - * WT_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 - * pEASData - 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 WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) -{ - S_WT_VOICE *pWTVoice; - const S_WT_REGION *pRegion; - const S_ARTICULATION *pArt; - S_SYNTH_CHANNEL *pChannel; - -#if (NUM_OUTPUT_CHANNELS == 2) - EAS_INT pan; -#endif - -#ifdef EAS_SPLIT_WT_SYNTH - S_WT_CONFIG wtConfig; -#endif - - /* no samples have been synthesized for this note yet */ - pVoice->regionIndex = regionIndex; - pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; - - /* get the articulation index for this region */ - pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; - pChannel = &pSynth->channels[pVoice->channel & 15]; - - /* update static channel parameters */ - if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) - WT_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); - -#ifdef DLS_SYNTHESIZER - if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) - return DLS_StartVoice(pVoiceMgr, pSynth, pVoice, voiceNum, regionIndex); -#endif - - pRegion = &(pSynth->pEAS->pWTRegions[regionIndex]); - pWTVoice->artIndex = pRegion->artIndex; - -#ifdef _DEBUG_SYNTH - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ } -#endif - - pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; - - /* MIDI note on puts this voice into attack state */ - pWTVoice->eg1State = eEnvelopeStateAttack; - pWTVoice->eg1Value = 0; - pWTVoice->eg1Increment = pArt->eg1.attackTime; - pWTVoice->eg2State = eEnvelopeStateAttack; - pWTVoice->eg2Value = 0; - pWTVoice->eg2Increment = pArt->eg2.attackTime; - - /* init the LFO */ - pWTVoice->modLFO.lfoValue = 0; - pWTVoice->modLFO.lfoPhase = -pArt->lfoDelay; - - pVoice->gain = 0; - -#if (NUM_OUTPUT_CHANNELS == 2) - /* - 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 - */ - pan = (EAS_INT) pSynth->channels[pVoice->channel & 15].pan - 64; - pan += pArt->pan; - EAS_CalcPanControl(pan, &pWTVoice->gainLeft, &pWTVoice->gainRight); -#endif - -#ifdef _FILTER_ENABLED - /* clear out the filter states */ - pWTVoice->filter.z1 = 0; - pWTVoice->filter.z2 = 0; -#endif - - /* if this wave is to be generated using noise generator */ - if (pRegion->region.keyGroupAndFlags & REGION_FLAG_USE_WAVE_GENERATOR) - { - pWTVoice->phaseAccum = 4574296; - pWTVoice->loopStart = WT_NOISE_GENERATOR; - pWTVoice->loopEnd = 4574295; - } - - /* normal sample */ - else - { - -#ifdef EAS_SPLIT_WT_SYNTH - if (voiceNum < NUM_PRIMARY_VOICES) - pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; - else - pWTVoice->phaseAccum = pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; -#else - pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; -#endif - - if (pRegion->region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED) - { - pWTVoice->loopStart = pWTVoice->phaseAccum + pRegion->loopStart; - pWTVoice->loopEnd = pWTVoice->phaseAccum + pRegion->loopEnd - 1; - } - else - pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 1; - } - -#ifdef EAS_SPLIT_WT_SYNTH - /* configure off-chip voices */ - if (voiceNum >= NUM_PRIMARY_VOICES) - { - wtConfig.phaseAccum = pWTVoice->phaseAccum; - wtConfig.loopStart = pWTVoice->loopStart; - wtConfig.loopEnd = pWTVoice->loopEnd; - wtConfig.gain = pVoice->gain; - -#if (NUM_OUTPUT_CHANNELS == 2) - wtConfig.gainLeft = pWTVoice->gainLeft; - wtConfig.gainRight = pWTVoice->gainRight; -#endif - - WTE_ConfigVoice(voiceNum - NUM_PRIMARY_VOICES, &wtConfig, pVoiceMgr->pFrameBuffer); - } -#endif - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * WT_CheckSampleEnd - *---------------------------------------------------------------------------- - * Purpose: - * Check for end of sample and calculate number of samples to synthesize - * - * Inputs: - * - * Outputs: - * - * Notes: - * - *---------------------------------------------------------------------------- -*/ -EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update) -{ - EAS_U32 endPhaseAccum; - EAS_U32 endPhaseFrac; - EAS_I32 numSamples; - EAS_BOOL done = EAS_FALSE; - - /* check to see if we hit the end of the waveform this time */ - /*lint -e{703} use shift for performance */ - endPhaseFrac = pWTVoice->phaseFrac + (pWTIntFrame->frame.phaseIncrement << SYNTH_UPDATE_PERIOD_IN_BITS); - endPhaseAccum = pWTVoice->phaseAccum + GET_PHASE_INT_PART(endPhaseFrac); - if (endPhaseAccum >= pWTVoice->loopEnd) - { - /* calculate how far current ptr is from end */ - numSamples = (EAS_I32) (pWTVoice->loopEnd - pWTVoice->phaseAccum); - - /* now account for the fractional portion */ - /*lint -e{703} use shift for performance */ - numSamples = (EAS_I32) ((numSamples << NUM_PHASE_FRAC_BITS) - pWTVoice->phaseFrac); - pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement); - - /* sound will be done this frame */ - done = EAS_TRUE; - } - - /* update data for off-chip synth */ - if (update) - { - pWTVoice->phaseFrac = endPhaseFrac; - pWTVoice->phaseAccum = endPhaseAccum; - } - - return done; -} - -/*---------------------------------------------------------------------------- - * WT_UpdateVoice() - *---------------------------------------------------------------------------- - * Purpose: - * Synthesize a block of samples for the given voice. - * Use linear interpolation. - * - * Inputs: - * pEASData - 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 WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) -{ - S_WT_VOICE *pWTVoice; - S_WT_INT_FRAME intFrame; - S_SYNTH_CHANNEL *pChannel; - const S_WT_REGION *pWTRegion; - const S_ARTICULATION *pArt; - EAS_I32 temp; - EAS_BOOL done; - -#ifdef DLS_SYNTHESIZER - if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) - return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples); -#endif - - /* establish pointers to critical data */ - pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; - pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK]; - pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; - pChannel = &pSynth->channels[pVoice->channel & 15]; - intFrame.prevGain = pVoice->gain; - - /* update the envelopes */ - WT_UpdateEG1(pWTVoice, &pArt->eg1); - WT_UpdateEG2(pWTVoice, &pArt->eg2); - - /* update the LFO */ - WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq); - -#ifdef _FILTER_ENABLED - /* calculate filter if library uses filter */ - if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED) - WT_UpdateFilter(pWTVoice, &intFrame, pArt); - else - intFrame.frame.k = 0; -#endif - - /* update the gain */ - intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain); - - /* calculate base pitch*/ - temp = pChannel->staticPitch + pWTRegion->tuning; - - /* include global transpose */ - if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) - temp += pVoice->note * 100; - else - temp += (pVoice->note + pSynth->globalTranspose) * 100; - intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp); - - /* call into engine to generate samples */ - intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer; - intFrame.pMixBuffer = pMixBuffer; - intFrame.numSamples = numSamples; - - /* check for end of sample */ - if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd)) - done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES)); - else - done = EAS_FALSE; - -#ifdef EAS_SPLIT_WT_SYNTH - if (voiceNum < NUM_PRIMARY_VOICES) - { -#ifndef _SPLIT_WT_TEST_HARNESS - WT_ProcessVoice(pWTVoice, &intFrame); -#endif - } - else - WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer); -#else - WT_ProcessVoice(pWTVoice, &intFrame); -#endif - - /* clear flag */ - pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; - - /* if voice has finished, set flag for voice manager */ - if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted)) - done = EAS_TRUE; - - /* if the update interval has elapsed, then force the current gain to the next - * gain since we never actually reach the next gain when ramping -- we just get - * very close to the target gain. - */ - pVoice->gain = (EAS_I16) intFrame.frame.gainTarget; - - return done; -} - -/*---------------------------------------------------------------------------- - * WT_UpdatePhaseInc() - *---------------------------------------------------------------------------- - * Purpose: - * Calculate the phase increment - * - * Inputs: - * pVoice - pointer to the voice being updated - * psRegion - pointer to the region - * psArticulation - pointer to the articulation - * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this - * voice during the duration of this synthesis - * pEASData - pointer to overall EAS data structure - * - * Outputs: - * - * Side Effects: - * set the phase increment for this voice - *---------------------------------------------------------------------------- -*/ -static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents) -{ - EAS_I32 temp; - - /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */ - temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, - ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7))); - - /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */ - temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, - ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7))); - - /* now multiply the (channel pressure + CC1) pitch values by the LFO value */ - temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp); - - /* - add in the LFO pitch due to - channel pressure and CC1 along with - the LFO pitch, the EG2 pitch, and the - "static" pitch for this voice on this channel - */ - temp += pitchCents + - (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) + - (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch)); - - /* convert from cents to linear phase increment */ - return EAS_Calculate2toX(temp); -} - -/*---------------------------------------------------------------------------- - * WT_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 - * - * Inputs: - * nChannel - channel to update - * pEASData - pointer to overall EAS data structure - * - * Outputs: - * - * Side Effects: - * - the given channel's static gain and static pitch are updated - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pVoiceMgr) reserved for future use */ -static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) -{ - EAS_I32 staticGain; - EAS_I32 pitchBend; - S_SYNTH_CHANNEL *pChannel; - - pChannel = &pSynth->channels[channel]; - - /* - nChannelGain = (CC7 * CC11)^2 * master volume - where CC7 == 100 by default, CC11 == 127, master volume == 32767 - */ - staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7), - (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7)); - - /* staticGain has to be squared */ - staticGain = MULT_EG1_EG1(staticGain, staticGain); - - pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume); - - /* - calculate pitch bend: RPN0 * ((2*pitch wheel)/16384 -1) - However, if we use the EG1 macros, remember that EG1 has a full - scale value of 32768 (instead of 16384). So instead of multiplying - by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead - of 16384. This utilizes the fact that the EG1 macro places a binary - point 15 places to the left instead of 14 places. - */ - /*lint -e{703} */ - pitchBend = - (((EAS_I32)(pChannel->pitchBend) << 2) - - 32768); - - pChannel->staticPitch = - MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity); - - /* if this is not a drum channel, then add in the per-channel tuning */ - if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) - pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100); - - /* clear update flag */ - pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; - return; -} - -/*---------------------------------------------------------------------------- - * WT_UpdateGain() - *---------------------------------------------------------------------------- - * Purpose: - * Calculate and assign static voice parameters as part of WT_UpdateVoice() - * - * Inputs: - * pVoice - ptr to the synth voice that we want to synthesize - * pEASData - pointer to overall EAS data structure - * - * Outputs: - * - * Side Effects: - * - various voice parameters are calculated and assigned - * - *---------------------------------------------------------------------------- -*/ -static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain) -{ - EAS_I32 lfoGain; - EAS_I32 temp; - - /* - If this voice was stolen, then the velocity is actually - for the new note, not the note that we are currently ramping down. - So we really shouldn't use this velocity. However, that would require - more memory to store the velocity value, and the improvement may - not be sufficient to warrant the added memory. - */ - /* velocity is fixed at note start for a given voice and must be squared */ - temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7); - temp = MULT_EG1_EG1(temp, temp); - - /* region gain is fixed as part of the articulation */ - temp = MULT_EG1_EG1(temp, gain); - - /* include the channel gain */ - temp = MULT_EG1_EG1(temp, pChannel->staticGain); - - /* calculate LFO gain using an approximation for 10^x */ - lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain); - lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS); - - /* convert from a dB-like value to linear gain */ - lfoGain = EAS_Calculate2toX(lfoGain); - temp = MULT_EG1_EG1(temp, lfoGain); - - /* calculate the voice's gain */ - temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value); - - return temp; -} - -/*---------------------------------------------------------------------------- - * WT_UpdateEG1() - *---------------------------------------------------------------------------- - * Purpose: - * Calculate the EG1 envelope for the given voice (but do not update any - * state) - * - * Inputs: - * pVoice - ptr to the voice whose envelope we want to update - * nVoice - this voice's number - used only for debug - * pEASData - pointer to overall EAS data structure - * - * Outputs: - * nValue - the envelope value - * - * Side Effects: - * - updates EG1 state value for the given voice - *---------------------------------------------------------------------------- -*/ -static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) -{ - EAS_I32 temp; - - switch (pWTVoice->eg1State) - { - case eEnvelopeStateAttack: - temp = pWTVoice->eg1Value + pWTVoice->eg1Increment; - - /* check if we have reached peak amplitude */ - if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) - { - /* limit the volume */ - temp = SYNTH_FULL_SCALE_EG1_GAIN; - - /* prepare to move to decay state */ - pWTVoice->eg1State = eEnvelopeStateDecay; - pWTVoice->eg1Increment = pEnv->decayTime; - } - - break; - - /* exponential decay */ - case eEnvelopeStateDecay: - temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); - - /* check if we have reached sustain level */ - if (temp <= pEnv->sustainLevel) - { - /* enforce the sustain level */ - temp = pEnv->sustainLevel; - - /* if sustain level is zero, skip sustain & release the voice */ - if (temp > 0) - pWTVoice->eg1State = eEnvelopeStateSustain; - - /* move to sustain state */ - else - pWTVoice->eg1State = eEnvelopeStateMuted; - } - - break; - - case eEnvelopeStateSustain: - return; - - case eEnvelopeStateRelease: - temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); - - /* if we hit zero, this voice isn't contributing any audio */ - if (temp <= 0) - { - temp = 0; - pWTVoice->eg1State = eEnvelopeStateMuted; - } - break; - - /* voice is muted, set target to zero */ - case eEnvelopeStateMuted: - temp = 0; - break; - - case eEnvelopeStateInvalid: - default: - temp = 0; -#ifdef _DEBUG_SYNTH - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n", - pWTVoice->eg1State); */ } -#endif - break; - - } - - pWTVoice->eg1Value = (EAS_I16) temp; -} - -/*---------------------------------------------------------------------------- - * WT_UpdateEG2() - *---------------------------------------------------------------------------- - * Purpose: - * Update the EG2 envelope for the given voice - * - * Inputs: - * pVoice - ptr to the voice whose envelope we want to update - * pEASData - pointer to overall EAS data structure - * - * Outputs: - * - * Side Effects: - * - updates EG2 values for the given voice - *---------------------------------------------------------------------------- -*/ - -static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) -{ - EAS_I32 temp; - - switch (pWTVoice->eg2State) - { - case eEnvelopeStateAttack: - temp = pWTVoice->eg2Value + pWTVoice->eg2Increment; - - /* check if we have reached peak amplitude */ - if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) - { - /* limit the volume */ - temp = SYNTH_FULL_SCALE_EG1_GAIN; - - /* prepare to move to decay state */ - pWTVoice->eg2State = eEnvelopeStateDecay; - - pWTVoice->eg2Increment = pEnv->decayTime; - } - - break; - - /* implement linear pitch decay in cents */ - case eEnvelopeStateDecay: - temp = pWTVoice->eg2Value -pWTVoice->eg2Increment; - - /* check if we have reached sustain level */ - if (temp <= pEnv->sustainLevel) - { - /* enforce the sustain level */ - temp = pEnv->sustainLevel; - - /* prepare to move to sustain state */ - pWTVoice->eg2State = eEnvelopeStateSustain; - } - break; - - case eEnvelopeStateSustain: - return; - - case eEnvelopeStateRelease: - temp = pWTVoice->eg2Value - pWTVoice->eg2Increment; - - if (temp <= 0) - { - temp = 0; - pWTVoice->eg2State = eEnvelopeStateMuted; - } - - break; - - /* voice is muted, set target to zero */ - case eEnvelopeStateMuted: - temp = 0; - break; - - case eEnvelopeStateInvalid: - default: - temp = 0; -#ifdef _DEBUG_SYNTH - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n", - pWTVoice->eg2State); */ } -#endif - break; - } - - pWTVoice->eg2Value = (EAS_I16) temp; -} - -/*---------------------------------------------------------------------------- - * WT_UpdateLFO () - *---------------------------------------------------------------------------- - * Purpose: - * Calculate the LFO for the given voice - * - * Inputs: - * pLFO - ptr to the LFO data - * phaseInc - phase increment - * - * Outputs: - * - * Side Effects: - * - updates LFO values for the given voice - *---------------------------------------------------------------------------- -*/ -void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc) -{ - - /* To save memory, if m_nPhaseValue is negative, we are in the - * delay phase, and m_nPhaseValue represents the time left - * in the delay. - */ - if (pLFO->lfoPhase < 0) - { - pLFO->lfoPhase++; - return; - } - - /* calculate LFO output from phase value */ - /*lint -e{701} Use shift for performance */ - pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2); - /*lint -e{502} */ - if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000)) - pLFO->lfoValue = ~pLFO->lfoValue; - - /* update LFO phase */ - pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff; -} - -#ifdef _FILTER_ENABLED -/*---------------------------------------------------------------------------- - * WT_UpdateFilter() - *---------------------------------------------------------------------------- - * Purpose: - * Update the Filter parameters - * - * Inputs: - * pVoice - ptr to the voice whose filter we want to update - * pEASData - pointer to overall EAS data structure - * - * Outputs: - * - * Side Effects: - * - updates Filter values for the given voice - *---------------------------------------------------------------------------- -*/ -static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt) -{ - EAS_I32 cutoff; - - /* no need to calculate filter coefficients if it is bypassed */ - if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY) - { - pIntFrame->frame.k = 0; - return; - } - - /* determine the dynamic cutoff frequency */ - cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc); - cutoff += pArt->filterCutoff; - - /* subtract the A5 offset and the sampling frequency */ - cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS; - - /* limit the cutoff frequency */ - if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS) - cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS; - else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS) - cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS; - - WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ); -} -#endif - -#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) -/*---------------------------------------------------------------------------- - * coef - *---------------------------------------------------------------------------- - * Table of filter coefficients for low-pass filter - *---------------------------------------------------------------------------- - * - * polynomial coefficients are based on 8kHz sampling frequency - * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x) - * - *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta - *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2) - *note: this is a power series in 2^x, not k*2^x - *where k = (2*pi*440)/8kHz == convert octaves to radians - * - * so actually, the following coefs listed as k2g0, k2g1, k2g2 are really - * k2g0*k^0 = k2g0 - * k2g1*k^1 - * k2g2*k^2 - * - * - * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x) - * - *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta - *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3) - *note: this is a power series in 2^x, not k*2^x - *where k = (2*pi*440)/8kHz == convert octaves to radians - *we also include the optimization factor of 0.81 - * - * so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really - * n1g0*k^0 = n1g0 - * n1g1*k^1 - * n1g2*k^2 - * n1g3*k^3 - * - * NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3 - *---------------------------------------------------------------------------- -*/ - -static const EAS_I16 nk1g0 = -32768; -static const EAS_I16 nk1g2 = 1580; -static const EAS_I16 k2g0 = 32767; - -static const EAS_I16 k2g1[] = -{ - -11324, /* k2g1[0] = -0.3455751918948761 */ - -10387, /* k2g1[1] = -0.3169878073928751 */ - -9528, /* k2g1[2] = -0.29076528753345476 */ - -8740, /* k2g1[3] = -0.2667120011011279 */ - -8017, /* k2g1[4] = -0.24464850028971705 */ - -7353, /* k2g1[5] = -0.22441018194495696 */ - -6745, /* k2g1[6] = -0.20584605955455101 */ - -6187, /* k2g1[7] = -0.18881763682420102 */ - -5675, /* k2g1[8] = -0.1731978744360067 */ - -5206, /* k2g1[9] = -0.15887024228080968 */ - -4775, /* k2g1[10] = -0.14572785009373057 */ - -4380, /* k2g1[11] = -0.13367265000706827 */ - -4018, /* k2g1[12] = -0.1226147050712642 */ - -3685, /* k2g1[13] = -0.11247151828678581 */ - -3381, /* k2g1[14] = -0.10316741714122014 */ - -3101, /* k2g1[15] = -0.0946329890599603 */ - -2844, /* k2g1[16] = -0.08680456355870586 */ - -2609, /* k2g1[17] = -0.07962373723441349 */ - -2393, /* k2g1[18] = -0.07303693805092666 */ - -2195, /* k2g1[19] = -0.06699502566866912 */ - -2014, /* k2g1[20] = -0.06145292483669077 */ - -1847, /* k2g1[21] = -0.056369289112013346 */ - -1694, /* k2g1[22] = -0.05170619239747895 */ - -1554, /* k2g1[23] = -0.04742884599684141 */ - -1426, /* k2g1[24] = -0.043505339076210514 */ - -1308, /* k2g1[25] = -0.03990640059558053 */ - -1199, /* k2g1[26] = -0.03660518093435039 */ - -1100, /* k2g1[27] = -0.03357705158166837 */ - -1009, /* k2g1[28] = -0.030799421397205727 */ - -926, /* k2g1[29] = -0.028251568071585884 */ - -849 /* k2g1[30] = -0.025914483529091967 */ -}; - -static const EAS_I16 k2g2[] = -{ - 1957, /* k2g2[0] = 0.059711106626580836 */ - 1646, /* k2g2[1] = 0.05024063501786333 */ - 1385, /* k2g2[2] = 0.042272226217199664 */ - 1165, /* k2g2[3] = 0.03556764576567844 */ - 981, /* k2g2[4] = 0.029926444346999134 */ - 825, /* k2g2[5] = 0.025179964880280382 */ - 694, /* k2g2[6] = 0.02118630011706455 */ - 584, /* k2g2[7] = 0.01782604998793514 */ - 491, /* k2g2[8] = 0.014998751854573014 */ - 414, /* k2g2[9] = 0.012619876941179595 */ - 348, /* k2g2[10] = 0.010618303146468736 */ - 293, /* k2g2[11] = 0.008934188679954682 */ - 246, /* k2g2[12] = 0.007517182949855368 */ - 207, /* k2g2[13] = 0.006324921212866403 */ - 174, /* k2g2[14] = 0.005321757979794424 */ - 147, /* k2g2[15] = 0.004477701309210577 */ - 123, /* k2g2[16] = 0.00376751612730811 */ - 104, /* k2g2[17] = 0.0031699697655869644 */ - 87, /* k2g2[18] = 0.00266719715992703 */ - 74, /* k2g2[19] = 0.0022441667321724647 */ - 62, /* k2g2[20] = 0.0018882309854916855 */ - 52, /* k2g2[21] = 0.0015887483774966232 */ - 44, /* k2g2[22] = 0.0013367651661223448 */ - 37, /* k2g2[23] = 0.0011247477162958733 */ - 31, /* k2g2[24] = 0.0009463572640678758 */ - 26, /* k2g2[25] = 0.0007962604042473498 */ - 22, /* k2g2[26] = 0.0006699696356181593 */ - 18, /* k2g2[27] = 0.0005637091964589207 */ - 16, /* k2g2[28] = 0.00047430217920125243 */ - 13, /* k2g2[29] = 0.00039907554925166274 */ - 11 /* k2g2[30] = 0.00033578022828973666 */ -}; - -static const EAS_I16 n1g2[] = -{ - 3170, /* n1g2[0] = 0.0967319927350769 */ - 3036, /* n1g2[1] = 0.0926446051254155 */ - 2908, /* n1g2[2] = 0.08872992911818503 */ - 2785, /* n1g2[3] = 0.08498066682523227 */ - 2667, /* n1g2[4] = 0.08138982872895201 */ - 2554, /* n1g2[5] = 0.07795072065216213 */ - 2446, /* n1g2[6] = 0.0746569312785634 */ - 2343, /* n1g2[7] = 0.07150232020051943 */ - 2244, /* n1g2[8] = 0.06848100647187474 */ - 2149, /* n1g2[9] = 0.06558735764447099 */ - 2058, /* n1g2[10] = 0.06281597926792246 */ - 1971, /* n1g2[11] = 0.06016170483307614 */ - 1888, /* n1g2[12] = 0.05761958614040857 */ - 1808, /* n1g2[13] = 0.05518488407540374 */ - 1732, /* n1g2[14] = 0.052853059773715245 */ - 1659, /* n1g2[15] = 0.05061976615964251 */ - 1589, /* n1g2[16] = 0.04848083984214659 */ - 1521, /* n1g2[17] = 0.046432293353298 */ - 1457, /* n1g2[18] = 0.04447030771468711 */ - 1396, /* n1g2[19] = 0.04259122531793907 */ - 1337, /* n1g2[20] = 0.040791543106060944 */ - 1280, /* n1g2[21] = 0.03906790604290942 */ - 1226, /* n1g2[22] = 0.037417100858604564 */ - 1174, /* n1g2[23] = 0.035836050059229754 */ - 1125, /* n1g2[24] = 0.03432180618965023 */ - 1077, /* n1g2[25] = 0.03287154633875494 */ - 1032, /* n1g2[26] = 0.03148256687687814 */ - 988, /* n1g2[27] = 0.030152278415589925 */ - 946, /* n1g2[28] = 0.028878200980459685 */ - 906, /* n1g2[29] = 0.02765795938779331 */ - 868 /* n1g2[30] = 0.02648927881672521 */ -}; - -static const EAS_I16 n1g3[] = -{ - -548, /* n1g3[0] = -0.016714088475899017 */ - -481, /* n1g3[1] = -0.014683605122742116 */ - -423, /* n1g3[2] = -0.012899791676436092 */ - -371, /* n1g3[3] = -0.01133268185193299 */ - -326, /* n1g3[4] = -0.00995594976868754 */ - -287, /* n1g3[5] = -0.008746467702146129 */ - -252, /* n1g3[6] = -0.00768391756106361 */ - -221, /* n1g3[7] = -0.006750449563854721 */ - -194, /* n1g3[8] = -0.005930382380083576 */ - -171, /* n1g3[9] = -0.005209939699767622 */ - -150, /* n1g3[10] = -0.004577018805123356 */ - -132, /* n1g3[11] = -0.004020987256990177 */ - -116, /* n1g3[12] = -0.003532504280467257 */ - -102, /* n1g3[13] = -0.00310336384922047 */ - -89, /* n1g3[14] = -0.002726356832432369 */ - -78, /* n1g3[15] = -0.002395149888601605 */ - -69, /* n1g3[16] = -0.0021041790717285314 */ - -61, /* n1g3[17] = -0.0018485563625771063 */ - -53, /* n1g3[18] = -0.001623987554831628 */ - -47, /* n1g3[19] = -0.0014267001167177025 */ - -41, /* n1g3[20] = -0.0012533798162347005 */ - -36, /* n1g3[21] = -0.0011011150453668693 */ - -32, /* n1g3[22] = -0.0009673479079754438 */ - -28, /* n1g3[23] = -0.0008498312496971563 */ - -24, /* n1g3[24] = -0.0007465909079943587 */ - -21, /* n1g3[25] = -0.0006558925481952733 */ - -19, /* n1g3[26] = -0.0005762125284029567 */ - -17, /* n1g3[27] = -0.0005062123038325457 */ - -15, /* n1g3[28] = -0.0004447159405951901 */ - -13, /* n1g3[29] = -0.00039069036118270117 */ - -11 /* n1g3[30] = -0.00034322798979677605 */ -}; - -/*---------------------------------------------------------------------------- - * WT_SetFilterCoeffs() - *---------------------------------------------------------------------------- - * Purpose: - * Update the Filter parameters - * - * Inputs: - * pVoice - ptr to the voice whose filter we want to update - * pEASData - pointer to overall EAS data structure - * - * Outputs: - * - * Side Effects: - * - updates Filter values for the given voice - *---------------------------------------------------------------------------- -*/ -void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance) -{ - EAS_I32 temp; - - /* - Convert the cutoff, which has had A5 subtracted, using the 2^x approx - Note, this cutoff is related to theta cutoff by - theta = k * 2^x - We use 2^x and incorporate k in the power series coefs instead - */ - cutoff = EAS_Calculate2toX(cutoff); - - /* calculate b2 coef */ - temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]); - temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp); - pIntFrame->frame.b2 = temp; - - /* calculate b1 coef */ - temp = MULT_AUDIO_COEF(cutoff, nk1g2); - temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp); - temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2); - pIntFrame->frame.b1 = temp >> 1; - - /* calculate K coef */ - temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]); - temp = MULT_AUDIO_COEF(cutoff, temp); - temp = MULT_AUDIO_COEF(cutoff, temp); - pIntFrame->frame.k = temp; -} -#endif - + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_synth_protos.h" +#include "eas_wtsynth.h" +#include "eas_pan.h" + +#ifdef DLS_SYNTHESIZER +#include "eas_dlssynth.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +/* local prototypes */ +static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr); +static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); +static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); +static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); +static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); +static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents); +static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain); +static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); +static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); + +#ifdef EAS_SPLIT_WT_SYNTH +extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +#endif + +#ifdef _FILTER_ENABLED +static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt); +#endif + +#ifdef _STATS +extern double statsPhaseIncrement; +extern double statsMaxPhaseIncrement; +extern long statsPhaseSampleCount; +extern double statsSampleSize; +extern long statsSampleCount; +#endif + +/*---------------------------------------------------------------------------- + * Synthesizer interface + *---------------------------------------------------------------------------- +*/ + +const S_SYNTH_INTERFACE wtSynth = +{ + WT_Initialize, + WT_StartVoice, + WT_UpdateVoice, + WT_ReleaseVoice, + WT_MuteVoice, + WT_SustainPedal, + WT_UpdateChannel +}; + +#ifdef EAS_SPLIT_WT_SYNTH +const S_FRAME_INTERFACE wtFrameInterface = +{ + WTE_StartFrame, + WTE_EndFrame +}; +#endif + +/*---------------------------------------------------------------------------- + * WT_Initialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pVoice - pointer to voice to initialize + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WT_Initialize (S_VOICE_MGR *pVoiceMgr) +{ + EAS_INT i; + + for (i = 0; i < NUM_WT_VOICES; i++) + { + + pVoiceMgr->wtVoices[i].artIndex = DEFAULT_ARTICULATION_INDEX; + + pVoiceMgr->wtVoices[i].eg1State = DEFAULT_EG1_STATE; + pVoiceMgr->wtVoices[i].eg1Value = DEFAULT_EG1_VALUE; + pVoiceMgr->wtVoices[i].eg1Increment = DEFAULT_EG1_INCREMENT; + + pVoiceMgr->wtVoices[i].eg2State = DEFAULT_EG2_STATE; + pVoiceMgr->wtVoices[i].eg2Value = DEFAULT_EG2_VALUE; + pVoiceMgr->wtVoices[i].eg2Increment = DEFAULT_EG2_INCREMENT; + + /* left and right gain values are needed only if stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + pVoiceMgr->wtVoices[i].gainLeft = DEFAULT_VOICE_GAIN; + pVoiceMgr->wtVoices[i].gainRight = DEFAULT_VOICE_GAIN; +#endif + + pVoiceMgr->wtVoices[i].phaseFrac = DEFAULT_PHASE_FRAC; + pVoiceMgr->wtVoices[i].phaseAccum = DEFAULT_PHASE_INT; + +#ifdef _FILTER_ENABLED + pVoiceMgr->wtVoices[i].filter.z1 = DEFAULT_FILTER_ZERO; + pVoiceMgr->wtVoices[i].filter.z2 = DEFAULT_FILTER_ZERO; +#endif + } + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * WT_ReleaseVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being released. + * + * Inputs: + * pEASData - pointer to S_EAS_DATA + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoice) used in some implementations */ +static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + const S_ARTICULATION *pArticulation; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_ReleaseVoice(pVoiceMgr, pSynth, pVoice, voiceNum); + return; + } +#endif + + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pArticulation = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + + /* release EG1 */ + pWTVoice->eg1State = eEnvelopeStateRelease; + pWTVoice->eg1Increment = pArticulation->eg1.releaseTime; + + /* + The spec says we should release EG2, but doing so with the current + voicing is causing clicks. This fix will need to be coordinated with + a new sound library release + */ + + /* release EG2 */ + pWTVoice->eg2State = eEnvelopeStateRelease; + pWTVoice->eg2Increment = pArticulation->eg2.releaseTime; +} + +/*---------------------------------------------------------------------------- + * WT_MuteVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being muted. + * + * Inputs: + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pSynth) used in some implementations */ +static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_MuteVoice(pVoiceMgr, pSynth, pVoice, voiceNum); + return; + } +#endif + + /* clear deferred action flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE); + + /* set the envelope state */ + pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateMuted; + pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateMuted; +} + +/*---------------------------------------------------------------------------- + * WT_SustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is held due to sustain pedal + * + * Inputs: + * pVoice - pointer to voice to sustain + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) used in some implementations */ +static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_SustainPedal(pVoiceMgr, pSynth, pVoice, pChannel, voiceNum); + return; + } +#endif + + /* don't catch the voice if below the sustain level */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + if (pWTVoice->eg1Value < pSynth->pEAS->pArticulations[pWTVoice->artIndex].eg1.sustainLevel) + return; + + /* sustain flag is set, damper pedal is on */ + /* defer releasing this note until the damper pedal is off */ + pWTVoice->eg1State = eEnvelopeStateDecay; + pVoice->voiceState = eVoiceStatePlay; + + /* + because sustain pedal is on, this voice + should defer releasing its note + */ + pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_SustainPedal: defer note off because sustain pedal is on\n"); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * WT_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 + * pEASData - 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 WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) +{ + S_WT_VOICE *pWTVoice; + const S_WT_REGION *pRegion; + const S_ARTICULATION *pArt; + S_SYNTH_CHANNEL *pChannel; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_INT pan; +#endif + +#ifdef EAS_SPLIT_WT_SYNTH + S_WT_CONFIG wtConfig; +#endif + + /* no samples have been synthesized for this note yet */ + pVoice->regionIndex = regionIndex; + pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* get the articulation index for this region */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + + /* update static channel parameters */ + if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) + WT_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return DLS_StartVoice(pVoiceMgr, pSynth, pVoice, voiceNum, regionIndex); +#endif + + pRegion = &(pSynth->pEAS->pWTRegions[regionIndex]); + pWTVoice->artIndex = pRegion->artIndex; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ } +#endif + + pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + + /* MIDI note on puts this voice into attack state */ + pWTVoice->eg1State = eEnvelopeStateAttack; + pWTVoice->eg1Value = 0; + pWTVoice->eg1Increment = pArt->eg1.attackTime; + pWTVoice->eg2State = eEnvelopeStateAttack; + pWTVoice->eg2Value = 0; + pWTVoice->eg2Increment = pArt->eg2.attackTime; + + /* init the LFO */ + pWTVoice->modLFO.lfoValue = 0; + pWTVoice->modLFO.lfoPhase = -pArt->lfoDelay; + + pVoice->gain = 0; + +#if (NUM_OUTPUT_CHANNELS == 2) + /* + 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 + */ + pan = (EAS_INT) pSynth->channels[pVoice->channel & 15].pan - 64; + pan += pArt->pan; + EAS_CalcPanControl(pan, &pWTVoice->gainLeft, &pWTVoice->gainRight); +#endif + +#ifdef _FILTER_ENABLED + /* clear out the filter states */ + pWTVoice->filter.z1 = 0; + pWTVoice->filter.z2 = 0; +#endif + + /* if this wave is to be generated using noise generator */ + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_USE_WAVE_GENERATOR) + { + pWTVoice->phaseAccum = 4574296; + pWTVoice->loopStart = WT_NOISE_GENERATOR; + pWTVoice->loopEnd = 4574295; + } + + /* normal sample */ + else + { + +#ifdef EAS_SPLIT_WT_SYNTH + if (voiceNum < NUM_PRIMARY_VOICES) + pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; + else + pWTVoice->phaseAccum = pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; +#else + pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; +#endif + + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED) + { + pWTVoice->loopStart = pWTVoice->phaseAccum + pRegion->loopStart; + pWTVoice->loopEnd = pWTVoice->phaseAccum + pRegion->loopEnd - 1; + } + else + pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 1; + } + +#ifdef EAS_SPLIT_WT_SYNTH + /* configure off-chip voices */ + if (voiceNum >= NUM_PRIMARY_VOICES) + { + wtConfig.phaseAccum = pWTVoice->phaseAccum; + wtConfig.loopStart = pWTVoice->loopStart; + wtConfig.loopEnd = pWTVoice->loopEnd; + wtConfig.gain = pVoice->gain; + +#if (NUM_OUTPUT_CHANNELS == 2) + wtConfig.gainLeft = pWTVoice->gainLeft; + wtConfig.gainRight = pWTVoice->gainRight; +#endif + + WTE_ConfigVoice(voiceNum - NUM_PRIMARY_VOICES, &wtConfig, pVoiceMgr->pFrameBuffer); + } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WT_CheckSampleEnd + *---------------------------------------------------------------------------- + * Purpose: + * Check for end of sample and calculate number of samples to synthesize + * + * Inputs: + * + * Outputs: + * + * Notes: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update) +{ + EAS_U32 endPhaseAccum; + EAS_U32 endPhaseFrac; + EAS_I32 numSamples; + EAS_BOOL done = EAS_FALSE; + + /* check to see if we hit the end of the waveform this time */ + /*lint -e{703} use shift for performance */ + endPhaseFrac = pWTVoice->phaseFrac + (pWTIntFrame->frame.phaseIncrement << SYNTH_UPDATE_PERIOD_IN_BITS); + endPhaseAccum = pWTVoice->phaseAccum + GET_PHASE_INT_PART(endPhaseFrac); + if (endPhaseAccum >= pWTVoice->loopEnd) + { + /* calculate how far current ptr is from end */ + numSamples = (EAS_I32) (pWTVoice->loopEnd - pWTVoice->phaseAccum); + + /* now account for the fractional portion */ + /*lint -e{703} use shift for performance */ + numSamples = (EAS_I32) ((numSamples << NUM_PHASE_FRAC_BITS) - pWTVoice->phaseFrac); + pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement); + + /* sound will be done this frame */ + done = EAS_TRUE; + } + + /* update data for off-chip synth */ + if (update) + { + pWTVoice->phaseFrac = endPhaseFrac; + pWTVoice->phaseAccum = endPhaseAccum; + } + + return done; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * Use linear interpolation. + * + * Inputs: + * pEASData - 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 WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_WT_VOICE *pWTVoice; + S_WT_INT_FRAME intFrame; + S_SYNTH_CHANNEL *pChannel; + const S_WT_REGION *pWTRegion; + const S_ARTICULATION *pArt; + EAS_I32 temp; + EAS_BOOL done; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples); +#endif + + /* establish pointers to critical data */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK]; + pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + intFrame.prevGain = pVoice->gain; + + /* update the envelopes */ + WT_UpdateEG1(pWTVoice, &pArt->eg1); + WT_UpdateEG2(pWTVoice, &pArt->eg2); + + /* update the LFO */ + WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq); + +#ifdef _FILTER_ENABLED + /* calculate filter if library uses filter */ + if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED) + WT_UpdateFilter(pWTVoice, &intFrame, pArt); + else + intFrame.frame.k = 0; +#endif + + /* update the gain */ + intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain); + + /* calculate base pitch*/ + temp = pChannel->staticPitch + pWTRegion->tuning; + + /* include global transpose */ + if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + temp += pVoice->note * 100; + else + temp += (pVoice->note + pSynth->globalTranspose) * 100; + intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp); + + /* call into engine to generate samples */ + intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer; + intFrame.pMixBuffer = pMixBuffer; + intFrame.numSamples = numSamples; + + /* check for end of sample */ + if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd)) + done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES)); + else + done = EAS_FALSE; + +#ifdef EAS_SPLIT_WT_SYNTH + if (voiceNum < NUM_PRIMARY_VOICES) + { +#ifndef _SPLIT_WT_TEST_HARNESS + WT_ProcessVoice(pWTVoice, &intFrame); +#endif + } + else + WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer); +#else + WT_ProcessVoice(pWTVoice, &intFrame); +#endif + + /* clear flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* if voice has finished, set flag for voice manager */ + if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted)) + done = EAS_TRUE; + + /* if the update interval has elapsed, then force the current gain to the next + * gain since we never actually reach the next gain when ramping -- we just get + * very close to the target gain. + */ + pVoice->gain = (EAS_I16) intFrame.frame.gainTarget; + + return done; +} + +/*---------------------------------------------------------------------------- + * WT_UpdatePhaseInc() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the phase increment + * + * Inputs: + * pVoice - pointer to the voice being updated + * psRegion - pointer to the region + * psArticulation - pointer to the articulation + * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this + * voice during the duration of this synthesis + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * set the phase increment for this voice + *---------------------------------------------------------------------------- +*/ +static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents) +{ + EAS_I32 temp; + + /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */ + temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, + ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7))); + + /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */ + temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, + ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7))); + + /* now multiply the (channel pressure + CC1) pitch values by the LFO value */ + temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp); + + /* + add in the LFO pitch due to + channel pressure and CC1 along with + the LFO pitch, the EG2 pitch, and the + "static" pitch for this voice on this channel + */ + temp += pitchCents + + (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) + + (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch)); + + /* convert from cents to linear phase increment */ + return EAS_Calculate2toX(temp); +} + +/*---------------------------------------------------------------------------- + * WT_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 + * + * Inputs: + * nChannel - channel to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - the given channel's static gain and static pitch are updated + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_I32 staticGain; + EAS_I32 pitchBend; + S_SYNTH_CHANNEL *pChannel; + + pChannel = &pSynth->channels[channel]; + + /* + nChannelGain = (CC7 * CC11)^2 * master volume + where CC7 == 100 by default, CC11 == 127, master volume == 32767 + */ + staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7), + (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7)); + + /* staticGain has to be squared */ + staticGain = MULT_EG1_EG1(staticGain, staticGain); + + pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume); + + /* + calculate pitch bend: RPN0 * ((2*pitch wheel)/16384 -1) + However, if we use the EG1 macros, remember that EG1 has a full + scale value of 32768 (instead of 16384). So instead of multiplying + by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead + of 16384. This utilizes the fact that the EG1 macro places a binary + point 15 places to the left instead of 14 places. + */ + /*lint -e{703} */ + pitchBend = + (((EAS_I32)(pChannel->pitchBend) << 2) + - 32768); + + pChannel->staticPitch = + MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity); + + /* if this is not a drum channel, then add in the per-channel tuning */ + if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) + pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100); + + /* clear update flag */ + pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + return; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateGain() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static voice parameters as part of WT_UpdateVoice() + * + * Inputs: + * pVoice - ptr to the synth voice that we want to synthesize + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - various voice parameters are calculated and assigned + * + *---------------------------------------------------------------------------- +*/ +static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain) +{ + EAS_I32 lfoGain; + EAS_I32 temp; + + /* + If this voice was stolen, then the velocity is actually + for the new note, not the note that we are currently ramping down. + So we really shouldn't use this velocity. However, that would require + more memory to store the velocity value, and the improvement may + not be sufficient to warrant the added memory. + */ + /* velocity is fixed at note start for a given voice and must be squared */ + temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7); + temp = MULT_EG1_EG1(temp, temp); + + /* region gain is fixed as part of the articulation */ + temp = MULT_EG1_EG1(temp, gain); + + /* include the channel gain */ + temp = MULT_EG1_EG1(temp, pChannel->staticGain); + + /* calculate LFO gain using an approximation for 10^x */ + lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain); + lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS); + + /* convert from a dB-like value to linear gain */ + lfoGain = EAS_Calculate2toX(lfoGain); + temp = MULT_EG1_EG1(temp, lfoGain); + + /* calculate the voice's gain */ + temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value); + + return temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateEG1() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the EG1 envelope for the given voice (but do not update any + * state) + * + * Inputs: + * pVoice - ptr to the voice whose envelope we want to update + * nVoice - this voice's number - used only for debug + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * nValue - the envelope value + * + * Side Effects: + * - updates EG1 state value for the given voice + *---------------------------------------------------------------------------- +*/ +static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) +{ + EAS_I32 temp; + + switch (pWTVoice->eg1State) + { + case eEnvelopeStateAttack: + temp = pWTVoice->eg1Value + pWTVoice->eg1Increment; + + /* check if we have reached peak amplitude */ + if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) + { + /* limit the volume */ + temp = SYNTH_FULL_SCALE_EG1_GAIN; + + /* prepare to move to decay state */ + pWTVoice->eg1State = eEnvelopeStateDecay; + pWTVoice->eg1Increment = pEnv->decayTime; + } + + break; + + /* exponential decay */ + case eEnvelopeStateDecay: + temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); + + /* check if we have reached sustain level */ + if (temp <= pEnv->sustainLevel) + { + /* enforce the sustain level */ + temp = pEnv->sustainLevel; + + /* if sustain level is zero, skip sustain & release the voice */ + if (temp > 0) + pWTVoice->eg1State = eEnvelopeStateSustain; + + /* move to sustain state */ + else + pWTVoice->eg1State = eEnvelopeStateMuted; + } + + break; + + case eEnvelopeStateSustain: + return; + + case eEnvelopeStateRelease: + temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); + + /* if we hit zero, this voice isn't contributing any audio */ + if (temp <= 0) + { + temp = 0; + pWTVoice->eg1State = eEnvelopeStateMuted; + } + break; + + /* voice is muted, set target to zero */ + case eEnvelopeStateMuted: + temp = 0; + break; + + case eEnvelopeStateInvalid: + default: + temp = 0; +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n", + pWTVoice->eg1State); */ } +#endif + break; + + } + + pWTVoice->eg1Value = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateEG2() + *---------------------------------------------------------------------------- + * Purpose: + * Update the EG2 envelope for the given voice + * + * Inputs: + * pVoice - ptr to the voice whose envelope we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates EG2 values for the given voice + *---------------------------------------------------------------------------- +*/ + +static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) +{ + EAS_I32 temp; + + switch (pWTVoice->eg2State) + { + case eEnvelopeStateAttack: + temp = pWTVoice->eg2Value + pWTVoice->eg2Increment; + + /* check if we have reached peak amplitude */ + if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) + { + /* limit the volume */ + temp = SYNTH_FULL_SCALE_EG1_GAIN; + + /* prepare to move to decay state */ + pWTVoice->eg2State = eEnvelopeStateDecay; + + pWTVoice->eg2Increment = pEnv->decayTime; + } + + break; + + /* implement linear pitch decay in cents */ + case eEnvelopeStateDecay: + temp = pWTVoice->eg2Value -pWTVoice->eg2Increment; + + /* check if we have reached sustain level */ + if (temp <= pEnv->sustainLevel) + { + /* enforce the sustain level */ + temp = pEnv->sustainLevel; + + /* prepare to move to sustain state */ + pWTVoice->eg2State = eEnvelopeStateSustain; + } + break; + + case eEnvelopeStateSustain: + return; + + case eEnvelopeStateRelease: + temp = pWTVoice->eg2Value - pWTVoice->eg2Increment; + + if (temp <= 0) + { + temp = 0; + pWTVoice->eg2State = eEnvelopeStateMuted; + } + + break; + + /* voice is muted, set target to zero */ + case eEnvelopeStateMuted: + temp = 0; + break; + + case eEnvelopeStateInvalid: + default: + temp = 0; +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n", + pWTVoice->eg2State); */ } +#endif + break; + } + + pWTVoice->eg2Value = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateLFO () + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the LFO for the given voice + * + * Inputs: + * pLFO - ptr to the LFO data + * phaseInc - phase increment + * + * Outputs: + * + * Side Effects: + * - updates LFO values for the given voice + *---------------------------------------------------------------------------- +*/ +void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc) +{ + + /* To save memory, if m_nPhaseValue is negative, we are in the + * delay phase, and m_nPhaseValue represents the time left + * in the delay. + */ + if (pLFO->lfoPhase < 0) + { + pLFO->lfoPhase++; + return; + } + + /* calculate LFO output from phase value */ + /*lint -e{701} Use shift for performance */ + pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2); + /*lint -e{502} */ + if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000)) + pLFO->lfoValue = ~pLFO->lfoValue; + + /* update LFO phase */ + pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff; +} + +#ifdef _FILTER_ENABLED +/*---------------------------------------------------------------------------- + * WT_UpdateFilter() + *---------------------------------------------------------------------------- + * Purpose: + * Update the Filter parameters + * + * Inputs: + * pVoice - ptr to the voice whose filter we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates Filter values for the given voice + *---------------------------------------------------------------------------- +*/ +static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt) +{ + EAS_I32 cutoff; + + /* no need to calculate filter coefficients if it is bypassed */ + if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY) + { + pIntFrame->frame.k = 0; + return; + } + + /* determine the dynamic cutoff frequency */ + cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc); + cutoff += pArt->filterCutoff; + + /* subtract the A5 offset and the sampling frequency */ + cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS; + + /* limit the cutoff frequency */ + if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS; + else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS; + + WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ); +} +#endif + +#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) +/*---------------------------------------------------------------------------- + * coef + *---------------------------------------------------------------------------- + * Table of filter coefficients for low-pass filter + *---------------------------------------------------------------------------- + * + * polynomial coefficients are based on 8kHz sampling frequency + * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x) + * + *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta + *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2) + *note: this is a power series in 2^x, not k*2^x + *where k = (2*pi*440)/8kHz == convert octaves to radians + * + * so actually, the following coefs listed as k2g0, k2g1, k2g2 are really + * k2g0*k^0 = k2g0 + * k2g1*k^1 + * k2g2*k^2 + * + * + * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x) + * + *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta + *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3) + *note: this is a power series in 2^x, not k*2^x + *where k = (2*pi*440)/8kHz == convert octaves to radians + *we also include the optimization factor of 0.81 + * + * so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really + * n1g0*k^0 = n1g0 + * n1g1*k^1 + * n1g2*k^2 + * n1g3*k^3 + * + * NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3 + *---------------------------------------------------------------------------- +*/ + +static const EAS_I16 nk1g0 = -32768; +static const EAS_I16 nk1g2 = 1580; +static const EAS_I16 k2g0 = 32767; + +static const EAS_I16 k2g1[] = +{ + -11324, /* k2g1[0] = -0.3455751918948761 */ + -10387, /* k2g1[1] = -0.3169878073928751 */ + -9528, /* k2g1[2] = -0.29076528753345476 */ + -8740, /* k2g1[3] = -0.2667120011011279 */ + -8017, /* k2g1[4] = -0.24464850028971705 */ + -7353, /* k2g1[5] = -0.22441018194495696 */ + -6745, /* k2g1[6] = -0.20584605955455101 */ + -6187, /* k2g1[7] = -0.18881763682420102 */ + -5675, /* k2g1[8] = -0.1731978744360067 */ + -5206, /* k2g1[9] = -0.15887024228080968 */ + -4775, /* k2g1[10] = -0.14572785009373057 */ + -4380, /* k2g1[11] = -0.13367265000706827 */ + -4018, /* k2g1[12] = -0.1226147050712642 */ + -3685, /* k2g1[13] = -0.11247151828678581 */ + -3381, /* k2g1[14] = -0.10316741714122014 */ + -3101, /* k2g1[15] = -0.0946329890599603 */ + -2844, /* k2g1[16] = -0.08680456355870586 */ + -2609, /* k2g1[17] = -0.07962373723441349 */ + -2393, /* k2g1[18] = -0.07303693805092666 */ + -2195, /* k2g1[19] = -0.06699502566866912 */ + -2014, /* k2g1[20] = -0.06145292483669077 */ + -1847, /* k2g1[21] = -0.056369289112013346 */ + -1694, /* k2g1[22] = -0.05170619239747895 */ + -1554, /* k2g1[23] = -0.04742884599684141 */ + -1426, /* k2g1[24] = -0.043505339076210514 */ + -1308, /* k2g1[25] = -0.03990640059558053 */ + -1199, /* k2g1[26] = -0.03660518093435039 */ + -1100, /* k2g1[27] = -0.03357705158166837 */ + -1009, /* k2g1[28] = -0.030799421397205727 */ + -926, /* k2g1[29] = -0.028251568071585884 */ + -849 /* k2g1[30] = -0.025914483529091967 */ +}; + +static const EAS_I16 k2g2[] = +{ + 1957, /* k2g2[0] = 0.059711106626580836 */ + 1646, /* k2g2[1] = 0.05024063501786333 */ + 1385, /* k2g2[2] = 0.042272226217199664 */ + 1165, /* k2g2[3] = 0.03556764576567844 */ + 981, /* k2g2[4] = 0.029926444346999134 */ + 825, /* k2g2[5] = 0.025179964880280382 */ + 694, /* k2g2[6] = 0.02118630011706455 */ + 584, /* k2g2[7] = 0.01782604998793514 */ + 491, /* k2g2[8] = 0.014998751854573014 */ + 414, /* k2g2[9] = 0.012619876941179595 */ + 348, /* k2g2[10] = 0.010618303146468736 */ + 293, /* k2g2[11] = 0.008934188679954682 */ + 246, /* k2g2[12] = 0.007517182949855368 */ + 207, /* k2g2[13] = 0.006324921212866403 */ + 174, /* k2g2[14] = 0.005321757979794424 */ + 147, /* k2g2[15] = 0.004477701309210577 */ + 123, /* k2g2[16] = 0.00376751612730811 */ + 104, /* k2g2[17] = 0.0031699697655869644 */ + 87, /* k2g2[18] = 0.00266719715992703 */ + 74, /* k2g2[19] = 0.0022441667321724647 */ + 62, /* k2g2[20] = 0.0018882309854916855 */ + 52, /* k2g2[21] = 0.0015887483774966232 */ + 44, /* k2g2[22] = 0.0013367651661223448 */ + 37, /* k2g2[23] = 0.0011247477162958733 */ + 31, /* k2g2[24] = 0.0009463572640678758 */ + 26, /* k2g2[25] = 0.0007962604042473498 */ + 22, /* k2g2[26] = 0.0006699696356181593 */ + 18, /* k2g2[27] = 0.0005637091964589207 */ + 16, /* k2g2[28] = 0.00047430217920125243 */ + 13, /* k2g2[29] = 0.00039907554925166274 */ + 11 /* k2g2[30] = 0.00033578022828973666 */ +}; + +static const EAS_I16 n1g2[] = +{ + 3170, /* n1g2[0] = 0.0967319927350769 */ + 3036, /* n1g2[1] = 0.0926446051254155 */ + 2908, /* n1g2[2] = 0.08872992911818503 */ + 2785, /* n1g2[3] = 0.08498066682523227 */ + 2667, /* n1g2[4] = 0.08138982872895201 */ + 2554, /* n1g2[5] = 0.07795072065216213 */ + 2446, /* n1g2[6] = 0.0746569312785634 */ + 2343, /* n1g2[7] = 0.07150232020051943 */ + 2244, /* n1g2[8] = 0.06848100647187474 */ + 2149, /* n1g2[9] = 0.06558735764447099 */ + 2058, /* n1g2[10] = 0.06281597926792246 */ + 1971, /* n1g2[11] = 0.06016170483307614 */ + 1888, /* n1g2[12] = 0.05761958614040857 */ + 1808, /* n1g2[13] = 0.05518488407540374 */ + 1732, /* n1g2[14] = 0.052853059773715245 */ + 1659, /* n1g2[15] = 0.05061976615964251 */ + 1589, /* n1g2[16] = 0.04848083984214659 */ + 1521, /* n1g2[17] = 0.046432293353298 */ + 1457, /* n1g2[18] = 0.04447030771468711 */ + 1396, /* n1g2[19] = 0.04259122531793907 */ + 1337, /* n1g2[20] = 0.040791543106060944 */ + 1280, /* n1g2[21] = 0.03906790604290942 */ + 1226, /* n1g2[22] = 0.037417100858604564 */ + 1174, /* n1g2[23] = 0.035836050059229754 */ + 1125, /* n1g2[24] = 0.03432180618965023 */ + 1077, /* n1g2[25] = 0.03287154633875494 */ + 1032, /* n1g2[26] = 0.03148256687687814 */ + 988, /* n1g2[27] = 0.030152278415589925 */ + 946, /* n1g2[28] = 0.028878200980459685 */ + 906, /* n1g2[29] = 0.02765795938779331 */ + 868 /* n1g2[30] = 0.02648927881672521 */ +}; + +static const EAS_I16 n1g3[] = +{ + -548, /* n1g3[0] = -0.016714088475899017 */ + -481, /* n1g3[1] = -0.014683605122742116 */ + -423, /* n1g3[2] = -0.012899791676436092 */ + -371, /* n1g3[3] = -0.01133268185193299 */ + -326, /* n1g3[4] = -0.00995594976868754 */ + -287, /* n1g3[5] = -0.008746467702146129 */ + -252, /* n1g3[6] = -0.00768391756106361 */ + -221, /* n1g3[7] = -0.006750449563854721 */ + -194, /* n1g3[8] = -0.005930382380083576 */ + -171, /* n1g3[9] = -0.005209939699767622 */ + -150, /* n1g3[10] = -0.004577018805123356 */ + -132, /* n1g3[11] = -0.004020987256990177 */ + -116, /* n1g3[12] = -0.003532504280467257 */ + -102, /* n1g3[13] = -0.00310336384922047 */ + -89, /* n1g3[14] = -0.002726356832432369 */ + -78, /* n1g3[15] = -0.002395149888601605 */ + -69, /* n1g3[16] = -0.0021041790717285314 */ + -61, /* n1g3[17] = -0.0018485563625771063 */ + -53, /* n1g3[18] = -0.001623987554831628 */ + -47, /* n1g3[19] = -0.0014267001167177025 */ + -41, /* n1g3[20] = -0.0012533798162347005 */ + -36, /* n1g3[21] = -0.0011011150453668693 */ + -32, /* n1g3[22] = -0.0009673479079754438 */ + -28, /* n1g3[23] = -0.0008498312496971563 */ + -24, /* n1g3[24] = -0.0007465909079943587 */ + -21, /* n1g3[25] = -0.0006558925481952733 */ + -19, /* n1g3[26] = -0.0005762125284029567 */ + -17, /* n1g3[27] = -0.0005062123038325457 */ + -15, /* n1g3[28] = -0.0004447159405951901 */ + -13, /* n1g3[29] = -0.00039069036118270117 */ + -11 /* n1g3[30] = -0.00034322798979677605 */ +}; + +/*---------------------------------------------------------------------------- + * WT_SetFilterCoeffs() + *---------------------------------------------------------------------------- + * Purpose: + * Update the Filter parameters + * + * Inputs: + * pVoice - ptr to the voice whose filter we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates Filter values for the given voice + *---------------------------------------------------------------------------- +*/ +void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance) +{ + EAS_I32 temp; + + /* + Convert the cutoff, which has had A5 subtracted, using the 2^x approx + Note, this cutoff is related to theta cutoff by + theta = k * 2^x + We use 2^x and incorporate k in the power series coefs instead + */ + cutoff = EAS_Calculate2toX(cutoff); + + /* calculate b2 coef */ + temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]); + temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp); + pIntFrame->frame.b2 = temp; + + /* calculate b1 coef */ + temp = MULT_AUDIO_COEF(cutoff, nk1g2); + temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp); + temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2); + pIntFrame->frame.b1 = temp >> 1; + + /* calculate K coef */ + temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]); + temp = MULT_AUDIO_COEF(cutoff, temp); + temp = MULT_AUDIO_COEF(cutoff, temp); + pIntFrame->frame.k = temp; +} +#endif + diff --git a/arm-hybrid-22k/lib_src/eas_wtsynth.h b/arm-hybrid-22k/lib_src/eas_wtsynth.h index 106ab40..90a7ad8 100644 --- a/arm-hybrid-22k/lib_src/eas_wtsynth.h +++ b/arm-hybrid-22k/lib_src/eas_wtsynth.h @@ -1,12 +1,12 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_wtsynth.h - * - * Contents and purpose: - * This file defines the interface for synthesizer engine - * - * Copyright Sonic Network Inc. 2004 +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtsynth.h + * + * Contents and purpose: + * This file defines the interface for synthesizer engine + * + * 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,48 +19,48 @@ * 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_WTSYNTH_H -#define _EAS_WTSYNTH_H - -#include "eas_sndlib.h" -#include "eas_wtengine.h" - -/* adjust the filter cutoff frequency to the sample rate */ -#if defined (_SAMPLE_RATE_8000) -#define FILTER_CUTOFF_FREQ_ADJUST 0 -#elif defined (_SAMPLE_RATE_16000) -#define FILTER_CUTOFF_FREQ_ADJUST 1200 -#elif defined (_SAMPLE_RATE_20000) -#define FILTER_CUTOFF_FREQ_ADJUST 1586 -#elif defined (_SAMPLE_RATE_22050) -#define FILTER_CUTOFF_FREQ_ADJUST 1756 -#elif defined (_SAMPLE_RATE_24000) -#define FILTER_CUTOFF_FREQ_ADJUST 1902 -#elif defined (_SAMPLE_RATE_32000) -#define FILTER_CUTOFF_FREQ_ADJUST 2400 -#elif defined (_SAMPLE_RATE_44100) -#define FILTER_CUTOFF_FREQ_ADJUST 2956 -#elif defined (_SAMPLE_RATE_48000) -#define FILTER_CUTOFF_FREQ_ADJUST 3102 -#else -#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" -#endif - -/* function prototypes */ -void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc); - -#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) -void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance); -#endif - -#endif - - + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WTSYNTH_H +#define _EAS_WTSYNTH_H + +#include "eas_sndlib.h" +#include "eas_wtengine.h" + +/* adjust the filter cutoff frequency to the sample rate */ +#if defined (_SAMPLE_RATE_8000) +#define FILTER_CUTOFF_FREQ_ADJUST 0 +#elif defined (_SAMPLE_RATE_16000) +#define FILTER_CUTOFF_FREQ_ADJUST 1200 +#elif defined (_SAMPLE_RATE_20000) +#define FILTER_CUTOFF_FREQ_ADJUST 1586 +#elif defined (_SAMPLE_RATE_22050) +#define FILTER_CUTOFF_FREQ_ADJUST 1756 +#elif defined (_SAMPLE_RATE_24000) +#define FILTER_CUTOFF_FREQ_ADJUST 1902 +#elif defined (_SAMPLE_RATE_32000) +#define FILTER_CUTOFF_FREQ_ADJUST 2400 +#elif defined (_SAMPLE_RATE_44100) +#define FILTER_CUTOFF_FREQ_ADJUST 2956 +#elif defined (_SAMPLE_RATE_48000) +#define FILTER_CUTOFF_FREQ_ADJUST 3102 +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +/* function prototypes */ +void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc); + +#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) +void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance); +#endif + +#endif + + diff --git a/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c b/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c index 880819c..1d6816b 100644 --- a/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c +++ b/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c @@ -1,11 +1,11 @@ -/*---------------------------------------------------------------------------- - * - * Filename: C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c - * Source: C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls - * CmdLine: -w C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c -l C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz.log -d 0 -c -f C:\Sonic\Release3-5\EASLib\FMSynth\GMdblib-3.fml C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls -w -l -d -c -f C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls - * Purpose: Wavetable sound libary - * - * Copyright (c) 2006 Sonic Network Inc. +/*---------------------------------------------------------------------------- + * + * Filename: C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c + * Source: C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls + * CmdLine: -w C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c -l C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz.log -d 0 -c -f C:\Sonic\Release3-5\EASLib\FMSynth\GMdblib-3.fml C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls -w -l -d -c -f C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls + * Purpose: Wavetable sound libary + * + * Copyright (c) 2006 Sonic Network Inc. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,5132 +18,5132 @@ * 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:$ - * $Date:$ - *---------------------------------------------------------------------------- -*/ - -#include "eas_sndlib.h" - -/*---------------------------------------------------------------------------- - * Articulations - *---------------------------------------------------------------------------- -*/ -const S_ARTICULATION eas_articulations[] = -{ - { /* articulation 0 */ - { 32767, 30725, 0, 30725 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 1 */ - { 32767, 26863, 0, 26863 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 2 */ - { 32767, 30484, 0, 30668 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 3 */ - { 32767, 26439, 0, 26439 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 4 */ - { 32767, 0, 32767, 32715 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 5 */ - { 32767, 21333, 0, 21333 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 6 */ - { 32767, 31882, 0, 31938 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 7 */ - { 32767, 32663, 32767, 32663 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 8 */ - { 32767, 0, 32767, 0 }, - { 32767, 1902, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 9 */ - { 32767, 32349, 0, 32349 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 10 */ - { 32767, 0, 32767, 17213 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -1 - }, - { /* articulation 11 */ - { 32767, 32072, 0, 32072 }, - { 32767, 761, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -56 - }, - { /* articulation 12 */ - { 32767, 23749, 0, 23749 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 56 - }, - { /* articulation 13 */ - { 32767, 32010, 0, 32010 }, - { 32767, 761, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -31 - }, - { /* articulation 14 */ - { 9511, 21333, 0, 21333 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 56 - }, - { /* articulation 15 */ - { 32767, 31844, 0, 31844 }, - { 32767, 761, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -6 - }, - { /* articulation 16 */ - { 32767, 32123, 0, 32194 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 56 - }, - { /* articulation 17 */ - { 32767, 31730, 0, 31730 }, - { 32767, 761, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 6 - }, - { /* articulation 18 */ - { 32767, 31391, 0, 31391 }, - { 32767, 951, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 31 - }, - { /* articulation 19 */ - { 32767, 31964, 0, 31964 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 25 - }, - { /* articulation 20 */ - { 32767, 31056, 0, 31056 }, - { 32767, 951, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 63 - }, - { /* articulation 21 */ - { 32767, 32289, 0, 32271 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -37 - }, - { /* articulation 22 */ - { 19021, 31882, 0, 31911 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -37 - }, - { /* articulation 23 */ - { 32767, 31988, 0, 32032 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -37 - }, - { /* articulation 24 */ - { 32767, 0, 32767, 32663 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 12 - }, - { /* articulation 25 */ - { 32767, 31352, 0, 31352 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -25 - }, - { /* articulation 26 */ - { 32767, 0, 32767, 32663 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 25 - }, - { /* articulation 27 */ - { 32767, 31817, 0, 31781 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -25 - }, - { /* articulation 28 */ - { 32767, 30725, 0, 30725 }, - { 32767, 95, 0, 0 }, - 0, 0, 951, 240, 0, 0, 0, 0, -56 - }, - { /* articulation 29 */ - { 32767, 32230, 0, 32218 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -37 - }, - { /* articulation 30 */ - { 32767, 26439, 0, 26439 }, - { 32767, 3804, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 50 - }, - { /* articulation 31 */ - { 32767, 23749, 0, 23749 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -50 - }, - { /* articulation 32 */ - { 32767, 29434, 0, 29434 }, - { 32767, 3804, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -50 - }, - { /* articulation 33 */ - { 32767, 30240, 0, 30234 }, - { 32767, 3804, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -44 - }, - { /* articulation 34 */ - { 32767, 32558, 0, 32558 }, - { 32767, 254, 0, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 25 - }, - { /* articulation 35 */ - { 32767, 0, 32767, 32663 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -63 - }, - { /* articulation 36 */ - { 3804, 23749, 0, 23749 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -63 - }, - { /* articulation 37 */ - { 32767, 23749, 0, 23749 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -59 - }, - { /* articulation 38 */ - { 32767, 30725, 0, 30725 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 50 - }, - { /* articulation 39 */ - { 32767, 28809, 0, 28809 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 44 - }, - { /* articulation 40 */ - { 1902, 30725, 0, 30725 }, - { 32767, 380, 0, 0 }, - 0, 0, 951, -100, 0, 0, 0, 0, 44 - }, - { /* articulation 41 */ - { 32767, 9042, 0, 9042 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 25 - }, - { /* articulation 42 */ - { 32767, 29889, 0, 29889 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 63 - }, - { /* articulation 43 */ - { 32767, 30240, 0, 30234 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 63 - }, - { /* articulation 44 */ - { 19021, 19970, 0, 19970 }, - { 951, 32767, 32767, 0 }, - 0, 0, 951, 100, 0, 0, 0, 0, -25 - }, - { /* articulation 45 */ - { 3804, 17213, 0, 17213 }, - { 951, 32767, 32767, 0 }, - 0, 0, 951, 500, 0, 0, 0, 0, -25 - }, - { /* articulation 46 */ - { 32767, 17213, 0, 17213 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -56 - }, - { /* articulation 47 */ - { 32767, 30725, 0, 30725 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, -56 - }, - { /* articulation 48 */ - { 32767, 0, 32767, 0 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 49 */ - { 32767, 31180, 0, 31180 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 50 */ - { 19021, 31964, 0, 32071 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 51 */ - { 32767, 29669, 0, 29669 }, - { 32767, 32767, 32767, 0 }, - 0, 0, 951, 0, 0, 0, 0, 0, 0 - }, - { /* articulation 52 */ - { 32767, 31742, 0, 31352 }, - { 32767, 294, 0, 0 }, - 0, 0, 951, 0, 10000, 7121, 0, 0, 0 - } -}; /*end Articulations */ - -/*---------------------------------------------------------------------------- - * Regions - *---------------------------------------------------------------------------- -*/ -const S_WT_REGION eas_regions[] = -{ - { { 0, 27, 27 }, -2868, 16422, 0, 0, 19, 0 }, /* region 0 */ - { { 0, 28, 28 }, -3568, 32767, 0, 0, 13, 0 }, /* region 1 */ - { { 0, 29, 29 }, -4553, 32767, 0, 0, 9, 1 }, /* region 2 */ - { { 0, 30, 30 }, -4853, 32767, 0, 0, 9, 2 }, /* region 3 */ - { { 0, 31, 31 }, -3868, 23197, 0, 0, 15, 3 }, /* region 4 */ - { { 1536, 32, 32 }, -3368, 20675, 0, 0, 29, 4 }, /* region 5 */ - { { 1537, 33, 33 }, -3868, 20675, 792, 800, 17, 5 }, /* region 6 */ - { { 1537, 34, 34 }, -3968, 16422, 792, 800, 17, 6 }, /* region 7 */ - { { 0, 35, 35 }, -4968, 32767, 0, 0, 20, 7 }, /* region 8 */ - { { 0, 36, 36 }, -4968, 32767, 0, 0, 20, 7 }, /* region 9 */ - { { 0, 37, 37 }, -4051, 18426, 0, 0, 16, 8 }, /* region 10 */ - { { 0, 38, 38 }, -4151, 23197, 0, 0, 5, 9 }, /* region 11 */ - { { 0, 39, 39 }, -4668, 23197, 0, 0, 12, 10 }, /* region 12 */ - { { 0, 40, 40 }, -4151, 23197, 0, 0, 5, 4 }, /* region 13 */ - { { 1, 41, 41 }, -5855, 26028, 798, 993, 14, 11 }, /* region 14 */ - { { 257, 42, 42 }, -4368, 26028, 4288, 6792, 2, 12 }, /* region 15 */ - { { 1, 43, 43 }, -5755, 26028, 798, 993, 14, 13 }, /* region 16 */ - { { 257, 44, 44 }, -4568, 26028, 4288, 6792, 2, 14 }, /* region 17 */ - { { 1, 45, 45 }, -5755, 26028, 798, 993, 14, 15 }, /* region 18 */ - { { 257, 46, 46 }, -4768, 26028, 4288, 6792, 2, 16 }, /* region 19 */ - { { 1, 47, 47 }, -5455, 26028, 798, 993, 14, 17 }, /* region 20 */ - { { 1, 48, 48 }, -5355, 26028, 798, 993, 14, 18 }, /* region 21 */ - { { 1, 49, 49 }, -5368, 16422, 1294, 5241, 3, 19 }, /* region 22 */ - { { 1, 50, 50 }, -5255, 26028, 798, 993, 14, 20 }, /* region 23 */ - { { 1, 51, 51 }, -5268, 16422, 6592, 9921, 0, 21 }, /* region 24 */ - { { 1, 52, 52 }, -5768, 32767, 1294, 5241, 3, 22 }, /* region 25 */ - { { 1, 53, 53 }, -5418, 14636, 6592, 9921, 0, 23 }, /* region 26 */ - { { 0, 54, 54 }, -5751, 26028, 0, 0, 11, 24 }, /* region 27 */ - { { 1, 55, 55 }, -5468, 32767, 1294, 5241, 3, 25 }, /* region 28 */ - { { 0, 56, 56 }, -7255, 32767, 0, 0, 24, 26 }, /* region 29 */ - { { 1, 57, 57 }, -5868, 32767, 1294, 5241, 3, 27 }, /* region 30 */ - { { 1, 58, 58 }, -7053, 23197, 0, 166, 26, 28 }, /* region 31 */ - { { 1, 59, 59 }, -5968, 16422, 6592, 9921, 0, 29 }, /* region 32 */ - { { 1, 60, 60 }, -6453, 23197, 432, 582, 18, 30 }, /* region 33 */ - { { 1, 61, 61 }, -6853, 16422, 432, 582, 18, 30 }, /* region 34 */ - { { 1, 62, 62 }, -7253, 20675, 432, 582, 18, 31 }, /* region 35 */ - { { 1, 63, 63 }, -7353, 23197, 432, 582, 18, 32 }, /* region 36 */ - { { 1, 64, 64 }, -7953, 23197, 432, 582, 18, 33 }, /* region 37 */ - { { 0, 65, 65 }, -7555, 32767, 0, 0, 4, 34 }, /* region 38 */ - { { 0, 66, 66 }, -7955, 20675, 0, 0, 4, 34 }, /* region 39 */ - { { 512, 67, 67 }, -7155, 18426, 0, 0, 24, 35 }, /* region 40 */ - { { 512, 68, 68 }, -7755, 18426, 0, 0, 24, 35 }, /* region 41 */ - { { 0, 69, 69 }, -7755, 32767, 0, 0, 21, 36 }, /* region 42 */ - { { 0, 70, 70 }, -6855, 21900, 0, 0, 21, 37 }, /* region 43 */ - { { 769, 71, 71 }, -6355, 23197, 0, 1226, 10, 38 }, /* region 44 */ - { { 769, 72, 72 }, -6955, 26028, 0, 1226, 10, 38 }, /* region 45 */ - { { 1024, 73, 73 }, -7955, 32767, 0, 0, 7, 39 }, /* region 46 */ - { { 1024, 74, 74 }, -8455, 32767, 0, 0, 7, 40 }, /* region 47 */ - { { 1, 75, 75 }, -8068, 23197, 0, 29, 30, 41 }, /* region 48 */ - { { 0, 76, 76 }, -10455, 23197, 0, 0, 28, 42 }, /* region 49 */ - { { 0, 77, 77 }, -10055, 23197, 0, 0, 28, 43 }, /* region 50 */ - { { 0, 78, 78 }, -8853, 16422, 0, 0, 23, 44 }, /* region 51 */ - { { 0, 79, 79 }, -10253, 16422, 0, 0, 23, 45 }, /* region 52 */ - { { 1280, 80, 80 }, -6468, 13045, 0, 0, 25, 46 }, /* region 53 */ - { { 1280, 81, 81 }, -6568, 16422, 0, 0, 25, 47 }, /* region 54 */ - { { 0, 82, 82 }, -8455, 20675, 0, 0, 22, 48 }, /* region 55 */ - { { 0, 83, 83 }, -9068, 32767, 0, 0, 6, 49 }, /* region 56 */ - { { 1, 84, 84 }, -8568, 23197, 0, 9337, 1, 50 }, /* region 57 */ - { { 0, 85, 85 }, -9655, 32767, 0, 0, 27, 0 }, /* region 58 */ - { { 0, 86, 86 }, -9068, 16422, 0, 0, 8, 51 }, /* region 59 */ - { { 32769, 87, 87 }, -9168, 32767, 1335, 1603, 8, 52 } /* region 60 */ -}; /* end Regions */ - -/*---------------------------------------------------------------------------- - * FM Regions - *---------------------------------------------------------------------------- -*/ -const S_FM_REGION eas_fmRegions[] = -{ - - { /* FM region 0 */ - { 37, 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 } - } - }, - { /* FM region 1 */ - { 37, 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 } - } - }, - { /* FM region 2 */ - { 37, 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 } - } - }, - { /* FM region 3 */ - { 37, 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 } - } - }, - { /* FM region 4 */ - { 34, 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 } - } - }, - { /* FM region 5 */ - { 34, 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 } - } - }, - { /* FM region 6 */ - { 34, 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 } - } - }, - { /* FM region 7 */ - { 37, 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 } - } - }, - { /* FM region 8 */ - { 33, 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 } - } - }, - { /* FM region 9 */ - { 34, 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 } - } - }, - { /* FM region 10 */ - { 34, 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 } - } - }, - { /* FM region 11 */ - { 34, 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 } - } - }, - { /* FM region 12 */ - { 34, 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 } - } - }, - { /* FM region 13 */ - { 34, 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 } - } - }, - { /* FM region 14 */ - { 37, 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 } - } - }, - { /* FM region 15 */ - { 37, 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 } - } - }, - { /* FM region 16 */ - { 35, 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 } - } - }, - { /* FM region 17 */ - { 33, 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 } - } - }, - { /* FM region 18 */ - { 34, 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 } - } - }, - { /* FM region 19 */ - { 33, 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 } - } - }, - { /* FM region 20 */ - { 34, 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 } - } - }, - { /* FM region 21 */ - { 34, 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 } - } - }, - { /* FM region 22 */ - { 37, 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 } - } - }, - { /* FM region 23 */ - { 34, 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 } - } - }, - { /* FM region 24 */ - { 37, 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 } - } - }, - { /* FM region 25 */ - { 37, 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 } - } - }, - { /* FM region 26 */ - { 37, 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 } - } - }, - { /* FM region 27 */ - { 37, 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 } - } - }, - { /* FM region 28 */ - { 37, 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 } - } - }, - { /* FM region 29 */ - { 37, 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 } - } - }, - { /* FM region 30 */ - { 37, 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 } - } - }, - { /* FM region 31 */ - { 41, 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 } - } - }, - { /* FM region 32 */ - { 37, 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 } - } - }, - { /* FM region 33 */ - { 37, 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 } - } - }, - { /* FM region 34 */ - { 37, 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 } - } - }, - { /* FM region 35 */ - { 37, 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 } - } - }, - { /* FM region 36 */ - { 37, 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 } - } - }, - { /* FM region 37 */ - { 37, 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 } - } - }, - { /* FM region 38 */ - { 34, 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 } - } - }, - { /* FM region 39 */ - { 34, 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 } - } - }, - { /* FM region 40 */ - { 37, 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 } - } - }, - { /* FM region 41 */ - { 37, 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 } - } - }, - { /* FM region 42 */ - { 37, 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 } - } - }, - { /* FM region 43 */ - { 37, 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 } - } - }, - { /* FM region 44 */ - { 37, 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 } - } - }, - { /* FM region 45 */ - { 37, 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 } - } - }, - { /* FM region 46 */ - { 34, 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 } - } - }, - { /* FM region 47 */ - { 37, 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 } - } - }, - { /* FM region 48 */ - { 34, 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 } - } - }, - { /* FM region 49 */ - { 34, 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 } - } - }, - { /* FM region 50 */ - { 34, 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 } - } - }, - { /* FM region 51 */ - { 37, 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 } - } - }, - { /* FM region 52 */ - { 34, 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 } - } - }, - { /* FM region 53 */ - { 37, 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 } - } - }, - { /* FM region 54 */ - { 34, 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 } - } - }, - { /* FM region 55 */ - { 41, 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 } - } - }, - { /* FM region 56 */ - { 37, 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 } - } - }, - { /* FM region 57 */ - { 37, 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 } - } - }, - { /* FM region 58 */ - { 37, 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 } - } - }, - { /* FM region 59 */ - { 37, 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 } - } - }, - { /* FM region 60 */ - { 34, 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 } - } - }, - { /* FM region 61 */ - { 34, 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 } - } - }, - { /* FM region 62 */ - { 34, 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 } - } - }, - { /* FM region 63 */ - { 34, 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 } - } - }, - { /* FM region 64 */ - { 37, 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 } - } - }, - { /* FM region 65 */ - { 37, 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 } - } - }, - { /* FM region 66 */ - { 37, 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 } - } - }, - { /* FM region 67 */ - { 37, 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 } - } - }, - { /* FM region 68 */ - { 34, 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 } - } - }, - { /* FM region 69 */ - { 34, 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 } - } - }, - { /* FM region 70 */ - { 34, 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 } - } - }, - { /* FM region 71 */ - { 34, 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 } - } - }, - { /* FM region 72 */ - { 37, 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 } - } - }, - { /* FM region 73 */ - { 37, 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 } - } - }, - { /* FM region 74 */ - { 35, 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 } - } - }, - { /* FM region 75 */ - { 37, 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 } - } - }, - { /* FM region 76 */ - { 37, 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 } - } - }, - { /* FM region 77 */ - { 50, 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 } - } - }, - { /* FM region 78 */ - { 34, 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 } - } - }, - { /* FM region 79 */ - { 35, 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 } - } - }, - { /* FM region 80 */ - { 34, 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 } - } - }, - { /* FM region 81 */ - { 34, 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 } - } - }, - { /* FM region 82 */ - { 37, 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 } - } - }, - { /* FM region 83 */ - { 37, 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 } - } - }, - { /* FM region 84 */ - { 37, 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 } - } - }, - { /* FM region 85 */ - { 34, 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 } - } - }, - { /* FM region 86 */ - { 34, 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 } - } - }, - { /* FM region 87 */ - { 34, 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 } - } - }, - { /* FM region 88 */ - { 35, 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 } - } - }, - { /* FM region 89 */ - { 34, 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 } - } - }, - { /* FM region 90 */ - { 34, 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 } - } - }, - { /* FM region 91 */ - { 35, 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 } - } - }, - { /* FM region 92 */ - { 34, 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 } - } - }, - { /* FM region 93 */ - { 37, 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 } - } - }, - { /* FM region 94 */ - { 35, 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 } - } - }, - { /* FM region 95 */ - { 34, 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 } - } - }, - { /* FM region 96 */ - { 50, 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 } - } - }, - { /* FM region 97 */ - { 34, 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 } - } - }, - { /* FM region 98 */ - { 34, 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 } - } - }, - { /* FM region 99 */ - { 34, 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 } - } - }, - { /* FM region 100 */ - { 34, 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 } - } - }, - { /* FM region 101 */ - { 34, 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 } - } - }, - { /* FM region 102 */ - { 50, 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 } - } - }, - { /* FM region 103 */ - { 37, 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 } - } - }, - { /* FM region 104 */ - { 34, 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 } - } - }, - { /* FM region 105 */ - { 37, 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 } - } - }, - { /* FM region 106 */ - { 37, 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 } - } - }, - { /* FM region 107 */ - { 37, 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 } - } - }, - { /* FM region 108 */ - { 37, 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 } - } - }, - { /* FM region 109 */ - { 34, 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 } - } - }, - { /* FM region 110 */ - { 37, 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 } - } - }, - { /* FM region 111 */ - { 34, 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 } - } - }, - { /* FM region 112 */ - { 37, 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 } - } - }, - { /* FM region 113 */ - { 37, 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 } - } - }, - { /* FM region 114 */ - { 37, 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 } - } - }, - { /* FM region 115 */ - { 37, 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 } - } - }, - { /* FM region 116 */ - { 37, 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 } - } - }, - { /* FM region 117 */ - { 37, 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 } - } - }, - { /* FM region 118 */ - { 37, 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 } - } - }, - { /* FM region 119 */ - { 37, 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 } - } - }, - { /* FM region 120 */ - { 52, 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 } - } - }, - { /* FM region 121 */ - { 37, 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 } - } - }, - { /* FM region 122 */ - { 34, 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 } - } - }, - { /* FM region 123 */ - { 50, 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 } - } - }, - { /* FM region 124 */ - { 50, 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 } - } - }, - { /* FM region 125 */ - { 34, 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 } - } - }, - { /* FM region 126 */ - { 53, 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 } - } - }, - { /* FM region 127 */ - { 53, 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 } - } - }}; /* end FM Regions */ - -/*---------------------------------------------------------------------------- - * Programs - *---------------------------------------------------------------------------- -*/ -const S_PROGRAM eas_programs[] = -{ - { 7864320, 0 } /* program 0 */ -}; /* end Programs */ - -/*---------------------------------------------------------------------------- - * Banks - *---------------------------------------------------------------------------- -*/ -const S_BANK eas_banks[] = -{ - { /* bank 0 */ - 30976, - { - 32768, 32769, 32770, 32771, 32772, 32773, 32774, 32775, - 32776, 32777, 32778, 32779, 32780, 32781, 32782, 32783, - 32784, 32785, 32786, 32787, 32788, 32789, 32790, 32791, - 32792, 32793, 32794, 32795, 32796, 32797, 32798, 32799, - 32800, 32801, 32802, 32803, 32804, 32805, 32806, 32807, - 32808, 32809, 32810, 32811, 32812, 32813, 32814, 32815, - 32816, 32817, 32818, 32819, 32820, 32821, 32822, 32823, - 32824, 32825, 32826, 32827, 32828, 32829, 32830, 32831, - 32832, 32833, 32834, 32835, 32836, 32837, 32838, 32839, - 32840, 32841, 32842, 32843, 32844, 32845, 32846, 32847, - 32848, 32849, 32850, 32851, 32852, 32853, 32854, 32855, - 32856, 32857, 32858, 32859, 32860, 32861, 32862, 32863, - 32864, 32865, 32866, 32867, 32868, 32869, 32870, 32871, - 32872, 32873, 32874, 32875, 32876, 32877, 32878, 32879, - 32880, 32881, 32882, 32883, 32884, 32885, 32886, 32887, - 32888, 32889, 32890, 32891, 32892, 32893, 32894, 32895 - } - } -}; /* end Banks */ - -/*---------------------------------------------------------------------------- - * Samples - *---------------------------------------------------------------------------- -*/ - -const EAS_SAMPLE eas_samples[] = -{ - 13, -24, 28, -32, 33, -37, 39, -61, 119, -76, 120, -70, 99, -122, 89, -113, - 91, -123, 122, -123, 77, 86, -116, 6, -118, 123, -23, 64, -93, 17, 24, -125, - 124, -125, 124, -24, -12, 56, 87, -54, 38, -91, 64, -2, -41, 126, -127, 20, - 8, -48, -62, 127, -128, 88, -43, -18, 86, -100, 44, -32, -26, 71, -13, 6, - 51, -33, -50, 106, -59, 33, 5, -20, 69, -56, 54, -48, -6, 38, -5, -38, - 35, -1, 12, -1, 4, 23, -56, 19, -7, 5, -4, 31, -38, 3, -12, -9, - -25, -7, 24, -32, 17, -21, -22, 24, -20, 6, -18, 0, -15, 5, -16, 15, - 3, 2, -10, 3, 27, -31, 37, -12, 32, -5, 2, -21, 27, -14, 20, -8, - 5, 15, -7, -11, 20, -37, 7, -23, 17, -22, 11, -14, 8, -44, 39, -52, - 26, 3, 14, -10, 51, -45, 29, -19, 19, -3, 41, -21, 46, -23, 10, 16, - -25, 3, 7, -30, 19, -9, -5, -1, 1, -19, 1, -24, -23, 51, -48, -10, - 17, -34, -38, 60, -71, 26, -43, 65, -59, 70, -26, 61, -51, 63, -51, 42, - -25, 58, -36, 31, 10, -14, -9, 8, -18, 8, 4, 8, 7, 31, -52, 39, - -53, 53, -56, 24, 11, 1, -20, -8, -32, -18, -10, -25, 4, 1, 37, -37, - 42, -42, 53, -57, 52, -18, 30, 11, 20, -52, 55, -61, 56, -50, 24, -26, - 38, -42, 36, -1, -43, 58, -46, 6, 18, -35, 31, -36, 28, -55, 55, -98, - 52, -41, 26, -24, 48, -31, 48, -26, 30, 19, -17, 23, -8, 13, 15, 19, - -7, -23, 41, -36, 20, -39, 65, -64, 66, -38, -9, 7, -14, -10, -3, 6, - 15, -19, -40, 53, -67, -11, -12, -25, 23, -11, -12, 46, -48, 39, -20, 20, - -14, 31, -54, 71, -25, 2, -8, -5, -9, 1, 7, 27, 17, -14, 43, -31, - 27, 11, -33, 20, -2, -33, 45, -38, 17, -9, -11, -17, -22, -19, 20, -25, - 4, 29, -35, 14, -17, 1, -7, 19, 2, 16, 32, -3, -17, 4, 0, -9, - 17, 5, -8, 52, -32, 40, -39, -5, -18, 14, -21, 31, 10, -17, 8, -34, - -7, 1, -44, 7, 10, -8, -6, -18, -25, -1, -19, 16, -29, 62, 6, 9, - 21, 0, -14, 4, 5, 20, 13, 27, -1, 18, -5, 21, -31, 11, 2, -9, - -4, 21, -27, 8, -21, -28, -19, 14, -12, 5, -20, 20, -36, 4, -18, -27, - -4, -4, 15, 4, 48, -7, -11, 20, -6, 7, 20, 1, 20, 0, 35, -35, - 28, -37, 7, -43, 21, -22, 23, -18, 12, -22, -13, -20, -11, 7, 23, -10, - 19, -18, 17, -41, 4, -16, -8, 21, 11, -4, 10, 30, -24, 32, -15, 15, - -13, 28, -5, 38, -10, 0, -22, -13, -12, 24, -18, 30, -7, 4, -16, 27, - -28, -3, -1, 18, -14, 31, -24, -3, -13, -19, -36, -2, -31, 9, -2, -12, - 17, 12, -50, 46, -49, 43, -15, 13, 22, 15, -25, 10, -8, -6, 14, -2, - 24, 15, 9, 17, -13, 5, 14, -15, 7, 20, 4, 4, 18, -16, 3, -47, - 31, -46, 19, -24, 5, -19, -1, -42, 14, -44, 18, -7, -1, 15, 9, -35, - 32, -44, 39, -46, 23, -16, 36, -25, 45, -34, 32, -8, 10, 5, 28, 0, - 12, 11, 3, 20, -23, 6, -8, 16, 7, 17, -19, 32, -44, 3, -8, -21, - -8, -5, 2, -29, 2, -3, -19, -14, 3, 7, -23, 10, 1, 3, 8, 13, - -44, 20, 21, -16, 23, 3, 5, 10, -11, 32, -11, 13, -7, 30, 4, 16, - -7, -6, -7, 14, -40, 4, -16, -26, 3, -1, 0, -6, 5, -50, 37, -27, - 18, -16, -14, 6, -1, -4, -15, 8, -12, 14, 9, -22, 42, -10, 23, -11, - 36, -15, 13, 30, 1, 47, -20, 33, -14, -12, 1, -20, -9, -9, -11, -13, - 7, -37, 25, -47, 14, -13, 4, -12, 9, -32, 18, -48, -1, -35, -1, -7, - 35, -20, 53, -4, 34, -7, 13, 19, 9, 30, 6, 45, -22, 23, -18, -6, - -1, 3, -30, 14, -15, 9, -39, 10, -33, -13, -24, 10, 14, 14, -10, 2, - -34, -4, -20, -21, -14, 40, -10, 17, -14, 28, -17, 37, -26, 69, -15, 38, - 2, 21, -25, 37, -61, 13, -9, 5, -17, 18, -41, 22, -57, -1, -9, -13, - 24, -10, 38, -5, 8, -16, -2, 1, 12, -25, -2, -13, 2, 2, -16, -19, - 32, -30, 22, 20, -4, 12, 11, -17, 19, -17, -3, 20, -33, 65, -27, 32, - -14, 8, -8, 13, -19, 9, -2, 7, 33, -40, 18, -18, -18, 6, -23, -11, - -11, -28, 4, -11, -15, -14, -8, -5, 34, -6, 19, 1, -3, 9, -1, 5, - 5, 14, -11, 40, -3, 18, -20, 16, -7, 2, -5, 9, -16, 9, -17, 0, - -17, 4, -17, -3, 3, 8, -14, -19, 12, -21, -7, 1, -2, -8, 16, 3, - -6, 35, -23, 33, -13, 11, 12, 3, -7, 26, -11, 19, -18, 23, -22, 39, - -49, 39, -50, 11, -38, 26, -29, 10, -6, -22, 15, -8, 15, -37, 36, -43, - 39, -43, 18, -26, 1, 11, 4, -2, 9, 7, 2, 7, 19, 1, 1, -4, - 16, -5, 16, -9, -3, 4, -4, -1, -17, 0, 11, 16, -27, 12, -15, 15, - -3, 0, 10, -3, -5, 12, -13, -7, -13, -31, -1, -3, -17, 15, -31, 25, - -10, 15, -1, 2, 4, 10, 7, 32, -13, 7, -22, 2, -10, 16, 1, -15, - 19, -24, 16, -18, -12, 18, -9, 9, 24, -8, 8, 11, 0, -31, 17, -55, - 21, -43, 40, -40, 29, -54, 44, -34, 22, 11, 16, 7, 19, 21, -6, 2, - -7, -16, 22, 0, -1, -4, 5, -8, 26, -42, 4, -6, -21, 35, -16, 8, - 0, -22, -13, 11, -31, 7, -28, 4, 17, -12, -18, -2, -23, 23, -1, 19, - 34, 7, 7, 35, -19, 11, -8, -17, 8, 4, 16, -16, -13, 9, -15, -5, - -1, -6, 7, 3, 11, 1, -7, -24, 21, -31, 36, -3, -10, 8, 2, -17, - 12, -24, 6, -3, 9, 15, 3, 13, -8, -13, -3, 6, -19, 14, -33, 16, - -17, -5, -31, 3, -29, 24, -7, -6, 35, -20, -5, 34, -20, 25, -3, 10, - 25, 8, 14, -13, 0, 1, 17, -33, 51, -38, 45, -32, 39, -3, -2, -24, - 3, -18, 14, -4, -44, 2, -25, -15, -2, -23, 3, -2, -2, 20, -14, 8, - -10, -4, 21, 11, -13, 32, -4, 8, 19, -16, -2, -2, -2, 14, -2, -1, - 27, -26, 20, 11, -13, 10, -3, -7, 12, -13, -3, -30, -16, 10, -26, -3, - -10, -2, -9, 15, -17, 1, -2, -7, 14, -8, 12, -3, -1, 2, 47, -26, - 22, -19, 16, 2, 13, -3, 21, -10, 22, -32, 43, -24, 16, 0, 5, -2, - 12, -44, -12, 1, -26, 1, -36, 5, 2, 9, -17, 20, -37, 14, -9, -5, - 6, -3, -13, 23, -19, 25, -33, 6, 17, 10, 19, 15, -4, 12, 5, -9, - 33, -20, 26, -9, 11, -2, 11, -21, -7, -13, -4, -8, -12, 0, -10, -9, - 8, -33, 9, -26, 8, 6, -8, 12, 7, -8, 0, 7, -16, 25, -8, 27, - 12, 0, 9, -9, 4, -17, 14, -16, 11, -8, 18, -2, 4, 2, -20, -18, - 22, -16, -5, 3, -24, 13, -10, -12, -10, 2, -16, 33, -15, 21, -15, -4, - -19, 29, -22, 18, 2, 20, 12, 18, -22, -7, -16, 7, -19, 14, 1, -17, - 33, -22, 38, -8, 3, -3, 21, -17, 51, -43, 15, -22, -23, -6, -12, -14, - 14, 9, 6, 4, -31, 3, -16, -14, 22, -22, 5, 13, -25, 17, -2, -18, - 7, 1, 5, 36, -16, 23, 4, -15, 29, -20, 10, 1, 24, 17, 16, -4, - -16, -37, -11, 1, -33, 27, -36, 17, -22, 2, -33, 16, -29, 32, -7, 24, - -12, 14, -12, 22, -16, 15, -20, 19, 9, 14, 12, -1, -24, 13, -6, -1, - 32, -19, 24, 12, -26, 4, -31, -38, 18, -16, -13, 3, -14, -1, 11, -15, - 15, 0, -2, 30, -6, 35, -23, 10, -35, 5, -14, 17, -21, 20, 4, 7, - 8, -5, -15, 20, -25, 26, 6, -3, 3, 5, -24, 26, -35, 4, 0, -6, - 13, -23, 8, -25, 1, -2, 9, 3, 17, 4, 0, 13, -15, 3, -21, -16, - 4, -5, -10, 11, -2, 7, 23, -22, 25, -19, 18, 25, -9, 14, -21, -7, - 11, -24, 22, -12, -7, 6, 9, -33, 11, -20, 2, -9, 2, 3, -13, 12, - -15, 23, -21, 16, -16, -2, 8, 13, -12, 18, -10, 16, -12, 20, -18, 18, - -1, 21, -21, 20, -30, -6, 10, -2, 13, -6, -15, 6, 2, -1, 1, -19, - 9, -15, -3, -11, 0, -5, 1, 5, 1, -4, -8, 1, -16, 23, 0, -23, - 2, 8, -6, 38, -4, 2, 13, -17, 31, -4, -8, 22, -14, 0, 12, -22, - 7, -7, 11, 4, -4, -12, -9, -22, 2, -17, -17, -11, 7, -17, 19, -24, - 9, -8, -6, 29, -4, 10, 4, 4, 23, -1, 9, -6, -12, 23, 16, -6, - 33, -29, 12, -7, -10, 17, -4, -18, 21, 0, -14, -2, -20, -21, 10, -28, - 5, -18, -4, 0, -11, 1, 5, -17, 3, 9, 20, 6, 1, -7, 2, -7, - 3, 9, -22, 29, 6, -1, 25, -10, 6, -1, 4, 12, 18, -13, 28, -11, - 6, -15, -14, -22, -7, 5, -14, 1, -16, -12, -5, 5, -9, 4, -1, -14, - 21, -10, -5, 0, -17, -7, 2, -10, 6, 11, 1, 37, -17, 6, 21, -24, - 41, 2, 23, 0, 10, -18, 16, -26, 14, -21, -19, 18, -9, -14, -1, -9, - -14, -3, -7, -10, 7, -7, 19, -11, 15, -25, -3, -6, 2, 8, -10, 4, - 12, -3, 11, -2, -2, 5, 31, -9, 39, -21, 14, -23, 18, -16, -1, -3, - -6, 0, 22, -9, -5, -17, -4, -12, 2, -3, -7, 10, -10, 7, -20, -19, - -10, 0, -14, 32, -15, -18, 13, -9, 2, 17, -14, 6, 36, -9, 28, 1, - 0, 17, -10, 5, 17, -8, 12, -2, 3, 2, -22, -6, -14, 6, 8, -11, - -14, 2, -23, 25, -35, 3, -18, 1, -14, 22, -1, -12, -7, -9, 13, -4, - 12, 4, -3, 18, 0, 1, 8, -14, 14, -2, 1, 17, -3, -14, 35, -17, - 19, -14, -6, 1, -9, 18, -17, -4, -13, -2, -14, 10, -10, -6, 0, 3, - 5, -12, -13, -3, -6, -6, 11, -13, -7, 13, -2, 6, 13, -7, 11, -5, - 23, 1, 29, -17, 23, -10, 18, -16, 12, -20, 10, 7, -9, -5, -21, -9, - 5, -13, -2, 0, -15, -11, 3, 0, -18, 5, -25, -2, 3, -2, -3, 4, - 8, 14, -7, 15, 4, 8, 19, 9, 11, 7, -3, 14, -11, 1, 15, -35, - 3, 3, -10, -16, 0, -15, 2, 3, -12, 27, -23, 32, -15, 10, -14, 3, - -27, 10, -15, 12, -24, 7, 2, 9, -2, -2, -1, 3, 1, 1, 8, -4, - 0, 6, -6, 1, 1, -1, 8, -11, 31, -27, 13, 4, -3, 5, -1, 0, - 2, 9, 0, 12, -31, 4, -27, 1, -25, 20, -21, -14, 12, -14, 0, -5, - -23, 18, -1, 15, 19, -5, 20, -8, 14, -7, 16, 3, 0, 8, 10, 0, - -8, -10, 3, -8, 9, -12, 4, 15, -6, 2, -12, -29, -3, -16, -11, 35, - -18, -1, -28, 7, -12, 0, 7, -5, 22, 10, 10, -4, 6, -13, 21, -23, - 20, 8, -13, 11, 15, -6, -6, -22, -1, 3, 14, 7, 11, -27, 12, -17, - -12, 8, -15, 3, -8, 12, -12, 5, -30, 12, -18, 9, -2, 3, 4, 15, - 1, 5, -9, 0, -8, 24, -2, 21, 5, -4, -4, 14, -15, 0, -1, 3, - 17, -5, 13, -19, -10, -4, -6, -4, -7, 18, -27, 8, 1, -12, -21, -13, - 1, -9, 11, 1, -3, -1, 22, -21, 9, 6, -3, 20, -2, 17, 7, -12, - 1, 4, 4, -9, 9, -20, 24, 7, -9, -3, -7, -6, 10, 7, 3, 9, - -2, -3, -4, 1, -19, -8, -16, 0, -12, 0, -25, 4, -22, 10, -9, 0, - -3, 15, -1, 8, 11, -15, 10, 13, 1, 22, -5, 15, 1, 24, 6, 0, - -6, 5, 5, 10, 8, -1, -11, -14, 3, -31, 2, -22, -4, -8, -15, -2, - -31, -12, 6, -7, 5, 2, 3, -4, 19, 3, 4, 7, 7, -8, 31, -6, - 26, 1, -2, 2, -3, -10, -4, -4, 9, 3, 12, -16, 16, -9, -1, 5, - 4, -7, 13, -17, 0, -11, -13, -22, 1, -9, 4, -7, 7, -10, 5, -1, - -6, -3, -21, 7, -10, 18, -3, 1, -7, -11, 11, -8, 12, 20, 3, 13, - 16, -1, 3, 13, -3, 23, 16, -3, 15, -14, 12, -6, -8, -28, 0, -33, - 4, -11, -12, -13, -21, -17, -16, -5, -12, 16, -7, 15, -6, -5, 3, -9, - 21, 17, 13, 14, 11, 21, -12, 31, -18, 7, 12, 8, 9, 7, 1, -3, - -7, -14, 17, -35, -10, -2, -18, -8, -10, -20, -22, 2, -10, -3, 1, -1, - 4, -5, 11, -20, 11, -6, 27, 7, 18, 8, -1, 2, 3, 11, -9, 5, - 5, -7, 29, -6, 20, -21, 23, -15, 19, -19, 2, -22, 11, -26, -7, -10, - -30, -1, -3, -6, 15, -22, 16, -7, -9, -2, -7, -5, 11, 17, -13, 2, - 8, -5, 6, 27, -6, 12, -6, 4, 15, 3, 14, -3, -12, 11, -2, 6, - 5, 4, -6, -12, 0, -32, 2, -22, 22, -12, -5, -7, -11, -7, 6, -1, - -3, -3, -16, 2, -1, 0, 0, -7, -2, 1, 12, -4, 5, 20, 1, 16, - -2, 14, -1, 19, 8, 29, -8, 7, -14, -2, 3, -13, 8, -40, 22, -18, - 2, -14, -8, -11, -8, 12, -21, -1, -10, -12, -6, -4, -14, 6, -19, 7, - 14, 1, 11, 11, -11, 25, 1, 14, -5, 31, 0, 22, 4, 1, 3, 6, - -3, 4, -2, -20, -7, -26, 1, -12, -7, -10, 2, -1, -5, -7, -8, -10, - 6, -7, -6, 10, -17, 6, 3, 15, -8, 15, -7, 12, 1, 9, -4, -2, - 10, 9, -1, 10, -4, 9, -8, 17, 0, -13, -7, -2, -11, 3, -2, -15, - -4, -11, -5, -9, 1, 8, -10, 8, -8, -6, -18, 21, -19, 26, -19, -1, - -11, 10, 4, 12, -10, 16, -10, 17, 8, 13, -1, 17, 1, 5, -1, 11, - -8, 9, 16, -17, 3, -26, -17, -14, 6, -17, 4, -20, 0, -1, -6, -4, - 2, -15, 13, -3, -1, 0, -2, -8, 11, 7, -3, -8, 5, 14, -1, 28, - -19, 13, -4, 8, 1, 11, 7, 6, -8, -2, -13, -10, -22, 6, 11, -1, - -1, -5, -13, 18, 3, -10, 9, -17, -8, 9, -9, 1, -17, -4, -16, 18, - -6, 15, -10, 17, 5, 0, -5, 0, -11, 12, 15, 4, 8, 5, -4, 0, - -2, 3, -17, -2, -1, 11, -6, -7, 2, -33, 23, -6, -1, -2, -2, -1, - -8, 3, -29, -2, -34, 16, -3, 16, 1, 10, -12, 23, 0, -3, 16, 12, - 19, 23, -1, 8, -26, 16, -32, 26, -13, 2, -11, 5, -1, -15, -9, -16, - 7, -6, 14, -15, 5, -10, -7, -9, -9, 6, -17, 13, 18, -5, -3, -4, - -4, -18, 28, -6, 13, 17, 24, -2, 9, -14, 1, -11, 7, 17, 1, -15, - 10, -23, -4, -12, 5, -20, 17, -10, 6, 0, -9, 4, -8, -15, 6, -16, - 7, 9, 3, 6, -12, -17, 0, 4, 13, 22, -4, 10, -8, 7, -12, 5, - 5, 1, 11, 2, 10, -3, -2, 3, -10, -5, -7, -4, -18, 17, -2, -14, - -16, -7, -10, -3, 6, -1, 14, -11, 15, -18, 2, -6, 0, -1, 0, 20, - -17, 1, 6, 2, 6, 12, -3, 7, 25, -5, 17, -14, 0, -6, 0, -2, - -5, -1, -10, 8, 2, -9, -19, -7, -17, 5, 3, -7, 4, -15, -5, 9, - -12, -1, -5, 3, -5, 26, -2, 3, -4, 5, 3, 7, 10, 5, 6, 6, - 26, -17, 0, -1, 3, -3, 10, -7, -7, -9, 11, -18, 0, -16, -6, -5, - 3, 7, -14, -14, 0, -21, 14, -8, -1, -12, 2, 1, 2, -3, -1, -3, - 18, 5, 5, 9, 12, 7, 18, 8, 5, -25, 16, -15, 16, -7, 9, -22, - 1, 14, -13, -5, 2, -6, -8, 13, -17, 6, -16, 1, -5, -14, -6, -6, - -15, -2, 9, -9, -18, 15, -19, 12, 7, 4, 8, 14, 15, 6, 10, -3, - 9, -7, 23, -17, 21, -20, 7, 0, -9, 8, -10, 1, 4, 2, 3, -9, - -9, -15, -6, -21, -16, -6, 0, -11, 19, -8, -9, 5, -6, 0, 5, 14, - 7, 1, 12, 8, 7, -5, 12, 8, -4, 19, 4, -7, 2, 3, -12, -8, - -1, 0, 5, 7, -5, -8, -22, -8, -21, -2, -9, 10, -20, 13, -6, 8, - -17, -9, -6, 2, 5, 8, 6, -3, 10, -9, -2, 15, -6, 20, 7, 11, - 10, -3, -4, -8, 25, -25, 18, -12, 17, -6, 20, -22, -1, -17, -10, 5, - -10, 9, -13, -9, -6, 10, -25, -5, -2, -5, 13, 2, -5, -8, -10, 11, - -27, 10, -4, 11, 0, 33, -4, 10, -14, 1, 12, -2, 27, -8, 6, 11, - 9, -12, -4, -10, -13, 12, 5, 1, -10, -14, -15, -8, -7, -9, 3, -5, - 10, 3, -11, -12, -13, -3, -3, 3, 2, 9, 17, -6, 25, -3, -3, -8, - 19, 3, 30, -10, 12, -22, 7, -5, -10, -3, 21, -8, 12, 6, -5, -13, - -13, -9, -9, -1, -23, 13, -17, 15, -22, -11, -18, 8, -14, 20, 1, 4, - -5, 3, 3, 5, 11, 1, 2, 27, 1, 10, -7, -8, -2, -2, 7, -1, - 17, -5, 24, -7, 5, -10, -20, -6, 5, -4, -5, -1, -18, -5, -14, -1, - -20, 1, 7, -7, 12, -4, -2, -4, 2, 8, 0, 7, 1, 6, -2, 18, - -5, -7, 4, 3, -2, 13, 4, 0, 2, -3, 2, -10, -6, 1, -6, 6, - -7, -3, -21, -2, -12, 5, -1, -9, 7, -3, 13, 5, 5, -8, 0, -8, - 19, -5, 13, 13, -7, 3, 0, -10, 0, -8, 20, -8, 13, -20, -5, -7, - 3, 5, -7, 2, -5, -4, -14, 11, -23, -13, 2, -1, 12, 13, 5, -6, - 23, -9, 9, -6, -9, 18, -13, 16, -3, -7, -17, 3, -13, 12, -9, 4, - 0, 0, 13, -18, -1, 3, -13, 20, -5, 1, -20, 15, -23, 18, -4, -8, - 5, -7, 16, 4, 6, -3, 7, -21, 19, -17, -7, 9, 5, 3, -5, -3, - -16, -9, 25, -9, 12, -5, 10, -5, 9, -4, -6, -3, 4, 10, -2, 11, - -12, -2, -14, 8, -23, -5, 0, -8, 9, -2, -11, -3, -9, 9, 2, 2, - 4, -5, 7, 11, -16, 0, -6, 7, 6, 25, 5, 6, -4, 3, 4, 3, - 2, -8, -3, 5, -1, -11, -4, -9, -3, -15, 10, -12, -5, 11, -4, -7, - 6, -29, -5, 6, 11, 3, 9, -18, 13, -14, 19, -1, -2, 4, 5, 12, - 1, 5, -8, 3, 1, 20, -6, 2, 3, -16, 10, -10, -18, -11, -7, -7, - 9, -4, -8, 9, -15, 13, -13, -3, -7, 3, 8, 11, -6, -16, 1, -8, - 20, 4, 15, -5, -3, 11, -5, 6, 0, -5, 10, 13, 0, -6, -11, 0, - 11, -11, 10, -7, -8, 1, 16, -9, 2, -22, -9, 0, 4, 5, -12, -22, - 2, -8, -8, 14, -16, 0, 13, 0, 9, -7, 2, -1, 7, 8, -3, -3, - 2, 15, 5, 10, -7, 12, -4, 22, -4, -3, -12, -2, -15, 8, -2, -22, - 7, -10, 5, 12, -20, -9, -11, -2, -12, 2, -9, 5, -3, 11, 7, -9, - 4, -4, 24, -7, 21, -15, -3, 2, 14, -1, 5, 18, -12, 13, 3, 5, - -10, -11, 0, -8, -2, -4, 2, -15, 9, -10, -16, -9, -7, 0, -1, 3, - -8, -10, 5, -8, 4, -3, 8, -2, 20, 1, 6, -4, -9, 4, 14, 7, - -1, 3, -5, 18, -7, 20, -6, -10, 8, 1, -2, 3, -4, -5, -3, -6, - 0, -16, -7, 12, 0, -17, 4, -31, -7, 1, 1, -4, 8, -11, 6, -1, - 11, -5, -7, -4, 2, 4, 15, -3, 21, -5, 20, 3, -12, 21, -1, 10, - 5, 6, -20, -1, -18, 2, 3, -4, -5, -1, 6, -2, -11, -17, -15, -13, - 0, 6, -18, 7, -18, 7, -7, 6, 7, -10, 18, 16, 2, -1, 3, -11, - 6, 14, 1, 15, -2, 29, -8, 17, -14, 2, -19, 12, 8, -6, -1, -23, - 6, -11, 7, -19, -18, 0, 1, -8, -8, -4, -20, 8, -8, 4, 10, -12, - 13, 0, 18, -10, -3, -4, 6, 4, 17, 7, -2, 18, -9, 14, -10, -4, - -11, 4, 3, 23, -17, -6, -2, -7, -7, 9, -10, 1, 2, -4, -14, -7, - -6, -8, -4, 7, 2, -3, 3, 0, 13, -10, -4, -9, -6, 18, 11, -4, - 16, -8, -4, 1, -1, 7, 3, 3, 3, 10, -15, -2, -9, 9, 0, 2, - 2, -9, 12, -7, 0, -23, -7, -19, 2, -1, 0, 4, -15, 7, 3, -3, - 0, 9, -12, 19, 4, 8, -13, -6, 5, -1, 14, 10, 9, 13, -3, 16, - -18, 13, -18, 7, -10, 13, -6, -11, -3, 7, -23, -6, -11, -21, 9, -1, - 4, -3, -16, 0, -12, 7, 14, -5, 15, 0, 6, -5, -3, -9, 9, 4, - 10, 4, -2, -7, 10, -1, 10, -6, -14, 15, -4, 13, -4, -4, -14, 5, - -2, 4, -9, 3, -14, 2, 3, -10, -1, -9, 0, 3, -6, 12, -16, 0, - 4, 10, -25, 6, -5, 2, 8, 3, -2, -4, 15, 4, 7, 2, -1, -6, - 10, 11, 2, -2, -14, 6, -3, 0, -3, -9, -10, 1, -1, -15, 9, -29, - 9, -10, 7, -3, -3, -10, -2, 14, 4, -6, 0, 1, 12, 4, 18, -15, - 19, 1, 15, 1, 1, 3, -10, 8, -1, 7, -30, 8, -19, -2, -5, -9, - -10, 0, -1, 6, -4, -12, 1, -18, 10, -1, -12, 2, 7, 12, 11, 0, - -4, -1, 6, 10, 17, -8, 1, -12, 5, -2, 1, -7, -1, 4, 3, -3, - -1, -18, 8, -9, 0, -2, 8, -12, 12, 7, -5, -2, -16, -7, 9, -5, - 11, -9, -4, 3, 1, -9, -1, -2, -6, 7, 12, 0, -8, 9, -10, 3, - 0, 2, -3, 11, 14, 4, 3, -12, 3, -3, 2, 12, -4, -2, -2, 9, - -21, -5, -28, -6, -10, 6, 7, -6, -3, -24, 7, -11, 10, 0, 8, 13, - 10, 6, -7, -2, -5, 7, -1, 9, 18, -2, 12, -4, 7, -26, 13, -6, - 19, 6, 6, -5, -16, -6, -8, -18, -2, 1, -11, 3, 4, -16, -8, -10, - -3, 2, -3, 5, 5, 0, 11, 0, -14, 0, 1, 14, 11, 13, 0, -2, - 5, -1, -4, -2, -4, 5, 21, 3, 14, -5, -22, 5, -11, -3, -6, -3, - -11, 0, -5, -13, -10, -18, 3, 9, -10, 2, 3, -11, 11, -11, 5, -19, - 23, -1, 20, 18, 4, -3, -6, 9, 4, -3, 8, 4, 6, 2, 5, -14, - -6, -3, 2, -6, -4, -3, -11, 0, -5, 0, -21, -2, -10, 11, 5, -4, - -5, -5, -8, 10, -10, 4, -1, 6, 12, 9, 2, 8, -20, 8, -2, 11, - -11, 1, -4, 5, 6, -6, 6, -14, 14, 4, -2, 12, -3, -10, 8, -5, - -15, -9, -1, 5, 8, -3, 0, -23, -9, -11, 4, -12, 3, -4, 4, 1, - 15, -12, 3, 13, 2, 5, 8, -8, 7, 11, -3, 17, -11, 5, 3, 19, - 13, 3, -11, -11, -2, -9, -7, -4, -24, -1, -17, -3, -17, 0, -15, 2, - -1, -5, -4, 3, 2, 2, 11, -4, 3, -6, 11, 8, 3, 6, 3, 7, - 7, 6, -6, 2, 0, 14, 14, 3, 8, -6, 4, -3, 6, -13, -2, -9, - -4, 5, -13, -5, -21, -1, -6, -1, -5, -14, 8, -7, 5, -7, -17, -11, - 7, 3, 20, 7, 1, -3, 4, 5, 14, -3, 5, 3, 10, 8, 6, -6, - -2, 6, 3, 7, -6, -3, -3, -6, -1, -27, -11, -17, 0, 11, 7, 1, - -7, -9, -13, 5, -11, 0, -10, 15, 2, 5, -2, -5, 1, 6, 6, -6, - -5, 6, 2, 5, 3, 10, -16, 11, 8, 18, 3, 13, -11, 7, 5, -7, - -6, -20, 15, -1, 10, -1, -13, -17, -11, -3, -13, -4, -14, -3, -2, -6, - 6, -28, 9, -8, 10, 0, 12, -2, 10, 9, 1, 3, -6, 5, 17, 24, - 18, 3, 4, -9, -4, 2, -8, -4, -2, -11, 1, -8, -12, -9, -10, 5, - 0, -7, -9, 7, -18, 6, -10, -12, -1, -1, 13, 1, 18, 2, -3, 4, - 3, 3, -3, 3, 10, 9, 7, 5, -8, -7, 0, 3, -7, 7, -2, -2, - 5, -10, 2, -5, -3, -1, 4, 1, -2, -10, 4, -9, -5, -12, -18, 3, - 6, -3, 3, -15, -1, -13, 6, -2, 8, 0, 8, 16, -2, 17, -4, 8, - 3, 23, -1, 11, -8, 10, -4, -5, -3, -13, -2, -1, -2, 2, -9, -13, - -13, -2, -11, -2, -20, -5, 0, 3, 2, -1, -10, 1, 8, 3, 9, 6, - 4, -3, 13, 3, 4, 11, 2, 11, 8, -2, -1, -2, -2, -2, -1, -21, - -1, -14, 8, 6, -8, -10, 2, -16, 4, -3, -1, -10, 7, -1, 4, -4, - -12, 3, -2, 13, 2, -3, -9, -2, 6, -7, 8, -8, -5, 12, 7, 8, - -3, 6, -1, 16, 0, 7, -8, 3, -7, -1, 0, -6, -4, -8, 6, -1, - 4, -19, 2, -3, -8, -3, -12, 4, -6, 2, -7, 1, -13, 2, 9, -1, - 17, -19, 3, -3, 23, 9, 6, 3, 6, 6, -5, 11, -11, 1, 0, -5, - 6, -6, -4, -5, -7, 3, -4, -14, -9, -7, -1, 5, -11, 4, -19, 14, - -4, 3, 4, 2, 0, 9, -2, -3, 2, -2, 10, 15, -3, 14, -6, -4, - 6, 1, -8, 11, -9, 4, 3, -9, 2, 2, -2, 2, -2, -9, -2, -2, - 1, -6, -6, -22, -16, -10, 12, 0, 5, -8, -2, -4, -2, 5, -1, 7, - 7, 9, 1, 7, 6, -1, 10, 11, 5, -3, 8, 1, -1, 8, -15, -6, - -10, 12, 0, 2, -5, -9, -12, -7, -4, -14, -4, 0, -1, 5, -7, -8, - -12, 0, 2, 16, -3, 11, -4, 16, 11, 2, -3, 2, 8, -1, 7, -13, - 4, -3, -1, 3, -10, -2, -11, 3, 2, 3, -7, -10, -5, -10, 12, -8, - 5, -7, 15, 1, -10, 7, -16, 1, 3, 4, -5, 7, -7, 4, -2, -1, - -8, 0, -2, 17, 10, -2, 6, -5, 3, 10, -7, 2, -3, 4, 5, 5, - -3, -8, -8, -1, 1, 7, -5, -11, -2, -10, -4, -15, -7, -10, -2, 2, - -4, -10, -8, 0, 2, 6, 3, 2, 3, 10, 14, 8, 7, 3, 5, -5, - 20, -6, -1, -2, 0, 1, -2, -2, -8, 3, -3, 10, -14, 3, -3, -2, - 0, -5, 0, -15, 4, -2, 0, 4, -7, 3, -8, 7, -14, -2, -6, 4, - 2, 3, -10, -2, 5, -3, 12, -2, -5, -9, 1, 4, 1, 11, -12, 15, - 5, 20, 10, -5, 1, 5, 3, -13, 6, -16, 5, 1, -5, -8, -3, -14, - -6, -2, -5, -8, -17, -9, 3, -6, -2, -3, -3, 1, 14, 2, 4, 5, - 3, 8, 7, 12, 0, 11, 4, 16, 2, -3, -9, -1, 1, -1, -3, -6, - -14, 4, -6, 2, -14, -9, -11, -1, 0, 0, -5, -6, -10, 5, -5, 2, - -3, 2, 2, 17, -2, -1, -3, 3, 11, 1, 10, 2, 7, 6, 5, -5, - -3, -3, -2, 7, 2, 1, -18, -5, -2, -3, -5, 0, -2, 0, 8, -9, - -10, -15, -7, -2, -1, 6, -8, 16, -10, 13, -4, 2, -4, 4, 7, 9, - 6, -5, -2, 8, -1, 11, -6, -1, 5, 8, 0, 9, -20, 0, -9, 4, - -3, 1, -4, -11, 2, -6, 0, -12, 0, 1, 5, -2, 1, -7, -4, 3, - -1, -10, 3, -3, 7, 4, 8, -9, -6, -10, 0, 0, 2, -4, 6, 9, - 10, 2, 0, -1, 2, 14, 3, 7, -7, 2, -2, -2, -6, -9, 2, -3, - 6, -3, -7, -9, -10, -2, 2, -1, -11, 2, 1, 7, -4, -7, -19, 3, - -1, 6, 6, 6, 6, 0, 6, 7, 3, -1, 3, 8, 3, 4, -10, -5, - -7, 5, -4, -14, 2, -8, 5, -2, 2, -16, -4, -11, 2, 4, -1, 2, - -1, 0, 5, 4, -12, 3, 9, 7, 13, -3, -7, 2, 6, -1, 7, -1, - -1, 5, -5, 7, -11, -9, -13, 2, 5, 2, -2, -7, 5, 4, -4, -2, - -15, -4, 3, 0, 0, -5, 2, -7, -1, 9, -2, -1, 5, 1, 1, -4, - -5, -4, 6, 8, 7, -5, 4, -7, 4, 0, 1, -6, -5, -2, 5, -1, - 0, 1, 1, 3, 9, -4, -2, -4, -9, -1, 4, -17, 1, -13, 11, -1, - 6, -9, -1, 5, 1, 8, -3, 4, -5, 1, 7, -5, 1, -3, 5, 3, - 4, -7, -11, -7, 1, 5, -13, 11, -11, 1, 3, 6, -9, 6, -5, -7, - 4, -13, 5, -7, 10, 5, 6, -15, -1, 6, 4, 18, -7, -7, -3, -4, - 2, -5, 3, -4, 9, -4, 3, 3, -3, -10, 0, -1, 2, 5, -3, 7, - 3, 2, -6, -11, -2, -1, 4, -5, 4, -5, 0, -5, 5, -5, -4, 2, - 4, 2, 5, -8, -13, -3, 0, -1, -2, 4, 6, 9, 1, 3, -7, -1, - 1, 12, 1, 1, -1, -5, -1, 2, -8, -9, -7, -2, 3, 10, -6, -7, - -12, -7, -4, -5, 6, 0, 10, 5, 7, -4, -2, -8, 10, 5, 9, 4, - -1, -1, -1, -1, -1, -2, -3, 3, 9, -2, 9, -14, -13, -8, -10, 1, - 1, 3, 3, 1, -3, -12, -5, -7, 1, 6, 6, -2, -7, -3, -3, 2, - 2, 4, -9, 14, 8, 11, -3, 5, -11, 1, -1, 5, 3, 8, 2, 8, - -2, -6, -13, -10, 0, 4, 3, 4, -3, -9, 1, -5, -5, -6, 1, -2, - 2, -10, -6, -15, 1, -5, 4, -1, 2, 2, 4, 10, 4, 2, -13, 0, - 4, 8, 17, 2, 5, 4, 2, -6, 5, -5, 0, 8, -2, -1, -5, -4, - -5, -1, -5, -4, -5, 0, 0, 1, -9, -15, -3, -12, 1, -1, -7, 10, - 2, 5, -1, 2, -6, 2, 2, 10, 10, -1, 2, -2, 4, 5, 0, -6, - 12, 5, 3, -1, -8, -8, -4, -4, 3, -11, 0, -1, -1, 0, -2, -14, - -6, -9, 2, 1, 7, -4, 3, -1, 0, -3, 1, 2, 7, 5, 4, 3, - -2, -3, 1, 6, -1, 6, -11, 7, 2, -6, 2, -4, 0, 2, 3, -7, - -9, 3, 0, 4, -6, 0, -21, 0, -5, -1, 0, -1, 1, -6, -1, -1, - 0, -7, 5, 7, -2, 8, -4, -1, 3, 9, -6, 10, -6, 7, 9, 10, - 9, -6, 5, -14, 6, -5, 1, 2, -3, 0, -9, -10, -14, -2, -3, 6, - -8, -15, 3, -9, 0, -3, 0, -6, -1, 3, 9, 10, 3, 3, -10, 6, - 1, 3, -1, 9, 12, 4, 4, -9, -7, -5, 8, 6, 1, 1, -4, -5, - -5, -1, -11, -3, -4, 1, -1, 1, -10, -7, -2, -3, -4, -3, -6, 11, - 5, 3, 2, -8, -5, -2, 3, 9, 13, 5, 4, 4, 0, -5, -1, -5, - 9, 2, 3, -9, -4, 3, -6, 2, 1, -9, 5, -2, 3, -2, -9, -8, - -15, -5, -3, 3, -13, 11, 6, -3, 1, -6, -6, -1, 6, 4, 6, 7, - 1, 5, 0, 8, -6, 7, 2, 6, 2, -5, 0, -3, -1, 3, -7, -1, - -3, 5, 7, 6, -18, -10, -11, -7, -3, 10, -4, 3, -4, -8, -5, -12, - -3, -4, 12, 10, 2, -4, 6, 3, 1, 2, 0, -3, 3, 7, 7, -5, - 2, -4, 1, 3, 11, 2, 3, 4, -2, -7, -5, -17, -11, 4, -3, 5, - -7, -7, -6, -1, -8, -5, -5, 1, 7, 1, 2, -1, -9, 7, 1, 7, - 3, 3, 6, 9, 6, 1, -6, -4, 2, 5, 7, 4, -2, 1, 3, -11, - -1, -16, -2, -6, 1, 3, -8, -15, -11, 4, -1, 9, -2, -5, 0, 6, - 0, -7, 0, -8, 4, 2, 6, 2, 0, 2, 6, 2, -2, 4, -2, 4, - 14, 2, 2, -6, -6, -3, 4, -4, -1, -4, 1, -3, -6, -1, -13, -1, - -2, 7, -8, -7, -10, 0, 4, 3, -8, -3, 1, 4, 6, 4, 6, -3, - 5, 3, 4, 0, 6, 1, 4, 7, -3, -10, 8, -1, 9, -1, 1, -11, - -7, -3, -3, -6, -8, -9, -6, 1, -3, -6, -6, -5, 0, 0, 2, -3, - 0, 6, 4, 3, 2, 7, 4, 11, 14, 5, -1, -5, 1, -2, 7, 3, - 0, 1, 2, -5, -7, -10, -12, -10, -5, -5, -6, -6, -9, 1, -8, -2, - -1, -9, 1, 8, 2, -5, -2, -5, 0, 5, 6, 6, 7, 8, 10, 2, - 0, -3, -1, 2, 13, 3, 0, -6, 0, 1, -3, 0, -12, -2, 4, -4, - 4, -8, -11, -1, -2, 1, -1, 2, -12, 3, -6, 1, -12, -7, -7, 3, - 0, 9, 0, 1, 6, 1, -1, 2, 1, 2, 8, 9, -3, -1, 0, 7, - 3, 8, -1, -4, -1, 1, 3, -9, -1, -17, -3, -2, -4, -4, -3, -4, - -6, -11, -15, -2, -5, 6, 10, 1, 3, -1, -3, 13, 7, 1, 6, 4, - 4, 9, 5, -3, -5, 9, 3, 5, -3, 1, -3, 3, 0, -7, -5, -7, - 0, -5, 0, -1, -15, -11, -4, -5, -10, 2, -7, 5, -4, 1, -9, 2, - 1, 8, 7, 10, 2, 2, 0, 4, 3, -2, 0, 4, 2, 6, 8, -2, - 4, 4, -2, 5, -3, -6, 3, -3, -5, -9, -8, -11, -5, -1, -1, -5, - -7, -5, -8, 0, -3, 5, -7, 11, 1, 0, 2, -3, -1, 3, 9, 6, - -3, 8, 1, 11, 2, 8, -3, -3, 6, 2, 1, 2, -7, -3, -2, -4, - -8, -3, -3, 5, -10, -10, -4, -12, -2, 3, -5, 3, -6, -8, -2, 5, - -3, 0, 1, 4, 8, 4, 5, 0, 4, 8, 1, 7, -3, 0, 3, 4, - 4, -5, -2, -7, -3, 0, 5, -5, -9, 3, -2, -1, -2, -5, -1, -4, - -3, -11, -4, -5, -6, 0, 5, 0, -5, 5, 3, 8, -1, 3, 3, 2, - 5, 7, -4, 3, 1, 3, 10, 2, -7, 1, 0, 6, -4, -3, -5, -7, - -2, -4, -3, -6, 0, -10, 4, -6, -4, -7, -2, 1, -4, -1, -3, -1, - 2, 6, 2, 4, -2, 2, 4, 2, 5, -3, 4, 2, 1, 0, 8, -3, - 2, 5, -5, 3, -5, -2, 5, -5, 3, -1, -4, -3, 4, -10, -5, -7, - -4, -4, 0, 0, -7, -1, -1, 2, 1, -2, -12, -4, -1, 0, 4, -5, - 2, 0, 3, 12, 11, 3, 11, -1, -3, 6, -6, 1, 1, 7, 6, -7, - -1, -7, -4, -4, -7, -8, -1, -6, -6, -2, -3, -5, 0, -4, 8, -7, - 1, 4, -3, 6, 1, -7, 3, 5, 6, 5, 13, 2, 2, -4, 4, -3, - 1, 4, -4, 2, -3, -10, -10, -7, -2, -2, -2, 0, -6, -2, 1, -3, - -4, -2, -5, -2, 7, 1, 6, -5, 6, -1, -1, 2, -3, 4, 11, 2, - -1, 2, -7, -5, 8, 0, 3, -3, -5, -1, -2, 3, 1, -4, 4, 7, - 0, 2, 3, -3, 0, 1, -5, -15, -5, -3, 1, 3, -3, -11, -4, -7, - 1, -2, -1, -1, 0, 1, 1, -5, -1, 3, -2, 7, 1, -4, -1, 0, - 4, 5, 3, 3, -1, 8, 11, 1, 4, 1, -5, 7, -6, -4, -2, -4, - -2, 3, -8, -3, -13, -6, 3, -3, -7, -4, -7, 3, 3, -3, 2, -1, - 1, -4, -2, -2, -5, 1, 11, 9, -2, 6, -3, 7, 7, 1, 1, -7, - 2, -3, 1, 4, -4, -4, 5, 1, 0, -3, -6, 2, -3, 0, -8, -12, - -6, -2, -3, 6, -1, -9, 0, -1, 1, 3, -2, -1, 0, 1, 6, 0, - -3, 5, 1, 6, 1, -1, 4, 1, 7, -3, -1, -1, -4, 4, 14, -1, - -1, 2, -4, -1, -6, -8, -8, -3, -2, 2, -9, -5, -7, -12, 5, 0, - -3, -4, -3, 5, 4, 3, -2, -6, 4, 7, 3, 5, 7, -3, 8, 0, - -5, -1, -1, 11, 10, 3, 4, -8, -3, -3, 1, -3, 0, -4, -3, 1, - -7, -8, -16, -7, -6, -2, 3, -7, -2, 1, -4, 0, -5, -5, 1, 5, - 10, 5, 0, 3, 0, 1, 13, 0, 5, 9, 6, 8, -1, -4, 0, -3, - 6, 4, -4, 0, -3, -15, -2, -12, -15, -3, -6, 2, 1, -3, -4, -9, - -9, -3, -3, -2, 3, 4, 9, 0, 2, 1, 2, 14, 5, 3, 8, 2, - 7, 4, -4, -4, -1, -9, 9, -5, -1, -7, -10, -2, -7, -4, 0, -5, - 2, 5, 1, 0, -5, -5, -1, -1, -3, 4, -8, 5, 3, -4, 4, -5, - -3, 9, 4, 8, 0, 0, 2, 0, -2, 0, -2, -7, 12, -1, 5, -4, - 2, -3, 0, 2, -2, -4, -2, 2, -5, 3, -7, -9, -4, -3, -2, -6, - -6, -2, -6, -1, -7, -8, 1, 3, 6, 10, 4, 5, 0, 5, 8, 1, - 3, 8, 5, 11, 12, -7, 4, 0, -3, 2, -1, -8, -7, -4, -2, -6, - -9, -6, -13, -4, -1, 0, -9, -5, -3, -4, -2, 3, 1, 1, 9, 4, - 2, 6, -1, 3, 6, 2, 0, -3, 3, 2, 6, 3, -1, -4, 4, 1, - 2, 2, -5, -8, -1, -3, -1, -9, -4, 1, -5, 5, -7, -4, 0, 3, - -10, 3, -3, -5, 1, 5, 4, 1, -5, 1, -5, 4, 1, -6, 0, 5, - 8, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, -10, -6, -8, - -2, -1, -3, -6, -6, -5, -6, -6, -5, 5, -3, 5, 6, -2, -1, -1, - -4, 6, -2, 6, 6, 2, 12, 8, -2, 3, -6, -2, 5, 4, -3, -2, - -5, -4, -7, -6, 1, -5, 2, 2, 0, 1, -7, 0, -4, -2, -1, -2, - -5, 7, -5, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, -5, -3, -4, - -4, 4, 3, 6, 1, -2, -2, -7, 4, 1, 1, -3, 3, -1, 2, 0, - -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, -1, 5, 5, - 2, 2, -3, 4, 3, 4, 6, 3, -1, 10, -4, -3, -2, -3, 0, -4, - 0, -2, -2, 0, 2, -5, -2, -5, -9, 8, -2, -1, -1, -3, -3, -2, - -6, 2, 1, 2, 9, 0, 1, 4, -5, 2, 4, -6, -1, 2, -1, 6, - 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, -2, 0, 3, - 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, -6, -1, -3, - 2, 4, 1, -1, 0, 1, 1, 3, -1, 5, -1, 7, 6, 1, -2, 0, - -6, -2, -2, -8, -2, -2, -3, -5, -5, -8, -3, -1, 5, -3, 1, 2, - 1, 2, -3, -2, -3, 2, 6, 2, 6, 0, 0, -2, 9, -1, 3, -2, - 3, 0, 0, 0, -6, -6, -1, -5, -7, 1, -3, -6, 2, -2, -1, -5, - -2, 1, 4, 2, 2, -3, -1, 6, -2, 2, 4, -3, 2, 2, 2, -3, - 1, 0, -4, 2, -1, -2, 3, 1, 1, -1, -5, -8, -2, -5, 0, 1, - -6, 3, -4, 2, 3, -6, 3, 0, 2, -2, -1, -4, -2, -4, 4, 0, - -3, 0, -6, -3, 10, -3, 3, 0, 4, 7, 3, 0, 5, 1, 5, 1, - -3, -2, 0, -6, 3, -1, -7, -5, -7, -1, -2, -2, -2, -3, -2, 2, - -2, -1, -3, -3, 2, -2, -6, -3, -3, 4, 3, 2, 0, -1, 5, 5, - 8, 2, 2, -2, 4, 0, 5, -5, -3, -1, -3, -3, -6, -4, -2, 3, - 0, -2, -2, -5, 5, -1, 3, -1, -1, -3, 0, 0, -5, -4, -3, -2, - 5, 0, -4, -4, 1, 2, 6, 0, -3, -1, 2, 3, 7, -3, 0, -4, - -2, 4, 3, 0, 1, 3, -3, 1, -7, -4, 0, 1, 1, -4, -4, -4, - -9, -1, -2, -3, -2, -3, -3, 4, 3, -1, -4, 2, 4, 4, 3, 2, - -1, 0, 9, -1, 4, 2, 7, -1, 6, -2, -2, -5, -1, -9, -2, -2, - -6, -1, -1, 1, -8, -6, -5, -1, -1, 1, -4, -5, 3, 1, 5, 3, - -3, 0, -2, 7, 0, 1, -2, 3, -1, 5, -1, -5, 7, -1, 3, 2, - -5, -6, -2, 4, 2, -1, -3, -1, -1, -1, -1, -2, -4, 1, -5, 3, - -1, -3, -5, 2, 6, -6, -1, -5, -4, 4, -1, -1, -2, -1, 2, 0, - 3, 1, 4, 2, 7, -1, 2, 0, -2, 1, 4, -5, -3, -7, -2, 0, - -1, -1, -3, 0, 0, -2, -6, 2, -4, 2, -4, 1, -7, -2, -1, 5, - 3, -2, -7, -4, 1, 6, 4, 5, 1, 4, 0, 5, 1, -1, 2, 0, - -3, -3, -5, -6, 3, -1, 5, -1, -2, 1, 1, 4, 2, -6, -3, -4, - -3, 2, -2, -8, -3, -6, -4, -2, -11, 0, 0, 1, 6, -3, -2, 1, - 2, 10, 8, 4, -2, -1, 2, 2, 1, -2, 3, 1, 5, 3, -1, 0, - -4, 4, -7, -2, -7, -8, -4, -3, -2, -7, -7, -3, -1, 5, -2, 0, - -7, 2, -1, 3, 1, 4, 6, 5, 8, 3, 2, -1, 3, -3, 0, 0, - -5, -1, 1, 1, -5, -3, -2, 6, 4, 5, -4, -8, -4, -3, -2, -5, - -4, -4, -4, 2, -3, -2, -4, -4, -4, 6, 1, 0, 1, 3, 3, 5, - 2, 1, 0, 6, 2, -1, 1, -3, -3, 2, -1, 0, 1, 3, 1, 4, - -4, -5, -10, -8, 1, -6, -3, -4, -6, -3, 0, 2, -3, -1, 2, 0, - 8, 1, 4, 4, 3, 6, 3, 1, 3, 5, 1, 2, -4, -7, -3, -3, - 3, 0, -7, -5, 0, -3, -1, -2, -4, 0, -5, 1, -6, -1, -5, -3, - 1, 4, -1, -3, 3, 3, 5, -1, -2, 2, -1, 2, 1, -1, -5, 5, - 1, 2, 2, -4, 0, -1, 3, 0, -2, -1, 2, 1, 5, 4, -3, -5, - 0, -2, -2, -6, -3, -3, -4, -1, -5, -4, -1, -2, 0, 2, -2, -6, - -3, 1, 1, 1, -1, 3, 4, 7, 2, 3, 4, -1, 7, 2, 3, 1, - -1, 1, -2, 0, -4, -5, -6, 0, -2, -7, -2, -5, -5, 1, -4, -5, - -5, 3, -1, 1, 2, -2, 0, 1, 4, 1, -4, 2, 2, 0, 9, 2, - 0, 4, 3, 1, 2, -4, -2, -4, 3, -4, -2, -6, 0, -1, 5, 2, - -4, 0, -4, -4, -1, -5, -4, -7, -3, 1, 0, -2, -1, -5, 1, 0, - -1, 0, 2, 4, 0, 3, -2, 1, 2, 6, 0, 1, 5, 0, 3, 3, - 2, -5, -2, 1, 5, 2, -2, -5, -9, 0, -6, -1, -6, -7, -5, -4, - 0, -2, -5, -3, 2, -2, 3, 2, 0, 9, 2, 0, 4, -3, 4, 5, - 8, 6, -2, -4, -1, 0, -2, -2, 1, -5, 2, -5, -1, -4, -3, -4, - 0, -2, -7, -3, -1, 0, -1, 0, -6, 3, -2, 5, 2, -1, -2, 1, - 0, 1, -1, -3, 2, 3, 1, 2, -4, -3, -1, 5, 5, 3, -4, 0, - 1, 2, 5, -5, 1, -5, 2, -2, 2, -4, -3, 0, -4, -3, -9, -7, - -4, 2, -2, 1, -6, -3, 0, 1, 5, 1, -5, 0, 0, 2, 1, 2, - 0, 6, 4, 6, 3, 2, 3, 1, -2, -2, -9, -4, -1, 4, 0, -1, - -5, -8, -5, -4, 0, -4, -1, -3, 0, 0, -4, -3, -1, 1, 2, 0, - -2, -3, 1, 3, 2, 3, 3, 0, 8, 2, 7, -1, 3, -2, 4, 0, - 0, 1, -4, 5, -1, -3, -3, -6, -4, 2, 1, -5, -4, -7, -4, -4, - -7, -2, -10, 1, 0, 1, -3, 4, -2, 5, 2, 1, -3, -1, 2, 8, - 4, 5, 0, 1, 4, 5, 2, 2, -2, 1, -4, 0, -3, -3, -1, 0, - 2, -4, -4, -5, -1, -7, 0, -4, -5, -1, -3, 2, -2, 0, 3, 0, - 2, 0, 1, -2, 2, 4, -1, 0, -3, -1, 1, 3, 2, -3, 2, 0, - 2, 2, -1, 2, -2, -3, 0, 0, -2, 2, -2, 4, -3, -6, -7, -6, - 2, -1, -4, -1, -7, -1, -3, 3, -1, 0, -2, 2, 2, -3, 3, -4, - 5, 7, 6, 3, 1, -1, 6, 2, 1, 0, -1, -1, 1, -3, 1, -3, - -5, -5, -3, -8, -3, -11, -1, -1, 0, -8, -2, -5, 3, 4, 0, 1, - -2, 2, 0, 6, 4, 1, 4, 1, 5, 0, 0, 1, 2, 5, 0, 1, - -10, 0, -5, 2, 0, -6, -6, -2, -2, 2, -3, 0, -4, 2, -4, 1, - -3, -4, 1, -2, 2, 1, -2, 0, 3, 2, -3, -1, -5, -3, 4, 2, - 3, -1, 4, 1, 5, -1, 2, -3, 2, -3, 0, -3, -2, 1, 1, 5, - 1, -2, -5, 1, -1, -4, -3, -7, 0, -5, -4, -4, 0, -4, 4, 0, - -1, 1, -8, 1, 0, 9, 1, 2, -2, 5, 5, 1, 6, -1, 6, 3, - 1, 1, -2, -2, -4, -3, -2, -3, -7, -4, -4, -1, -3, -8, -1, -8, - 4, -5, 0, -3, 1, 0, 4, -1, 0, 1, 3, 3, 4, -4, 6, -2, - 2, 5, 4, -3, 4, -3, 5, 0, -4, 0, 0, -1, 0, -4, -4, 3, - -1, -2, -4, -8, -9, -5, -4, 4, -4, 1, -4, 1, 1, -1, -1, -1, - 3, 2, 3, 0, 1, 2, 1, 5, 3, 1, 0, 5, 3, 3, 0, -5, - -4, -2, 5, 0, -2, -5, -2, -6, -2, -5, -8, -2, 1, -1, -3, -7, - -8, -6, 0, 4, 7, -2, 7, -1, 7, 3, 2, -5, 0, 2, 0, 1, - -3, 2, 2, 3, 3, -3, 0, -2, 3, -1, -1, -4, -6, -2, -3, 4, - -4, 0, -4, 6, -2, -6, -2, -7, 1, 2, -1, -3, -2, -2, 3, -1, - 0, -3, -1, 4, 7, 4, 0, 2, -1, 0, 6, -2, 1, 1, 5, 4, - 1, -3, -3, -2, 2, 2, 1, -6, -6, -3, -4, -2, -6, -5, -4, -5, - -2, -8, -8, -3, 0, 4, 0, 1, -1, 2, 5, 4, 2, 2, 3, 3, - 4, 10, 0, 2, 0, 3, 1, 1, 0, -3, 1, -3, 1, -7, 0, 1, - -2, 1, -6, -4, -10, -1, -4, -2, -2, -3, 2, -4, 1, -5, -4, -4, - 2, 1, 1, -4, -1, 3, 1, 6, 2, -2, -2, 3, 3, 2, 7, -5, - 5, 0, 8, 1, -1, 2, 3, -1, -6, 0, -10, 3, -1, -1, -5, -6, - -8, -2, 0, -3, -5, -8, -4, 2, -3, -1, -2, 0, -1, 7, -1, 3, - 2, 4, 7, 3, 4, -1, 5, 1, 9, 1, -2, -1, -1, 1, -3, -2, - -6, -7, 1, -3, -1, -9, -4, -6, 0, 2, -3, -2, -4, -3, 0, -4, - -1, -4, 0, 1, 6, -1, 1, -1, 3, 5, -1, 3, 4, 5, 7, 4, - -2, 0, -2, 0, 3, 1, -1, -8, -2, -1, -2, -5, -1, -2, -2, 2, - -5, -7, -9, -2, -3, -2, 1, -5, 4, -4, 5, -1, -1, -3, 2, 3, - 7, 3, -1, 3, 4, -1, 5, -4, 0, 4, 4, 3, 4, -9, 1, -5, - 2, -2, -2, -3, -7, -1, -2, -2, -5, -3, -1, 1, -2, -1, -4, -4, - 1, -1, -7, 0, -1, 2, 5, 4, -4, -5, -4, 0, 2, 1, -1, 3, - 5, 4, 0, 0, -1, 3, 8, 3, 3, -4, 0, 1, 0, -2, -6, -2, - -4, 3, -2, -3, -5, -6, -3, -1, -1, -7, 0, 0, 3, -5, -4, -11, - 0, 0, 3, 3, 1, 1, 1, 4, 6, 1, 1, 2, 9, 3, 3, -4, - -4, -3, 2, -1, -6, 1, -5, 2, 0, -1, -8, -5, -6, 1, 0, -2, - -1, -2, -1, 2, 0, -9, 0, 5, 4, 7, -3, -3, 3, 4, 2, 4, - 0, -1, 3, 1, 5, -5, -6, -7, 0, 3, 0, -2, -4, 3, 3, -3, - -4, -7, -2, 4, 1, -1, -4, -1, -6, -2, 3, -2, -3, 1, 4, 1, - -1, -4, -3, 3, 4, 5, -2, 2, -3, 4, 0, 3, -3, -3, 0, 3, - 1, -2, -1, -3, 2, 4, -2, -2, -3, -1, -1, 3, -11, -2, -8, 5, - -1, 3, -5, -2, 2, -1, 3, -3, 0, -1, -1, 5, -2, 0, -2, 3, - 2, 3, -2, -6, -3, 2, 4, -6, 5, -6, 1, 2, 3, -6, 2, -3, - -4, 3, -9, 2, -6, 3, 4, 2, -9, -1, 1, 2, 8, -3, -4, -1, - -2, 2, -2, 2, -3, 3, -1, 1, 2, -1, -6, 1, 2, 2, 1, -2, - 2, 3, 1, -3, -6, -3, 0, 1, -3, 0, -3, -1, -4, 2, -4, -3, - -1, 4, 0, 5, -6, -7, -1, 0, 0, -3, -1, 2, 4, 0, 3, -4, - -1, 1, 7, 4, 2, -1, -4, 0, 2, -4, -5, -5, -1, 1, 4, -5, - -4, -6, -3, -2, -3, 2, -2, 5, 2, 3, -4, -2, -5, 6, 3, 4, - 2, -3, 1, 0, 0, 1, -3, -1, 1, 7, 0, 6, -6, -7, -2, -7, - 0, -1, 0, 2, 1, -2, -7, -2, -5, 0, 2, 0, -3, -5, -1, -3, - 0, -1, 0, -6, 8, 4, 5, -1, 1, -4, 1, 1, 4, 2, 5, 3, - 6, 0, -2, -9, -4, -1, 0, 0, 1, -1, -4, -1, -5, -5, -5, 0, - 0, 1, -6, -5, -9, 0, -3, 0, -2, 0, 0, 3, 4, 2, 1, -7, - 1, 3, 4, 9, 1, 4, 4, 2, -4, 2, -2, 1, 5, -2, 0, -3, - -4, -3, -2, -4, -4, -4, 1, -1, 2, -6, -8, -3, -8, -1, -2, -4, - 5, 2, 3, -1, 0, -4, 2, -1, 5, 5, -1, 3, 0, 3, 3, 0, - -4, 9, 4, 2, -1, -6, -4, -2, -2, 2, -7, 0, 0, -2, -2, -2, - -10, -4, -7, 0, -2, 2, -2, 2, 1, 0, -3, 0, 1, 6, 3, 2, - 0, 0, -1, 2, 3, -1, 4, -5, 6, 2, -3, 0, -3, 0, 1, 0, - -5, -6, 1, 0, 1, -5, -2, -14, 0, -4, -1, -1, -1, 1, -3, 0, - -2, -1, -4, 4, 5, -1, 5, -1, 3, 3, 5, -3, 5, -3, 5, 5, - 6, 4, -6, 2, -9, 4, -4, 0, 1, -2, -1, -8, -6, -11, -2, -3, - 3, -6, -8, 3, -5, 1, -3, 1, -3, 1, 3, 5, 6, 2, 1, -6, - 4, -1, 1, 0, 7, 7, 2, 3, -6, -4, -4, 3, 3, 0, 1, -1, - -2, -4, 0, -8, -2, -3, 1, -2, 1, -5, -2, -1, -3, -3, -4, -3, - 7, 4, 1, -1, -6, -5, -3, 2, 5, 8, 3, 3, 2, 1, -4, -1, - -2, 6, 3, 2, -4, -1, 1, -5, -1, -1, -5, 2, -2, 1, -2, -7, - -5, -11, -4, -3, 3, -8, 8, 4, -2, -2, -4, -4, -1, 4, 3, 5, - 5, 2, 4, -1, 6, -3, 6, 2, 3, 0, -4, 0, -2, -2, 0, -5, - -2, -1, 4, 3, 1, -13, -8, -8, -5, -3, 7, -2, 3, -2, -5, -3, - -8, -2, -3, 8, 6, 1, -2, 5, 3, 1, 2, 0, -1, 2, 4, 3, - -5, 1, -3, 0, 1, 7, 1, 2, 3, -1, -4, -4, -10, -7, 3, 0, - 2, -5, -5, -4, -1, -7, -3, -3, 1, 3, 0, 0, -1, -6, 6, 1, - 4, 1, 2, 5, 6, 4, -1, -4, -3, 1, 2, 5, 2, -1, 1, 3, - -8, -1, -10, -2, -5, 0, -1, -6, -10, -7, 2, -2, 6, -1, -2, 1, - 4, -1, -5, -1, -5, 4, 1, 4, 2, 1, 3, 4, 0, -2, 1, -1, - 3, 8, 2, 1, -4, -3, -3, 3, -3, -1, -4, 0, -4, -6, -2, -8, - 1, -2, 5, -6, -5, -6, 0, 3, 1, -6, -3, 1, 2, 4, 2, 4, - -2, 3, 3, 3, 1, 5, 1, 2, 3, -2, -6, 6, -1, 6, -2, 1, - -7, -5, -2, -3, -6, -6, -6, -4, 0, -2, -4, -4, -3, 0, -1, 1, - -3, -1, 3, 1, 1, 0, 6, 4, 8, 10, 5, 0, -3, 1, -2, 5, - 2, 1, 1, 1, -4, -6, -8, -8, -8, -5, -4, -5, -4, -5, 0, -5, - -3, 0, -7, 0, 4, 1, -4, -1, -4, -2, 4, 4, 5, 6, 6, 7, - 0, 0, -1, 0, 2, 9, 2, 1, -3, 0, 1, -3, 1, -9, -1, 3, - -4, 3, -6, -7, -2, -1, -1, -1, 1, -9, 2, -5, 1, -8, -6, -6, - 1, -1, 6, 0, 2, 5, 2, 0, 2, 1, 2, 6, 5, -2, -1, 0, - 4, 1, 6, 0, -2, 1, 0, 3, -7, -1, -13, -4, -3, -3, -3, -2, - -3, -5, -9, -11, -2, -3, 4, 7, -1, 2, 0, -2, 8, 5, 1, 4, - 3, 2, 7, 3, -2, -4, 7, 2, 3, -2, 1, -1, 2, 0, -5, -4, - -4, 0, -4, 0, -1, -10, -9, -3, -5, -8, 1, -5, 3, -3, 0, -7, - 1, 0, 5, 4, 7, 1, 1, 0, 2, 2, -2, -1, 2, 1, 4, 6, - -1, 4, 3, -1, 4, -2, -3, 3, -1, -2, -6, -6, -7, -3, -1, 0, - -4, -6, -5, -6, 0, -3, 3, -5, 7, 0, -1, 1, -3, -1, 1, 6, - 3, -3, 7, 1, 10, 1, 6, -1, -2, 5, 2, 1, 1, -4, -2, 0, - -3, -7, -2, -4, 4, -8, -8, -4, -10, -2, 2, -4, 1, -5, -7, -1, - 3, -1, 1, 1, 4, 6, 2, 2, 0, 4, 7, 0, 5, -2, 0, 3, - 3, 3, -3, -1, -5, -2, 0, 3, -4, -6, 2, -1, 0, -2, -4, 0, - -4, -3, -9, -3, -4, -4, 0, 3, -1, -4, 3, 1, 5, -2, 1, 2, - 2, 4, 5, -3, 2, 1, 3, 7, 1, -5, 1, 0, 5, -3, -2, -3, - -4, 0, -3, -2, -5, 0, -8, 3, -6, -4, -6, -2, 2, -4, -2, -3, - -2, 1, 4, 2, 3, -2, 2, 4, 1, 4, -2, 3, 2, 1, 1, 7, - -1, 2, 4, -4, 2, -4, -2, 5, -4, 3, -1, -3, -2, 3, -8, -4, - -6, -3, -3, -1, 0, -6, -1, 0, 1, 1, -2, -10, -3, -1, 0, 2, - -5, 1, 1, 2, 10, 8, 2, 8, -1, -2, 4, -5, 2, 2, 7, 6, - -6, -1, -5, -4, -3, -6, -7, 0, -5, -5, -1, -2, -5, 0, -4, 6, - -6, 0, 3, -3, 4, 0, -6, 2, 5, 5, 4, 10, 0, 2, -3, 3, - -2, 0, 3, -3, 2, -3, -8, -8, -5, -1, -1, -1, 0, -5, -2, 0, - -3, -4, -1, -5, -2, 5, 0, 5, -4, 4, -1, -1, 1, -3, 3, 9, - 2, -1, 1, -6, -3, 7, 1, 3, -2, -4, 0, -1, 3, 1, -3, 4, - 6, 0, 1, 2, -3, 0, 0, -5, -13, -4, -2, 1, 2, -3, -10, -4, - -7, 1, -2, -2, -1, 0, 1, 1, -4, -1, 2, -2, 7, 1, -3, 0, - 0, 4, 5, 2, 2, -1, 6, 9, 1, 3, 1, -5, 5, -6, -5, -2, - -4, -2, 2, -7, -4, -11, -5, 3, -3, -6, -4, -6, 3, 3, -3, 2, - 0, 1, -3, -1, -2, -4, 1, 10, 8, -2, 4, -3, 6, 6, 1, 0, - -7, 2, -2, 1, 3, -4, -4, 4, 1, 0, -2, -5, 2, -2, 0, -7, - -11, -5, -2, -2, 5, -1, -8, -1, -1, 1, 2, -2, -1, 1, 1, 5, - 0, -3, 5, 1, 6, 1, -1, 3, 1, 6, -3, -1, -1, -3, 4, 12, - -1, -1, 2, -4, -1, -6, -8, -7, -3, -2, 1, -9, -5, -6, -10, 5, - 1, -2, -3, -2, 5, 4, 3, -1, -5, 4, 6, 3, 4, 6, -2, 7, - 0, -4, -1, -1, 9, 8, 2, 2, -8, -3, -3, 0, -2, 0, -4, -2, - 0, -6, -7, -14, -6, -5, -1, 3, -6, -2, 1, -3, 0, -4, -5, 1, - 5, 9, 4, 0, 3, 0, 1, 12, 0, 4, 8, 5, 7, -1, -4, 0, - -3, 5, 4, -4, 0, -3, -13, -2, -10, -14, -3, -5, 2, 1, -3, -4, - -8, -8, -3, -2, -2, 3, 4, 8, 0, 2, 1, 2, 12, 5, 3, 8, - 2, 6, 3, -4, -4, -2, -8, 8, -5, -2, -6, -10, -2, -6, -4, 0, - -4, 2, 5, 1, 0, -4, -4, -1, -1, -3, 4, -7, 4, 3, -3, 4, - -4, -3, 8, 4, 7, 0, 0, 2, -1, -2, -1, -2, -7, 11, -1, 5, - -4, 2, -2, 0, 2, -2, -4, -2, 1, -5, 3, -6, -9, -3, -3, -2, - -5, -5, -2, -6, -2, -7, -8, 1, 3, 5, 9, 4, 4, 0, 5, 8, - 1, 3, 7, 5, 10, 11, -7, 3, 0, -3, 1, -1, -7, -7, -3, -2, - -6, -9, -6, -12, -4, -1, 0, -8, -5, -3, -3, -2, 3, 1, 1, 9, - 4, 2, 5, -1, 2, 6, 2, 0, -3, 2, 2, 5, 2, -1, -4, 4, - 1, 1, 2, -5, -8, -1, -3, -1, -9, -4, 1, -4, 5, -6, -4, 0, - 3, -9, 3, -3, -5, 1, 4, 4, 1, -4, 1, -4, 4, 1, -6, 0, - 5, 7, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, -9, -6, - -7, -2, -1, -3, -5, -6, -5, -5, -6, -5, 4, -3, 5, 5, -2, -1, - -1, -3, 6, -2, 5, 6, 2, 11, 8, -1, 3, -6, -2, 5, 4, -3, - -3, -5, -3, -7, -5, 0, -5, 2, 1, 0, 1, -7, 0, -3, -2, -1, - -2, -5, 7, -4, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, -5, -3, - -4, -4, 4, 3, 6, 0, -2, -2, -6, 4, 1, 1, -3, 3, -1, 2, - 0, -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, -1, 5, - 5, 2, 2, -3, 4, 3, 3, 6, 3, -1, 10, -4, -3, -2, -3, 0, - -4, 0, -2, -2, 0, 1, -4, -2, -5, -9, 8, -2, -1, -1, -3, -3, - -2, -6, 2, 1, 2, 9, 0, 1, 3, -4, 2, 4, -6, -1, 2, -1, - 6, 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, -2, 0, - 3, 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, -6, -1, - -3, 2, 11, 11, -28, -10, 54, -53, 2, 43, -37, 0, 43, -48, 7, 11, - -18, 19, -33, 32, -1, -7, -6, 19, -21, 23, -38, 0, 54, -49, 0, 15, - 20, -28, -20, 53, -28, -48, 70, -6, -60, 51, 5, -32, 1, 31, -10, -33, - 24, 33, -68, 21, 50, -67, -1, 57, -28, -21, 26, 15, -48, 9, 33, -32, - -3, 23, -10, 5, -4, -10, 24, -42, 29, -13, 0, 26, -15, -26, 46, -17, - -38, 45, -26, 8, -1, 4, -5, -3, 15, -27, -2, 39, -37, -25, 74, -33, - -25, 16, 24, -26, -25, 46, 10, -74, 50, 33, -80, 37, 32, -51, 13, 26, - -21, -5, 0, 18, -33, -1, 49, -29, -29, 38, 7, -26, -20, 45, -21, -18, - 26, -6, -6, 17, -29, -5, 41, -38, 10, 19, -18, -7, 15, 2, -24, 1, - 21, -6, -28, 51, -30, -7, 10, 6, -22, -3, 37, -32, -24, 63, -16, -60, - 65, -10, -35, 15, 17, -15, -8, -1, 33, -37, -10, 55, -44, -5, 41, -35, - -9, 20, -5, -18, 13, 19, -27, 2, 34, -34, -7, 21, -27, 27, -25, 26, - 5, -30, 32, -45, 38, -3, -41, 24, 25, -31, 5, 9, 9, -37, 13, 31, - -36, 7, 20, -18, -25, 56, -50, 13, 17, -17, 19, -40, 46, -3, -82, 88, - -1, -73, 66, -10, -4, -18, 13, 5, -27, 14, 7, -7, -10, 37, -39, 11, - 14, -38, 35, -21, 5, 11, -27, 45, -37, -6, 34, -39, 23, 16, -51, 51, - -11, -28, 19, -6, 12, -29, 12, 26, -21, -25, 48, -35, -6, 24, -9, 0, - -31, 54, -19, -47, 73, -33, -43, 81, -59, 12, 15, -28, 22, -26, 33, -2, - -29, 14, 34, -63, 28, 16, -40, 31, -22, 18, 8, -22, 25, -31, 6, 26, - -54, 33, 19, -53, 56, -25, -9, 24, -39, 34, -18, -15, 35, -18, -16, 43, - -41, -3, 47, -54, 9, 33, -13, -24, -2, 41, -26, -35, 73, -49, 1, 32, - -34, 20, -28, 22, -5, -16, 23, 18, -62, 47, 5, -57, 51, -15, -5, 0, - 4, 12, -11, -15, 29, -28, 4, 26, -44, 43, -19, -14, 35, -37, 23, -15, - -11, 45, -54, 17, 42, -67, 18, 47, -58, 17, 25, -35, 14, -6, 11, -3, - -42, 73, -50, -12, 67, -68, 28, -6, -4, 16, -44, 47, 8, -64, 80, -39, - -31, 54, -43, 14, -2, 11, -14, 4, -3, 19, -34, 0, 61, -98, 69, 12, - -61, 48, -35, 28, -12, -38, 85, -86, 42, 25, -76, 77, -31, -37, 39, -2, - -12, 7, -10, 16, -1, -33, 60, -48, -16, 70, -69, 13, 38, -43, 15, 0, - 0, 22, -65, 75, -28, -60, 96, -58, -8, 32, -6, 1, -11, 4, 17, -46, - 17, 46, -86, 66, 9, -69, 67, -21, -30, 33, -32, 42, -34, 1, 50, -74, - 40, 5, -34, 21, 7, -23, 21, -14, 10, -1, -33, 58, -48, -3, 65, -77, - 14, 51, -65, 32, -10, 0, 24, -58, 71, -27, -54, 86, -56, -12, 45, -17, - -18, 21, -1, -5, -14, 12, 19, -75, 78, 1, -80, 84, -25, -33, 48, -50, - 45, -30, -15, 69, -86, 46, 22, -56, 14, 36, -35, 2, 16, -11, 4, -24, - 41, -27, -19, 53, -42, -4, 49, -67, 36, 2, -26, 37, -46, 58, -40, -26, - 82, -70, -7, 55, -30, -20, 36, -1, -32, 11, 7, 7, -41, 39, 18, -68, - 65, -11, -39, 40, -34, 30, -20, -12, 70, -98, 53, 27, -74, 40, 10, -31, - 11, 20, -19, 6, -6, 12, -19, -9, 46, -36, -31, 83, -65, 8, 32, -48, - 42, -45, 49, -23, -32, 68, -59, 5, 39, -31, -1, 23, -20, -8, 17, -7, - -15, -1, 16, 25, -63, 51, 14, -66, 47, -10, -15, 5, -1, 36, -72, 54, - 22, -86, 64, -3, -31, 13, 11, -8, -12, 14, 15, -34, 6, 29, -24, -25, - 62, -49, -9, 49, -56, 45, -31, 18, 4, -37, 57, -41, -11, 38, -38, 7, - 24, -20, 10, -13, 20, -17, -8, 18, -4, -30, 35, 14, -63, 56, -7, -52, - 50, -5, -4, -19, 17, 36, -83, 51, 14, -52, 30, 4, 0, -15, 14, 8, - -43, 32, 3, -20, 2, 19, -11, -20, 45, -42, 14, 3, -5, 9, -31, 43, - -20, -30, 51, -24, -19, 47, -42, 21, -17, 25, -24, -20, 52, -37, 1, 20, - -6, -21, 25, -2, -33, 30, -9, -15, 23, -13, 26, -49, 29, 22, -76, 71, - -12, -37, 27, 4, 7, -41, 30, 10, -45, 28, 13, -13, -21, 31, -1, -33, - 27, 6, -18, -10, 24, -6, -26, 33, -10, -37, 72, -60, 24, 1, -13, 15, - -36, 52, -44, 18, 14, -31, 23, 2, -16, -8, 10, 23, -47, 19, 17, -10, - -17, 10, 29, -69, 56, -5, -38, 47, -28, 14, -21, 6, 32, -55, 33, 12, - -39, 24, 5, -11, -25, 31, 12, -47, 35, 9, -25, 1, 7, 5, -36, 57, - -52, 18, 29, -45, 37, -45, 35, -13, -17, 41, -31, 7, 8, -18, 15, -19, - 19, -22, 2, 33, -37, 20, -4, 2, -25, 27, 0, -34, 37, -13, -6, 3, - 1, 17, -46, 28, 32, -78, 60, -7, -25, 18, -6, 12, -35, 31, 4, -38, - 37, -11, -8, -13, 37, -22, -17, 32, -27, 25, -34, 24, 9, -43, 41, -19, - -1, 29, -48, 29, -6, -8, 10, -11, 27, -35, 18, 9, -19, -7, 12, 4, - -27, 30, 2, -24, 13, 7, -18, -1, 16, 11, -68, 77, -15, -45, 43, -24, - 29, -38, 16, 21, -43, 27, -7, -10, 11, 1, -4, -13, 26, -17, -1, 1, - -1, 3, -19, 34, -24, -13, 49, -51, 22, 3, -23, 29, -33, 28, -7, -15, - 31, -35, 2, 29, -28, -11, 27, -4, -18, 19, 2, -31, 26, -16, 17, -28, - 34, -3, -49, 64, -39, 6, 1, -8, 25, -38, 32, 4, -53, 47, 0, -32, - 16, 14, -1, -37, 31, -4, -7, -8, 9, 7, -20, 36, -34, 4, 25, -39, - 25, -13, 4, 12, -36, 51, -38, 0, 34, -51, 27, 13, -34, 14, 12, -9, - -23, 41, -21, -1, -16, 28, 10, -62, 66, -23, -26, 26, -9, 13, -29, 13, - 31, -62, 49, 1, -49, 49, -18, -7, 2, 14, -10, -19, 20, 5, -8, -17, - 37, -27, -5, 23, -35, 17, 15, -30, 30, -20, 28, -32, -5, 48, -64, 29, - 13, -37, 35, -10, -1, -7, -3, 14, -16, -9, 26, -5, -35, 48, -21, -21, - 40, -26, -11, 21, 3, 0, -42, 47, 8, -71, 72, -21, -21, 25, -15, 7, - -16, 14, -1, -24, 18, 32, -48, 12, 30, -46, 12, 26, -45, 36, -20, 18, - -3, -34, 52, -40, -2, 25, -29, 32, -11, -18, 18, -3, 3, -24, 7, 36, - -40, -10, 50, -35, -19, 47, -30, -4, 22, -17, 8, -22, 29, 4, -72, 85, - -21, -48, 57, -19, -8, -10, 17, 5, -31, 16, 24, -47, 29, 12, -31, 14, - 2, -27, 43, -26, 5, 13, -33, 48, -46, -6, 58, -67, 13, 45, -50, 26, - -6, -6, -2, -9, 24, -20, -7, 40, -37, -5, 36, -29, -17, 38, -21, 2, - -5, 6, 14, -52, 59, -11, -59, 82, -38, -22, 32, -11, -6, -4, 11, 14, - -38, 30, 5, -44, 24, 25, -37, 0, 21, 1, -9, -24, 49, -36, -12, 47, - -49, 20, 34, -70, 43, 6, -31, 21, -20, 24, -13, -10, 37, -35, -8, 37, - -26, -22, 44, -20, -13, 20, -7, 8, -28, 36, -15, -42, 79, -41, -28, 46, - -17, -8, -5, 5, 29, -44, 17, 24, -43, 20, 13, -42, 16, 37, -43, 5, - 22, 4, -31, 6, 26, -40, 11, 31, -45, 24, 9, -27, 26, -29, 26, -13, - -16, 38, -40, 19, 21, -37, -9, 51, -32, -18, 34, -11, -7, -11, 22, 0, - -40, 49, -20, -23, 44, -22, -9, 3, -2, 19, -44, 42, 6, -52, 41, 6, - -43, 20, 28, -48, 31, 8, -23, 10, -7, 7, -19, 4, 31, -41, 15, 28, - -40, 16, -8, 16, -25, -4, 51, -55, 19, 0, 8, -29, 29, -16, -11, 37, - -39, 18, 4, -6, -5, -14, 35, -6, -52, 72, -37, -9, 13, 11, -17, -22, - 53, -32, -20, 42, -19, -18, 12, 19, -29, 12, 12, -24, 15, -6, 6, -12, - -15, 54, -44, -2, 41, -48, 32, -20, -4, 9, 1, 5, -35, 48, -11, -17, - -9, 24, 1, -37, 38, -9, -16, 16, -2, -11, -1, 13, 11, -55, 67, -31, - -19, 37, -26, -4, 12, 16, -34, 11, 21, -22, -10, 12, 0, 0, -21, 37, - -16, -11, 29, -37, 15, -3, 17, -37, 13, 38, -54, 30, -2, -19, 11, -11, - 20, -20, 15, 4, -22, 13, 2, -8, -13, 20, 4, -28, 33, -9, -34, 38, - -13, -6, -14, 46, -33, -9, 36, -34, 4, 8, -9, 11, -9, 5, 1, -17, - 23, -16, -3, 4, 18, -26, -11, 54, -53, 5, 18, -5, -11, 8, 11, -20, - 12, -10, 1, 2, 5, -4, -5, -1, 23, -35, 22, -1, -25, 19, 3, -7, - -11, 22, 1, -37, 45, -26, -12, 20, 2, -23, 17, 13, -23, -4, 18, 1, - -15, -15, 33, 4, -49, 46, -25, 3, 5, 2, -11, 7, 13, -33, 13, 10, - -24, 12, 6, -3, -4, 12, -9, -10, -3, 20, -19, -3, 19, -2, -21, 16, - 5, -33, 35, -17, -3, 2, 17, -12, -21, 27, -17, -6, 19, -8, -6, 14, - -12, 10, -16, 13, 0, -19, 11, 20, -23, -9, 38, -50, 22, 17, -24, -5, - 17, 7, -24, 0, 23, -18, -14, 27, -15, 5, 6, -9, 1, -2, 7, -24, - 16, 10, -12, -9, 26, -19, -14, 30, -18, -13, 19, -10, 10, -8, 6, 1, - -27, 35, -13, -20, 26, -5, -11, -10, 28, -9, -32, 36, -3, -25, 12, 28, - -51, 36, -6, -20, 18, -2, -3, -1, -11, 28, -31, -4, 48, -56, 16, 19, - -18, 6, -4, 1, -10, 11, 0, -4, -6, 25, -26, -9, 30, -26, -6, 23, - -13, 10, -7, -3, 19, -56, 64, -30, -31, 50, -4, -31, 15, 15, -27, 6, - 13, -6, -14, 20, -2, -27, 23, 7, -30, 10, 19, -10, -1, -13, 27, -31, - 3, 38, -56, 29, 20, -45, 24, 5, -17, 0, 5, 3, -9, 2, 24, -25, - -14, 31, -13, -22, 28, -6, -8, 1, 3, 13, -41, 51, -39, -20, 60, -30, - -28, 48, -14, -26, 25, -10, 7, -17, 16, 5, -25, 13, 10, -32, 11, 35, - -46, 17, 10, 5, -32, 10, 21, -44, 19, 30, -39, 15, 7, -18, 11, -11, - 10, -13, 1, 19, -14, -12, 30, -25, -18, 43, -23, -15, 30, -13, -6, -14, - 43, -42, -9, 55, -36, -17, 43, -21, -11, 12, -13, 16, -28, 23, 10, -38, - 27, 17, -47, 22, 20, -46, 30, -7, 6, -10, -6, 26, -34, 15, 22, -39, - 15, 21, -43, 26, -6, 1, -14, 12, 20, -26, -12, 41, -29, -29, 57, -40, - 2, 27, -22, 8, -10, 10, -10, -10, 30, -14, -29, 47, -17, -24, 25, -11, - 3, -17, 30, -3, -32, 28, 7, -44, 35, 12, -46, 39, -6, -10, -2, -3, - 23, -31, -4, 49, -48, 6, 39, -55, 32, -8, -9, 0, 8, 7, -15, -3, - 29, -26, -16, 43, -44, 13, 26, -30, 9, 6, -5, 4, -28, 30, 9, -56, - 64, -19, -33, 43, -25, -8, 14, 8, -14, -8, 18, 11, -44, 23, 17, -39, - 20, 19, -24, -1, 12, 7, -27, -2, 47, -51, 3, 47, -55, 28, 1, -23, - 17, 4, -12, 5, -9, 18, -9, -21, 30, -24, 6, 12, -11, -2, 14, -13, - -3, -10, 26, -10, -45, 74, -31, -31, 51, -26, -14, 19, -8, 2, -4, 3, - 23, -43, 20, 15, -31, 13, 20, -36, 18, 9, -17, -3, 0, 21, -32, 12, - 32, -50, 21, 12, -26, 16, -6, 5, 1, -16, 21, -5, -27, 28, -11, -11, - 19, -2, -20, 28, -17, -2, 4, -5, 9, -26, 43, -31, -11, 47, -42, 1, - 19, -16, 5, -8, 12, 9, -41, 41, -7, -32, 22, 25, -51, 23, 14, -18, - 7, -21, 31, -22, -2, 24, -24, 6, 18, -39, 25, -9, 3, 5, -17, 28, - -13, -17, 27, -21, -12, 25, -12, -12, 32, -19, -6, 11, -24, 29, -21, 11, - -2, -17, 36, -29, -9, 24, -16, -2, 7, -6, 17, -27, 27, -20, -11, 23, - -1, -31, 25, 15, -32, 12, -8, 21, -22, -8, 26, -16, -15, 47, -45, 8, - 12, -12, 14, -28, 33, -10, -15, 15, -11, 6, 2, -17, 5, 23, -20, -5, - 19, -21, 12, -8, -8, 31, -38, 31, -17, -14, 31, -27, -1, 19, -20, 19, - -10, 4, -2, -7, 2, 1, -6, 6, 12, -27, 12, 8, -10, -7, 8, -1, - -3, -15, 47, -53, 15, 25, -40, 24, -7, 12, -13, -11, 22, -7, -22, 14, - 7, -5, -11, 13, 5, -8, -9, 4, 7, -22, 22, -12, 16, -9, -16, 29, - -32, 8, 23, -36, 14, 7, -3, 5, -27, 24, -1, -20, 14, 7, -7, -4, - 9, -21, 6, 23, -27, 7, -1, 23, -30, -3, 31, -39, 26, -17, -3, 30, - -24, 9, -7, -13, 30, -24, 3, 2, 9, -6, -15, 24, -18, 9, -20, 16, - 2, -8, 11, -11, 6, -10, 6, 11, -38, 27, 20, -42, 28, -26, 35, -21, - -29, 51, -32, 8, -3, 15, -19, 3, 14, -33, 24, 4, -9, -9, 4, 23, - -29, 0, 21, -32, 39, -38, 20, 8, -34, 38, -27, 8, 12, -12, 3, -8, - 11, -11, 1, 3, -9, 18, -18, 10, 0, -7, 4, -13, 17, -13, 0, 33, - -56, 42, -11, -7, 7, -17, 36, -50, 24, 21, -25, -7, 14, 9, -27, 8, - 23, -28, 3, 8, 2, -12, -10, 39, -43, 24, -4, -5, 18, -38, 39, -26, - -8, 26, -24, 14, 10, -20, 5, -9, 15, -19, 13, -12, 5, 24, -39, 24, - -8, 8, -16, -14, 53, -49, 16, 5, -22, 26, -28, 18, -13, 7, 18, -31, - 6, 17, -12, -13, 3, 26, -35, 16, 18, -36, 21, -12, 28, -49, 27, 22, - -38, 13, -1, 17, -28, -5, 30, -22, 2, 25, -42, 32, -19, 18, -23, -1, - 21, -20, 22, -31, 25, 3, -25, 9, -6, 27, -29, -3, 32, -35, 19, -7, - -8, 11, -12, 28, -35, 1, 39, -33, -6, 2, 30, -35, -1, 41, -42, 18, - -9, 6, -8, -2, 26, -46, 24, 24, -41, 11, 11, -2, -12, -9, 48, -59, - 31, -10, 6, -12, -5, 34, -43, 33, -12, -7, 11, -11, 1, 7, -12, 17, - -23, 32, -24, -5, 19, -26, 27, -28, 24, -15, -5, 31, -41, 11, 11, -4, - -19, 10, 37, -53, 2, 43, -35, 2, -3, 20, -20, 3, 32, -53, 30, 5, - -24, 10, -7, 41, -53, 10, 33, -31, -8, 11, 12, -30, 28, 4, -37, 28, - 8, -30, 12, -17, 42, -38, 5, 24, -33, 35, -41, 23, -1, -4, 5, -20, - 32, -18, -10, 25, -22, -4, 14, 6, -24, -5, 62, -80, 28, 19, -20, 4, - -14, 41, -49, 14, 34, -45, 3, 13, 17, -37, -4, 66, -61, -5, 35, -15, - -5, -2, 14, -24, 21, 5, -41, 41, -22, 18, -24, 5, 44, -66, 34, -3, - -17, 24, -26, 20, -13, 14, -1, -31, 39, -19, -20, 31, -14, 0, -12, 46, - -61, 29, 19, -44, 36, -26, 30, -31, -7, 49, -41, -15, 54, -42, -1, 12, - 24, -48, 8, 44, -57, 17, 13, 7, -34, 13, 33, -55, 28, 4, -14, 4, - -9, 32, -42, 15, 28, -58, 40, -12, 0, 7, -8, 8, -24, 29, -9, -29, - 38, -23, 9, -8, 13, -7, -14, 24, -37, 32, -7, 3, -17, 1, 39, -46, - -20, 78, -68, 15, 17, -6, -4, -15, 37, -47, 15, 20, -17, -12, 28, 9, - -52, 25, 31, -54, 24, 4, -1, -11, -5, 51, -74, 36, 9, -27, 17, -6, - 8, -12, 3, 6, -16, 14, 0, -15, 10, 3, 7, -31, 34, -22, -2, 17, - -20, 9, 10, -7, -13, -5, 45, -52, 8, 30, -33, 15, -11, 28, -32, -5, - 44, -42, -4, 42, -25, -29, 29, 14, -36, 12, 19, -20, 8, -14, 33, -42, - 16, 23, -48, 32, 2, -14, 2, -1, 14, -21, -9, 42, -47, 24, 0, -10, - 0, 15, -19, -1, 21, -31, 13, 15, -23, 10, -14, 20, -7, -27, 50, -32, - -5, 18, -10, -1, -8, 25, -36, 12, 34, -45, 6, 27, -20, -16, 12, 19, - -22, 0, 12, 0, -13, -8, 31, -41, 17, 16, -29, 17, 11, -19, -4, -2, - 36, -55, 30, 13, -35, 25, -7, -8, 10, -4, -8, 13, -7, 0, 4, -16, - 8, 13, -35, 40, -25, -6, 44, -51, 17, 15, -18, -3, 1, 14, -18, -1, - 24, -23, -9, 20, -6, -9, 1, 24, -30, 6, 6, 10, -29, 8, 31, -48, - 21, 27, -43, 13, 4, -4, -5, -2, 19, -18, 12, -15, 4, 16, -25, 9, - 1, 2, 0, -13, 12, 3, -16, -3, 18, -10, -6, 25, -41, 21, 11, -30, - 20, -3, 0, 1, -14, 27, -19, -21, 38, -28, 9, -3, 14, -22, 13, -4, - -2, -6, 12, 2, -26, 30, -1, -38, 31, 7, -32, 25, -16, 14, -4, -9, - 15, -19, 6, 4, -11, 2, 11, -8, -4, 10, -7, -4, 6, -10, 2, 11, - -9, 0, -5, 15, -16, 0, 9, -2, -7, 0, 11, -11, -12, 35, -44, 20, - 13, -19, 2, 13, -11, -14, 12, 10, -22, -2, 27, -24, -2, 15, 5, -29, - 22, -10, 6, -2, -3, 16, -31, 20, 11, -39, 29, 9, -34, 25, -10, 5, - -2, -15, 14, 0, -5, -6, 19, -18, 13, -22, 5, 24, -30, -1, 35, -23, - -12, 12, 12, -26, 5, 22, -32, 16, 16, -27, 2, 10, -4, -12, 2, 23, - -19, -1, 1, 11, -17, 4, 8, -18, 12, 12, -24, 1, 24, -20, -15, 29, - -5, -31, 42, -23, -8, 20, -18, 19, -33, 24, 8, -22, 0, 32, -38, 9, - 21, -25, 2, 23, -30, 7, 16, -20, 12, -10, 8, -14, 12, 16, -41, 24, - 14, -30, 6, 2, 19, -22, -6, 25, -8, -24, 23, -1, -29, 32, 9, -53, - 50, 4, -42, 12, 12, 3, -24, 15, 14, -25, 5, 4, 7, -25, 26, -5, - -23, 28, 0, -32, 23, -1, -21, 14, 10, -7, -13, 21, -25, 16, -8, 1, - -1, -1, 13, -22, 12, 12, -28, 3, 13, 1, -15, -3, 38, -41, -5, 45, - -37, -9, 30, -4, -35, 42, -10, -25, 19, -4, 3, -18, 12, 22, -43, 25, - 14, -37, 21, 4, -19, 5, 17, -12, -17, 26, -4, -22, 11, 7, 6, -31, - 35, -15, -14, 22, -14, 0, 0, 14, -16, -12, 31, -17, -19, 25, -10, 0, - 2, 12, -23, 8, 16, -44, 37, 0, -19, -2, 21, -5, -25, 22, 12, -38, - 3, 37, -11, -38, 36, 11, -54, 40, -9, -11, 14, -11, 11, -19, 17, 17, - -47, 16, 25, -17, -23, 34, -3, -29, 25, -17, 5, 14, -17, 3, -4, 21, - -23, -11, 35, -31, 7, 13, -17, 13, -6, 6, -22, 13, 5, -8, -8, 16, - 8, -34, 18, 21, -49, 32, 12, -45, 32, 0, 1, -32, 27, 2, -20, 10, - 6, 3, -26, 18, 19, -50, 31, 13, -40, 20, 12, -7, -19, 21, -9, -12, - 24, -21, 6, 7, -6, -2, -9, 23, -19, -8, 15, -7, 18, -26, 13, 5, - -21, 21, -19, 4, 25, -26, -14, 32, -2, -33, 21, 8, -29, 38, -35, 17, - 8, -19, 15, -29, 24, 15, -40, 10, 28, -21, -26, 34, 7, -42, 35, -3, - -14, -1, 18, -6, -30, 29, -1, -11, 8, -8, 16, -22, -2, 25, -27, 14, - 0, -9, 1, 9, 1, -25, 22, -16, 12, 8, -33, 32, 2, -35, 19, 4, - 0, -17, 15, 1, -6, 9, -15, 16, -30, 25, 8, -46, 40, 11, -39, 8, - 11, 2, -21, 10, 11, -17, 15, -6, -4, -10, 18, -6, -23, 29, -2, -7, - -13, 9, 24, -48, 23, 17, -30, 27, -22, 9, 4, -16, 8, 4, -9, -2, - 19, -12, -12, 21, -22, 15, -8, -2, 20, -39, 32, -5, -16, 11, 5, -15, - -8, 30, -5, -36, 34, -5, -13, 1, 3, 22, -37, 14, 6, -8, 0, -6, - 11, -17, 23, -6, -18, 19, -7, -4, -14, 11, 17, -32, 24, -6, -2, 9, - -26, 30, -24, 2, 18, -19, 7, 4, -6, -3, -1, 3, 1, 0, -21, 39, - -20, -33, 51, -27, -6, 24, -18, 8, -10, 12, -3, -23, 25, -11, 5, -19, - 25, 2, -34, 29, -5, -9, -7, 18, -12, -18, 30, -4, -26, 20, -9, 22, - -32, 7, 26, -28, 6, -9, 19, -20, 5, 2, -9, 26, -15, -13, 18, -19, - 15, -3, -26, 34, 2, -33, 6, 36, -36, -12, 36, -32, 29, -24, 10, 13, - -39, 30, -6, -17, 12, 9, -9, -17, 28, -6, -27, 21, 4, -15, 6, 13, - -13, -16, 30, -21, 1, -4, 4, 28, -60, 46, -3, -21, 3, 5, -8, 17, - -17, 3, 11, -6, -9, 11, -8, -17, 44, -36, 0, 20, -9, -4, -13, 29, - -24, 5, -3, 6, 14, -36, 26, -3, -23, 30, -3, -30, 25, 3, -12, -22, - 42, -13, -27, 19, 9, -3, -20, 16, -7, -3, 7, -5, 6, -13, 22, -21, - -15, 39, -17, -21, 30, -23, 19, -6, -20, 31, -24, 0, 8, 12, -31, 20, - 8, -27, 20, -14, 20, -22, -2, 17, 0, -18, 11, 0, 7, -28, 22, -2, - -19, 31, -17, -8, -2, 28, -24, -16, 34, -4, -28, 9, 26, -12, -30, 29, - -7, -6, 10, -1, -10, 5, -3, 6, -23, 29, -18, 10, -16, 7, 28, -48, - 21, 4, -12, 9, 4, -12, 5, -1, -7, 2, 0, -3, 11, -15, -3, 26, - -19, -4, 3, 1, 10, -37, 49, -26, -9, 6, 18, -23, 0, 17, -3, -27, - 25, 3, -22, 10, 6, -3, -19, 32, -23, 9, -3, -3, 11, -31, 27, 12, - -42, 23, 13, -12, -18, 30, -10, -19, 13, -4, 0, 17, -25, 12, -2, -2, - 4, -8, 9, -12, 8, -17, 24, -2, -19, 14, -16, 18, -6, -12, 22, -12, - -17, 20, 0, -4, -13, 19, -5, -18, 30, -19, 8, -17, 19, -9, -6, 8, - 1, 1, -36, 48, -9, -40, 46, 1, -50, 44, -5, -14, -3, 10, 4, -17, - 11, -1, 11, -25, 9, 10, -24, 19, 2, -9, -4, 4, 10, -26, 20, -8, - 6, -3, -12, 17, 7, -31, 18, -14, 17, -7, 0, 2, -8, 9, -15, 19, - -16, 8, 2, -22, 21, 15, -33, 4, 24, -20, -13, 36, -18, -24, 33, -16, - -8, 20, -19, 22, -32, 21, 0, -5, -7, 18, -17, -11, 26, -5, -25, 25, - 3, -17, -3, 15, 7, -35, 22, -3, 2, -2, -6, 7, -3, -4, 4, -13, - 25, -17, 1, -4, 7, -12, 13, -2, -11, 12, 2, -25, 24, 0, -25, 17, - -4, 6, -9, 14, -11, -8, 5, 0, 10, -25, 23, 1, -28, 27, 5, -26, - 0, 23, -11, -20, 21, 10, -30, 12, 9, -5, -16, 25, -12, -19, 26, -3, - -12, 1, 9, -1, -15, 11, 3, -12, 6, -5, 11, -7, -8, 6, 3, -11, - 4, 5, 0, -11, 7, -1, 6, -17, 1, 26, -35, 14, 6, -6, -8, 15, - -7, -9, 13, -2, -20, 19, 6, -11, -14, 24, 7, -36, 19, 11, -24, 1, - 23, -18, -4, 18, -10, -19, 29, -10, -9, -1, 6, 10, -23, 10, 19, -32, - 11, 11, -4, -13, 5, 12, -17, 3, 13, -20, 11, 0, -8, 5, 14, -32, - 19, 1, -22, 28, -16, -8, 13, 3, 0, -11, -10, 38, -40, 3, 22, -9, - -16, 19, -4, -13, 13, 9, -29, 9, 16, -9, -20, 25, -2, -22, 11, 6, - 4, -22, 12, 16, -35, 15, 26, -42, 13, 12, -5, -20, 24, -4, -18, 20, - -7, -11, 9, 5, -7, 1, -2, -2, 10, -18, 9, 11, -17, -2, 7, -5, - 28, -48, 12, 31, -36, 12, 8, -2, -14, 8, 2, -5, -1, 11, -17, -4, - 21, -1, -27, 19, 3, -13, 0, 8, 15, -39, 19, 17, -43, 34, 4, -32, - 16, 8, -10, -8, 21, -10, -12, 6, 9, -4, -10, 3, 9, -13, 8, 2, - -7, 1, 1, 2, -18, 22, -10, 2, 5, -19, 19, -4, -11, 11, -5, 2, - -13, 7, 15, -24, 9, 11, -20, -2, 21, 1, -38, 21, 9, -2, -22, 23, - 6, -41, 34, -2, -19, 27, -10, -23, 20, -3, 13, -34, 20, 10, -15, -3, - 14, -1, -19, 3, 4, 5, 8, -14, 9, -18, 18, -1, -22, 24, -8, -8, - 10, -10, 14, -12, -4, 6, -14, 30, -38, 28, -5, -23, 19, 4, -10, -9, - 22, -7, -22, 17, 8, -5, -19, 25, -9, -23, 31, -6, -26, 31, -20, 18, - -29, 22, 20, -54, 33, -4, 1, -3, 4, -8, 0, -5, 13, -6, -6, 9, - -1, -24, 36, -9, -26, 30, -24, 11, 8, -23, 22, -16, 5, -11, 20, -2, - -26, 23, -9, -3, 0, 9, -10, -6, 13, -3, -17, 25, -12, -2, -8, 16, - 4, -35, 39, -14, -9, -2, 23, -6, -37, 40, -12, -11, 4, 8, 1, -13, - 1, 17, -26, 12, 10, -27, 17, 4, -6, -18, 42, -32, 2, 4, -16, 36, - -31, 0, 10, 0, -1, -12, 15, 0, -28, 22, -3, -1, 6, -6, -9, -3, - 25, -18, -8, 7, 6, 5, -39, 48, -16, -23, 22, -2, -8, 1, 18, -25, - -9, 25, 1, -28, 16, 9, 0, -34, 37, -4, -27, 27, -18, -1, 6, 4, - -5, -8, 16, -9, 10, -21, 6, 12, -14, -4, 6, 9, 3, -31, 33, -14, - -12, 23, -28, 25, -10, 2, -11, 1, 11, 6, -30, 3, 40, -21, -34, 46, - -12, -22, 11, 6, -2, -10, 14, -10, -21, 49, -29, -16, 17, 9, -15, -13, - 32, -19, 0, 0, 8, 0, -14, 8, -4, -16, 30, -17, 2, -1, 0, 9, - -15, 6, -4, 11, -15, -6, 28, -28, 17, -18, 7, 11, -19, 12, 3, -24, - 21, 3, -29, 15, 26, -25, -27, 51, -18, -19, 7, 20, -21, -11, 36, -32, - -3, 35, -27, -4, 6, 8, 2, -31, 18, 18, -29, 1, 25, -16, -8, 19, - -30, 13, 16, -20, 8, -12, 19, -3, -21, 15, 0, -6, -3, 4, 6, 1, - -20, 2, 20, -5, -27, 31, -7, -21, 19, 6, -19, -10, 40, -28, -17, 40, - -15, -22, 12, 13, -23, 6, 14, -12, -7, 10, 11, -11, -30, 45, -9, -44, - 48, -5, -14, -5, 20, -22, 9, 3, -10, 0, 4, 4, -7, -9, 24, -23, - 3, 8, -15, 15, -2, -19, 21, -8, -6, -1, 14, -7, -12, 18, -10, -3, - 3, 21, -37, 2, 29, -23, -7, 22, -10, -2, -7, 20, -10, -20, 15, 5, - -25, 17, 23, -29, -16, 50, -35, -9, 19, 4, -22, 2, 24, -19, -10, 25, - -9, -22, 23, 3, -15, -6, 10, -4, 13, -29, 17, 13, -26, -2, 25, -23, - 14, -16, 12, -2, -2, 4, -11, 1, 11, 0, -22, 14, 18, -28, -6, 11, - 22, -29, -10, 42, -30, -12, 26, -12, -15, 19, 15, -41, 10, 33, -16, -32, - 20, 29, -47, 10, 36, -35, -1, 20, -19, 1, 9, 5, -14, -16, 15, 29, - -38, -6, 35, -16, -20, 18, 6, -9, -7, 1, 4, 6, -4, 0, -9, 2, - 8, 2, -14, -4, 24, -12, -32, 41, -1, -26, 1, 23, -22, 4, 11, -10, - -6, 8, 16, -28, -12, 52, -28, -40, 53, 2, -29, 2, 17, -10, -5, -2, - 8, -1, -13, 25, -10, -33, 51, -16, -32, 12, 29, -27, -11, 25, 7, -27, - 4, 12, 0, -15, 5, -2, 4, -11, 11, 21, -51, 15, 37, -46, 7, 24, - -9, -20, 2, 27, -11, -17, 4, 22, -40, 26, 16, -36, 2, 35, -32, -2, - 12, 14, -23, -17, 26, 10, -26, 3, 20, -20, -9, 28, -16, -9, 19, -4, - -21, 15, 12, -17, -15, 24, -7, -6, 5, -2, 10, -21, 4, 12, -9, -11, - 30, -12, -32, 38, 3, -33, 11, 11, 0, -24, 4, 44, -37, -18, 36, -8, - -25, 21, 5, -24, 10, -1, 18, -22, -2, 30, -38, -8, 41, -24, -3, 4, - 8, -6, -11, 20, -11, -20, 22, -2, 2, -8, 8, -12, 8, -17, 11, 18, - -34, 19, -4, 5, -3, -9, 5, -6, 6, -4, -6, 17, -5, -11, 2, 12, - -8, -16, 15, 3, -21, 13, 8, -7, -8, 12, -5, -5, -17, 33, -1, -44, - 35, 15, -42, 18, 15, -21, 4, -4, 10, -5, -14, 27, -21, -7, 19, 1, - -3, -8, -6, 9, -1, -23, 29, -13, -1, -2, 4, 8, -6, -20, 26, -22, - 5, 21, -25, 9, 3, -11, 16, -12, -4, 20, -20, -8, 25, -13, -5, 6, - -11, 13, 6, -30, 13, 24, -31, -11, 27, 9, -43, 28, 2, -3, -5, -4, - 13, -16, -1, 10, -8, -4, 11, 8, -23, 14, 0, -4, -10, 1, 14, -14, - 3, 2, -3, 20, -35, 26, -6, -25, 38, -32, 12, -10, 16, -10, 14, -24, - 9, 33, -83, 72, -13, -27, 28, -26, 25, -13, 8, -25, 18, 15, -29, 17, - -3, 9, -25, 2, 19, -20, 18, -20, 13, 4, -18, 32, -32, -10, 35, -18, - -12, 16, 10, -15, -5, 4, 13, -21, 1, 0, 14, -18, 9, 12, -26, 27, - -27, 9, 1, -4, -1, 1, 14, -33, 52, -49, -1, 46, -50, 21, -5, 12, - -9, -7, 6, 1, -2, -10, 14, -2, -10, 13, -19, 23, -26, 18, -2, -22, - 34, -30, 8, 20, -38, 14, 18, -18, -5, 9, 3, -6, -13, 24, -1, -28, - 12, 11, -14, -1, 21, -37, 31, -16, 5, 6, -26, 32, -23, 4, 2, 9, - 2, -40, 40, -7, -10, 2, 0, 9, -16, -1, 16, -3, -10, -3, 19, -22, - 6, 7, -9, -4, -10, 39, -38, 5, 27, -28, 0, 13, -8, 1, -3, 5, - -3, -9, 13, -8, -4, 13, -14, -6, 22, -14, -13, 31, -30, 22, -15, -15, - 55, -56, 6, 26, -23, 8, 1, 4, -17, 8, 6, -9, 9, -11, 15, -18, - 5, 14, -18, 9, -22, 26, -2, -23, 25, -11, 1, -16, 15, 12, -28, -4, - 35, -31, -3, 28, -8, -12, -8, 26, -21, -1, 3, -2, 12, -18, 18, -3, - -6, -9, 14, -23, 9, 36, -57, 29, 21, -50, 29, -2, -13, 7, 0, -5, - 6, -1, -4, 10, -25, 23, -3, -19, 28, -20, 11, -17, -5, 37, -39, 19, - -7, 1, 7, -17, 12, 14, -36, 6, 23, -23, 9, 12, -19, 4, 2, 2, - 6, -27, 14, 17, -39, 14, 34, -22, -31, 34, 6, -36, 28, -1, -28, 24, - 1, -18, 24, -20, 9, -2, -15, 21, -4, -23, 23, -10, -4, 15, -12, 3, - -6, 2, 10, -28, 28, -6, -15, 14, -14, 10, 1, -18, 14, 5, -19, 15, - 2, -18, 22, -17, -7, 29, -43, 45, -15, -40, 62, -27, -23, 23, 10, -20, - -20, 41, -7, -20, 9, 10, -22, 8, 5, 9, -21, 0, 22, -11, -18, 27, - -4, -34, 30, 3, -9, -2, 1, 4, -13, 6, 16, -25, 11, -11, 8, 1, - -11, 14, -4, -6, 4, 1, -2, -7, 1, -3, 11, -31, 57, -36, -10, 37, - -44, 22, -2, -10, 4, -1, 7, -2, -7, 7, 14, -33, 5, 24, -29, 7, - 10, -1, -13, 0, 26, -23, -16, 43, -32, -14, 23, 11, -23, -5, 13, 13, - -44, 44, -7, -18, 7, -7, 12, -12, -1, -1, 7, 0, -6, 26, -37, 17, - -6, 4, -19, 18, 13, -37, 24, 4, -7, 0, -13, 15, 3, -28, 22, 14, - -41, 27, 5, -28, 38, -30, 9, -6, -1, 18, -28, 8, 26, -36, 4, 21, - -3, -30, 28, -6, 1, -26, 45, -28, -15, 34, -15, -12, 6, 8, 1, -9, - -16, 26, 1, -50, 65, -34, -12, 25, -9, 4, -14, 21, -17, -2, -6, 10, - 17, -29, -6, 40, -23, -20, 27, 0, -40, 44, -27, 16, -6, 2, 3, -20, - 15, 15, -32, -1, 28, -9, -29, 38, -22, 14, -21, 16, -5, -6, 17, -35, - 20, 13, -19, 0, 2, 2, 16, -32, 0, 47, -61, 16, 31, -37, 21, -8, - 6, -7, 3, -6, 8, -9, -12, 29, -13, -20, 33, -16, 0, -21, 46, -39, - 2, 17, -3, -11, -6, 18, 2, -35, 29, 17, -37, 0, 42, -42, 9, -3, - 16, -19, -2, 24, -17, -2, 0, -1, 6, -12, 19, -12, -16, 27, -2, -27, - 16, 17, -42, 38, -22, 8, 2, -12, -1, 15, -18, 13, -6, -11, 7, 21, - -36, 26, -23, 38, -48, 15, 26, -20, -18, 24, -1, -4, -20, 34, -16, -17, - 18, 11, -30, 15, 7, -10, -10, 12, 15, -31, -1, 28, -6, -32, 30, 4, - -24, 1, 28, -28, 7, -11, 33, -39, 23, -15, 19, -12, -12, 11, 4, -25, - 33, -22, 14, -4, -3, -6, 10, -21, 31, -40, 19, 13, -10, -1, 14, -18, - -3, 10, -4, -5, -2, 10, -6, -14, 21, 14, -40, 15, 6, 3, -31, 28, - 12, -42, 11, 43, -44, 2, 27, -17, -18, 22, -16, 33, -59, 37, 15, -35, - 11, 20, -22, 1, -7, 22, -22, 7, -1, 9, -16, -4, 20, 3, -38, 31, - 9, -31, -3, 39, -34, 8, 4, -19, 41, -41, 11, 21, -40, 19, 18, -47, - 45, -14, -5, -13, 26, -4, -28, 19, 15, -45, 38, -4, -9, -4, 17, -29, - 28, -27, 34, -25, -20, 39, 5, -52, 49, -15, -13, 5, -3, 14, -2, -20, - 17, -3, -12, 18, -7, -9, 1, 10, 7, -31, 19, 13, -29, 12, -22, 52, - -30, -28, 40, 7, -60, 56, -19, -5, -5, 22, -26, 13, 1, 5, -28, 30, - -12, 3, -17, 25, -26, 16, -16, 20, -5, -14, 26, -19, -33, 67, -47, 2, - 20, -19, 21, -22, 12, 12, -25, 0, 17, -26, 24, -4, -15, 6, 9, -8, - 13, -28, 24, -15, 13, -27, 26, 3, -11, -31, 61, -31, -19, 24, 5, -33, - 22, -3, 14, -35, 22, 10, -28, 8, 23, -24, -2, 1, 18, -18, -8, 26, - -15, -12, 26, -31, 15, 10, -24, 18, -19, 35, -32, -1, 15, 7, -40, 36, - -14, -4, 16, -12, -22, 51, -54, 41, -31, 14, 4, -17, 5, 13, -24, 29, - -31, 12, 25, -34, -2, 30, -36, 21, -16, 22, -4, -36, 42, -11, -6, -12, - 31, -16, -29, 34, 6, -29, -4, 37, -23, -25, 51, -34, 9, -11, 23, -25, - 14, -8, 5, -20, 32, -22, 6, 14, -16, -3, 24, -49, 51, -46, 31, -4, - -21, 26, -13, 0, 7, -9, -2, -1, 8, -21, 22, -21, 29, -29, 10, 22, - -41, 37, -24, -7, 15, 3, -25, 26, 1, -15, 5, 2, 14, -33, -3, 54, - -69, 27, 13, 5, -37, 27, 4, -6, -19, 19, -3, -9, 2, 10, -11, 15, - -30, 38, -35, 20, 0, -29, 37, -16, 1, -14, 21, -12, -7, 22, -33, 30, - -19, 4, -7, -1, 31, -57, 46, -15, -8, 20, -21, -1, 18, -21, 17, -12, - 6, 7, -20, 2, 32, -57, 46, -7, -25, 12, 25, -32, -3, 18, 1, -12, - -15, 31, 4, -56, 52, -11, -6, -20, 23, 19, -50, 37, -7, -9, -1, 14, - -22, 10, 14, -36, 37, -18, -8, 25, -31, 20, -16, 21, -26, 10, 7, -15, - 9, 3, -14, 19, -25, 24, -15, -4, -4, 27, -37, 21, 7, -12, 1, -5, - 4, 5, -12, -4, 10, -12, 17, -10, -16, 52, -56, 5, 29, -12, -5, -28, - 56, -30, -19, 34, -3, -30, 20, 4, -21, 12, 9, -17, 21, -35, 43, -19, - -20, 21, -4, -13, 12, -10, 9, 0, -6, -4, 10, -19, 25, -23, 6, -3, - 10, -5, -15, 31, -12, -14, -4, 22, -15, -5, 1, 17, -17, -8, 28, -15, - -8, 6, -10, 2, 7, 8, -31, 25, 3, -20, -2, 26, -10, -22, 12, 20, - -25, 6, -11, 33, -36, -2, 43, -36, -8, 20, -9, -7, 2, 4, 5, -7, - -5, 24, -28, 11, 6, -24, 20, -7, -2, 6, -9, -1, 20, -35, 13, 27, - -31, -7, 31, -13, -12, -6, 27, -14, -24, 33, -6, -10, 15, -14, 6, -13, - 9, 0, -8, -1, 19, -20, 6, 10, -9, -15, 23, -20, -4, 31, -24, 2, - -13, 23, 1, -25, 14, 12, -16, -18, 25, 4, -25, 15, -3, 2, 6, -16, - 21, -12, -19, 19, 1, -18, 21, 1, -30, 25, 3, -15, -5, 6, 18, -34, - 4, 32, -13, -18, 1, 28, -21, -30, 44, -1, -41, 28, 16, -32, 9, 14, - -17, 6, -11, 5, 21, -43, 38, -11, -24, 39, -15, -18, 18, -3, -15, 0, - 20, -15, 2, -1, -6, 32, -43, 13, 19, -26, -3, 17, 10, -29, 19, 1, - -19, 22, -13, 7, -16, 10, 8, -17, -1, 12, 1, -18, 1, 40, -49, 6, - 34, -35, -8, 30, -2, -23, 4, 15, 12, -39, 2, 55, -57, -8, 47, -27, - -7, 18, -7, 2, -11, 0, 19, -21, 4, 2, 10, -32, 34, -16, -12, 20, - -12, 2, -4, 20, -12, -22, 22, -14, 9, -12, 6, 21, -24, -7, 27, -13, - -22, 13, 16, -38, 37, -2, -21, 19, -14, 2, -6, 6, 7, -16, -11, 44, - -22, -35, 52, -10, -41, 24, 16, -13, -19, 14, 21, -20, -29, 55, -20, -21, - 5, 28, -30, -3, 22, -6, -10, 5, 11, -11, -7, 15, -11, -4, -10, 18, - 1, -23, 24, 3, -24, 10, 5, 0, -32, 35, -7, -12, 1, 11, 18, -53, - 36, 7, -26, 0, 24, -27, 0, 26, -24, 6, 6, -13, 16, -21, 13, 1, - -25, 20, 26, -61, 40, 21, -41, -6, 28, 1, -24, -7, 38, -14, -25, 20, - 5, -16, -1, 6, 13, -20, -7, 39, -33, -8, 25, -14, 5, -20, 26, 2, - -28, 14, 14, -18, -23, 64, -60, 11, 24, -9, -13, -2, 17, -5, -25, 16, - 22, -13, -44, 61, -14, -38, 35, -7, -18, 28, -16, -10, 25, -9, -20, 8, - 6, 8, -23, 11, 19, -27, -1, 15, 0, -25, 18, 8, 2, -34, 38, 1, - -41, 23, -7, 13, -6, -19, 45, -20, -27, 24, 14, -61, 53, -13, -13, 21, - -21, 36, -25, -33, 58, -33, -26, 35, 19, -50, 7, 50, -35, -20, 28, 5, - -29, -1, 28, -20, 3, -10, 20, -8, -16, 35, -22, -13, 17, -10, -3, 15, - -25, 24, -7, 0, -8, -3, 29, -32, -7, 30, -16, 9, -29, 24, 10, -27, - -9, 49, -40, 4, 14, -28, 37, -29, -18, 68, -67, 12, 45, -48, 3, 31, - -21, -16, 9, 20, -3, -40, 38, 17, -65, 41, 8, -15, -9, -2, 46, -51, - -7, 64, -51, -31, 57, -21, 5, -10, -7, 35, -36, 0, 20, -20, 14, -16, - 10, 9, -1, -26, 26, -18, -3, 5, 14, -8, -17, 32, -25, 1, 17, -29, - 17, 17, -47, 50, -19, -12, 9, -1, -11, 17, -29, 44, -25, -36, 63, -32, - -18, 29, -7, 9, -38, 32, 14, -50, 21, 37, -57, 13, 37, -17, -16, -9, - 28, -6, -60, 76, -13, -34, 29, 1, -5, 9, -41, 35, -2, -48, 52, -5, - -3, -17, 14, 5, -12, -13, 24, -20, 7, -4, 10, 2, -13, 10, -2, -18, - 20, 2, -33, 37, -18, -9, 25, -21, 14, -15, 9, -2, -14, 15, 10, -44, - 37, 7, -36, 15, 18, -9, -21, 2, 45, -53, 3, 47, -48, 3, 25, -17, - 14, -24, -2, 53, -72, 22, 38, -32, -13, 22, -15, 30, -36, 6, 27, -30, - -4, 21, -3, -20, 8, 13, -3, -29, 43, -10, -41, 33, -14, 20, -22, 9, - 13, -14, -10, 25, -30, 14, 6, -29, 29, 2, -23, 4, 14, -15, -3, 13, - 11, -29, 21, -1, -25, 13, 5, 1, -9, -18, 58, -31, -44, 56, 7, -69, - 46, -10, 11, -3, -27, 41, 1, -58, 46, 7, -33, 14, -14, 30, -22, -24, - 77, -66, 6, 6, 27, -36, -2, 21, 10, -62, 57, 11, -46, 23, 7, -8, - -18, 24, -21, 17, -35, 40, -4, -31, 36, -13, -10, 0, -2, 2, 0, 2, - -14, 18, 22, -53, 11, 43, -45, -13, 39, -7, -12, -6, 22, -8, -27, 19, - 15, -35, 13, 21, -30, 26, -35, 40, -17, -11, -5, 33, -25, -4, -9, 32, - -10, -44, 65, -23, -18, 0, 28, -31, 17, -23, 45, -50, 11, 52, -68, 13, - 23, -10, -32, 41, -13, 4, -13, 5, 9, -11, 4, -8, 6, 12, -25, 4, - 24, -20, -15, 11, 30, -42, 5, 30, -7, -40, 27, 17, -27, -5, 14, 16, - -26, -9, 39, -23, -11, 17, -16, 30, -52, 43, -9, -4, -28, 31, 4, -15, - -15, 34, 6, -69, 65, -3, -40, 6, 42, -40, 8, 11, 18, -29, -28, 62, - -40, -17, 31, 2, -22, 20, -13, 16, -18, 0, -6, 12, -4, -10, 17, 0, - -6, -25, 44, -25, -6, 0, 24, -13, -33, 43, 1, -46, 36, 3, 0, -34, - 38, -11, -14, 5, -11, 30, -19, 3, -12, 45, -56, -3, 41, -20, -21, 17, - 22, -18, -15, 14, 37, -92, 53, 25, -48, -2, 57, -44, -4, 3, 35, -31, - -32, 59, -24, -17, 9, 28, -39, 22, -10, 9, -7, 0, 7, -29, 33, -16, - -17, 37, -24, -17, 43, -14, -28, 18, 18, -33, 5, 4, 21, -34, 13, 4, - -6, 7, -15, 14, -8, 11, -17, -1, 15, 0, -42, 58, -18, -35, 37, 14, - -47, 9, 27, -14, -33, 20, 58, -79, 11, 49, -18, -55, 58, -6, -29, 6, - 12, 16, -55, 61, -29, -20, 37, -15, -1, 9, -26, 22, 3, -25, 0, 31, - -18, -1, -12, 40, -11, -64, 62, -11, -23, 3, 32, -11, -18, 19, 5, -36, - 15, 11, -21, 6, 18, -16, 5, 16, -35, 14, -2, 19, -53, 45, 31, -81, - 31, 46, -51, -14, 44, -13, -23, -11, 67, -62, -3, 50, -23, -26, 24, 16, - -34, -2, 3, 27, -33, 1, 38, -35, 13, 0, -24, 50, -59, 11, 31, -20, - -6, 10, 20, -28, -15, 38, -2, -60, 43, 32, -68, 24, 47, -54, 9, 3, - 23, -46, 11, 36, -56, 34, -2, -20, 12, 24, -36, 9, 7, 18, -45, 11, - 45, -50, -10, 42, 4, -63, 62, -10, -22, -9, 26, 8, -52, 41, 14, -54, - 41, -9, -8, 12, -26, 33, -25, 6, 3, -14, 20, -28, -2, 50, -23, -51, - 64, 11, -86, 57, 17, -39, -5, 19, 41, -79, 33, 43, -64, 2, 40, -21, - -7, -6, 38, -37, -8, 43, -39, 5, 16, 3, -49, 67, -38, -20, 39, -20, - 10, -24, 43, -15, -47, 57, -13, -53, 59, -16, 8, -27, 35, -4, -36, 35, - -29, 13, -5, 5, -13, 32, -5, -48, 57, -29, -15, 30, -26, 23, -34, 33, - 25, -79, 54, 25, -70, 16, 33, -1, -60, 37, 52, -76, 7, 54, -22, -61, - 76, -23, -30, 30, -15, 14, -21, 24, -4, -20, 23, 0, -49, 63, -31, -12, - 28, -15, 9, -17, 26, -25, -1, 4, 15, -31, 22, 8, -23, 18, -8, -7, - 6, -1, 7, -12, -1, 32, -62, 42, 14, -59, 41, 13, -31, -5, 40, -14, - -49, 36, 38, -64, 1, 68, -54, -29, 61, -16, -29, 8, 37, -22, -33, 42, - 18, -75, 47, 6, -25, 26, -33, 42, -32, 1, 4, 3, -2, 5, -20, 27, - 4, -43, 33, 2, -27, 6, 26, -25, 8, 2, 19, -46, 26, 15, -56, 44, - 12, -34, -4, 43, -34, -1, 2, 27, -40, -3, 52, -64, 26, 21, -30, -3, - 30, 1, -37, 13, 27, -28, -31, 49, 4, -63, 61, 2, -23, -10, 22, 7, - -53, 17, 43, -51, 21, 15, -26, 37, -31, -4, 9, 0, -28, 28, 4, -10, - -5, 21, 2, -40, 32, 9, -50, 20, 43, -63, 32, -6, 13, -24, -4, 62, - -87, 46, 12, -27, -14, 25, 13, -44, 25, 24, -29, -8, 13, 18, -56, 46, - 6, -51, 55, -19, -10, -4, 17, 3, -52, 60, -3, -49, 41, -14, 0, -4, - -3, 17, -9, -9, 1, 18, -11, -17, 3, 17, -5, -23, 15, 42, -83, 51, - -1, -17, 6, -16, 57, -83, 48, 16, -46, 10, 24, -8, -32, 32, 15, -49, - 26, 19, -24, -22, 40, 20, -80, 64, -11, -24, 14, -11, 17, -18, 18, -5, - -21, 45, -36, -11, 24, -16, 5, -10, 32, -13, -17, 24, -15, -4, -8, 9, - 0, -16, 33, -36, 36, -7, -39, 46, -35, 33, -61, 51, 10, -63, 50, 11, - -34, -5, 39, -8, -46, 41, 6, -45, 22, 14, -4, -41, 74, -33, -44, 57, - -19, -20, -12, 42, -4, -37, 30, 18, -31, 0, -1, 10, -16, 3, 8, 1, - 9, -31, 21, -2, -11, -1, 3, 24, -40, 15, 31, -52, 20, -1, 13, -32, - 31, 6, -44, 41, -17, -18, 21, 18, -32, -10, 41, -2, -60, 42, 9, -25, - -9, 38, -10, -29, 40, -27, -7, 14, 8, -20, -2, 26, -11, -35, 42, -2, - -36, 28, -1, 3, -33, 39, -7, -24, 9, 4, 4, -10, 7, -2, 0, 15, - -52, 45, 4, -38, 14, 29, -20, -23, 39, -1, -38, 13, 23, -26, -1, 12, - 2, -30, 41, -10, -30, 36, -3, -22, -6, 35, -20, -32, 27, 22, -41, 19, - 23, -18, -18, 22, -5, -34, 39, -19, 5, -3, 29, -26, -21, 47, -38, -23, - 38, -4, -15, 6, 19, -12, -4, 6, -14, 17, -14, -11, 22, 3, -20, -13, - 38, -2, -52, 43, 16, -30, -19, 37, 1, -51, 47, 2, -23, -1, 22, -10, - -24, 17, 21, -62, 51, 11, -38, 19, 8, -3, -50, 61, -18, -15, 4, 16, - -9, -15, 29, -32, -2, 37, -43, 9, 35, -36, 13, -16, 28, -28, -5, 41, - -35, -3, 12, 15, -29, 2, 19, -20, 19, -21, 7, 18, -20, 1, -24, 47, - -17, -45, 54, 10, -43, 0, 37, -3, -63, 58, 4, -55, 43, -2, -6, -31, - 50, -35, -10, 37, -12, -17, 1, 29, -34, -5, 31, -19, -10, 29, -26, 32, - -44, 25, -5, -27, 43, -45, 33, 12, -29, -6, 38, -18, -34, 23, 18, -21, - -12, 17, 27, -52, 18, 32, -49, 42, -19, -24, 40, -26, -7, 0, 32, -12, - -44, 69, -18, -46, 21, 26, -41, -5, 49, -24, -8, 22, 0, -23, -17, 32, - -6, -42, 64, -40, 17, 0, 3, -11, -28, 63, -61, 13, 26, -12, -7, 4, - -5, 8, -2, -5, -14, 18, 13, -38, 6, 36, -7, -71, 86, -10, -56, 45, - -11, -2, -18, 9, 26, -38, 24, 1, -24, 41, -35, -10, 24, -1, -24, 10, - 25, -15, -20, 10, 36, -44, -32, 96, -69, -8, 44, -32, 12, -20, 33, -33, - 11, 24, -24, -15, 40, -23, -27, 20, 18, -19, -4, 28, -23, 9, -9, 4, - -19, 32, -27, -15, 59, -37, -17, 28, 2, -20, -12, 28, 20, -68, 46, 2, - -24, 3, 6, 16, -28, 17, 8, -21, 1, 6, -21, 15, 34, -68, 43, 41, - -81, 31, 10, -5, -28, 1, 51, -37, -21, 64, -40, -23, 44, -25, -12, 15, - 7, -21, 14, 0, 6, -29, 29, 7, -39, 30, -10, 0, -4, -5, 13, 8, - -24, 23, -28, 38, -27, -34, 50, -5, -33, 10, 55, -47, -22, 43, -3, -45, - 11, 38, -37, 15, 16, -25, 24, -22, -4, 0, 4, 14, -41, 33, 35, -67, - 13, 52, -57, 0, 25, -4, -7, -11, 18, 5, -37, 32, 2, -39, 54, -24, - -18, 13, 16, -27, -2, 7, 31, -52, 29, 17, -41, 38, -23, -15, 28, -4, - -28, 40, -13, -20, 8, 13, 0, -40, 37, 20, -53, 14, 39, -34, -21, 27, - 14, -28, 12, 14, -23, 7, 3, -28, 24, 6, -23, 10, 9, 20, -39, -12, - 61, -39, -44, 74, -24, -25, 21, 13, -31, 10, 11, -3, -21, 19, 7, -43, - 46, -26, -2, 22, -16, 0, 13, -16, 10, -9, -20, 33, -30, 29, -2, -29, - 44, -8, -62, 54, 13, -50, 8, 34, 7, -43, 9, 41, -34, -39, 54, -6, - -28, 9, 20, -16, -6, 25, -30, -6, 45, -51, 4, 36, -21, -22, 28, 4, - -25, 18, 6, -5, -33, 37, -9, -19, 14, 8, -5, -4, 5, -1, -13, 0, - 16, -46, 49, -5, -25, 30, -8, -16, 15, -17, -4, 24, -26, 14, -8, 16, - 3, -40, 16, 47, -78, 21, 65, -53, -20, 24, 26, -55, 6, 55, -47, -6, - 35, -4, -28, 14, 1, -19, 15, -9, 20, -22, 19, -6, -31, 32, 7, -36, - 14, 20, -18, -7, 9, 9, -27, 22, -15, 8, 9, -15, 2, -2, 9, -19, - 11, 5, 11, -38, 38, -4, -35, 23, 17, -48, 34, 15, -51, 41, -2, -11, - -30, 35, 20, -65, 33, 34, -37, -23, 48, -2, -48, 21, 19, -12, -34, 42, - 8, -49, 33, 10, -27, 25, -15, -6, 9, -11, 7, -14, 22, -7, -11, 18, - 4, -18, -12, 30, -40, 14, 16, -11, -2, 30, -36, 4, 20, -19, -25, 21, - 17, -39, 38, -11, 13, -32, 19, 13, -49, 41, -2, -25, 8, 24, -23, -16, - 41, -9, -44, 34, 28, -48, -15, 59, -22, -54, 64, -6, -10, -20, 29, 4, - -56, 42, 7, -31, 20, 0, -5, 9, -3, -27, 33, -15, -18, 25, 5, -21, - 10, -6, -4, 1, 5, 14, -42, 47, -10, -14, -15, 30, -6, -53, 64, -4, - -33, 13, 27, -34, -16, 37, -4, -42, 38, 11, -35, 11, 17, -10, -33, 55, - -35, -6, 14, 20, -35, -11, 63, -52, -17, 55, -22, -23, 19, -2, 0, -5, - -10, 21, -5, -14, 12, 1, -10, 6, -15, 11, 13, -37, 43, -14, -17, 11, - 10, -13, -28, 43, -15, -25, 35, 11, -45, 20, 25, -34, -21, 51, -16, -42, - 35, 18, -23, -32, 75, -47, -18, 34, -1, -28, 1, 34, -40, 16, 23, -26, - 4, 18, -22, -4, -7, 18, -8, -25, 41, 0, -24, 13, 9, -30, 14, -4, - -14, 30, -18, 5, 9, -12, -3, -8, 25, -22, -18, 50, -18, -43, 48, 0, - -39, 11, 27, -14, -26, 42, -10, -33, 4, 61, -72, 7, 58, -40, -22, 28, - 24, -62, 19, 31, -22, -23, 41, -13, -16, 5, 11, -13, -4, 23, -21, 4, - 7, -8, -20, 33, -19, -10, 26, -7, -13, 2, 18, -21, -10, 28, -20, -15, - 54, -36, -26, 56, -30, -32, 42, -5, -21, 1, 40, -26, -19, 29, 7, -59, - 34, 24, -43, 20, 3, 12, -36, 23, 23, -48, -1, 61, -49, -25, 62, -27, - -23, 19, 13, -17, 4, 0, 9, -29, 19, -5, -7, 13, -9, 17, -7, 0, - -14, 11, -5, -17, 2, 35, -29, -10, 45, -27, -21, 31, -9, -17, 12, 5, - -10, -12, 26, 0, -37, 34, 6, -36, 18, 8, -2, -42, 39, 16, -47, 25, - 37, -57, 1, 51, -59, 13, 19, -10, -10, 11, 11, -8, -32, 42, -19, -36, - 59, -26, 1, -7, 17, -14, -2, -1, -2, 5, -5, 4, 0, 15, -25, -3, - 30, -28, -15, 36, -13, -5, -13, 26, 2, -45, 41, 2, -38, 21, 20, -29, - -11, 46, -27, -35, 46, 3, -38, 20, 25, -48, 19, 18, -26, 5, 3, 10, - -17, -13, 46, -29, -27, 52, -40, 18, -6, 9, -14, -8, 21, -11, -11, 16, - 14, -42, 33, 5, -31, 14, 0, -14, 19, -9, 11, -5, 2, 2, -39, 58, - -35, -26, 47, -1, -40, 19, 32, -36, -14, 37, -2, -40, 18, 32, -47, -6, - 49, -34, -7, 36, -16, -15, 2, 22, -36, -5, 53, -56, 27, 6, 2, -13, - -8, 28, -40, 4, 22, -2, -33, 46, -14, -36, 51, -10, -47, 40, -2, -18, - 3, 11, 13, -50, 57, -33, -5, 30, -31, -4, 19, -3, -17, 20, -2, -8, - -16, 34, -6, -45, 30, 35, -73, 21, 55, -52, 3, 11, 19, -42, -2, 55, - -57, 13, 23, -11, -16, 12, 16, -45, 25, 9, -22, -2, 37, -23, -29, 49, - -24, -27, 46, -23, -8, 22, -14, 6, -26, 45, -42, -9, 41, -15, -12, 11, - 13, -25, -1, 10, 9, -42, 37, -2, -20, 17, 14, -41, 25, 17, -52, 45, - -14, 1, -23, 21, 30, -74, 44, 35, -53, -4, 42, -18, -36, 30, 9, -26, - 17, 15, -18, -12, 37, -32, -25, 48, -27, -6, 20, -8, 12, -32, 38, -22, - -17, 36, -18, -13, 15, 7, -22, 14, -3, 5, -21, 33, -18, -18, 17, 12, - -31, 10, 34, -51, 33, -12, 15, -23, 1, 19, -50, 51, -7, -41, 47, 11, - -56, 20, 30, -23, -34, 37, 17, -29, -14, 54, -25, -45, 50, -16, -17, 11, - 14, -2, -30, 44, -16, -32, 39, -18, -16, 26, -5, -22, 25, -7, 1, -18, - 27, -8, -21, 23, 0, -30, 16, 27, -54, 46, -1, -24, -9, 28, 8, -62, - 48, 6, -31, 13, 17, -25, 17, -16, -1, 9, 2, 0, -15, 12, 19, -42, - -2, 57, -56, -2, 47, -11, -40, 21, 38, -56, -22, 71, -26, -41, 52, 3, - -29, 14, -1, -7, -20, 29, -3, -34, 41, -1, -35, 26, 12, -38, 25, -6, - -4, 7, -9, 6, -14, 31, -24, -7, 24, 3, -47, 33, 9, -28, -7, 23, - 18, -44, 22, 29, -48, 1, 46, -52, 14, 21, -21, -9, 26, 3, -41, 20, - 34, -52, -14, 75, -39, -40, 53, 0, -35, 6, 29, -15, -36, 44, 0, -39, - 36, -15, -11, 25, -9, -8, 6, 0, 1, -30, 29, -1, -17, 12, 20, -34, - 17, 4, -35, 29, -4, -10, -8, 35, 0, -45, 34, 18, -77, 45, 22, -29, - -9, 24, 14, -50, 29, 15, -34, -1, 47, -52, 3, 58, -54, -12, 40, -7, - -28, 10, 33, -22, -50, 79, -24, -38, 25, 10, -5, -30, 27, 16, -42, 15, - 14, -19, 11, 6, -33, 35, 2, -46, 49, -20, -7, 13, -4, 0, -12, 14, - 3, -50, 58, -8, -44, 40, 17, -22, -41, 60, -13, -48, 25, 50, -62, -3, - 71, -55, -12, 23, 3, -20, -1, 13, 20, -50, 48, -27, -23, 57, -43, -5, - 8, 30, -34, -16, 51, -18, -42, 35, 19, -40, 23, 0, -35, 39, -23, 0, - 21, -24, 16, -6, 2, 14, -53, 43, 1, -46, 51, -2, -19, 3, 25, -32, - -11, 24, -1, -34, 25, 42, -74, 29, 42, -41, -34, 56, -3, -32, -26, 84, - -35, -72, 101, -39, -13, 5, 24, -31, -2, 21, -25, 2, 22, 0, -37, 43, - 2, -41, 23, -6, -9, 9, -7, 24, -19, -8, 24, -33, 31, -11, -37, 57, - -25, -22, 35, -2, -29, 2, 26, -1, -39, 20, 51, -72, 14, 45, -45, -17, - 49, -30, -12, 24, 25, -48, -23, 107, -96, -10, 61, -7, -47, 22, 34, -35, - -13, 21, 17, -55, 40, 12, -43, 23, 6, -21, 19, -10, -4, 10, 3, -2, - -35, 38, -7, -29, 31, 1, -15, 15, -11, 5, -8, -3, 10, -30, 40, 10, - -62, 43, 30, -80, 22, 59, -63, -6, 42, 4, -35, -2, 67, -87, 21, 44, - -44, -6, 34, -6, -39, 26, 28, -26, -47, 87, -25, -74, 69, 15, -63, 22, - 19, 3, -13, -14, 36, -30, 1, 5, -9, 9, 3, -14, 29, -9, -25, 14, - 6, -6, -38, 54, -12, -38, 46, 14, -70, 48, 19, -68, 37, 25, -27, -25, - 29, 39, -81, 27, 50, -53, -12, 44, -4, -46, 23, 27, -32, -24, 67, -34, - -36, 65, -33, -31, 52, -22, -23, 21, 8, 18, -61, 46, 14, -59, 26, 31, - -49, 24, 11, -27, 30, -29, 8, -7, 20, -20, -4, 11, 0, -1, 0, -1, - 0, -1, 1, -2, 2, -1, -4, -2, 1, 19, -2, -20, 3, -10, -11, 12, - 3, -10, -3, 25, -4, 1, 6, 4, -12, 10, 2, -4, -28, -11, 9, 2, - 1, 18, -9, -20, 12, 11, 10, 1, -5, 5, -15, 4, 7, -27, -3, 4, - -8, 38, -31, -15, 7, 13, -34, 37, -6, -19, -6, 20, 41, -31, -20, 28, - -13, 30, -4, 0, -23, -1, 0, -13, 21, 3, -32, 19, 30, -52, 18, -24, - -27, 31, -14, 4, 1, -16, 14, 12, -20, 32, 14, -41, 37, -6, -5, 1, - 27, -34, 42, 9, 2, -34, 20, -25, 11, 15, -10, -14, -19, -24, 5, -12, - 3, -17, 2, 46, -13, -15, 31, -23, -16, 21, 25, -6, -36, 10, 1, 26, - -18, -12, 1, 21, -8, 17, -16, -29, -39, 17, -5, -1, -4, -6, -18, 33, - -21, 24, -17, 31, 0, 4, 0, 6, -26, 18, 24, 46, 5, 19, -10, 11, - 25, -13, 10, 50, -50, -52, 21, -23, -29, -8, 34, -35, -39, 15, -16, -43, - -5, -29, 29, -1, -8, -30, 18, 5, -14, 52, 12, -4, -28, 19, 25, 25, - 16, -44, 53, -20, 49, -23, 25, -32, 1, -63, 50, 37, -52, -13, 13, 4, - -18, 22, -56, 7, 23, -46, -7, 39, -69, -15, 26, 28, 21, 9, -64, 55, - 23, -34, 46, -26, -9, 36, -31, 4, 5, 37, -58, 28, 49, -25, 20, -1, - -12, -25, -6, 12, 9, -23, -34, 0, -2, 14, 3, -4, -13, 25, 23, -11, - 1, -34, 6, 9, 30, -36, -19, 11, -16, 14, 76, -97, 33, 25, -50, 8, - 25, -35, 20, -20, 4, -27, 63, -73, 25, 35, -22, 7, -33, 13, 2, 6, - -3, 5, 1, 17, 1, -36, 40, -4, 10, -28, -9, 14, -16, 5, 20, -32, - -45, 59, -10, 26, -29, -10, -13, -32, 44, -74, 81, -51, -12, 66, -11, -33, - 17, 38, 12, 57, -39, 5, 39, 9, -4, 4, 0, 25, -50, 24, -19, -1, - -30, -21, 24, -46, -20, -35, 19, -10, 1, -45, -7, 29, -8, -70, 51, -4, - -51, 42, 20, 21, 21, -24, 7, 69, 1, 17, 10, 9, 8, 16, -8, 66, - -32, -13, -24, 30, 50, -86, -15, 34, -23, -56, -26, 7, 22, -45, 23, -41, - 50, -84, -19, 50, 0, 2, -20, -31, 49, -12, -8, 12, 63, -20, -23, 57, - -37, 85, -57, -29, 83, -11, -15, -29, 25, -44, 33, -51, 74, -56, 63, -99, - 72, 15, -40, -41, -29, 68, -66, 46, 12, 21, -65, 5, 62, -24, -24, -15, - 7, -25, 7, -4, -16, 47, 13, -38, 3, 55, -31, -40, 31, -1, -35, 22, - 4, 34, -6, -1, -12, 6, 75, -51, 12, 57, -19, -24, -5, 12, -10, 26, - -13, 10, -44, 25, -13, -26, 39, -42, -25, -65, 36, -55, -41, -12, 2, 8, - 22, 22, -24, -27, 51, -38, 36, 1, -14, -8, 88, 2, 15, 28, 6, 46, - 8, 32, -22, 37, -29, 10, 3, -36, 9, -9, 2, 6, -15, -79, 32, -15, - -26, -4, -29, -28, 7, 16, -29, -27, 3, 8, 2, 9, 5, 1, -13, 38, - 16, 26, -16, 0, 19, -14, 20, -29, -3, 43, 17, -14, 39, -34, -15, 24, - 36, -27, -1, 7, -55, 24, 50, -43, 21, 5, -5, -122, 78, -43, -33, 12, - -12, 9, -45, -3, -1, -22, 37, -3, 17, -35, -11, 32, 5, 62, 0, -4, - 20, 18, -33, 93, 2, -77, 45, 33, -29, -35, 45, -55, 48, -12, 15, -54, - 16, -3, -50, 1, -21, -39, 16, -1, -33, -38, 19, -45, 9, 34, 26, -15, - 21, 60, -32, 7, -2, 24, 21, 28, -19, -12, 7, 60, 23, -23, 7, -44, - -54, 54, -17, -42, 38, -24, -23, 18, 9, -31, 4, 24, -26, -27, 33, -53, - 15, 26, -38, 11, 13, -39, 24, 32, 19, 14, 16, -27, -24, 14, 14, 9, - 6, -48, -8, -8, 60, -39, 1, -32, 51, -34, 0, 33, -16, -33, -10, 60, - -40, -1, 3, 31, 50, -16, -32, -40, 45, -34, -8, 54, -80, 0, 19, 21, - -21, 87, -70, -19, 23, 25, -56, 40, -33, 19, -44, -8, 7, -12, 18, -20, - 22, -10, 18, 5, -7, 26, 33, -65, 49, -9, -9, 27, 22, 22, -37, 18, - -19, -1, 61, -23, -39, 4, 4, -32, -3, 27, -39, -3, 38, -19, -12, -8, - -37, 3, -10, -14, -37, 0, 4, 24, 1, 33, -35, 29, -2, 24, 24, -21, - 23, -3, -31, 47, 12, -26, 35, -19, -17, 22, 20, -27, 1, -16, -18, 17, - -2, -19, -22, 25, -2, -11, -3, -60, -2, 30, 64, -76, -7, -29, 45, 1, - 46, -23, -43, 2, 43, 68, -38, -8, 45, -7, -8, 15, -47, -27, 71, -12, - -3, -17, -54, -29, 75, -51, 8, -27, 12, -18, 60, -29, -42, 22, 51, -32, - -27, 28, -11, 48, -34, 30, 26, -19, 20, 14, -16, 2, 7, -36, 70, -14, - -21, -39, 82, -50, -49, 33, -28, 9, -17, -15, -51, 5, 7, -17, 58, -29, - -33, 2, 29, 14, -46, 3, 28, 2, 28, -22, 7, -3, 28, 2, 40, -71, - 2, 23, 24, 19, 11, -62, 56, 1, -24, -7, -10, -26, 30, -49, 18, -40, - 52, -51, 46, -3, -28, -26, 40, 11, -5, 8, -46, 25, -10, 34, -25, 44, - -17, -7, 12, 12, -28, -19, 30, -26, 6, -38, 13, 45, -43, 24, 24, -49, - -13, 19, 3, 27, -5, -8, 5, -6, -4, 39, 7, 1, -38, 22, 20, -20, - 19, -24, -50, 47, -11, -25, 32, -59, 17, 12, 35, -50, -14, -7, 15, 33, - -15, 11, -45, 10, 14, 50, -68, -4, 11, -35, 20, 88, -72, 40, 16, -9, - 3, 55, -44, 25, -24, 6, 14, -66, 9, 7, -10, 9, -7, 1, -42, -24, - -26, 74, -5, -23, -44, 12, 11, 12, 57, -60, -19, 7, -2, 40, 3, -26, - -14, 44, 29, 7, -23, 21, -32, 42, 13, -30, -16, 36, -9, 3, -21, 17, - -67, 30, -4, 23, -19, 8, -32, 5, 31, -4, -26, 18, -24, 6, 39, -7, - -24, -2, -5, 6, -3, 11, -10, -6, 16, -15, -15, 5, -19, -17, 38, -27, - 35, -48, 7, -20, 4, 12, 1, -33, 28, -24, -2, 28, -10, -11, 23, -2, - 5, 21, -5, 8, 0, 21, 12, -24, 36, -40, 36, 29, -2, -19, 1, 3, - -8, 9, -11, -13, -31, 26, -5, 23, -26, -30, 1, 30, -19, -2, -15, 3, - 5, 5, -3, 3, -43, 38, 16, -30, 18, 12, -1, -4, 20, -47, 11, 1, - 21, -15, 1, 0, -43, -5, 37, -28, 11, -51, 21, 2, 20, -24, 22, -46, - 34, -1, 7, 27, -12, -24, 28, 39, -4, 10, -19, 8, 6, 37, -26, 2, - -12, -32, 36, 17, -11, -14, -26, -1, 17, 17, -53, -10, -11, 23, -16, -26, - 10, -33, 1, 61, -5, -21, -14, -28, 50, 13, -41, 17, -12, 38, -19, 24, - 36, -75, 16, 1, 58, -15, -19, -33, 56, -40, 39, -18, 1, 0, -34, 11, - 32, -6, -52, 32, 2, 39, -31, -23, 0, -11, 10, -26, 55, -6, -51, 0, - 36, -33, -14, -9, 30, -11, -5, 14, -17, 6, -34, 28, 16, -3, -21, 7, - 25, 13, -30, 14, 12, 33, 3, -16, 9, -12, -17, 15, 2, 23, 14, -46, - 1, 13, -4, -19, 6, 30, -53, -13, 1, -17, 13, -38, 11, 20, 1, -24, - 19, -10, 7, -28, 48, 25, -59, -33, 51, 12, -4, -3, 13, -23, 64, 0, - -5, -24, -6, 21, -27, 28, -19, -29, 51, -24, -9, -12, 3, -3, 35, 6, - -33, -37, -5, 45, -47, 30, -16, -9, -10, 51, -31, 32, 10, -22, -10, 8, - -13, -28, 8, 15, -25, 39, -36, 2, 50, -30, 36, -40, -14, 35, -9, -3, - 12, -25, 36, -7, -20, -6, 48, -5, 31, -4, -18, -48, 67, -47, 26, -30, - 6, 9, -14, -29, 3, 23, -12, -27, 29, -22, -36, -9, 51, -30, -18, -16, - 47, -4, -25, 18, 16, 13, -11, 15, 10, 2, -36, 42, 3, -9, -21, 52, - -19, 18, -34, -3, -11, 23, 19, -13, -17, -19, 16, -1, 0, -32, -1, -4, - 25, 9, -37, -3, -9, 45, -15, -29, 36, 4, -29, -9, 35, 16, -36, -21, - 25, -12, 10, -21, 25, 5, -17, -8, 12, 35, -56, 4, -15, 47, -32, -5, - 18, 3, 11, 2, 7, 1, 1, -24, 23, 6, 7, -46, -37, 73, 12, -2, - -20, 34, -45, 32, -23, 15, -40, -34, 12, 4, 13, -39, 3, 23, 17, -24, - -15, 16, 19, -30, -9, 12, 53, -64, 1, 23, 40, -11, 8, 33, -36, 42, - -68, 71, -16, -10, -41, 22, 16, -19, -18, 26, -2, 1, 4, -21, -3, -16, - -4, 16, -31, 1, -26, -5, -8, 43, -69, 28, 14, 10, -16, 21, -18, -2, - -14, 0, 32, 23, -28, -21, 68, 0, -40, 24, 32, 1, -10, 8, -20, 32, - -37, 16, -3, 24, -10, -5, -30, 35, -39, 12, 6, -26, -2, -58, 65, -66, - 13, -10, -6, -15, 28, -27, -39, 51, -28, 16, -10, 60, -51, 30, 51, -24, - 11, -9, -7, 14, 39, -33, 4, -14, 25, -13, -8, 35, -40, -1, 27, -9, - 11, -9, -13, 5, 19, -37, -12, 23, 1, -2, -31, 37, -7, -41, 35, 16, - -6, -28, -8, 9, -23, 22, -8, 27, -17, -27, -10, 10, 12, -6, 11, -51, - 21, -19, -29, 23, -10, -4, 32, 3, 25, 7, -25, 23, 35, -21, -2, -3, - 23, -4, 14, 6, -8, -5, -6, 10, 10, 5, -38, -7, 16, -38, -2, 12, - 8, -54, 5, 18, -12, -18, 23, 17, -52, 50, -78, 11, 4, 5, 19, 7, - 27, -24, 5, 3, 35, -20, 34, -15, -10, 4, 21, 16, -14, 12, -8, -2, - 42, -30, -22, 28, -9, -34, -11, 23, -36, 0, 15, -10, 14, -37, -7, -19, - 30, -18, 15, -17, -14, -14, 51, -20, -8, 13, -12, 7, 35, 9, -12, -13, - 48, 1, -2, -32, 13, -5, 1, 15, 40, -66, 18, 1, 49, -45, -38, -8, - 14, -16, -2, 24, -13, -62, 15, 54, -28, -18, -3, 10, 13, -21, -18, -9, - 44, -13, 8, 37, 6, -18, 4, 27, -18, 21, 3, -8, 13, 27, -19, 14, - 2, -27, -11, -8, 17, -38, -26, 29, -31, 5, -7, -5, -9, -4, -11, 9, - -3, -5, -18, 16, 3, 0, -8, -2, -6, -1, 58, -11, 12, 2, 31, -21, - 13, 27, -17, -23, 54, 18, -33, -7, -7, 3, -2, -25, 15, -1, -25, -41, - -13, 46, -71, -15, 40, 10, -14, 0, -10, 18, 0, -31, 25, -8, -10, -13, - 24, 30, -9, 6, 4, 26, -3, 5, 31, -25, 0, -7, 16, 20, -1, -12, - -22, 11, -10, -3, -26, 12, 3, 2, -17, -31, 4, -26, 15, 13, 6, -22, - -5, 5, 8, 11, -23, 17, 17, -33, 0, 12, 21, -20, -3, 20, 21, -7, - -20, 38, 20, -27, -16, 3, 7, -8, -3, 0, 22, -38, -37, 26, 23, -26, - -8, -5, 0, -12, -2, 30, -8, -4, -2, -13, 15, -24, -4, 29, 10, 32, - -7, -57, 48, -13, 41, -13, 16, -20, -20, 33, -13, 26, -17, -18, 20, 10, - -44, 18, 2, -18, 3, -13, -5, -25, -16, 7, 30, -32, 8, -34, 19, -5, - 23, -28, 12, -4, -14, 30, 1, -2, 15, -20, -16, 44, -2, 34, -31, 36, - -25, 15, -3, 13, -10, -36, 39, -5, 0, -16, 1, 27, -28, 24, -26, -8, - -12, -16, 25, -2, -12, -28, 16, -17, 7, -24, 31, -15, -8, 31, -22, -7, - 0, 14, 16, -17, 8, -15, 24, -3, 17, -14, 6, -4, -22, 22, 9, 1, - 3, -21, 18, -8, 11, 0, 10, -3, -12, 3, 15, -15, 1, 2, -13, 3, - -23, -3, 15, -11, -5, 9, -30, -6, -10, 27, -2, -9, -12, 10, 4, 0, - -16, 16, -10, -27, 51, -5, -4, -1, -4, 5, 38, -18, -11, 17, 1, -2, - 8, 0, -7, 6, -6, -4, 9, -12, -11, 11, 1, -14, 1, -31, 13, 3, - -28, 12, 24, -30, 7, -6, 5, -4, -6, 8, 1, 14, -19, -1, 32, -22, - -9, 34, 6, -9, -9, -5, 15, 6, -25, 14, 6, -41, 0, 10, 2, 12, - -18, 6, 5, -1, -16, 4, 26, -33, 5, 4, -4, -9, 5, -2, 14, -10, - -11, 16, -6, 11, -5, -15, 14, 18, -19, 21, -24, 13, 6, -13, 21, -12, - -11, -2, 10, -6, -7, -13, 12, -13, 1, 10, -7, 2, -2, -21, 24, 5, - 2, 5, -24, 17, -17, -15, 9, 20, -12, -9, -15, 14, -1, -2, 14, -13, - 5, -32, 21, 10, 7, -11, 24, -1, -23, 24, -25, 31, 7, -16, -2, -4, - 9, -19, 17, 4, -27, 22, 21, -28, -6, 32, -48, 6, -4, 20, -6, -41, - 11, 31, -16, -14, 2, -8, -13, -13, 35, -15, 15, -20, 1, 26, 7, -13, - 18, 5, -19, 11, -7, 20, 22, -35, -11, 20, -24, 21, -20, 34, -15, -17, - -8, -2, 16, -9, -12, 2, 20, -31, 24, -21, 2, 12, -27, 28, -10, -5, - 24, 7, -29, 4, 6, -24, 33, -4, -8, -16, 1, 32, -28, 13, 7, 2, - -10, -38, 30, 2, -18, -2, 17, 13, -6, -46, -1, 61, -48, 18, 10, 2, - -17, -13, 8, 27, -8, 0, 11, -5, 20, -39, 4, 19, -8, -13, -15, 29, - -36, 29, -16, 14, -25, 17, -14, -15, 18, 5, 3, -5, -2, -19, 31, -12, - 14, -23, 31, -24, -4, 0, 4, 2, 11, -15, 22, -27, -4, 9, -8, 22, - -2, 7, -33, -12, -3, 30, -3, -10, 12, -19, 2, -9, 16, -4, -15, 5, - 32, -13, -13, 22, -11, 1, 3, 18, -12, 3, -17, 16, 15, -36, -2, 10, - -12, 9, -29, 14, 12, -23, 5, 39, -20, -39, 13, 14, -13, 2, -16, 43, - -25, -1, -12, 19, 11, -27, 0, 28, 3, -3, -15, -1, 10, -31, 43, -6, - 5, -10, 4, -18, 24, -6, -14, -8, -5, 4, 1, -5, -20, 21, 5, -19, - 22, -8, -13, -3, 20, -10, 20, -12, -7, 11, -11, -15, 6, 3, 24, -9, - -4, -3, -4, -20, 44, -12, -15, 4, -3, -6, 2, 9, 3, -17, -7, 9, - -2, 2, -22, 18, -8, -2, -10, 4, 6, -1, -4, 9, -1, 6, -9, 8, - 2, 4, 4, -6, 17, -32, 11, -1, 21, -7, -29, 12, 2, -35, 28, 12, - -15, 15, -43, 37, -30, -4, 2, 27, 8, -22, -1, -13, 20, -28, 36, -6, - -12, -4, -8, 14, 2, -12, 5, 12, -3, -11, 3, -1, 2, 18, 12, -11, - 4, -31, 13, 10, -10, 12, 7, -35, 10, -17, -3, 12, -5, 2, 0, -23, - 7, 5, -4, 23, -30, 2, 4, -3, 18, -16, 17, 16, -12, -3, -14, 17, - -1, -5, 9, 19, -23, 11, -8, -19, 34, -7, -13, 1, 3, 19, -23, -15, - 19, -17, 5, -24, 16, 4, -5, -7, 7, -2, -20, 4, 15, 21, -29, -7, - 16, -3, -17, 9, 3, 15, -15, -5, 12, -14, 8, 21, -15, 12, -18, -1, - 17, -19, 2, 16, 16, -11, -30, 22, -12, -12, -1, 21, -28, 29, -30, -6, - 19, -14, -5, 0, 10, 18, -8, -15, -1, 7, -15, 28, -3, -3, -9, -8, - 0, 6, 18, -32, 7, -3, -11, 6, 30, -42, 32, -13, -8, 5, 8, 8, - -15, 3, 4, -22, 27, -6, 6, -11, 1, -6, 13, -5, 2, -12, 29, -30, - 10, -15, 18, -19, 8, 21, 1, -28, 15, -20, 25, -25, -1, 11, -2, 1, - -22, -3, 15, 1, -22, 18, 16, -24, 1, 19, 6, 9, -7, -22, 8, -6, - 2, 14, -9, -4, -13, 10, -12, 13, 0, -11, -12, -2, -6, 20, -9, 4, - 5, -14, 3, 9, -2, 13, -5, 0, 14, -17, -1, -3, 8, -6, 7, 29, - -19, -13, 3, 27, -17, -8, 11, -2, -14, -9, 7, -3, -9, -14, 24, -12, - -35, -13, 40, -10, 1, -7, 1, 2, -1, 1, 16, 3, -13, -11, 30, 2, - -9, 0, -9, 2, 15, -9, 8, 3, -19, 12, 5, -21, 5, -6, 16, -4, - 7, -4, -2, 9, -35, 27, -6, 0, -12, 15, -29, 8, 2, -7, 4, 1, - -15, 28, -15, -13, 18, 4, -1, 1, -4, -7, -16, 21, -11, 25, -19, 2, - -10, 20, -32, 11, 6, 6, -15, 22, 8, -25, -13, 5, 20, 13, 7, -23, - -6, 7, -4, 4, 0, -7, 3, -10, -4, 9, 1, 3, -8, 2, 16, -22, - -7, -3, 12, -4, -4, 8, -10, 6, -13, -5, 3, 3, 6, 4, 4, -9, - -27, 1, 16, 17, -15, 0, -12, 15, -2, -6, 10, 3, -16, -16, 22, 13, - -12, 4, -4, 7, 11, -12, -14, 15, -1, 3, -12, 7, -7, 12, -14, 9, - -9, 2, 2, 9, -12, -17, 12, -17, 14, -2, -18, 2, 16, -5, 1, 8, - -5, -12, 0, -3, 21, -2, -17, 10, 10, -4, -16, 6, 15, -1, -25, -11, - 18, 0, -11, 8, 15, -16, -18, -4, 39, 3, -30, -6, 22, 2, -22, 2, - 21, -9, -9, 12, -3, 19, -24, -12, 20, -8, 4, 3, -3, 15, -20, -3, - 14, -7, -4, -14, 9, -8, 0, 7, -6, -8, -4, -3, 4, 13, -18, 0, - 9, -2, 5, -4, 10, 3, -9, -6, 9, -3, 1, 4, -3, 4, -11, 2, - -3, 5, 11, -13, -1, 4, -7, 1, -11, 1, 17, -17, 2, 13, 1, -21, - -2, 7, -5, -4, -5, 16, -5, -7, 4, 8, 8, -14, 4, 8, -7, -1, - 5, 2, -11, -9, 9, 6, -10, -2, 6, -7, -2, -1, 15, -17, -4, 5, - -2, 2, -3, -5, 11, -3, 1, 16, -12, -3, -7, 6, 5, -4, 5, 0, - -3, -15, 5, 3, -8, 9, 3, -8, 1, -6, -4, 0, -7, 21, -18, 9, - -8, 11, -2, -10, 10, 1, 14, -19, -11, -7, 18, -7, 4, 6, 2, -15, - 2, 4, 5, -3, 0, 0, 12, -2, -15, -4, 18, -7, -9, 18, -7, -6, - -9, 4, 7, -21, 11, -18, 14, -5, -4, 8, 5, 4, -3, -4, -11, 11, - -15, 19, 2, -18, 8, -4, -13, 18, 3, -14, -3, 9, -11, 2, 10, -9, - -5, -1, -15, 13, 16, -9, -4, 29, -15, -14, 6, 9, -1, -15, 12, 12, - -6, -6, 13, -10, 18, -14, 7, -12, 5, -9, -12, 16, -6, -16, 7, -1, - -22, 8, 2, -1, 9, 4, -31, -9, 12, 14, -9, -5, 17, -25, 7, 0, - 13, 4, -1, -17, 10, 13, -7, -11, 17, 2, -23, 27, 5, -10, -3, 13, - 5, -5, -5, -4, 0, -3, -5, 3, 4, -9, -7, 5, 4, -13, -10, 1, - 7, -4, -2, -3, -5, 15, -9, 0, 1, 12, -17, -6, 32, -15, -16, -11, - 20, 0, 2, -11, -5, 25, -21, 3, 10, 15, -24, -4, 8, -5, 0, 15, - -1, -7, 1, -18, 21, -7, 3, -12, 0, 12, -10, 6, -3, -2, 2, -1, - 9, 1, -9, 7, -9, -4, 9, -16, -4, 8, -10, 4, -3, -2, 13, -9, - 4, -16, 4, -3, -5, 14, 7, -8, 2, 9, 0, -2, -12, 7, -3, 2, - -4, -15, 11, -8, -11, -4, 23, -5, -1, 4, -9, 7, -4, 7, 8, -13, - -6, -4, 16, 10, -11, 8, -1, -1, 2, -5, 0, -3, -6, 2, 3, -6, - 13, -19, -9, 19, -11, 6, -12, 12, -10, -3, -11, -10, 14, 2, -19, 14, - 4, -6, 4, 11, -7, 3, -3, -8, 24, -18, 6, -8, 15, -14, -7, 19, - 0, -11, -3, 2, 2, 0, 2, 6, -7, -22, 16, 0, 11, -12, 7, -12, - 10, -16, 4, 8, -11, -11, 4, 16, -19, 13, 1, -19, 12, 19, -15, -4, - 9, -8, -13, 5, 14, -12, 5, -21, 7, 4, 11, -19, -1, 15, -16, -3, - -12, 14, 1, 1, 15, -6, -13, 7, 0, 6, 4, -11, -3, 10, 14, -20, - 7, 3, 1, 5, 17, -17, -5, 3, -4, 6, -1, 3, -18, 10, -10, 0, - 0, 14, -18, -19, 17, -23, -5, -1, 4, -4, -2, 1, -13, 26, -15, 2, - -10, 3, 13, 0, -6, 3, -4, 3, 0, -2, 9, 2, 9, -14, 23, -4, - -10, 15, 7, -16, 0, 9, 3, 0, 14, -12, 0, 4, -10, 1, -11, -13, - -6, 15, -14, -7, 2, -20, 4, -7, 9, -3, 2, -14, -1, 1, -1, 9, - -18, 10, -1, 1, -3, 22, 1, -1, 5, -4, 10, 2, 5, 0, 3, -2, - -1, 5, -2, -3, -5, 10, 2, -16, 2, 3, -1, -1, -11, 7, 6, 0, - -10, 10, -7, -2, -15, 15, 4, -25, 0, 4, 4, -12, 0, 5, -7, -6, - 6, 6, -8, 1, -1, -7, 17, -9, 2, 8, 4, -6, -6, 19, -5, -11, - 12, -12, 3, 3, -5, 9, 11, -26, 0, 0, 7, 5, -8, 11, -5, -6, - -16, 7, 12, -10, 0, -6, 7, -8, 3, -4, 11, -9, -16, 13, 18, -18, - 2, -5, 7, 5, 0, -1, 4, -9, -13, 18, 5, -4, -14, 1, 7, -5, - 4, -9, 15, 3, -10, -4, 5, 3, -11, -17, 18, 4, -9, -3, 3, -5, - -11, -3, 0, 7, -1, -8, -2, 6, -7, 7, -3, 6, 3, -12, 15, -5, - 23, -12, 8, -12, -4, 10, 1, 4, -3, 0, 0, 8, 0, 1, 11, -27, - -9, 9, -4, -3, 12, -19, -2, -8, -6, 1, -1, 2, -12, 5, -11, 3, - -1, -1, -10, 18, 0, 3, 2, 4, -5, 11, -3, 9, -2, -5, 7, -6, - 8, 10, 2, -1, -8, 1, -16, 2, 9, 1, -4, 0, -15, -5, 6, -14, - -9, 14, -22, 3, 7, -1, -2, -2, 0, 1, -2, 1, 9, 0, 7, -1, - 6, 4, 0, -6, -2, 2, 4, -9, 11, 1, -25, 9, -6, 5, 0, -7, - -8, 3, 5, 1, -2, 3, -9, -5, 7, 14, -12, 3, -10, 10, 3, -16, - -3, 26, -8, -9, -2, 15, 0, -21, 8, 11, -17, 3, 8, -8, 10, -19, - -3, 8, -4, 6, -10, 3, 4, -6, -4, 6, 0, 4, -19, 9, 3, -7, - 17, -7, 2, 3, -27, 12, 5, -14, 5, -6, -6, 6, 11, -11, 6, -12, - -2, 9, 8, 1, -18, 18, -9, 0, 13, -8, -10, 24, -11, 4, 13, -4, - -18, -3, 2, 9, -7, -1, 4, -6, 0, -11, 5, -1, -1, -8, -10, -6, - 6, -15, 20, 6, -25, 11, -5, -7, 12, 4, 0, -6, 6, 2, -1, 5, - 1, -11, 9, 20, -11, 14, -6, -15, 11, -11, 7, 1, -5, 2, -8, -2, - 12, -5, -16, 8, -4, -10, 2, 2, -6, -8, 5, 0, 3, 4, -17, 13, - 4, -9, 1, 5, 4, 8, -7, -3, 3, -2, 4, 14, -9, -6, -7, -3, - 11, -17, 0, 9, -10, 0, 1, 0, -9, -7, 8, 7, -3, 15, -22, 2, - 7, 0, 2, 4, -2, -6, -3, -1, 9, 2, -2, 1, -4, -1, -6, 2, - 4, -8, 3, -2, 1, 0, -9, 14, -6, -5, 3, -1, -6, 5, -5, -6, - 5, -5, -1, 12, -10, -6, -3, 9, -7, -8, 14, -5, -11, 9, -1, 5, - -5, 3, 1, 0, 1, 3, -7, 7, -1, 1, 4, 5, -16, 7, 6, -6, - -2, 11, -8, -9, 3, -9, -2, 15, -11, -11, 6, -1, -7, -4, 4, 2, - -9, 1, 1, -2, 0, 6, -3, -3, 6, -7, 6, 11, -11, -9, 0, 15, - -8, 14, -2, -13, 1, 4, 0, 7, -2, -10, -1, 8, -6, -4, 5, 1, - -6, 1, -8, 0, -4, 7, 4, -3, -8, -4, -3, 8, 3, -8, -3, 16, - -7, -1, 0, -1, -4, -2, 2, 6, -1, -2, -4, 5, 5, -4, -2, -8, - -6, 10, 4, -5, -2, -2, -2, 0, -4, 0, 2, 0, -12, 6, 2, 0, - 3, 2, -11, 2, 1, -2, 10, 1, -6, 9, -8, -3, 5, -1, 5, -2, - 0, -5, -7, 8, 5, -4, -9, -1, 1, -2, -7, 4, -12, -4, 5, 0, - -4, 5, -13, 8, 2, 4, 1, -10, -6, -3, 17, 4, 1, -7, 6, 2, - 1, -3, -1, 0, 7, -8, -2, 6, 2, -8, 0, 21, -16, -5, -1, -2, - 4, 0, -18, 11, -10, -4, 11, -4, -1, -2, 2, -3, 2, -2, -8, -1, - 1, -3, 8, 2, 0, 1, 5, -7, 2, -4, -1, 4, 5, 0, 1, -6, - -11, -6, 7, 8, 5, -7, -12, 7, 2, -6, -3, 7, -4, -3, -1, 2, - 9, 0, -7, 9, 5, -15, -3, -7, 2, 3, -2, 0, -3, 6, -13, -2, - 0, -5, 3, 9, -5, 9, -12, -9, 12, 4, 1, 5, 3, -4, -2, 3, - 11, -16, 2, 0, 10, -9, -4, 8, -4, -7, 2, 2, -6, 3, -22, 8, - 11, -7, -6, -2, -5, -5, -8, 3, 7, 12, -8, -1, 4, 8, -14, 4, - 13, -6, -8, 2, 17, -1, -3, 12, -10, -2, -7, 0, -6, 16, -17, -4, - 10, -9, -2, 1, 0, -1, -7, 7, -10, -3, 3, -1, -7, 11, -11, 3, - 3, 8, -6, -2, 1, 0, -15, 15, 5, 0, 7, -5, 4, -3, -2, 2, - -4, 10, -9, -9, 15, -6, -12, 14, 3, -7, 0, -9, -1, -5, 3, -4, - 3, 4, -14, -2, -1, 8, -3, 13, -5, -18, 12, -1, -7, 0, 5, -2, - -6, 14, 3, -9, 3, 1, -10, 0, 7, 3, -7, 4, 2, -14, 4, 4, - -6, 14, -4, -12, 6, 2, -10, 1, 5, -6, -10, 3, 8, -11, 9, -1, - -3, 2, -6, -8, 4, 2, -10, 6, 11, -7, 0, 2, 1, -10, 8, 6, - -5, 2, -2, 3, -4, 1, 4, -11, 6, 4, -8, 4, 4, -13, -4, 2, - 6, -3, 2, -4, -11, 11, 2, -13, 9, 3, -21, -2, 17, -4, -1, 6, - -11, -2, 1, -4, 4, 5, 0, 0, 1, 13, -8, 0, -3, 2, -6, 1, - 7, -4, 2, 2, -5, -5, 8, -14, -4, 8, -10, -1, 3, -4, -6, 6, - 5, -12, -6, 5, 1, -4, 2, -4, -1, 8, -8, 1, 8, -4, 6, -1, - 17, -8, -7, -1, 4, -1, 14, -5, 0, -6, -1, 0, -1, 2, -10, -7, - 0, 6, -6, 4, -12, -1, 7, -5, -2, 0, 3, 0, -9, 10, -8, -1, - -5, 11, -15, 6, 6, -1, 1, 1, -4, 4, -7, 12, -11, 10, 2, -15, - 5, 11, 5, -7, -7, 0, 0, -5, 11, 0, -5, -10, -12, 15, 1, -2, - -4, 2, 6, -9, -8, -3, -1, -5, 5, -4, 1, 5, -13, -1, 10, 0, - 0, -2, 1, 9, 0, 3, -7, 14, -2, 0, -2, 3, -12, 9, 4, 0, - -4, -7, 0, -6, -5, 5, -3, -5, -5, 4, 7, -13, -7, -6, 3, 1, - 0, 6, -3, -5, -4, 7, 1, 3, 1, -3, 5, 3, 3, 2, -1, 2, - 4, -9, 8, 2, -5, 6, -12, 7, -5, -8, -6, 9, -14, 4, -7, 4, - -6, 1, -2, -11, 4, -4, 2, 7, -4, 4, 5, -2, -4, -5, 6, 2, - 0, 5, 9, 3, -4, -7, 1, 6, 3, -2, -7, 1, 1, -6, 0, 8, - -12, -11, 7, -12, 0, 2, -5, 4, -1, -9, -2, 7, -8, 1, 1, 5, - 1, -4, 5, -8, 4, 2, -5, 7, 6, -6, -3, -8, 13, -2, -3, 2, - 0, 0, -5, 6, 5, -6, -3, -3, 2, 8, -12, 4, 7, -12, -10, 13, - -3, -2, 1, -5, 1, 1, -2, 5, -5, -6, -12, 4, 0, 4, 3, 3, - -10, -8, -3, 10, -5, 7, -8, 3, -1, 6, 0, 3, 6, 4, -6, 2, - 5, 5, -6, -4, -2, 4, -2, -9, -4, 7, -1, -12, 10, -5, -9, -11, - 1, 4, -8, 1, 7, -3, 4, -7, -1, 8, -5, -6, 9, -1, 0, 8, - 3, 7, -9, 6, -1, 9, -7, 2, 3, -4, -5, 6, -6, 8, -10, -12, - 4, 3, 1, -1, -9, -1, -4, -5, -3, 6, 7, -11, -4, 6, 0, -3, - 3, 4, -5, -4, 1, -3, 3, -2, 0, 1, -1, 3, -9, 7, 3, -7, - -2, 5, 5, -9, 7, 0, -8, 8, 1, -5, 6, -4, -6, 2, 6, -3, - 0, 0, -3, -9, -6, -2, 9, 2, -2, -11, 7, 9, -9, -7, 8, 0, - -7, 1, 4, -5, -3, -3, 5, 5, -3, -13, 7, 5, -6, 5, -2, 7, - -9, -8, 6, 2, -5, 3, 7, -4, -6, -7, 1, 7, 6, -5, -5, 6, - -10, 10, 1, -4, 4, -4, -2, 1, 9, -10, 0, 4, -8, -1, -5, -1, - 3, -2, 6, 1, -5, -5, -5, 2, -3, 3, 3, -1, 0, -4, 0, 9, - -1, -6, -6, 4, -1, 2, 5, 0, -2, -2, -4, 2, 4, -1, -4, 4, - 0, -3, -9, -2, 6, 0, -7, -1, 3, -2, -1, 2, 2, -7, -2, 0, - 2, 4, -6, 3, -3, 6, 0, 0, -2, -6, 1, 11, -2, -1, -8, 3, - -7, 1, -2, 6, -9, 6, 0, -1, 1, -6, -7, 5, -1, 2, -2, -1, - -1, 0, -3, 1, 2, -1, -3, -5, 3, 7, -9, 5, 3, -5, -5, 5, - -1, 0, 4, 4, -11, 8, -3, -10, 9, -7, -1, 1, -2, 1, -3, 6, - -3, -5, 2, 4, -7, 5, 2, -2, -3, 1, -2, -4, 2, 0, -4, 8, - 2, -12, 0, 6, -10, -2, 8, -6, -3, 6, -4, 2, 9, -4, -7, 2, - 5, -1, 1, 4, 0, -5, 2, -7, 2, 4, 1, -5, -1, 7, -5, -5, - 12, -7, -12, 6, -4, -3, 3, 4, -3, -5, -1, -3, -10, 9, -8, -2, - 6, -3, -4, 6, -1, 0, 3, 2, 1, -3, -5, 2, 0, 4, -3, -3, - 1, 4, -8, 0, 7, 4, -9, 0, 3, 1, 1, -5, -4, 3, -1, -4, - 4, 3, -8, -2, -2, -3, -1, 0, -3, -2, 3, -2, 1, 0, -1, 0, - -6, 8, -5, 5, -5, 5, -3, 5, -7, 1, -3, -1, -1, 2, 8, -2, - -5, 1, -3, -1, -4, -4, 9, -1, 1, -3, -2, 1, -14, 8, 3, -14, - 4, 1, 2, 2, 0, -5, 3, -1, 2, -2, 8, -8, -3, -3, 7, -1, - -3, -1, -3, 1, 5, -7, 7, -12, -1, 1, 4, 3, -7, 5, 6, -2, - 2, -6, -3, 0, -5, 2, 1, -1, 2, -7, 1, 8, -5, -4, -3, 2, - -2, -5, 3, 2, -3, -6, -1, 1, -4, 4, 5, 2, -14, -1, 3, -4, - 3, 10, 2, 2, -4, -1, 4, 3, -6, 2, 1, -2, -9, 7, -2, 1, - -4, -5, 1, -7, -1, 1, 2, 2, -1, -6, 5, -1, -12, -4, 11, -2, - -3, 6, -4, 2, 0, 0, -2, 0, 3, 2, 4, 2, -3, -6, 9, -10, - -4, 2, 4, -1, -5, -1, 2, 1, 2, -7, -2, -4, -4, -2, 7, 5, - -6, 0, 1, -1, -4, 2, -6, 3, 9, -11, -2, 8, 0, -5, 6, -1, - 3, -5, 6, 1, -10, -4, -3, 4, 10, -8, -2, 1, 4, -8, 4, 3, - -8, -5, 2, 4, -5, 6, -2, 2, 2, -3, -10, 0, -6, 2, 4, 12, - -4, -10, 6, 2, -5, 2, -3, 6, -4, 0, -6, -4, 7, 0, -4, 12, - 0, -14, 3, 2, 1, 1, 2, -7, -1, 3, -1, -4, 10, -9, -11, 6, - 4, -9, -5, -1, 5, 0, 6, -5, -5, -4, 3, -7, 9, 0, -1, 0, - 4, -3, -2, -1, -4, 0, 10, 3, -5, 4, -4, -6, 8, 0, -7, -3, - 17, -9, -8, -1, 3, -3, -3, 0, -4, -3, -5, -4, 8, 8, -9, -5, - 4, 0, -7, 6, 7, 3, -6, 3, -3, 1, -4, -4, 4, 10, 1, -5, - -2, 0, -9, 4, 1, 1, -4, -2, 6, -3, -5, 0, -6, 3, 0, -2, - 4, 1, 0, -4, 3, -1, -10, -2, -2, 2, 9, -11, 8, 3, -2, -1, - -1, -3, -1, -8, 4, 6, 2, -7, 2, -1, 3, -6, 0, 1, -1, 2, - 2, 3, -1, -13, 2, 9, 3, -5, -3, 2, -3, 5, -4, -2, 0, -4, - -1, 1, -4, 0, -4, 0, -2, -2, -5, 1, 4, -1, 1, -4, 1, 2, - 0, -2, 2, 1, 1, 0, 7, 0, -3, -4, -2, 5, 0, -3, -2, 3, - 2, -9, -1, -1, -1, -4, 1, 5, -6, 1, -4, 8, -12, 1, -5, 3, - 3, -1, -6, 9, -3, -2, 0, 4, 0, -3, 4, 10, -5, -4, -2, 0, - 2, -3, -2, -2, 0, 0, -3, 0, 3, -8, 0, -5, 1, 0, 5, 1, - 4, -14, -2, 1, 3, 1, 0, -1, 6, -2, 2, -5, 4, 1, -2, -3, - 1, 3, 5, -5, 3, -1, -8, 0, -3, 5, -7, 2, -4, 2, -4, 2, - -3, -2, -7, 4, 2, -2, -4, 5, -5, -3, 0, -4, 3, 5, -6, 5, - 8, -5, 0, 2, 1, -6, 0, 5, 1, -2, 6, -10, 7, -9, 3, -5, - 4, -1, -1, -4, 5, -6, 5, -1, -9, -1, 2, 4, -2, 0, 5, -9, - 1, 0, -2, 1, -1, -3, -1, 9, -1, -9, -2, 2, 1, 2, -2, 3, - -7, 3, -1, 3, -1, -5, -5, 9, 1, -1, -3, 2, -7, 1, 3, -4, - -2, 5, 3, -2, 0, -5, -1, -1, -3, 1, -2, 0, -1, -2, 7, -3, - -12, -1, -2, 0, 5, 4, -4, -2, 6, -3, -5, 8, -5, -4, 2, 6, - 1, -1, -1, -4, 4, 3, -6, -4, 6, -1, -4, 2, 2, -10, -4, 3, - 0, -3, 5, -4, -5, -1, 2, -5, -1, 2, -2, 1, 6, -2, -4, 5, - -2, 1, 4, 0, -2, 0, 3, 0, -2, -4, -6, 6, 3, -2, -1, -1, - 1, -1, 0, 0, -14, -1, 3, 0, 0, 4, -6, -2, 0, -2, -3, -3, - 3, -4, 7, 4, -4, -3, -2, 3, 1, 0, 1, 2, 5, -2, -6, -1, - 1, 1, -4, 3, 0, -2, -3, 2, -8, 1, -2, -5, 0, 2, -2, 6, - 2, -1, -7, 4, -5, 2, -4, -6, 5, 5, 2, -1, -3, -4, -7, 0, - 6, -3, 0, -4, 8, 1, -6, -1, 2, 0, -2, -1, 7, -5, -4, 0, - 7, 0, -5, -4, 3, -2, 3, -3, 1, 3, -1, -6, 2, 3, -7, 3, - 0, -3, -3, -2, -4, 2, -2, -1, -3, 2, -4, 0, 4, 2, -6, 1, - -1, 1, 1, 4, 1, 2, -4, 0, 0, 5, 0, -5, -5, 7, 0, -4, - -4, 2, -6, -4, 5, -1, -1, -4, -3, 3, -1, -6, 1, 4, -1, -3, - -3, 3, 4, -1, 3, 2, 0, -3, -3, 5, 2, -3, -1, 1, -1, -2, - -1, 2, 1, -5, -1, 1, -3, -3, -4, 0, 2, -3, -2, 0, 4, -1, - -2, 0, 3, -6, 0, 3, 5, -1, -2, 3, 0, -3, 0, -3, 8, -4, - -6, 4, 2, -5, 0, -1, 2, -5, -7, -2, 1, 2, 1, 0, -2, -1, - -2, 0, 4, 0, -5, 2, 7, 5, -5, 3, -3, 0, 1, 0, -2, 5, - -10, 0, 1, 3, -12, 1, -2, -1, 1, -2, -4, 3, -6, -2, 3, 0, - -6, 0, 2, 4, 2, -3, 6, 2, -7, 2, 1, -4, 9, 3, -1, 0, - -2, -7, 0, 5, 3, -6, 4, -8, -3, -3, -1, -3, 3, -3, -5, 3, - -3, 3, -1, 2, -7, -2, -1, -4, 2, 2, 4, 3, 0, 0, -1, -2, - 1, 4, -2, 2, -1, 2, -2, -1, -8, 2, 2, -3, -1, 2, -2, -5, - 0, -1, -4, -1, 5, 1, 3, -2, -1, 0, 2, 6, -4, -1, -6, -2, - 2, 4, 1, -2, -5, -4, 0, 3, -4, 1, 4, -1, -9, -1, 1, -1, - -2, -2, 2, 1, -5, 6, -1, 5, -4, -3, -2, 8, -2, 1, 5, 2, - -8, 0, 2, 0, 3, -3, -4, 3, -7, -6, 4, 1, -6, 0, 2, -2, - -4, -2, 2, 4, -5, -2, 3, 0, -5, 1, 7, 6, -4, -7, 4, 3, - -6, -3, 12, -3, -3, -5, -2, 2, -2, -7, -2, 10, -4, -5, 2, 0, - -3, -5, 3, -1, 3, -2, -3, 3, 6, -8, 2, 5, -3, -3, -5, 13, - -3, -1, 1, 1, -4, -3, 0, 3, -3, -2, -1, 1, 2, -7, -6, 3, - -7, -3, 3, 1, 2, 1, -7, 3, -3, -1, -5, 6, 3, -1, -6, 6, - 3, -2, -3, -1, 1, -3, 3, -5, 4, 0, -6, -3, 5, -1, -5, 8, - -2, -1, 0, -4, 5, -4, -5, -1, 1, 4, -1, 1, 5, -5, 3, -2, - -2, -5, -2, 2, 4, -2, 2, 1, -16, 5, 1, -1, -2, -2, 1, -4, - 0, -8, 2, 4, -5, 0, 6, -2, 0, 0, 0, -1, 2, -5, 6, -1, - -1, 2, -1, 4, -5, 1, 0, -4, -2, -3, 2, 2, 4, -3, 1, -9, - -1, 2, 0, 1, -1, -1, -4, 3, -7, 6, -4, 2, -4, 7, -3, -1, - 3, -7, 0, 10, -1, -8, 2, 2, -5, -5, 4, -2, -2, -7, -5, 4, - 2, 3, -11, 10, -6, -5, -4, 0, 9, -1, 0, 4, -6, -1, 3, -1, - 6, -6, -1, -1, 9, -5, -3, 7, -1, -1, 4, 2, -7, 3, -2, 0, - -2, 2, -9, 0, 4, -6, 0, 2, 3, -14, 4, -3, -12, 3, -1, 3, - -4, 4, -8, 6, 5, -3, -2, -4, 8, 0, -3, -1, 1, -4, 4, -3, - 7, 0, 1, -5, 1, 6, -10, 1, 8, -5, -8, 6, 4, -2, 5, 2, - -9, 4, -1, -1, 0, -4, -5, 3, 4, -11, 3, -7, -4, 1, 2, 0, - -3, -2, -7, 4, -9, 4, -6, -1, 2, -2, -1, 3, 9, -6, 2, -1, - 3, 4, 2, 3, -1, 0, -1, 1, 4, 0, -3, 3, 6, -7, -4, 4, - -3, 0, -5, -2, 2, 4, -1, -1, 0, -9, -4, -6, 14, -11, -5, -1, - 5, -6, -3, 3, -2, -6, 3, 5, -1, -4, 5, -7, 7, 4, -7, 6, - 4, -2, -4, 5, 8, -12, 3, -1, -5, 3, -3, 2, 10, -7, -12, 3, - -2, 5, -4, 4, 3, -6, -4, -6, 10, -4, 2, -3, 2, 0, -2, 0, - 2, 2, -12, -2, 13, -2, -6, 0, -5, 10, 1, -1, -2, 0, -12, 3, - 11, 0, -5, -9, 7, -4, 2, -3, 0, 9, -2, -6, 0, 3, -2, -13, - 1, 12, -7, -3, 0, -1, -4, -4, -5, 1, 5, -4, -7, 2, 0, -3, - 5, -2, 10, -12, 5, 1, 10, 8, -6, 4, -12, 7, -1, 5, 0, -1, - -2, 7, 4, -4, 5, -4, -20, 6, 1, -6, 5, 0, -14, 3, -12, 3, - -8, 6, -10, 2, -4, -3, 1, 4, -7, 4, 8, 2, 1, 2, 2, 3, - 3, 0, 7, -7, 3, -1, -1, 11, 3, 1, -6, 0, -8, -10, 8, 6, - -4, -1, -5, -11, 3, -1, -14, 6, -4, -13, 10, 0, 1, -5, 0, 0, - 1, -3, 7, 4, 3, 3, -1, 6, 1, -1, -6, 2, 2, -3, -4, 15, - -17, -4, 1, -3, 4, -4, -6, -2, 4, 4, -4, 3, -4, -7, -2, 13, - -1, -4, -2, -3, 9, -7, -12, 13, 10, -12, -3, 4, 13, -14, -6, 12, - -4, -10, 11, -5, 4, -1, -17, 9, -1, 4, -3, -5, 6, 0, -7, 3, - 2, 4, -9, -9, 13, -8, 7, 6, -8, 11, -15, -11, 16, -10, -2, 1, - -8, -1, 11, -1, -4, 2, -13, 9, 3, 11, -16, 4, 7, -9, 9, 4, - -16, 11, 9, -10, 13, 4, -10, -12, 2, 4, 4, -10, 7, -6, 0, -8, - -3, 3, -1, -4, -9, -9, 3, -5, -3, 24, -19, -5, 7, -11, 4, 9, - 1, -3, -1, 7, -4, 4, 4, -4, -7, 22, 0, -1, 10, -19, 3, 1, - -6, 9, -7, 3, -5, -5, 5, 9, -17, -2, 4, -9, -4, 5, -3, -7, - -3, 6, -4, 10, -12, -3, 13, -6, -5, 5, 3, 8, 0, -7, 0, 2, - -3, 12, 3, -10, -4, -8, 8, -1, -16, 13, -5, -5, 0, 3, -6, -8, - -2, 13, -5, 12, -4, -17, 11, 0, 2, 2, 3, -6, -3, -3, 4, 7, - -3, 1, -2, -2, -3, -4, 7, -3, -4, 4, -5, 6, -11, 5, 7, -10, - 0, 2, -6, -1, 5, -3, 3, -5, 5, -8, 4, 10, -8, 3, -4, 7, - -5, 3, -3, -2, 4, 2, -4, -7, 2, -3, -5, 6, -2, 5, -4, 6, - -10, -5, 5, 0, -8, 6, -6, -1, -3, 5, 2, 0, -4, 10, -12, -5, - -21, -1, -4, 5, 3, 2, 18, -14, 8, 5, 1, -4, -5, -2, -9, 0, - -12, 20, -4, 7, 1, 6, 7, -1, -5, 13, -1, -7, 6, -2, -5, 2, - 1, 4, 6, -7, 6, -9, -3, 6, -3, 8, -10, 8, -6, 0, -20, 1, - -5, 5, -4, -8, -12, -13, 8, -2, 17, 3, -5, -20, -1, -7, 3, 22, - 22, 12, -11, -13, -15, -9, 21, -3, 25, 43, -4, -3, -6, -21, -30, -37, - -9, 8, -5, 8, 53, 50, 1, -5, -13, -15, -41, -23, 6, -34, -47, -17, - -2, 2, -13, 22, 29, 32, 44, 51, 55, 10, 15, 7, 0, -31, -48, -38, - -48, -43, -13, 7, 4, -46, -23, -6, 6, 4, 12, 50, 26, 4, 24, 40, - 33, 20, 17, 17, -7, -30, 10, -2, -17, 5, -36, -7, -38, -30, -13, 1, - 9, -1, -6, -29, -15, -11, 7, 3, 6, 16, 27, -22, -8, 5, 24, 27, - 0, 4, -5, -5, -2, 15, 12, 12, 2, 13, 0, -19, -26, 4, -19, -24, - -33, -21, -28, 0, 6, 18, 20, 15, 40, 2, -8, 17, 21, 47, -2, -12, - 11, -9, 22, -19, 3, -27, -29, -10, -38, -36, -42, 33, 12, -29, 10, -15, - 0, -1, -22, 24, 27, 8, 15, 7, 16, -13, 9, 33, 8, -4, 33, 70, - 21, -26, -18, -15, -22, -76, -2, 15, -35, -4, 8, 5, -3, -45, 6, 24, - -20, 6, -15, 8, -1, 2, 7, -4, 39, 4, 22, 34, -25, 26, -1, -31, - -4, 10, 2, 22, -25, -19, -2, -2, -44, -29, -17, 10, -6, 29, -8, 12, - 18, -9, -6, -36, 4, -14, -8, 10, -12, 28, 9, 16, 17, -29, 26, 0, - 1, 11, -13, 11, 1, 7, -7, -3, -5, 22, -10, 10, -29, 22, -29, -30, - 29, -30, 3, -43, 21, 5, -18, 6, -5, 23, 18, -31, 35, 28, -19, 9, - 13, 10, -3, -10, 37, -69, 7, 11, -16, 8, -76, 11, 58, -57, 18, -7, - -11, 26, -40, 100, -53, -1, 14, 3, -26, -35, 21, 20, -30, 10, -26, 37, - 25, -97, 118, -72, 37, 11, -15, 52, -22, 6, 85, -32, 24, -63, 48, -60, - -19, 3, -28, -19, 7, -28, 15, -22, 7, 20, -7, 16, -13, 8, 25, -27, - 2, 7, -18, 15, -30, 23, -3, 28, -31, 34, 22, -23, -6, -6, 28, -68, - -10, -3, -22, 12, -43, 70, -52, 32, 8, -4, 55, -14, 19, 21, 45, -13, - -33, -9, 20, -22, -14, 9, -21, -2, 6, -56, 17, -26, 23, -13, -8, -1, - 3, 31, 16, 20, -12, -10, 50, -27, -17, -13, -26, 29, -23, -7, 58, -40, - -20, 16, 16, -13, -65, 63, 18, -25, 23, -3, 6, 11, -11, -24, -19, 8, - 32, -44, 47, -50, 26, 6, 43, -58, 15, -21, 46, -81, 60, -28, 65, -37, - 42, 42, -55, -6, -23, -9, -52, -25, -5, 7, -67, 26, 59, -62, 31, 63, - -23, 52, -16, 27, 14, -13, 19, -41, -8, 37, -7, 9, -33, 16, 7, 36, - -40, -26, -26, 49, -3, 3, -50, 33, 23, -10, -13, -14, -19, -13, 1, 2, - -41, -19, 32, -3, -29, 9, 58, 1, 9, 15, 19, -19, 59, 2, 6, -6, - -24, 52, -67, 3, 5, -37, 3, 31, -42, 45, -1, -31, -6, 19, 11, -17, - -5, -2, -22, 3, -35, 35, -39, 8, 17, 6, 7, -32, 2, -1, 40, -32, - -2, 26, -5, 2, -5, -12, 18, 21, -15, 29, -28, 13, -23, 36, 28, -75, - 55, -53, 50, -45, 9, -3, 42, -10, -33, 8, -9, -17, 8, 13, -13, 34, - -48, 39, -5, -26, 24, 19, -34, 29, -41, 22, -42, -11, -15, 37, 0, -31, - 15, 4, 11, 18, -28, 23, -3, -52, 33, -1, -8, 19, -39, 44, -3, -16, - 31, 7, -17, 38, -44, 62, -21, 0, -7, -13, 25, 12, -50, -13, 2, 9, - -47, 43, -29, -12, -3, -3, -37, -22, 0, -6, 60, -69, 27, 9, 12, 13, - -7, 46, 43, -2, 3, -5, -5, 17, 13, -37, 35, -39, -38, 33, -44, -10, - 11, -9, 50, -68, 26, -22, 10, -20, 34, -13, -17, 21, -34, -1, 42, -23, - -7, 9, 3, 1, -1, -9, 36, -15, 5, -21, 40, -47, 25, -11, 20, 24, - -19, 16, -13, 6, -25, -2, 19, -17, 7, -36, 28, -8, -28, -11, 9, 25, - -55, 7, 39, -36, -3, 8, 28, 25, -33, 29, 1, -28, -1, -7, 40, -50, - 22, 15, 21, -2, -1, 18, 8, 46, -52, -1, 14, -39, -10, 18, -10, -27, - -15, -9, 2, -7, -47, 23, 17, -40, 12, 37, -24, 22, 9, 5, 27, -14, - -17, -17, 23, 16, -18, 19, 32, -19, -10, 13, 12, -33, 31, -4, 12, -17, - 22, -3, -8, -33, 16, -45, -17, -13, -24, 23, 19, -22, 52, -63, 23, 26, - 8, -11, 30, 40, -35, 28, -5, 11, -10, -16, 18, -35, -21, -6, 9, 0, - -33, 9, -15, -24, 15, -23, -19, 30, 13, -20, 37, 24, -48, 47, 21, -31, - 51, -22, 40, -24, 47, -55, 31, -21, -57, 15, -7, -28, 5, 25, -12, -42, - 46, -43, -21, 6, 4, 14, -15, 11, 51, -27, 6, 21, -27, 42, 17, -35, - 3, 3, -15, 11, 17, -26, 0, 6, 11, 18, -37, 4, 28, -14, -14, -30, - 43, -50, -17, 55, -50, 16, -32, 51, -35, -13, -4, 54, -22, 23, -48, 51, - 2, 10, -16, 7, -10, 15, -48, 25, -5, -4, 6, 21, -17, -2, 30, -23, - 16, -3, -12, -11, 21, -57, 3, 10, -3, 0, -19, 36, -42, 50, 0, -30, - 55, -15, 12, -10, 28, -47, 29, -16, 6, -37, -1, -6, 3, -45, 35, -30, - 8, -4, -12, 32, 42, -23, 3, 5, 30, -38, 15, 16, -36, 60, -1, -53, - 28, -25, -10, 45, -20, 2, -22, 24, -6, -19, -31, 18, 6, -56, -15, -3, - -5, 1, 12, 5, -7, 70, -9, -7, 49, -31, 48, 36, -15, 5, -23, 35, - -51, 4, -32, -40, 7, -20, -15, -7, 17, -32, -2, 17, 1, -8, 46, -4, - 12, 15, 41, -50, 29, -21, -13, 10, -20, 12, 2, -24, 12, -1, 6, 8, - -29, 19, -27, 51, -67, 83, -44, -22, 21, -2, -14, 13, -52, 72, -37, 19, - -25, 43, -37, -22, 19, -12, -36, 14, 17, -3, 27, -39, 58, -23, 1, 14, - 52, -25, 15, -1, 1, -23, -11, -9, 4, 14, -83, 23, 4, -38, -21, 2, - -1, 17, 2, 48, -30, 24, 29, 9, 19, -44, 46, 22, 5, -32, 39, 0, - -28, -27, 16, -32, -31, 7, -17, -13, -9, -6, 14, -33, -18, 35, -39, 52, - -40, 31, 12, 14, -24, 52, -35, 11, 1, 26, 10, -18, 20, 7, -7, -5, - 7, 5, -15, -10, -7, 8, -10, -26, 21, -16, -14, 13, -27, 27, -44, 6, - 18, 6, -12, -4, -11, 12, -1, 7, 6, 3, 20, -5, 11, 15, 9, -10, - 37, -37, -3, 11, -23, 9, -35, 19, -32, 4, 14, -28, 41, -42, 43, -5, - 11, -20, -16, 20, -10, 6, 6, -4, 1, -6, 7, 20, -42, 25, -29, 34, - -31, -10, 14, -4, -9, -4, 13, 7, -7, -2, -19, 25, -10, 0, 16, -1, - -9, -6, 53, -52, 10, -7, 5, -10, 1, 4, 9, -24, 10, -21, 61, -40, - 3, 3, 12, -38, 31, -3, -7, 8, -13, 8, -15, 4, -33, 44, -29, 5, - 5, 37, -52, 16, -13, 25, 7, -34, 17, -7, 14, -11, 24, -32, 22, -23, - 42, 5, -30, 21, 19, -21, 2, -11, 14, -18, -16, -34, 41, -30, 7, 2, - -23, 20, -37, 26, -17, 18, -37, 64, 0, 14, -19, 5, 12, -8, -13, 22, - -9, -26, 24, 17, -8, 3, -5, -14, -14, 17, -30, 14, 26, -67, 38, -9, - -20, 11, 11, -22, 11, 15, 1, 11, -22, 0, 1, 38, -43, 2, 15, -31, - 2, -5, 29, -18, -27, 21, -8, 15, -20, 46, -24, 20, 16, -7, 24, -63, - 40, -8, 9, -8, 14, -10, -11, -28, 4, 10, 8, -26, 13, 11, -35, -1, - 40, -36, -5, -3, 38, -7, -23, 3, 4, 17, 3, -15, 11, 24, -67, 26, - 2, 21, -54, 30, 14, -34, 12, 25, -16, 12, -13, -7, 47, -24, -23, 7, - 18, -4, -19, 31, -18, -14, -11, 21, -15, 5, -31, 40, -53, 21, -4, 30, - -32, -3, 14, -5, 30, -17, 3, 13, 8, -4, -5, -11, -12, 8, -7, 16, - 10, -21, 35, -59, 13, 10, -3, -7, 1, 2, -16, -4, 27, -43, 35, -16, - -14, 36, 0, -51, 13, 31, -19, 14, 21, -19, 14, -3, -27, 29, -10, 34, - -46, 30, -12, -17, 11, -34, 23, -23, 10, -3, 4, -8, -14, 25, -16, 35, - -12, 22, -7, 3, 9, 0, 11, -5, -10, -16, 9, -21, 7, -36, -4, -13, - 4, -6, -7, -2, -1, 0, 14, 16, -15, 7, 27, -28, 43, -32, 17, 7, - -25, 33, -7, 6, -10, 11, -20, 1, 5, 28, -11, -26, 20, -17, 29, -40, - 1, -6, 13, -23, 23, -23, -28, 18, 5, -22, 16, -19, 41, -9, -16, -11, - 45, -17, 6, -51, 34, 36, -44, 29, -33, 22, -13, 3, 5, -26, 2, 11, - 23, -17, 0, -7, 12, 3, -27, 18, 13, -2, -30, 22, -6, 7, 1, -4, - 5, -1, 12, -14, 1, -15, -5, 12, 6, 3, -13, 15, -14, 14, -1, -12, - 3, 3, -4, -18, 7, 2, -7, -5, 9, -15, 7, 17, -27, 45, -52, 60, - -15, -12, -9, -11, -14, 27, -18, -9, 21, -10, 10, 3, -23, -4, 8, -23, - 19, -31, 12, 18, 12, -7, 1, 15, 3, 27, -38, -7, 42, -9, 1, -7, - -22, 5, -10, 0, -28, 5, 12, -6, 0, -12, -15, 18, 19, -14, -27, 47, - -6, -1, -21, 32, -31, 52, -41, 3, -39, 34, -29, 16, 8, -6, 33, 16, - -23, -10, 16, 9, 2, -33, 40, 0, -21, -2, -18, 1, 13, -32, 24, -11, - -14, 24, -20, 0, -19, 11, 23, 1, -30, 4, 38, -23, 11, 0, 9, 18, - -36, 10, -21, -1, -5, -1, 23, -24, 9, 27, -13, 4, -39, 60, -17, -11, - -12, 25, -9, -36, 26, -7, -3, 28, -27, 26, -12, -20, 8, 13, -40, 7, - -23, 38, -33, 14, 8, -1, -23, 36, -19, 15, 13, -36, 4, 17, -32, 31, - -23, 20, 0, 23, -3, 5, -17, -11, 12, -24, 21, -29, 34, -26, -1, 4, - -14, 21, 9, -1, -1, 21, -33, 29, 1, -28, 28, -20, 22, -24, -13, -13, - -6, 10, -22, 33, -49, 17, -24, 1, 22, -11, 43, -27, 28, 28, -33, 36, - 5, -5, 2, 22, -28, 16, -24, -16, 4, -69, 66, -47, -12, 19, -17, -1, - 24, -32, 46, -36, -3, 50, -26, 24, -22, 9, 39, -53, 0, 32, -1, -21, - 29, -26, -4, 29, -45, 12, -10, 11, -12, 20, -23, -11, 20, 10, -1, -24, - 33, -16, 12, 2, 4, 14, -17, -17, 20, -42, 6, -18, 0, -4, -10, 11, - 2, -10, 4, 7, 2, 27, -35, 11, 12, 4, -11, 19, -19, 40, -6, -16, - 44, 2, -10, 32, -37, 1, -23, -8, 23, -59, 11, -5, -9, -9, -1, -8, - 5, -18, 26, -14, 27, -10, 9, 30, 23, -31, 30, -1, -1, -14, -13, 35, - -76, 42, -79, 43, -29, 1, 2, -5, -6, 5, 30, 15, -20, 23, 25, -37, - 39, -5, -20, 24, -7, 2, 20, -38, 20, -31, -12, -2, -12, 13, -31, 10, - -9, 0, -11, 27, -16, 10, -2, 44, -46, 18, 33, -16, -12, 3, 11, 15, - -26, 8, -22, 19, -3, -11, 5, -48, 31, 16, -15, -5, -2, 17, 6, -9, - -8, 9, 25, -7, 0, 7, -8, -5, 10, -11, -26, 26, -15, 17, -31, -11, - 15, -1, -16, 1, 10, 4, -7, 18, -6, 2, 11, -2, 11, -26, -4, 25, - -27, -19, 7, 29, -29, 13, -10, 3, -27, 31, -55, 38, -13, 17, -9, 32, - -27, 17, 18, -3, -10, 17, -45, 58, -12, -18, 25, 4, -40, 35, -61, 10, - -3, 2, -15, -14, 33, -20, -2, -4, -19, 31, -29, 25, 8, -11, -3, 32, - 1, -26, 12, 25, -42, 5, 27, 1, 2, 17, -25, -2, 6, 9, -17, 9, - -11, 9, 9, -21, 11, 15, -55, 34, -24, -6, -1, -9, 17, -13, 1, -11, - 31, -24, -15, 38, -21, 27, -30, 30, -35, 28, 15, -30, 56, -40, -17, 39, - -9, -7, 4, -18, 7, 13, -25, 3, -9, -13, -13, 27, -35, 13, 0, 6, - -3, 26, -20, 27, -23, 25, -25, 38, -2, -3, 8, -11, 0, 0, 0, -28, - 28, -27, -6, 23, -33, -8, -1, -29, 0, 2, 26, -40, 15, 2, 23, 28, - -32, 17, 26, -17, 10, 1, -14, 17, 1, 14, -9, -10, -15, 12, -3, -19, - 2, 20, -19, -19, -14, 4, -2, -8, 13, -16, 22, -9, 28, 7, -9, -22, - 49, -28, 3, -5, 9, -2, 5, -26, 39, -12, -29, 19, -11, 7, -33, 27, - -32, 15, -9, -9, 16, -7, -3, 27, -4, -18, 19, 23, -20, 3, 2, 11, - -21, 14, 4, -13, 8, -15, 9, 4, -37, 9, -11, 22, -20, -12, 17, 12, - -20, -2, 13, 18, -19, -1, 19, -28, 12, 2, 12, 2, -37, 12, 21, -19, - -23, 17, 21, -35, 9, 26, -20, -15, 12, 14, 23, -20, 17, 9, -16, -4, - 5, 3, -8, -24, 13, -5, 5, -7, -11, 31, -24, -34, 28, -8, -26, 16, - -7, 2, -2, 9, -21, 42, -54, 34, 42, -22, 16, -1, 14, -15, -12, 21, - -16, -3, -18, 55, -46, 11, 6, -19, 18, -36, -9, 12, -21, 23, -41, 37, - -12, -10, 1, 13, -5, -7, 42, 2, 1, -2, 4, -3, 15, -53, 27, -3, - -26, -14, 32, -30, -5, 11, 12, -3, -4, -24, 35, -37, 12, 4, 5, -17, - 32, 0, -18, 41, -41, 43, -2, 22, -36, 7, -5, 11, -25, 7, -29, 9, - 2, -4, -11, 5, -2, 15, -31, -11, 24, 3, -15, 26, 11, -10, 18, 5, - -8, -2, -43, 43, 2, -43, -20, 25, 4, -3, 39, -11, -6, -3, -1, -12, - 22, -21, 6, 22, -7, -17, -5, 18, -4, -14, 3, 18, -11, -18, -3, -2, - 2, -5, 1, 10, -28, 17, 8, -8, -12, 23, -13, 10, 0, -12, 14, 11, - -11, 34, -21, 3, 1, -9, -17, 1, 9, -28, 5, -34, 21, -8, 8, 8, - -13, 18, 2, -15, 5, -3, 11, -2, 11, -2, 15, -10, 14, 5, -1, 18, - -6, 1, -26, 13, -25, 2, 6, -39, -14, 0, -5, 13, -22, -14, 34, -22, - -1, 16, -13, 11, 32, -10, 31, -5, 18, -21, 34, -47, 32, -9, 10, 8, - -31, 5, 4, -9, 5, -52, 16, -14, 4, 20, -11, -13, 13, -10, -12, 11, - 16, -20, 13, -12, 14, 10, 1, -15, 32, -24, 18, 0, 5, -26, 6, 16, - -23, -10, 12, -40, 17, -14, -13, 38, -5, 5, -19, -3, 17, 14, -8, 8, - -15, 21, -6, 10, -12, -16, 27, 6, -35, 16, -26, 45, -25, -1, -9, 29, - -25, 8, -31, 9, 25, -10, 4, 11, -22, -5, 1, -12, 6, -10, -11, 17, - -31, 5, 21, -6, 33, -55, 47, 6, -6, 2, 11, 14, -11, 10, -14, -26, - 8, -18, 4, 11, 6, -4, -2, -20, -2, -26, 38, 4, -24, -6, 7, 22, - -15, 30, 0, 13, 3, -11, 4, -10, -28, 38, -14, -9, -5, -45, 40, -21, - -28, 31, 0, -9, 18, -45, 20, 12, -20, 39, -25, 14, 1, 17, -4, 29, - -12, 26, -8, -21, -19, 10, 3, -31, 34, -16, -12, 5, -14, -4, -13, 13, - -7, 13, -15, -23, 40, -27, 15, 4, -11, 23, -20, -2, 7, 8, 3, 2, - -4, 1, 7, -22, 42, -37, 24, 1, -9, 16, -31, 9, 6, -3, -25, 40, - -41, 0, 2, -7, 18, 0, -10, 21, -5, -17, 29, -37, 27, 3, -22, 10, - 11, -5, 13, -17, 15, -19, -23, 17, -10, -35, 20, 4, -4, 3, -10, 7, - 15, -14, 10, -3, 10, -25, 13, 1, 20, -13, 13, 19, -38, 18, -4, 19, - -10, 9, -27, 19, -35, -8, -10, 39, -14, 2, 14, 36, -16, -8, -8, -7, - -2, -11, 4, 1, -42, 51, -17, 10, -15, -33, 29, -25, -7, 6, 2, 11, - 3, -20, 37, -28, 6, 34, -22, 5, 28, -4, 17, 5, -47, 28, 1, -3, - -21, 8, -6, -7, 10, -15, 6, -30, 6, -19, 1, -4, 30, -22, 29, -13, - -4, -2, 11, -1, -15, 38, -4, -9, 25, -29, -17, 10, -2, -3, 7, -15, - 24, -26, 21, 2, 6, -20, 10, -26, 41, -33, 19, -11, 6, -3, -9, 5, - 3, -21, 8, -5, -7, 10, 13, -10, -3, -4, -10, 26, -1, 1, 5, 11, - -3, 2, 23, -35, 21, -43, 17, -4, 2, -24, 14, -22, -3, 3, -5, -2, - 12, -13, 16, -5, 7, 17, 4, -44, 26, 17, -4, 36, -58, 43, -20, 8, - 3, -23, -18, -17, 16, 4, 3, -33, 15, -4, -10, 19, -20, 23, 13, -6, - -4, 25, -12, 21, -9, -4, 6, -1, 23, -7, -15, 3, -15, 3, -13, -23, - -3, -32, 4, 6, -18, 0, 11, -14, 42, -37, 26, -20, 50, -18, 18, 11, - 4, 18, -5, 8, -22, 30, 5, -20, 16, -20, -28, 2, 4, -10, -10, -10, - -27, 38, -38, 14, -17, -20, 34, -11, -5, -5, 10, 5, 25, -20, -2, 28, - -8, 26, -39, 68, -50, 53, -35, -5, 3, -23, 24, 8, -21, -28, 19, 6, - -18, -13, -7, 26, -7, 0, -4, 7, -7, -15, 29, -10, -12, 13, 9, -4, - -34, 39, -49, 38, -31, 29, -26, 2, -18, 45, 3, -16, -2, 29, 4, -27, - 2, 17, 6, -12, -3, 12, -12, -14, -22, 11, -13, 6, -2, 30, -39, 12, - 5, 10, -18, 3, -5, 24, -39, 15, 49, -42, 19, 9, -25, 5, -60, 31, - -19, -8, 9, 28, 28, -34, 21, -4, 25, 24, -18, 17, -35, 1, 7, -28, - 32, -29, 6, 7, 4, -23, 21, -17, -14, 16, -29, 21, -43, -24, 2, 58, - -33, 60, -20, 24, -29, 18, -24, 29, -14, -6, 10, -19, 15, 38, -38, 35, - -15, -11, 20, 9, -57, -4, 0, -8, 15, -8, -20, -6, 9, 21, 8, -21, - 12, 1, 6, -29, 24, 17, 6, -33, 26, 20, -12, 14, -17, 3, -2, -19, - -6, 13, -55, -5, 5, 8, 21, -12, 11, -13, 15, -34, 45, -47, 43, -6, - 5, 34, -32, 28, -15, 12, -38, 30, -16, 1, -4, -2, 6, 4, -26, 2, - 21, -42, 5, 19, -20, 44, -70, 38, -5, -4, -8, 20, -16, 22, -25, 46, - -21, 1, -31, 48, -32, 7, -23, 62, -48, 38, -2, -30, 41, -57, 41, -41, - 9, -5, 16, 9, 1, -50, 80, -48, 5, -20, 11, -9, -19, -8, 1, 20, - -24, 4, 36, -42, 42, -32, 39, 6, -12, 1, 12, 3, -17, 2, -13, 57, - -70, 26, 6, 0, -23, 8, 4, -17, -10, -41, 34, -10, -46, 51, 23, -10, - -4, -10, 16, -9, 4, 32, -14, 6, -7, 23, -18, -9, 5, -14, 4, 15, - -29, 10, 15, -14, 19, -28, 40, -30, -20, 17, 3, 5, 37, -32, 12, 0, - -18, 1, -7, -23, 4, -51, 69, -22, -43, 30, -39, 54, -64, 29, 21, -2, - 2, -22, 29, 2, 14, 5, 8, -7, 7, 34, 2, -25, 10, -7, -5, 24, - -64, -1, -18, -7, 23, -24, 26, -23, -35, -17, 51, -60, 53, -2, 14, 17, - 6, 5, 11, -9, 15, 21, -1, 21, -49, 45, -34, -16, 12, 0, -34, 2, - -67, 50, -48, 23, -20, -12, 20, -22, 32, -15, 15, -23, 65, -9, 33, 26, - -3, 4, 14, 8, -17, -17, -47, 57, -63, 13, 8, -30, -8, -31, -12, 28, - -45, 9, -3, 19, -31, 31, -2, 41, -46, 38, 38, -23, 21, -13, 9, 35, - -2, 5, 13, -36, -2, -10, 15, -16, -48, 22, 29, -49, -21, 15, -10, -15, - -23, 26, 40, -39, 26, -10, 13, 21, -46, 35, -20, 8, -1, 30, 17, -64, - 22, 2, 22, -30, 6, 19, -18, -34, 38, -4, 13, 0, -11, 50, -51, 21, - -10, 13, -42, -9, 45, 4, -82, 12, 37, -11, -12, -8, 21, 6, -33, 32, - -14, 6, 13, -44, 37, -22, 20, 2, 12, -15, 26, 30, -17, -11, -30, 18, - -4, -5, 11, -2, -22, -15, 25, -16, 11, -15, 21, -8, -17, -9, 27, 11, - -43, 2, 4, 31, -59, -5, 44, -16, 26, -13, 3, 1, -1, -40, 70, -44, - 43, -15, 2, 22, -36, 13, 41, -43, -12, 4, 12, -34, -22, 9, 22, -23, - -22, 27, -24, 22, -18, 45, 12, -32, 7, 17, -24, -15, 4, 20, 6, -40, - 29, 48, -64, 28, -3, -6, 43, -22, -34, 36, -41, 13, -2, -59, 72, -53, - 39, -30, -3, 16, 29, -40, 5, 30, -21, 15, -35, 9, 14, 2, 4, -16, - 4, 8, 14, 1, 30, -32, 5, -14, 28, -26, -1, -12, -16, -4, -22, -5, - 28, -8, -24, 7, 42, -22, -3, -9, 16, 38, -42, 25, 8, 10, -9, 38, - -28, 31, -8, -34, 22, -70, 21, 15, -36, -10, -15, -1, 49, -37, -17, 51, - -24, 11, 30, -27, 33, -39, -12, 36, -4, -49, 38, 12, 10, -17, -11, 59, - -26, -59, 33, 28, -37, 17, -39, 40, -16, -29, 28, 14, -19, -14, 18, 23, - -17, -16, 15, -11, 9, -16, 45, -25, -27, -1, 40, -36, 1, 19, -1, -14, - -3, 1, 29, -9, -58, 54, -12, -19, 16, 13, 29, -74, 48, -20, 22, -66, - 3, 23, 2, -31, 11, 41, -41, 2, 25, 4, 8, -3, 8, 23, -10, -6, - 27, -1, -67, 31, -29, 29, -29, 0, 17, -20, -18, -10, 29, -45, 43, -35, - 61, 4, -49, 31, -10, 53, -60, 19, 11, 15, -22, -3, -20, 26, 3, -60, - 59, -41, -26, 17, 22, 12, -6, -12, 30, -14, -8, -7, 16, 54, -34, -18, - 26, -15, -11, 7, -44, 39, -52, 48, -53, 18, -38, 3, 13, -11, 37, -12, - 11, 9, 14, -7, 40, -19, -6, 6, -15, 29, -34, 1, 18, -18, -9, -24, - -30, 17, -50, 31, 4, 8, 17, -7, -5, 0, 17, 25, 16, 15, 43, -54, - 39, -10, 2, -40, -23, 26, 3, -61, -2, 15, -6, -56, 46, -2, 16, -80, - 43, 52, -9, -30, 41, 17, 2, -33, -7, 52, -7, -29, 31, 0, -23, 10, - -24, 44, -82, 18, 45, -14, -40, -40, 40, 12, -66, 0, 74, -35, -5, 17, - 67, -59, 32, -4, 29, -1, -48, 39, 1, 8, -63, 43, -12, -37, -5, -12, - 25, 2, -21, 7, 24, -34, -11, 19, 28, 6, -34, 44, 13, -35, -19, 28, - -50, -13, 56, 7, -32, -12, 19, 6, -1, -6, 6, 0, 17, -26, 41, -20, - -5, -6, 43, -58, 10, -12, -14, 74, -84, 74, -28, -15, -27, 19, -15, -3, - 17, 24, 10, -60, 64, 0, -9, -39, 1, 25, -12, -25, 22, 8, -21, -40, - 73, -32, -18, -11, 6, 57, -52, 36, -19, 37, -40, 9, 2, 14, -15, 27, - -33, 35, 7, -37, 24, 10, -66, 17, 1, -10, 13, -38, 15, -9, 43, -30, - 19, -15, 17, -8, 7, 8, -38, 66, -55, 10, 9, -37, 37, -32, -11, 47, - -14, 11, 37, -41, -33, 12, 3, 34, -59, 35, 14, -4, -7, -2, -21, 48, - -52, 49, -8, -44, 0, 11, -6, -2, 11, -35, 64, -38, -35, 64, 7, -32, - 15, 15, 19, -39, 18, -31, 25, 6, -28, 25, 17, -34, -26, 21, -18, 15, - -15, -31, 24, -4, -26, 41, -2, -18, -24, 75, -21, 1, -6, -2, 16, 12, - -24, 15, 8, -14, 7, 7, -4, -37, 45, -67, 39, -41, 9, 19, 13, -60, - 44, -22, 23, 2, -35, 14, 35, -25, 7, 21, -39, 15, 1, 39, -43, 26, - -18, -14, 36, -10, -16, -15, 29, -34, 16, -1, -13, 24, 0, -43, 55, -18, - -31, 22, -15, -15, 43, -33, 50, -10, -43, 22, -27, 60, -30, 14, 0, 10, - -3, 10, -20, 11, -34, -7, 70, -59, -26, 25, -23, 7, -29, 8, 11, -13, - -8, 3, 13, -13, 35, -8, 34, -33, 9, 30, -5, 33, -37, -10, 56, -38, - -5, 14, -50, -24, 39, -11, -11, -27, -22, 46, -13, -6, -1, -6, 37, -56, - 48, -11, 24, -14, 32, -13, -1, 5, 8, 37, -86, 36, -1, -6, -12, 13, - -40, 3, 9, 15, -13, -23, 3, -15, 61, -50, -12, 29, -14, -2, 25, -31, - 52, -41, 31, 31, -27, -10, 9, 22, -15, 3, -11, 22, -25, 8, -40, 0, - -5, 2, -9, 40, -62, 5, 16, -6, -7, -21, 31, 29, -28, -3, 47, -31, - 51, -34, 59, -32, -8, 44, -7, -2, -20, 3, 64, -51, -58, -3, 0, -39, - 26, -22, 14, -39, 8, 20, -30, -2, 7, 8, 37, 15, -9, 43, -5, 2, - 11, -5, 10, 2, -37, 56, -59, -11, 8, -14, -30, -29, -3, 29, -1, -33, - 42, -44, 53, -58, 85, -28, -5, -2, 41, 5, 15, -49, 30, 26, -46, 17, - 9, -55, 0, 38, -46, 32, -32, 10, 15, -60, 8, 23, -1, 7, -35, 71, - -11, -39, 39, -22, -8, -3, 10, 36, 13, -73, 53, -15, 7, -7, -15, 25, - -7, -24, 21, 9, -51, -11, 27, -15, 11, -6, 26, -26, 27, 16, -33, 47, - -29, -18, 53, -53, -2, 38, -29, 12, -37, 18, 10, -10, -20, -8, 12, 15, - -43, 32, 3, -44, 35, 29, -38, 17, -16, 13, 45, -37, 21, 18, -7, -38, - 32, -21, -6, -4, 20, -14, -9, -16, 14, 1, -19, -13, 22, -4, -39, 58, - -34, 3, 17, -10, 50, -3, -47, 36, 29, -27, -13, 39, -20, -8, 12, -40, - -20, 1, 0, -24, 23, -40, 38, 4, -1, -19, 16, 10, -4, 28, -25, 44, - -17, 19, -21, 50, -10, -16, -13, 7, -28, 11, -9, -17, 13, -52, 22, -3, - -21, -49, 75, -42, 34, -3, 18, 1, 10, -20, 13, 13, 22, -11, -35, 46, - -29, 44, -39, -31, 37, -22, -27, 42, -57, 40, -34, 4, 12, 9, -29, 13, - 6, -10, 4, 21, 7, -17, 3, 25, -18, 44, -26, -1, 20, -38, 19, 24, - -35, -18, -6, -14, 23, -32, -15, 24, -6, -50, 62, -39, -3, 0, -23, 87, - -44, 37, -9, -4, 67, -73, 46, 45, -32, -14, 8, -4, -22, -5, -22, -20, - 36, -34, 6, 26, -35, -18, 15, 0, -12, 0, 12, -10, 28, -15, 24, 13, - -21, 19, 15, -17, 20, -7, 0, -21, 7, -16, 5, -12, -1, -11, 7, 32, - -68, 69, -55, 24, 2, -3, 21, -47, 28, 20, -15, -29, -2, 23, 4, -18, - 15, -22, 36, -38, 17, -23, 14, -18, 17, 31, -37, 30, 8, -1, -3, -5, - -12, 22, -18, -28, 33, 0, -9, -16, 20, 9, -26, -20, 21, 2, -4, 14, - -24, 16, -11, 12, -1, -39, 7, 51, -2, 1, -12, -30, 63, -43, -19, -2, - -6, 20, 10, -18, -2, 23, 15, -3, -34, 1, 9, 10, -22, -29, 28, 28, - -32, -2, 23, -26, 2, 11, 25, -35, -14, 15, 23, -48, 12, 7, 22, -52, - 25, 17, 16, -47, 29, 13, -19, 12, -67, 65, -6, -30, 32, 7, -12, 14, - -19, 27, -52, -2, 15, 40, -69, -5, 33, 15, 6, -51, 36, 21, -2, -24, - 15, -3, -9, -4, 30, -34, -2, -19, 27, -23, 3, -12, 2, 18, -15, -6, - -3, 22, -30, 55, -21, 26, -35, 44, -27, 25, -21, 4, 14, -20, -1, 10, - -42, 12, 7, -12, 5, -37, 13, 1, 3, -33, 24, 15, 0, -4, 10, -14, - -6, 35, -6, -4, -8, 13, 26, -7, -32, 36, -9, 5, -15, 14, -15, -36, - 8, 2, -15, -22, -7, 28, -4, -25, 17, 39, -16, 4, 20, 8, 4, -2, - 4, 31, -46, -12, 15, 0, -9, -36, 18, -10, -12, 7, -17, 3, -13, -4, - 37, -27, 6, -16, 76, -41, 13, -14, 25, 28, -21, -10, 31, -4, -39, 21, - -9, -35, 12, 3, -16, 7, -54, 51, -34, 44, -45, 30, -7, -30, 49, -21, - -1, 27, 12, -8, 9, 8, 5, -27, 42, -30, 32, -28, -27, 19, -18, -36, - 10, -25, 19, -9, -14, -5, 13, 31, -21, 22, -28, 15, 13, 10, -12, 6, - 32, 1, 24, -47, 36, -4, -23, 0, -16, 6, -41, 1, 17, -33, -9, 5, - 34, -5, -15, -1, 30, 13, -30, 20, 7, -12, -16, 11, 20, -4, -19, 21, - 26, -25, -17, -5, 23, -32, -3, -12, 18, -5, -28, 8, 15, -14, -10, 31, - 11, -43, 12, 35, -5, 3, -33, 48, -1, -11, -6, 28, -23, -13, 13, 9, - -7, -22, 2, -25, 32, -38, 17, -16, 10, -54, 69, -62, 61, -30, 4, 24, - 3, -12, 4, 27, -22, 22, 0, 4, -15, 4, -46, 20, -16, 29, -30, 14, - -25, 30, -18, 16, -12, -7, 21, -10, 16, -23, 15, 9, -12, 12, 13, -21, - 19, -28, -2, 5, -15, 0, 3, -17, 6, -6, 18, -11, 6, 13, -1, 15, - -23, 14, 5, -17, -14, 5, 24, -23, 15, -26, 9, -10, 15, -29, 2, -12, - 23, 8, 10, -37, 26, 7, -5, -25, 3, 16, 14, -10, -5, -16, 22, -7, - -8, 18, -58, 86, -15, -5, 4, -30, 40, -7, -21, -12, 9, -10, 16, -48, - 40, -29, -6, -5, -22, 21, 3, -20, 39, -36, 29, -5, 2, 3, 15, 2, - 6, 21, -11, 28, -13, 2, -33, 24, 1, -28, 12, -33, 12, 11, 0, -41, - 11, -5, -9, 26, -34, 15, 2, 18, -7, -25, 5, 11, -4, -7, 35, -6, - 23, 12, -42, 33, -32, 26, -41, 25, -23, 15, -13, 11, -5, -4, 0, -8, - -4, 1, 10, 6, -8, -7, 18, 8, -11, -19, 9, 17, -2, -13, 8, -21, - 31, -16, -24, 3, -12, 10, 23, -8, 12, 8, 23, -7, -22, -8, 5, -5, - -14, -33, 4, 7, -11, -11, 15, -22, 38, -2, -11, 24, -16, 38, 14, -6, - 7, -14, 18, -13, 2, -8, -14, 13, -19, -13, 2, 2, -23, -9, 11, 1, - -12, 16, 1, 2, 18, 1, -20, 9, -5, -14, 16, -11, 2, 8, -2, -9, - 0, 11, 13, -22, 18, -16, 35, -39, 45, -22, -18, 12, 1, -19, 21, -48, - 42, -20, 9, -23, 20, -11, -27, 21, -13, -14, -11, 29, -13, 25, -25, 36, - -13, 8, 17, 34, -14, 11, 4, -4, -15, -9, -12, 1, 19, -69, 7, 10, - -34, -20, 1, -5, 13, 6, 34, -17, 5, 40, -1, 21, -38, 35, 22, 11, - -28, 28, 11, -25, -26, 12, -20, -38, 10, -16, -11, -11, -6, 13, -22, -31, - 43, -42, 49, -33, 20, 17, 13, -22, 44, -21, -4, 14, 9, 33, 10, 0, - -1, 0, 0, -2, 11, 23, 22, 24, 25, 20, 21, 15, 40, -1, -24, -42, - -5, -19, -11, -8, 4, -46, -31, -14, -33, -40, -44, -48, -89, -63, -47, -33, - -27, -10, -6, 22, 25, 26, 28, 37, 11, 15, 51, 44, 54, 66, 66, 71, - 111, 84, 70, 63, 47, 39, 22, 47, -28, -79, -111, -90, -91, -112, -81, -87, - -49, -46, -5, -24, 26, 24, 47, 29, 23, 30, 30, 13, -1, 4, -14, 17, - 35, 62, 31, 53, 59, 72, 64, 27, 26, 9, 9, -61, -44, -88, -74, -81, - -83, -124, -96, -37, -78, -48, -56, -68, -60, 7, 44, 39, 54, 77, 102, 110, - 108, 89, 101, 100, 105, 64, 22, -1, 44, 40, -19, -29, -35, -16, -27, -40, - -77, -82, -113, -104, -93, -57, -72, -56, -3, 1, 7, -1, 49, 39, 30, 31, - 23, 10, 31, 11, 7, -19, -2, -2, 28, 62, 92, 75, 33, 34, -20, -47, - -61, -85, -105, -93, -119, -112, -54, -70, -67, -32, -1, 4, 4, 20, 29, 62, - 70, 54, 62, 78, 115, 92, 85, 78, 52, 21, 19, 27, 2, -8, 13, 0, - 5, 3, 9, 18, 0, -59, -61, -45, -57, -65, -76, -89, -102, -48, -24, 17, - 6, 26, 33, 35, 26, 41, 63, 20, 12, 29, 34, 8, 7, 31, 21, 31, - 39, 33, -5, -8, -55, -57, -98, -94, -88, -64, -82, -74, -39, -14, 3, 16, - 22, 8, 2, 17, 5, 36, 76, 74, 71, 57, 73, 62, 47, 30, 32, 19, - 4, 7, -14, -18, -2, 17, -5, 13, 22, 31, 10, 8, -13, -47, -80, -85, - -86, -71, -73, -60, -35, -10, 9, 19, 49, 53, 47, 60, 73, 43, 33, 20, - 13, -1, -7, -7, 7, 9, -2, 5, -14, -40, -69, -61, -66, -67, -84, -58, - -58, -33, 2, -7, -5, 12, 32, 18, 25, 19, 24, 65, 59, 62, 64, 63, - 55, 60, 52, 31, 19, -12, -26, -4, -7, -10, -3, 6, -22, -14, 12, 19, - 4, -26, -38, -40, -56, -61, -66, -59, -65, -51, -20, 29, 40, 51, 52, 62, - 61, 53, 26, 20, 6, 8, 6, 9, -14, -14, -15, -2, -11, -23, -36, -38, - -60, -77, -69, -60, -51, -56, -44, -27, 10, -2, 14, 10, 22, 16, 41, 60, - 39, 35, 60, 62, 43, 45, 63, 52, 17, 12, 15, -1, -2, 0, -38, -48, - -32, -22, -7, 3, 13, 10, -2, -1, -8, -12, -25, -48, -46, -52, -49, -36, - -17, 9, 17, 26, 48, 57, 55, 69, 60, 32, 6, 4, -6, -20, -24, -9, - -21, -25, -14, -18, -38, -38, -32, -51, -52, -60, -34, -6, -6, -16, -11, -2, - -1, 17, 19, 3, 11, 25, 31, 41, 39, 33, 33, 41, 34, 34, 23, 21, - 15, 6, -13, -24, -28, -20, -8, -12, -19, -12, -5, 9, 14, 2, -12, -25, - -28, -21, -28, -23, -22, -18, -26, -5, 24, 45, 46, 47, 39, 33, 36, 42, - 29, 7, -5, -10, -21, -29, -39, -39, -31, -24, -29, -39, -51, -43, -27, -22, - -18, -25, -26, -20, 9, 19, 18, 4, -2, 19, 30, 38, 25, 24, 28, 33, - 41, 38, 34, 32, 38, 24, 8, 4, -8, -11, -15, -25, -31, -25, -20, -22, - -15, -11, -9, -12, -17, -20, -20, -15, -6, -11, -8, 0, 11, 29, 19, 17, - 17, 18, 28, 31, 25, 18, 23, 18, 10, 1, -7, -18, -26, -24, -30, -41, - -38, -44, -32, -31, -31, -35, -25, -12, -2, -8, -11, -13, -13, -2, 8, 15, - 19, 29, 35, 37, 39, 43, 42, 40, 35, 27, 25, 18, 15, 9, 4, -4, - -15, -28, -28, -26, -28, -18, -15, -25, -23, -12, -11, -14, -10, -2, -4, -1, - 8, 15, 19, 22, 25, 16, 16, 17, 5, 7, 13, 18, 13, 9, 6, 6, - 4, -4, -21, -31, -28, -37, -39, -34, -38, -38, -32, -17, -6, -4, -14, -19, - -9, 3, -2, 3, 4, 7, 8, 13, 23, 35, 38, 43, 42, 31, 25, 23, - 17, 8, 3, 4, -7, -7, -10, -13, -20, -19, -28, -33, -30, -23, -18, -13, - -17, -12, 3, 14, 23, 31, 27, 23, 21, 22, 19, 12, 4, 2, 2, -2, - 0, 4, 11, 11, 6, 4, -2, -5, -14, -17, -30, -38, -44, -42, -28, -21, - -23, -21, -15, -15, -4, 8, 11, 4, -7, -15, -7, 5, 10, 21, 26, 28, - 27, 34, 37, 36, 28, 19, 10, 11, 8, -2, -18, -17, -19, -19, -22, -24, - -21, -24, -18, -17, -13, -19, -13, -1, 12, 19, 22, 21, 19, 19, 30, 34, - 24, 13, 7, 2, 1, 1, 2, -1, -2, -6, 0, 0, -2, -15, -21, -17, - -21, -28, -32, -31, -31, -32, -27, -24, -17, -4, 1, -3, -1, 1, 4, 7, - 8, 15, 16, 15, 15, 20, 32, 36, 38, 32, 19, 12, 3, 2, -2, -4, - -11, -19, -17, -15, -11, -16, -20, -27, -30, -28, -22, -13, -6, -2, 2, 12, - 23, 29, 45, 44, 36, 32, 21, 16, 14, 10, 1, -9, -8, -2, -1, -7, - -13, -13, -12, -9, -11, -18, -24, -26, -28, -30, -24, -21, -21, -21, -11, -11, - -10, 0, -2, 0, 4, 12, 13, 14, 12, 17, 22, 28, 30, 28, 20, 16, - 13, 8, 2, -2, -6, -15, -14, -18, -15, -15, -16, -18, -18, -16, -19, -18, - -17, -10, 0, -1, 4, 13, 22, 37, 39, 36, 27, 27, 32, 26, 15, 6, - -1, -4, -5, -7, -11, -11, -9, -15, -15, -14, -18, -21, -19, -17, -21, -19, - -15, -15, -10, -15, -14, -12, -11, -6, -2, 1, -2, 1, 5, 14, 22, 33, - 35, 23, 18, 16, 13, 11, 6, 1, -9, -18, -11, -6, -7, -8, -9, -11, - -11, -12, -13, -17, -21, -24, -24, -15, -4, 7, 12, 17, 25, 30, 28, 31, - 32, 31, 27, 22, 15, 12, 3, -2, -8, -6, -3, -9, -13, -22, -24, -20, - -18, -22, -24, -18, -14, -13, -10, -11, -9, -3, -2, -3, -5, -10, -10, -5, - -1, 4, 11, 15, 19, 22, 27, 23, 20, 16, 14, 5, -3, -11, -15, -16, - -12, -12, -11, -5, 1, -3, -10, -13, -15, -11, -10, -10, -11, -8, -3, 2, - 7, 9, 15, 25, 30, 33, 31, 25, 21, 20, 16, 13, 7, -2, -8, -5, - -4, -11, -20, -21, -22, -21, -17, -20, -21, -22, -19, -19, -11, -4, -2, -2, - -2, 2, 5, 2, 0, 0, -3, 1, 8, 16, 13, 14, 17, 15, 13, 8, - 5, -1, -6, -10, -13, -14, -14, -13, -10, -7, -8, -8, -6, -6, -3, -1, - -1, -9, -12, -7, 3, 13, 17, 14, 13, 17, 22, 23, 24, 18, 15, 18, - 18, 18, 15, 8, 0, -5, -8, -11, -15, -17, -21, -26, -26, -24, -26, -24, - -13, -9, -6, -3, -2, 3, 4, 6, 7, 5, 2, 4, 2, -2, -4, -3, - 5, 13, 17, 10, 3, -1, -2, -4, -5, -11, -14, -13, -11, -8, -8, -8, - -6, -3, 0, -1, -5, -5, 0, 4, 3, 1, 2, 0, 0, 6, 13, 20, - 17, 17, 18, 21, 18, 14, 13, 11, 11, 7, 9, 3, -5, -12, -14, -18, - -21, -23, -26, -26, -13, -3, -6, -13, -14, -5, 5, 8, 3, 0, 1, 3, - 6, 4, -1, -1, 1, 3, 7, 5, 3, 0, 1, -1, 3, 0, -3, -11, - -11, -9, -10, -9, -8, -5, -7, -7, -10, -9, -6, -1, 4, 6, 4, 2, - 5, 10, 13, 9, 12, 13, 14, 15, 16, 13, 12, 10, 13, 14, 13, 8, - 2, -1, -4, -6, -9, -15, -20, -21, -19, -14, -16, -22, -21, -13, -5, -3, - -3, -1, 3, 5, 10, 9, 9, 6, 8, 7, 7, 7, 3, -4, -6, -4, - -1, -4, -8, -10, -11, -8, -4, -6, -10, -7, -8, -11, -11, -8, -5, -4, - 0, 3, 3, 8, 10, 10, 12, 12, 11, 10, 13, 12, 10, 6, 8, 9, - 9, 11, 13, 11, 9, 10, 7, 2, -3, -8, -9, -14, -16, -16, -19, -18, - -14, -13, -11, -11, -10, -5, -1, 3, 5, 2, 2, 9, 14, 11, 9, 10, - 7, 2, 0, 2, -2, -9, -13, -15, -18, -17, -15, -13, -10, -5, -5, -7, - -7, -4, -1, 0, -2, -4, -2, 1, 4, 9, 10, 10, 11, 11, 13, 14, - 10, 11, 9, 9, 4, 6, 5, 4, 5, 7, 8, 10, 9, 4, -4, -8, - -9, -10, -11, -12, -14, -15, -17, -15, -9, -4, -1, -6, -5, 2, 8, 8, - 6, 5, 3, 4, 5, 9, 10, 10, 5, -1, -5, -10, -12, -14, -16, -18, - -17, -11, -10, -11, -8, -5, -2, -2, 0, 3, 4, 5, 3, 2, 3, 5, - 9, 12, 12, 11, 10, 12, 14, 12, 8, 5, 0, -1, 1, 3, 0, 1, - 3, 5, 6, 5, 0, -5, -11, -10, -13, -12, -13, -15, -14, -8, -4, -3, - -3, -4, 0, 4, 5, 3, 6, 4, 4, 7, 10, 9, 9, 8, 5, 5, - 2, -4, -10, -15, -17, -20, -22, -22, -19, -14, -11, -10, -8, -6, 0, 3, - 5, 3, 4, 8, 11, 11, 12, 13, 12, 12, 15, 15, 16, 16, 13, 11, - 6, 3, -2, -5, -5, -3, -2, -1, 2, 0, -3, -4, -5, -7, -10, -12, - -11, -12, -11, -8, -4, -2, 0, 1, 2, 2, 2, 4, 3, 3, 4, 5, - 9, 10, 6, 2, 1, 2, 0, -3, -7, -13, -18, -19, -18, -16, -18, -20, - -19, -14, -8, -4, -1, 3, 3, 5, 7, 9, 9, 10, 12, 13, 13, 13, - 13, 16, 15, 13, 9, 6, 3, 2, 1, 0, -3, -5, -6, -4, -2, -2, - -4, -4, -5, -5, -3, -3, -4, -6, -6, -7, -4, 0, 2, 3, 2, 2, - 1, 2, 2, 1, 4, 5, 4, 1, 0, 2, 2, 0, -2, -6, -8, -6, - -7, -9, -11, -15, -18, -19, -18, -18, -17, -13, -9, -2, 2, 3, 5, 10, - 12, 13, 14, 14, 15, 17, 17, 16, 16, 15, 13, 11, 7, 2, -6, -10, - -8, -6, -8, -8, -7, -6, -6, -3, -4, -6, -5, -3, -2, -2, 0, 1, - 0, 2, 2, 3, 2, 3, 2, 3, 3, 5, 2, 0, 4, 6, 5, -1, - -4, -2, -1, -2, -6, -8, -9, -10, -12, -10, -14, -17, -22, -22, -21, -19, - -15, -8, -3, 1, 7, 12, 12, 15, 19, 22, 21, 18, 16, 16, 16, 13, - 12, 6, 3, 3, 2, -3, -6, -7, -12, -12, -11, -8, -9, -8, -7, -3, - 0, 0, 0, 0, -2, -2, 0, 1, 2, 2, 4, 6, 6, 7, 5, 4, - 3, 4, 5, 3, 0, -2, -2, -4, -6, -10, -8, -8, -10, -11, -12, -12, - -12, -13, -16, -16, -16, -14, -11, -8, -4, -2, 1, 6, 12, 17, 19, 20, - 20, 21, 21, 19, 13, 10, 9, 5, 0, -3, -4, -4, -5, -6, -6, -4, - -7, -10, -12, -12, -12, -10, -7, -4, -2, 4, 6, 8, 7, 7, 7, 7, - 8, 8, 7, 5, 6, 6, 4, 1, -1, -1, 0, -3, -7, -10, -10, -8, - -11, -14, -14, -12, -11, -9, -6, -8, -8, -8, -11, -13, -12, -9, -8, -5, - 0, 4, 8, 11, 14, 18, 18, 20, 23, 23, 20, 14, 9, 4, 0, -3, - -6, -8, -8, -8, -8, -9, -10, -11, -10, -9, -8, -8, -7, -6, -3, 0, - 3, 6, 12, 16, 16, 14, 10, 8, 9, 7, 4, 1, 0, 0, -2, -1, - 0, 0, -3, -7, -10, -13, -13, -12, -13, -15, -14, -13, -9, -6, -5, -5, - -7, -8, -9, -7, -6, -5, -7, -5, 1, 8, 13, 17, 19, 20, 21, 22, - 22, 18, 12, 9, 5, -1, -5, -9, -11, -13, -12, -12, -11, -10, -8, -7, - -7, -6, -7, -6, -3, 0, 1, 3, 7, 10, 11, 12, 15, 15, 14, 9, - 6, 3, 1, 0, -2, -2, -2, -3, -6, -8, -10, -11, -13, -15, -15, -15, - -13, -12, -12, -7, -5, -5, -5, -4, -3, -3, -4, -4, -1, -1, 1, 4, - 7, 10, 12, 14, 17, 20, 22, 19, 14, 8, 5, 2, -2, -5, -10, -14, - -13, -11, -10, -10, -10, -10, -8, -6, -3, -3, -3, -1, -1, 2, 6, 10, - 13, 14, 15, 15, 15, 13, 11, 8, 5, 1, -1, -3, -3, -6, -10, -12, - -12, -12, -12, -13, -15, -18, -19, -15, -11, -6, -4, -3, -4, -4, -2, 1, - 4, 2, -1, -2, 1, 4, 6, 8, 7, 7, 11, 14, 15, 15, 15, 13, - 10, 6, 1, -3, -6, -9, -13, -15, -15, -13, -11, -9, -9, -9, -7, -3, - 0, 2, 2, 4, 7, 11, 15, 16, 14, 11, 12, 13, 15, 13, 9, 4, - 1, -1, -4, -6, -8, -11, -15, -17, -17, -17, -17, -15, -13, -13, -12, -10, - -7, -6, -4, 1, 2, 2, 3, 4, 5, 4, 4, 3, 5, 6, 6, 8, - 7, 7, 9, 11, 10, 9, 8, 5, 2, 0, -2, -6, -10, -13, -13, -14, - -14, -13, -11, -9, -4, -1, -1, -1, 2, 6, 8, 10, 11, 12, 14, 14, - 14, 13, 11, 10, 7, 4, 2, 3, 1, -3, -6, -10, -14, -17, -18, -18, - -19, -19, -17, -15, -13, -9, -5, -1, 1, 0, 1, 3, 5, 6, 6, 6, - 7, 8, 9, 8, 4, 1, 0, 2, 4, 5, 6, 5, 4, 4, 4, 3, - 1, -3, -7, -9, -11, -12, -12, -12, -11, -10, -7, -4, -2, 1, 4, 5, - 8, 11, 13, 14, 14, 11, 11, 11, 10, 10, 9, 6, 5, 3, 1, -2, - -5, -10, -14, -16, -17, -18, -19, -20, -19, -17, -14, -10, -5, -1, 1, 3, - 5, 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 4, 2, 0, -1, - 0, 0, 1, 2, 1, 1, 2, 1, -2, -5, -8, -9, -10, -11, -12, -12, - -10, -7, -4, -1, 2, 8, 11, 13, 15, 15, 13, 12, 11, 10, 9, 8, - 6, 5, 4, 4, 3, 0, -3, -6, -10, -14, -18, -21, -22, -21, -18, -16, - -13, -10, -6, -3, 0, 3, 5, 5, 5, 6, 7, 8, 8, 8, 7, 8, - 7, 6, 5, 4, 1, 0, -2, -4, -4, -5, -4, -4, -3, -2, -1, -2, - -3, -4, -7, -8, -9, -9, -9, -8, -5, -2, 2, 4, 8, 11, 14, 15, - 15, 14, 12, 10, 7, 5, 4, 4, 2, 1, 1, 2, -1, -3, -7, -10, - -15, -18, -18, -18, -18, -17, -15, -11, -7, -3, 1, 3, 4, 5, 6, 7, - 7, 8, 8, 9, 10, 10, 9, 6, 4, 2, 0, -3, -4, -6, -7, -7, - -6, -5, -3, -2, -2, -2, -2, -3, -4, -5, -6, -6, -6, -6, -5, -4, - -1, 4, 7, 9, 11, 12, 12, 11, 10, 9, 8, 7, 5, 3, 3, 2, - 1, 0, -1, -4, -7, -8, -10, -13, -14, -15, -15, -15, -14, -11, -9, -6, - -3, 0, 2, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 6, 5, 3, - 1, -3, -6, -8, -8, -7, -7, -7, -6, -4, -2, 0, -1, -2, -3, -3, - -3, -3, -4, -3, -3, -1, 1, 3, 4, 6, 7, 8, 9, 10, 10, 9, - 7, 6, 6, 4, 3, 2, 1, -1, -2, -4, -6, -9, -11, -12, -12, -12, - -11, -11, -10, -9, -8, -7, -5, -4, -1, 1, 3, 5, 7, 9, 10, 11, - 10, 9, 8, 7, 6, 2, -1, -3, -4, -6, -7, -7, -7, -7, -6, -5, - -5, -4, -3, -3, -4, -4, -4, -3, -2, 0, 0, 1, 1, 2, 4, 6, - 6, 7, 7, 8, 7, 7, 7, 7, 7, 6, 5, 2, 0, -2, -4, -5, - -7, -8, -8, -8, -9, -10, -10, -9, -8, -7, -7, -7, -5, -3, -2, 0, - 1, 2, 4, 6, 9, 10, 11, 12, 10, 8, 6, 3, 1, -2, -4, -6, - -7, -7, -7, -7, -8, -7, -7, -6, -6, -5, -4, -3, -3, -2, -1, 1, - 2, 2, 3, 4, 5, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 4, - 3, 2, 1, -1, -3, -4, -6, -8, -9, -9, -8, -8, -6, -5, -5, -5, - -6, -6, -6, -5, -4, -2, 0, 2, 4, 6, 7, 8, 9, 9, 9, 9, - 6, 4, 1, -1, -3, -5, -6, -7, -7, -7, -6, -6, -6, -6, -6, -5, - -4, -3, -3, -2, -1, 1, 3, 4, 5, 5, 5, 5, 5, 5, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 1, -1, -3, -4, -5, -6, -7, -7, - -7, -7, -7, -6, -5, -4, -4, -3, -3, -3, -3, -2, -1, 0, 1, 3, - 5, 7, 8, 8, 8, 7, 6, 4, 2, 0, -2, -3, -4, -5, -6, -7, - -7, -7, -7, -6, -6, -5, -5, -5, -3, -2, 0, 1, 2, 3, 4, 5, - 6, 6, 6, 5, 5, 4, 3, 3, 3, 3, 3, 3, 2, 1, 1, -1, - -2, -3, -4, -5, -6, -6, -7, -6, -5, -4, -3, -3, -3, -3, -3, -2, - -1, -1, 0, 1, 1, 1, 2, 3, 5, 6, 6, 6, 5, 4, 2, 1, - 0, -2, -4, -5, -5, -6, -6, -6, -7, -7, -7, -6, -5, -4, -3, -2, - -1, 0, 2, 3, 3, 4, 4, 5, 5, 5, 4, 4, 4, 4, 3, 3, - 2, 1, 1, 0, 0, -1, -1, -2, -3, -4, -5, -5, -5, -5, -5, -4, - -4, -3, -3, -2, -1, -1, -1, -1, 0, 0, 0, 1, 2, 3, 3, 4, - 4, 4, 4, 4, 3, 1, 0, 0, -2, -3, -4, -5, -5, -6, -6, -6, - -5, -4, -4, -4, -3, -2, -2, -1, 0, 2, 3, 3, 4, 4, 4, 4, - 3, 3, 3, 3, 2, 2, 1, 1, 1, 0, -1, -1, -2, -3, -3, -3, - -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 0, 0, -1, -1, - -2, -3, -3, -3, -4, -4, -4, -4, -3, -3, -2, -1, -1, -1, 0, 1, - 1, 1, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 0, -8, -33, -24, -25, -25, -26, -27, -32, -28, -36, -31, -36, -22, -34, - 11, -74, -14, 94, 41, 28, 33, 30, 40, 34, 23, 41, 40, 60, 56, 59, - 60, 44, 39, 54, 45, 52, 17, 44, 62, 34, 33, 19, 18, 43, 35, 22, - 36, -15, -10, 32, -7, -12, -6, -8, -50, -47, -44, -4, -25, -48, -76, -58, - -75, -96, -85, -118, -114, -63, -106, -103, -83, -110, -99, -84, -76, -58, -63, -61, - -51, -53, -36, -32, -41, -27, -11, 11, 8, 27, 19, 30, 35, 28, 57, 53, - 38, 71, 51, 68, 110, 78, 89, 109, 97, 82, 94, 115, 114, 79, 70, 79, - 94, 85, 76, 84, 95, 83, 82, 55, 54, 54, 41, 41, 27, 20, 6, -11, - -21, -16, -14, -33, -33, -52, -54, -59, -62, -71, -79, -88, -88, -78, -78, -72, - -71, -94, -99, -93, -90, -78, -87, -105, -103, -79, -62, -71, -78, -63, -61, -66, - -49, -23, -10, -11, -24, -20, -4, -22, 9, 8, 27, 43, 34, 38, 51, 83, - 65, 58, 74, 75, 70, 73, 71, 65, 100, 89, 94, 65, 84, 49, 49, 61, - 54, 43, 51, 58, 53, 35, 40, 36, 38, 34, 23, 14, -12, -10, -1, -1, - -11, -12, -19, -33, -66, -52, -42, -37, -55, -42, -28, -32, -29, -35, -41, -28, - -25, -46, -85, -64, -62, -55, -49, -68, -55, -53, -52, -47, -43, -26, -32, -41, - -34, -35, -40, -26, -8, -1, -6, -11, 5, -2, 8, 3, 8, 6, 4, 20, - 29, 43, 24, 33, 20, 30, 24, 39, 38, 40, 29, 37, 36, 39, 61, 58, - 41, 51, 59, 51, 55, 58, 48, 32, 45, 40, 27, 30, 41, 44, 26, 19, - 23, -3, 7, 0, -3, 2, 3, -6, -5, -14, -6, -10, -27, -45, -47, -41, - -38, -50, -51, -46, -43, -45, -65, -65, -80, -95, -82, -74, -66, -69, -67, -33, - -31, -53, -48, -51, -43, -18, -24, -24, -33, -26, -10, 0, -17, -6, 17, 31, - 2, 23, 45, 46, 12, 75, 38, 63, 69, 31, 38, 80, 57, 48, 59, 81, - 74, 32, 52, 72, 24, 60, 44, 55, 40, 28, 48, 33, 24, 10, -2, 21, - 34, 13, 18, 7, -1, -12, -20, -18, -30, -9, -7, -30, -27, -26, -38, -20, - -54, -55, -64, -53, -36, -62, -37, -71, -47, -42, -71, -45, -55, -50, -54, -56, - -36, -37, -54, -36, -12, -38, -33, -26, -7, -22, -44, -10, 2, 3, 15, 8, - 18, 6, 12, 8, 15, 28, 22, 50, 35, 55, 42, 36, 49, 52, 64, 48, - 60, 49, 60, 62, 40, 47, 68, 52, 59, 61, 44, 53, 44, 35, 31, 31, - 47, 22, 6, 4, -7, 5, -4, -21, -13, -9, -10, -27, -46, -32, -44, -46, - -62, -44, -51, -67, -53, -59, -63, -74, -67, -61, -61, -65, -47, -58, -57, -45, - -41, -46, -41, -38, -22, -25, -34, -16, -10, -18, 0, 1, -6, 5, 17, 15, - 10, 23, 38, 28, 28, 54, 40, 19, 55, 55, 41, 46, 53, 40, 49, 51, - 52, 41, 56, 39, 53, 38, 33, 35, 18, 15, 38, 30, 23, 27, 13, 11, - 7, 16, -1, 0, 0, 13, -6, -10, -15, -10, -10, -24, -20, -16, -38, -36, - -21, -40, -32, -42, -38, -52, -53, -41, -48, -58, -50, -47, -37, -41, -45, -29, - -41, -6, -48, -24, -25, -15, -9, -10, -10, -10, -1, -17, 4, 3, 10, -4, - 9, 15, 25, 24, 19, 23, 34, 28, 33, 37, 38, 26, 36, 47, 35, 46, - 45, 28, 35, 32, 32, 24, 21, 26, 23, 19, 37, 20, 9, 29, -2, 26, - 24, 8, 4, 14, 21, 11, -9, -8, 4, -9, -31, -11, -15, -21, -24, -29, - -22, -33, -26, -29, -48, -32, -44, -28, -22, -35, -30, -38, -31, -46, -44, -36, - -27, -23, -29, -24, -11, -20, -28, -13, -34, -19, -1, 7, -3, -1, 6, -3, - 5, 4, 8, 17, 26, 19, 33, 27, 16, 35, 14, 36, 39, 22, 32, 31, - 19, 32, 23, 29, 21, 30, 29, 23, 31, 13, 24, 17, 11, 26, 18, 12, - 5, 23, 16, 9, 15, -10, 3, 18, -15, -4, -4, 6, -14, -15, -5, -34, - -11, -20, -18, -8, -17, -29, -30, -29, -19, -34, -35, -20, -36, -20, -16, -21, - -38, -16, -30, -24, -25, -19, -18, -15, -7, -5, -5, -10, -23, -3, -14, 0, - -1, -12, -9, 7, 7, 2, 12, 5, 7, 19, 10, 21, 21, 27, 30, 22, - 18, 34, 22, 11, 26, 24, 20, 21, 25, 29, 22, 27, 27, 20, 10, 20, - 16, 22, 15, 16, 16, 5, 19, 10, 3, 22, -5, -5, -7, -16, -4, -11, - -22, -7, -16, -11, -23, -16, -30, -24, -28, -20, -29, -24, -32, -22, -22, -30, - -17, -23, -28, -22, -20, -21, -21, -17, -30, -15, -14, -20, -9, 3, 6, 5, - -20, 10, 13, -2, 11, 8, -1, 7, 16, 5, 22, 23, 13, 22, 13, 22, - 25, 15, 16, 11, 15, 13, 7, 12, 19, 18, 20, 12, 23, 11, 6, 10, - 1, 11, 19, 5, 20, 0, 11, 11, 1, 14, 15, -3, -1, -7, 6, -6, - -9, -9, 4, -3, -10, -20, -14, -9, -14, -7, -10, -5, -4, -29, -14, -12, - -26, -21, -27, -18, -10, -19, -27, -18, -8, -25, -8, -13, -15, -14, -15, 5, - -13, -7, -11, -4, -12, 0, 15, 5, 4, 1, 11, 6, 4, 3, 6, 21, - 19, 8, 15, 13, 6, 14, 16, 18, 17, 20, 15, 11, 15, 24, 13, 11, - 19, 7, 17, 14, 6, 17, 7, 7, 6, 6, 5, 11, 0, 6, 0, -6, - 5, 1, -11, -6, -1, -8, -9, -15, -7, -4, -16, -17, -13, -13, -17, -14, - -12, -12, -28, -13, -19, -25, -31, -24, -17, -17, -16, -7, -15, -12, -8, -15, - -8, -16, -10, -4, -1, -2, 3, 5, 2, -2, 5, 3, 6, 10, 8, 11, - 14, 14, 13, 15, 22, 16, 14, 18, 13, 17, 19, 16, 10, 17, 8, 17, - 14, 3, 14, 7, 10, 10, 7, 6, 6, -1, 6, 1, 0, 12, -6, 6, - 12, -4, -5, -4, -2, -2, -1, -2, -8, -11, -9, -11, -11, -18, -6, -5, - -16, -9, -14, -10, -13, -10, -11, -15, -14, -14, -12, -17, -17, -17, -7, -11, - -14, -15, -12, -6, -15, -5, -13, -9, 0, 12, -2, -2, 6, 2, -7, 4, - 10, 2, 9, 8, 7, 4, 5, 11, 15, 11, 10, 18, 9, 13, 13, 13, - 21, 11, 18, 19, 13, 14, 16, 6, 8, 1, 19, 11, 10, 11, 1, 3, - -1, -1, 5, -11, 5, -1, -5, -3, -13, -10, -6, -7, -5, -15, -10, -11, - -18, -8, -16, -20, -18, -9, -12, -17, -21, -21, -13, -21, -8, -10, -10, -5, - -16, -7, 2, -6, -6, -9, -7, -2, -9, -5, 6, -7, 1, 3, -1, 2, - 1, 2, 9, 8, 5, 15, 12, 1, 11, 9, 8, 10, 15, 14, 5, 13, - 17, 14, 15, 10, 7, 16, 5, 5, 5, 8, 9, 10, 10, 7, 0, 4, - 6, 9, -10, -4, 5, 2, -1, 0, -3, -4, -5, -10, -5, -8, -9, -10, - -3, -13, -6, -9, -20, -15, -11, -18, -14, -10, -12, -20, -14, -14, -7, -12, - -21, -14, -9, -8, -11, -5, -2, -7, -4, 4, -2, -3, -1, 0, -1, 8, - 6, 9, 7, 10, 6, 3, 4, 7, 10, 11, 6, 9, 17, 11, 9, 7, - -2, 16, 13, 12, 18, 5, 16, 9, 4, 9, 6, 8, 9, 4, 4, 3, - -2, -3, 2, -6, -3, 1, -7, -6, -3, -6, -14, -8, -9, -4, -13, -9, - -8, -16, -10, -12, -13, -11, -7, -8, -12, -9, -8, -7, -11, -4, -8, -7, - -8, -3, -13, -10, -3, 6, -5, -5, 0, -5, -3, 6, -2, -2, 4, -2, - 6, 2, -2, 5, 5, -2, 5, 15, 13, 4, 6, 6, 14, 9, 4, 8, - 7, 3, 11, 12, 2, 10, 7, 10, 8, 4, 6, 2, 0, 3, 2, 4, - 2, -6, -2, 2, -4, 3, -5, -6, -5, -5, -5, -4, -8, -7, -4, -4, - -7, -8, -7, -13, -10, -10, -11, -9, -8, -8, -7, -11, -7, -3, -9, -6, - -7, -3, -4, -5, 3, -3, -1, -2, -4, 1, 4, 0, 3, 0, 5, 2, - 0, 5, 4, 1, 3, 1, 0, 1, 7, 3, 0, 4, 3, 6, 5, 0, - 9, 5, 7, 6, 3, 6, 2, 3, 5, -4, 9, 0, 4, 10, 0, 5, - 1, -2, 4, -3, -3, -2, 0, 2, -7, 3, -10, -1, -6, -9, -2, -4, - -10, -3, -7, -6, -4, -10, -6, -6, -11, -6, 0, -6, -8, -4, -1, -9, - -10, 0, -6, -7, -2, -7, 1, -5, -5, -1, 1, -6, 2, 0, -3, -1, - 7, -4, 0, 7, 0, 8, 2, 3, 4, 4, 2, 5, -1, 6, 7, 5, - 6, 4, 2, 4, 6, 8, 6, 3, 1, 8, 9, 2, -1, 4, 3, 4, - 3, -3, 7, 4, 3, -2, 2, -4, -6, -2, -5, -2, -3, 0, -5, -6, - -13, -5, -6, -11, -9, -10, -5, -4, -9, -9, -7, -7, -8, -8, -6, -5, - -7, -5, -1, -3, -4, -2, -2, 2, -3, 1, 2, -3, 1, 2, 1, 0, - 1, 5, 0, 2, 5, 2, 0, 4, 1, 7, 3, 2, 6, 0, 5, 7, - 5, 5, 1, 3, 3, 5, 10, 3, 4, 8, 2, 7, 3, -2, 3, 0, - -1, -1, 1, 0, 1, -3, -2, -5, -4, -3, -1, -7, -8, -4, -4, -10, - -2, -8, -8, -8, -8, -9, -6, -8, -9, -4, -2, -7, -5, -2, -7, -6, - -9, -2, 0, -4, 4, -6, -3, -4, -1, 2, 1, 2, 9, 0, 3, 0, - 6, 4, 0, 5, 6, 2, 7, 7, 5, 7, 6, 8, 6, 6, 5, 5, - 1, 6, 5, -1, 3, 4, -1, 4, 1, 4, 3, -5, 0, 4, 1, 4, - -2, -3, -4, 0, -4, -8, -2, -5, -4, -8, -6, -5, -3, -3, -7, -9, - -6, -10, -10, -6, -6, -5, -4, -7, -6, -4, -10, -3, -10, 0, -2, -2, - -6, -1, 3, -3, -3, 1, 2, 1, 4, 3, 4, 3, 4, 1, 2, 6, - 5, 5, 5, 7, 9, 1, 5, 4, 4, 7, 2, 9, 2, 4, 8, 2, - 5, 6, 3, -2, -2, -1, -2, -1, 1, -2, -4, 1, -6, -2, -5, -3, - -5, -5, -6, -4, -3, -4, -10, -4, -3, -8, -4, 0, -3, -5, -6, -6, - -3, -1, -7, -3, 1, -1, -4, -2, 1, -2, 0, -1, -2, 0, 0, 5, - -2, 0, 3, 3, 1, 5, 2, 4, 1, 4, 1, 2, 3, 3, 3, 4, - 3, 3, 5, 1, 4, 2, 3, 1, 2, 0, 2, 1, -2, -2, -1, 0, - -2, -1, -1, -3, -5, -2, 0, -5, -1, 0, -5, -2, -2, -2, -3, -3, - -1, -4, -1, -2, -4, -2, -1, -2, -1, 0, -3, -1, -1, 0, 1, -1, - -1, 3, -4, -2, -2, 4, -2, -1, -1, -1, 0, 0, -1, -1, -1, -1, - 2, 0, -1, 2, -1, 0, -1, 2, 0, 3, 5, -2, 1, 2, 0, 5, - 0, -3, 4, -3, 1, 2, 0, 4, -1, -2, 1, 0, 0, 0, -1, 1, - -2, 0, 1, 1, 0, -5, 1, -2, -1, 0, -2, -3, -1, -3, 0, -2, - -3, -4, 1, -2, -3, -2, -2, -1, -1, -2, -1, -4, -5, 2, -4, 0, - 1, -1, 2, -2, -1, 0, 0, 1, -3, 3, 2, 0, -2, 2, 1, 2, - -2, 5, 3, -2, -2, -1, 1, 0, 0, 1, 3, 2, 0, 0, -1, -2, - 1, 1, 2, 1, 1, -1, 0, -1, -1, -1, -3, 1, 1, 2, -2, -1, - 0, 0, -2, 0, -1, -1, 2, -2, 1, -1, 0, 0, -1, -1, -2, 0, - -1, 1, -1, -1, 2, -2, 0, -1, -1, 2, -1, 0, -3, -1, 0, 0, - 0, -3, -3, -2, 0, 0, -1, -1, 0, -4, 2, 0, -2, 0, 1, -3, - -1, 2, 1, 0, -1, 0, 0, -1, 0, 2, -1, -1, 0, 0, -2, 1, - 1, 0, 1, 0, 2, -3, -2, 2, -1, -1, 2, -2, 1, 1, 0, 0, - 1, 1, 0, -4, 3, -1, 2, 0, 2, -1, -2, 0, 1, 1, -1, -1, - -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, 1, 0, -5, 0, -1, -1, - -1, 1, -1, 1, -1, 1, 0, -2, 0, -2, 1, -1, 1, 0, -1, -2, - 0, -1, 0, 0, 2, 0, 0, 0, 1, 0, 0, 2, 0, -1, 0, 0, - 0, 2, -1, 1, 1, -1, -1, 0, 0, 1, 1, 0, 0, 0, 0, -1, - 0, 0, -2, 0, 0, -1, 1, -2, -1, -1, -1, -2, -1, -2, 1, -1, - 0, -2, -2, 1, -2, -1, 1, 0, 1, 1, -1, -1, 0, -1, 0, 0, - 0, -2, 0, -1, 0, 0, -1, -2, -2, -2, 1, -1, 0, 0, -1, 1, - 1, -2, -1, -2, -1, 1, -1, -1, -2, -2, 0, 0, 1, -1, -1, -1, - -1, -2, 2, 0, 0, 1, 1, 1, -2, 0, -1, 0, -1, -1, 2, 0, - -1, -1, -1, 1, -1, 2, 0, -1, 1, 1, 0, 1, 0, -1, -1, -1, - -1, -3, 0, 0, -1, 1, 0, 0, -2, -2, -2, 0, -1, 0, 0, -1, - 0, -1, -2, -1, -2, 0, -2, 0, 0, -1, -2, 1, -2, 0, -1, -2, - 2, 0, -1, 2, -1, 1, -1, 0, 0, -1, 0, 0, 0, -1, 0, 1, - 0, 0, 1, 0, -1, -1, 0, -2, -1, 0, 0, 1, 0, 0, 0, 0, - -1, -1, 1, -1, -2, -1, 0, 0, -2, 0, -1, 0, 0, 0, 1, 0, - 0, -1, 1, 0, -1, 0, 1, -1, 0, -1, -2, 0, -1, 0, -1, -1, - -1, 0, -1, 0, 0, 0, -1, -1, 0, -2, 0, 0, 0, -2, -2, 0, - -2, -1, -1, -1, -2, 0, -1, -1, -1, 0, 0, -1, -1, 0, 1, -1, - -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, - -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0, - -1, 0, -1, -1, 0, -2, -1, 0, -1, -1, -1, -1, 0, -1, 0, 0, - 0, 0, -1, 1, 0, 0, 0, -1, -1, 0, -1, -1, 0, 0, 0, 0, - 0, -1, -1, 0, -1, -1, 0, 0, -1, 0, -2, 0, -1, -1, -1, 0, - -1, -1, 0, -1, 0, 0, 0, -2, -1, 0, -1, -1, 0, 1, -1, -1, - 0, 0, 0, 0, -1, -1, -1, -1, 0, 1, 0, 0, 0, 0, 0, -1, - 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, -1, -1, 0, - 0, -1, -1, 0, -1, 0, 0, 0, -1, 0, -1, -1, 0, -2, -1, -1, - -1, 0, -1, 0, -1, -1, 0, 0, -1, 0, -1, 0, -1, -1, -1, 0, - -1, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, - 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, - 0, -1, -1, 0, 0, 0, -1, 0, 1, -1, -1, -1, 0, 0, -1, -1, - -1, -1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 0, - -1, 0, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, 0, -1, - 0, -1, 0, 0, -1, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, -1, - -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, - 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, - -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, - -1, -1, 0, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0, -1, -1, -1, - -1, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, - 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, - 0, -1, 0, -1, 0, 0, -1, -1, -1, 0, -1, -1, 0, -1, -1, 0, - 0, -1, -1, -1, -1, 0, -1, -1, 0, 0, -1, 0, 0, 0, -1, -1, - 0, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, 0, -1, 0, 0, -1, - -1, 0, 0, -1, 0, 0, -1, -1, -1, 0, -1, 0, 0, -1, -1, 0, - 0, -1, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, -1, 0, -1, 0, - -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 0, 11, -3, 47, -12, -15, -34, 3, 12, 38, 5, -24, -26, -9, -12, - 63, -18, 12, -17, -50, 34, -6, 40, -2, -8, -37, -6, 9, 12, 32, -4, - -33, 2, -33, 35, 20, 6, -11, -33, -11, 12, 23, 30, -21, -13, -28, -6, - 33, 14, 7, -18, -22, -11, 18, 23, 5, -4, -22, -30, 29, -11, 40, -12, - -15, -5, -11, 16, 13, -9, 5, -19, 3, 4, 2, 19, -28, 24, -41, 40, - -9, -8, 4, -29, 28, -1, 22, -16, -32, 16, -22, 45, 19, -45, 17, -54, - 25, 28, 33, -19, -30, -21, -25, 83, -20, 15, -3, -74, 12, 33, 4, 53, - -26, -57, -9, 0, 36, 33, 8, -67, -2, -17, 27, 55, -17, -11, -31, -23, - 24, 22, 6, 19, -55, 27, -48, 55, -8, 14, 7, -61, 26, -25, 34, 32, - -26, 11, -50, 5, 14, -1, 67, -75, 47, -79, 29, 15, 8, 42, -49, 2, - -34, -3, 51, -23, 52, -33, -32, -7, -14, 52, 6, 29, -73, 5, -9, -2, - 64, -39, -6, 25, -60, 30, 5, 16, -13, 40, -61, 7, 20, -50, 75, -36, - 10, -12, -4, -17, 23, 16, -18, 31, -38, -21, 33, -37, 56, -11, -5, -1, - -43, 43, -56, 93, -67, 40, -17, -46, 60, -56, 62, -24, 14, -18, -23, 9, - -16, 44, 19, -53, 58, -124, 81, -18, 32, 26, -43, -23, -28, 42, 1, 60, - -27, -61, 14, -37, 42, 64, -32, -2, -43, -31, 25, 59, -7, -1, -19, -73, - 51, 23, 18, 7, -24, -65, 29, 18, -2, 57, -47, -27, 4, -2, 16, 41, - -25, -47, 36, -51, 49, 24, -37, 13, -15, -11, 12, 26, -58, 52, -20, -16, - 31, -24, -20, 52, -16, -9, 32, -69, 5, 48, -34, 52, -12, -59, 20, -10, - 30, 16, 21, -75, 1, 8, -33, 126, -57, 9, -37, -49, 32, 24, 62, -59, - 19, -85, -2, 91, -23, 65, -49, -75, 19, -16, 68, 9, 16, -77, -3, 3, - -13, 111, -69, 17, -30, -59, 56, 1, 19, 23, -26, -21, -24, 25, -31, 97, - -59, 4, -16, -34, 40, 17, 16, -24, -6, -40, 26, 17, 3, 4, -23, -3, - -1, 23, -8, 6, -29, -2, 21, -13, 22, -11, -31, 40, -35, 48, -27, 7, - -39, 4, 28, -12, 55, -68, 9, -9, 2, 51, -21, -20, -18, -15, 33, 20, - 15, -57, 41, -78, 72, -2, -7, 13, -60, 11, 13, 49, -19, 10, -55, -23, - 59, -6, 22, 2, -79, 40, -11, 46, -11, 11, -66, 13, 24, -24, 80, -65, - 5, -22, 1, 19, 23, -8, -27, -11, 2, 0, 64, -61, 21, -52, 34, 23, - 7, -1, -51, 21, -41, 86, -45, 49, -62, -6, 0, 11, 51, -33, 16, -62, - -1, 23, 8, 62, -45, -35, 7, -39, 88, -54, 70, -86, 33, -27, -1, 61, - -60, 58, -62, 10, 15, -28, 65, -48, 11, -2, -44, 78, -64, 75, -78, 26, - -29, 22, 40, -30, 16, -53, -12, 56, -15, 48, -51, -22, -10, 9, 52, -20, - 40, -92, 16, -3, 26, 43, -19, -35, -31, 15, 13, 49, -11, -34, -24, -1, - 9, 50, -12, -25, -17, -10, 15, 44, -20, 0, -28, -22, 32, 5, 27, -33, - 15, -67, 61, -19, 19, 18, -46, -1, -1, 7, 18, 14, -27, -21, 18, -27, - 42, 22, -56, 38, -56, 21, 17, 2, 5, -3, -11, -38, 48, -27, 32, 8, - -50, 1, 10, -3, 38, -10, -16, -36, 34, -45, 74, -12, -30, 16, -52, 22, - 24, 17, -1, -13, -41, -10, 50, -5, 41, -32, -62, 25, -5, 48, 24, -26, - -61, 4, -2, 44, 62, -59, -23, -38, -4, 61, 34, 0, -57, -18, -41, 63, - 36, 6, -1, -69, -11, 10, 19, 60, -31, 3, -64, 18, -19, 61, 10, -17, - 10, -73, 13, 30, -7, 64, -39, -27, -34, 8, 20, 46, 24, -87, 29, -70, - 51, 51, -12, 6, -44, -30, 10, 52, -7, 2, -6, -72, 63, -9, 17, 15, - -37, -24, 14, 24, -11, 43, -55, -29, 42, -19, 47, 1, -49, -13, 13, 6, - 38, 4, -59, -2, 7, 5, 61, -31, -42, 11, -32, 54, 14, -11, -23, -10, - -20, 40, 19, -18, 0, -19, -28, 52, -14, -5, 29, -70, 53, -17, 19, -18, - 15, -30, -2, 37, -41, 38, 7, -61, 67, -67, 35, 11, -12, 11, -34, 38, - -61, 89, -59, 10, 28, -60, 52, -19, -22, 34, -30, 42, -42, 45, -68, 35, - 19, -45, 80, -81, 26, -16, 4, 30, 0, -13, -19, -14, 23, -22, 75, -77, - 47, -45, -5, 48, -36, 48, -50, 18, -35, 25, 5, 4, 14, -16, -33, 40, - -49, 71, -38, 17, -30, -6, 12, 4, 31, -27, -6, -12, -11, 27, 15, -13, - 12, -54, 32, -19, 53, -17, -1, -16, -39, 39, -5, 30, -3, -29, -13, -2, - 23, 16, 4, -18, -41, 26, -11, 35, 18, -48, 13, -33, 28, 1, 38, -45, - 5, -13, -18, 49, 1, -21, 16, -44, 14, 16, 7, -6, -5, -10, -18, 52, - -33, 25, -11, -36, 31, -15, 14, 11, -22, 9, -27, 41, -42, 56, -50, 15, - 10, -28, 30, -18, 3, 7, -7, 7, -16, 13, -27, 29, 5, -25, 42, -71, - 44, -18, 21, 8, -7, -21, -15, 21, -9, 36, -2, -43, 17, -26, 14, 45, - -33, 19, -40, 1, -3, 37, -5, -5, -2, -46, 38, 0, 7, 18, -33, -12, - 11, -11, 33, 2, -16, -15, -3, 1, 18, 26, -32, -4, -14, -17, 54, -1, - -1, -17, -35, 10, 12, 40, -12, -10, -30, -31, 51, -12, 65, -35, -34, -12, - -32, 60, 22, 19, -33, -39, -20, 2, 75, 2, 9, -42, -72, 35, 13, 65, - 5, -28, -60, -15, 23, 40, 44, -33, -34, -34, -5, 48, 33, 2, -21, -47, - -15, 25, 33, 12, 7, -55, -12, 7, 19, 28, 9, -34, -28, 5, 7, 32, - 15, -41, 8, -32, 10, 36, -4, 14, -40, 16, -45, 56, -15, 17, 0, -33, - 2, 0, 7, 23, -12, -1, -26, 3, 6, 10, 24, -32, 21, -50, 33, -9, - 15, 11, -24, 1, -12, 12, 4, 13, -10, -11, -2, -5, 7, 17, -23, 25, - -27, 12, -6, 0, 8, -16, 18, -24, 31, -27, 9, -3, -2, 18, -4, -7, - -11, -12, 10, 12, 15, -17, 7, -34, 18, 8, 4, 9, -18, -14, -3, 15, - 9, 7, 0, -37, 21, -13, 16, 18, -32, 12, -23, 21, 3, 12, -14, -14, - 3, -5, 24, 4, -21, 9, -32, 26, 14, -1, 12, -40, 0, -6, 24, 11, - 3, -11, -34, 17, -8, 28, 18, -36, 9, -38, 13, 26, 11, 7, -20, -13, - -34, 49, -24, 41, -8, -36, 4, -8, 3, 47, -11, -5, -24, -15, -9, 44, - 8, -5, 8, -61, 17, 14, 14, 23, -15, -43, 1, -1, 28, 27, 1, -40, - -6, -20, 18, 45, -22, 4, -20, -34, 39, 12, 3, 9, -31, -23, 15, 17, - -7, 36, -36, -19, 30, -30, 36, 1, -16, -8, 5, -14, 20, 10, -13, 0, - 6, -30, 37, -22, 3, 14, -27, 24, -15, 14, -15, 19, -22, 4, 17, -31, - 29, -14, -10, 27, -26, 22, -14, 8, -17, 9, -2, -11, 33, -27, 14, 0, - -29, 31, -21, 21, -7, -2, -14, -4, 20, -15, 37, -27, -9, 7, -24, 24, - 8, -9, 12, -23, 7, -14, 30, -22, 25, -16, -20, 24, -27, 23, 8, -9, - 6, -11, -18, 12, -3, 22, -14, 28, -61, 41, -32, 21, 29, -26, 8, -31, - 2, 5, 28, 3, -9, -14, -21, -3, 48, -33, 49, -62, 9, -1, 6, 33, - -24, 11, -44, 24, -2, 6, 25, -40, 8, 1, -16, 49, -41, 27, -41, 18, - 0, 3, 31, -50, 36, -42, 22, 15, -18, 24, -34, 5, 12, -21, 52, -56, - 52, -58, 29, -8, -8, 39, -51, 48, -47, 24, 4, -16, 22, -28, 6, 7, - -22, 48, -55, 51, -44, 31, -10, -5, 8, -36, 41, -31, 35, -9, -16, 10, - -17, 6, 21, -13, 10, -26, 5, -17, 39, -3, 3, 1, -43, 12, 1, 17, - 15, -7, -24, -9, 5, 15, 17, 8, -38, 2, -25, 25, 15, 12, -13, -16, - -11, 3, 19, 9, -9, -9, -15, 1, 19, -1, 14, -20, -1, -12, 15, -7, - 11, -10, -2, -3, 10, -9, 18, -17, 2, -4, -3, 4, 3, -2, -5, 9, - -9, 4, 5, -13, 5, 5, -21, 22, -16, 11, -4, 13, -22, 5, 3, -23, - 35, -14, -6, 13, -24, 4, 17, -6, 6, -7, -6, -27, 43, -28, 25, 9, - -45, 28, -23, 8, 25, -14, 0, -15, -4, -3, 27, 3, -15, 18, -59, 34, - 3, -3, 38, -39, -11, 4, -9, 27, 9, -2, -38, 21, -31, 19, 47, -53, - 43, -47, -11, 29, -2, 19, -7, -9, -36, 19, 12, -8, 53, -58, 1, 2, - -33, 67, -23, 25, -44, 5, -25, 28, 32, -29, 32, -60, 0, 25, -7, 39, - -14, -29, -12, 2, 11, 20, 23, -54, 18, -25, 1, 45, -10, -10, -4, -29, - 7, 28, 7, -11, 9, -46, 16, 11, 8, 8, -7, -25, -3, 16, -3, 32, - -25, -7, -20, 12, 0, 30, -14, -4, -15, -6, 6, 24, -9, 3, -16, -24, - 23, -3, 27, -20, 15, -56, 42, -17, 21, 13, -27, -8, -2, 5, 8, 21, - -21, -12, 4, -14, 15, 24, -39, 31, -38, 19, -2, 16, -16, 3, -6, -21, - 30, -14, 16, 4, -30, 11, -7, 7, 12, -5, -10, -9, 9, -17, 37, -15, - -5, 6, -26, 12, 13, -8, 7, -2, -18, 1, 17, -13, 15, 4, -37, 25, - -18, 8, 13, 1, -23, 21, -25, 10, 7, -1, -6, 10, -15, -7, 21, -26, - 29, -12, -3, -3, 0, -16, 29, -18, 21, -15, 1, -23, 22, -4, 3, 21, - -43, 22, -19, 4, 21, -8, 4, -11, -7, -5, 7, 19, -20, 31, -47, 11, - 2, -9, 44, -28, 8, -31, 5, -1, 20, 24, -38, 14, -32, -4, 47, -30, - 38, -41, -1, -12, 12, 27, -16, 29, -57, 12, -1, 3, 38, -29, 3, -25, - -1, 28, -10, 36, -52, 20, -33, 27, 14, -11, 18, -42, 13, 3, 3, 20, - -21, 0, -20, 15, 4, 0, 23, -49, 28, -24, 18, 16, -15, -2, -26, 22, - -10, 33, -7, -26, 11, -25, 19, 21, -14, 8, -33, 6, -2, 30, 2, -12, - -6, -37, 34, -4, 22, 1, -33, -3, -4, 15, 20, 3, -20, -16, 2, -14, - 38, -3, -7, 2, -24, -4, 22, -4, 11, -2, -15, -19, 21, -15, 24, 8, - -21, 1, -12, -3, 9, 21, -22, 17, -26, -2, 6, 14, -8, 19, -24, -10, - 8, -10, 17, 9, -7, -12, 8, -27, 29, -3, 4, -4, -3, -26, 25, -9, - 13, 9, -19, -7, 2, -4, 10, 19, -29, 13, -16, -3, 18, 4, -12, 10, - -24, 1, 6, 10, -9, 19, -26, -3, 16, -15, 20, -4, -16, 1, 3, -4, - 9, 6, -19, 7, 3, -18, 26, -13, -7, 12, -13, 2, 9, -5, -7, 15, - -18, 6, 8, -18, 13, -2, -12, 15, -12, 9, -6, -2, -16, 25, -14, 18, - 1, -29, 11, -4, 14, 2, 3, -26, 6, -3, 1, 19, -3, -15, 12, -29, - 17, -2, 12, -2, -4, -3, -28, 34, -21, 31, -7, -17, -3, -13, 20, 1, - 14, -14, -22, 11, -13, 33, -2, -11, -4, -30, 33, -12, 30, -17, -17, -4, - -4, 25, 2, 3, -20, -22, 20, -13, 42, -15, -11, -9, -16, 23, 8, 16, - -28, -3, -11, 4, 27, -8, 5, -17, -9, 8, -2, 25, -27, 17, -32, 19, - -4, 16, -8, -16, 6, -20, 32, 0, -14, 8, -34, 18, 12, 3, 13, -36, - 11, -34, 49, -14, 22, -12, -38, 17, -21, 42, 5, -10, -12, -34, 8, 18, - 18, 26, -50, 9, -50, 42, 16, 10, 10, -51, 2, -21, 38, 16, 7, -17, - -29, -12, 13, 19, 25, -16, -7, -40, 14, 5, 23, 6, -11, -23, -3, 11, - 2, 25, -26, 0, -12, 5, 4, 9, 2, -18, 10, -15, 5, 20, -26, 23, - -28, 6, 8, 1, 12, -26, 10, -19, 20, 7, -14, 17, -37, 18, 1, -1, - 23, -28, 9, -25, 20, 1, 6, 6, -23, 9, -15, 12, 10, -11, 5, -5, - -12, 15, -8, 4, 4, -4, -6, 8, -11, 3, 6, -6, 0, 6, -12, 1, - 14, -26, 27, -17, -3, 15, -18, 15, -10, 1, -6, 4, 9, -17, 28, -42, - 18, 3, -17, 45, -38, 9, -12, -7, 19, 8, 7, -31, 8, -18, 6, 53, - -51, 34, -41, -13, 32, -4, 17, -10, -6, -28, 25, 0, -2, 23, -32, -7, - 21, -28, 36, -7, -14, 7, -10, -4, 13, -3, -7, 7, -5, -6, 14, -10, - -10, 22, -29, 22, 0, -23, 24, -25, 15, 3, 3, -4, -9, 5, -23, 33, - -10, -6, 22, -48, 31, -8, 7, 10, -15, -5, -14, 20, -7, 16, 3, -32, - 20, -21, 13, 18, -20, 9, -25, 13, -3, 21, -4, -10, -4, -18, 18, 6, - 2, 6, -32, 8, -4, 18, 10, -3, -21, -12, 3, 3, 28, -3, -18, -4, - -14, 10, 19, 5, -9, -10, -21, 8, 21, 2, 11, -23, -12, -8, 14, 12, - -1, 5, -31, 14, -9, 15, 7, -14, 5, -19, 11, -3, 5, 1, -11, 12, - -13, 14, -6, -10, 5, -9, 16, -4, 3, -15, -5, 9, 2, 14, -11, -9, - -7, -7, 22, -2, 12, -14, -15, -2, 2, 19, 0, 6, -28, -3, 0, 5, - 27, -10, -8, -15, -9, 12, 10, 20, -25, 5, -23, 0, 27, -10, 21, -27, - -3, -14, 17, 8, 1, 6, -28, 2, 7, -2, 21, -14, -6, -9, 3, 6, - 2, 16, -33, 19, -17, 7, 10, -6, -3, -4, 0, 0, 11, -1, -13, 5, - -9, -1, 25, -27, 19, -20, 3, 9, 1, 2, -11, 5, -19, 26, -4, -6, - 13, -28, 10, 13, -11, 17, -19, -1, -10, 22, -4, -1, 13, -43, 29, -8, - 3, 18, -25, 5, -13, 16, -5, 12, 0, -29, 25, -23, 14, 17, -29, 23, - -23, 8, 2, 0, 4, -8, 11, -25, 22, -8, -6, 28, -35, 19, -6, -17, - 25, -15, 9, -5, 1, -12, 10, 5, -14, 22, -24, 0, 18, -23, 23, -9, - -10, 8, -1, -1, 4, -4, -13, 8, 6, -7, 22, -27, -8, 10, -6, 23, - 1, -17, -10, -9, 15, 14, 15, -17, -24, -1, -11, 41, 4, -4, -12, -35, - 12, 13, 19, 12, -22, -25, -6, 8, 22, 17, -3, -36, 7, -21, 21, 32, - -22, 8, -23, -17, 17, 15, 1, 10, -19, -20, 2, 10, 3, 23, -13, -21, - 7, -19, 26, 12, -10, 4, -35, 4, 7, 12, 19, -17, -3, -24, 14, 7, - 7, 15, -43, 12, -13, 8, 37, -29, 13, -34, 11, 2, 11, 14, -34, 22, - -31, 20, 14, -14, 18, -29, 5, -4, 3, 13, -11, 13, -23, 9, -3, -5, - 22, -22, 12, -10, -11, 15, -2, 6, 4, -10, -15, 11, -5, 10, 8, -14, - -12, 12, -10, 16, 17, -37, 16, -18, -3, 31, -11, -1, -9, -8, 0, 22, - 6, -21, 9, -32, 14, 26, -19, 27, -40, 6, -4, 13, 14, -14, 3, -34, - 21, 1, 10, 15, -32, 5, -10, 5, 19, -10, 3, -21, 10, -7, 14, 9, - -23, 18, -25, 9, 7, -5, 4, -1, -8, -2, 15, -17, 16, -5, -17, 16, - -13, 9, 3, 2, -17, 13, -10, -2, 29, -33, 17, -15, -10, 23, -6, 12, - -14, -3, -9, 2, 26, -23, 28, -45, 14, -1, 1, 33, -35, 17, -34, 15, - 10, 3, 12, -31, 7, -15, 18, 19, -19, 12, -39, 16, 5, 8, 17, -37, - 16, -35, 39, -3, 8, -5, -31, 9, -4, 26, 0, -3, -18, -15, 19, -2, - 25, -12, -21, 1, -16, 26, 4, 6, -20, -1, -14, 11, 21, -20, 22, -32, - 0, 14, -9, 19, -10, -2, -13, 14, -9, 4, 17, -36, 30, -20, -2, 22, - -21, 13, -11, 7, -12, 15, -6, -15, 25, -29, 20, 3, -18, 17, -17, 7, - -3, 11, -9, -4, 13, -33, 34, -10, -5, 22, -34, 11, -4, 8, -1, 11, - -14, -16, 24, -27, 31, 3, -29, 19, -23, 2, 26, -11, 1, -3, -14, -4, - 27, -14, 3, 9, -38, 26, -1, -7, 20, -15, -12, 14, -8, 4, 7, -11, - -10, 12, -3, 0, 16, -28, 7, 1, -2, 14, -7, -10, -5, 4, 5, 9, - 3, -22, 4, -5, 0, 27, -18, 1, -9, -10, 13, 10, 1, -9, -1, -21, - 15, 11, -8, 15, -21, -8, 12, -4, 13, 0, -12, -5, 2, -1, 9, 2, - -8, 0, -4, 1, 4, -1, -1, -1, -1, -2, -15, 21, -17, 23, -30, 1, - 34, -34, 6, 5, -15, 19, 1, -25, 6, 20, -2, -28, 15, 10, -15, 0, - -7, 10, 7, -5, -9, -6, 19, -3, -21, 3, 20, -4, -20, 1, 16, -3, - -8, -2, 5, 1, -8, -6, 3, 9, 2, -13, -4, 15, -7, -9, 0, 3, - 6, -7, -7, 5, 8, -8, -4, 0, 1, 1, -6, -4, 7, 2, -2, -7, - 0, 4, -3, -4, 0, 2, 0, -2, -4, 1, 4, -2, -4, -3, 1, 3, - -5, -4, 4, 3, -6, -5, 4, -1, -2, -3, 0, 3, -3, -1, -4, 3, - 3, -5, -3, 1, 1, -2, -3, 1, 2, -2, -4, 0, 0, 0, -1, -3, - 1, 1, -3, -2, 1, 0, -2, -2, 0, 0, -2, -1, 0, -1, 1, -2, - -2, 1, 0, -2, 0, -1, 0, -1, -1, -1, 0, 0, -1, -3, 1, 1, - -2, -2, 0, 1, -1, -2, -1, 0, 0, 0, -2, -1, 1, 0, -3, 0, - 2, -1, -2, 0, 0, 0, -2, 0, -1, 0, -1, -1, 1, 0, -1, 0, - -1, 1, 0, -13, 5, 7, -11, 24, -50, 41, 4, -29, 14, -11, 8, 11, - -15, -12, 15, 18, -21, -14, 22, -2, -11, -3, -3, 18, -3, -5, -14, 9, - 22, -24, -16, 23, 12, -23, -8, 9, 10, -4, -8, -3, 11, -4, -14, 0, - 8, 8, -5, -14, 8, 10, -12, -4, -2, 10, 0, -11, -3, 11, 0, -7, - -2, -1, 7, -6, -8, 3, 6, 0, -3, -8, 7, 2, -7, -2, 2, 1, - -2, -4, -1, 3, 3, -4, -5, 1, 3, -3, -6, 2, 5, -1, -7, -1, - 3, -1, -4, -3, 5, 0, -3, -2, -1, 4, -1, -5, -1, 3, -1, -4, - -1, 3, 1, -4, -2, 1, 0, -2, -3, 0, 2, -1, -4, 1, 1, -1, - -2, -2, 1, -1, -3, 0, 0, 0, -1, -2, 0, 0, -2, -1, 0, -1, - 0, -2, -1, 0, -1, 0, -1, -2, 2, -1, -2, -1, 0, 1, -2, 0, - -1, -1, 0, -1, -2, 0, 1, -1, -3, 0, 1, -1, -3, 0, 1, -2, - -1, 0, 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, -1, -1, 0, 0, - -2, 0, 0, 0, 0, -2, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, - 0, 0, -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, -1, -1, 0, - 0, 0, 1, -2, 4, -3, 3, -40, 71, -73, 67, -27, -68, 127, -80, 3, - 5, 1, 17, -14, 1, -30, 53, -3, -42, 15, 19, -9, -17, -1, 13, 16, - -17, 4, -32, 43, 15, -68, 18, 54, -38, -7, -1, 11, 7, -3, -18, 5, - 25, -27, -9, 9, 19, -6, -12, -8, 20, -1, -15, -1, 1, 17, -10, -16, - 12, 12, -13, 0, -6, 10, 2, -16, -1, 14, -4, 4, -11, -2, 12, -6, - -8, 4, 4, -2, -4, 1, -2, 4, 3, -7, -5, 8, 0, -10, 1, 4, - 2, -4, -6, 4, 1, -1, -7, 1, 8, -9, 2, -5, 3, 3, -4, -3, - 0, 3, -3, -5, 4, 3, -3, -4, 0, 2, 0, -3, -4, 5, 0, -5, - -1, 2, 0, -3, 0, -1, 2, -2, -4, 3, 0, -1, -2, -1, 2, -2, - -2, 1, -1, 0, -1, -3, 1, 1, -2, 1, -3, 1, 1, -3, -1, 1, - 0, -1, -2, 1, -1, -1, 1, -2, 1, -1, -1, -1, -1, 0, 1, -3, - 0, 0, 1, -4, 0, 1, -2, 0, -2, 0, 0, 0, -2, 1, -1, 0, - -2, 0, 2, -2, -1, 0, -1, 2, -2, -1, 1, -2, 0, -1, 1, -1, - -1, -1, 1, -2, 1, -1, -1, 2, -3, 0, 0, -1, 1, -1, 0, 1, - 0, -2, 0, -1, 1, -2, 0, 0, -1, 1, 0, -2, 0, 1, -2, 1, - 0, 0, -1, 0, 1, -1, -1, -1, 1, 1, -1, 0, 0, 0, -1, 1, - 0, -1, 1, 0, 0, 1, 0, -1, 1, 0, 3, -40, 58, -39, 12, 42, - -117, 108, 1, -66, 22, 17, 0, -9, 10, -39, 42, 4, -23, -12, 28, 3, - -34, 9, 17, 3, -9, 10, -29, 13, 53, -79, 3, 64, -26, -24, 16, -9, - 14, 2, -8, -15, 31, -9, -30, 11, 29, -15, -7, 0, 3, 6, -4, -9, - -6, 22, 1, -24, 9, 11, -8, 0, -2, 2, 8, -12, -6, 10, 2, 2, - -9, -4, 11, -2, -10, 3, 2, 3, -5, -1, 1, -1, 6, -4, -8, 9, - 2, -8, -3, 6, 3, -4, -3, -1, 6, -2, -8, 0, 9, -4, -3, -2, - 2, 4, -4, -1, -1, 4, -2, -6, 4, 2, -1, -4, 0, 1, 2, -3, - -5, 3, 3, -3, -4, 3, 0, -1, 0, -2, 2, 0, -3, 0, 3, 0, - -3, -1, 2, 0, -3, 1, 0, -1, 2, -2, -2, 2, -1, 0, -1, -1, - 1, -1, -2, 0, 0, 1, -3, 1, 0, -1, 1, -2, -1, 2, -2, -1, - 0, -1, 2, -3, -1, 1, 1, -2, -2, 2, 1, -2, -1, 0, 0, 1, - -3, 1, 0, 0, 0, -2, 3, 0, -2, 0, 0, 1, 0, -1, 1, -2, - 0, 0, 0, -1, 1, 0, 0, 0, -1, 1, -1, 1, 0, -1, 1, -2, - 0, 1, 1, 0, 1, -2, 1, 0, 1, 0, 0, 3, -1, 0, 1, 0, - 0, 3, -29, 35, -12, -16, 56, -88, 39, 62, -79, 5, 29, 1, -13, 12, - -29, 26, 17, -28, -3, 12, 5, -11, -19, 28, 1, -5, 9, -21, -7, 60, - -56, -20, 57, -10, -27, 21, -21, 16, 12, -12, -21, 24, 6, -29, 4, 19, - 2, -7, -5, -3, 7, 6, -11, -9, 11, 13, -18, -4, 13, 1, -3, -6, - -1, 10, -8, -6, 5, 3, 5, -3, -11, 4, 9, -11, 0, 4, 3, -4, - -1, 0, 0, 7, 0, -14, 7, 5, -7, -4, 4, 5, -1, -4, -4, 4, - 1, -4, -4, 7, -1, -1, -3, 0, 5, -1, -4, -1, 2, 0, -3, 1, - 1, 2, -2, -4, 1, 2, 0, -5, 2, 3, -2, -2, 1, 1, -2, 2, - -3, 0, 0, -1, -1, 0, 1, 0, -3, 0, 0, -1, 1, -1, -2, 1, - -1, 0, -2, 2, 1, -2, -1, 1, 0, -1, -1, 0, 1, -1, 0, -2, - 1, 1, -1, 0, -1, -1, 0, 0, -1, -1, 0, -1, -1, 2, -2, -1, - 1, 0, 0, -1, -1, 1, 0, -1, 1, -1, 0, 1, -3, 1, 1, -1, - -1, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 1, 0, 0, 2, -2, - 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, -1, -1, -7, -9, - 35, -52, 59, -33, -32, 64, -15, -41, 19, 22, -20, 9, -11, -3, 33, -27, - 2, 7, -9, 19, -37, 24, 7, -11, 11, -1, -30, 37, 8, -57, 36, 19, - -33, 14, 0, -17, 26, 1, -20, -5, 26, -18, -13, 14, 7, -6, 4, -9, - -4, 11, 3, -14, -7, 20, 0, -18, 10, 1, 4, -5, -7, 6, 0, -3, - -2, -2, 8, 5, -11, -6, 10, -1, -10, 6, -2, -1, 1, -3, 0, 3, - 5, -9, -5, 9, -3, -4, 1, 1, 3, -1, -4, -1, 2, -2, -5, 5, - -3, 0, 1, -5, 4, 2, -3, -3, 0, 0, -2, 1, 0, -2, 3, -2, - -5, 2, 2, -2, -4, 3, 0, -2, 1, -2, -2, 5, -2, -6, 1, 2, - -1, -1, 0, 1, -1, -2, -1, -1, 2, 0, -4, 0, 1, 0, -3, 0, - 2, 0, -3, 0, 0, 1, -1, -1, 1, 0, -1, -2, 1, 0, 0, -1, - 0, -2, 1, 0, -1, 1, -1, 0, -2, 1, 1, -2, -1, 2, -2, 1, - -3, 1, 1, -1, 0, 0, -1, 1, 0, -2, 2, -1, -1, 0, 0, 1, - 0, 1, 0, -2, 1, 0, 0, -1, 1, 0, 0, 0, 0, -3, -20, 45, - -56, 40, -5, -34, 27, 24, -42, -1, 29, -14, -4, 2, -7, 24, -20, -1, - 18, -25, 25, -29, 9, 21, -26, 14, 4, -20, 7, 27, -42, 5, 31, -24, - -2, 19, -30, 21, 8, -11, -17, 20, 1, -22, 11, 7, -7, 6, -5, -7, - 3, 11, -6, -18, 11, 16, -20, 1, 5, 2, -3, -3, 0, -3, 4, -1, - -7, 2, 10, -9, -8, 7, 2, -9, 5, -1, -5, 2, 1, -3, -2, 9, - -5, -8, 4, 1, -5, 0, 1, 2, -1, 0, -5, 4, -1, -5, 4, -3, - 1, 1, -5, 3, 0, 0, -3, 0, -1, -2, 1, 2, -5, 2, 1, -5, - -2, 3, -1, -5, 2, 1, -4, 2, -1, -4, 2, 3, -7, -1, 2, 0, - -2, 1, 0, -2, -1, 0, -3, 1, 2, -3, -2, 3, 0, -3, -1, 1, - 0, -1, -2, -1, 1, 0, 0, -1, 0, 0, -2, 0, 0, 1, -2, 2, - -3, 1, 0, 0, -2, 1, 0, -1, 0, 0, -1, -1, 2, -3, 0, 0, - -1, 0, 0, -1, 1, 0, -4, -13, 32, -41, 31, -10, -10, 4, 22, -25, - -8, 21, -3, -14, 5, 1, 12, -23, 8, 18, -31, 25, -26, 10, 17, -23, - 8, 5, -9, 0, 16, -25, 2, 23, -22, -2, 22, -30, 15, 7, -6, -13, - 12, 1, -17, 9, 5, -6, 4, -3, -7, 5, 7, -6, -13, 7, 10, -11, - 0, 0, 4, -3, -3, 2, -7, 4, 2, -5, 0, 6, -3, -8, 4, 2, - -8, 7, 0, -8, -1, 6, 0, -8, 6, 0, -5, 1, 0, -5, 3, 2, - -3, -2, 4, -5, -1, -1, -2, 3, -4, 1, -1, -3, 3, -1, -2, -2, - 1, -2, -2, 1, 1, -4, 1, 2, -5, -3, 5, -3, -4, 4, -1, -4, - 2, -1, -4, 3, 1, -5, -2, 2, 0, -2, 2, -1, -4, 3, -1, -3, - 0, 1, -2, -2, 1, -1, -1, -1, 0, 0, -1, -1, -1, 0, -1, 1, - -1, -1, 0, -2, 1, 0, -1, -1, 0, -1, -1, -1, 2, -2, -1, 1, - -1, -2, 1, -1, -1, 1, -2, 1, -7, -3, 15, -23, 20, -16, 9, -12, - 16, -12, -8, 11, 5, -18, 6, 8, 0, -18, 16, 4, -19, 16, -17, 10, - 5, -8, -2, 9, -5, -4, 10, -17, 5, 13, -18, 2, 12, -17, 10, 0, - -2, -8, 7, -4, -7, 6, 1, -3, 1, 3, -9, -2, 10, -7, -8, 4, - 6, -6, 1, 0, 0, -2, 1, -1, -8, 6, 1, -5, 2, 4, -2, -4, - 1, 1, -7, 5, -1, -4, -2, 4, 0, -4, 4, -3, -4, 1, 0, -3, - 0, 2, -1, -2, 2, -2, -1, -3, 0, 3, -4, 3, -3, 0, 2, 0, - -3, -1, 1, -3, -1, 2, 0, -1, 0, 0, -3, 0, 1, -4, -1, 2, - 0, -2, 0, 1, -3, 1, 1, -3, -2, 2, -1, -1, 2, -1, -2, 1, - 0, -1, -1, 0, 2, 33, 42, 58, 71, 79, 85, 88, 91, 94, 79, 95, - 82, 106, 86, 105, 47, 16, -6, 13, 44, 31, -15, -38, -36, 20, 70, 41, - 48, 58, 24, -57, -127, -119, -102, -126, -128, -111, -78, -82, -88, -87, -60, -66, - -98, -104, -99, -97, -99, -104, -101, -88, -87, -91, -61, -27, -34, -54, -55, -45, - -24, -10, -5, -4, 5, 34, 63, 101, 94, 78, 52, 51, 52, 74, 81, 77, - 59, 46, 17, 7, 39, 53, 47, 42, 66, 83, 73, 52, 28, 22, 11, 8, - 11, 0, -15, -23, -15, -14, -6, 16, 46, 62, 71, 76, 90, 102, 103, 103, - 101, 100, 90, 75, 63, 67, 49, 37, 28, 12, 5, 6, 15, 15, 8, -7, - -12, -4, -10, -28, -24, -17, -25, -50, -64, -81, -103, -116, -116, -113, -95, -72, - -54, -41, -47, -65, -65, -50, -33, -24, -7, 11, 8, -4, -13, -28, -51, -75, - -90, -91, -90, -90, -87, -88, -83, -84, -82, -81, -81, -76, -65, -71, -85, -84, - -79, -83, -81, -77, -72, -70, -65, -66, -66, -65, -66, -68, -61, -56, -51, -36, - -13, -3, -5, -8, -12, -12, 3, 16, 21, 31, 50, 69, 77, 82, 90, 102, - 110, 114, 116, 117, 118, 119, 116, 112, 109, 105, 98, 99, 103, 102, 91, 73, - 64, 63, 61, 57, 51, 40, 24, 35, 57, 75, 84, 79, 65, 37, 4, -26, - -45, -57, -54, -46, -45, -54, -67, -67, -48, -16, 15, 35, 44, 45, 44, 45, - 46, 38, 23, 2, -15, -34, -52, -60, -70, -77, -80, -79, -74, -77, -84, -86, - -80, -72, -68, -72, -80, -87, -92, -96, -101, -104, -104, -101, -93, -90, -89, -86, - -85, -84, -83, -82, -81, -79, -77, -76, -73, -71, -66, -62, -55, -39, -31, -27, - -25, -31, -37, -46, -51, -53, -54, -48, -45, -38, -20, 3, 24, 35, 39, 32, - 16, 5, 3, 0, -6, -13, -13, -11, -2, 14, 28, 40, 50, 53, 50, 55, - 64, 74, 90, 105, 108, 112, 106, 104, 109, 112, 123, 127, 127, 127, 127, 127, - 127, 118, 113, 107, 110, 114, 111, 104, 101, 101, 102, 103, 99, 99, 89, 73, - 53, 35, 20, 0, -22, -43, -63, -77, -82, -76, -65, -48, -36, -29, -24, -25, - -29, -37, -40, -49, -59, -67, -73, -76, -78, -79, -75, -73, -74, -75, -68, -52, - -44, -30, -19, -9, -6, -9, -13, -24, -33, -35, -31, -30, -35, -40, -44, -45, - -51, -53, -54, -50, -50, -47, -42, -50, -55, -54, -56, -56, -54, -54, -49, -48, - -41, -32, -28, -18, -13, -5, 6, 18, 33, 49, 60, 71, 78, 88, 95, 97, - 93, 88, 91, 93, 97, 98, 97, 94, 91, 85, 81, 72, 70, 66, 61, 60, - 64, 66, 74, 83, 92, 102, 108, 109, 107, 102, 97, 95, 91, 87, 80, 74, - 67, 62, 61, 58, 61, 61, 57, 53, 43, 35, 27, 25, 24, 20, 20, 22, - 27, 34, 36, 32, 21, 8, -3, -10, -16, -18, -16, -16, -19, -15, -11, -11, - -12, -20, -34, -45, -59, -72, -80, -89, -94, -95, -102, -111, -114, -111, -111, -108, - -106, -104, -101, -98, -93, -90, -86, -86, -83, -82, -81, -79, -76, -73, -70, -72, - -78, -81, -79, -79, -72, -60, -43, -31, -25, -27, -34, -37, -40, -42, -41, -39, - -36, -34, -25, -12, -4, 5, 12, 16, 17, 15, 13, 6, -4, -7, -8, -6, - -1, 4, 7, 9, 12, 16, 19, 19, 22, 28, 29, 28, 29, 30, 34, 40, - 49, 57, 71, 78, 85, 92, 96, 95, 89, 85, 86, 93, 99, 104, 102, 100, - 94, 85, 77, 73, 69, 66, 63, 60, 60, 59, 57, 52, 47, 41, 31, 18, - 6, -3, -7, -11, -12, -14, -18, -22, -23, -22, -24, -30, -37, -41, -44, -50, - -56, -64, -67, -65, -62, -58, -58, -58, -59, -61, -62, -66, -72, -78, -79, -77, - -73, -68, -64, -61, -56, -53, -54, -52, -52, -57, -63, -69, -70, -68, -65, -62, - -59, -57, -56, -58, -60, -61, -63, -64, -62, -61, -60, -58, -54, -49, -45, -42, - -39, -36, -32, -28, -22, -13, -7, -3, 2, 13, 28, 41, 52, 64, 71, 73, - 73, 70, 64, 61, 60, 64, 66, 65, 66, 64, 61, 60, 62, 65, 64, 66, - 67, 67, 68, 66, 64, 66, 68, 73, 76, 74, 72, 66, 58, 52, 46, 42, - 38, 38, 41, 47, 52, 52, 48, 45, 42, 40, 38, 34, 29, 27, 26, 28, - 29, 28, 29, 30, 31, 28, 24, 21, 19, 17, 14, 10, 6, 3, -4, -9, - -15, -19, -26, -33, -40, -49, -55, -60, -65, -70, -73, -72, -72, -71, -70, -71, - -75, -78, -81, -83, -86, -86, -85, -84, -82, -80, -77, -72, -69, -66, -63, -61, - -61, -61, -61, -61, -60, -58, -53, -48, -42, -36, -30, -28, -30, -32, -33, -32, - -31, -28, -22, -18, -10, -5, 0, 3, 6, 11, 16, 19, 22, 24, 26, 27, - 29, 34, 40, 46, 48, 48, 48, 45, 40, 36, 33, 31, 33, 35, 40, 48, - 55, 62, 68, 73, 76, 78, 78, 77, 79, 82, 85, 87, 87, 87, 86, 86, - 86, 83, 78, 71, 63, 55, 48, 44, 39, 36, 36, 36, 35, 32, 28, 24, - 18, 13, 9, 6, 4, 1, -2, -5, -11, -17, -20, -21, -20, -21, -24, -28, - -32, -34, -33, -33, -35, -37, -40, -43, -47, -52, -58, -63, -69, -74, -77, -80, - -81, -82, -81, -80, -77, -74, -69, -62, -54, -48, -48, -51, -54, -57, -57, -57, - -56, -55, -55, -56, -57, -56, -55, -54, -54, -54, -54, -52, -49, -45, -41, -38, - -34, -31, -29, -27, -24, -20, -17, -11, -7, -3, 0, 5, 10, 16, 22, 27, - 31, 34, 38, 42, 44, 45, 48, 50, 52, 57, 61, 64, 64, 65, 65, 63, - 60, 57, 55, 55, 58, 61, 63, 65, 67, 69, 71, 74, 77, 79, 79, 77, - 74, 71, 68, 66, 63, 60, 57, 55, 51, 46, 40, 36, 30, 25, 20, 17, - 16, 17, 16, 14, 12, 10, 7, 3, -1, -5, -11, -15, -17, -18, -18, -19, - -21, -25, -29, -32, -33, -33, -36, -39, -43, -46, -50, -53, -56, -58, -59, -60, - -61, -62, -63, -65, -66, -67, -68, -70, -72, -72, -70, -67, -63, -61, -60, -60, - -58, -56, -54, -53, -52, -52, -52, -51, -50, -49, -47, -45, -43, -40, -37, -35, - -34, -32, -29, -25, -21, -18, -14, -9, -4, 0, 4, 7, 11, 15, 18, 21, - 25, 28, 33, 37, 41, 44, 46, 47, 47, 46, 46, 45, 43, 42, 42, 43, - 46, 48, 49, 50, 52, 55, 59, 62, 65, 66, 67, 68, 69, 69, 70, 72, - 74, 74, 73, 72, 71, 69, 65, 61, 57, 53, 50, 46, 43, 38, 35, 32, - 28, 23, 19, 17, 17, 15, 13, 11, 9, 5, 1, -3, -6, -9, -12, -14, - -17, -19, -23, -27, -31, -35, -38, -40, -43, -46, -48, -52, -55, -57, -61, -64, - -66, -67, -68, -69, -70, -70, -70, -69, -69, -70, -71, -70, -66, -62, -59, -55, - -52, -50, -46, -43, -41, -38, -36, -35, -35, -34, -33, -33, -33, -33, -31, -30, - -28, -26, -25, -24, -21, -20, -20, -19, -19, -18, -17, -16, -15, -13, -11, -8, - -3, 2, 9, 15, 21, 27, 33, 38, 41, 45, 48, 51, 53, 55, 56, 56, - 56, 56, 56, 56, 56, 55, 57, 58, 60, 61, 62, 62, 64, 66, 68, 69, - 71, 72, 73, 74, 72, 70, 67, 63, 60, 57, 54, 50, 46, 41, 36, 31, - 27, 23, 19, 16, 14, 12, 11, 9, 8, 5, 2, -1, -4, -8, -10, -15, - -18, -19, -20, -22, -22, -23, -23, -24, -26, -29, -31, -33, -35, -36, -37, -38, - -41, -44, -46, -48, -50, -52, -54, -56, -59, -61, -63, -63, -64, -65, -64, -63, - -62, -61, -60, -59, -58, -57, -58, -57, -57, -55, -53, -50, -49, -47, -46, -43, - -40, -37, -33, -31, -28, -26, -23, -20, -16, -14, -12, -9, -5, -2, 1, 5, - 9, 13, 17, 21, 24, 26, 29, 32, 35, 37, 37, 38, 39, 41, 43, 44, - 45, 46, 48, 50, 51, 53, 52, 52, 50, 48, 47, 46, 46, 46, 46, 47, - 48, 49, 51, 54, 56, 58, 60, 61, 62, 62, 62, 61, 59, 57, 55, 54, - 53, 52, 51, 49, 46, 41, 36, 31, 27, 22, 18, 14, 11, 9, 6, 3, - 0, -2, -5, -8, -11, -16, -20, -25, -28, -31, -34, -37, -39, -41, -41, -42, - -42, -42, -43, -45, -46, -47, -49, -50, -52, -54, -56, -57, -58, -60, -61, -63, - -64, -64, -64, -63, -63, -61, -59, -58, -57, -55, -54, -53, -52, -52, -51, -50, - -49, -47, -46, -45, -44, -42, -40, -38, -35, -32, -30, -28, -25, -22, -19, -17, - -15, -12, -9, -5, -1, 3, 7, 11, 15, 19, 23, 25, 27, 30, 34, 36, - 37, 38, 39, 40, 42, 44, 45, 46, 47, 49, 50, 52, 53, 52, 51, 49, - 47, 47, 46, 46, 46, 47, 47, 48, 50, 52, 55, 57, 59, 61, 62, 62, - 62, 61, 60, 58, 56, 54, 54, 53, 51, 50, 47, 44, 39, 34, 29, 25, - 20, 16, 13, 10, 7, 4, 2, -1, -3, -6, -9, -14, -18, -22, -26, -30, - -33, -35, -38, -40, -41, -41, -42, -42, -43, -44, -46, -47, -48, -49, -51, -53, - -55, -56, -57, -59, -60, -62, -63, -64, -64, -63, -63, -62, -60, -59, -57, -56, - -55, -53, -52, -52, -51, -51, -50, -48, -46, -45, -44, -43, -41, -39, -36, -34, - -31, -29, -26, -24, -21, -16, 1, -2, -1, -9, -9, -6, 5, 6, -1, -10, - 8, 24, 11, -2, -14, -9, -15, -13, 5, 14, 12, -6, -1, -12, 1, -9, - 12, 12, 10, 5, -19, -11, -13, -2, 8, 5, 1, -2, -3, 9, -6, 6, - 5, 6, -3, -17, -7, 3, 2, -1, 0, 7, -7, 5, 4, 6, -18, -24, - 6, 20, -1, -4, -1, 10, 3, -10, 8, 7, -11, -17, -15, 5, 18, 4, - 1, 8, -16, -4, 0, 11, 9, -10, -15, 0, -22, -12, 19, 34, 16, -9, - -16, -7, -12, -10, 13, 23, -1, -10, -2, -3, -11, 13, 7, -6, -9, 3, - 11, -10, -18, 12, 22, 7, -27, -29, -4, 20, 20, 10, 8, -16, -26, -6, - 22, 21, 7, 15, 8, -50, -50, -7, 35, 22, -13, 32, 41, -33, -46, -10, - 23, -7, -25, 23, 21, -38, -36, 14, 44, 2, 2, 34, -14, -51, -29, 11, - 19, 7, 22, 13, -23, -21, -8, -9, 1, 14, 26, 26, -8, -34, -33, 4, - 1, -6, -2, 16, -7, -23, 12, 27, 5, 6, 6, 0, -8, 0, -1, -17, - -13, -12, 3, 9, 4, 11, 23, 36, 0, -43, -16, 4, -21, -26, 27, 16, - -25, 3, 65, 4, -34, 24, -10, -38, -14, 13, 4, -15, 36, 44, -42, -51, - 20, -5, -6, 68, 20, -18, -39, -11, 9, 17, 6, -33, -20, -13, 48, 30, - 22, -4, -9, -53, -20, 32, 32, -16, 17, -11, -36, -8, -5, 39, 28, 33, - 21, -64, -48, 3, -22, 15, 62, -26, 0, 3, 5, 73, -14, -48, -20, -59, - 4, 70, 60, -7, -2, -88, -22, -17, 39, 17, 33, -3, 15, 28, -47, -80, - -37, 5, 7, 104, 16, -99, -92, -36, 109, 78, 26, -15, -92, -21, 62, 48, - -51, -81, -25, 55, 63, 35, 21, -115, -54, 101, 73, -41, -110, -66, 50, 107, - 45, -8, -109, -38, 12, 102, 3, 17, -45, -2, -36, 39, 46, -12, -28, -27, - -17, 17, -18, 82, -5, -3, -25, -5, -14, 15, 9, -3, -17, -6, 2, 7, - -36, -13, 6, 21, -23, -20, 16, -18, 3, -2, 26, 0, 13, -23, -2, -19, - -28, -18, 15, 12, 22, -4, 23, -17, -22, -9, -18, -4, 11, 13, 0, 34, - -16, -20, 26, 23, 15, -4, -25, 7, 8, -9, 8, 44, 1, -40, 17, -32, - 9, -30, -52, 52, 3, 2, -21, 83, 58, -14, -46, -61, -12, -67, -20, 64, - 72, 57, -10, 5, 1, -77, 31, -47, -39, 12, 22, 57, 28, 0, 9, -76, - 15, -74, 33, -12, 39, 114, -35, -36, -38, -23, 27, -21, 14, 56, 47, 6, - -72, -61, -4, 18, -4, 19, 13, 45, 71, 48, -1, -125, -52, -56, -20, -18, - -12, 51, 78, 68, -46, 32, -40, -29, -28, -81, -25, 75, 42, 58, -38, 1, - -29, -34, 31, -36, -14, 10, 64, 37, 2, -31, -72, -17, -33, 30, -52, -54, - 25, 43, 70, 81, -9, -73, 4, -65, 15, -28, 25, 0, 28, 19, 51, -26, - 6, 0, -37, -15, -22, -20, -16, -5, 50, 56, 67, 25, 16, -35, -29, -14, - -39, 19, -24, -52, -13, -32, -10, 39, 33, 59, 6, 37, 55, 11, -9, -35, - -15, -57, -56, -36, -34, 19, 19, 6, 20, 17, -11, 5, 26, 19, 16, 7, - -20, -26, -55, -62, -36, -18, 19, 37, 47, 25, -6, -14, 1, -4, -13, 12, - 23, 34, 38, 41, 33, 31, -10, -56, -52, -49, -31, -40, -21, -12, 0, 5, - 12, 22, 22, 21, 31, 12, 2, -8, -4, -18, -7, 3, 1, -1, 11, 12, - 18, 17, 9, -2, -12, -13, -11, -1, 8, 3, 3, 2, 5, -5, -16, -15, - -13, -8, -12, -9, -2, -1, 2, 7, 10, 7, 11, 14, 7, -1, -4, 5, - -3, -2, 0, -6, -10, -1, -5, 3, 9, 0, -8, -9, -6, -6, 0, 6, - 3, 6, 7, 10, 0, -8, -3, -5, -1, -8, -7, -4, -3, -3, 0, -1, - -6, 2, 7, 7, 5, 4, 10, 5, 8, -1, -11, -15, -11, -15, -10, -1, - -8, -12, -5, 1, 3, 6, 8, 11, 18, 22, 26, 10, -10, -1, -15, -3, - -21, -16, -14, -12, -7, -8, -18, -20, -11, 9, 20, 27, 26, 11, 1, 21, - 6, 3, -9, -15, -9, -20, 3, 5, 21, 14, 6, 11, -21, -22, -6, -21, - -23, -18, 11, 6, 5, 21, 9, 23, 16, -3, -30, -7, -27, -4, 5, 18, - 22, 16, 2, 7, -1, -2, -10, -14, -10, -17, -10, -15, -16, 3, 12, 30, - 18, -1, -6, -15, -3, 5, 11, -18, -2, 8, 21, 11, -13, -4, -30, -7, - 0, 12, 25, -3, 17, 14, -20, -6, -27, -41, -11, -12, 23, -8, 13, 24, - 18, 27, -11, -8, -12, -2, 17, 23, 13, -20, -21, -2, -21, -34, -46, -23, - 28, 48, 9, -10, 8, 29, 27, 5, -29, -12, 13, -5, -2, -35, 1, 3, - 24, 13, 17, -18, -30, -21, 14, -1, 6, -8, 48, 45, -7, -34, -49, -32, - -6, -26, 20, 29, 76, 30, -21, -66, -36, -15, 40, -5, 29, 3, 10, -39, - -25, -2, 24, 19, 19, -4, -8, 3, -22, -23, -18, 13, 17, -3, -25, 23, - 66, 26, -18, -27, -34, -30, -30, 36, 25, 28, -22, -17, -7, -22, 21, 18, - 42, 8, -25, -28, -31, -10, 15, 18, 0, -1, -5, 16, -12, 13, 13, 12, - -8, -37, -9, 13, -5, 8, -3, 13, -8, 4, 24, -16, -43, -18, 26, 26, - -11, -9, 19, 9, -15, 9, 15, -12, -31, -27, 8, 29, 5, 7, 17, -33, - -14, 14, 23, -1, -18, -18, -4, -35, -17, 47, 71, -16, -20, -11, -16, -25, - 6, 37, 14, -18, 1, -8, -14, 10, 14, 2, -20, 0, 20, -10, -25, 14, - 32, 7, -39, -38, -3, 34, 25, 13, 3, -24, -34, 5, 38, 18, 7, 29, - -30, -74, -41, 36, 40, -12, 26, 55, -17, -59, -26, 28, -2, -31, 24, 25, - -44, -39, 21, 44, -1, 10, 33, -34, -50, -12, 18, 13, 20, 17, -6, -31, - -10, -6, -1, 7, 12, 14, 6, -16, -24, 6, 9, -16, -16, 6, 2, -10, - 13, 12, -10, 0, 11, 11, 10, -3, -22, -22, -12, -7, 19, 17, -2, -12, - 6, 16, 7, -11, -1, -20, -22, -8, 26, 16, -3, 12, 1, -33, 2, 30, - -23, -5, 28, -17, -19, 21, 9, -28, -14, 25, -1, 4, 24, 0, -26, -9, - 7, 2, -2, 20, -10, -11, 5, -3, -4, 8, -9, 14, 18, 25, -22, -15, - -22, -3, -12, 27, 30, 15, -11, -26, -4, 15, -7, -14, 23, -23, -4, 34, - -2, -38, 14, -11, -24, 16, 34, 11, -13, 3, -3, -19, -34, 0, -3, 24, - 43, 1, -12, -38, -25, -11, 23, 35, 12, -28, -25, -16, 7, 22, 1, -10, - 8, 8, -3, 6, -24, -20, -13, 9, 31, 12, -16, 7, -29, 5, 8, -28, - 3, 4, 12, 26, -9, -15, -5, -20, 9, 21, 0, 1, -9, 0, 8, -3, - -7, -9, -3, 22, 8, 3, -11, -9, -11, 3, 15, 9, -10, 1, -3, -3, - -2, -5, 9, 0, 12, 7, -15, -7, 0, -8, 5, 9, -5, 7, -7, 10, - 4, -11, -2, -8, -4, 9, 9, 0, -2, -11, -3, -4, 3, 4, 3, -2, - 3, 3, -8, -9, -2, 0, 3, 5, -1, -10, -7, 2, 8, 3, 0, -5, - -5, 2, 4, -2, -5, -3, 2, 3, 0, 2, -5, -3, 3, 2, -2, -4, - -2, 1, 2, 1, 0, -1, 1, -2, -5, 0, 0, 2, 0, -3, -2, 0, - 1, 0, -2, -2, -2, 0, 3, 3, -2, -5, -1, -1, -1, -4, 3, 9, - 1, -1, -2, -11, -7, 1, 9, 11, 8, -4, -11, -12, -9, -4, 18, 15, - 14, 1, -22, -29, -14, 3, 30, 29, 14, -2, -35, -43, -11, 13, 36, 42, - 15, -16, -49, -44, -10, 28, 47, 38, 11, -25, -66, -39, 4, 36, 58, 33, - -3, -44, -65, -29, 19, 52, 54, 23, -13, -59, -65, -15, 32, 69, 49, 8, - -30, -74, -51, 3, 43, 71, 40, -5, -48, -77, -31, 16, 57, 67, 24, -15, - -67, -72, -12, 36, 66, 59, 5, -31, -80, -51, 3, 49, 75, 37, -2, -59, - -81, -28, 20, 67, 66, 22, -23, -76, -65, -10, 41, 78, 48, 4, -36, -85, - -47, 6, 59, 80, 31, -8, -69, -82, -22, 29, 73, 63, 17, -31, -81, -63, - -1, 47, 79, 47, 3, -56, -90, -40, 19, 75, 73, 28, -25, -86, -74, -10, - 48, 85, 56, 6, -51, -93, -48, 11, 67, 86, 33, -11, -78, -87, -29, 36, - 89, 66, 13, -38, -91, -60, 2, 50, 83, 48, 0, -56, -90, -41, 16, 71, - 78, 30, -17, -80, -75, -20, 31, 82, 62, 15, -32, -85, -66, -7, 48, 84, - 50, 4, -53, -87, -44, 8, 62, 78, 35, -8, -65, -83, -30, 23, 70, 71, - 24, -20, -76, -75, -12, 32, 73, 62, 15, -30, -85, -62, -2, 41, 76, 51, - 9, -39, -86, -52, 1, 45, 79, 46, 8, -49, -89, -46, 3, 54, 80, 43, - 7, -55, -83, -50, 0, 53, 76, 54, 11, -52, -83, -55, 0, 40, 67, 58, - 22, -32, -79, -67, -11, 28, 63, 52, 37, -9, -70, -63, -28, 10, 42, 49, - 53, 8, -46, -64, -41, 1, 22, 38, 51, 39, -16, -63, -46, -23, 5, 33, - 38, 48, 14, -42, -57, -29, -5, 22, 37, 40, 28, -23, -53, -39, -10, 14, - 30, 40, 31, -1, -48, -40, -18, 11, 19, 31, 26, 14, -20, -50, -25, -5, - 11, 31, 30, 14, 0, -35, -39, -4, -1, 19, 27, 17, 9, -10, -39, -21, - -8, 9, 24, 26, 13, -5, -19, -30, -12, -1, 17, 25, 16, 3, -19, -26, - -13, -6, 17, 22, 20, 5, -16, -32, -19, -1, 23, 27, 23, 4, -30, -33, - -23, -1, 35, 35, 24, -2, -41, -45, -21, 9, 45, 41, 22, -12, -50, -46, - -18, 28, 55, 45, 10, -27, -78, -42, 0, 53, 66, 32, -1, -61, -74, -28, - 27, 64, 64, 24, -28, -80, -66, -15, 53, 84, 48, 5, -59, -94, -41, 17, - 75, 80, 26, -21, -91, -79, -12, 48, 87, 55, 10, -58, -96, -46, 9, 80, - 81, 30, -23, -84, -80, -15, 49, 90, 49, 9, -57, -95, -45, 17, 76, 79, - 26, -20, -91, -75, -18, 52, 90, 52, 6, -59, -92, -41, 15, 68, 80, 31, - -21, -87, -76, -13, 45, 87, 49, 11, -60, -94, -35, 14, 80, 68, 22, -23, - -89, -66, -7, 47, 93, 44, -8, -61, -95, -31, 24, 86, 75, 10, -35, -96, - -66, -1, 61, 100, 44, -12, -77, -105, -33, 32, 97, 92, 16, -44, -111, -90, - -5, 65, 121, 65, -3, -80, -123, -59, 17, 98, 111, 46, -25, -112, -109, -33, - 42, 112, 90, 30, -55, -115, -84, -17, 66, 105, 71, 13, -73, -113, -61, 0, - 77, 96, 56, 4, -80, -108, -50, 8, 78, 93, 47, 3, -88, -98, -40, 7, - 65, 76, 53, 18, -71, -90, -44, 0, 39, 57, 43, 34, -19, -69, -54, -19, - 18, 32, 31, 34, 7, -40, -36, -21, -1, 12, 12, 25, 27, -9, -32, -14, - -14, 2, 0, 1, 20, 19, -2, -13, -11, -18, -12, -2, 18, 24, 12, -2, - -14, -19, -19, -12, 18, 24, 22, -2, -15, -32, -20, 3, 22, 26, 17, -13, - -31, -27, -13, 17, 33, 32, 5, -29, -47, -29, 2, 33, 42, 32, -6, -53, - -52, -24, 22, 51, 41, 27, -32, -74, -45, 0, 45, 59, 33, -1, -62, -66, - -31, 26, 73, 49, 17, -42, -80, -42, -8, 63, 72, 28, -10, -75, -72, -23, - 32, 88, 47, 13, -56, -93, -38, 10, 76, 69, 26, -20, -96, -66, -10, 48, - 90, 47, 0, -69, -103, -29, 25, 87, 73, 18, -35, -104, -68, -2, 61, 93, - 47, -5, -83, -98, -31, 30, 92, 68, 17, -39, -97, -63, -5, 64, 88, 35, - -9, -74, -86, -22, 31, 85, 54, 13, -44, -93, -46, 9, 65, 75, 23, -17, - -75, -78, -15, 39, 84, 54, 3, -52, -96, -46, 12, 71, 90, 29, -18, -89, - -87, -26, 36, 86, 72, 26, -37, -106, -77, -12, 45, 99, 68, 22, -46, -108, - -73, -10, 43, 87, 69, 19, -27, -92, -79, -12, 27, 63, 57, 26, 4, -53, - -75, -35, 12, 33, 37, 31, 26, -9, -53, -39, -16, 6, 20, 23, 22, 13, - -8, -22, -23, -18, -3, 9, 25, 19, 4, -8, -20, -17, -10, 6, 16, 17, - 13, -8, -34, -21, -6, 17, 33, 23, 6, -32, -51, -23, 11, 36, 46, 31, - -11, -46, -65, -31, 15, 59, 55, 28, -20, -73, -64, -26, 42, 78, 51, 14, - -53, -85, -48, -4, 70, 80, 38, -16, -80, -76, -32, 39, 90, 58, 19, -59, - -99, -50, 14, 71, 75, 36, -21, -94, -70, -23, 51, 88, 53, 9, -68, -97, - -40, 16, 83, 73, 29, -33, -100, -61, -13, 58, 87, 41, 0, -74, -81, -35, - 24, 87, 55, 20, -41, -88, -58, 0, 69, 73, 34, -5, -86, -75, -20, 38, - 79, 49, 13, -48, -90, -39, 2, 71, 68, 31, -16, -84, -67, -15, 38, 79, - 42, 12, -50, -85, -37, 2, 62, 71, 34, -5, -83, -75, -24, 27, 82, 51, - 27, -30, -88, -54, -15, 44, 73, 50, 16, -49, -81, -47, -6, 38, 58, 50, - 27, -31, -69, -52, -13, 15, 36, 45, 33, -5, -41, -44, -23, 2, 14, 27, - 33, 10, -25, -20, -18, -6, 1, -1, 17, 22, 3, -13, -10, -17, -13, -6, - 13, 24, 15, 1, -11, -19, -19, -16, 12, 24, 24, 3, -12, -29, -26, -1, - 18, 27, 19, -4, -31, -28, -19, 11, 30, 35, 12, -21, -46, -35, -6, 28, - 42, 36, 5, -46, -57, -31, 10, 50, 43, 33, -16, -71, -55, -9, 35, 62, - 38, 10, -51, -71, -40, 11, 69, 58, 24, -26, -81, -50, -18, 48, 79, 37, - 1, -62, -81, -32, 16, 84, 59, 20, -37, -96, -50, -2, 63, 78, 33, -4, - -85, -80, -20, 33, 88, 59, 10, -50, -107, -47, 14, 75, 85, 27, -19, -95, - -83, -15, 47, 94, 60, 8, -66, -105, -46, 15, 83, 81, 26, -23, -91, -76, - -18, 48, 92, 47, 1, -59, -94, -36, 18, 78, 66, 19, -27, -91, -60, -3, - 53, 80, 35, -8, -62, -86, -28, 27, 79, 66, 13, -38, -94, -62, 1, 56, - 95, 42, -6, -75, -96, -39, 22, 80, 80, 36, -20, -97, -92, -24, 30, 93, - 79, 32, -27, -102, -87, -22, 31, 81, 79, 29, -14, -81, -91, -25, 19, 56, - 63, 31, 11, -39, -77, -47, 3, 31, 37, 33, 27, 3, -48, -46, -20, 0, - 18, 22, 23, 16, -3, -20, -19, -15, -4, 2, 8, 5, 0, 0, 0, 1, - -1, -1, 3, -4, -2, 1, -1, -2, 2, 3, -6, 1, 2, -6, 2, 2, - -4, -1, 2, -5, 1, 4, -4, 0, -1, 0, -1, -2, 2, 2, -6, 0, - 4, -3, -3, 4, -2, -3, -2, 0, 1, 1, -2, -2, 3, -8, 27, -42, - 11, 21, -35, 34, -25, 12, 9, -24, 14, 13, -38, 53, -42, -3, 46, -73, - 55, -16, -9, 28, -49, 38, -12, -21, 49, -51, 20, 32, -73, 64, -28, -7, - 32, -50, 42, -11, -30, 49, -21, -31, 46, -25, -7, 20, -22, 18, -16, -10, - 21, -23, 5, 28, -35, 8, 0, 8, -26, 19, 6, -11, -20, 64, -46, -18, - 51, -73, 119, -117, 46, 36, -80, 67, -46, 22, 0, -24, 56, -59, 14, 26, - -40, 24, -9, 20, -20, -15, 43, -26, -11, 9, 14, -3, -31, 6, 54, -62, - 3, 67, -78, 20, 21, -25, 31, -41, 18, 27, -53, 32, 15, -48, 37, -11, - 4, -12, -3, 31, -24, -21, 42, -10, -45, 55, -32, 34, -43, -14, 86, -78, - 8, 39, -35, -2, 13, 2, 5, -11, -4, 7, 5, -31, 37, -4, -28, 28, - -9, -11, 10, -1, 4, -18, 17, -9, -13, 24, -18, 20, -18, -30, 59, -25, - -29, 48, -15, -29, 23, 4, -3, -18, 14, 6, -8, -19, 19, 8, -13, 0, - 13, -18, 4, 1, 0, 0, 10, -14, -12, 39, -46, 23, 9, -22, 23, -20, - -22, 63, -42, -28, 77, -66, 12, 38, -56, 31, 27, -77, 66, -11, -39, 59, - -33, -41, 92, -54, -50, 96, -36, -46, 46, -17, 31, -43, -28, 98, -57, -50, - 84, -22, -44, 39, -8, 17, -28, -13, 63, -67, 16, 10, 3, -15, -4, 36, - -34, -1, 26, -27, -2, 13, 7, -22, 0, 27, -11, -19, 6, 26, -42, 14, - 18, -7, -14, -10, 37, -14, -24, 25, -4, -5, -10, 3, 35, -39, -7, 31, - -8, -23, 15, 4, -1, -25, 28, 7, -35, 34, -16, -1, 9, -35, 45, -22, - -17, 48, -52, 24, 22, -65, 48, 7, -45, 47, -19, -33, 71, -70, 46, -7, - -52, 68, -25, -35, 48, -13, -17, 14, 2, -12, 8, -10, 1, 22, -32, 4, - 34, -26, -18, 29, -7, -19, 15, -7, 15, -8, -29, 50, -22, -35, 53, -19, - -37, 47, -9, -40, 41, 1, -27, 7, 3, 0, 0, -7, 13, -7, -21, 26, - 14, -44, 11, 40, -51, 10, 26, -28, 16, -13, -3, 31, -42, 11, 34, -52, - 11, 34, -43, 10, 29, -19, -21, 27, -10, -5, 10, -14, 11, 3, -35, 43, - 3, -52, 37, 22, -66, 49, -12, -19, 50, -58, 16, 42, -70, 50, -2, -42, - 60, -69, 43, 11, -57, 54, -8, -31, 23, -8, -7, 24, -32, 11, 21, -51, - 60, -44, -6, 68, -87, 33, 45, -79, 50, -7, -13, 21, -40, 31, 12, -41, - 18, 24, -39, 15, 7, -17, 25, -20, -12, 43, -47, 17, 6, -16, 10, 4, - -11, -1, 14, -10, -7, 6, 9, -23, 9, 3, 13, -30, 16, 16, -33, 17, - 4, -17, 23, -29, 3, 54, -86, 50, 11, -41, 30, -23, 15, 18, -60, 56, - 7, -65, 49, -4, -12, 1, -6, 19, -4, -33, 35, -10, -12, 13, -2, -2, - -2, 2, -10, 16, -8, -11, 19, -6, -19, 24, -14, 9, 3, -24, 24, -6, - -13, 19, -11, -6, 6, -9, 16, -8, -10, 14, -10, -1, -5, 16, -8, -25, - 37, -11, -27, 37, -14, -13, 19, -17, 14, -5, -15, 26, -27, 10, 11, -23, - 22, -5, -19, 25, -7, -28, 44, -35, 0, 25, -31, 31, -10, -26, 46, -41, - 2, 33, -40, 24, 8, -43, 44, -12, -25, 37, -25, -6, 29, -27, 5, 24, - -40, 24, -1, -25, 23, -1, -6, -2, -1, 14, -24, 8, 13, -11, 0, -13, - 16, 15, -56, 43, 12, -35, 14, -9, 18, -10, -19, 28, -3, -27, 23, -2, - -14, 27, -35, 10, 35, -68, 44, 7, -43, 46, -21, -25, 56, -35, -21, 51, - -33, -8, 28, -27, 19, -2, -26, 36, -26, 3, 13, -12, 6, -10, 8, -14, - 15, -12, 0, 13, -9, -16, 32, -27, 3, 23, -49, 49, -17, -31, 63, -64, - 25, 36, -76, 61, -11, -47, 75, -54, -9, 69, -81, 32, 29, -63, 46, -7, - -26, 39, -31, 6, 18, -26, 13, -5, 5, -5, -2, 5, -12, 17, -17, -2, - 22, -25, 1, 20, -19, 3, 6, -6, 3, -9, 10, -6, -3, 7, -7, -3, - 12, -5, -5, -11, 24, -7, -23, 24, 0, -14, 0, 12, -10, -2, 5, 0, - 1, -10, 10, -2, -17, 26, -11, -16, 28, -22, 6, 4, -17, 30, -27, -7, - 46, -54, 15, 29, -42, 25, -4, -15, 26, -29, 11, 15, -28, 19, -7, 1, - 8, -20, 14, 1, -15, 11, -2, -2, 0, -10, 15, -5, -12, 15, -1, -15, - 12, 4, -15, 9, -1, -9, 9, -5, -6, 13, -12, 1, 6, -6, -3, 6, - -4, 0, -6, 11, -9, -2, 13, -12, -2, -1, 8, -11, 4, 2, -6, 4, - -4, 4, 0, -13, 15, 0, -21, 23, -5, -15, 15, -2, -9, 6, -2, -4, - 2, 3, -1, -7, 7, -2, -9, 6, 2, -9, 4, 5, -12, 10, -9, 4, - 5, -16, 12, -2, -13, 20, -13, -4, 17, -23, 14, 2, -20, 22, -13, -3, - 15, -22, 12, 4, -18, 17, -7, -7, 13, -14, 6, 4, -10, 9, -5, -6, - 7, 0, -7, 8, -4, -1, 0, -6, 4, 7, -14, 2, 13, -16, 3, 10, - -15, 7, -1, -10, 14, -10, -2, 11, -9, -4, 7, -6, 3, -3, -5, 9, - -6, -3, 5, 1, -7, 3, -2, 0, -2, 0, 4, -3, -2, 4, -6, 4, - -2, -2, 0, 1, 0, -7, 7, -2, -7, 9, -7, -4, 11, -15, 11, -2, - -9, 9, -4, -3, 2, 3, -7, 5, 0, -5, 6, -7, 1, 7, -10, -2, - 13, -9, -4, 8, -4, -2, -1, 1, 1, -7, 4, 5, -8, 0, 6, -6, - 0, 3, -4, 0, 1, -2, 2, -4, -4, 8, -7, -1, 6, -9, 8, -3, - -6, 12, -12, 1, 10, -11, 1, 5, -6, 3, -2, -3, 7, -10, 2, 7, - -12, 5, 2, -5, 3, -5, 0, 6, -10, 3, 4, -8, 2, 2, -3, 3, - -8, 8, 2, -14, 10, 3, -12, 8, 2, -11, 8, -2, -6, 9, -7, -4, - 10, -9, -1, 7, -7, 1, 3, -8, 8, -2, -8, 10, -3, -5, 5, -6, - 3, 1, -8, 10, -5, -5, 7, -4, -2, 2, -3, 1, -1, -3, 4, -3, - 0, 0, 0, 0, -4, 3, -2, -3, 3, -5, 3, 0, -7, 5, 1, -8, - 5, 1, -6, 6, -5, 0, 3, -7, 3, 2, -6, 3, 2, -6, 3, 1, - -3, -2, 5, -4, -1, 3, -4, 0, 0, -3, 5, -5, -3, 7, -5, -3, - 6, -4, 0, -1, -3, 3, -2, -1, 2, -1, -2, 1, -2, 1, -1, -7, - 8, -1, 5, -7, 13, -22, 8, -7, 8, -110, -28, 24, 54, 36, 2, 60, - -45, 57, 42, -43, 20, 41, -66, 24, -11, 18, -18, -38, -63, -36, 30, -11, - 33, 25, 30, 18, 11, -18, -5, 5, -46, 40, 1, -13, -18, -20, -31, 20, - 10, 29, -7, -18, 40, -29, -17, 42, -19, 6, -4, 6, -8, 10, -26, -5, - 3, 1, -17, 6, 0, 19, -1, 8, 0, -6, -10, -1, -12, -1, 1, -3, - 8, -7, 4, 11, 4, 14, -13, 16, -19, -4, -13, -13, -14, 6, 4, -1, - 4, 11, -1, 11, -1, 1, -4, -1, -15, 6, -9, 1, -1, 0, 3, 1, - -8, 3, -1, -1, 2, -2, 2, -2, 1, -5, -7, 3, -3, 6, -3, 4, - -1, 0, -4, 2, -7, 3, -6, -1, -1, 4, 0, 3, -2, 2, -5, 5, - -8, -3, -3, 2, -5, 7, -1, 4, -2, 4, -10, 6, -6, -1, -4, 5, - -13, 7, -6, 5, -8, 17, -20, 14, -6, 9, -40, 71, -127, 9, -73, 127, - 76, -28, 74, -32, 8, -62, -49, -38, 40, -68, 22, -12, 68, 10, 39, -10, - 0, 35, -23, 0, -59, -15, -7, -3, -23, 1, -20, 37, 27, 2, 30, -2, - 17, 2, -5, -7, -27, -29, 16, -3, -11, 1, -16, -5, -8, -10, 7, 32, - 9, 5, -4, 16, 5, -8, -17, -16, 5, -13, 8, 11, 15, -10, -9, 0, - -1, 2, 7, -3, -23, 9, 2, 3, 1, -13, -1, -6, 11, -6, 8, 1, - 12, -12, 9, -14, 8, -1, 0, -3, -13, 4, -7, -4, 8, 5, -5, -7, - 4, -2, -3, 2, 3, -6, 8, -3, 1, -3, -2, 2, -6, 2, -4, -3, - -4, 3, 1, 0, 0, 1, -1, -1, 2, -2, 0, -4, -2, 1, 2, 0, - -3, 1, -3, 0, -1, -3, -6, 2, -2, 3, -4, 10, -8, 9, -5, 12, - -19, 46, 37, -128, 60, -90, 102, -65, 40, -57, 39, -6, 23, -8, 19, 24, - 15, -17, -47, -27, -36, -16, 21, 3, 23, 14, 50, -8, 19, 25, 7, -9, - -28, -63, -37, 0, -42, 54, -17, 68, -3, 30, -12, -4, 11, -15, 9, -25, - -15, -2, -27, -25, 38, -8, -13, 33, 24, 12, -38, 39, -12, -3, -17, -44, - 38, 2, 27, 3, -5, -4, -13, -30, -56, -4, 11, 1, 9, 17, 46, 25, - -14, 6, -3, -7, -21, 2, 16, -5, -22, 2, -2, 6, -12, -25, -15, 10, - 9, 8, 11, 43, 8, -5, -22, -16, 14, -31, 16, 7, -7, -26, -20, -2, - 9, 11, 26, 7, 6, -20, -13, 0, 4, 17, -17, -18, 10, 2, -10, 27, - -8, 24, -23, -14, 1, 0, 13, -19, 14, 10, -16, 16, -4, -20, 20, -33, - 2, 2, 24, 21, -3, -26, -24, -18, -18, 10, 10, 24, 18, 2, 9, -24, - 16, -14, -8, 9, -5, -14, 8, -5, 30, -11, 11, -13, -15, -12, 7, 4, - -13, -13, 13, -13, 12, 23, 9, 0, 14, -10, -9, -35, -2, -21, 12, -1, - 17, 19, 11, -4, 0, -18, -24, 11, -10, 1, 11, 12, -13, -16, 10, -23, - 21, 9, -9, 3, 12, -6, 3, -5, 12, 0, -2, 0, -19, -9, 5, -11, - -7, 10, 1, -3, 9, 18, -6, 0, -1, 1, -13, 2, 1, -3, -8, 17, - -4, -9, 18, -15, 8, -1, -11, -5, -14, 11, -5, -7, 12, 16, -7, 7, - -3, -11, -5, -6, 1, 4, -3, -3, 15, 5, 0, 3, 6, -16, 4, -14, - -6, -9, -4, 2, 11, 11, 7, -2, 4, -12, -7, -14, -6, -7, 9, 4, - 7, -2, 6, 5, 6, -4, -3, -4, 7, -7, -11, -9, 0, -3, 7, -2, - -2, 3, 13, -4, -6, -15, 9, -7, -1, 4, 6, 5, 8, -6, -8, 0, - -11, -4, 6, -8, 4, 3, 5, 13, -4, -9, -3, 4, -3, -3, 4, -1, - -12, 6, -14, 2, 3, 15, 2, 6, -7, -8, 3, 1, -2, 3, -3, -12, - -6, -14, 7, -2, 13, 6, 10, 6, 0, -2, -10, -12, -8, -6, -7, -6, - 6, 4, -2, 5, 2, 0, -1, 3, -11, 4, 0, 20, -8, -2, 0, -1, - -3, 7, -3, -4, -2, -6, -10, -10, -8, 1, 2, 5, 8, 2, 5, 8, - 3, 4, 3, -2, -15, 0, -1, -7, -2, -5, -10, 10, -1, 5, 3, 5, - -1, -2, -8, -5, -9, 1, -8, 6, 5, 4, 1, 1, 2, 3, -2, 4, - -7, 1, -7, -9, -2, 0, 2, 3, 6, -8, 8, 3, 0, -2, -9, -3, - -2, 0, 3, -1, -2, -3, 7, -3, 10, -8, 1, -12, 3, -7, 2, -3, - 7, 4, 4, 0, 0, -6, -1, -5, -3, -4, -7, 0, 5, 7, 0, 2, - -3, 10, -1, 3, -7, -5, -4, -9, -3, -7, 5, -4, 9, 2, 1, 4, - 5, 0, -5, 1, -8, 4, -9, 5, -5, 0, 3, -2, -1, 1, 1, -7, - 7, 0, 3, -5, 0, -3, -1, -1, -5, -1, 1, -1, 1, -1, 0, 2, - 0, 2, -7, -7, 4, -1, 0, 3, 4, -1, -3, -4, -6, 3, -2, 4, - -1, 5, -2, -1, -5, -2, -4, 1, 3, 2, 2, 0, -3, 1, 1, -3, - -3, -1, 1, -3, -2, -1, -2, -3, -1, 0, 4, 3, 5, 2, 1, -4, - -9, -3, -7, 1, -2, 7, -2, 3, 3, 3, 1, 0, -1, -6, -7, -6, - -4, -1, 1, 0, 5, 2, -2, 2, -3, -1, 3, -1, 1, -4, -4, -5, - 0, -7, 2, -4, 3, 4, 1, 2, -1, -1, -2, -2, 0, -1, 1, -1, - -1, -3, 1, 1, 3, -3, -1, 1, 1, -2, -3, -8, -5, 0, -1, 5, - 2, 3, 1, -2, -1, -1, -3, 1, 1, -2, -3, -3, -1, 0, -1, 1, - 2, 2, 5, 0, -1, -2, -1, -2, 0, -4, 0, -5, -1, -1, 0, 1, - 5, 4, -2, -1, -2, 0, -6, -1, 0, 1, -1, -2, 1, 0, 0, 3, - 1, -2, 1, -2, -4, -1, 0, -1, -1, -4, -2, -4, 2, -1, 1, 0, - 3, 2, 0, 4, -1, 4, -6, 2, -4, -3, -5, -4, -3, 0, 2, 0, - 1, 4, 2, 2, -2, -2, -5, -6, -5, -3, -2, 1, -1, 0, 0, 2, - 2, 2, 0, 4, -2, 3, 2, -1, -2, -3, -3, -3, -5, -5, -5, -1, - -1, 0, 2, 2, 4, 1, 2, 1, 2, -1, -1, -3, -4, -5, -3, -2, - -2, -1, 1, 4, 2, 2, 2, 1, -1, -2, -6, -2, -3, 2, -1, 1, - -2, 0, 2, 1, 2, -2, 1, 0, -2, -2, -3, 0, -2, -1, -1, 0, - -2, -2, 1, 0, 2, -1, 1, -1, 0, -1, -1, -7, 8, -1, 5, -7, - 13, -22, 8, -7, 8, -110, -28, 24, 54, 36, 2, 60, -45, 57, 42, -43, - 20, 41, -66, 24, -11, 18, -18, -38, -63, -36, 30, -11, 33, 25, 30, 18, - 11, -18, -5, 5, -46, 40, 1, -13, -18, -20, -31, 20, 10, 29, -7, -18, - 40, -29, -17, 42, -19, 6, -4, 6, -8, 10, -26, -5, 3, 1, -17, 6, - 0, 19, -1, 8, 0, -6, -10, -1, -12, -1, 1, -3, 8, -7, 4, 11, - 4, 14, -13, 16, -19, -4, -13, -13, -14, 6, 4, -1, 4, 11, -1, 11, - -1, 1, -4, -1, -15, 6, -9, 1, -1, 0, 3, 1, -8, 3, -1, -1, - 2, -2, 2, -2, 1, -5, -7, 3, -3, 6, -3, 4, -1, 0, -4, 2, - -7, 3, -6, -1, -1, 4, 0, 3, -2, 2, -5, 5, -8, -3, -3, 2, - -5, 7, -1, 4, -2, 4, -10, 6, -6, -1, -4, 5, -13, 7, -6, 5, - -8, 17, -20, 14, -6, 9, -40, 71, -127, 9, -73, 127, 76, -28, 74, -32, - 8, -62, -49, -38, 40, -68, 22, -12, 68, 10, 39, -10, 0, 35, -23, 0, - -59, -15, -7, -3, -23, 1, -20, 37, 27, 2, 30, -2, 17, 2, -5, -7, - -27, -29, 16, -3, -11, 1, -16, -5, -8, -10, 7, 32, 9, 5, -4, 16, - 5, -8, -17, -16, 5, -13, 8, 11, 15, -10, -9, 0, -1, 2, 7, -3, - -23, 9, 2, 3, 1, -13, -1, -6, 11, -6, 8, 1, 12, -12, 9, -14, - 8, -1, 0, -3, -13, 4, -7, -4, 8, 5, -5, -7, 4, -2, -3, 2, - 3, -6, 8, -3, 1, -3, -2, 2, -6, 2, -4, -3, -4, 3, 1, 0, - 0, 1, -1, -1, 2, -2, 0, -4, -2, 1, 2, 0, -3, 1, -3, 0, - -1, -3, -6, 2, -2, 3, -4, 10, -8, 9, -5, 12, -19, 46, 37, -128, - 60, -90, 102, -65, 40, -57, 39, -6, 23, -8, 19, 24, 15, -17, -47, -27, - -36, -16, 21, 3, 23, 14, 50, -8, 19, 25, 7, -9, -28, -63, -37, 0, - -42, 54, -17, 68, -3, 30, -12, -4, 11, -15, 9, -25, -15, -2, -27, -25, - 38, -8, -13, 33, 24, 12, -38, 39, -12, -3, -17, -44, 38, 2, 27, 3, - -5, -4, -13, -30, -56, -4, 11, 1, 9, 17, 46, 25, -14, 6, -3, -7, - -21, 2, 16, -5, -22, 2, -2, 6, -12, -25, -15, 10, 9, 8, 11, 43, - 8, -5, -22, -16, 14, -31, 16, 7, -7, -26, -20, -2, 9, 11, 26, 7, - 6, -20, -13, 0, 4, 17, -17, -18, 10, 2, -10, 27, -8, 24, -23, -14, - 1, 0, 13, -19, 14, 10, -16, 16, -4, -20, 20, -33, 2, 2, 24, 21, - -3, -26, -24, -18, -18, 10, 10, 24, 18, 2, 9, -24, 16, -14, -8, 9, - -5, -14, 8, -5, 30, -11, 11, -13, -15, -12, 7, 4, -13, -13, 13, -13, - 12, 23, 9, 0, 14, -10, -9, -35, -2, -21, 12, -1, 17, 19, 11, -4, - 0, -18, -24, 11, -10, 1, 11, 12, -13, -16, 10, -23, 21, 9, -9, 3, - 12, -6, 3, -5, 12, 0, -2, 0, -19, -9, 5, -11, -7, 10, 1, -3, - 9, 18, -6, 0, -1, 1, -13, 2, 1, -3, -8, 17, -4, -9, 18, -15, - 8, -1, -11, -5, -14, 11, -5, -7, 12, 16, -7, 7, -3, -11, -5, -6, - 1, 4, -3, -3, 15, 5, 0, 3, 6, -16, 4, -14, -6, -9, -4, 2, - 11, 11, 7, -2, 4, -12, -7, -14, -6, -7, 9, 4, 7, -2, 6, 5, - 6, -4, -3, -4, 7, -7, -11, -9, 0, -3, 7, -2, -2, 3, 13, -4, - -6, -15, 9, -7, -1, 4, 6, 5, 8, -6, -8, 0, -11, -4, 6, -8, - 4, 3, 5, 13, -4, -9, -3, 4, -3, -3, 4, -1, -12, 6, -14, 2, - 3, 15, 2, 6, -7, -8, 3, 1, -2, 3, -3, -12, -6, -14, 7, -2, - 13, 6, 10, 6, 0, -2, -10, -12, -8, -6, -7, -6, 6, 4, -2, 5, - 2, 0, -1, 3, -11, 4, 0, 20, -8, -2, 0, -1, -3, 7, -3, -4, - -2, -6, -10, -10, -8, 1, 2, 5, 8, 2, 5, 8, 3, 4, 3, -2, - -15, 0, -1, -7, -2, -5, -10, 10, -1, 5, 3, 5, -1, -2, -8, -5, - -9, 1, -8, 6, 5, 4, 1, 1, 2, 3, -2, 4, -7, 1, -7, -9, - -2, 0, 2, 3, 6, -8, 8, 3, 0, -2, -9, -3, -2, 0, 3, -1, - -2, -3, 7, -3, 10, -8, 1, -12, 3, -7, 2, -3, 7, 4, 4, 0, - 0, -6, -1, -5, -3, -4, -7, 0, 5, 7, 0, 2, -3, 10, -1, 3, - -7, -5, -4, -9, -3, -7, 5, -4, 9, 2, 1, 4, 5, 0, -5, 1, - -8, 4, -9, 5, -5, 0, 3, -2, -1, 1, 1, -7, 7, 0, 3, -5, - 0, -3, -1, -1, -5, -1, 1, -1, 1, -1, 0, 2, 0, 2, -7, -7, - 4, -1, 0, 3, 4, -1, -3, -4, -6, 3, -2, 4, -1, 5, -2, -1, - -5, -2, -4, 1, 3, 2, 2, 0, -3, 1, 1, -3, -3, -1, 1, -3, - -2, -1, -2, -3, -1, 0, 4, 3, 5, 2, 1, -4, -9, -3, -7, 1, - -2, 7, -2, 3, 3, 3, 1, 0, -1, -6, -7, -6, -4, -1, 1, 0, - 5, 2, -2, 2, -3, -1, 3, -1, 1, -4, -4, -5, 0, -7, 2, -4, - 3, 4, 1, 2, -1, -1, -2, -2, 0, -1, 1, -1, -1, -3, 1, 1, - 3, -3, -1, 1, 1, -2, -3, -8, -5, 0, -1, 5, 2, 3, 1, -2, - -1, -1, -3, 1, 1, -2, -3, -3, -1, 0, -1, 1, 2, 2, 5, 0, - -1, -2, -1, -2, 0, -4, 0, -5, -1, -1, 0, 1, 5, 4, -2, -1, - -2, 0, -6, -1, 0, 1, -1, -2, 1, 0, 0, 3, 1, -2, 1, -2, - -4, -1, 0, -1, -1, -4, -2, -4, 2, -1, 1, 0, 3, 2, 0, 4, - -1, 4, -6, 2, -4, -3, -5, -4, -3, 0, 2, 0, 1, 4, 2, 2, - -2, -2, -5, -6, -5, -3, -2, 1, -1, 0, 0, 2, 2, 2, 0, 4, - -2, 3, 2, -1, -2, -3, -3, -3, -5, -5, -5, -1, -1, 0, 2, 2, - 4, 1, 2, 1, 2, -1, -1, -3, -4, -5, -3, -2, -2, -1, 1, 4, - 2, 2, 2, 1, -1, -2, -6, -2, -3, 2, -1, 1, -2, 0, 2, 1, - 2, -2, 1, 0, -2, -2, -3, 0, -2, -1, -1, 0, -2, -2, 1, 0, - 2, -1, 1, -1, 0, -1, -1, 1, -7, 5, -22, -32, -35, -32, -43, -35, - -55, -42, -66, -48, -80, -57, -17, -128, -59, -76, 0, -26, 1, -33, 21, 3, - 16, 15, 26, 43, 28, 66, 6, 97, 40, 103, 67, 101, 102, 98, 94, 21, - 98, 90, 57, 78, 89, 81, 61, -6, 54, 4, 62, 19, 27, 34, 12, 16, - 14, -17, 19, -5, -2, -13, -38, -24, -3, -33, -14, -11, -16, 0, -13, 7, - -26, -13, -16, 6, -57, -23, -28, -13, -9, -34, -32, -20, -87, -62, -28, -38, - -75, -37, -27, -41, -71, -48, -30, -44, -83, -67, -52, -48, -45, -46, -45, -63, - -47, -40, -32, -45, -24, -32, -43, -21, -17, 0, 21, 26, 43, 51, 62, 47, - 41, 55, 57, 68, 34, 53, 63, 62, 71, 60, 61, 56, 53, 56, 54, 38, - 50, 58, 50, 40, 28, 54, 39, 41, 38, 22, 32, 20, -3, 19, -1, -7, - -6, -16, -16, -14, -27, -29, -46, -66, -61, -51, -54, -61, -41, -50, -47, -52, - -55, -45, -44, -28, -58, -56, -31, -37, -36, -32, -18, -16, -34, -29, -9, -21, - -20, -30, -22, -17, -19, -8, -12, -14, -6, -14, -6, -11, -2, 4, -6, 9, - 8, 17, 23, 13, 31, 13, 24, 30, 28, 29, 30, 43, 34, 37, 52, 42, - 44, 50, 67, 59, 49, 54, 48, 43, 51, 45, 42, 62, 47, 39, 37, 36, - 24, 28, 13, 3, 9, -11, -3, -9, -14, -18, -34, -27, -29, -39, -42, -38, - -46, -37, -46, -43, -41, -35, -38, -31, -38, -34, -39, -39, -34, -48, -44, -47, - -49, -54, -52, -44, -53, -37, -47, -38, -31, -38, -27, -19, -19, -15, -16, 0, - 0, 2, 7, 13, 29, 22, 32, 32, 39, 47, 41, 40, 55, 48, 41, 44, - 57, 43, 36, 47, 43, 42, 37, 32, 32, 27, 33, 36, 30, 23, 25, 25, - 22, 18, 22, 20, 16, 8, 6, 12, 7, 0, 1, 3, -5, -14, -9, -7, - -8, -19, -15, -16, -23, -21, -21, -32, -31, -29, -26, -27, -29, -33, -26, -29, - -30, -39, -28, -41, -43, -35, -34, -32, -29, -28, -28, -25, -27, -24, -27, -27, - -27, -22, -23, -17, -9, -10, -14, -10, -8, -4, -2, -1, -3, 5, 4, 10, - 11, 7, 13, 11, 14, 27, 22, 22, 22, 27, 36, 34, 36, 37, 45, 44, - 47, 48, 51, 49, 52, 51, 52, 48, 50, 47, 48, 42, 40, 29, 33, 24, - 22, 12, 5, 0, -3, -5, -9, -21, -21, -25, -19, -28, -28, -30, -33, -39, - -42, -42, -46, -46, -45, -42, -43, -47, -47, -36, -32, -30, -34, -31, -22, -29, - -29, -30, -26, -28, -30, -21, -26, -27, -21, -19, -16, -11, -12, -8, -2, 1, - -4, 1, 0, 1, 9, 8, 7, 12, 10, 13, 20, 17, 18, 21, 26, 29, - 30, 30, 29, 34, 33, 34, 33, 30, 32, 33, 28, 33, 29, 35, 32, 31, - 30, 31, 30, 25, 27, 24, 21, 21, 20, 16, 17, 12, 6, 4, -3, 1, - -6, -7, -11, -13, -11, -10, -8, -13, -12, -9, -17, -14, -19, -24, -22, -24, - -30, -32, -30, -33, -37, -39, -40, -42, -39, -41, -39, -40, -41, -35, -35, -35, - -37, -36, -33, -30, -25, -25, -19, -16, -16, -10, -6, -7, -4, -2, 1, 3, - 6, 10, 9, 15, 17, 18, 17, 13, 19, 18, 17, 19, 20, 24, 24, 27, - 27, 29, 30, 26, 28, 28, 27, 28, 26, 25, 24, 25, 20, 19, 17, 18, - 15, 12, 13, 10, 6, 8, 6, 3, 4, 3, 0, -3, 0, -1, -2, -5, - -4, -5, -4, -5, -6, -8, -9, -9, -12, -11, -16, -16, -15, -15, -13, -17, - -16, -17, -17, -21, -20, -25, -24, -24, -24, -26, -30, -30, -27, -30, -26, -26, - -27, -27, -25, -24, -19, -20, -17, -13, -12, -8, -8, -8, -6, -5, -2, -1, - 0, 3, 8, 10, 12, 16, 18, 24, 25, 25, 28, 30, 28, 32, 33, 31, - 32, 31, 35, 33, 31, 31, 27, 28, 26, 23, 23, 20, 22, 18, 16, 13, - 11, 9, 5, 4, -2, -2, -3, -8, -9, -11, -12, -13, -15, -15, -15, -15, - -15, -14, -12, -12, -13, -13, -8, -11, -10, -12, -10, -12, -12, -8, -8, -9, - -9, -9, -8, -9, -10, -11, -11, -10, -13, -14, -13, -16, -16, -17, -17, -18, - -19, -18, -17, -16, -16, -15, -15, -13, -12, -10, -12, -10, -9, -8, -6, -6, - -3, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 15, 15, 14, 13, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, - 3, 2, 1, 0, -1, -1, -2, -3, -4, -5, -5, -6, -7, -7, -8, -9, - -9, -10, -11, -11, -12, -12, -13, -13, -13, -13, -14, -14, -14, -15, -15, -15, - -15, -15, -15, -16, -16, -16, -15, -15, -15, -14, -13, -13, -12, -11, -10, -9, - -8, -7, -6, -5, -4, -2, -1, 0, 1, 2, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, - 17, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 13, 12, 11, 10, - 9, 7, 6, 5, 3, 1, 0, -2, -4, -5, -7, -9, -10, -11, -13, -14, - -15, -15, -16, -17, -17, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -17, -17, -16, -16, -15, -14, -14, -13, -12, -11, -10, -9, -8, -7, -6, - -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, - 11, 11, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 14, 14, 14, 13, 12, 12, 11, 10, 9, 8, 8, 7, - 6, 5, 4, 3, 2, 1, 0, 0, -1, 10, -20, 30, 25, 21, 14, 4, - 15, -48, -33, 11, -70, 54, -5, -21, -8, -3, 73, -52, 65, -55, 80, -28, - -67, -3, -13, 21, -49, -2, 11, 36, 59, -60, 34, -28, 21, -25, -45, 54, - 5, 0, -19, -12, 20, 54, -51, -23, 22, 36, -59, -20, 8, 28, -9, -54, - 127, -44, 69, -128, 5, 69, -8, -98, 45, 69, 20, -97, 23, -7, 121, -81, - -2, -21, 51, -67, -14, -24, 127, -60, 45, -116, 127, -29, -93, -23, 107, -5, - -21, -62, 37, 41, 29, -74, -63, 103, 24, -59, -44, 62, 43, -28, -46, 7, - 72, 19, -70, -47, 42, 53, -68, -13, 37, 59, -38, -60, 39, 66, 27, -128, - 36, 77, 15, -74, -15, 75, 38, -49, -11, -39, 16, -8, -30, 35, 41, -1, - -2, 17, -68, 99, -97, 60, -49, 32, -44, -29, 82, -26, 39, -35, 10, 38, - -20, -21, -92, 83, -24, 13, 31, -33, 22, 45, -31, -24, 9, -24, -32, 42, - -17, 34, 7, -27, 6, 61, -9, -34, -5, -8, -17, -6, -34, 17, 43, -9, - 35, -34, 16, 27, -24, -17, -17, 5, -17, 42, -31, 22, 17, -26, -22, 32, - 41, -27, -25, -10, -5, 16, -2, 13, -1, 48, -33, -27, 6, 16, 13, -37, - -11, 18, 25, -42, -11, 46, -7, -15, 9, 15, 4, -3, -36, -24, 31, -8, - 14, 12, 27, -19, -17, -14, -7, 42, -5, -15, 5, 1, -15, 14, 43, -19, - 1, -25, -35, 16, 16, 29, -12, 8, -14, 1, 21, -8, -12, -22, -4, 24, - 26, -16, -22, 37, 3, -41, 7, 4, 3, 30, 4, -27, 11, -6, -26, 33, - 23, -23, -14, -20, -7, -4, 36, 0, 18, 10, -27, 1, 1, 16, -1, -4, - -44, -5, 17, 9, 13, -4, -3, 31, 24, -14, -26, 9, -27, -28, 19, 22, - 32, -11, -15, 5, 15, -23, -21, 16, 14, 18, -11, -26, 13, 10, -12, -12, - 11, 14, -6, -13, -3, 6, -6, 3, 12, 32, 14, -22, -45, -10, 37, 11, - -50, -11, 50, 22, -13, -4, -4, 15, -16, -33, 7, 34, -9, -14, -1, 21, - 15, -14, -12, -6, 7, 8, 2, 0, -5, 6, 15, 4, -9, 13, 3, -51, - -18, 27, 10, 5, -11, 6, -1, 5, 22, 2, -14, -39, -12, 19, 17, 4, - 11, 5, -25, 2, 23, 8, 2, -3, -39, -22, 4, 18, 6, 14, 25, 20, - -17, -20, 17, 7, -43, -38, -18, 17, 24, -6, 30, 44, 6, -36, -20, 7, - 24, 1, -69, -25, 47, 15, -4, 35, 19, -18, -22, -12, 20, 39, -36, -49, - 9, 28, -16, 9, 34, 36, -22, -69, -16, 39, 7, -28, -3, 33, -18, -7, - 18, 53, 24, -37, -61, -10, 38, 2, -24, -11, 12, 17, 0, 28, 50, -5, - -59, -57, 22, 14, -15, -5, 22, 9, -20, 19, 33, 31, -33, -62, -13, -2, - 45, -9, -4, -3, 19, 8, -8, 40, 8, -16, -44, -19, 16, 3, 23, -32, - 22, 5, -9, 5, 26, 21, -27, -18, -45, 3, 15, 0, 7, 7, 7, 13, - 18, -10, 3, -5, -30, -30, -3, 9, 31, 17, -10, 19, 28, -33, -20, 31, - 14, -67, -27, 13, 20, 29, 1, -2, 24, -3, -26, -12, 32, -7, -31, -17, - 5, 22, 11, -6, 6, 7, 2, 7, 5, -12, -22, -17, -24, 22, 47, 1, - 2, 10, 5, -29, -5, 13, 1, -30, -28, -5, 23, 25, 6, 5, 1, 7, - 0, 5, 3, -33, -37, -6, 19, 20, 26, -1, -15, 21, 9, -14, -13, 0, - -11, -24, -9, 9, 23, 1, 1, 32, 11, -25, -18, 5, -5, -6, -9, -10, - 2, 18, 4, 12, 6, -2, -8, 2, 2, -7, 2, -22, -5, 17, 25, 15, - -5, -1, -24, -8, -10, -5, 12, 7, -4, -10, 4, 8, 22, 11, -1, -12, - -31, -17, 6, 12, 11, 5, -3, -1, 22, 0, -4, 3, -18, -17, -3, 16, - 9, 2, -5, 0, 4, -9, 18, 17, -22, -19, -8, -6, 21, 11, -6, -16, - 33, 13, -15, -3, -15, 1, -3, -10, -7, 8, 17, -11, 9, 19, 0, 5, - 0, -18, -13, 2, -20, 10, 29, -11, -13, 5, 11, 16, 4, -25, -21, 13, - -5, 1, 3, -1, 6, 13, -7, -1, 17, -6, -6, -9, -6, -3, -1, 1, - 18, 11, -22, 2, 18, -2, -15, 1, 5, -12, -10, -7, 9, 26, 10, -11, - 5, 0, -7, -3, -11, -9, -3, 2, -10, 19, 28, -3, -3, -4, 9, -14, - -5, -7, 8, -3, -27, 5, 37, 11, -2, 3, -27, -15, 12, -2, 14, 2, - -8, -16, 22, 11, -1, 10, -17, -8, -5, -23, 2, 29, 8, -21, 8, 12, - 6, 8, -17, 3, -2, -12, -27, 16, 25, -5, -7, 2, 19, 1, -15, 7, - 2, -5, -34, 2, 18, 17, -10, 2, 18, -1, -12, -10, 5, 1, -16, -9, - 12, 21, 4, -10, 2, 12, 1, -19, -11, 20, 5, -14, -21, 5, 17, -5, - 3, 17, 4, -25, -5, 5, 4, 0, -5, 2, 2, -1, 1, 13, 0, -11, - -8, 3, 2, -1, -3, -3, 11, 8, -6, 2, 7, 4, -5, -23, -2, 14, - -1, -15, -2, 15, 10, 1, -4, 16, 1, -24, -12, 8, 8, -20, -2, 14, - 13, 10, 2, 2, -9, -6, -9, -3, 5, 7, -3, -9, 0, 2, 8, 3, - -1, 2, -4, 0, -2, 0, -2, 3, 5, -4, -28, 22, -43, 36, -13, -127, - -43, 2, -18, 126, 78, -127, -48, 68, -74, -67, 33, 62, 83, 42, -32, -46, - -70, -26, 115, 21, -66, 72, 52, -27, 44, 50, 50, 61, 28, -12, 3, -59, - 49, 3, -19, 39, 94, 16, 31, 6, 29, 3, -100, -1, -4, -60, 19, 7, - -29, -28, -38, -3, -47, -20, -21, -1, 5, -55, -12, -55, -39, 26, 47, -22, - -9, -41, -21, -19, -37, 0, 45, -56, 24, 75, -50, -9, 31, 28, 26, 13, - -3, -15, -27, 1, 1, -31, -10, 38, -1, 7, 43, 19, 21, 41, 33, 9, - -17, -3, -42, -76, -30, -8, -9, -1, 21, 22, 38, 32, 22, 0, -18, -32, - -58, -12, 5, -48, -13, 64, 29, -2, 2, 19, 43, 25, -19, -39, -69, -92, - -15, 23, 30, 30, 51, 37, 35, 37, 30, -27, -63, 5, -30, -56, -16, 26, - 52, 20, 14, 59, 27, -9, 22, -4, -20, -37, -17, -34, -34, -1, 35, 26, - 31, 5, -16, 4, 33, 22, 8, 5, -28, -41, -20, -10, -6, -2, -16, 12, - 31, -23, 7, -2, -39, -28, -13, 8, 5, 16, -4, -6, -18, -24, -27, -50, - -6, 5, 12, 0, -2, -14, -23, 5, -28, -10, 2, 28, 15, 2, 22, 27, - 41, 31, 2, 12, 31, 5, 12, -6, 15, 40, 34, 18, 26, 26, 12, 34, - 23, 34, 30, 22, 10, -26, -22, 1, 0, -1, 12, -4, -21, -5, -5, -20, - -31, -25, -24, -42, -44, -41, -41, -37, -29, -28, -29, -40, -17, -21, -38, -42, - -38, -40, -36, -13, -14, -8, -15, -7, -6, 5, 12, -1, -17, -1, 9, 2, - 16, 30, 27, 37, 36, 38, 36, 36, 19, 45, 45, 33, 26, 33, 28, 36, - 31, 17, 12, 22, 11, 11, 17, 5, -13, 6, 10, 2, -6, 2, 9, 15, - -6, -8, -23, -44, -3, -11, -35, -25, -35, -23, -21, 0, -11, -21, -17, 11, - -6, -11, -17, -33, -16, -16, -4, -7, -7, -9, -4, 1, 1, -3, 6, 7, - 4, -17, -11, -6, -4, 1, 3, 6, 4, 5, -4, 17, 7, 3, 9, -20, - 0, -7, -3, -5, 4, 9, 16, 2, 3, 8, 15, 15, 1, -3, 8, -1, - 5, 14, 7, 4, 8, -8, 2, -3, 5, 11, 5, 3, -4, 10, 17, 13, - -11, -5, 1, -3, 0, -6, -12, 2, -3, 13, -5, -25, -15, -7, 4, 1, - -8, -4, -12, -16, 3, 9, -6, 3, -21, -4, 4, -14, 1, -1, -2, 3, - -8, -5, 0, 7, -2, -3, -1, 3, -9, 5, -4, -17, -1, 9, 3, 7, - 1, -4, -3, 5, 2, -7, -9, 12, -6, -14, -16, 2, -1, 16, 2, 2, - 7, -6, -26, 3, -2, -4, -2, 10, 3, -7, 3, 8, 9, 5, 4, 1, - -5, -5, 11, 8, 7, 11, 12, -1, -5, -16, 13, 7, 2, 11, 4, -4, - 9, -8, -8, 14, 11, -8, 0, -1, -5, -2, -1, -10, -5, -9, -9, -16, - -12, -8, -16, 5, -10, -4, -11, -3, 1, 0, -3, -5, -13, -9, -2, -8, - 5, -9, -7, -2, 2, -11, -7, 13, 8, -3, 2, 7, -2, -1, 5, 0, - 11, 6, 13, 15, 1, -4, 9, 5, 3, 8, -3, -4, 16, 4, 11, 9, - 0, 8, 1, -6, -5, -18, 3, 7, -18, -4, 0, -3, -3, -6, -4, -5, - -5, -10, -2, -9, -5, -2, -4, -11, -2, 1, -5, -2, 11, -6, -9, 1, - 4, -6, -1, -5, 1, 2, 9, 5, 0, 4, 4, -2, 7, 0, -10, 5, - 2, -3, 0, -6, 7, -4, -3, 6, -1, -6, -1, -1, 2, -2, -6, -3, - 0, 8, -6, 4, -1, -5, -3, 3, 1, -5, -6, -2, -3, 5, 6, 0, - 7, -3, 3, -1, 0, -2, 9, 1, 1, -3, 4, 5, -5, 2, -2, 2, - -11, -2, -4, 11, 4, 5, 0, -5, -12, -6, -5, -5, 3, -2, -2, 2, - 2, 1, 0, -1, -8, -5, -5, -3, 2, -1, 3, -1, 3, 0, -1, 0, - -1, 1, 1, -4, -4, 2, -2, 1, -6, 1, 2, 4, 2, 2, -5, -1, - 6, -3, -1, -4, 11, 3, -9, -2, -6, -3, 2, 4, 2, 1, 2, 4, - 3, -6, -4, -3, -2, 0, 2, -2, 5, 2, -1, 3, -9, -3, -3, -4, - -4, -1, 0, -2, 7, 3, 1, 1, -2, -4, -2, -3, -2, -4, 2, 4, - -1, 2, 3, 0, 3, -1, 0, -2, -2, -3, 1, -1, -4, 5, -1, 5, - 0, -3, -2, -1, -4, 3, -1, -3, -2, -2, -1, 0, 0, 1, -1, 0, - -2, -2, 0, -3, -1, 0, 0, 1, 1, -2, -1, 1, -3, 1, 2, 0, - -1, 0, -1, 1, 5, -2, 1, -3, -3, -1, -3, 0, 1, 3, 2, -1, - -1, -2, -2, -1, 1, 30, -9, -44, 13, 26, -53, -41, 2, 76, 47, 40, - -52, -53, -5, 12, -33, 15, 62, 53, -27, -98, -26, -42, 52, 75, 43, -32, - -3, -83, -13, -36, 35, 39, 56, 25, -9, -122, -22, -3, 79, -6, 6, 25, - -20, -12, -40, -19, 15, 74, 37, -14, -33, 6, 25, 7, -10, -4, 42, 4, - -33, -87, -55, 29, 39, 21, -34, -27, 1, 26, 5, -22, -13, 10, 56, 0, - -26, -40, 30, 42, 23, -7, -23, 28, 21, 9, -37, -25, 11, 25, 8, -48, - -19, -15, 41, -2, -30, -28, 4, 30, -12, -23, -28, 17, 38, 3, -12, -8, - 17, 26, 9, -32, 0, 12, 49, -3, -29, -17, 2, 41, -17, -24, -17, 9, - 30, -23, -22, -21, 19, 17, -12, -35, -18, 12, 29, 2, -27, 7, 14, 42, - -11, -24, -3, 15, 40, -23, -24, -17, 21, 22, -10, -23, -10, 23, 13, -4, - -37, 0, 15, 19, -12, -40, -2, 13, 30, -16, -22, -3, 22, 22, -13, -16, - -7, 34, 9, -5, -34, -5, 29, 10, -3, -39, 3, 17, 14, -13, -25, 5, - 21, 12, -18, -22, -8, 31, 8, -5, -27, -9, 30, 1, -3, -30, 6, 27, - 4, -14, -31, 8, 25, 10, -14, -21, -3, 24, 4, -11, -17, -1, 30, -1, - -12, -26, 3, 32, 3, -13, -26, 5, 23, 3, -14, -17, 6, 22, 1, -17, - -16, 4, 25, 4, -18, -19, 4, 23, 5, -17, -14, 5, 21, 1, -20, -11, - 7, 23, 2, -19, -17, 8, 19, 6, -18, -15, 10, 14, 6, -26, -5, 11, - 15, 4, -27, -5, 4, 22, 1, -17, -12, 6, 15, 1, -16, -13, 20, 8, - 4, -28, -7, 17, 9, 10, -31, 3, 1, 13, 0, -18, 0, 6, 17, -10, - -14, -15, 21, 10, 3, -19, -14, 22, -4, 11, -27, 8, 9, 7, -2, -26, - 8, 2, 23, -13, -7, -13, 12, 11, -11, -2, -15, 27, -8, 2, -22, 0, - 18, 0, 6, -27, 10, -4, 19, -13, -7, 1, 2, 19, -26, 7, -17, 28, - -2, -8, -6, -11, 23, -9, 10, -24, 12, -2, 10, -8, -14, 13, -5, 25, - -33, 7, -11, 17, 8, -19, 9, -18, 26, -17, 6, -12, 8, 8, -5, 0, - -23, 20, -10, 25, -24, 2, 0, -2, 17, -30, 22, -16, 25, -15, -7, -2, - -4, 21, -15, 13, -25, 19, -11, 9, -8, -7, 19, -15, 20, -34, 17, -9, - 15, 0, -15, 11, -17, 24, -24, 16, -15, 15, 0, -11, 6, -21, 30, -18, - 18, -22, 6, 3, -6, 10, -20, 23, -17, 20, -23, 7, -3, 2, 16, -24, - 18, -26, 27, -15, 5, -2, -5, 19, -21, 12, -22, 22, -9, 9, -11, -5, - 11, -13, 21, -27, 22, -17, 13, -5, -13, 14, -14, 28, -24, 9, -16, 12, - 3, -7, 5, -14, 22, -20, 14, -21, 14, 3, -2, 6, -26, 20, -17, 23, - -17, 3, 0, -2, 11, -23, 14, -14, 26, -14, 0, -10, -3, 18, -14, 15, - -24, 19, -9, 4, -8, -9, 18, -6, 15, -29, 11, -10, 16, -1, -11, 9, - -13, 23, -23, 8, -13, 12, 10, -11, 0, -20, 22, -7, 12, -19, 4, 4, - 1, 4, -23, 18, -10, 22, -17, -7, 0, -1, 23, -20, 6, -18, 18, 0, - -3, -8, -5, 20, -8, 6, -27, 14, 2, 11, -5, -20, 13, -10, 24, -22, - 3, -5, 11, 8, -20, 1, -12, 28, -7, 0, -19, 2, 15, -5, 6, -25, - 20, -4, 13, -19, -10, 10, 5, 17, -27, 1, -10, 22, -2, -10, -2, -7, - 26, -18, 4, -24, 18, 10, 1, -8, -23, 16, 2, 15, -22, -1, 3, 10, - 5, -27, 9, -8, 35, -19, -3, -18, 7, 19, -7, -3, -16, 14, 6, -5, - -9, -12, 23, -5, 11, -33, 19, -10, 23, -22, 3, -5, 14, -2, -8, -8, - 7, 7, 2, -14, 0, -2, 17, -14, 3, -17, 20, -5, 7, -19, 3, 3, - 10, -5, -9, -4, 6, 6, -2, -10, 1, 2, 12, -13, 0, -11, 18, -3, - 3, -16, 2, 4, 7, -5, -6, 0, 6, 1, -6, -6, 4, 6, 5, -11, - -2, -4, 12, -6, 1, -9, 9, 0, 1, -11, 0, 6, 5, -2, -11, 1, - 2, 7, -5, -7, 3, 1, 8, -13, 0, -6, 15, -3, -2, -11, 1, 9, - 1, -2, -12, 6, 2, 5, -9, -5, 3, 6, 5, -12, -3, -3, 12, 0, - -5, -7, 0, 8, -2, -2, -9, 7, 3, 5, -11, -4, 0, 9, 2, -7, - -6, 0, 7, 1, -6, -3, 1, 8, -4, -5, -7, 7, 4, 4, -11, -1, - -2, 10, -5, -1, -7, 8, 1, 1, -12, 1, 4, 7, -4, -8, -4, 8, - 0, 3, -16, 11, -7, 1, 0, 0, -1, -1, -4, 1, -1, -3, -13, -8, - -14, -3, -2, -2, 1, 8, 5, 7, -21, -13, -2, -6, -8, -22, -6, 5, - 11, 34, 41, 33, 13, 28, 33, 48, 35, 21, -3, -26, -18, -10, 3, 7, - 22, 21, 63, 40, 41, 43, 4, -8, -43, -63, -77, -77, -59, -18, 3, 2, - -21, -46, -74, -90, -108, -101, -94, -89, -84, -85, -77, -59, -50, -33, -7, 18, - 37, 47, 64, 101, 127, 125, 127, 126, 126, 126, 122, 100, 87, 62, 37, 28, - 27, 25, 27, 34, 25, -4, -45, -85, -123, -128, -126, -128, -127, -123, -92, -73, - -55, -45, -37, -33, -32, -33, -43, -53, -55, -43, -20, 3, 20, 34, 42, 49, - 55, 63, 74, 84, 93, 101, 107, 112, 117, 109, 92, 63, 33, 8, -13, -25, - -29, -30, -27, -27, -32, -46, -63, -82, -98, -109, -116, -121, -118, -104, -80, -49, - -12, 21, 45, 58, 64, 66, 66, 61, 51, 44, 37, 32, 32, 33, 33, 28, - 23, 15, 8, 3, 2, 9, 16, 20, 24, 23, 14, -1, -20, -37, -48, -53, - -52, -47, -38, -26, -13, -5, -1, -4, -10, -22, -34, -43, -48, -46, -34, -16, - 5, 25, 45, 65, 78, 84, 83, 71, 55, 39, 24, 9, -3, -12, -23, -34, - -45, -57, -65, -71, -71, -63, -49, -34, -21, -11, -2, 2, 8, 11, 12, 14, - 14, 20, 28, 38, 50, 58, 63, 61, 56, 46, 33, 17, -1, -19, -34, -45, - -48, -44, -32, -19, -5, 5, 7, 4, -2, -7, -11, -15, -18, -21, -23, -26, - -28, -30, -31, -29, -26, -20, -12, -1, 11, 21, 32, 42, 51, 55, 55, 52, - 46, 41, 37, 32, 30, 28, 27, 24, 19, 12, -1, -21, -45, -67, -89, -103, - -107, -101, -90, -70, -51, -33, -18, -2, 11, 23, 33, 39, 44, 49, 52, 57, - 59, 59, 56, 52, 48, 41, 35, 28, 20, 15, 11, 4, 0, -5, -11, -18, - -25, -34, -42, -47, -48, -46, -40, -33, -27, -24, -21, -24, -32, -42, -51, -56, - -58, -56, -47, -35, -18, 2, 24, 48, 70, 88, 99, 104, 102, 97, 89, 79, - 69, 59, 49, 37, 27, 14, 0, -14, -29, -44, -58, -71, -81, -87, -88, -88, - -85, -81, -77, -72, -63, -51, -37, -21, -5, 12, 29, 43, 53, 59, 61, 57, - 48, 36, 24, 13, 8, 8, 15, 25, 38, 48, 54, 54, 50, 43, 33, 22, - 11, 3, -6, -15, -25, -35, -46, -54, -61, -65, -68, -69, -69, -68, -64, -59, - -52, -43, -32, -20, -7, 6, 19, 31, 42, 51, 58, 62, 64, 62, 58, 52, - 44, 35, 26, 17, 9, 1, -5, -10, -15, -18, -19, -20, -19, -18, -16, -15, - -14, -14, -15, -16, -17, -18, -19, -19, -19, -19, -18, -16, -14, -11, -9, -6, - -3, 0, 3, 6, 10, 14, 18, 22, 27, 32, 35, 37, 37, 35, 30, 23, - 14, 4, -6, -15, -24, -31, -36, -39, -40, -39, -37, -32, -26, -19, -10, -1, - 8, 17, 24, 29, 32, 33, 32, 29, 25, 20, 15, 11, 7, 3, -1, -5, - -9, -14, -19, -24, -28, -31, -32, -31, -27, -23, -16, -10, -3, 2, 7, 10, - 12, 13, 13, 13, 12, 10, 8, 7, 5, 5, 5, 5, 6, 8, 10, 13, - 17, 20, 23, 25, 26, 25, 21, 16, 9, 1, -7, -16, -24, -31, -37, -42, - -47, -49, -51, -52, -51, -48, -43, -37, -30, -20, -7, 6, 19, 0, -4, 10, - 10, 11, -15, 4, -1, 3, -11, 11, 2, -12, 3, 18, -10, -62, 89, -16, - -95, 118, -128, 122, -128, 112, -100, 109, -121, 120, -104, 58, 10, -88, 127, -102, - 6, 98, -126, 35, 89, -111, -7, 112, -53, -94, 92, 64, -106, -53, 109, 52, - -100, -75, 86, 95, -45, -119, -12, 111, 74, -58, -118, -27, 97, 100, -4, -107, - -95, 17, 109, 92, -4, -99, -109, -26, 78, 115, 66, -27, -104, -109, -41, 55, - 112, 98, 32, -53, -109, -105, -44, 41, 102, 109, 67, -4, -74, -112, -102, -47, - 27, 88, 112, 93, 45, -19, -78, -110, -105, -65, -4, 59, 101, 110, 87, 43, - -13, -67, -103, -111, -89, -44, 13, 65, 100, 109, 93, 59, 14, -36, -78, -104, - -108, -90, -53, -6, 43, 83, 104, 106, 88, 57, 17, -27, -66, -95, -108, -102, - -80, -44, -2, 41, 77, 99, 106, 98, 77, 46, 10, -29, -64, -91, -105, -105, - -91, -64, -29, 10, 48, 78, 98, 105, 100, 84, 59, 30, -3, -36, -65, -88, - -101, -105, -99, -83, -60, -32, -1, 30, 58, 80, 96, 103, 102, 94, 80, 62, - 40, 16, -10, -35, -58, -78, -92, -101, -104, -100, -91, -77, -58, -36, -13, 12, - 36, 57, 75, 89, 98, 102, 102, 97, 88, 76, 61, 44, 25, 5, -15, -35, - -54, -70, -84, -94, -101, -104, -103, -98, -89, -77, -63, -46, -27, -8, 12, 31, - 49, 65, 79, 90, 97, 102, 104, 102, 97, 90, 81, 70, 57, 42, 27, 10, - -7, -24, -40, -56, -70, -81, -91, -99, -103, -105, -105, -101, -95, -87, -76, -63, - -49, -34, -18, -1, 16, 32, 48, 62, 74, 85, 93, 100, 104, 105, 105, 102, - 97, 90, 82, 72, 61, 48, 35, 21, 6, -9, -24, -38, -52, -65, -76, -86, - -94, -101, -105, -108, -108, -106, -102, -96, -87, -78, -66, -54, -40, -26, -11, 4, - 19, 34, 48, 61, 73, 83, 92, 99, 104, 107, 108, 108, 105, 101, 96, 89, - 80, 70, 60, 48, 36, 22, 9, -5, -19, -33, -46, -58, -69, -80, -89, -96, - -102, -107, -109, -110, -110, -107, -102, -97, -89, -80, -70, -59, -47, -33, -20, -6, - 7, 19, 30, 41, 50, 58, 65, 71, 75, 78, 79, 80, 79, 77, 74, 70, - 65, 60, 54, 48, 42, 36, 29, 22, 16, 10, 4, -2, -7, -12, -16, -19, - -22, -24, -26, -27, -27, -27, -26, -25, -23, -22, -19, -17, -14, -12, -10, 0, - -5, -2, -5, 2, -29, 22, 0, -27, 67, -59, 45, -13, -37, 28, 65, -4, - 6, 60, 5, 58, 44, 60, 27, 43, 96, 71, 81, 48, 96, 70, 23, 90, - 66, 80, 88, 40, 20, 61, 64, 12, 36, 24, 4, 7, 5, -27, -38, -26, - -33, -49, -50, -70, -69, -93, -92, -94, -104, -104, -101, -110, -107, -111, -111, -126, - -87, -119, -100, -94, -112, -93, -93, -80, -81, -76, -58, -56, -70, -30, -21, -42, - -13, -3, 2, 8, 20, 28, 41, 45, 59, 62, 69, 84, 85, 90, 103, 109, - 111, 118, 121, 121, 123, 121, 122, 121, 122, 121, 122, 121, 121, 120, 121, 120, - 121, 120, 121, 120, 120, 119, 120, 119, 120, 118, 105, 106, 110, 83, 89, 92, - 75, 67, 61, 57, 47, 40, 33, 24, 17, 10, 3, -2, -10, -20, -31, -31, - -37, -49, -50, -63, -66, -69, -74, -79, -91, -89, -92, -95, -102, -106, -104, -107, - -113, -113, -110, -113, -116, -114, -115, -114, -115, -114, -113, -114, -113, -114, -113, -112, - -113, -109, -105, -111, -106, -107, -103, -100, -103, -99, -97, -98, -99, -92, -92, -93, - -92, -92, -90, -88, -90, -88, -86, -89, -85, -85, -87, -85, -85, -82, -83, -82, - -80, -78, -79, -76, -74, -73, -73, -69, -68, -66, -64, -65, -62, -58, -56, -56, - -52, -50, -47, -43, -42, -39, -35, -33, -31, -27, -23, -21, -16, -16, -8, -7, - -3, 1, 0, 10, 15, 15, 19, 26, 29, 30, 38, 41, 42, 47, 54, 54, - 57, 63, 68, 69, 72, 77, 78, 80, 85, 84, 86, 87, 86, 87, 86, 85, - 86, 85, 84, 85, 84, 83, 84, 83, 82, 82, 83, 82, 81, 82, 81, 80, - 81, 80, 79, 80, 79, 79, 78, 79, 78, 78, 77, 74, 70, 66, 64, 61, - 55, 52, 49, 45, 40, 35, 32, 29, 24, 19, 15, 12, 8, 4, 0, -4, - -8, -11, -15, -17, -20, -25, -26, -29, -32, -34, -37, -39, -41, -43, -45, -46, - -48, -49, -50, -50, -52, -52, -53, -52, -53, -54, -53, -53, -52, -52, -51, -50, - -50, -49, -48, -48, -46, -45, -44, -42, -41, -40, -39, -37, -35, -34, -32, -30, - -28, -27, -24, -23, -22, -20, -19, -17, -15, -14, -13, -12, -10, -9, -8, -8, - -6, -6, -5, -4, -4, -3, -3, -2, -2, -1, -2, -1, -2, -1, -1, 0, - -1, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, 1, 9, -6, -3, 11, - -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, 24, -28, 27, -12, -1, - -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, 14, -16, 4, 8, -9, - 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, -20, 21, -16, 1, 17, - -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, -4, 13, -23, 29, -40, - 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, 4, -13, 20, -29, 37, - -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, 9, -4, -12, 22, -19, - -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, -10, 18, -40, 66, -91, - 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, 7, -9, -4, -2, -5, - 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, 38, -16, -20, 53, -75, - 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, 9, 4, -46, 70, -85, - 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, 14, -58, 93, -118, 127, - -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, -120, 56, 15, -85, 116, - -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, 29, -37, 42, -50, 63, - -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, -3, 3, -24, 24, -34, - 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, 14, -29, 42, -58, 58, - -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, 32, -20, -4, 4, -14, - 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, 24, -7, -25, 31, -29, - 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, 32, 2, -29, 23, -21, - 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, -10, -7, 17, -42, 34, - -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, 3, -24, 31, -44, 27, - -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, -7, 7, -25, 17, -17, - 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, -6, 8, -18, 18, -36, - 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, 16, -40, 47, -52, 34, - -12, -4, 2, -13, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, 1, 9, - -6, -3, 11, -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, 24, -28, - 27, -12, -1, -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, 14, -16, - 4, 8, -9, 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, -20, 21, - -16, 1, 17, -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, -4, 13, - -23, 29, -40, 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, 4, -13, - 20, -29, 37, -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, 9, -4, - -12, 22, -19, -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, -10, 18, - -40, 66, -91, 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, 7, -9, - -4, -2, -5, 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, 38, -16, - -20, 53, -75, 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, 9, 4, - -46, 70, -85, 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, 14, -58, - 93, -118, 127, -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, -120, 56, - 15, -85, 116, -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, 29, -37, - 42, -50, 63, -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, -3, 3, - -24, 24, -34, 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, 14, -29, - 42, -58, 58, -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, 32, -20, - -4, 4, -14, 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, 24, -7, - -25, 31, -29, 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, 32, 2, - -29, 23, -21, 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, -10, -7, - 17, -42, 34, -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, 3, -24, - 31, -44, 27, -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, -7, 7, - -25, 17, -17, 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, -6, 8, - -18, 18, -36, 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, 16, -40, - 47, -52, 34, -12, -4, 2, -13, -1, -9, -21, -32, -43, -55, -58, -40, -8, - 15, 29, 38, 44, 59, 63, 51, 20, -20, -47, -61, -58, -48, -42, -43, -35, - -15, 15, 41, 55, 61, 62, 70, 67, 45, 11, -31, -62, -80, -78, -71, -62, - -54, -39, -15, 18, 50, 68, 79, 83, 92, 88, 57, 16, -31, -71, -94, -95, - -90, -83, -71, -55, -28, 7, 49, 77, 93, 100, 109, 107, 78, 36, -20, -71, - -99, -104, -100, -92, -83, -69, -43, -5, 42, 79, 100, 108, 114, 112, 90, 51, - -9, -65, -100, -110, -105, -95, -87, -76, -52, -11, 35, 75, 100, 107, 111, 106, - 90, 52, -4, -60, -97, -109, -99, -87, -80, -65, -35, 5, 43, 75, 91, 95, - 93, 87, 71, 31, -19, -64, -93, -99, -88, -76, -66, -44, -9, 28, 59, 79, - 84, 80, 71, 59, 35, -5, -45, -76, -96, -95, -77, -59, -39, -9, 28, 61, - 86, 98, 93, 74, 52, 28, -6, -43, -72, -94, -108, -99, -77, -52, -20, 19, - 56, 84, 106, 115, 106, 79, 45, 3, -40, -74, -93, -108, -112, -100, -79, -46, - -1, 45, 78, 100, 113, 118, 108, 81, 39, -19, -67, -93, -103, -108, -104, -94, - -74, -32, 19, 61, 88, 102, 108, 109, 100, 73, 21, -44, -87, -102, -104, -97, - -90, -78, -49, 0, 46, 78, 90, 92, 89, 87, 77, 43, -15, -72, -101, -104, - -93, -79, -69, -47, -3, 47, 84, 96, 89, 74, 65, 58, 37, -7, -61, -99, - -110, -101, -82, -62, -38, 2, 49, 92, 112, 106, 82, 59, 41, 18, -19, -61, - -95, -111, -110, -98, -74, -39, 6, 54, 99, 122, 123, 104, 79, 50, 12, -32, - -72, -100, -111, -110, -106, -90, -54, -4, 49, 99, 123, 126, 113, 95, 69, 24, - -27, -72, -102, -114, -109, -104, -94, -64, -16, 36, 87, 116, 121, 111, 97, 76, - 36, -15, -61, -94, -110, -108, -98, -86, -60, -19, 29, 77, 104, 109, 99, 86, - 67, 35, -7, -47, -82, -98, -101, -92, -77, -48, -14, 25, 67, 92, 95, 83, - 66, 45, 18, -9, -37, -62, -77, -81, -78, -54, -16, 0, 0, 0, 12, -10, - 16, -14, -18, 17, -31, -2, 3, -19, -8, 17, 28, 37, 31, -1, -25, -16, - -47, -13, -43, -22, 6, 34, 41, 49, 41, 27, 6, -33, -62, -54, -59, -32, - -13, 29, 53, 73, 60, 54, 16, -19, -58, -77, -89, -42, -46, 17, 55, 78, - 86, 81, 33, -3, -35, -84, -110, -75, -70, 0, 39, 78, 92, 105, 70, 13, - -15, -82, -107, -103, -84, -41, 20, 81, 85, 127, 86, 39, -4, -63, -103, -99, - -107, -69, 2, 68, 82, 127, 84, 58, 28, -44, -88, -104, -108, -83, -13, 29, - 69, 116, 87, 77, 40, -16, -65, -89, -104, -89, -40, -1, 47, 96, 90, 85, - 52, 9, -38, -62, -96, -95, -62, -22, 21, 73, 78, 86, 65, 35, -15, -41, - -80, -92, -69, -48, 1, 43, 65, 80, 73, 49, 8, -23, -59, -75, -74, -60, - -22, 17, 49, 69, 65, 60, 25, -1, -36, -59, -70, -61, -40, -9, 30, 52, - 57, 63, 37, 17, -12, -41, -61, -57, -50, -30, 9, 30, 49, 60, 47, 28, - 6, -20, -49, -51, -53, -42, -11, 13, 34, 53, 50, 34, 18, -3, -35, -39, - -52, -49, -23, 0, 18, 41, 47, 36, 31, 10, -21, -28, -43, -49, -31, -13, - 2, 28, 39, 35, 38, 19, -7, -18, -33, -42, -36, -26, -12, 19, 30, 34, - 36, 22, 6, -5, -25, -38, -36, -29, -17, 8, 19, 26, 35, 28, 12, 3, - -17, -30, -29, -29, -22, -3, 9, 19, 33, 26, 14, 8, -9, -18, -22, -28, - -25, -9, 3, 15, 22, 20, 18, 12, 1, -11, -22, -24, -21, -13, -3, 8, - 11, 20, 21, 12, 5, -6, -19, -16, -17, -17, -7, 3, 8, 20, 17, 7, - 7, -2, -11, -13, -16, -17, -5, 2, 5, 12, 13, 8, 6, 3, -9, -11, - -9, -14, -5, 1, -3, 6, 11, 6, 7, 2, -6, -4, -4, -10, -6, -3, - -4, 5, 8, 2, 5, 4, -2, 0, -3, -9, -4, -3, -3, 2, 3, 0, - 6, 4, 0, -1, -2, -2, 0, -4, 8, -1, 9, 14, 53, 57, 33, -4, - -20, -14, -31, -71, -112, -43, 30, -22, -102, -74, 38, 90, 35, -22, 20, 99, - 96, 22, -42, -5, 48, 16, -74, -97, -51, 10, -21, -80, -68, 24, 77, 43, - -9, 20, 90, 99, 32, -28, -8, 41, 18, -63, -97, -55, -2, -18, -74, -67, - 11, 69, 44, -1, 17, 83, 98, 40, -20, -8, 35, 20, -55, -95, -60, -8, - -19, -69, -68, 3, 61, 45, 1, 15, 78, 99, 46, -14, -8, 33, 22, -48, - -93, -62, -13, -19, -67, -70, -5, 56, 44, 3, 13, 73, 99, 51, -10, -7, - 32, 25, -42, -91, -66, -15, -18, -65, -73, -11, 51, 44, 3, 9, 69, 100, - 55, -6, -8, 32, 30, -36, -89, -68, -17, -17, -64, -77, -18, 47, 45, 3, - 5, 64, 100, 60, -2, -8, 32, 34, -30, -87, -70, -19, -14, -63, -80, -25, - 43, 45, 3, 1, 59, 100, 66, 1, -9, 31, 39, -23, -84, -74, -20, -12, - -59, -84, -32, 38, 46, 3, -3, 53, 101, 71, 6, -10, 31, 43, -14, -81, - -76, -24, -9, -57, -86, -41, 33, 46, 5, -9, 47, 99, 77, 9, -11, 28, - 49, -6, -76, -79, -25, -9, -50, -91, -46, 9, -41, 2, 6, -33, 33, -4, - -1, 34, -93, 60, -49, 68, -21, 41, -38, -38, 27, -87, 127, -34, 38, -3, - -34, -2, -85, 79, -24, 4, 75, -23, 11, -70, 1, -6, -6, 63, -48, 76, - -71, 2, -7, -15, 46, -32, 48, -25, -5, 10, -31, 18, -23, 5, 6, 17, - 11, 3, 24, -46, -21, -1, -5, 31, 1, 36, -23, -11, -4, -29, 14, -5, - 29, 9, -2, -2, -20, -2, -15, 13, 7, 4, 15, -11, 4, -13, -1, 1, - -13, 15, -6, 9, 9, -2, -4, -11, -2, -11, 7, 12, 9, 5, -6, -6, - -16, -2, 3, 6, 13, 1, 7, -14, -3, -11, -1, 8, 0, 18, -3, -3, - -6, -13, 0, 4, 2, 9, 2, 2, -6, -4, -1, -8, 2, 4, 2, 7, - -4, 2, 1, -7, -3, -2, 0, 2, 8, -2, 2, -1, -7, -3, -1, 3, - 4, 3, 3, -3, -4, -4, 0, 2, 1, 5, -1, -2, 1, -4, -1, 1, - 0, 2, 8, -22, 25, 30, 6, -19, -62, -19, 10, 83, 57, -67, -88, -52, - 63, 127, 42, -63, -121, -70, 82, 111, 46, -43, -114, -35, 45, 73, 39, -19, - -54, -41, 9, 49, 24, -16, -14, -9, -6, 10, 8, -22, 25, 30, 6, -19, - -62, -19, 10, 83, 57, -67, -88, -52, 63, 127, 42, -63, -121, -70, 82, 111, - 46, -43, -114, -35, 45, 73, 39, -19, -54, -41, 9, 49, 24, -16, -14, -9, - -6, 10, 94, 127, 124, 127, 127, 114, 73, 35, -11, -52, -98, -118, -125, -128, - -128, -128, -128, -128, -128, -128, -124, -86, -47, 0, 40, 87, 106, 116, 119, 125, - 37, -7, 122, 72, -57, -71, -88, -28, 48, 127, 36, -30, -53, -126, -16, 71, - 92, 51, -1, -83, -128, 14, 43, 83, 86, -14, -106, -87, -7, 28, 1, 122, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 -}; - -const EAS_U32 eas_sampleLengths[] = -{ - 9922, 9338, 6793, 5242, 3057, 2818, 2806, 1835, - 1603, 1262, 1227, 1168, 1132, 1132, 994, 907, - 817, 801, 583, 418, 402, 387, 387, 357, - 347, 212, 167, 40, 40, 32, 30 -}; - -const EAS_U32 eas_sampleOffsets[] = -{ - 0x00000000, 0x000026c2, 0x00004b3c, 0x000065c5, 0x00007a3f, 0x00008630, 0x00009132, 0x00009c28, - 0x0000a353, 0x0000a996, 0x0000ae84, 0x0000b34f, 0x0000b7df, 0x0000bc4b, 0x0000c0b7, 0x0000c499, - 0x0000c824, 0x0000cb55, 0x0000ce76, 0x0000d0bd, 0x0000d25f, 0x0000d3f1, 0x0000d574, 0x0000d6f7, - 0x0000d85c, 0x0000d9b7, 0x0000da8b, 0x0000db32, 0x0000db5a, 0x0000db82, 0x0000dba2 -}; - -/*---------------------------------------------------------------------------- - * S_EAS (hybrid) - *---------------------------------------------------------------------------- -*/ -const S_EAS easSoundLib = -{ - 0x01534145, - 0x00105622, - eas_banks, - eas_programs, - eas_regions, - eas_articulations, - eas_sampleLengths, - eas_sampleOffsets, - eas_samples, - eas_fmRegions, - 1, - 1, - 61, - 53, - 31, - 128 -}; /* end S_EAS */ - -/*---------------------------------------------------------------------------- - * Statistics - * - * Number of banks: 1 - * Number of programs: 1 - * Number of regions: 61 - * Number of articulations: 53 - * Number of samples: 31 - * Size of sample pool: 56276 - *---------------------------------------------------------------------------- -*/ -/* end C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c */ + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision:$ + * $Date:$ + *---------------------------------------------------------------------------- +*/ + +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * Articulations + *---------------------------------------------------------------------------- +*/ +const S_ARTICULATION eas_articulations[] = +{ + { /* articulation 0 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 1 */ + { 32767, 26863, 0, 26863 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 2 */ + { 32767, 30484, 0, 30668 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 3 */ + { 32767, 26439, 0, 26439 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 4 */ + { 32767, 0, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 5 */ + { 32767, 21333, 0, 21333 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 6 */ + { 32767, 31882, 0, 31938 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 7 */ + { 32767, 32663, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 8 */ + { 32767, 0, 32767, 0 }, + { 32767, 1902, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 9 */ + { 32767, 32349, 0, 32349 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 10 */ + { 32767, 0, 32767, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -1 + }, + { /* articulation 11 */ + { 32767, 32072, 0, 32072 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 12 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 13 */ + { 32767, 32010, 0, 32010 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -31 + }, + { /* articulation 14 */ + { 9511, 21333, 0, 21333 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 15 */ + { 32767, 31844, 0, 31844 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -6 + }, + { /* articulation 16 */ + { 32767, 32123, 0, 32194 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 17 */ + { 32767, 31730, 0, 31730 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 6 + }, + { /* articulation 18 */ + { 32767, 31391, 0, 31391 }, + { 32767, 951, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 31 + }, + { /* articulation 19 */ + { 32767, 31964, 0, 31964 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 20 */ + { 32767, 31056, 0, 31056 }, + { 32767, 951, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 21 */ + { 32767, 32289, 0, 32271 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 22 */ + { 19021, 31882, 0, 31911 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 23 */ + { 32767, 31988, 0, 32032 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 24 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 12 + }, + { /* articulation 25 */ + { 32767, 31352, 0, 31352 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 26 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 27 */ + { 32767, 31817, 0, 31781 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 28 */ + { 32767, 30725, 0, 30725 }, + { 32767, 95, 0, 0 }, + 0, 0, 951, 240, 0, 0, 0, 0, -56 + }, + { /* articulation 29 */ + { 32767, 32230, 0, 32218 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 30 */ + { 32767, 26439, 0, 26439 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 31 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 32 */ + { 32767, 29434, 0, 29434 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 33 */ + { 32767, 30240, 0, 30234 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -44 + }, + { /* articulation 34 */ + { 32767, 32558, 0, 32558 }, + { 32767, 254, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 35 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 36 */ + { 3804, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 37 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -59 + }, + { /* articulation 38 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 39 */ + { 32767, 28809, 0, 28809 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 44 + }, + { /* articulation 40 */ + { 1902, 30725, 0, 30725 }, + { 32767, 380, 0, 0 }, + 0, 0, 951, -100, 0, 0, 0, 0, 44 + }, + { /* articulation 41 */ + { 32767, 9042, 0, 9042 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 42 */ + { 32767, 29889, 0, 29889 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 43 */ + { 32767, 30240, 0, 30234 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 44 */ + { 19021, 19970, 0, 19970 }, + { 951, 32767, 32767, 0 }, + 0, 0, 951, 100, 0, 0, 0, 0, -25 + }, + { /* articulation 45 */ + { 3804, 17213, 0, 17213 }, + { 951, 32767, 32767, 0 }, + 0, 0, 951, 500, 0, 0, 0, 0, -25 + }, + { /* articulation 46 */ + { 32767, 17213, 0, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 47 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 48 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 49 */ + { 32767, 31180, 0, 31180 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 50 */ + { 19021, 31964, 0, 32071 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 51 */ + { 32767, 29669, 0, 29669 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 52 */ + { 32767, 31742, 0, 31352 }, + { 32767, 294, 0, 0 }, + 0, 0, 951, 0, 10000, 7121, 0, 0, 0 + } +}; /*end Articulations */ + +/*---------------------------------------------------------------------------- + * Regions + *---------------------------------------------------------------------------- +*/ +const S_WT_REGION eas_regions[] = +{ + { { 0, 27, 27 }, -2868, 16422, 0, 0, 19, 0 }, /* region 0 */ + { { 0, 28, 28 }, -3568, 32767, 0, 0, 13, 0 }, /* region 1 */ + { { 0, 29, 29 }, -4553, 32767, 0, 0, 9, 1 }, /* region 2 */ + { { 0, 30, 30 }, -4853, 32767, 0, 0, 9, 2 }, /* region 3 */ + { { 0, 31, 31 }, -3868, 23197, 0, 0, 15, 3 }, /* region 4 */ + { { 1536, 32, 32 }, -3368, 20675, 0, 0, 29, 4 }, /* region 5 */ + { { 1537, 33, 33 }, -3868, 20675, 792, 800, 17, 5 }, /* region 6 */ + { { 1537, 34, 34 }, -3968, 16422, 792, 800, 17, 6 }, /* region 7 */ + { { 0, 35, 35 }, -4968, 32767, 0, 0, 20, 7 }, /* region 8 */ + { { 0, 36, 36 }, -4968, 32767, 0, 0, 20, 7 }, /* region 9 */ + { { 0, 37, 37 }, -4051, 18426, 0, 0, 16, 8 }, /* region 10 */ + { { 0, 38, 38 }, -4151, 23197, 0, 0, 5, 9 }, /* region 11 */ + { { 0, 39, 39 }, -4668, 23197, 0, 0, 12, 10 }, /* region 12 */ + { { 0, 40, 40 }, -4151, 23197, 0, 0, 5, 4 }, /* region 13 */ + { { 1, 41, 41 }, -5855, 26028, 798, 993, 14, 11 }, /* region 14 */ + { { 257, 42, 42 }, -4368, 26028, 4288, 6792, 2, 12 }, /* region 15 */ + { { 1, 43, 43 }, -5755, 26028, 798, 993, 14, 13 }, /* region 16 */ + { { 257, 44, 44 }, -4568, 26028, 4288, 6792, 2, 14 }, /* region 17 */ + { { 1, 45, 45 }, -5755, 26028, 798, 993, 14, 15 }, /* region 18 */ + { { 257, 46, 46 }, -4768, 26028, 4288, 6792, 2, 16 }, /* region 19 */ + { { 1, 47, 47 }, -5455, 26028, 798, 993, 14, 17 }, /* region 20 */ + { { 1, 48, 48 }, -5355, 26028, 798, 993, 14, 18 }, /* region 21 */ + { { 1, 49, 49 }, -5368, 16422, 1294, 5241, 3, 19 }, /* region 22 */ + { { 1, 50, 50 }, -5255, 26028, 798, 993, 14, 20 }, /* region 23 */ + { { 1, 51, 51 }, -5268, 16422, 6592, 9921, 0, 21 }, /* region 24 */ + { { 1, 52, 52 }, -5768, 32767, 1294, 5241, 3, 22 }, /* region 25 */ + { { 1, 53, 53 }, -5418, 14636, 6592, 9921, 0, 23 }, /* region 26 */ + { { 0, 54, 54 }, -5751, 26028, 0, 0, 11, 24 }, /* region 27 */ + { { 1, 55, 55 }, -5468, 32767, 1294, 5241, 3, 25 }, /* region 28 */ + { { 0, 56, 56 }, -7255, 32767, 0, 0, 24, 26 }, /* region 29 */ + { { 1, 57, 57 }, -5868, 32767, 1294, 5241, 3, 27 }, /* region 30 */ + { { 1, 58, 58 }, -7053, 23197, 0, 166, 26, 28 }, /* region 31 */ + { { 1, 59, 59 }, -5968, 16422, 6592, 9921, 0, 29 }, /* region 32 */ + { { 1, 60, 60 }, -6453, 23197, 432, 582, 18, 30 }, /* region 33 */ + { { 1, 61, 61 }, -6853, 16422, 432, 582, 18, 30 }, /* region 34 */ + { { 1, 62, 62 }, -7253, 20675, 432, 582, 18, 31 }, /* region 35 */ + { { 1, 63, 63 }, -7353, 23197, 432, 582, 18, 32 }, /* region 36 */ + { { 1, 64, 64 }, -7953, 23197, 432, 582, 18, 33 }, /* region 37 */ + { { 0, 65, 65 }, -7555, 32767, 0, 0, 4, 34 }, /* region 38 */ + { { 0, 66, 66 }, -7955, 20675, 0, 0, 4, 34 }, /* region 39 */ + { { 512, 67, 67 }, -7155, 18426, 0, 0, 24, 35 }, /* region 40 */ + { { 512, 68, 68 }, -7755, 18426, 0, 0, 24, 35 }, /* region 41 */ + { { 0, 69, 69 }, -7755, 32767, 0, 0, 21, 36 }, /* region 42 */ + { { 0, 70, 70 }, -6855, 21900, 0, 0, 21, 37 }, /* region 43 */ + { { 769, 71, 71 }, -6355, 23197, 0, 1226, 10, 38 }, /* region 44 */ + { { 769, 72, 72 }, -6955, 26028, 0, 1226, 10, 38 }, /* region 45 */ + { { 1024, 73, 73 }, -7955, 32767, 0, 0, 7, 39 }, /* region 46 */ + { { 1024, 74, 74 }, -8455, 32767, 0, 0, 7, 40 }, /* region 47 */ + { { 1, 75, 75 }, -8068, 23197, 0, 29, 30, 41 }, /* region 48 */ + { { 0, 76, 76 }, -10455, 23197, 0, 0, 28, 42 }, /* region 49 */ + { { 0, 77, 77 }, -10055, 23197, 0, 0, 28, 43 }, /* region 50 */ + { { 0, 78, 78 }, -8853, 16422, 0, 0, 23, 44 }, /* region 51 */ + { { 0, 79, 79 }, -10253, 16422, 0, 0, 23, 45 }, /* region 52 */ + { { 1280, 80, 80 }, -6468, 13045, 0, 0, 25, 46 }, /* region 53 */ + { { 1280, 81, 81 }, -6568, 16422, 0, 0, 25, 47 }, /* region 54 */ + { { 0, 82, 82 }, -8455, 20675, 0, 0, 22, 48 }, /* region 55 */ + { { 0, 83, 83 }, -9068, 32767, 0, 0, 6, 49 }, /* region 56 */ + { { 1, 84, 84 }, -8568, 23197, 0, 9337, 1, 50 }, /* region 57 */ + { { 0, 85, 85 }, -9655, 32767, 0, 0, 27, 0 }, /* region 58 */ + { { 0, 86, 86 }, -9068, 16422, 0, 0, 8, 51 }, /* region 59 */ + { { 32769, 87, 87 }, -9168, 32767, 1335, 1603, 8, 52 } /* region 60 */ +}; /* end Regions */ + +/*---------------------------------------------------------------------------- + * FM Regions + *---------------------------------------------------------------------------- +*/ +const S_FM_REGION eas_fmRegions[] = +{ + + { /* FM region 0 */ + { 37, 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 } + } + }, + { /* FM region 1 */ + { 37, 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 } + } + }, + { /* FM region 2 */ + { 37, 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 } + } + }, + { /* FM region 3 */ + { 37, 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 } + } + }, + { /* FM region 4 */ + { 34, 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 } + } + }, + { /* FM region 5 */ + { 34, 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 } + } + }, + { /* FM region 6 */ + { 34, 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 } + } + }, + { /* FM region 7 */ + { 37, 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 } + } + }, + { /* FM region 8 */ + { 33, 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 } + } + }, + { /* FM region 9 */ + { 34, 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 } + } + }, + { /* FM region 10 */ + { 34, 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 } + } + }, + { /* FM region 11 */ + { 34, 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 } + } + }, + { /* FM region 12 */ + { 34, 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 } + } + }, + { /* FM region 13 */ + { 34, 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 } + } + }, + { /* FM region 14 */ + { 37, 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 } + } + }, + { /* FM region 15 */ + { 37, 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 } + } + }, + { /* FM region 16 */ + { 35, 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 } + } + }, + { /* FM region 17 */ + { 33, 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 } + } + }, + { /* FM region 18 */ + { 34, 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 } + } + }, + { /* FM region 19 */ + { 33, 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 } + } + }, + { /* FM region 20 */ + { 34, 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 } + } + }, + { /* FM region 21 */ + { 34, 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 } + } + }, + { /* FM region 22 */ + { 37, 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 } + } + }, + { /* FM region 23 */ + { 34, 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 } + } + }, + { /* FM region 24 */ + { 37, 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 } + } + }, + { /* FM region 25 */ + { 37, 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 } + } + }, + { /* FM region 26 */ + { 37, 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 } + } + }, + { /* FM region 27 */ + { 37, 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 } + } + }, + { /* FM region 28 */ + { 37, 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 } + } + }, + { /* FM region 29 */ + { 37, 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 } + } + }, + { /* FM region 30 */ + { 37, 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 } + } + }, + { /* FM region 31 */ + { 41, 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 } + } + }, + { /* FM region 32 */ + { 37, 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 } + } + }, + { /* FM region 33 */ + { 37, 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 } + } + }, + { /* FM region 34 */ + { 37, 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 } + } + }, + { /* FM region 35 */ + { 37, 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 } + } + }, + { /* FM region 36 */ + { 37, 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 } + } + }, + { /* FM region 37 */ + { 37, 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 } + } + }, + { /* FM region 38 */ + { 34, 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 } + } + }, + { /* FM region 39 */ + { 34, 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 } + } + }, + { /* FM region 40 */ + { 37, 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 } + } + }, + { /* FM region 41 */ + { 37, 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 } + } + }, + { /* FM region 42 */ + { 37, 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 } + } + }, + { /* FM region 43 */ + { 37, 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 } + } + }, + { /* FM region 44 */ + { 37, 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 } + } + }, + { /* FM region 45 */ + { 37, 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 } + } + }, + { /* FM region 46 */ + { 34, 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 } + } + }, + { /* FM region 47 */ + { 37, 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 } + } + }, + { /* FM region 48 */ + { 34, 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 } + } + }, + { /* FM region 49 */ + { 34, 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 } + } + }, + { /* FM region 50 */ + { 34, 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 } + } + }, + { /* FM region 51 */ + { 37, 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 } + } + }, + { /* FM region 52 */ + { 34, 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 } + } + }, + { /* FM region 53 */ + { 37, 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 } + } + }, + { /* FM region 54 */ + { 34, 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 } + } + }, + { /* FM region 55 */ + { 41, 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 } + } + }, + { /* FM region 56 */ + { 37, 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 } + } + }, + { /* FM region 57 */ + { 37, 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 } + } + }, + { /* FM region 58 */ + { 37, 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 } + } + }, + { /* FM region 59 */ + { 37, 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 } + } + }, + { /* FM region 60 */ + { 34, 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 } + } + }, + { /* FM region 61 */ + { 34, 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 } + } + }, + { /* FM region 62 */ + { 34, 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 } + } + }, + { /* FM region 63 */ + { 34, 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 } + } + }, + { /* FM region 64 */ + { 37, 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 } + } + }, + { /* FM region 65 */ + { 37, 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 } + } + }, + { /* FM region 66 */ + { 37, 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 } + } + }, + { /* FM region 67 */ + { 37, 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 } + } + }, + { /* FM region 68 */ + { 34, 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 } + } + }, + { /* FM region 69 */ + { 34, 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 } + } + }, + { /* FM region 70 */ + { 34, 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 } + } + }, + { /* FM region 71 */ + { 34, 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 } + } + }, + { /* FM region 72 */ + { 37, 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 } + } + }, + { /* FM region 73 */ + { 37, 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 } + } + }, + { /* FM region 74 */ + { 35, 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 } + } + }, + { /* FM region 75 */ + { 37, 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 } + } + }, + { /* FM region 76 */ + { 37, 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 } + } + }, + { /* FM region 77 */ + { 50, 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 } + } + }, + { /* FM region 78 */ + { 34, 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 } + } + }, + { /* FM region 79 */ + { 35, 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 } + } + }, + { /* FM region 80 */ + { 34, 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 } + } + }, + { /* FM region 81 */ + { 34, 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 } + } + }, + { /* FM region 82 */ + { 37, 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 } + } + }, + { /* FM region 83 */ + { 37, 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 } + } + }, + { /* FM region 84 */ + { 37, 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 } + } + }, + { /* FM region 85 */ + { 34, 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 } + } + }, + { /* FM region 86 */ + { 34, 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 } + } + }, + { /* FM region 87 */ + { 34, 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 } + } + }, + { /* FM region 88 */ + { 35, 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 } + } + }, + { /* FM region 89 */ + { 34, 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 } + } + }, + { /* FM region 90 */ + { 34, 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 } + } + }, + { /* FM region 91 */ + { 35, 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 } + } + }, + { /* FM region 92 */ + { 34, 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 } + } + }, + { /* FM region 93 */ + { 37, 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 } + } + }, + { /* FM region 94 */ + { 35, 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 } + } + }, + { /* FM region 95 */ + { 34, 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 } + } + }, + { /* FM region 96 */ + { 50, 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 } + } + }, + { /* FM region 97 */ + { 34, 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 } + } + }, + { /* FM region 98 */ + { 34, 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 } + } + }, + { /* FM region 99 */ + { 34, 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 } + } + }, + { /* FM region 100 */ + { 34, 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 } + } + }, + { /* FM region 101 */ + { 34, 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 } + } + }, + { /* FM region 102 */ + { 50, 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 } + } + }, + { /* FM region 103 */ + { 37, 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 } + } + }, + { /* FM region 104 */ + { 34, 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 } + } + }, + { /* FM region 105 */ + { 37, 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 } + } + }, + { /* FM region 106 */ + { 37, 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 } + } + }, + { /* FM region 107 */ + { 37, 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 } + } + }, + { /* FM region 108 */ + { 37, 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 } + } + }, + { /* FM region 109 */ + { 34, 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 } + } + }, + { /* FM region 110 */ + { 37, 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 } + } + }, + { /* FM region 111 */ + { 34, 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 } + } + }, + { /* FM region 112 */ + { 37, 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 } + } + }, + { /* FM region 113 */ + { 37, 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 } + } + }, + { /* FM region 114 */ + { 37, 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 } + } + }, + { /* FM region 115 */ + { 37, 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 } + } + }, + { /* FM region 116 */ + { 37, 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 } + } + }, + { /* FM region 117 */ + { 37, 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 } + } + }, + { /* FM region 118 */ + { 37, 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 } + } + }, + { /* FM region 119 */ + { 37, 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 } + } + }, + { /* FM region 120 */ + { 52, 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 } + } + }, + { /* FM region 121 */ + { 37, 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 } + } + }, + { /* FM region 122 */ + { 34, 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 } + } + }, + { /* FM region 123 */ + { 50, 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 } + } + }, + { /* FM region 124 */ + { 50, 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 } + } + }, + { /* FM region 125 */ + { 34, 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 } + } + }, + { /* FM region 126 */ + { 53, 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 } + } + }, + { /* FM region 127 */ + { 53, 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 } + } + }}; /* end FM Regions */ + +/*---------------------------------------------------------------------------- + * Programs + *---------------------------------------------------------------------------- +*/ +const S_PROGRAM eas_programs[] = +{ + { 7864320, 0 } /* program 0 */ +}; /* end Programs */ + +/*---------------------------------------------------------------------------- + * Banks + *---------------------------------------------------------------------------- +*/ +const S_BANK eas_banks[] = +{ + { /* bank 0 */ + 30976, + { + 32768, 32769, 32770, 32771, 32772, 32773, 32774, 32775, + 32776, 32777, 32778, 32779, 32780, 32781, 32782, 32783, + 32784, 32785, 32786, 32787, 32788, 32789, 32790, 32791, + 32792, 32793, 32794, 32795, 32796, 32797, 32798, 32799, + 32800, 32801, 32802, 32803, 32804, 32805, 32806, 32807, + 32808, 32809, 32810, 32811, 32812, 32813, 32814, 32815, + 32816, 32817, 32818, 32819, 32820, 32821, 32822, 32823, + 32824, 32825, 32826, 32827, 32828, 32829, 32830, 32831, + 32832, 32833, 32834, 32835, 32836, 32837, 32838, 32839, + 32840, 32841, 32842, 32843, 32844, 32845, 32846, 32847, + 32848, 32849, 32850, 32851, 32852, 32853, 32854, 32855, + 32856, 32857, 32858, 32859, 32860, 32861, 32862, 32863, + 32864, 32865, 32866, 32867, 32868, 32869, 32870, 32871, + 32872, 32873, 32874, 32875, 32876, 32877, 32878, 32879, + 32880, 32881, 32882, 32883, 32884, 32885, 32886, 32887, + 32888, 32889, 32890, 32891, 32892, 32893, 32894, 32895 + } + } +}; /* end Banks */ + +/*---------------------------------------------------------------------------- + * Samples + *---------------------------------------------------------------------------- +*/ + +const EAS_SAMPLE eas_samples[] = +{ + 13, -24, 28, -32, 33, -37, 39, -61, 119, -76, 120, -70, 99, -122, 89, -113, + 91, -123, 122, -123, 77, 86, -116, 6, -118, 123, -23, 64, -93, 17, 24, -125, + 124, -125, 124, -24, -12, 56, 87, -54, 38, -91, 64, -2, -41, 126, -127, 20, + 8, -48, -62, 127, -128, 88, -43, -18, 86, -100, 44, -32, -26, 71, -13, 6, + 51, -33, -50, 106, -59, 33, 5, -20, 69, -56, 54, -48, -6, 38, -5, -38, + 35, -1, 12, -1, 4, 23, -56, 19, -7, 5, -4, 31, -38, 3, -12, -9, + -25, -7, 24, -32, 17, -21, -22, 24, -20, 6, -18, 0, -15, 5, -16, 15, + 3, 2, -10, 3, 27, -31, 37, -12, 32, -5, 2, -21, 27, -14, 20, -8, + 5, 15, -7, -11, 20, -37, 7, -23, 17, -22, 11, -14, 8, -44, 39, -52, + 26, 3, 14, -10, 51, -45, 29, -19, 19, -3, 41, -21, 46, -23, 10, 16, + -25, 3, 7, -30, 19, -9, -5, -1, 1, -19, 1, -24, -23, 51, -48, -10, + 17, -34, -38, 60, -71, 26, -43, 65, -59, 70, -26, 61, -51, 63, -51, 42, + -25, 58, -36, 31, 10, -14, -9, 8, -18, 8, 4, 8, 7, 31, -52, 39, + -53, 53, -56, 24, 11, 1, -20, -8, -32, -18, -10, -25, 4, 1, 37, -37, + 42, -42, 53, -57, 52, -18, 30, 11, 20, -52, 55, -61, 56, -50, 24, -26, + 38, -42, 36, -1, -43, 58, -46, 6, 18, -35, 31, -36, 28, -55, 55, -98, + 52, -41, 26, -24, 48, -31, 48, -26, 30, 19, -17, 23, -8, 13, 15, 19, + -7, -23, 41, -36, 20, -39, 65, -64, 66, -38, -9, 7, -14, -10, -3, 6, + 15, -19, -40, 53, -67, -11, -12, -25, 23, -11, -12, 46, -48, 39, -20, 20, + -14, 31, -54, 71, -25, 2, -8, -5, -9, 1, 7, 27, 17, -14, 43, -31, + 27, 11, -33, 20, -2, -33, 45, -38, 17, -9, -11, -17, -22, -19, 20, -25, + 4, 29, -35, 14, -17, 1, -7, 19, 2, 16, 32, -3, -17, 4, 0, -9, + 17, 5, -8, 52, -32, 40, -39, -5, -18, 14, -21, 31, 10, -17, 8, -34, + -7, 1, -44, 7, 10, -8, -6, -18, -25, -1, -19, 16, -29, 62, 6, 9, + 21, 0, -14, 4, 5, 20, 13, 27, -1, 18, -5, 21, -31, 11, 2, -9, + -4, 21, -27, 8, -21, -28, -19, 14, -12, 5, -20, 20, -36, 4, -18, -27, + -4, -4, 15, 4, 48, -7, -11, 20, -6, 7, 20, 1, 20, 0, 35, -35, + 28, -37, 7, -43, 21, -22, 23, -18, 12, -22, -13, -20, -11, 7, 23, -10, + 19, -18, 17, -41, 4, -16, -8, 21, 11, -4, 10, 30, -24, 32, -15, 15, + -13, 28, -5, 38, -10, 0, -22, -13, -12, 24, -18, 30, -7, 4, -16, 27, + -28, -3, -1, 18, -14, 31, -24, -3, -13, -19, -36, -2, -31, 9, -2, -12, + 17, 12, -50, 46, -49, 43, -15, 13, 22, 15, -25, 10, -8, -6, 14, -2, + 24, 15, 9, 17, -13, 5, 14, -15, 7, 20, 4, 4, 18, -16, 3, -47, + 31, -46, 19, -24, 5, -19, -1, -42, 14, -44, 18, -7, -1, 15, 9, -35, + 32, -44, 39, -46, 23, -16, 36, -25, 45, -34, 32, -8, 10, 5, 28, 0, + 12, 11, 3, 20, -23, 6, -8, 16, 7, 17, -19, 32, -44, 3, -8, -21, + -8, -5, 2, -29, 2, -3, -19, -14, 3, 7, -23, 10, 1, 3, 8, 13, + -44, 20, 21, -16, 23, 3, 5, 10, -11, 32, -11, 13, -7, 30, 4, 16, + -7, -6, -7, 14, -40, 4, -16, -26, 3, -1, 0, -6, 5, -50, 37, -27, + 18, -16, -14, 6, -1, -4, -15, 8, -12, 14, 9, -22, 42, -10, 23, -11, + 36, -15, 13, 30, 1, 47, -20, 33, -14, -12, 1, -20, -9, -9, -11, -13, + 7, -37, 25, -47, 14, -13, 4, -12, 9, -32, 18, -48, -1, -35, -1, -7, + 35, -20, 53, -4, 34, -7, 13, 19, 9, 30, 6, 45, -22, 23, -18, -6, + -1, 3, -30, 14, -15, 9, -39, 10, -33, -13, -24, 10, 14, 14, -10, 2, + -34, -4, -20, -21, -14, 40, -10, 17, -14, 28, -17, 37, -26, 69, -15, 38, + 2, 21, -25, 37, -61, 13, -9, 5, -17, 18, -41, 22, -57, -1, -9, -13, + 24, -10, 38, -5, 8, -16, -2, 1, 12, -25, -2, -13, 2, 2, -16, -19, + 32, -30, 22, 20, -4, 12, 11, -17, 19, -17, -3, 20, -33, 65, -27, 32, + -14, 8, -8, 13, -19, 9, -2, 7, 33, -40, 18, -18, -18, 6, -23, -11, + -11, -28, 4, -11, -15, -14, -8, -5, 34, -6, 19, 1, -3, 9, -1, 5, + 5, 14, -11, 40, -3, 18, -20, 16, -7, 2, -5, 9, -16, 9, -17, 0, + -17, 4, -17, -3, 3, 8, -14, -19, 12, -21, -7, 1, -2, -8, 16, 3, + -6, 35, -23, 33, -13, 11, 12, 3, -7, 26, -11, 19, -18, 23, -22, 39, + -49, 39, -50, 11, -38, 26, -29, 10, -6, -22, 15, -8, 15, -37, 36, -43, + 39, -43, 18, -26, 1, 11, 4, -2, 9, 7, 2, 7, 19, 1, 1, -4, + 16, -5, 16, -9, -3, 4, -4, -1, -17, 0, 11, 16, -27, 12, -15, 15, + -3, 0, 10, -3, -5, 12, -13, -7, -13, -31, -1, -3, -17, 15, -31, 25, + -10, 15, -1, 2, 4, 10, 7, 32, -13, 7, -22, 2, -10, 16, 1, -15, + 19, -24, 16, -18, -12, 18, -9, 9, 24, -8, 8, 11, 0, -31, 17, -55, + 21, -43, 40, -40, 29, -54, 44, -34, 22, 11, 16, 7, 19, 21, -6, 2, + -7, -16, 22, 0, -1, -4, 5, -8, 26, -42, 4, -6, -21, 35, -16, 8, + 0, -22, -13, 11, -31, 7, -28, 4, 17, -12, -18, -2, -23, 23, -1, 19, + 34, 7, 7, 35, -19, 11, -8, -17, 8, 4, 16, -16, -13, 9, -15, -5, + -1, -6, 7, 3, 11, 1, -7, -24, 21, -31, 36, -3, -10, 8, 2, -17, + 12, -24, 6, -3, 9, 15, 3, 13, -8, -13, -3, 6, -19, 14, -33, 16, + -17, -5, -31, 3, -29, 24, -7, -6, 35, -20, -5, 34, -20, 25, -3, 10, + 25, 8, 14, -13, 0, 1, 17, -33, 51, -38, 45, -32, 39, -3, -2, -24, + 3, -18, 14, -4, -44, 2, -25, -15, -2, -23, 3, -2, -2, 20, -14, 8, + -10, -4, 21, 11, -13, 32, -4, 8, 19, -16, -2, -2, -2, 14, -2, -1, + 27, -26, 20, 11, -13, 10, -3, -7, 12, -13, -3, -30, -16, 10, -26, -3, + -10, -2, -9, 15, -17, 1, -2, -7, 14, -8, 12, -3, -1, 2, 47, -26, + 22, -19, 16, 2, 13, -3, 21, -10, 22, -32, 43, -24, 16, 0, 5, -2, + 12, -44, -12, 1, -26, 1, -36, 5, 2, 9, -17, 20, -37, 14, -9, -5, + 6, -3, -13, 23, -19, 25, -33, 6, 17, 10, 19, 15, -4, 12, 5, -9, + 33, -20, 26, -9, 11, -2, 11, -21, -7, -13, -4, -8, -12, 0, -10, -9, + 8, -33, 9, -26, 8, 6, -8, 12, 7, -8, 0, 7, -16, 25, -8, 27, + 12, 0, 9, -9, 4, -17, 14, -16, 11, -8, 18, -2, 4, 2, -20, -18, + 22, -16, -5, 3, -24, 13, -10, -12, -10, 2, -16, 33, -15, 21, -15, -4, + -19, 29, -22, 18, 2, 20, 12, 18, -22, -7, -16, 7, -19, 14, 1, -17, + 33, -22, 38, -8, 3, -3, 21, -17, 51, -43, 15, -22, -23, -6, -12, -14, + 14, 9, 6, 4, -31, 3, -16, -14, 22, -22, 5, 13, -25, 17, -2, -18, + 7, 1, 5, 36, -16, 23, 4, -15, 29, -20, 10, 1, 24, 17, 16, -4, + -16, -37, -11, 1, -33, 27, -36, 17, -22, 2, -33, 16, -29, 32, -7, 24, + -12, 14, -12, 22, -16, 15, -20, 19, 9, 14, 12, -1, -24, 13, -6, -1, + 32, -19, 24, 12, -26, 4, -31, -38, 18, -16, -13, 3, -14, -1, 11, -15, + 15, 0, -2, 30, -6, 35, -23, 10, -35, 5, -14, 17, -21, 20, 4, 7, + 8, -5, -15, 20, -25, 26, 6, -3, 3, 5, -24, 26, -35, 4, 0, -6, + 13, -23, 8, -25, 1, -2, 9, 3, 17, 4, 0, 13, -15, 3, -21, -16, + 4, -5, -10, 11, -2, 7, 23, -22, 25, -19, 18, 25, -9, 14, -21, -7, + 11, -24, 22, -12, -7, 6, 9, -33, 11, -20, 2, -9, 2, 3, -13, 12, + -15, 23, -21, 16, -16, -2, 8, 13, -12, 18, -10, 16, -12, 20, -18, 18, + -1, 21, -21, 20, -30, -6, 10, -2, 13, -6, -15, 6, 2, -1, 1, -19, + 9, -15, -3, -11, 0, -5, 1, 5, 1, -4, -8, 1, -16, 23, 0, -23, + 2, 8, -6, 38, -4, 2, 13, -17, 31, -4, -8, 22, -14, 0, 12, -22, + 7, -7, 11, 4, -4, -12, -9, -22, 2, -17, -17, -11, 7, -17, 19, -24, + 9, -8, -6, 29, -4, 10, 4, 4, 23, -1, 9, -6, -12, 23, 16, -6, + 33, -29, 12, -7, -10, 17, -4, -18, 21, 0, -14, -2, -20, -21, 10, -28, + 5, -18, -4, 0, -11, 1, 5, -17, 3, 9, 20, 6, 1, -7, 2, -7, + 3, 9, -22, 29, 6, -1, 25, -10, 6, -1, 4, 12, 18, -13, 28, -11, + 6, -15, -14, -22, -7, 5, -14, 1, -16, -12, -5, 5, -9, 4, -1, -14, + 21, -10, -5, 0, -17, -7, 2, -10, 6, 11, 1, 37, -17, 6, 21, -24, + 41, 2, 23, 0, 10, -18, 16, -26, 14, -21, -19, 18, -9, -14, -1, -9, + -14, -3, -7, -10, 7, -7, 19, -11, 15, -25, -3, -6, 2, 8, -10, 4, + 12, -3, 11, -2, -2, 5, 31, -9, 39, -21, 14, -23, 18, -16, -1, -3, + -6, 0, 22, -9, -5, -17, -4, -12, 2, -3, -7, 10, -10, 7, -20, -19, + -10, 0, -14, 32, -15, -18, 13, -9, 2, 17, -14, 6, 36, -9, 28, 1, + 0, 17, -10, 5, 17, -8, 12, -2, 3, 2, -22, -6, -14, 6, 8, -11, + -14, 2, -23, 25, -35, 3, -18, 1, -14, 22, -1, -12, -7, -9, 13, -4, + 12, 4, -3, 18, 0, 1, 8, -14, 14, -2, 1, 17, -3, -14, 35, -17, + 19, -14, -6, 1, -9, 18, -17, -4, -13, -2, -14, 10, -10, -6, 0, 3, + 5, -12, -13, -3, -6, -6, 11, -13, -7, 13, -2, 6, 13, -7, 11, -5, + 23, 1, 29, -17, 23, -10, 18, -16, 12, -20, 10, 7, -9, -5, -21, -9, + 5, -13, -2, 0, -15, -11, 3, 0, -18, 5, -25, -2, 3, -2, -3, 4, + 8, 14, -7, 15, 4, 8, 19, 9, 11, 7, -3, 14, -11, 1, 15, -35, + 3, 3, -10, -16, 0, -15, 2, 3, -12, 27, -23, 32, -15, 10, -14, 3, + -27, 10, -15, 12, -24, 7, 2, 9, -2, -2, -1, 3, 1, 1, 8, -4, + 0, 6, -6, 1, 1, -1, 8, -11, 31, -27, 13, 4, -3, 5, -1, 0, + 2, 9, 0, 12, -31, 4, -27, 1, -25, 20, -21, -14, 12, -14, 0, -5, + -23, 18, -1, 15, 19, -5, 20, -8, 14, -7, 16, 3, 0, 8, 10, 0, + -8, -10, 3, -8, 9, -12, 4, 15, -6, 2, -12, -29, -3, -16, -11, 35, + -18, -1, -28, 7, -12, 0, 7, -5, 22, 10, 10, -4, 6, -13, 21, -23, + 20, 8, -13, 11, 15, -6, -6, -22, -1, 3, 14, 7, 11, -27, 12, -17, + -12, 8, -15, 3, -8, 12, -12, 5, -30, 12, -18, 9, -2, 3, 4, 15, + 1, 5, -9, 0, -8, 24, -2, 21, 5, -4, -4, 14, -15, 0, -1, 3, + 17, -5, 13, -19, -10, -4, -6, -4, -7, 18, -27, 8, 1, -12, -21, -13, + 1, -9, 11, 1, -3, -1, 22, -21, 9, 6, -3, 20, -2, 17, 7, -12, + 1, 4, 4, -9, 9, -20, 24, 7, -9, -3, -7, -6, 10, 7, 3, 9, + -2, -3, -4, 1, -19, -8, -16, 0, -12, 0, -25, 4, -22, 10, -9, 0, + -3, 15, -1, 8, 11, -15, 10, 13, 1, 22, -5, 15, 1, 24, 6, 0, + -6, 5, 5, 10, 8, -1, -11, -14, 3, -31, 2, -22, -4, -8, -15, -2, + -31, -12, 6, -7, 5, 2, 3, -4, 19, 3, 4, 7, 7, -8, 31, -6, + 26, 1, -2, 2, -3, -10, -4, -4, 9, 3, 12, -16, 16, -9, -1, 5, + 4, -7, 13, -17, 0, -11, -13, -22, 1, -9, 4, -7, 7, -10, 5, -1, + -6, -3, -21, 7, -10, 18, -3, 1, -7, -11, 11, -8, 12, 20, 3, 13, + 16, -1, 3, 13, -3, 23, 16, -3, 15, -14, 12, -6, -8, -28, 0, -33, + 4, -11, -12, -13, -21, -17, -16, -5, -12, 16, -7, 15, -6, -5, 3, -9, + 21, 17, 13, 14, 11, 21, -12, 31, -18, 7, 12, 8, 9, 7, 1, -3, + -7, -14, 17, -35, -10, -2, -18, -8, -10, -20, -22, 2, -10, -3, 1, -1, + 4, -5, 11, -20, 11, -6, 27, 7, 18, 8, -1, 2, 3, 11, -9, 5, + 5, -7, 29, -6, 20, -21, 23, -15, 19, -19, 2, -22, 11, -26, -7, -10, + -30, -1, -3, -6, 15, -22, 16, -7, -9, -2, -7, -5, 11, 17, -13, 2, + 8, -5, 6, 27, -6, 12, -6, 4, 15, 3, 14, -3, -12, 11, -2, 6, + 5, 4, -6, -12, 0, -32, 2, -22, 22, -12, -5, -7, -11, -7, 6, -1, + -3, -3, -16, 2, -1, 0, 0, -7, -2, 1, 12, -4, 5, 20, 1, 16, + -2, 14, -1, 19, 8, 29, -8, 7, -14, -2, 3, -13, 8, -40, 22, -18, + 2, -14, -8, -11, -8, 12, -21, -1, -10, -12, -6, -4, -14, 6, -19, 7, + 14, 1, 11, 11, -11, 25, 1, 14, -5, 31, 0, 22, 4, 1, 3, 6, + -3, 4, -2, -20, -7, -26, 1, -12, -7, -10, 2, -1, -5, -7, -8, -10, + 6, -7, -6, 10, -17, 6, 3, 15, -8, 15, -7, 12, 1, 9, -4, -2, + 10, 9, -1, 10, -4, 9, -8, 17, 0, -13, -7, -2, -11, 3, -2, -15, + -4, -11, -5, -9, 1, 8, -10, 8, -8, -6, -18, 21, -19, 26, -19, -1, + -11, 10, 4, 12, -10, 16, -10, 17, 8, 13, -1, 17, 1, 5, -1, 11, + -8, 9, 16, -17, 3, -26, -17, -14, 6, -17, 4, -20, 0, -1, -6, -4, + 2, -15, 13, -3, -1, 0, -2, -8, 11, 7, -3, -8, 5, 14, -1, 28, + -19, 13, -4, 8, 1, 11, 7, 6, -8, -2, -13, -10, -22, 6, 11, -1, + -1, -5, -13, 18, 3, -10, 9, -17, -8, 9, -9, 1, -17, -4, -16, 18, + -6, 15, -10, 17, 5, 0, -5, 0, -11, 12, 15, 4, 8, 5, -4, 0, + -2, 3, -17, -2, -1, 11, -6, -7, 2, -33, 23, -6, -1, -2, -2, -1, + -8, 3, -29, -2, -34, 16, -3, 16, 1, 10, -12, 23, 0, -3, 16, 12, + 19, 23, -1, 8, -26, 16, -32, 26, -13, 2, -11, 5, -1, -15, -9, -16, + 7, -6, 14, -15, 5, -10, -7, -9, -9, 6, -17, 13, 18, -5, -3, -4, + -4, -18, 28, -6, 13, 17, 24, -2, 9, -14, 1, -11, 7, 17, 1, -15, + 10, -23, -4, -12, 5, -20, 17, -10, 6, 0, -9, 4, -8, -15, 6, -16, + 7, 9, 3, 6, -12, -17, 0, 4, 13, 22, -4, 10, -8, 7, -12, 5, + 5, 1, 11, 2, 10, -3, -2, 3, -10, -5, -7, -4, -18, 17, -2, -14, + -16, -7, -10, -3, 6, -1, 14, -11, 15, -18, 2, -6, 0, -1, 0, 20, + -17, 1, 6, 2, 6, 12, -3, 7, 25, -5, 17, -14, 0, -6, 0, -2, + -5, -1, -10, 8, 2, -9, -19, -7, -17, 5, 3, -7, 4, -15, -5, 9, + -12, -1, -5, 3, -5, 26, -2, 3, -4, 5, 3, 7, 10, 5, 6, 6, + 26, -17, 0, -1, 3, -3, 10, -7, -7, -9, 11, -18, 0, -16, -6, -5, + 3, 7, -14, -14, 0, -21, 14, -8, -1, -12, 2, 1, 2, -3, -1, -3, + 18, 5, 5, 9, 12, 7, 18, 8, 5, -25, 16, -15, 16, -7, 9, -22, + 1, 14, -13, -5, 2, -6, -8, 13, -17, 6, -16, 1, -5, -14, -6, -6, + -15, -2, 9, -9, -18, 15, -19, 12, 7, 4, 8, 14, 15, 6, 10, -3, + 9, -7, 23, -17, 21, -20, 7, 0, -9, 8, -10, 1, 4, 2, 3, -9, + -9, -15, -6, -21, -16, -6, 0, -11, 19, -8, -9, 5, -6, 0, 5, 14, + 7, 1, 12, 8, 7, -5, 12, 8, -4, 19, 4, -7, 2, 3, -12, -8, + -1, 0, 5, 7, -5, -8, -22, -8, -21, -2, -9, 10, -20, 13, -6, 8, + -17, -9, -6, 2, 5, 8, 6, -3, 10, -9, -2, 15, -6, 20, 7, 11, + 10, -3, -4, -8, 25, -25, 18, -12, 17, -6, 20, -22, -1, -17, -10, 5, + -10, 9, -13, -9, -6, 10, -25, -5, -2, -5, 13, 2, -5, -8, -10, 11, + -27, 10, -4, 11, 0, 33, -4, 10, -14, 1, 12, -2, 27, -8, 6, 11, + 9, -12, -4, -10, -13, 12, 5, 1, -10, -14, -15, -8, -7, -9, 3, -5, + 10, 3, -11, -12, -13, -3, -3, 3, 2, 9, 17, -6, 25, -3, -3, -8, + 19, 3, 30, -10, 12, -22, 7, -5, -10, -3, 21, -8, 12, 6, -5, -13, + -13, -9, -9, -1, -23, 13, -17, 15, -22, -11, -18, 8, -14, 20, 1, 4, + -5, 3, 3, 5, 11, 1, 2, 27, 1, 10, -7, -8, -2, -2, 7, -1, + 17, -5, 24, -7, 5, -10, -20, -6, 5, -4, -5, -1, -18, -5, -14, -1, + -20, 1, 7, -7, 12, -4, -2, -4, 2, 8, 0, 7, 1, 6, -2, 18, + -5, -7, 4, 3, -2, 13, 4, 0, 2, -3, 2, -10, -6, 1, -6, 6, + -7, -3, -21, -2, -12, 5, -1, -9, 7, -3, 13, 5, 5, -8, 0, -8, + 19, -5, 13, 13, -7, 3, 0, -10, 0, -8, 20, -8, 13, -20, -5, -7, + 3, 5, -7, 2, -5, -4, -14, 11, -23, -13, 2, -1, 12, 13, 5, -6, + 23, -9, 9, -6, -9, 18, -13, 16, -3, -7, -17, 3, -13, 12, -9, 4, + 0, 0, 13, -18, -1, 3, -13, 20, -5, 1, -20, 15, -23, 18, -4, -8, + 5, -7, 16, 4, 6, -3, 7, -21, 19, -17, -7, 9, 5, 3, -5, -3, + -16, -9, 25, -9, 12, -5, 10, -5, 9, -4, -6, -3, 4, 10, -2, 11, + -12, -2, -14, 8, -23, -5, 0, -8, 9, -2, -11, -3, -9, 9, 2, 2, + 4, -5, 7, 11, -16, 0, -6, 7, 6, 25, 5, 6, -4, 3, 4, 3, + 2, -8, -3, 5, -1, -11, -4, -9, -3, -15, 10, -12, -5, 11, -4, -7, + 6, -29, -5, 6, 11, 3, 9, -18, 13, -14, 19, -1, -2, 4, 5, 12, + 1, 5, -8, 3, 1, 20, -6, 2, 3, -16, 10, -10, -18, -11, -7, -7, + 9, -4, -8, 9, -15, 13, -13, -3, -7, 3, 8, 11, -6, -16, 1, -8, + 20, 4, 15, -5, -3, 11, -5, 6, 0, -5, 10, 13, 0, -6, -11, 0, + 11, -11, 10, -7, -8, 1, 16, -9, 2, -22, -9, 0, 4, 5, -12, -22, + 2, -8, -8, 14, -16, 0, 13, 0, 9, -7, 2, -1, 7, 8, -3, -3, + 2, 15, 5, 10, -7, 12, -4, 22, -4, -3, -12, -2, -15, 8, -2, -22, + 7, -10, 5, 12, -20, -9, -11, -2, -12, 2, -9, 5, -3, 11, 7, -9, + 4, -4, 24, -7, 21, -15, -3, 2, 14, -1, 5, 18, -12, 13, 3, 5, + -10, -11, 0, -8, -2, -4, 2, -15, 9, -10, -16, -9, -7, 0, -1, 3, + -8, -10, 5, -8, 4, -3, 8, -2, 20, 1, 6, -4, -9, 4, 14, 7, + -1, 3, -5, 18, -7, 20, -6, -10, 8, 1, -2, 3, -4, -5, -3, -6, + 0, -16, -7, 12, 0, -17, 4, -31, -7, 1, 1, -4, 8, -11, 6, -1, + 11, -5, -7, -4, 2, 4, 15, -3, 21, -5, 20, 3, -12, 21, -1, 10, + 5, 6, -20, -1, -18, 2, 3, -4, -5, -1, 6, -2, -11, -17, -15, -13, + 0, 6, -18, 7, -18, 7, -7, 6, 7, -10, 18, 16, 2, -1, 3, -11, + 6, 14, 1, 15, -2, 29, -8, 17, -14, 2, -19, 12, 8, -6, -1, -23, + 6, -11, 7, -19, -18, 0, 1, -8, -8, -4, -20, 8, -8, 4, 10, -12, + 13, 0, 18, -10, -3, -4, 6, 4, 17, 7, -2, 18, -9, 14, -10, -4, + -11, 4, 3, 23, -17, -6, -2, -7, -7, 9, -10, 1, 2, -4, -14, -7, + -6, -8, -4, 7, 2, -3, 3, 0, 13, -10, -4, -9, -6, 18, 11, -4, + 16, -8, -4, 1, -1, 7, 3, 3, 3, 10, -15, -2, -9, 9, 0, 2, + 2, -9, 12, -7, 0, -23, -7, -19, 2, -1, 0, 4, -15, 7, 3, -3, + 0, 9, -12, 19, 4, 8, -13, -6, 5, -1, 14, 10, 9, 13, -3, 16, + -18, 13, -18, 7, -10, 13, -6, -11, -3, 7, -23, -6, -11, -21, 9, -1, + 4, -3, -16, 0, -12, 7, 14, -5, 15, 0, 6, -5, -3, -9, 9, 4, + 10, 4, -2, -7, 10, -1, 10, -6, -14, 15, -4, 13, -4, -4, -14, 5, + -2, 4, -9, 3, -14, 2, 3, -10, -1, -9, 0, 3, -6, 12, -16, 0, + 4, 10, -25, 6, -5, 2, 8, 3, -2, -4, 15, 4, 7, 2, -1, -6, + 10, 11, 2, -2, -14, 6, -3, 0, -3, -9, -10, 1, -1, -15, 9, -29, + 9, -10, 7, -3, -3, -10, -2, 14, 4, -6, 0, 1, 12, 4, 18, -15, + 19, 1, 15, 1, 1, 3, -10, 8, -1, 7, -30, 8, -19, -2, -5, -9, + -10, 0, -1, 6, -4, -12, 1, -18, 10, -1, -12, 2, 7, 12, 11, 0, + -4, -1, 6, 10, 17, -8, 1, -12, 5, -2, 1, -7, -1, 4, 3, -3, + -1, -18, 8, -9, 0, -2, 8, -12, 12, 7, -5, -2, -16, -7, 9, -5, + 11, -9, -4, 3, 1, -9, -1, -2, -6, 7, 12, 0, -8, 9, -10, 3, + 0, 2, -3, 11, 14, 4, 3, -12, 3, -3, 2, 12, -4, -2, -2, 9, + -21, -5, -28, -6, -10, 6, 7, -6, -3, -24, 7, -11, 10, 0, 8, 13, + 10, 6, -7, -2, -5, 7, -1, 9, 18, -2, 12, -4, 7, -26, 13, -6, + 19, 6, 6, -5, -16, -6, -8, -18, -2, 1, -11, 3, 4, -16, -8, -10, + -3, 2, -3, 5, 5, 0, 11, 0, -14, 0, 1, 14, 11, 13, 0, -2, + 5, -1, -4, -2, -4, 5, 21, 3, 14, -5, -22, 5, -11, -3, -6, -3, + -11, 0, -5, -13, -10, -18, 3, 9, -10, 2, 3, -11, 11, -11, 5, -19, + 23, -1, 20, 18, 4, -3, -6, 9, 4, -3, 8, 4, 6, 2, 5, -14, + -6, -3, 2, -6, -4, -3, -11, 0, -5, 0, -21, -2, -10, 11, 5, -4, + -5, -5, -8, 10, -10, 4, -1, 6, 12, 9, 2, 8, -20, 8, -2, 11, + -11, 1, -4, 5, 6, -6, 6, -14, 14, 4, -2, 12, -3, -10, 8, -5, + -15, -9, -1, 5, 8, -3, 0, -23, -9, -11, 4, -12, 3, -4, 4, 1, + 15, -12, 3, 13, 2, 5, 8, -8, 7, 11, -3, 17, -11, 5, 3, 19, + 13, 3, -11, -11, -2, -9, -7, -4, -24, -1, -17, -3, -17, 0, -15, 2, + -1, -5, -4, 3, 2, 2, 11, -4, 3, -6, 11, 8, 3, 6, 3, 7, + 7, 6, -6, 2, 0, 14, 14, 3, 8, -6, 4, -3, 6, -13, -2, -9, + -4, 5, -13, -5, -21, -1, -6, -1, -5, -14, 8, -7, 5, -7, -17, -11, + 7, 3, 20, 7, 1, -3, 4, 5, 14, -3, 5, 3, 10, 8, 6, -6, + -2, 6, 3, 7, -6, -3, -3, -6, -1, -27, -11, -17, 0, 11, 7, 1, + -7, -9, -13, 5, -11, 0, -10, 15, 2, 5, -2, -5, 1, 6, 6, -6, + -5, 6, 2, 5, 3, 10, -16, 11, 8, 18, 3, 13, -11, 7, 5, -7, + -6, -20, 15, -1, 10, -1, -13, -17, -11, -3, -13, -4, -14, -3, -2, -6, + 6, -28, 9, -8, 10, 0, 12, -2, 10, 9, 1, 3, -6, 5, 17, 24, + 18, 3, 4, -9, -4, 2, -8, -4, -2, -11, 1, -8, -12, -9, -10, 5, + 0, -7, -9, 7, -18, 6, -10, -12, -1, -1, 13, 1, 18, 2, -3, 4, + 3, 3, -3, 3, 10, 9, 7, 5, -8, -7, 0, 3, -7, 7, -2, -2, + 5, -10, 2, -5, -3, -1, 4, 1, -2, -10, 4, -9, -5, -12, -18, 3, + 6, -3, 3, -15, -1, -13, 6, -2, 8, 0, 8, 16, -2, 17, -4, 8, + 3, 23, -1, 11, -8, 10, -4, -5, -3, -13, -2, -1, -2, 2, -9, -13, + -13, -2, -11, -2, -20, -5, 0, 3, 2, -1, -10, 1, 8, 3, 9, 6, + 4, -3, 13, 3, 4, 11, 2, 11, 8, -2, -1, -2, -2, -2, -1, -21, + -1, -14, 8, 6, -8, -10, 2, -16, 4, -3, -1, -10, 7, -1, 4, -4, + -12, 3, -2, 13, 2, -3, -9, -2, 6, -7, 8, -8, -5, 12, 7, 8, + -3, 6, -1, 16, 0, 7, -8, 3, -7, -1, 0, -6, -4, -8, 6, -1, + 4, -19, 2, -3, -8, -3, -12, 4, -6, 2, -7, 1, -13, 2, 9, -1, + 17, -19, 3, -3, 23, 9, 6, 3, 6, 6, -5, 11, -11, 1, 0, -5, + 6, -6, -4, -5, -7, 3, -4, -14, -9, -7, -1, 5, -11, 4, -19, 14, + -4, 3, 4, 2, 0, 9, -2, -3, 2, -2, 10, 15, -3, 14, -6, -4, + 6, 1, -8, 11, -9, 4, 3, -9, 2, 2, -2, 2, -2, -9, -2, -2, + 1, -6, -6, -22, -16, -10, 12, 0, 5, -8, -2, -4, -2, 5, -1, 7, + 7, 9, 1, 7, 6, -1, 10, 11, 5, -3, 8, 1, -1, 8, -15, -6, + -10, 12, 0, 2, -5, -9, -12, -7, -4, -14, -4, 0, -1, 5, -7, -8, + -12, 0, 2, 16, -3, 11, -4, 16, 11, 2, -3, 2, 8, -1, 7, -13, + 4, -3, -1, 3, -10, -2, -11, 3, 2, 3, -7, -10, -5, -10, 12, -8, + 5, -7, 15, 1, -10, 7, -16, 1, 3, 4, -5, 7, -7, 4, -2, -1, + -8, 0, -2, 17, 10, -2, 6, -5, 3, 10, -7, 2, -3, 4, 5, 5, + -3, -8, -8, -1, 1, 7, -5, -11, -2, -10, -4, -15, -7, -10, -2, 2, + -4, -10, -8, 0, 2, 6, 3, 2, 3, 10, 14, 8, 7, 3, 5, -5, + 20, -6, -1, -2, 0, 1, -2, -2, -8, 3, -3, 10, -14, 3, -3, -2, + 0, -5, 0, -15, 4, -2, 0, 4, -7, 3, -8, 7, -14, -2, -6, 4, + 2, 3, -10, -2, 5, -3, 12, -2, -5, -9, 1, 4, 1, 11, -12, 15, + 5, 20, 10, -5, 1, 5, 3, -13, 6, -16, 5, 1, -5, -8, -3, -14, + -6, -2, -5, -8, -17, -9, 3, -6, -2, -3, -3, 1, 14, 2, 4, 5, + 3, 8, 7, 12, 0, 11, 4, 16, 2, -3, -9, -1, 1, -1, -3, -6, + -14, 4, -6, 2, -14, -9, -11, -1, 0, 0, -5, -6, -10, 5, -5, 2, + -3, 2, 2, 17, -2, -1, -3, 3, 11, 1, 10, 2, 7, 6, 5, -5, + -3, -3, -2, 7, 2, 1, -18, -5, -2, -3, -5, 0, -2, 0, 8, -9, + -10, -15, -7, -2, -1, 6, -8, 16, -10, 13, -4, 2, -4, 4, 7, 9, + 6, -5, -2, 8, -1, 11, -6, -1, 5, 8, 0, 9, -20, 0, -9, 4, + -3, 1, -4, -11, 2, -6, 0, -12, 0, 1, 5, -2, 1, -7, -4, 3, + -1, -10, 3, -3, 7, 4, 8, -9, -6, -10, 0, 0, 2, -4, 6, 9, + 10, 2, 0, -1, 2, 14, 3, 7, -7, 2, -2, -2, -6, -9, 2, -3, + 6, -3, -7, -9, -10, -2, 2, -1, -11, 2, 1, 7, -4, -7, -19, 3, + -1, 6, 6, 6, 6, 0, 6, 7, 3, -1, 3, 8, 3, 4, -10, -5, + -7, 5, -4, -14, 2, -8, 5, -2, 2, -16, -4, -11, 2, 4, -1, 2, + -1, 0, 5, 4, -12, 3, 9, 7, 13, -3, -7, 2, 6, -1, 7, -1, + -1, 5, -5, 7, -11, -9, -13, 2, 5, 2, -2, -7, 5, 4, -4, -2, + -15, -4, 3, 0, 0, -5, 2, -7, -1, 9, -2, -1, 5, 1, 1, -4, + -5, -4, 6, 8, 7, -5, 4, -7, 4, 0, 1, -6, -5, -2, 5, -1, + 0, 1, 1, 3, 9, -4, -2, -4, -9, -1, 4, -17, 1, -13, 11, -1, + 6, -9, -1, 5, 1, 8, -3, 4, -5, 1, 7, -5, 1, -3, 5, 3, + 4, -7, -11, -7, 1, 5, -13, 11, -11, 1, 3, 6, -9, 6, -5, -7, + 4, -13, 5, -7, 10, 5, 6, -15, -1, 6, 4, 18, -7, -7, -3, -4, + 2, -5, 3, -4, 9, -4, 3, 3, -3, -10, 0, -1, 2, 5, -3, 7, + 3, 2, -6, -11, -2, -1, 4, -5, 4, -5, 0, -5, 5, -5, -4, 2, + 4, 2, 5, -8, -13, -3, 0, -1, -2, 4, 6, 9, 1, 3, -7, -1, + 1, 12, 1, 1, -1, -5, -1, 2, -8, -9, -7, -2, 3, 10, -6, -7, + -12, -7, -4, -5, 6, 0, 10, 5, 7, -4, -2, -8, 10, 5, 9, 4, + -1, -1, -1, -1, -1, -2, -3, 3, 9, -2, 9, -14, -13, -8, -10, 1, + 1, 3, 3, 1, -3, -12, -5, -7, 1, 6, 6, -2, -7, -3, -3, 2, + 2, 4, -9, 14, 8, 11, -3, 5, -11, 1, -1, 5, 3, 8, 2, 8, + -2, -6, -13, -10, 0, 4, 3, 4, -3, -9, 1, -5, -5, -6, 1, -2, + 2, -10, -6, -15, 1, -5, 4, -1, 2, 2, 4, 10, 4, 2, -13, 0, + 4, 8, 17, 2, 5, 4, 2, -6, 5, -5, 0, 8, -2, -1, -5, -4, + -5, -1, -5, -4, -5, 0, 0, 1, -9, -15, -3, -12, 1, -1, -7, 10, + 2, 5, -1, 2, -6, 2, 2, 10, 10, -1, 2, -2, 4, 5, 0, -6, + 12, 5, 3, -1, -8, -8, -4, -4, 3, -11, 0, -1, -1, 0, -2, -14, + -6, -9, 2, 1, 7, -4, 3, -1, 0, -3, 1, 2, 7, 5, 4, 3, + -2, -3, 1, 6, -1, 6, -11, 7, 2, -6, 2, -4, 0, 2, 3, -7, + -9, 3, 0, 4, -6, 0, -21, 0, -5, -1, 0, -1, 1, -6, -1, -1, + 0, -7, 5, 7, -2, 8, -4, -1, 3, 9, -6, 10, -6, 7, 9, 10, + 9, -6, 5, -14, 6, -5, 1, 2, -3, 0, -9, -10, -14, -2, -3, 6, + -8, -15, 3, -9, 0, -3, 0, -6, -1, 3, 9, 10, 3, 3, -10, 6, + 1, 3, -1, 9, 12, 4, 4, -9, -7, -5, 8, 6, 1, 1, -4, -5, + -5, -1, -11, -3, -4, 1, -1, 1, -10, -7, -2, -3, -4, -3, -6, 11, + 5, 3, 2, -8, -5, -2, 3, 9, 13, 5, 4, 4, 0, -5, -1, -5, + 9, 2, 3, -9, -4, 3, -6, 2, 1, -9, 5, -2, 3, -2, -9, -8, + -15, -5, -3, 3, -13, 11, 6, -3, 1, -6, -6, -1, 6, 4, 6, 7, + 1, 5, 0, 8, -6, 7, 2, 6, 2, -5, 0, -3, -1, 3, -7, -1, + -3, 5, 7, 6, -18, -10, -11, -7, -3, 10, -4, 3, -4, -8, -5, -12, + -3, -4, 12, 10, 2, -4, 6, 3, 1, 2, 0, -3, 3, 7, 7, -5, + 2, -4, 1, 3, 11, 2, 3, 4, -2, -7, -5, -17, -11, 4, -3, 5, + -7, -7, -6, -1, -8, -5, -5, 1, 7, 1, 2, -1, -9, 7, 1, 7, + 3, 3, 6, 9, 6, 1, -6, -4, 2, 5, 7, 4, -2, 1, 3, -11, + -1, -16, -2, -6, 1, 3, -8, -15, -11, 4, -1, 9, -2, -5, 0, 6, + 0, -7, 0, -8, 4, 2, 6, 2, 0, 2, 6, 2, -2, 4, -2, 4, + 14, 2, 2, -6, -6, -3, 4, -4, -1, -4, 1, -3, -6, -1, -13, -1, + -2, 7, -8, -7, -10, 0, 4, 3, -8, -3, 1, 4, 6, 4, 6, -3, + 5, 3, 4, 0, 6, 1, 4, 7, -3, -10, 8, -1, 9, -1, 1, -11, + -7, -3, -3, -6, -8, -9, -6, 1, -3, -6, -6, -5, 0, 0, 2, -3, + 0, 6, 4, 3, 2, 7, 4, 11, 14, 5, -1, -5, 1, -2, 7, 3, + 0, 1, 2, -5, -7, -10, -12, -10, -5, -5, -6, -6, -9, 1, -8, -2, + -1, -9, 1, 8, 2, -5, -2, -5, 0, 5, 6, 6, 7, 8, 10, 2, + 0, -3, -1, 2, 13, 3, 0, -6, 0, 1, -3, 0, -12, -2, 4, -4, + 4, -8, -11, -1, -2, 1, -1, 2, -12, 3, -6, 1, -12, -7, -7, 3, + 0, 9, 0, 1, 6, 1, -1, 2, 1, 2, 8, 9, -3, -1, 0, 7, + 3, 8, -1, -4, -1, 1, 3, -9, -1, -17, -3, -2, -4, -4, -3, -4, + -6, -11, -15, -2, -5, 6, 10, 1, 3, -1, -3, 13, 7, 1, 6, 4, + 4, 9, 5, -3, -5, 9, 3, 5, -3, 1, -3, 3, 0, -7, -5, -7, + 0, -5, 0, -1, -15, -11, -4, -5, -10, 2, -7, 5, -4, 1, -9, 2, + 1, 8, 7, 10, 2, 2, 0, 4, 3, -2, 0, 4, 2, 6, 8, -2, + 4, 4, -2, 5, -3, -6, 3, -3, -5, -9, -8, -11, -5, -1, -1, -5, + -7, -5, -8, 0, -3, 5, -7, 11, 1, 0, 2, -3, -1, 3, 9, 6, + -3, 8, 1, 11, 2, 8, -3, -3, 6, 2, 1, 2, -7, -3, -2, -4, + -8, -3, -3, 5, -10, -10, -4, -12, -2, 3, -5, 3, -6, -8, -2, 5, + -3, 0, 1, 4, 8, 4, 5, 0, 4, 8, 1, 7, -3, 0, 3, 4, + 4, -5, -2, -7, -3, 0, 5, -5, -9, 3, -2, -1, -2, -5, -1, -4, + -3, -11, -4, -5, -6, 0, 5, 0, -5, 5, 3, 8, -1, 3, 3, 2, + 5, 7, -4, 3, 1, 3, 10, 2, -7, 1, 0, 6, -4, -3, -5, -7, + -2, -4, -3, -6, 0, -10, 4, -6, -4, -7, -2, 1, -4, -1, -3, -1, + 2, 6, 2, 4, -2, 2, 4, 2, 5, -3, 4, 2, 1, 0, 8, -3, + 2, 5, -5, 3, -5, -2, 5, -5, 3, -1, -4, -3, 4, -10, -5, -7, + -4, -4, 0, 0, -7, -1, -1, 2, 1, -2, -12, -4, -1, 0, 4, -5, + 2, 0, 3, 12, 11, 3, 11, -1, -3, 6, -6, 1, 1, 7, 6, -7, + -1, -7, -4, -4, -7, -8, -1, -6, -6, -2, -3, -5, 0, -4, 8, -7, + 1, 4, -3, 6, 1, -7, 3, 5, 6, 5, 13, 2, 2, -4, 4, -3, + 1, 4, -4, 2, -3, -10, -10, -7, -2, -2, -2, 0, -6, -2, 1, -3, + -4, -2, -5, -2, 7, 1, 6, -5, 6, -1, -1, 2, -3, 4, 11, 2, + -1, 2, -7, -5, 8, 0, 3, -3, -5, -1, -2, 3, 1, -4, 4, 7, + 0, 2, 3, -3, 0, 1, -5, -15, -5, -3, 1, 3, -3, -11, -4, -7, + 1, -2, -1, -1, 0, 1, 1, -5, -1, 3, -2, 7, 1, -4, -1, 0, + 4, 5, 3, 3, -1, 8, 11, 1, 4, 1, -5, 7, -6, -4, -2, -4, + -2, 3, -8, -3, -13, -6, 3, -3, -7, -4, -7, 3, 3, -3, 2, -1, + 1, -4, -2, -2, -5, 1, 11, 9, -2, 6, -3, 7, 7, 1, 1, -7, + 2, -3, 1, 4, -4, -4, 5, 1, 0, -3, -6, 2, -3, 0, -8, -12, + -6, -2, -3, 6, -1, -9, 0, -1, 1, 3, -2, -1, 0, 1, 6, 0, + -3, 5, 1, 6, 1, -1, 4, 1, 7, -3, -1, -1, -4, 4, 14, -1, + -1, 2, -4, -1, -6, -8, -8, -3, -2, 2, -9, -5, -7, -12, 5, 0, + -3, -4, -3, 5, 4, 3, -2, -6, 4, 7, 3, 5, 7, -3, 8, 0, + -5, -1, -1, 11, 10, 3, 4, -8, -3, -3, 1, -3, 0, -4, -3, 1, + -7, -8, -16, -7, -6, -2, 3, -7, -2, 1, -4, 0, -5, -5, 1, 5, + 10, 5, 0, 3, 0, 1, 13, 0, 5, 9, 6, 8, -1, -4, 0, -3, + 6, 4, -4, 0, -3, -15, -2, -12, -15, -3, -6, 2, 1, -3, -4, -9, + -9, -3, -3, -2, 3, 4, 9, 0, 2, 1, 2, 14, 5, 3, 8, 2, + 7, 4, -4, -4, -1, -9, 9, -5, -1, -7, -10, -2, -7, -4, 0, -5, + 2, 5, 1, 0, -5, -5, -1, -1, -3, 4, -8, 5, 3, -4, 4, -5, + -3, 9, 4, 8, 0, 0, 2, 0, -2, 0, -2, -7, 12, -1, 5, -4, + 2, -3, 0, 2, -2, -4, -2, 2, -5, 3, -7, -9, -4, -3, -2, -6, + -6, -2, -6, -1, -7, -8, 1, 3, 6, 10, 4, 5, 0, 5, 8, 1, + 3, 8, 5, 11, 12, -7, 4, 0, -3, 2, -1, -8, -7, -4, -2, -6, + -9, -6, -13, -4, -1, 0, -9, -5, -3, -4, -2, 3, 1, 1, 9, 4, + 2, 6, -1, 3, 6, 2, 0, -3, 3, 2, 6, 3, -1, -4, 4, 1, + 2, 2, -5, -8, -1, -3, -1, -9, -4, 1, -5, 5, -7, -4, 0, 3, + -10, 3, -3, -5, 1, 5, 4, 1, -5, 1, -5, 4, 1, -6, 0, 5, + 8, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, -10, -6, -8, + -2, -1, -3, -6, -6, -5, -6, -6, -5, 5, -3, 5, 6, -2, -1, -1, + -4, 6, -2, 6, 6, 2, 12, 8, -2, 3, -6, -2, 5, 4, -3, -2, + -5, -4, -7, -6, 1, -5, 2, 2, 0, 1, -7, 0, -4, -2, -1, -2, + -5, 7, -5, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, -5, -3, -4, + -4, 4, 3, 6, 1, -2, -2, -7, 4, 1, 1, -3, 3, -1, 2, 0, + -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, -1, 5, 5, + 2, 2, -3, 4, 3, 4, 6, 3, -1, 10, -4, -3, -2, -3, 0, -4, + 0, -2, -2, 0, 2, -5, -2, -5, -9, 8, -2, -1, -1, -3, -3, -2, + -6, 2, 1, 2, 9, 0, 1, 4, -5, 2, 4, -6, -1, 2, -1, 6, + 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, -2, 0, 3, + 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, -6, -1, -3, + 2, 4, 1, -1, 0, 1, 1, 3, -1, 5, -1, 7, 6, 1, -2, 0, + -6, -2, -2, -8, -2, -2, -3, -5, -5, -8, -3, -1, 5, -3, 1, 2, + 1, 2, -3, -2, -3, 2, 6, 2, 6, 0, 0, -2, 9, -1, 3, -2, + 3, 0, 0, 0, -6, -6, -1, -5, -7, 1, -3, -6, 2, -2, -1, -5, + -2, 1, 4, 2, 2, -3, -1, 6, -2, 2, 4, -3, 2, 2, 2, -3, + 1, 0, -4, 2, -1, -2, 3, 1, 1, -1, -5, -8, -2, -5, 0, 1, + -6, 3, -4, 2, 3, -6, 3, 0, 2, -2, -1, -4, -2, -4, 4, 0, + -3, 0, -6, -3, 10, -3, 3, 0, 4, 7, 3, 0, 5, 1, 5, 1, + -3, -2, 0, -6, 3, -1, -7, -5, -7, -1, -2, -2, -2, -3, -2, 2, + -2, -1, -3, -3, 2, -2, -6, -3, -3, 4, 3, 2, 0, -1, 5, 5, + 8, 2, 2, -2, 4, 0, 5, -5, -3, -1, -3, -3, -6, -4, -2, 3, + 0, -2, -2, -5, 5, -1, 3, -1, -1, -3, 0, 0, -5, -4, -3, -2, + 5, 0, -4, -4, 1, 2, 6, 0, -3, -1, 2, 3, 7, -3, 0, -4, + -2, 4, 3, 0, 1, 3, -3, 1, -7, -4, 0, 1, 1, -4, -4, -4, + -9, -1, -2, -3, -2, -3, -3, 4, 3, -1, -4, 2, 4, 4, 3, 2, + -1, 0, 9, -1, 4, 2, 7, -1, 6, -2, -2, -5, -1, -9, -2, -2, + -6, -1, -1, 1, -8, -6, -5, -1, -1, 1, -4, -5, 3, 1, 5, 3, + -3, 0, -2, 7, 0, 1, -2, 3, -1, 5, -1, -5, 7, -1, 3, 2, + -5, -6, -2, 4, 2, -1, -3, -1, -1, -1, -1, -2, -4, 1, -5, 3, + -1, -3, -5, 2, 6, -6, -1, -5, -4, 4, -1, -1, -2, -1, 2, 0, + 3, 1, 4, 2, 7, -1, 2, 0, -2, 1, 4, -5, -3, -7, -2, 0, + -1, -1, -3, 0, 0, -2, -6, 2, -4, 2, -4, 1, -7, -2, -1, 5, + 3, -2, -7, -4, 1, 6, 4, 5, 1, 4, 0, 5, 1, -1, 2, 0, + -3, -3, -5, -6, 3, -1, 5, -1, -2, 1, 1, 4, 2, -6, -3, -4, + -3, 2, -2, -8, -3, -6, -4, -2, -11, 0, 0, 1, 6, -3, -2, 1, + 2, 10, 8, 4, -2, -1, 2, 2, 1, -2, 3, 1, 5, 3, -1, 0, + -4, 4, -7, -2, -7, -8, -4, -3, -2, -7, -7, -3, -1, 5, -2, 0, + -7, 2, -1, 3, 1, 4, 6, 5, 8, 3, 2, -1, 3, -3, 0, 0, + -5, -1, 1, 1, -5, -3, -2, 6, 4, 5, -4, -8, -4, -3, -2, -5, + -4, -4, -4, 2, -3, -2, -4, -4, -4, 6, 1, 0, 1, 3, 3, 5, + 2, 1, 0, 6, 2, -1, 1, -3, -3, 2, -1, 0, 1, 3, 1, 4, + -4, -5, -10, -8, 1, -6, -3, -4, -6, -3, 0, 2, -3, -1, 2, 0, + 8, 1, 4, 4, 3, 6, 3, 1, 3, 5, 1, 2, -4, -7, -3, -3, + 3, 0, -7, -5, 0, -3, -1, -2, -4, 0, -5, 1, -6, -1, -5, -3, + 1, 4, -1, -3, 3, 3, 5, -1, -2, 2, -1, 2, 1, -1, -5, 5, + 1, 2, 2, -4, 0, -1, 3, 0, -2, -1, 2, 1, 5, 4, -3, -5, + 0, -2, -2, -6, -3, -3, -4, -1, -5, -4, -1, -2, 0, 2, -2, -6, + -3, 1, 1, 1, -1, 3, 4, 7, 2, 3, 4, -1, 7, 2, 3, 1, + -1, 1, -2, 0, -4, -5, -6, 0, -2, -7, -2, -5, -5, 1, -4, -5, + -5, 3, -1, 1, 2, -2, 0, 1, 4, 1, -4, 2, 2, 0, 9, 2, + 0, 4, 3, 1, 2, -4, -2, -4, 3, -4, -2, -6, 0, -1, 5, 2, + -4, 0, -4, -4, -1, -5, -4, -7, -3, 1, 0, -2, -1, -5, 1, 0, + -1, 0, 2, 4, 0, 3, -2, 1, 2, 6, 0, 1, 5, 0, 3, 3, + 2, -5, -2, 1, 5, 2, -2, -5, -9, 0, -6, -1, -6, -7, -5, -4, + 0, -2, -5, -3, 2, -2, 3, 2, 0, 9, 2, 0, 4, -3, 4, 5, + 8, 6, -2, -4, -1, 0, -2, -2, 1, -5, 2, -5, -1, -4, -3, -4, + 0, -2, -7, -3, -1, 0, -1, 0, -6, 3, -2, 5, 2, -1, -2, 1, + 0, 1, -1, -3, 2, 3, 1, 2, -4, -3, -1, 5, 5, 3, -4, 0, + 1, 2, 5, -5, 1, -5, 2, -2, 2, -4, -3, 0, -4, -3, -9, -7, + -4, 2, -2, 1, -6, -3, 0, 1, 5, 1, -5, 0, 0, 2, 1, 2, + 0, 6, 4, 6, 3, 2, 3, 1, -2, -2, -9, -4, -1, 4, 0, -1, + -5, -8, -5, -4, 0, -4, -1, -3, 0, 0, -4, -3, -1, 1, 2, 0, + -2, -3, 1, 3, 2, 3, 3, 0, 8, 2, 7, -1, 3, -2, 4, 0, + 0, 1, -4, 5, -1, -3, -3, -6, -4, 2, 1, -5, -4, -7, -4, -4, + -7, -2, -10, 1, 0, 1, -3, 4, -2, 5, 2, 1, -3, -1, 2, 8, + 4, 5, 0, 1, 4, 5, 2, 2, -2, 1, -4, 0, -3, -3, -1, 0, + 2, -4, -4, -5, -1, -7, 0, -4, -5, -1, -3, 2, -2, 0, 3, 0, + 2, 0, 1, -2, 2, 4, -1, 0, -3, -1, 1, 3, 2, -3, 2, 0, + 2, 2, -1, 2, -2, -3, 0, 0, -2, 2, -2, 4, -3, -6, -7, -6, + 2, -1, -4, -1, -7, -1, -3, 3, -1, 0, -2, 2, 2, -3, 3, -4, + 5, 7, 6, 3, 1, -1, 6, 2, 1, 0, -1, -1, 1, -3, 1, -3, + -5, -5, -3, -8, -3, -11, -1, -1, 0, -8, -2, -5, 3, 4, 0, 1, + -2, 2, 0, 6, 4, 1, 4, 1, 5, 0, 0, 1, 2, 5, 0, 1, + -10, 0, -5, 2, 0, -6, -6, -2, -2, 2, -3, 0, -4, 2, -4, 1, + -3, -4, 1, -2, 2, 1, -2, 0, 3, 2, -3, -1, -5, -3, 4, 2, + 3, -1, 4, 1, 5, -1, 2, -3, 2, -3, 0, -3, -2, 1, 1, 5, + 1, -2, -5, 1, -1, -4, -3, -7, 0, -5, -4, -4, 0, -4, 4, 0, + -1, 1, -8, 1, 0, 9, 1, 2, -2, 5, 5, 1, 6, -1, 6, 3, + 1, 1, -2, -2, -4, -3, -2, -3, -7, -4, -4, -1, -3, -8, -1, -8, + 4, -5, 0, -3, 1, 0, 4, -1, 0, 1, 3, 3, 4, -4, 6, -2, + 2, 5, 4, -3, 4, -3, 5, 0, -4, 0, 0, -1, 0, -4, -4, 3, + -1, -2, -4, -8, -9, -5, -4, 4, -4, 1, -4, 1, 1, -1, -1, -1, + 3, 2, 3, 0, 1, 2, 1, 5, 3, 1, 0, 5, 3, 3, 0, -5, + -4, -2, 5, 0, -2, -5, -2, -6, -2, -5, -8, -2, 1, -1, -3, -7, + -8, -6, 0, 4, 7, -2, 7, -1, 7, 3, 2, -5, 0, 2, 0, 1, + -3, 2, 2, 3, 3, -3, 0, -2, 3, -1, -1, -4, -6, -2, -3, 4, + -4, 0, -4, 6, -2, -6, -2, -7, 1, 2, -1, -3, -2, -2, 3, -1, + 0, -3, -1, 4, 7, 4, 0, 2, -1, 0, 6, -2, 1, 1, 5, 4, + 1, -3, -3, -2, 2, 2, 1, -6, -6, -3, -4, -2, -6, -5, -4, -5, + -2, -8, -8, -3, 0, 4, 0, 1, -1, 2, 5, 4, 2, 2, 3, 3, + 4, 10, 0, 2, 0, 3, 1, 1, 0, -3, 1, -3, 1, -7, 0, 1, + -2, 1, -6, -4, -10, -1, -4, -2, -2, -3, 2, -4, 1, -5, -4, -4, + 2, 1, 1, -4, -1, 3, 1, 6, 2, -2, -2, 3, 3, 2, 7, -5, + 5, 0, 8, 1, -1, 2, 3, -1, -6, 0, -10, 3, -1, -1, -5, -6, + -8, -2, 0, -3, -5, -8, -4, 2, -3, -1, -2, 0, -1, 7, -1, 3, + 2, 4, 7, 3, 4, -1, 5, 1, 9, 1, -2, -1, -1, 1, -3, -2, + -6, -7, 1, -3, -1, -9, -4, -6, 0, 2, -3, -2, -4, -3, 0, -4, + -1, -4, 0, 1, 6, -1, 1, -1, 3, 5, -1, 3, 4, 5, 7, 4, + -2, 0, -2, 0, 3, 1, -1, -8, -2, -1, -2, -5, -1, -2, -2, 2, + -5, -7, -9, -2, -3, -2, 1, -5, 4, -4, 5, -1, -1, -3, 2, 3, + 7, 3, -1, 3, 4, -1, 5, -4, 0, 4, 4, 3, 4, -9, 1, -5, + 2, -2, -2, -3, -7, -1, -2, -2, -5, -3, -1, 1, -2, -1, -4, -4, + 1, -1, -7, 0, -1, 2, 5, 4, -4, -5, -4, 0, 2, 1, -1, 3, + 5, 4, 0, 0, -1, 3, 8, 3, 3, -4, 0, 1, 0, -2, -6, -2, + -4, 3, -2, -3, -5, -6, -3, -1, -1, -7, 0, 0, 3, -5, -4, -11, + 0, 0, 3, 3, 1, 1, 1, 4, 6, 1, 1, 2, 9, 3, 3, -4, + -4, -3, 2, -1, -6, 1, -5, 2, 0, -1, -8, -5, -6, 1, 0, -2, + -1, -2, -1, 2, 0, -9, 0, 5, 4, 7, -3, -3, 3, 4, 2, 4, + 0, -1, 3, 1, 5, -5, -6, -7, 0, 3, 0, -2, -4, 3, 3, -3, + -4, -7, -2, 4, 1, -1, -4, -1, -6, -2, 3, -2, -3, 1, 4, 1, + -1, -4, -3, 3, 4, 5, -2, 2, -3, 4, 0, 3, -3, -3, 0, 3, + 1, -2, -1, -3, 2, 4, -2, -2, -3, -1, -1, 3, -11, -2, -8, 5, + -1, 3, -5, -2, 2, -1, 3, -3, 0, -1, -1, 5, -2, 0, -2, 3, + 2, 3, -2, -6, -3, 2, 4, -6, 5, -6, 1, 2, 3, -6, 2, -3, + -4, 3, -9, 2, -6, 3, 4, 2, -9, -1, 1, 2, 8, -3, -4, -1, + -2, 2, -2, 2, -3, 3, -1, 1, 2, -1, -6, 1, 2, 2, 1, -2, + 2, 3, 1, -3, -6, -3, 0, 1, -3, 0, -3, -1, -4, 2, -4, -3, + -1, 4, 0, 5, -6, -7, -1, 0, 0, -3, -1, 2, 4, 0, 3, -4, + -1, 1, 7, 4, 2, -1, -4, 0, 2, -4, -5, -5, -1, 1, 4, -5, + -4, -6, -3, -2, -3, 2, -2, 5, 2, 3, -4, -2, -5, 6, 3, 4, + 2, -3, 1, 0, 0, 1, -3, -1, 1, 7, 0, 6, -6, -7, -2, -7, + 0, -1, 0, 2, 1, -2, -7, -2, -5, 0, 2, 0, -3, -5, -1, -3, + 0, -1, 0, -6, 8, 4, 5, -1, 1, -4, 1, 1, 4, 2, 5, 3, + 6, 0, -2, -9, -4, -1, 0, 0, 1, -1, -4, -1, -5, -5, -5, 0, + 0, 1, -6, -5, -9, 0, -3, 0, -2, 0, 0, 3, 4, 2, 1, -7, + 1, 3, 4, 9, 1, 4, 4, 2, -4, 2, -2, 1, 5, -2, 0, -3, + -4, -3, -2, -4, -4, -4, 1, -1, 2, -6, -8, -3, -8, -1, -2, -4, + 5, 2, 3, -1, 0, -4, 2, -1, 5, 5, -1, 3, 0, 3, 3, 0, + -4, 9, 4, 2, -1, -6, -4, -2, -2, 2, -7, 0, 0, -2, -2, -2, + -10, -4, -7, 0, -2, 2, -2, 2, 1, 0, -3, 0, 1, 6, 3, 2, + 0, 0, -1, 2, 3, -1, 4, -5, 6, 2, -3, 0, -3, 0, 1, 0, + -5, -6, 1, 0, 1, -5, -2, -14, 0, -4, -1, -1, -1, 1, -3, 0, + -2, -1, -4, 4, 5, -1, 5, -1, 3, 3, 5, -3, 5, -3, 5, 5, + 6, 4, -6, 2, -9, 4, -4, 0, 1, -2, -1, -8, -6, -11, -2, -3, + 3, -6, -8, 3, -5, 1, -3, 1, -3, 1, 3, 5, 6, 2, 1, -6, + 4, -1, 1, 0, 7, 7, 2, 3, -6, -4, -4, 3, 3, 0, 1, -1, + -2, -4, 0, -8, -2, -3, 1, -2, 1, -5, -2, -1, -3, -3, -4, -3, + 7, 4, 1, -1, -6, -5, -3, 2, 5, 8, 3, 3, 2, 1, -4, -1, + -2, 6, 3, 2, -4, -1, 1, -5, -1, -1, -5, 2, -2, 1, -2, -7, + -5, -11, -4, -3, 3, -8, 8, 4, -2, -2, -4, -4, -1, 4, 3, 5, + 5, 2, 4, -1, 6, -3, 6, 2, 3, 0, -4, 0, -2, -2, 0, -5, + -2, -1, 4, 3, 1, -13, -8, -8, -5, -3, 7, -2, 3, -2, -5, -3, + -8, -2, -3, 8, 6, 1, -2, 5, 3, 1, 2, 0, -1, 2, 4, 3, + -5, 1, -3, 0, 1, 7, 1, 2, 3, -1, -4, -4, -10, -7, 3, 0, + 2, -5, -5, -4, -1, -7, -3, -3, 1, 3, 0, 0, -1, -6, 6, 1, + 4, 1, 2, 5, 6, 4, -1, -4, -3, 1, 2, 5, 2, -1, 1, 3, + -8, -1, -10, -2, -5, 0, -1, -6, -10, -7, 2, -2, 6, -1, -2, 1, + 4, -1, -5, -1, -5, 4, 1, 4, 2, 1, 3, 4, 0, -2, 1, -1, + 3, 8, 2, 1, -4, -3, -3, 3, -3, -1, -4, 0, -4, -6, -2, -8, + 1, -2, 5, -6, -5, -6, 0, 3, 1, -6, -3, 1, 2, 4, 2, 4, + -2, 3, 3, 3, 1, 5, 1, 2, 3, -2, -6, 6, -1, 6, -2, 1, + -7, -5, -2, -3, -6, -6, -6, -4, 0, -2, -4, -4, -3, 0, -1, 1, + -3, -1, 3, 1, 1, 0, 6, 4, 8, 10, 5, 0, -3, 1, -2, 5, + 2, 1, 1, 1, -4, -6, -8, -8, -8, -5, -4, -5, -4, -5, 0, -5, + -3, 0, -7, 0, 4, 1, -4, -1, -4, -2, 4, 4, 5, 6, 6, 7, + 0, 0, -1, 0, 2, 9, 2, 1, -3, 0, 1, -3, 1, -9, -1, 3, + -4, 3, -6, -7, -2, -1, -1, -1, 1, -9, 2, -5, 1, -8, -6, -6, + 1, -1, 6, 0, 2, 5, 2, 0, 2, 1, 2, 6, 5, -2, -1, 0, + 4, 1, 6, 0, -2, 1, 0, 3, -7, -1, -13, -4, -3, -3, -3, -2, + -3, -5, -9, -11, -2, -3, 4, 7, -1, 2, 0, -2, 8, 5, 1, 4, + 3, 2, 7, 3, -2, -4, 7, 2, 3, -2, 1, -1, 2, 0, -5, -4, + -4, 0, -4, 0, -1, -10, -9, -3, -5, -8, 1, -5, 3, -3, 0, -7, + 1, 0, 5, 4, 7, 1, 1, 0, 2, 2, -2, -1, 2, 1, 4, 6, + -1, 4, 3, -1, 4, -2, -3, 3, -1, -2, -6, -6, -7, -3, -1, 0, + -4, -6, -5, -6, 0, -3, 3, -5, 7, 0, -1, 1, -3, -1, 1, 6, + 3, -3, 7, 1, 10, 1, 6, -1, -2, 5, 2, 1, 1, -4, -2, 0, + -3, -7, -2, -4, 4, -8, -8, -4, -10, -2, 2, -4, 1, -5, -7, -1, + 3, -1, 1, 1, 4, 6, 2, 2, 0, 4, 7, 0, 5, -2, 0, 3, + 3, 3, -3, -1, -5, -2, 0, 3, -4, -6, 2, -1, 0, -2, -4, 0, + -4, -3, -9, -3, -4, -4, 0, 3, -1, -4, 3, 1, 5, -2, 1, 2, + 2, 4, 5, -3, 2, 1, 3, 7, 1, -5, 1, 0, 5, -3, -2, -3, + -4, 0, -3, -2, -5, 0, -8, 3, -6, -4, -6, -2, 2, -4, -2, -3, + -2, 1, 4, 2, 3, -2, 2, 4, 1, 4, -2, 3, 2, 1, 1, 7, + -1, 2, 4, -4, 2, -4, -2, 5, -4, 3, -1, -3, -2, 3, -8, -4, + -6, -3, -3, -1, 0, -6, -1, 0, 1, 1, -2, -10, -3, -1, 0, 2, + -5, 1, 1, 2, 10, 8, 2, 8, -1, -2, 4, -5, 2, 2, 7, 6, + -6, -1, -5, -4, -3, -6, -7, 0, -5, -5, -1, -2, -5, 0, -4, 6, + -6, 0, 3, -3, 4, 0, -6, 2, 5, 5, 4, 10, 0, 2, -3, 3, + -2, 0, 3, -3, 2, -3, -8, -8, -5, -1, -1, -1, 0, -5, -2, 0, + -3, -4, -1, -5, -2, 5, 0, 5, -4, 4, -1, -1, 1, -3, 3, 9, + 2, -1, 1, -6, -3, 7, 1, 3, -2, -4, 0, -1, 3, 1, -3, 4, + 6, 0, 1, 2, -3, 0, 0, -5, -13, -4, -2, 1, 2, -3, -10, -4, + -7, 1, -2, -2, -1, 0, 1, 1, -4, -1, 2, -2, 7, 1, -3, 0, + 0, 4, 5, 2, 2, -1, 6, 9, 1, 3, 1, -5, 5, -6, -5, -2, + -4, -2, 2, -7, -4, -11, -5, 3, -3, -6, -4, -6, 3, 3, -3, 2, + 0, 1, -3, -1, -2, -4, 1, 10, 8, -2, 4, -3, 6, 6, 1, 0, + -7, 2, -2, 1, 3, -4, -4, 4, 1, 0, -2, -5, 2, -2, 0, -7, + -11, -5, -2, -2, 5, -1, -8, -1, -1, 1, 2, -2, -1, 1, 1, 5, + 0, -3, 5, 1, 6, 1, -1, 3, 1, 6, -3, -1, -1, -3, 4, 12, + -1, -1, 2, -4, -1, -6, -8, -7, -3, -2, 1, -9, -5, -6, -10, 5, + 1, -2, -3, -2, 5, 4, 3, -1, -5, 4, 6, 3, 4, 6, -2, 7, + 0, -4, -1, -1, 9, 8, 2, 2, -8, -3, -3, 0, -2, 0, -4, -2, + 0, -6, -7, -14, -6, -5, -1, 3, -6, -2, 1, -3, 0, -4, -5, 1, + 5, 9, 4, 0, 3, 0, 1, 12, 0, 4, 8, 5, 7, -1, -4, 0, + -3, 5, 4, -4, 0, -3, -13, -2, -10, -14, -3, -5, 2, 1, -3, -4, + -8, -8, -3, -2, -2, 3, 4, 8, 0, 2, 1, 2, 12, 5, 3, 8, + 2, 6, 3, -4, -4, -2, -8, 8, -5, -2, -6, -10, -2, -6, -4, 0, + -4, 2, 5, 1, 0, -4, -4, -1, -1, -3, 4, -7, 4, 3, -3, 4, + -4, -3, 8, 4, 7, 0, 0, 2, -1, -2, -1, -2, -7, 11, -1, 5, + -4, 2, -2, 0, 2, -2, -4, -2, 1, -5, 3, -6, -9, -3, -3, -2, + -5, -5, -2, -6, -2, -7, -8, 1, 3, 5, 9, 4, 4, 0, 5, 8, + 1, 3, 7, 5, 10, 11, -7, 3, 0, -3, 1, -1, -7, -7, -3, -2, + -6, -9, -6, -12, -4, -1, 0, -8, -5, -3, -3, -2, 3, 1, 1, 9, + 4, 2, 5, -1, 2, 6, 2, 0, -3, 2, 2, 5, 2, -1, -4, 4, + 1, 1, 2, -5, -8, -1, -3, -1, -9, -4, 1, -4, 5, -6, -4, 0, + 3, -9, 3, -3, -5, 1, 4, 4, 1, -4, 1, -4, 4, 1, -6, 0, + 5, 7, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, -9, -6, + -7, -2, -1, -3, -5, -6, -5, -5, -6, -5, 4, -3, 5, 5, -2, -1, + -1, -3, 6, -2, 5, 6, 2, 11, 8, -1, 3, -6, -2, 5, 4, -3, + -3, -5, -3, -7, -5, 0, -5, 2, 1, 0, 1, -7, 0, -3, -2, -1, + -2, -5, 7, -4, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, -5, -3, + -4, -4, 4, 3, 6, 0, -2, -2, -6, 4, 1, 1, -3, 3, -1, 2, + 0, -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, -1, 5, + 5, 2, 2, -3, 4, 3, 3, 6, 3, -1, 10, -4, -3, -2, -3, 0, + -4, 0, -2, -2, 0, 1, -4, -2, -5, -9, 8, -2, -1, -1, -3, -3, + -2, -6, 2, 1, 2, 9, 0, 1, 3, -4, 2, 4, -6, -1, 2, -1, + 6, 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, -2, 0, + 3, 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, -6, -1, + -3, 2, 11, 11, -28, -10, 54, -53, 2, 43, -37, 0, 43, -48, 7, 11, + -18, 19, -33, 32, -1, -7, -6, 19, -21, 23, -38, 0, 54, -49, 0, 15, + 20, -28, -20, 53, -28, -48, 70, -6, -60, 51, 5, -32, 1, 31, -10, -33, + 24, 33, -68, 21, 50, -67, -1, 57, -28, -21, 26, 15, -48, 9, 33, -32, + -3, 23, -10, 5, -4, -10, 24, -42, 29, -13, 0, 26, -15, -26, 46, -17, + -38, 45, -26, 8, -1, 4, -5, -3, 15, -27, -2, 39, -37, -25, 74, -33, + -25, 16, 24, -26, -25, 46, 10, -74, 50, 33, -80, 37, 32, -51, 13, 26, + -21, -5, 0, 18, -33, -1, 49, -29, -29, 38, 7, -26, -20, 45, -21, -18, + 26, -6, -6, 17, -29, -5, 41, -38, 10, 19, -18, -7, 15, 2, -24, 1, + 21, -6, -28, 51, -30, -7, 10, 6, -22, -3, 37, -32, -24, 63, -16, -60, + 65, -10, -35, 15, 17, -15, -8, -1, 33, -37, -10, 55, -44, -5, 41, -35, + -9, 20, -5, -18, 13, 19, -27, 2, 34, -34, -7, 21, -27, 27, -25, 26, + 5, -30, 32, -45, 38, -3, -41, 24, 25, -31, 5, 9, 9, -37, 13, 31, + -36, 7, 20, -18, -25, 56, -50, 13, 17, -17, 19, -40, 46, -3, -82, 88, + -1, -73, 66, -10, -4, -18, 13, 5, -27, 14, 7, -7, -10, 37, -39, 11, + 14, -38, 35, -21, 5, 11, -27, 45, -37, -6, 34, -39, 23, 16, -51, 51, + -11, -28, 19, -6, 12, -29, 12, 26, -21, -25, 48, -35, -6, 24, -9, 0, + -31, 54, -19, -47, 73, -33, -43, 81, -59, 12, 15, -28, 22, -26, 33, -2, + -29, 14, 34, -63, 28, 16, -40, 31, -22, 18, 8, -22, 25, -31, 6, 26, + -54, 33, 19, -53, 56, -25, -9, 24, -39, 34, -18, -15, 35, -18, -16, 43, + -41, -3, 47, -54, 9, 33, -13, -24, -2, 41, -26, -35, 73, -49, 1, 32, + -34, 20, -28, 22, -5, -16, 23, 18, -62, 47, 5, -57, 51, -15, -5, 0, + 4, 12, -11, -15, 29, -28, 4, 26, -44, 43, -19, -14, 35, -37, 23, -15, + -11, 45, -54, 17, 42, -67, 18, 47, -58, 17, 25, -35, 14, -6, 11, -3, + -42, 73, -50, -12, 67, -68, 28, -6, -4, 16, -44, 47, 8, -64, 80, -39, + -31, 54, -43, 14, -2, 11, -14, 4, -3, 19, -34, 0, 61, -98, 69, 12, + -61, 48, -35, 28, -12, -38, 85, -86, 42, 25, -76, 77, -31, -37, 39, -2, + -12, 7, -10, 16, -1, -33, 60, -48, -16, 70, -69, 13, 38, -43, 15, 0, + 0, 22, -65, 75, -28, -60, 96, -58, -8, 32, -6, 1, -11, 4, 17, -46, + 17, 46, -86, 66, 9, -69, 67, -21, -30, 33, -32, 42, -34, 1, 50, -74, + 40, 5, -34, 21, 7, -23, 21, -14, 10, -1, -33, 58, -48, -3, 65, -77, + 14, 51, -65, 32, -10, 0, 24, -58, 71, -27, -54, 86, -56, -12, 45, -17, + -18, 21, -1, -5, -14, 12, 19, -75, 78, 1, -80, 84, -25, -33, 48, -50, + 45, -30, -15, 69, -86, 46, 22, -56, 14, 36, -35, 2, 16, -11, 4, -24, + 41, -27, -19, 53, -42, -4, 49, -67, 36, 2, -26, 37, -46, 58, -40, -26, + 82, -70, -7, 55, -30, -20, 36, -1, -32, 11, 7, 7, -41, 39, 18, -68, + 65, -11, -39, 40, -34, 30, -20, -12, 70, -98, 53, 27, -74, 40, 10, -31, + 11, 20, -19, 6, -6, 12, -19, -9, 46, -36, -31, 83, -65, 8, 32, -48, + 42, -45, 49, -23, -32, 68, -59, 5, 39, -31, -1, 23, -20, -8, 17, -7, + -15, -1, 16, 25, -63, 51, 14, -66, 47, -10, -15, 5, -1, 36, -72, 54, + 22, -86, 64, -3, -31, 13, 11, -8, -12, 14, 15, -34, 6, 29, -24, -25, + 62, -49, -9, 49, -56, 45, -31, 18, 4, -37, 57, -41, -11, 38, -38, 7, + 24, -20, 10, -13, 20, -17, -8, 18, -4, -30, 35, 14, -63, 56, -7, -52, + 50, -5, -4, -19, 17, 36, -83, 51, 14, -52, 30, 4, 0, -15, 14, 8, + -43, 32, 3, -20, 2, 19, -11, -20, 45, -42, 14, 3, -5, 9, -31, 43, + -20, -30, 51, -24, -19, 47, -42, 21, -17, 25, -24, -20, 52, -37, 1, 20, + -6, -21, 25, -2, -33, 30, -9, -15, 23, -13, 26, -49, 29, 22, -76, 71, + -12, -37, 27, 4, 7, -41, 30, 10, -45, 28, 13, -13, -21, 31, -1, -33, + 27, 6, -18, -10, 24, -6, -26, 33, -10, -37, 72, -60, 24, 1, -13, 15, + -36, 52, -44, 18, 14, -31, 23, 2, -16, -8, 10, 23, -47, 19, 17, -10, + -17, 10, 29, -69, 56, -5, -38, 47, -28, 14, -21, 6, 32, -55, 33, 12, + -39, 24, 5, -11, -25, 31, 12, -47, 35, 9, -25, 1, 7, 5, -36, 57, + -52, 18, 29, -45, 37, -45, 35, -13, -17, 41, -31, 7, 8, -18, 15, -19, + 19, -22, 2, 33, -37, 20, -4, 2, -25, 27, 0, -34, 37, -13, -6, 3, + 1, 17, -46, 28, 32, -78, 60, -7, -25, 18, -6, 12, -35, 31, 4, -38, + 37, -11, -8, -13, 37, -22, -17, 32, -27, 25, -34, 24, 9, -43, 41, -19, + -1, 29, -48, 29, -6, -8, 10, -11, 27, -35, 18, 9, -19, -7, 12, 4, + -27, 30, 2, -24, 13, 7, -18, -1, 16, 11, -68, 77, -15, -45, 43, -24, + 29, -38, 16, 21, -43, 27, -7, -10, 11, 1, -4, -13, 26, -17, -1, 1, + -1, 3, -19, 34, -24, -13, 49, -51, 22, 3, -23, 29, -33, 28, -7, -15, + 31, -35, 2, 29, -28, -11, 27, -4, -18, 19, 2, -31, 26, -16, 17, -28, + 34, -3, -49, 64, -39, 6, 1, -8, 25, -38, 32, 4, -53, 47, 0, -32, + 16, 14, -1, -37, 31, -4, -7, -8, 9, 7, -20, 36, -34, 4, 25, -39, + 25, -13, 4, 12, -36, 51, -38, 0, 34, -51, 27, 13, -34, 14, 12, -9, + -23, 41, -21, -1, -16, 28, 10, -62, 66, -23, -26, 26, -9, 13, -29, 13, + 31, -62, 49, 1, -49, 49, -18, -7, 2, 14, -10, -19, 20, 5, -8, -17, + 37, -27, -5, 23, -35, 17, 15, -30, 30, -20, 28, -32, -5, 48, -64, 29, + 13, -37, 35, -10, -1, -7, -3, 14, -16, -9, 26, -5, -35, 48, -21, -21, + 40, -26, -11, 21, 3, 0, -42, 47, 8, -71, 72, -21, -21, 25, -15, 7, + -16, 14, -1, -24, 18, 32, -48, 12, 30, -46, 12, 26, -45, 36, -20, 18, + -3, -34, 52, -40, -2, 25, -29, 32, -11, -18, 18, -3, 3, -24, 7, 36, + -40, -10, 50, -35, -19, 47, -30, -4, 22, -17, 8, -22, 29, 4, -72, 85, + -21, -48, 57, -19, -8, -10, 17, 5, -31, 16, 24, -47, 29, 12, -31, 14, + 2, -27, 43, -26, 5, 13, -33, 48, -46, -6, 58, -67, 13, 45, -50, 26, + -6, -6, -2, -9, 24, -20, -7, 40, -37, -5, 36, -29, -17, 38, -21, 2, + -5, 6, 14, -52, 59, -11, -59, 82, -38, -22, 32, -11, -6, -4, 11, 14, + -38, 30, 5, -44, 24, 25, -37, 0, 21, 1, -9, -24, 49, -36, -12, 47, + -49, 20, 34, -70, 43, 6, -31, 21, -20, 24, -13, -10, 37, -35, -8, 37, + -26, -22, 44, -20, -13, 20, -7, 8, -28, 36, -15, -42, 79, -41, -28, 46, + -17, -8, -5, 5, 29, -44, 17, 24, -43, 20, 13, -42, 16, 37, -43, 5, + 22, 4, -31, 6, 26, -40, 11, 31, -45, 24, 9, -27, 26, -29, 26, -13, + -16, 38, -40, 19, 21, -37, -9, 51, -32, -18, 34, -11, -7, -11, 22, 0, + -40, 49, -20, -23, 44, -22, -9, 3, -2, 19, -44, 42, 6, -52, 41, 6, + -43, 20, 28, -48, 31, 8, -23, 10, -7, 7, -19, 4, 31, -41, 15, 28, + -40, 16, -8, 16, -25, -4, 51, -55, 19, 0, 8, -29, 29, -16, -11, 37, + -39, 18, 4, -6, -5, -14, 35, -6, -52, 72, -37, -9, 13, 11, -17, -22, + 53, -32, -20, 42, -19, -18, 12, 19, -29, 12, 12, -24, 15, -6, 6, -12, + -15, 54, -44, -2, 41, -48, 32, -20, -4, 9, 1, 5, -35, 48, -11, -17, + -9, 24, 1, -37, 38, -9, -16, 16, -2, -11, -1, 13, 11, -55, 67, -31, + -19, 37, -26, -4, 12, 16, -34, 11, 21, -22, -10, 12, 0, 0, -21, 37, + -16, -11, 29, -37, 15, -3, 17, -37, 13, 38, -54, 30, -2, -19, 11, -11, + 20, -20, 15, 4, -22, 13, 2, -8, -13, 20, 4, -28, 33, -9, -34, 38, + -13, -6, -14, 46, -33, -9, 36, -34, 4, 8, -9, 11, -9, 5, 1, -17, + 23, -16, -3, 4, 18, -26, -11, 54, -53, 5, 18, -5, -11, 8, 11, -20, + 12, -10, 1, 2, 5, -4, -5, -1, 23, -35, 22, -1, -25, 19, 3, -7, + -11, 22, 1, -37, 45, -26, -12, 20, 2, -23, 17, 13, -23, -4, 18, 1, + -15, -15, 33, 4, -49, 46, -25, 3, 5, 2, -11, 7, 13, -33, 13, 10, + -24, 12, 6, -3, -4, 12, -9, -10, -3, 20, -19, -3, 19, -2, -21, 16, + 5, -33, 35, -17, -3, 2, 17, -12, -21, 27, -17, -6, 19, -8, -6, 14, + -12, 10, -16, 13, 0, -19, 11, 20, -23, -9, 38, -50, 22, 17, -24, -5, + 17, 7, -24, 0, 23, -18, -14, 27, -15, 5, 6, -9, 1, -2, 7, -24, + 16, 10, -12, -9, 26, -19, -14, 30, -18, -13, 19, -10, 10, -8, 6, 1, + -27, 35, -13, -20, 26, -5, -11, -10, 28, -9, -32, 36, -3, -25, 12, 28, + -51, 36, -6, -20, 18, -2, -3, -1, -11, 28, -31, -4, 48, -56, 16, 19, + -18, 6, -4, 1, -10, 11, 0, -4, -6, 25, -26, -9, 30, -26, -6, 23, + -13, 10, -7, -3, 19, -56, 64, -30, -31, 50, -4, -31, 15, 15, -27, 6, + 13, -6, -14, 20, -2, -27, 23, 7, -30, 10, 19, -10, -1, -13, 27, -31, + 3, 38, -56, 29, 20, -45, 24, 5, -17, 0, 5, 3, -9, 2, 24, -25, + -14, 31, -13, -22, 28, -6, -8, 1, 3, 13, -41, 51, -39, -20, 60, -30, + -28, 48, -14, -26, 25, -10, 7, -17, 16, 5, -25, 13, 10, -32, 11, 35, + -46, 17, 10, 5, -32, 10, 21, -44, 19, 30, -39, 15, 7, -18, 11, -11, + 10, -13, 1, 19, -14, -12, 30, -25, -18, 43, -23, -15, 30, -13, -6, -14, + 43, -42, -9, 55, -36, -17, 43, -21, -11, 12, -13, 16, -28, 23, 10, -38, + 27, 17, -47, 22, 20, -46, 30, -7, 6, -10, -6, 26, -34, 15, 22, -39, + 15, 21, -43, 26, -6, 1, -14, 12, 20, -26, -12, 41, -29, -29, 57, -40, + 2, 27, -22, 8, -10, 10, -10, -10, 30, -14, -29, 47, -17, -24, 25, -11, + 3, -17, 30, -3, -32, 28, 7, -44, 35, 12, -46, 39, -6, -10, -2, -3, + 23, -31, -4, 49, -48, 6, 39, -55, 32, -8, -9, 0, 8, 7, -15, -3, + 29, -26, -16, 43, -44, 13, 26, -30, 9, 6, -5, 4, -28, 30, 9, -56, + 64, -19, -33, 43, -25, -8, 14, 8, -14, -8, 18, 11, -44, 23, 17, -39, + 20, 19, -24, -1, 12, 7, -27, -2, 47, -51, 3, 47, -55, 28, 1, -23, + 17, 4, -12, 5, -9, 18, -9, -21, 30, -24, 6, 12, -11, -2, 14, -13, + -3, -10, 26, -10, -45, 74, -31, -31, 51, -26, -14, 19, -8, 2, -4, 3, + 23, -43, 20, 15, -31, 13, 20, -36, 18, 9, -17, -3, 0, 21, -32, 12, + 32, -50, 21, 12, -26, 16, -6, 5, 1, -16, 21, -5, -27, 28, -11, -11, + 19, -2, -20, 28, -17, -2, 4, -5, 9, -26, 43, -31, -11, 47, -42, 1, + 19, -16, 5, -8, 12, 9, -41, 41, -7, -32, 22, 25, -51, 23, 14, -18, + 7, -21, 31, -22, -2, 24, -24, 6, 18, -39, 25, -9, 3, 5, -17, 28, + -13, -17, 27, -21, -12, 25, -12, -12, 32, -19, -6, 11, -24, 29, -21, 11, + -2, -17, 36, -29, -9, 24, -16, -2, 7, -6, 17, -27, 27, -20, -11, 23, + -1, -31, 25, 15, -32, 12, -8, 21, -22, -8, 26, -16, -15, 47, -45, 8, + 12, -12, 14, -28, 33, -10, -15, 15, -11, 6, 2, -17, 5, 23, -20, -5, + 19, -21, 12, -8, -8, 31, -38, 31, -17, -14, 31, -27, -1, 19, -20, 19, + -10, 4, -2, -7, 2, 1, -6, 6, 12, -27, 12, 8, -10, -7, 8, -1, + -3, -15, 47, -53, 15, 25, -40, 24, -7, 12, -13, -11, 22, -7, -22, 14, + 7, -5, -11, 13, 5, -8, -9, 4, 7, -22, 22, -12, 16, -9, -16, 29, + -32, 8, 23, -36, 14, 7, -3, 5, -27, 24, -1, -20, 14, 7, -7, -4, + 9, -21, 6, 23, -27, 7, -1, 23, -30, -3, 31, -39, 26, -17, -3, 30, + -24, 9, -7, -13, 30, -24, 3, 2, 9, -6, -15, 24, -18, 9, -20, 16, + 2, -8, 11, -11, 6, -10, 6, 11, -38, 27, 20, -42, 28, -26, 35, -21, + -29, 51, -32, 8, -3, 15, -19, 3, 14, -33, 24, 4, -9, -9, 4, 23, + -29, 0, 21, -32, 39, -38, 20, 8, -34, 38, -27, 8, 12, -12, 3, -8, + 11, -11, 1, 3, -9, 18, -18, 10, 0, -7, 4, -13, 17, -13, 0, 33, + -56, 42, -11, -7, 7, -17, 36, -50, 24, 21, -25, -7, 14, 9, -27, 8, + 23, -28, 3, 8, 2, -12, -10, 39, -43, 24, -4, -5, 18, -38, 39, -26, + -8, 26, -24, 14, 10, -20, 5, -9, 15, -19, 13, -12, 5, 24, -39, 24, + -8, 8, -16, -14, 53, -49, 16, 5, -22, 26, -28, 18, -13, 7, 18, -31, + 6, 17, -12, -13, 3, 26, -35, 16, 18, -36, 21, -12, 28, -49, 27, 22, + -38, 13, -1, 17, -28, -5, 30, -22, 2, 25, -42, 32, -19, 18, -23, -1, + 21, -20, 22, -31, 25, 3, -25, 9, -6, 27, -29, -3, 32, -35, 19, -7, + -8, 11, -12, 28, -35, 1, 39, -33, -6, 2, 30, -35, -1, 41, -42, 18, + -9, 6, -8, -2, 26, -46, 24, 24, -41, 11, 11, -2, -12, -9, 48, -59, + 31, -10, 6, -12, -5, 34, -43, 33, -12, -7, 11, -11, 1, 7, -12, 17, + -23, 32, -24, -5, 19, -26, 27, -28, 24, -15, -5, 31, -41, 11, 11, -4, + -19, 10, 37, -53, 2, 43, -35, 2, -3, 20, -20, 3, 32, -53, 30, 5, + -24, 10, -7, 41, -53, 10, 33, -31, -8, 11, 12, -30, 28, 4, -37, 28, + 8, -30, 12, -17, 42, -38, 5, 24, -33, 35, -41, 23, -1, -4, 5, -20, + 32, -18, -10, 25, -22, -4, 14, 6, -24, -5, 62, -80, 28, 19, -20, 4, + -14, 41, -49, 14, 34, -45, 3, 13, 17, -37, -4, 66, -61, -5, 35, -15, + -5, -2, 14, -24, 21, 5, -41, 41, -22, 18, -24, 5, 44, -66, 34, -3, + -17, 24, -26, 20, -13, 14, -1, -31, 39, -19, -20, 31, -14, 0, -12, 46, + -61, 29, 19, -44, 36, -26, 30, -31, -7, 49, -41, -15, 54, -42, -1, 12, + 24, -48, 8, 44, -57, 17, 13, 7, -34, 13, 33, -55, 28, 4, -14, 4, + -9, 32, -42, 15, 28, -58, 40, -12, 0, 7, -8, 8, -24, 29, -9, -29, + 38, -23, 9, -8, 13, -7, -14, 24, -37, 32, -7, 3, -17, 1, 39, -46, + -20, 78, -68, 15, 17, -6, -4, -15, 37, -47, 15, 20, -17, -12, 28, 9, + -52, 25, 31, -54, 24, 4, -1, -11, -5, 51, -74, 36, 9, -27, 17, -6, + 8, -12, 3, 6, -16, 14, 0, -15, 10, 3, 7, -31, 34, -22, -2, 17, + -20, 9, 10, -7, -13, -5, 45, -52, 8, 30, -33, 15, -11, 28, -32, -5, + 44, -42, -4, 42, -25, -29, 29, 14, -36, 12, 19, -20, 8, -14, 33, -42, + 16, 23, -48, 32, 2, -14, 2, -1, 14, -21, -9, 42, -47, 24, 0, -10, + 0, 15, -19, -1, 21, -31, 13, 15, -23, 10, -14, 20, -7, -27, 50, -32, + -5, 18, -10, -1, -8, 25, -36, 12, 34, -45, 6, 27, -20, -16, 12, 19, + -22, 0, 12, 0, -13, -8, 31, -41, 17, 16, -29, 17, 11, -19, -4, -2, + 36, -55, 30, 13, -35, 25, -7, -8, 10, -4, -8, 13, -7, 0, 4, -16, + 8, 13, -35, 40, -25, -6, 44, -51, 17, 15, -18, -3, 1, 14, -18, -1, + 24, -23, -9, 20, -6, -9, 1, 24, -30, 6, 6, 10, -29, 8, 31, -48, + 21, 27, -43, 13, 4, -4, -5, -2, 19, -18, 12, -15, 4, 16, -25, 9, + 1, 2, 0, -13, 12, 3, -16, -3, 18, -10, -6, 25, -41, 21, 11, -30, + 20, -3, 0, 1, -14, 27, -19, -21, 38, -28, 9, -3, 14, -22, 13, -4, + -2, -6, 12, 2, -26, 30, -1, -38, 31, 7, -32, 25, -16, 14, -4, -9, + 15, -19, 6, 4, -11, 2, 11, -8, -4, 10, -7, -4, 6, -10, 2, 11, + -9, 0, -5, 15, -16, 0, 9, -2, -7, 0, 11, -11, -12, 35, -44, 20, + 13, -19, 2, 13, -11, -14, 12, 10, -22, -2, 27, -24, -2, 15, 5, -29, + 22, -10, 6, -2, -3, 16, -31, 20, 11, -39, 29, 9, -34, 25, -10, 5, + -2, -15, 14, 0, -5, -6, 19, -18, 13, -22, 5, 24, -30, -1, 35, -23, + -12, 12, 12, -26, 5, 22, -32, 16, 16, -27, 2, 10, -4, -12, 2, 23, + -19, -1, 1, 11, -17, 4, 8, -18, 12, 12, -24, 1, 24, -20, -15, 29, + -5, -31, 42, -23, -8, 20, -18, 19, -33, 24, 8, -22, 0, 32, -38, 9, + 21, -25, 2, 23, -30, 7, 16, -20, 12, -10, 8, -14, 12, 16, -41, 24, + 14, -30, 6, 2, 19, -22, -6, 25, -8, -24, 23, -1, -29, 32, 9, -53, + 50, 4, -42, 12, 12, 3, -24, 15, 14, -25, 5, 4, 7, -25, 26, -5, + -23, 28, 0, -32, 23, -1, -21, 14, 10, -7, -13, 21, -25, 16, -8, 1, + -1, -1, 13, -22, 12, 12, -28, 3, 13, 1, -15, -3, 38, -41, -5, 45, + -37, -9, 30, -4, -35, 42, -10, -25, 19, -4, 3, -18, 12, 22, -43, 25, + 14, -37, 21, 4, -19, 5, 17, -12, -17, 26, -4, -22, 11, 7, 6, -31, + 35, -15, -14, 22, -14, 0, 0, 14, -16, -12, 31, -17, -19, 25, -10, 0, + 2, 12, -23, 8, 16, -44, 37, 0, -19, -2, 21, -5, -25, 22, 12, -38, + 3, 37, -11, -38, 36, 11, -54, 40, -9, -11, 14, -11, 11, -19, 17, 17, + -47, 16, 25, -17, -23, 34, -3, -29, 25, -17, 5, 14, -17, 3, -4, 21, + -23, -11, 35, -31, 7, 13, -17, 13, -6, 6, -22, 13, 5, -8, -8, 16, + 8, -34, 18, 21, -49, 32, 12, -45, 32, 0, 1, -32, 27, 2, -20, 10, + 6, 3, -26, 18, 19, -50, 31, 13, -40, 20, 12, -7, -19, 21, -9, -12, + 24, -21, 6, 7, -6, -2, -9, 23, -19, -8, 15, -7, 18, -26, 13, 5, + -21, 21, -19, 4, 25, -26, -14, 32, -2, -33, 21, 8, -29, 38, -35, 17, + 8, -19, 15, -29, 24, 15, -40, 10, 28, -21, -26, 34, 7, -42, 35, -3, + -14, -1, 18, -6, -30, 29, -1, -11, 8, -8, 16, -22, -2, 25, -27, 14, + 0, -9, 1, 9, 1, -25, 22, -16, 12, 8, -33, 32, 2, -35, 19, 4, + 0, -17, 15, 1, -6, 9, -15, 16, -30, 25, 8, -46, 40, 11, -39, 8, + 11, 2, -21, 10, 11, -17, 15, -6, -4, -10, 18, -6, -23, 29, -2, -7, + -13, 9, 24, -48, 23, 17, -30, 27, -22, 9, 4, -16, 8, 4, -9, -2, + 19, -12, -12, 21, -22, 15, -8, -2, 20, -39, 32, -5, -16, 11, 5, -15, + -8, 30, -5, -36, 34, -5, -13, 1, 3, 22, -37, 14, 6, -8, 0, -6, + 11, -17, 23, -6, -18, 19, -7, -4, -14, 11, 17, -32, 24, -6, -2, 9, + -26, 30, -24, 2, 18, -19, 7, 4, -6, -3, -1, 3, 1, 0, -21, 39, + -20, -33, 51, -27, -6, 24, -18, 8, -10, 12, -3, -23, 25, -11, 5, -19, + 25, 2, -34, 29, -5, -9, -7, 18, -12, -18, 30, -4, -26, 20, -9, 22, + -32, 7, 26, -28, 6, -9, 19, -20, 5, 2, -9, 26, -15, -13, 18, -19, + 15, -3, -26, 34, 2, -33, 6, 36, -36, -12, 36, -32, 29, -24, 10, 13, + -39, 30, -6, -17, 12, 9, -9, -17, 28, -6, -27, 21, 4, -15, 6, 13, + -13, -16, 30, -21, 1, -4, 4, 28, -60, 46, -3, -21, 3, 5, -8, 17, + -17, 3, 11, -6, -9, 11, -8, -17, 44, -36, 0, 20, -9, -4, -13, 29, + -24, 5, -3, 6, 14, -36, 26, -3, -23, 30, -3, -30, 25, 3, -12, -22, + 42, -13, -27, 19, 9, -3, -20, 16, -7, -3, 7, -5, 6, -13, 22, -21, + -15, 39, -17, -21, 30, -23, 19, -6, -20, 31, -24, 0, 8, 12, -31, 20, + 8, -27, 20, -14, 20, -22, -2, 17, 0, -18, 11, 0, 7, -28, 22, -2, + -19, 31, -17, -8, -2, 28, -24, -16, 34, -4, -28, 9, 26, -12, -30, 29, + -7, -6, 10, -1, -10, 5, -3, 6, -23, 29, -18, 10, -16, 7, 28, -48, + 21, 4, -12, 9, 4, -12, 5, -1, -7, 2, 0, -3, 11, -15, -3, 26, + -19, -4, 3, 1, 10, -37, 49, -26, -9, 6, 18, -23, 0, 17, -3, -27, + 25, 3, -22, 10, 6, -3, -19, 32, -23, 9, -3, -3, 11, -31, 27, 12, + -42, 23, 13, -12, -18, 30, -10, -19, 13, -4, 0, 17, -25, 12, -2, -2, + 4, -8, 9, -12, 8, -17, 24, -2, -19, 14, -16, 18, -6, -12, 22, -12, + -17, 20, 0, -4, -13, 19, -5, -18, 30, -19, 8, -17, 19, -9, -6, 8, + 1, 1, -36, 48, -9, -40, 46, 1, -50, 44, -5, -14, -3, 10, 4, -17, + 11, -1, 11, -25, 9, 10, -24, 19, 2, -9, -4, 4, 10, -26, 20, -8, + 6, -3, -12, 17, 7, -31, 18, -14, 17, -7, 0, 2, -8, 9, -15, 19, + -16, 8, 2, -22, 21, 15, -33, 4, 24, -20, -13, 36, -18, -24, 33, -16, + -8, 20, -19, 22, -32, 21, 0, -5, -7, 18, -17, -11, 26, -5, -25, 25, + 3, -17, -3, 15, 7, -35, 22, -3, 2, -2, -6, 7, -3, -4, 4, -13, + 25, -17, 1, -4, 7, -12, 13, -2, -11, 12, 2, -25, 24, 0, -25, 17, + -4, 6, -9, 14, -11, -8, 5, 0, 10, -25, 23, 1, -28, 27, 5, -26, + 0, 23, -11, -20, 21, 10, -30, 12, 9, -5, -16, 25, -12, -19, 26, -3, + -12, 1, 9, -1, -15, 11, 3, -12, 6, -5, 11, -7, -8, 6, 3, -11, + 4, 5, 0, -11, 7, -1, 6, -17, 1, 26, -35, 14, 6, -6, -8, 15, + -7, -9, 13, -2, -20, 19, 6, -11, -14, 24, 7, -36, 19, 11, -24, 1, + 23, -18, -4, 18, -10, -19, 29, -10, -9, -1, 6, 10, -23, 10, 19, -32, + 11, 11, -4, -13, 5, 12, -17, 3, 13, -20, 11, 0, -8, 5, 14, -32, + 19, 1, -22, 28, -16, -8, 13, 3, 0, -11, -10, 38, -40, 3, 22, -9, + -16, 19, -4, -13, 13, 9, -29, 9, 16, -9, -20, 25, -2, -22, 11, 6, + 4, -22, 12, 16, -35, 15, 26, -42, 13, 12, -5, -20, 24, -4, -18, 20, + -7, -11, 9, 5, -7, 1, -2, -2, 10, -18, 9, 11, -17, -2, 7, -5, + 28, -48, 12, 31, -36, 12, 8, -2, -14, 8, 2, -5, -1, 11, -17, -4, + 21, -1, -27, 19, 3, -13, 0, 8, 15, -39, 19, 17, -43, 34, 4, -32, + 16, 8, -10, -8, 21, -10, -12, 6, 9, -4, -10, 3, 9, -13, 8, 2, + -7, 1, 1, 2, -18, 22, -10, 2, 5, -19, 19, -4, -11, 11, -5, 2, + -13, 7, 15, -24, 9, 11, -20, -2, 21, 1, -38, 21, 9, -2, -22, 23, + 6, -41, 34, -2, -19, 27, -10, -23, 20, -3, 13, -34, 20, 10, -15, -3, + 14, -1, -19, 3, 4, 5, 8, -14, 9, -18, 18, -1, -22, 24, -8, -8, + 10, -10, 14, -12, -4, 6, -14, 30, -38, 28, -5, -23, 19, 4, -10, -9, + 22, -7, -22, 17, 8, -5, -19, 25, -9, -23, 31, -6, -26, 31, -20, 18, + -29, 22, 20, -54, 33, -4, 1, -3, 4, -8, 0, -5, 13, -6, -6, 9, + -1, -24, 36, -9, -26, 30, -24, 11, 8, -23, 22, -16, 5, -11, 20, -2, + -26, 23, -9, -3, 0, 9, -10, -6, 13, -3, -17, 25, -12, -2, -8, 16, + 4, -35, 39, -14, -9, -2, 23, -6, -37, 40, -12, -11, 4, 8, 1, -13, + 1, 17, -26, 12, 10, -27, 17, 4, -6, -18, 42, -32, 2, 4, -16, 36, + -31, 0, 10, 0, -1, -12, 15, 0, -28, 22, -3, -1, 6, -6, -9, -3, + 25, -18, -8, 7, 6, 5, -39, 48, -16, -23, 22, -2, -8, 1, 18, -25, + -9, 25, 1, -28, 16, 9, 0, -34, 37, -4, -27, 27, -18, -1, 6, 4, + -5, -8, 16, -9, 10, -21, 6, 12, -14, -4, 6, 9, 3, -31, 33, -14, + -12, 23, -28, 25, -10, 2, -11, 1, 11, 6, -30, 3, 40, -21, -34, 46, + -12, -22, 11, 6, -2, -10, 14, -10, -21, 49, -29, -16, 17, 9, -15, -13, + 32, -19, 0, 0, 8, 0, -14, 8, -4, -16, 30, -17, 2, -1, 0, 9, + -15, 6, -4, 11, -15, -6, 28, -28, 17, -18, 7, 11, -19, 12, 3, -24, + 21, 3, -29, 15, 26, -25, -27, 51, -18, -19, 7, 20, -21, -11, 36, -32, + -3, 35, -27, -4, 6, 8, 2, -31, 18, 18, -29, 1, 25, -16, -8, 19, + -30, 13, 16, -20, 8, -12, 19, -3, -21, 15, 0, -6, -3, 4, 6, 1, + -20, 2, 20, -5, -27, 31, -7, -21, 19, 6, -19, -10, 40, -28, -17, 40, + -15, -22, 12, 13, -23, 6, 14, -12, -7, 10, 11, -11, -30, 45, -9, -44, + 48, -5, -14, -5, 20, -22, 9, 3, -10, 0, 4, 4, -7, -9, 24, -23, + 3, 8, -15, 15, -2, -19, 21, -8, -6, -1, 14, -7, -12, 18, -10, -3, + 3, 21, -37, 2, 29, -23, -7, 22, -10, -2, -7, 20, -10, -20, 15, 5, + -25, 17, 23, -29, -16, 50, -35, -9, 19, 4, -22, 2, 24, -19, -10, 25, + -9, -22, 23, 3, -15, -6, 10, -4, 13, -29, 17, 13, -26, -2, 25, -23, + 14, -16, 12, -2, -2, 4, -11, 1, 11, 0, -22, 14, 18, -28, -6, 11, + 22, -29, -10, 42, -30, -12, 26, -12, -15, 19, 15, -41, 10, 33, -16, -32, + 20, 29, -47, 10, 36, -35, -1, 20, -19, 1, 9, 5, -14, -16, 15, 29, + -38, -6, 35, -16, -20, 18, 6, -9, -7, 1, 4, 6, -4, 0, -9, 2, + 8, 2, -14, -4, 24, -12, -32, 41, -1, -26, 1, 23, -22, 4, 11, -10, + -6, 8, 16, -28, -12, 52, -28, -40, 53, 2, -29, 2, 17, -10, -5, -2, + 8, -1, -13, 25, -10, -33, 51, -16, -32, 12, 29, -27, -11, 25, 7, -27, + 4, 12, 0, -15, 5, -2, 4, -11, 11, 21, -51, 15, 37, -46, 7, 24, + -9, -20, 2, 27, -11, -17, 4, 22, -40, 26, 16, -36, 2, 35, -32, -2, + 12, 14, -23, -17, 26, 10, -26, 3, 20, -20, -9, 28, -16, -9, 19, -4, + -21, 15, 12, -17, -15, 24, -7, -6, 5, -2, 10, -21, 4, 12, -9, -11, + 30, -12, -32, 38, 3, -33, 11, 11, 0, -24, 4, 44, -37, -18, 36, -8, + -25, 21, 5, -24, 10, -1, 18, -22, -2, 30, -38, -8, 41, -24, -3, 4, + 8, -6, -11, 20, -11, -20, 22, -2, 2, -8, 8, -12, 8, -17, 11, 18, + -34, 19, -4, 5, -3, -9, 5, -6, 6, -4, -6, 17, -5, -11, 2, 12, + -8, -16, 15, 3, -21, 13, 8, -7, -8, 12, -5, -5, -17, 33, -1, -44, + 35, 15, -42, 18, 15, -21, 4, -4, 10, -5, -14, 27, -21, -7, 19, 1, + -3, -8, -6, 9, -1, -23, 29, -13, -1, -2, 4, 8, -6, -20, 26, -22, + 5, 21, -25, 9, 3, -11, 16, -12, -4, 20, -20, -8, 25, -13, -5, 6, + -11, 13, 6, -30, 13, 24, -31, -11, 27, 9, -43, 28, 2, -3, -5, -4, + 13, -16, -1, 10, -8, -4, 11, 8, -23, 14, 0, -4, -10, 1, 14, -14, + 3, 2, -3, 20, -35, 26, -6, -25, 38, -32, 12, -10, 16, -10, 14, -24, + 9, 33, -83, 72, -13, -27, 28, -26, 25, -13, 8, -25, 18, 15, -29, 17, + -3, 9, -25, 2, 19, -20, 18, -20, 13, 4, -18, 32, -32, -10, 35, -18, + -12, 16, 10, -15, -5, 4, 13, -21, 1, 0, 14, -18, 9, 12, -26, 27, + -27, 9, 1, -4, -1, 1, 14, -33, 52, -49, -1, 46, -50, 21, -5, 12, + -9, -7, 6, 1, -2, -10, 14, -2, -10, 13, -19, 23, -26, 18, -2, -22, + 34, -30, 8, 20, -38, 14, 18, -18, -5, 9, 3, -6, -13, 24, -1, -28, + 12, 11, -14, -1, 21, -37, 31, -16, 5, 6, -26, 32, -23, 4, 2, 9, + 2, -40, 40, -7, -10, 2, 0, 9, -16, -1, 16, -3, -10, -3, 19, -22, + 6, 7, -9, -4, -10, 39, -38, 5, 27, -28, 0, 13, -8, 1, -3, 5, + -3, -9, 13, -8, -4, 13, -14, -6, 22, -14, -13, 31, -30, 22, -15, -15, + 55, -56, 6, 26, -23, 8, 1, 4, -17, 8, 6, -9, 9, -11, 15, -18, + 5, 14, -18, 9, -22, 26, -2, -23, 25, -11, 1, -16, 15, 12, -28, -4, + 35, -31, -3, 28, -8, -12, -8, 26, -21, -1, 3, -2, 12, -18, 18, -3, + -6, -9, 14, -23, 9, 36, -57, 29, 21, -50, 29, -2, -13, 7, 0, -5, + 6, -1, -4, 10, -25, 23, -3, -19, 28, -20, 11, -17, -5, 37, -39, 19, + -7, 1, 7, -17, 12, 14, -36, 6, 23, -23, 9, 12, -19, 4, 2, 2, + 6, -27, 14, 17, -39, 14, 34, -22, -31, 34, 6, -36, 28, -1, -28, 24, + 1, -18, 24, -20, 9, -2, -15, 21, -4, -23, 23, -10, -4, 15, -12, 3, + -6, 2, 10, -28, 28, -6, -15, 14, -14, 10, 1, -18, 14, 5, -19, 15, + 2, -18, 22, -17, -7, 29, -43, 45, -15, -40, 62, -27, -23, 23, 10, -20, + -20, 41, -7, -20, 9, 10, -22, 8, 5, 9, -21, 0, 22, -11, -18, 27, + -4, -34, 30, 3, -9, -2, 1, 4, -13, 6, 16, -25, 11, -11, 8, 1, + -11, 14, -4, -6, 4, 1, -2, -7, 1, -3, 11, -31, 57, -36, -10, 37, + -44, 22, -2, -10, 4, -1, 7, -2, -7, 7, 14, -33, 5, 24, -29, 7, + 10, -1, -13, 0, 26, -23, -16, 43, -32, -14, 23, 11, -23, -5, 13, 13, + -44, 44, -7, -18, 7, -7, 12, -12, -1, -1, 7, 0, -6, 26, -37, 17, + -6, 4, -19, 18, 13, -37, 24, 4, -7, 0, -13, 15, 3, -28, 22, 14, + -41, 27, 5, -28, 38, -30, 9, -6, -1, 18, -28, 8, 26, -36, 4, 21, + -3, -30, 28, -6, 1, -26, 45, -28, -15, 34, -15, -12, 6, 8, 1, -9, + -16, 26, 1, -50, 65, -34, -12, 25, -9, 4, -14, 21, -17, -2, -6, 10, + 17, -29, -6, 40, -23, -20, 27, 0, -40, 44, -27, 16, -6, 2, 3, -20, + 15, 15, -32, -1, 28, -9, -29, 38, -22, 14, -21, 16, -5, -6, 17, -35, + 20, 13, -19, 0, 2, 2, 16, -32, 0, 47, -61, 16, 31, -37, 21, -8, + 6, -7, 3, -6, 8, -9, -12, 29, -13, -20, 33, -16, 0, -21, 46, -39, + 2, 17, -3, -11, -6, 18, 2, -35, 29, 17, -37, 0, 42, -42, 9, -3, + 16, -19, -2, 24, -17, -2, 0, -1, 6, -12, 19, -12, -16, 27, -2, -27, + 16, 17, -42, 38, -22, 8, 2, -12, -1, 15, -18, 13, -6, -11, 7, 21, + -36, 26, -23, 38, -48, 15, 26, -20, -18, 24, -1, -4, -20, 34, -16, -17, + 18, 11, -30, 15, 7, -10, -10, 12, 15, -31, -1, 28, -6, -32, 30, 4, + -24, 1, 28, -28, 7, -11, 33, -39, 23, -15, 19, -12, -12, 11, 4, -25, + 33, -22, 14, -4, -3, -6, 10, -21, 31, -40, 19, 13, -10, -1, 14, -18, + -3, 10, -4, -5, -2, 10, -6, -14, 21, 14, -40, 15, 6, 3, -31, 28, + 12, -42, 11, 43, -44, 2, 27, -17, -18, 22, -16, 33, -59, 37, 15, -35, + 11, 20, -22, 1, -7, 22, -22, 7, -1, 9, -16, -4, 20, 3, -38, 31, + 9, -31, -3, 39, -34, 8, 4, -19, 41, -41, 11, 21, -40, 19, 18, -47, + 45, -14, -5, -13, 26, -4, -28, 19, 15, -45, 38, -4, -9, -4, 17, -29, + 28, -27, 34, -25, -20, 39, 5, -52, 49, -15, -13, 5, -3, 14, -2, -20, + 17, -3, -12, 18, -7, -9, 1, 10, 7, -31, 19, 13, -29, 12, -22, 52, + -30, -28, 40, 7, -60, 56, -19, -5, -5, 22, -26, 13, 1, 5, -28, 30, + -12, 3, -17, 25, -26, 16, -16, 20, -5, -14, 26, -19, -33, 67, -47, 2, + 20, -19, 21, -22, 12, 12, -25, 0, 17, -26, 24, -4, -15, 6, 9, -8, + 13, -28, 24, -15, 13, -27, 26, 3, -11, -31, 61, -31, -19, 24, 5, -33, + 22, -3, 14, -35, 22, 10, -28, 8, 23, -24, -2, 1, 18, -18, -8, 26, + -15, -12, 26, -31, 15, 10, -24, 18, -19, 35, -32, -1, 15, 7, -40, 36, + -14, -4, 16, -12, -22, 51, -54, 41, -31, 14, 4, -17, 5, 13, -24, 29, + -31, 12, 25, -34, -2, 30, -36, 21, -16, 22, -4, -36, 42, -11, -6, -12, + 31, -16, -29, 34, 6, -29, -4, 37, -23, -25, 51, -34, 9, -11, 23, -25, + 14, -8, 5, -20, 32, -22, 6, 14, -16, -3, 24, -49, 51, -46, 31, -4, + -21, 26, -13, 0, 7, -9, -2, -1, 8, -21, 22, -21, 29, -29, 10, 22, + -41, 37, -24, -7, 15, 3, -25, 26, 1, -15, 5, 2, 14, -33, -3, 54, + -69, 27, 13, 5, -37, 27, 4, -6, -19, 19, -3, -9, 2, 10, -11, 15, + -30, 38, -35, 20, 0, -29, 37, -16, 1, -14, 21, -12, -7, 22, -33, 30, + -19, 4, -7, -1, 31, -57, 46, -15, -8, 20, -21, -1, 18, -21, 17, -12, + 6, 7, -20, 2, 32, -57, 46, -7, -25, 12, 25, -32, -3, 18, 1, -12, + -15, 31, 4, -56, 52, -11, -6, -20, 23, 19, -50, 37, -7, -9, -1, 14, + -22, 10, 14, -36, 37, -18, -8, 25, -31, 20, -16, 21, -26, 10, 7, -15, + 9, 3, -14, 19, -25, 24, -15, -4, -4, 27, -37, 21, 7, -12, 1, -5, + 4, 5, -12, -4, 10, -12, 17, -10, -16, 52, -56, 5, 29, -12, -5, -28, + 56, -30, -19, 34, -3, -30, 20, 4, -21, 12, 9, -17, 21, -35, 43, -19, + -20, 21, -4, -13, 12, -10, 9, 0, -6, -4, 10, -19, 25, -23, 6, -3, + 10, -5, -15, 31, -12, -14, -4, 22, -15, -5, 1, 17, -17, -8, 28, -15, + -8, 6, -10, 2, 7, 8, -31, 25, 3, -20, -2, 26, -10, -22, 12, 20, + -25, 6, -11, 33, -36, -2, 43, -36, -8, 20, -9, -7, 2, 4, 5, -7, + -5, 24, -28, 11, 6, -24, 20, -7, -2, 6, -9, -1, 20, -35, 13, 27, + -31, -7, 31, -13, -12, -6, 27, -14, -24, 33, -6, -10, 15, -14, 6, -13, + 9, 0, -8, -1, 19, -20, 6, 10, -9, -15, 23, -20, -4, 31, -24, 2, + -13, 23, 1, -25, 14, 12, -16, -18, 25, 4, -25, 15, -3, 2, 6, -16, + 21, -12, -19, 19, 1, -18, 21, 1, -30, 25, 3, -15, -5, 6, 18, -34, + 4, 32, -13, -18, 1, 28, -21, -30, 44, -1, -41, 28, 16, -32, 9, 14, + -17, 6, -11, 5, 21, -43, 38, -11, -24, 39, -15, -18, 18, -3, -15, 0, + 20, -15, 2, -1, -6, 32, -43, 13, 19, -26, -3, 17, 10, -29, 19, 1, + -19, 22, -13, 7, -16, 10, 8, -17, -1, 12, 1, -18, 1, 40, -49, 6, + 34, -35, -8, 30, -2, -23, 4, 15, 12, -39, 2, 55, -57, -8, 47, -27, + -7, 18, -7, 2, -11, 0, 19, -21, 4, 2, 10, -32, 34, -16, -12, 20, + -12, 2, -4, 20, -12, -22, 22, -14, 9, -12, 6, 21, -24, -7, 27, -13, + -22, 13, 16, -38, 37, -2, -21, 19, -14, 2, -6, 6, 7, -16, -11, 44, + -22, -35, 52, -10, -41, 24, 16, -13, -19, 14, 21, -20, -29, 55, -20, -21, + 5, 28, -30, -3, 22, -6, -10, 5, 11, -11, -7, 15, -11, -4, -10, 18, + 1, -23, 24, 3, -24, 10, 5, 0, -32, 35, -7, -12, 1, 11, 18, -53, + 36, 7, -26, 0, 24, -27, 0, 26, -24, 6, 6, -13, 16, -21, 13, 1, + -25, 20, 26, -61, 40, 21, -41, -6, 28, 1, -24, -7, 38, -14, -25, 20, + 5, -16, -1, 6, 13, -20, -7, 39, -33, -8, 25, -14, 5, -20, 26, 2, + -28, 14, 14, -18, -23, 64, -60, 11, 24, -9, -13, -2, 17, -5, -25, 16, + 22, -13, -44, 61, -14, -38, 35, -7, -18, 28, -16, -10, 25, -9, -20, 8, + 6, 8, -23, 11, 19, -27, -1, 15, 0, -25, 18, 8, 2, -34, 38, 1, + -41, 23, -7, 13, -6, -19, 45, -20, -27, 24, 14, -61, 53, -13, -13, 21, + -21, 36, -25, -33, 58, -33, -26, 35, 19, -50, 7, 50, -35, -20, 28, 5, + -29, -1, 28, -20, 3, -10, 20, -8, -16, 35, -22, -13, 17, -10, -3, 15, + -25, 24, -7, 0, -8, -3, 29, -32, -7, 30, -16, 9, -29, 24, 10, -27, + -9, 49, -40, 4, 14, -28, 37, -29, -18, 68, -67, 12, 45, -48, 3, 31, + -21, -16, 9, 20, -3, -40, 38, 17, -65, 41, 8, -15, -9, -2, 46, -51, + -7, 64, -51, -31, 57, -21, 5, -10, -7, 35, -36, 0, 20, -20, 14, -16, + 10, 9, -1, -26, 26, -18, -3, 5, 14, -8, -17, 32, -25, 1, 17, -29, + 17, 17, -47, 50, -19, -12, 9, -1, -11, 17, -29, 44, -25, -36, 63, -32, + -18, 29, -7, 9, -38, 32, 14, -50, 21, 37, -57, 13, 37, -17, -16, -9, + 28, -6, -60, 76, -13, -34, 29, 1, -5, 9, -41, 35, -2, -48, 52, -5, + -3, -17, 14, 5, -12, -13, 24, -20, 7, -4, 10, 2, -13, 10, -2, -18, + 20, 2, -33, 37, -18, -9, 25, -21, 14, -15, 9, -2, -14, 15, 10, -44, + 37, 7, -36, 15, 18, -9, -21, 2, 45, -53, 3, 47, -48, 3, 25, -17, + 14, -24, -2, 53, -72, 22, 38, -32, -13, 22, -15, 30, -36, 6, 27, -30, + -4, 21, -3, -20, 8, 13, -3, -29, 43, -10, -41, 33, -14, 20, -22, 9, + 13, -14, -10, 25, -30, 14, 6, -29, 29, 2, -23, 4, 14, -15, -3, 13, + 11, -29, 21, -1, -25, 13, 5, 1, -9, -18, 58, -31, -44, 56, 7, -69, + 46, -10, 11, -3, -27, 41, 1, -58, 46, 7, -33, 14, -14, 30, -22, -24, + 77, -66, 6, 6, 27, -36, -2, 21, 10, -62, 57, 11, -46, 23, 7, -8, + -18, 24, -21, 17, -35, 40, -4, -31, 36, -13, -10, 0, -2, 2, 0, 2, + -14, 18, 22, -53, 11, 43, -45, -13, 39, -7, -12, -6, 22, -8, -27, 19, + 15, -35, 13, 21, -30, 26, -35, 40, -17, -11, -5, 33, -25, -4, -9, 32, + -10, -44, 65, -23, -18, 0, 28, -31, 17, -23, 45, -50, 11, 52, -68, 13, + 23, -10, -32, 41, -13, 4, -13, 5, 9, -11, 4, -8, 6, 12, -25, 4, + 24, -20, -15, 11, 30, -42, 5, 30, -7, -40, 27, 17, -27, -5, 14, 16, + -26, -9, 39, -23, -11, 17, -16, 30, -52, 43, -9, -4, -28, 31, 4, -15, + -15, 34, 6, -69, 65, -3, -40, 6, 42, -40, 8, 11, 18, -29, -28, 62, + -40, -17, 31, 2, -22, 20, -13, 16, -18, 0, -6, 12, -4, -10, 17, 0, + -6, -25, 44, -25, -6, 0, 24, -13, -33, 43, 1, -46, 36, 3, 0, -34, + 38, -11, -14, 5, -11, 30, -19, 3, -12, 45, -56, -3, 41, -20, -21, 17, + 22, -18, -15, 14, 37, -92, 53, 25, -48, -2, 57, -44, -4, 3, 35, -31, + -32, 59, -24, -17, 9, 28, -39, 22, -10, 9, -7, 0, 7, -29, 33, -16, + -17, 37, -24, -17, 43, -14, -28, 18, 18, -33, 5, 4, 21, -34, 13, 4, + -6, 7, -15, 14, -8, 11, -17, -1, 15, 0, -42, 58, -18, -35, 37, 14, + -47, 9, 27, -14, -33, 20, 58, -79, 11, 49, -18, -55, 58, -6, -29, 6, + 12, 16, -55, 61, -29, -20, 37, -15, -1, 9, -26, 22, 3, -25, 0, 31, + -18, -1, -12, 40, -11, -64, 62, -11, -23, 3, 32, -11, -18, 19, 5, -36, + 15, 11, -21, 6, 18, -16, 5, 16, -35, 14, -2, 19, -53, 45, 31, -81, + 31, 46, -51, -14, 44, -13, -23, -11, 67, -62, -3, 50, -23, -26, 24, 16, + -34, -2, 3, 27, -33, 1, 38, -35, 13, 0, -24, 50, -59, 11, 31, -20, + -6, 10, 20, -28, -15, 38, -2, -60, 43, 32, -68, 24, 47, -54, 9, 3, + 23, -46, 11, 36, -56, 34, -2, -20, 12, 24, -36, 9, 7, 18, -45, 11, + 45, -50, -10, 42, 4, -63, 62, -10, -22, -9, 26, 8, -52, 41, 14, -54, + 41, -9, -8, 12, -26, 33, -25, 6, 3, -14, 20, -28, -2, 50, -23, -51, + 64, 11, -86, 57, 17, -39, -5, 19, 41, -79, 33, 43, -64, 2, 40, -21, + -7, -6, 38, -37, -8, 43, -39, 5, 16, 3, -49, 67, -38, -20, 39, -20, + 10, -24, 43, -15, -47, 57, -13, -53, 59, -16, 8, -27, 35, -4, -36, 35, + -29, 13, -5, 5, -13, 32, -5, -48, 57, -29, -15, 30, -26, 23, -34, 33, + 25, -79, 54, 25, -70, 16, 33, -1, -60, 37, 52, -76, 7, 54, -22, -61, + 76, -23, -30, 30, -15, 14, -21, 24, -4, -20, 23, 0, -49, 63, -31, -12, + 28, -15, 9, -17, 26, -25, -1, 4, 15, -31, 22, 8, -23, 18, -8, -7, + 6, -1, 7, -12, -1, 32, -62, 42, 14, -59, 41, 13, -31, -5, 40, -14, + -49, 36, 38, -64, 1, 68, -54, -29, 61, -16, -29, 8, 37, -22, -33, 42, + 18, -75, 47, 6, -25, 26, -33, 42, -32, 1, 4, 3, -2, 5, -20, 27, + 4, -43, 33, 2, -27, 6, 26, -25, 8, 2, 19, -46, 26, 15, -56, 44, + 12, -34, -4, 43, -34, -1, 2, 27, -40, -3, 52, -64, 26, 21, -30, -3, + 30, 1, -37, 13, 27, -28, -31, 49, 4, -63, 61, 2, -23, -10, 22, 7, + -53, 17, 43, -51, 21, 15, -26, 37, -31, -4, 9, 0, -28, 28, 4, -10, + -5, 21, 2, -40, 32, 9, -50, 20, 43, -63, 32, -6, 13, -24, -4, 62, + -87, 46, 12, -27, -14, 25, 13, -44, 25, 24, -29, -8, 13, 18, -56, 46, + 6, -51, 55, -19, -10, -4, 17, 3, -52, 60, -3, -49, 41, -14, 0, -4, + -3, 17, -9, -9, 1, 18, -11, -17, 3, 17, -5, -23, 15, 42, -83, 51, + -1, -17, 6, -16, 57, -83, 48, 16, -46, 10, 24, -8, -32, 32, 15, -49, + 26, 19, -24, -22, 40, 20, -80, 64, -11, -24, 14, -11, 17, -18, 18, -5, + -21, 45, -36, -11, 24, -16, 5, -10, 32, -13, -17, 24, -15, -4, -8, 9, + 0, -16, 33, -36, 36, -7, -39, 46, -35, 33, -61, 51, 10, -63, 50, 11, + -34, -5, 39, -8, -46, 41, 6, -45, 22, 14, -4, -41, 74, -33, -44, 57, + -19, -20, -12, 42, -4, -37, 30, 18, -31, 0, -1, 10, -16, 3, 8, 1, + 9, -31, 21, -2, -11, -1, 3, 24, -40, 15, 31, -52, 20, -1, 13, -32, + 31, 6, -44, 41, -17, -18, 21, 18, -32, -10, 41, -2, -60, 42, 9, -25, + -9, 38, -10, -29, 40, -27, -7, 14, 8, -20, -2, 26, -11, -35, 42, -2, + -36, 28, -1, 3, -33, 39, -7, -24, 9, 4, 4, -10, 7, -2, 0, 15, + -52, 45, 4, -38, 14, 29, -20, -23, 39, -1, -38, 13, 23, -26, -1, 12, + 2, -30, 41, -10, -30, 36, -3, -22, -6, 35, -20, -32, 27, 22, -41, 19, + 23, -18, -18, 22, -5, -34, 39, -19, 5, -3, 29, -26, -21, 47, -38, -23, + 38, -4, -15, 6, 19, -12, -4, 6, -14, 17, -14, -11, 22, 3, -20, -13, + 38, -2, -52, 43, 16, -30, -19, 37, 1, -51, 47, 2, -23, -1, 22, -10, + -24, 17, 21, -62, 51, 11, -38, 19, 8, -3, -50, 61, -18, -15, 4, 16, + -9, -15, 29, -32, -2, 37, -43, 9, 35, -36, 13, -16, 28, -28, -5, 41, + -35, -3, 12, 15, -29, 2, 19, -20, 19, -21, 7, 18, -20, 1, -24, 47, + -17, -45, 54, 10, -43, 0, 37, -3, -63, 58, 4, -55, 43, -2, -6, -31, + 50, -35, -10, 37, -12, -17, 1, 29, -34, -5, 31, -19, -10, 29, -26, 32, + -44, 25, -5, -27, 43, -45, 33, 12, -29, -6, 38, -18, -34, 23, 18, -21, + -12, 17, 27, -52, 18, 32, -49, 42, -19, -24, 40, -26, -7, 0, 32, -12, + -44, 69, -18, -46, 21, 26, -41, -5, 49, -24, -8, 22, 0, -23, -17, 32, + -6, -42, 64, -40, 17, 0, 3, -11, -28, 63, -61, 13, 26, -12, -7, 4, + -5, 8, -2, -5, -14, 18, 13, -38, 6, 36, -7, -71, 86, -10, -56, 45, + -11, -2, -18, 9, 26, -38, 24, 1, -24, 41, -35, -10, 24, -1, -24, 10, + 25, -15, -20, 10, 36, -44, -32, 96, -69, -8, 44, -32, 12, -20, 33, -33, + 11, 24, -24, -15, 40, -23, -27, 20, 18, -19, -4, 28, -23, 9, -9, 4, + -19, 32, -27, -15, 59, -37, -17, 28, 2, -20, -12, 28, 20, -68, 46, 2, + -24, 3, 6, 16, -28, 17, 8, -21, 1, 6, -21, 15, 34, -68, 43, 41, + -81, 31, 10, -5, -28, 1, 51, -37, -21, 64, -40, -23, 44, -25, -12, 15, + 7, -21, 14, 0, 6, -29, 29, 7, -39, 30, -10, 0, -4, -5, 13, 8, + -24, 23, -28, 38, -27, -34, 50, -5, -33, 10, 55, -47, -22, 43, -3, -45, + 11, 38, -37, 15, 16, -25, 24, -22, -4, 0, 4, 14, -41, 33, 35, -67, + 13, 52, -57, 0, 25, -4, -7, -11, 18, 5, -37, 32, 2, -39, 54, -24, + -18, 13, 16, -27, -2, 7, 31, -52, 29, 17, -41, 38, -23, -15, 28, -4, + -28, 40, -13, -20, 8, 13, 0, -40, 37, 20, -53, 14, 39, -34, -21, 27, + 14, -28, 12, 14, -23, 7, 3, -28, 24, 6, -23, 10, 9, 20, -39, -12, + 61, -39, -44, 74, -24, -25, 21, 13, -31, 10, 11, -3, -21, 19, 7, -43, + 46, -26, -2, 22, -16, 0, 13, -16, 10, -9, -20, 33, -30, 29, -2, -29, + 44, -8, -62, 54, 13, -50, 8, 34, 7, -43, 9, 41, -34, -39, 54, -6, + -28, 9, 20, -16, -6, 25, -30, -6, 45, -51, 4, 36, -21, -22, 28, 4, + -25, 18, 6, -5, -33, 37, -9, -19, 14, 8, -5, -4, 5, -1, -13, 0, + 16, -46, 49, -5, -25, 30, -8, -16, 15, -17, -4, 24, -26, 14, -8, 16, + 3, -40, 16, 47, -78, 21, 65, -53, -20, 24, 26, -55, 6, 55, -47, -6, + 35, -4, -28, 14, 1, -19, 15, -9, 20, -22, 19, -6, -31, 32, 7, -36, + 14, 20, -18, -7, 9, 9, -27, 22, -15, 8, 9, -15, 2, -2, 9, -19, + 11, 5, 11, -38, 38, -4, -35, 23, 17, -48, 34, 15, -51, 41, -2, -11, + -30, 35, 20, -65, 33, 34, -37, -23, 48, -2, -48, 21, 19, -12, -34, 42, + 8, -49, 33, 10, -27, 25, -15, -6, 9, -11, 7, -14, 22, -7, -11, 18, + 4, -18, -12, 30, -40, 14, 16, -11, -2, 30, -36, 4, 20, -19, -25, 21, + 17, -39, 38, -11, 13, -32, 19, 13, -49, 41, -2, -25, 8, 24, -23, -16, + 41, -9, -44, 34, 28, -48, -15, 59, -22, -54, 64, -6, -10, -20, 29, 4, + -56, 42, 7, -31, 20, 0, -5, 9, -3, -27, 33, -15, -18, 25, 5, -21, + 10, -6, -4, 1, 5, 14, -42, 47, -10, -14, -15, 30, -6, -53, 64, -4, + -33, 13, 27, -34, -16, 37, -4, -42, 38, 11, -35, 11, 17, -10, -33, 55, + -35, -6, 14, 20, -35, -11, 63, -52, -17, 55, -22, -23, 19, -2, 0, -5, + -10, 21, -5, -14, 12, 1, -10, 6, -15, 11, 13, -37, 43, -14, -17, 11, + 10, -13, -28, 43, -15, -25, 35, 11, -45, 20, 25, -34, -21, 51, -16, -42, + 35, 18, -23, -32, 75, -47, -18, 34, -1, -28, 1, 34, -40, 16, 23, -26, + 4, 18, -22, -4, -7, 18, -8, -25, 41, 0, -24, 13, 9, -30, 14, -4, + -14, 30, -18, 5, 9, -12, -3, -8, 25, -22, -18, 50, -18, -43, 48, 0, + -39, 11, 27, -14, -26, 42, -10, -33, 4, 61, -72, 7, 58, -40, -22, 28, + 24, -62, 19, 31, -22, -23, 41, -13, -16, 5, 11, -13, -4, 23, -21, 4, + 7, -8, -20, 33, -19, -10, 26, -7, -13, 2, 18, -21, -10, 28, -20, -15, + 54, -36, -26, 56, -30, -32, 42, -5, -21, 1, 40, -26, -19, 29, 7, -59, + 34, 24, -43, 20, 3, 12, -36, 23, 23, -48, -1, 61, -49, -25, 62, -27, + -23, 19, 13, -17, 4, 0, 9, -29, 19, -5, -7, 13, -9, 17, -7, 0, + -14, 11, -5, -17, 2, 35, -29, -10, 45, -27, -21, 31, -9, -17, 12, 5, + -10, -12, 26, 0, -37, 34, 6, -36, 18, 8, -2, -42, 39, 16, -47, 25, + 37, -57, 1, 51, -59, 13, 19, -10, -10, 11, 11, -8, -32, 42, -19, -36, + 59, -26, 1, -7, 17, -14, -2, -1, -2, 5, -5, 4, 0, 15, -25, -3, + 30, -28, -15, 36, -13, -5, -13, 26, 2, -45, 41, 2, -38, 21, 20, -29, + -11, 46, -27, -35, 46, 3, -38, 20, 25, -48, 19, 18, -26, 5, 3, 10, + -17, -13, 46, -29, -27, 52, -40, 18, -6, 9, -14, -8, 21, -11, -11, 16, + 14, -42, 33, 5, -31, 14, 0, -14, 19, -9, 11, -5, 2, 2, -39, 58, + -35, -26, 47, -1, -40, 19, 32, -36, -14, 37, -2, -40, 18, 32, -47, -6, + 49, -34, -7, 36, -16, -15, 2, 22, -36, -5, 53, -56, 27, 6, 2, -13, + -8, 28, -40, 4, 22, -2, -33, 46, -14, -36, 51, -10, -47, 40, -2, -18, + 3, 11, 13, -50, 57, -33, -5, 30, -31, -4, 19, -3, -17, 20, -2, -8, + -16, 34, -6, -45, 30, 35, -73, 21, 55, -52, 3, 11, 19, -42, -2, 55, + -57, 13, 23, -11, -16, 12, 16, -45, 25, 9, -22, -2, 37, -23, -29, 49, + -24, -27, 46, -23, -8, 22, -14, 6, -26, 45, -42, -9, 41, -15, -12, 11, + 13, -25, -1, 10, 9, -42, 37, -2, -20, 17, 14, -41, 25, 17, -52, 45, + -14, 1, -23, 21, 30, -74, 44, 35, -53, -4, 42, -18, -36, 30, 9, -26, + 17, 15, -18, -12, 37, -32, -25, 48, -27, -6, 20, -8, 12, -32, 38, -22, + -17, 36, -18, -13, 15, 7, -22, 14, -3, 5, -21, 33, -18, -18, 17, 12, + -31, 10, 34, -51, 33, -12, 15, -23, 1, 19, -50, 51, -7, -41, 47, 11, + -56, 20, 30, -23, -34, 37, 17, -29, -14, 54, -25, -45, 50, -16, -17, 11, + 14, -2, -30, 44, -16, -32, 39, -18, -16, 26, -5, -22, 25, -7, 1, -18, + 27, -8, -21, 23, 0, -30, 16, 27, -54, 46, -1, -24, -9, 28, 8, -62, + 48, 6, -31, 13, 17, -25, 17, -16, -1, 9, 2, 0, -15, 12, 19, -42, + -2, 57, -56, -2, 47, -11, -40, 21, 38, -56, -22, 71, -26, -41, 52, 3, + -29, 14, -1, -7, -20, 29, -3, -34, 41, -1, -35, 26, 12, -38, 25, -6, + -4, 7, -9, 6, -14, 31, -24, -7, 24, 3, -47, 33, 9, -28, -7, 23, + 18, -44, 22, 29, -48, 1, 46, -52, 14, 21, -21, -9, 26, 3, -41, 20, + 34, -52, -14, 75, -39, -40, 53, 0, -35, 6, 29, -15, -36, 44, 0, -39, + 36, -15, -11, 25, -9, -8, 6, 0, 1, -30, 29, -1, -17, 12, 20, -34, + 17, 4, -35, 29, -4, -10, -8, 35, 0, -45, 34, 18, -77, 45, 22, -29, + -9, 24, 14, -50, 29, 15, -34, -1, 47, -52, 3, 58, -54, -12, 40, -7, + -28, 10, 33, -22, -50, 79, -24, -38, 25, 10, -5, -30, 27, 16, -42, 15, + 14, -19, 11, 6, -33, 35, 2, -46, 49, -20, -7, 13, -4, 0, -12, 14, + 3, -50, 58, -8, -44, 40, 17, -22, -41, 60, -13, -48, 25, 50, -62, -3, + 71, -55, -12, 23, 3, -20, -1, 13, 20, -50, 48, -27, -23, 57, -43, -5, + 8, 30, -34, -16, 51, -18, -42, 35, 19, -40, 23, 0, -35, 39, -23, 0, + 21, -24, 16, -6, 2, 14, -53, 43, 1, -46, 51, -2, -19, 3, 25, -32, + -11, 24, -1, -34, 25, 42, -74, 29, 42, -41, -34, 56, -3, -32, -26, 84, + -35, -72, 101, -39, -13, 5, 24, -31, -2, 21, -25, 2, 22, 0, -37, 43, + 2, -41, 23, -6, -9, 9, -7, 24, -19, -8, 24, -33, 31, -11, -37, 57, + -25, -22, 35, -2, -29, 2, 26, -1, -39, 20, 51, -72, 14, 45, -45, -17, + 49, -30, -12, 24, 25, -48, -23, 107, -96, -10, 61, -7, -47, 22, 34, -35, + -13, 21, 17, -55, 40, 12, -43, 23, 6, -21, 19, -10, -4, 10, 3, -2, + -35, 38, -7, -29, 31, 1, -15, 15, -11, 5, -8, -3, 10, -30, 40, 10, + -62, 43, 30, -80, 22, 59, -63, -6, 42, 4, -35, -2, 67, -87, 21, 44, + -44, -6, 34, -6, -39, 26, 28, -26, -47, 87, -25, -74, 69, 15, -63, 22, + 19, 3, -13, -14, 36, -30, 1, 5, -9, 9, 3, -14, 29, -9, -25, 14, + 6, -6, -38, 54, -12, -38, 46, 14, -70, 48, 19, -68, 37, 25, -27, -25, + 29, 39, -81, 27, 50, -53, -12, 44, -4, -46, 23, 27, -32, -24, 67, -34, + -36, 65, -33, -31, 52, -22, -23, 21, 8, 18, -61, 46, 14, -59, 26, 31, + -49, 24, 11, -27, 30, -29, 8, -7, 20, -20, -4, 11, 0, -1, 0, -1, + 0, -1, 1, -2, 2, -1, -4, -2, 1, 19, -2, -20, 3, -10, -11, 12, + 3, -10, -3, 25, -4, 1, 6, 4, -12, 10, 2, -4, -28, -11, 9, 2, + 1, 18, -9, -20, 12, 11, 10, 1, -5, 5, -15, 4, 7, -27, -3, 4, + -8, 38, -31, -15, 7, 13, -34, 37, -6, -19, -6, 20, 41, -31, -20, 28, + -13, 30, -4, 0, -23, -1, 0, -13, 21, 3, -32, 19, 30, -52, 18, -24, + -27, 31, -14, 4, 1, -16, 14, 12, -20, 32, 14, -41, 37, -6, -5, 1, + 27, -34, 42, 9, 2, -34, 20, -25, 11, 15, -10, -14, -19, -24, 5, -12, + 3, -17, 2, 46, -13, -15, 31, -23, -16, 21, 25, -6, -36, 10, 1, 26, + -18, -12, 1, 21, -8, 17, -16, -29, -39, 17, -5, -1, -4, -6, -18, 33, + -21, 24, -17, 31, 0, 4, 0, 6, -26, 18, 24, 46, 5, 19, -10, 11, + 25, -13, 10, 50, -50, -52, 21, -23, -29, -8, 34, -35, -39, 15, -16, -43, + -5, -29, 29, -1, -8, -30, 18, 5, -14, 52, 12, -4, -28, 19, 25, 25, + 16, -44, 53, -20, 49, -23, 25, -32, 1, -63, 50, 37, -52, -13, 13, 4, + -18, 22, -56, 7, 23, -46, -7, 39, -69, -15, 26, 28, 21, 9, -64, 55, + 23, -34, 46, -26, -9, 36, -31, 4, 5, 37, -58, 28, 49, -25, 20, -1, + -12, -25, -6, 12, 9, -23, -34, 0, -2, 14, 3, -4, -13, 25, 23, -11, + 1, -34, 6, 9, 30, -36, -19, 11, -16, 14, 76, -97, 33, 25, -50, 8, + 25, -35, 20, -20, 4, -27, 63, -73, 25, 35, -22, 7, -33, 13, 2, 6, + -3, 5, 1, 17, 1, -36, 40, -4, 10, -28, -9, 14, -16, 5, 20, -32, + -45, 59, -10, 26, -29, -10, -13, -32, 44, -74, 81, -51, -12, 66, -11, -33, + 17, 38, 12, 57, -39, 5, 39, 9, -4, 4, 0, 25, -50, 24, -19, -1, + -30, -21, 24, -46, -20, -35, 19, -10, 1, -45, -7, 29, -8, -70, 51, -4, + -51, 42, 20, 21, 21, -24, 7, 69, 1, 17, 10, 9, 8, 16, -8, 66, + -32, -13, -24, 30, 50, -86, -15, 34, -23, -56, -26, 7, 22, -45, 23, -41, + 50, -84, -19, 50, 0, 2, -20, -31, 49, -12, -8, 12, 63, -20, -23, 57, + -37, 85, -57, -29, 83, -11, -15, -29, 25, -44, 33, -51, 74, -56, 63, -99, + 72, 15, -40, -41, -29, 68, -66, 46, 12, 21, -65, 5, 62, -24, -24, -15, + 7, -25, 7, -4, -16, 47, 13, -38, 3, 55, -31, -40, 31, -1, -35, 22, + 4, 34, -6, -1, -12, 6, 75, -51, 12, 57, -19, -24, -5, 12, -10, 26, + -13, 10, -44, 25, -13, -26, 39, -42, -25, -65, 36, -55, -41, -12, 2, 8, + 22, 22, -24, -27, 51, -38, 36, 1, -14, -8, 88, 2, 15, 28, 6, 46, + 8, 32, -22, 37, -29, 10, 3, -36, 9, -9, 2, 6, -15, -79, 32, -15, + -26, -4, -29, -28, 7, 16, -29, -27, 3, 8, 2, 9, 5, 1, -13, 38, + 16, 26, -16, 0, 19, -14, 20, -29, -3, 43, 17, -14, 39, -34, -15, 24, + 36, -27, -1, 7, -55, 24, 50, -43, 21, 5, -5, -122, 78, -43, -33, 12, + -12, 9, -45, -3, -1, -22, 37, -3, 17, -35, -11, 32, 5, 62, 0, -4, + 20, 18, -33, 93, 2, -77, 45, 33, -29, -35, 45, -55, 48, -12, 15, -54, + 16, -3, -50, 1, -21, -39, 16, -1, -33, -38, 19, -45, 9, 34, 26, -15, + 21, 60, -32, 7, -2, 24, 21, 28, -19, -12, 7, 60, 23, -23, 7, -44, + -54, 54, -17, -42, 38, -24, -23, 18, 9, -31, 4, 24, -26, -27, 33, -53, + 15, 26, -38, 11, 13, -39, 24, 32, 19, 14, 16, -27, -24, 14, 14, 9, + 6, -48, -8, -8, 60, -39, 1, -32, 51, -34, 0, 33, -16, -33, -10, 60, + -40, -1, 3, 31, 50, -16, -32, -40, 45, -34, -8, 54, -80, 0, 19, 21, + -21, 87, -70, -19, 23, 25, -56, 40, -33, 19, -44, -8, 7, -12, 18, -20, + 22, -10, 18, 5, -7, 26, 33, -65, 49, -9, -9, 27, 22, 22, -37, 18, + -19, -1, 61, -23, -39, 4, 4, -32, -3, 27, -39, -3, 38, -19, -12, -8, + -37, 3, -10, -14, -37, 0, 4, 24, 1, 33, -35, 29, -2, 24, 24, -21, + 23, -3, -31, 47, 12, -26, 35, -19, -17, 22, 20, -27, 1, -16, -18, 17, + -2, -19, -22, 25, -2, -11, -3, -60, -2, 30, 64, -76, -7, -29, 45, 1, + 46, -23, -43, 2, 43, 68, -38, -8, 45, -7, -8, 15, -47, -27, 71, -12, + -3, -17, -54, -29, 75, -51, 8, -27, 12, -18, 60, -29, -42, 22, 51, -32, + -27, 28, -11, 48, -34, 30, 26, -19, 20, 14, -16, 2, 7, -36, 70, -14, + -21, -39, 82, -50, -49, 33, -28, 9, -17, -15, -51, 5, 7, -17, 58, -29, + -33, 2, 29, 14, -46, 3, 28, 2, 28, -22, 7, -3, 28, 2, 40, -71, + 2, 23, 24, 19, 11, -62, 56, 1, -24, -7, -10, -26, 30, -49, 18, -40, + 52, -51, 46, -3, -28, -26, 40, 11, -5, 8, -46, 25, -10, 34, -25, 44, + -17, -7, 12, 12, -28, -19, 30, -26, 6, -38, 13, 45, -43, 24, 24, -49, + -13, 19, 3, 27, -5, -8, 5, -6, -4, 39, 7, 1, -38, 22, 20, -20, + 19, -24, -50, 47, -11, -25, 32, -59, 17, 12, 35, -50, -14, -7, 15, 33, + -15, 11, -45, 10, 14, 50, -68, -4, 11, -35, 20, 88, -72, 40, 16, -9, + 3, 55, -44, 25, -24, 6, 14, -66, 9, 7, -10, 9, -7, 1, -42, -24, + -26, 74, -5, -23, -44, 12, 11, 12, 57, -60, -19, 7, -2, 40, 3, -26, + -14, 44, 29, 7, -23, 21, -32, 42, 13, -30, -16, 36, -9, 3, -21, 17, + -67, 30, -4, 23, -19, 8, -32, 5, 31, -4, -26, 18, -24, 6, 39, -7, + -24, -2, -5, 6, -3, 11, -10, -6, 16, -15, -15, 5, -19, -17, 38, -27, + 35, -48, 7, -20, 4, 12, 1, -33, 28, -24, -2, 28, -10, -11, 23, -2, + 5, 21, -5, 8, 0, 21, 12, -24, 36, -40, 36, 29, -2, -19, 1, 3, + -8, 9, -11, -13, -31, 26, -5, 23, -26, -30, 1, 30, -19, -2, -15, 3, + 5, 5, -3, 3, -43, 38, 16, -30, 18, 12, -1, -4, 20, -47, 11, 1, + 21, -15, 1, 0, -43, -5, 37, -28, 11, -51, 21, 2, 20, -24, 22, -46, + 34, -1, 7, 27, -12, -24, 28, 39, -4, 10, -19, 8, 6, 37, -26, 2, + -12, -32, 36, 17, -11, -14, -26, -1, 17, 17, -53, -10, -11, 23, -16, -26, + 10, -33, 1, 61, -5, -21, -14, -28, 50, 13, -41, 17, -12, 38, -19, 24, + 36, -75, 16, 1, 58, -15, -19, -33, 56, -40, 39, -18, 1, 0, -34, 11, + 32, -6, -52, 32, 2, 39, -31, -23, 0, -11, 10, -26, 55, -6, -51, 0, + 36, -33, -14, -9, 30, -11, -5, 14, -17, 6, -34, 28, 16, -3, -21, 7, + 25, 13, -30, 14, 12, 33, 3, -16, 9, -12, -17, 15, 2, 23, 14, -46, + 1, 13, -4, -19, 6, 30, -53, -13, 1, -17, 13, -38, 11, 20, 1, -24, + 19, -10, 7, -28, 48, 25, -59, -33, 51, 12, -4, -3, 13, -23, 64, 0, + -5, -24, -6, 21, -27, 28, -19, -29, 51, -24, -9, -12, 3, -3, 35, 6, + -33, -37, -5, 45, -47, 30, -16, -9, -10, 51, -31, 32, 10, -22, -10, 8, + -13, -28, 8, 15, -25, 39, -36, 2, 50, -30, 36, -40, -14, 35, -9, -3, + 12, -25, 36, -7, -20, -6, 48, -5, 31, -4, -18, -48, 67, -47, 26, -30, + 6, 9, -14, -29, 3, 23, -12, -27, 29, -22, -36, -9, 51, -30, -18, -16, + 47, -4, -25, 18, 16, 13, -11, 15, 10, 2, -36, 42, 3, -9, -21, 52, + -19, 18, -34, -3, -11, 23, 19, -13, -17, -19, 16, -1, 0, -32, -1, -4, + 25, 9, -37, -3, -9, 45, -15, -29, 36, 4, -29, -9, 35, 16, -36, -21, + 25, -12, 10, -21, 25, 5, -17, -8, 12, 35, -56, 4, -15, 47, -32, -5, + 18, 3, 11, 2, 7, 1, 1, -24, 23, 6, 7, -46, -37, 73, 12, -2, + -20, 34, -45, 32, -23, 15, -40, -34, 12, 4, 13, -39, 3, 23, 17, -24, + -15, 16, 19, -30, -9, 12, 53, -64, 1, 23, 40, -11, 8, 33, -36, 42, + -68, 71, -16, -10, -41, 22, 16, -19, -18, 26, -2, 1, 4, -21, -3, -16, + -4, 16, -31, 1, -26, -5, -8, 43, -69, 28, 14, 10, -16, 21, -18, -2, + -14, 0, 32, 23, -28, -21, 68, 0, -40, 24, 32, 1, -10, 8, -20, 32, + -37, 16, -3, 24, -10, -5, -30, 35, -39, 12, 6, -26, -2, -58, 65, -66, + 13, -10, -6, -15, 28, -27, -39, 51, -28, 16, -10, 60, -51, 30, 51, -24, + 11, -9, -7, 14, 39, -33, 4, -14, 25, -13, -8, 35, -40, -1, 27, -9, + 11, -9, -13, 5, 19, -37, -12, 23, 1, -2, -31, 37, -7, -41, 35, 16, + -6, -28, -8, 9, -23, 22, -8, 27, -17, -27, -10, 10, 12, -6, 11, -51, + 21, -19, -29, 23, -10, -4, 32, 3, 25, 7, -25, 23, 35, -21, -2, -3, + 23, -4, 14, 6, -8, -5, -6, 10, 10, 5, -38, -7, 16, -38, -2, 12, + 8, -54, 5, 18, -12, -18, 23, 17, -52, 50, -78, 11, 4, 5, 19, 7, + 27, -24, 5, 3, 35, -20, 34, -15, -10, 4, 21, 16, -14, 12, -8, -2, + 42, -30, -22, 28, -9, -34, -11, 23, -36, 0, 15, -10, 14, -37, -7, -19, + 30, -18, 15, -17, -14, -14, 51, -20, -8, 13, -12, 7, 35, 9, -12, -13, + 48, 1, -2, -32, 13, -5, 1, 15, 40, -66, 18, 1, 49, -45, -38, -8, + 14, -16, -2, 24, -13, -62, 15, 54, -28, -18, -3, 10, 13, -21, -18, -9, + 44, -13, 8, 37, 6, -18, 4, 27, -18, 21, 3, -8, 13, 27, -19, 14, + 2, -27, -11, -8, 17, -38, -26, 29, -31, 5, -7, -5, -9, -4, -11, 9, + -3, -5, -18, 16, 3, 0, -8, -2, -6, -1, 58, -11, 12, 2, 31, -21, + 13, 27, -17, -23, 54, 18, -33, -7, -7, 3, -2, -25, 15, -1, -25, -41, + -13, 46, -71, -15, 40, 10, -14, 0, -10, 18, 0, -31, 25, -8, -10, -13, + 24, 30, -9, 6, 4, 26, -3, 5, 31, -25, 0, -7, 16, 20, -1, -12, + -22, 11, -10, -3, -26, 12, 3, 2, -17, -31, 4, -26, 15, 13, 6, -22, + -5, 5, 8, 11, -23, 17, 17, -33, 0, 12, 21, -20, -3, 20, 21, -7, + -20, 38, 20, -27, -16, 3, 7, -8, -3, 0, 22, -38, -37, 26, 23, -26, + -8, -5, 0, -12, -2, 30, -8, -4, -2, -13, 15, -24, -4, 29, 10, 32, + -7, -57, 48, -13, 41, -13, 16, -20, -20, 33, -13, 26, -17, -18, 20, 10, + -44, 18, 2, -18, 3, -13, -5, -25, -16, 7, 30, -32, 8, -34, 19, -5, + 23, -28, 12, -4, -14, 30, 1, -2, 15, -20, -16, 44, -2, 34, -31, 36, + -25, 15, -3, 13, -10, -36, 39, -5, 0, -16, 1, 27, -28, 24, -26, -8, + -12, -16, 25, -2, -12, -28, 16, -17, 7, -24, 31, -15, -8, 31, -22, -7, + 0, 14, 16, -17, 8, -15, 24, -3, 17, -14, 6, -4, -22, 22, 9, 1, + 3, -21, 18, -8, 11, 0, 10, -3, -12, 3, 15, -15, 1, 2, -13, 3, + -23, -3, 15, -11, -5, 9, -30, -6, -10, 27, -2, -9, -12, 10, 4, 0, + -16, 16, -10, -27, 51, -5, -4, -1, -4, 5, 38, -18, -11, 17, 1, -2, + 8, 0, -7, 6, -6, -4, 9, -12, -11, 11, 1, -14, 1, -31, 13, 3, + -28, 12, 24, -30, 7, -6, 5, -4, -6, 8, 1, 14, -19, -1, 32, -22, + -9, 34, 6, -9, -9, -5, 15, 6, -25, 14, 6, -41, 0, 10, 2, 12, + -18, 6, 5, -1, -16, 4, 26, -33, 5, 4, -4, -9, 5, -2, 14, -10, + -11, 16, -6, 11, -5, -15, 14, 18, -19, 21, -24, 13, 6, -13, 21, -12, + -11, -2, 10, -6, -7, -13, 12, -13, 1, 10, -7, 2, -2, -21, 24, 5, + 2, 5, -24, 17, -17, -15, 9, 20, -12, -9, -15, 14, -1, -2, 14, -13, + 5, -32, 21, 10, 7, -11, 24, -1, -23, 24, -25, 31, 7, -16, -2, -4, + 9, -19, 17, 4, -27, 22, 21, -28, -6, 32, -48, 6, -4, 20, -6, -41, + 11, 31, -16, -14, 2, -8, -13, -13, 35, -15, 15, -20, 1, 26, 7, -13, + 18, 5, -19, 11, -7, 20, 22, -35, -11, 20, -24, 21, -20, 34, -15, -17, + -8, -2, 16, -9, -12, 2, 20, -31, 24, -21, 2, 12, -27, 28, -10, -5, + 24, 7, -29, 4, 6, -24, 33, -4, -8, -16, 1, 32, -28, 13, 7, 2, + -10, -38, 30, 2, -18, -2, 17, 13, -6, -46, -1, 61, -48, 18, 10, 2, + -17, -13, 8, 27, -8, 0, 11, -5, 20, -39, 4, 19, -8, -13, -15, 29, + -36, 29, -16, 14, -25, 17, -14, -15, 18, 5, 3, -5, -2, -19, 31, -12, + 14, -23, 31, -24, -4, 0, 4, 2, 11, -15, 22, -27, -4, 9, -8, 22, + -2, 7, -33, -12, -3, 30, -3, -10, 12, -19, 2, -9, 16, -4, -15, 5, + 32, -13, -13, 22, -11, 1, 3, 18, -12, 3, -17, 16, 15, -36, -2, 10, + -12, 9, -29, 14, 12, -23, 5, 39, -20, -39, 13, 14, -13, 2, -16, 43, + -25, -1, -12, 19, 11, -27, 0, 28, 3, -3, -15, -1, 10, -31, 43, -6, + 5, -10, 4, -18, 24, -6, -14, -8, -5, 4, 1, -5, -20, 21, 5, -19, + 22, -8, -13, -3, 20, -10, 20, -12, -7, 11, -11, -15, 6, 3, 24, -9, + -4, -3, -4, -20, 44, -12, -15, 4, -3, -6, 2, 9, 3, -17, -7, 9, + -2, 2, -22, 18, -8, -2, -10, 4, 6, -1, -4, 9, -1, 6, -9, 8, + 2, 4, 4, -6, 17, -32, 11, -1, 21, -7, -29, 12, 2, -35, 28, 12, + -15, 15, -43, 37, -30, -4, 2, 27, 8, -22, -1, -13, 20, -28, 36, -6, + -12, -4, -8, 14, 2, -12, 5, 12, -3, -11, 3, -1, 2, 18, 12, -11, + 4, -31, 13, 10, -10, 12, 7, -35, 10, -17, -3, 12, -5, 2, 0, -23, + 7, 5, -4, 23, -30, 2, 4, -3, 18, -16, 17, 16, -12, -3, -14, 17, + -1, -5, 9, 19, -23, 11, -8, -19, 34, -7, -13, 1, 3, 19, -23, -15, + 19, -17, 5, -24, 16, 4, -5, -7, 7, -2, -20, 4, 15, 21, -29, -7, + 16, -3, -17, 9, 3, 15, -15, -5, 12, -14, 8, 21, -15, 12, -18, -1, + 17, -19, 2, 16, 16, -11, -30, 22, -12, -12, -1, 21, -28, 29, -30, -6, + 19, -14, -5, 0, 10, 18, -8, -15, -1, 7, -15, 28, -3, -3, -9, -8, + 0, 6, 18, -32, 7, -3, -11, 6, 30, -42, 32, -13, -8, 5, 8, 8, + -15, 3, 4, -22, 27, -6, 6, -11, 1, -6, 13, -5, 2, -12, 29, -30, + 10, -15, 18, -19, 8, 21, 1, -28, 15, -20, 25, -25, -1, 11, -2, 1, + -22, -3, 15, 1, -22, 18, 16, -24, 1, 19, 6, 9, -7, -22, 8, -6, + 2, 14, -9, -4, -13, 10, -12, 13, 0, -11, -12, -2, -6, 20, -9, 4, + 5, -14, 3, 9, -2, 13, -5, 0, 14, -17, -1, -3, 8, -6, 7, 29, + -19, -13, 3, 27, -17, -8, 11, -2, -14, -9, 7, -3, -9, -14, 24, -12, + -35, -13, 40, -10, 1, -7, 1, 2, -1, 1, 16, 3, -13, -11, 30, 2, + -9, 0, -9, 2, 15, -9, 8, 3, -19, 12, 5, -21, 5, -6, 16, -4, + 7, -4, -2, 9, -35, 27, -6, 0, -12, 15, -29, 8, 2, -7, 4, 1, + -15, 28, -15, -13, 18, 4, -1, 1, -4, -7, -16, 21, -11, 25, -19, 2, + -10, 20, -32, 11, 6, 6, -15, 22, 8, -25, -13, 5, 20, 13, 7, -23, + -6, 7, -4, 4, 0, -7, 3, -10, -4, 9, 1, 3, -8, 2, 16, -22, + -7, -3, 12, -4, -4, 8, -10, 6, -13, -5, 3, 3, 6, 4, 4, -9, + -27, 1, 16, 17, -15, 0, -12, 15, -2, -6, 10, 3, -16, -16, 22, 13, + -12, 4, -4, 7, 11, -12, -14, 15, -1, 3, -12, 7, -7, 12, -14, 9, + -9, 2, 2, 9, -12, -17, 12, -17, 14, -2, -18, 2, 16, -5, 1, 8, + -5, -12, 0, -3, 21, -2, -17, 10, 10, -4, -16, 6, 15, -1, -25, -11, + 18, 0, -11, 8, 15, -16, -18, -4, 39, 3, -30, -6, 22, 2, -22, 2, + 21, -9, -9, 12, -3, 19, -24, -12, 20, -8, 4, 3, -3, 15, -20, -3, + 14, -7, -4, -14, 9, -8, 0, 7, -6, -8, -4, -3, 4, 13, -18, 0, + 9, -2, 5, -4, 10, 3, -9, -6, 9, -3, 1, 4, -3, 4, -11, 2, + -3, 5, 11, -13, -1, 4, -7, 1, -11, 1, 17, -17, 2, 13, 1, -21, + -2, 7, -5, -4, -5, 16, -5, -7, 4, 8, 8, -14, 4, 8, -7, -1, + 5, 2, -11, -9, 9, 6, -10, -2, 6, -7, -2, -1, 15, -17, -4, 5, + -2, 2, -3, -5, 11, -3, 1, 16, -12, -3, -7, 6, 5, -4, 5, 0, + -3, -15, 5, 3, -8, 9, 3, -8, 1, -6, -4, 0, -7, 21, -18, 9, + -8, 11, -2, -10, 10, 1, 14, -19, -11, -7, 18, -7, 4, 6, 2, -15, + 2, 4, 5, -3, 0, 0, 12, -2, -15, -4, 18, -7, -9, 18, -7, -6, + -9, 4, 7, -21, 11, -18, 14, -5, -4, 8, 5, 4, -3, -4, -11, 11, + -15, 19, 2, -18, 8, -4, -13, 18, 3, -14, -3, 9, -11, 2, 10, -9, + -5, -1, -15, 13, 16, -9, -4, 29, -15, -14, 6, 9, -1, -15, 12, 12, + -6, -6, 13, -10, 18, -14, 7, -12, 5, -9, -12, 16, -6, -16, 7, -1, + -22, 8, 2, -1, 9, 4, -31, -9, 12, 14, -9, -5, 17, -25, 7, 0, + 13, 4, -1, -17, 10, 13, -7, -11, 17, 2, -23, 27, 5, -10, -3, 13, + 5, -5, -5, -4, 0, -3, -5, 3, 4, -9, -7, 5, 4, -13, -10, 1, + 7, -4, -2, -3, -5, 15, -9, 0, 1, 12, -17, -6, 32, -15, -16, -11, + 20, 0, 2, -11, -5, 25, -21, 3, 10, 15, -24, -4, 8, -5, 0, 15, + -1, -7, 1, -18, 21, -7, 3, -12, 0, 12, -10, 6, -3, -2, 2, -1, + 9, 1, -9, 7, -9, -4, 9, -16, -4, 8, -10, 4, -3, -2, 13, -9, + 4, -16, 4, -3, -5, 14, 7, -8, 2, 9, 0, -2, -12, 7, -3, 2, + -4, -15, 11, -8, -11, -4, 23, -5, -1, 4, -9, 7, -4, 7, 8, -13, + -6, -4, 16, 10, -11, 8, -1, -1, 2, -5, 0, -3, -6, 2, 3, -6, + 13, -19, -9, 19, -11, 6, -12, 12, -10, -3, -11, -10, 14, 2, -19, 14, + 4, -6, 4, 11, -7, 3, -3, -8, 24, -18, 6, -8, 15, -14, -7, 19, + 0, -11, -3, 2, 2, 0, 2, 6, -7, -22, 16, 0, 11, -12, 7, -12, + 10, -16, 4, 8, -11, -11, 4, 16, -19, 13, 1, -19, 12, 19, -15, -4, + 9, -8, -13, 5, 14, -12, 5, -21, 7, 4, 11, -19, -1, 15, -16, -3, + -12, 14, 1, 1, 15, -6, -13, 7, 0, 6, 4, -11, -3, 10, 14, -20, + 7, 3, 1, 5, 17, -17, -5, 3, -4, 6, -1, 3, -18, 10, -10, 0, + 0, 14, -18, -19, 17, -23, -5, -1, 4, -4, -2, 1, -13, 26, -15, 2, + -10, 3, 13, 0, -6, 3, -4, 3, 0, -2, 9, 2, 9, -14, 23, -4, + -10, 15, 7, -16, 0, 9, 3, 0, 14, -12, 0, 4, -10, 1, -11, -13, + -6, 15, -14, -7, 2, -20, 4, -7, 9, -3, 2, -14, -1, 1, -1, 9, + -18, 10, -1, 1, -3, 22, 1, -1, 5, -4, 10, 2, 5, 0, 3, -2, + -1, 5, -2, -3, -5, 10, 2, -16, 2, 3, -1, -1, -11, 7, 6, 0, + -10, 10, -7, -2, -15, 15, 4, -25, 0, 4, 4, -12, 0, 5, -7, -6, + 6, 6, -8, 1, -1, -7, 17, -9, 2, 8, 4, -6, -6, 19, -5, -11, + 12, -12, 3, 3, -5, 9, 11, -26, 0, 0, 7, 5, -8, 11, -5, -6, + -16, 7, 12, -10, 0, -6, 7, -8, 3, -4, 11, -9, -16, 13, 18, -18, + 2, -5, 7, 5, 0, -1, 4, -9, -13, 18, 5, -4, -14, 1, 7, -5, + 4, -9, 15, 3, -10, -4, 5, 3, -11, -17, 18, 4, -9, -3, 3, -5, + -11, -3, 0, 7, -1, -8, -2, 6, -7, 7, -3, 6, 3, -12, 15, -5, + 23, -12, 8, -12, -4, 10, 1, 4, -3, 0, 0, 8, 0, 1, 11, -27, + -9, 9, -4, -3, 12, -19, -2, -8, -6, 1, -1, 2, -12, 5, -11, 3, + -1, -1, -10, 18, 0, 3, 2, 4, -5, 11, -3, 9, -2, -5, 7, -6, + 8, 10, 2, -1, -8, 1, -16, 2, 9, 1, -4, 0, -15, -5, 6, -14, + -9, 14, -22, 3, 7, -1, -2, -2, 0, 1, -2, 1, 9, 0, 7, -1, + 6, 4, 0, -6, -2, 2, 4, -9, 11, 1, -25, 9, -6, 5, 0, -7, + -8, 3, 5, 1, -2, 3, -9, -5, 7, 14, -12, 3, -10, 10, 3, -16, + -3, 26, -8, -9, -2, 15, 0, -21, 8, 11, -17, 3, 8, -8, 10, -19, + -3, 8, -4, 6, -10, 3, 4, -6, -4, 6, 0, 4, -19, 9, 3, -7, + 17, -7, 2, 3, -27, 12, 5, -14, 5, -6, -6, 6, 11, -11, 6, -12, + -2, 9, 8, 1, -18, 18, -9, 0, 13, -8, -10, 24, -11, 4, 13, -4, + -18, -3, 2, 9, -7, -1, 4, -6, 0, -11, 5, -1, -1, -8, -10, -6, + 6, -15, 20, 6, -25, 11, -5, -7, 12, 4, 0, -6, 6, 2, -1, 5, + 1, -11, 9, 20, -11, 14, -6, -15, 11, -11, 7, 1, -5, 2, -8, -2, + 12, -5, -16, 8, -4, -10, 2, 2, -6, -8, 5, 0, 3, 4, -17, 13, + 4, -9, 1, 5, 4, 8, -7, -3, 3, -2, 4, 14, -9, -6, -7, -3, + 11, -17, 0, 9, -10, 0, 1, 0, -9, -7, 8, 7, -3, 15, -22, 2, + 7, 0, 2, 4, -2, -6, -3, -1, 9, 2, -2, 1, -4, -1, -6, 2, + 4, -8, 3, -2, 1, 0, -9, 14, -6, -5, 3, -1, -6, 5, -5, -6, + 5, -5, -1, 12, -10, -6, -3, 9, -7, -8, 14, -5, -11, 9, -1, 5, + -5, 3, 1, 0, 1, 3, -7, 7, -1, 1, 4, 5, -16, 7, 6, -6, + -2, 11, -8, -9, 3, -9, -2, 15, -11, -11, 6, -1, -7, -4, 4, 2, + -9, 1, 1, -2, 0, 6, -3, -3, 6, -7, 6, 11, -11, -9, 0, 15, + -8, 14, -2, -13, 1, 4, 0, 7, -2, -10, -1, 8, -6, -4, 5, 1, + -6, 1, -8, 0, -4, 7, 4, -3, -8, -4, -3, 8, 3, -8, -3, 16, + -7, -1, 0, -1, -4, -2, 2, 6, -1, -2, -4, 5, 5, -4, -2, -8, + -6, 10, 4, -5, -2, -2, -2, 0, -4, 0, 2, 0, -12, 6, 2, 0, + 3, 2, -11, 2, 1, -2, 10, 1, -6, 9, -8, -3, 5, -1, 5, -2, + 0, -5, -7, 8, 5, -4, -9, -1, 1, -2, -7, 4, -12, -4, 5, 0, + -4, 5, -13, 8, 2, 4, 1, -10, -6, -3, 17, 4, 1, -7, 6, 2, + 1, -3, -1, 0, 7, -8, -2, 6, 2, -8, 0, 21, -16, -5, -1, -2, + 4, 0, -18, 11, -10, -4, 11, -4, -1, -2, 2, -3, 2, -2, -8, -1, + 1, -3, 8, 2, 0, 1, 5, -7, 2, -4, -1, 4, 5, 0, 1, -6, + -11, -6, 7, 8, 5, -7, -12, 7, 2, -6, -3, 7, -4, -3, -1, 2, + 9, 0, -7, 9, 5, -15, -3, -7, 2, 3, -2, 0, -3, 6, -13, -2, + 0, -5, 3, 9, -5, 9, -12, -9, 12, 4, 1, 5, 3, -4, -2, 3, + 11, -16, 2, 0, 10, -9, -4, 8, -4, -7, 2, 2, -6, 3, -22, 8, + 11, -7, -6, -2, -5, -5, -8, 3, 7, 12, -8, -1, 4, 8, -14, 4, + 13, -6, -8, 2, 17, -1, -3, 12, -10, -2, -7, 0, -6, 16, -17, -4, + 10, -9, -2, 1, 0, -1, -7, 7, -10, -3, 3, -1, -7, 11, -11, 3, + 3, 8, -6, -2, 1, 0, -15, 15, 5, 0, 7, -5, 4, -3, -2, 2, + -4, 10, -9, -9, 15, -6, -12, 14, 3, -7, 0, -9, -1, -5, 3, -4, + 3, 4, -14, -2, -1, 8, -3, 13, -5, -18, 12, -1, -7, 0, 5, -2, + -6, 14, 3, -9, 3, 1, -10, 0, 7, 3, -7, 4, 2, -14, 4, 4, + -6, 14, -4, -12, 6, 2, -10, 1, 5, -6, -10, 3, 8, -11, 9, -1, + -3, 2, -6, -8, 4, 2, -10, 6, 11, -7, 0, 2, 1, -10, 8, 6, + -5, 2, -2, 3, -4, 1, 4, -11, 6, 4, -8, 4, 4, -13, -4, 2, + 6, -3, 2, -4, -11, 11, 2, -13, 9, 3, -21, -2, 17, -4, -1, 6, + -11, -2, 1, -4, 4, 5, 0, 0, 1, 13, -8, 0, -3, 2, -6, 1, + 7, -4, 2, 2, -5, -5, 8, -14, -4, 8, -10, -1, 3, -4, -6, 6, + 5, -12, -6, 5, 1, -4, 2, -4, -1, 8, -8, 1, 8, -4, 6, -1, + 17, -8, -7, -1, 4, -1, 14, -5, 0, -6, -1, 0, -1, 2, -10, -7, + 0, 6, -6, 4, -12, -1, 7, -5, -2, 0, 3, 0, -9, 10, -8, -1, + -5, 11, -15, 6, 6, -1, 1, 1, -4, 4, -7, 12, -11, 10, 2, -15, + 5, 11, 5, -7, -7, 0, 0, -5, 11, 0, -5, -10, -12, 15, 1, -2, + -4, 2, 6, -9, -8, -3, -1, -5, 5, -4, 1, 5, -13, -1, 10, 0, + 0, -2, 1, 9, 0, 3, -7, 14, -2, 0, -2, 3, -12, 9, 4, 0, + -4, -7, 0, -6, -5, 5, -3, -5, -5, 4, 7, -13, -7, -6, 3, 1, + 0, 6, -3, -5, -4, 7, 1, 3, 1, -3, 5, 3, 3, 2, -1, 2, + 4, -9, 8, 2, -5, 6, -12, 7, -5, -8, -6, 9, -14, 4, -7, 4, + -6, 1, -2, -11, 4, -4, 2, 7, -4, 4, 5, -2, -4, -5, 6, 2, + 0, 5, 9, 3, -4, -7, 1, 6, 3, -2, -7, 1, 1, -6, 0, 8, + -12, -11, 7, -12, 0, 2, -5, 4, -1, -9, -2, 7, -8, 1, 1, 5, + 1, -4, 5, -8, 4, 2, -5, 7, 6, -6, -3, -8, 13, -2, -3, 2, + 0, 0, -5, 6, 5, -6, -3, -3, 2, 8, -12, 4, 7, -12, -10, 13, + -3, -2, 1, -5, 1, 1, -2, 5, -5, -6, -12, 4, 0, 4, 3, 3, + -10, -8, -3, 10, -5, 7, -8, 3, -1, 6, 0, 3, 6, 4, -6, 2, + 5, 5, -6, -4, -2, 4, -2, -9, -4, 7, -1, -12, 10, -5, -9, -11, + 1, 4, -8, 1, 7, -3, 4, -7, -1, 8, -5, -6, 9, -1, 0, 8, + 3, 7, -9, 6, -1, 9, -7, 2, 3, -4, -5, 6, -6, 8, -10, -12, + 4, 3, 1, -1, -9, -1, -4, -5, -3, 6, 7, -11, -4, 6, 0, -3, + 3, 4, -5, -4, 1, -3, 3, -2, 0, 1, -1, 3, -9, 7, 3, -7, + -2, 5, 5, -9, 7, 0, -8, 8, 1, -5, 6, -4, -6, 2, 6, -3, + 0, 0, -3, -9, -6, -2, 9, 2, -2, -11, 7, 9, -9, -7, 8, 0, + -7, 1, 4, -5, -3, -3, 5, 5, -3, -13, 7, 5, -6, 5, -2, 7, + -9, -8, 6, 2, -5, 3, 7, -4, -6, -7, 1, 7, 6, -5, -5, 6, + -10, 10, 1, -4, 4, -4, -2, 1, 9, -10, 0, 4, -8, -1, -5, -1, + 3, -2, 6, 1, -5, -5, -5, 2, -3, 3, 3, -1, 0, -4, 0, 9, + -1, -6, -6, 4, -1, 2, 5, 0, -2, -2, -4, 2, 4, -1, -4, 4, + 0, -3, -9, -2, 6, 0, -7, -1, 3, -2, -1, 2, 2, -7, -2, 0, + 2, 4, -6, 3, -3, 6, 0, 0, -2, -6, 1, 11, -2, -1, -8, 3, + -7, 1, -2, 6, -9, 6, 0, -1, 1, -6, -7, 5, -1, 2, -2, -1, + -1, 0, -3, 1, 2, -1, -3, -5, 3, 7, -9, 5, 3, -5, -5, 5, + -1, 0, 4, 4, -11, 8, -3, -10, 9, -7, -1, 1, -2, 1, -3, 6, + -3, -5, 2, 4, -7, 5, 2, -2, -3, 1, -2, -4, 2, 0, -4, 8, + 2, -12, 0, 6, -10, -2, 8, -6, -3, 6, -4, 2, 9, -4, -7, 2, + 5, -1, 1, 4, 0, -5, 2, -7, 2, 4, 1, -5, -1, 7, -5, -5, + 12, -7, -12, 6, -4, -3, 3, 4, -3, -5, -1, -3, -10, 9, -8, -2, + 6, -3, -4, 6, -1, 0, 3, 2, 1, -3, -5, 2, 0, 4, -3, -3, + 1, 4, -8, 0, 7, 4, -9, 0, 3, 1, 1, -5, -4, 3, -1, -4, + 4, 3, -8, -2, -2, -3, -1, 0, -3, -2, 3, -2, 1, 0, -1, 0, + -6, 8, -5, 5, -5, 5, -3, 5, -7, 1, -3, -1, -1, 2, 8, -2, + -5, 1, -3, -1, -4, -4, 9, -1, 1, -3, -2, 1, -14, 8, 3, -14, + 4, 1, 2, 2, 0, -5, 3, -1, 2, -2, 8, -8, -3, -3, 7, -1, + -3, -1, -3, 1, 5, -7, 7, -12, -1, 1, 4, 3, -7, 5, 6, -2, + 2, -6, -3, 0, -5, 2, 1, -1, 2, -7, 1, 8, -5, -4, -3, 2, + -2, -5, 3, 2, -3, -6, -1, 1, -4, 4, 5, 2, -14, -1, 3, -4, + 3, 10, 2, 2, -4, -1, 4, 3, -6, 2, 1, -2, -9, 7, -2, 1, + -4, -5, 1, -7, -1, 1, 2, 2, -1, -6, 5, -1, -12, -4, 11, -2, + -3, 6, -4, 2, 0, 0, -2, 0, 3, 2, 4, 2, -3, -6, 9, -10, + -4, 2, 4, -1, -5, -1, 2, 1, 2, -7, -2, -4, -4, -2, 7, 5, + -6, 0, 1, -1, -4, 2, -6, 3, 9, -11, -2, 8, 0, -5, 6, -1, + 3, -5, 6, 1, -10, -4, -3, 4, 10, -8, -2, 1, 4, -8, 4, 3, + -8, -5, 2, 4, -5, 6, -2, 2, 2, -3, -10, 0, -6, 2, 4, 12, + -4, -10, 6, 2, -5, 2, -3, 6, -4, 0, -6, -4, 7, 0, -4, 12, + 0, -14, 3, 2, 1, 1, 2, -7, -1, 3, -1, -4, 10, -9, -11, 6, + 4, -9, -5, -1, 5, 0, 6, -5, -5, -4, 3, -7, 9, 0, -1, 0, + 4, -3, -2, -1, -4, 0, 10, 3, -5, 4, -4, -6, 8, 0, -7, -3, + 17, -9, -8, -1, 3, -3, -3, 0, -4, -3, -5, -4, 8, 8, -9, -5, + 4, 0, -7, 6, 7, 3, -6, 3, -3, 1, -4, -4, 4, 10, 1, -5, + -2, 0, -9, 4, 1, 1, -4, -2, 6, -3, -5, 0, -6, 3, 0, -2, + 4, 1, 0, -4, 3, -1, -10, -2, -2, 2, 9, -11, 8, 3, -2, -1, + -1, -3, -1, -8, 4, 6, 2, -7, 2, -1, 3, -6, 0, 1, -1, 2, + 2, 3, -1, -13, 2, 9, 3, -5, -3, 2, -3, 5, -4, -2, 0, -4, + -1, 1, -4, 0, -4, 0, -2, -2, -5, 1, 4, -1, 1, -4, 1, 2, + 0, -2, 2, 1, 1, 0, 7, 0, -3, -4, -2, 5, 0, -3, -2, 3, + 2, -9, -1, -1, -1, -4, 1, 5, -6, 1, -4, 8, -12, 1, -5, 3, + 3, -1, -6, 9, -3, -2, 0, 4, 0, -3, 4, 10, -5, -4, -2, 0, + 2, -3, -2, -2, 0, 0, -3, 0, 3, -8, 0, -5, 1, 0, 5, 1, + 4, -14, -2, 1, 3, 1, 0, -1, 6, -2, 2, -5, 4, 1, -2, -3, + 1, 3, 5, -5, 3, -1, -8, 0, -3, 5, -7, 2, -4, 2, -4, 2, + -3, -2, -7, 4, 2, -2, -4, 5, -5, -3, 0, -4, 3, 5, -6, 5, + 8, -5, 0, 2, 1, -6, 0, 5, 1, -2, 6, -10, 7, -9, 3, -5, + 4, -1, -1, -4, 5, -6, 5, -1, -9, -1, 2, 4, -2, 0, 5, -9, + 1, 0, -2, 1, -1, -3, -1, 9, -1, -9, -2, 2, 1, 2, -2, 3, + -7, 3, -1, 3, -1, -5, -5, 9, 1, -1, -3, 2, -7, 1, 3, -4, + -2, 5, 3, -2, 0, -5, -1, -1, -3, 1, -2, 0, -1, -2, 7, -3, + -12, -1, -2, 0, 5, 4, -4, -2, 6, -3, -5, 8, -5, -4, 2, 6, + 1, -1, -1, -4, 4, 3, -6, -4, 6, -1, -4, 2, 2, -10, -4, 3, + 0, -3, 5, -4, -5, -1, 2, -5, -1, 2, -2, 1, 6, -2, -4, 5, + -2, 1, 4, 0, -2, 0, 3, 0, -2, -4, -6, 6, 3, -2, -1, -1, + 1, -1, 0, 0, -14, -1, 3, 0, 0, 4, -6, -2, 0, -2, -3, -3, + 3, -4, 7, 4, -4, -3, -2, 3, 1, 0, 1, 2, 5, -2, -6, -1, + 1, 1, -4, 3, 0, -2, -3, 2, -8, 1, -2, -5, 0, 2, -2, 6, + 2, -1, -7, 4, -5, 2, -4, -6, 5, 5, 2, -1, -3, -4, -7, 0, + 6, -3, 0, -4, 8, 1, -6, -1, 2, 0, -2, -1, 7, -5, -4, 0, + 7, 0, -5, -4, 3, -2, 3, -3, 1, 3, -1, -6, 2, 3, -7, 3, + 0, -3, -3, -2, -4, 2, -2, -1, -3, 2, -4, 0, 4, 2, -6, 1, + -1, 1, 1, 4, 1, 2, -4, 0, 0, 5, 0, -5, -5, 7, 0, -4, + -4, 2, -6, -4, 5, -1, -1, -4, -3, 3, -1, -6, 1, 4, -1, -3, + -3, 3, 4, -1, 3, 2, 0, -3, -3, 5, 2, -3, -1, 1, -1, -2, + -1, 2, 1, -5, -1, 1, -3, -3, -4, 0, 2, -3, -2, 0, 4, -1, + -2, 0, 3, -6, 0, 3, 5, -1, -2, 3, 0, -3, 0, -3, 8, -4, + -6, 4, 2, -5, 0, -1, 2, -5, -7, -2, 1, 2, 1, 0, -2, -1, + -2, 0, 4, 0, -5, 2, 7, 5, -5, 3, -3, 0, 1, 0, -2, 5, + -10, 0, 1, 3, -12, 1, -2, -1, 1, -2, -4, 3, -6, -2, 3, 0, + -6, 0, 2, 4, 2, -3, 6, 2, -7, 2, 1, -4, 9, 3, -1, 0, + -2, -7, 0, 5, 3, -6, 4, -8, -3, -3, -1, -3, 3, -3, -5, 3, + -3, 3, -1, 2, -7, -2, -1, -4, 2, 2, 4, 3, 0, 0, -1, -2, + 1, 4, -2, 2, -1, 2, -2, -1, -8, 2, 2, -3, -1, 2, -2, -5, + 0, -1, -4, -1, 5, 1, 3, -2, -1, 0, 2, 6, -4, -1, -6, -2, + 2, 4, 1, -2, -5, -4, 0, 3, -4, 1, 4, -1, -9, -1, 1, -1, + -2, -2, 2, 1, -5, 6, -1, 5, -4, -3, -2, 8, -2, 1, 5, 2, + -8, 0, 2, 0, 3, -3, -4, 3, -7, -6, 4, 1, -6, 0, 2, -2, + -4, -2, 2, 4, -5, -2, 3, 0, -5, 1, 7, 6, -4, -7, 4, 3, + -6, -3, 12, -3, -3, -5, -2, 2, -2, -7, -2, 10, -4, -5, 2, 0, + -3, -5, 3, -1, 3, -2, -3, 3, 6, -8, 2, 5, -3, -3, -5, 13, + -3, -1, 1, 1, -4, -3, 0, 3, -3, -2, -1, 1, 2, -7, -6, 3, + -7, -3, 3, 1, 2, 1, -7, 3, -3, -1, -5, 6, 3, -1, -6, 6, + 3, -2, -3, -1, 1, -3, 3, -5, 4, 0, -6, -3, 5, -1, -5, 8, + -2, -1, 0, -4, 5, -4, -5, -1, 1, 4, -1, 1, 5, -5, 3, -2, + -2, -5, -2, 2, 4, -2, 2, 1, -16, 5, 1, -1, -2, -2, 1, -4, + 0, -8, 2, 4, -5, 0, 6, -2, 0, 0, 0, -1, 2, -5, 6, -1, + -1, 2, -1, 4, -5, 1, 0, -4, -2, -3, 2, 2, 4, -3, 1, -9, + -1, 2, 0, 1, -1, -1, -4, 3, -7, 6, -4, 2, -4, 7, -3, -1, + 3, -7, 0, 10, -1, -8, 2, 2, -5, -5, 4, -2, -2, -7, -5, 4, + 2, 3, -11, 10, -6, -5, -4, 0, 9, -1, 0, 4, -6, -1, 3, -1, + 6, -6, -1, -1, 9, -5, -3, 7, -1, -1, 4, 2, -7, 3, -2, 0, + -2, 2, -9, 0, 4, -6, 0, 2, 3, -14, 4, -3, -12, 3, -1, 3, + -4, 4, -8, 6, 5, -3, -2, -4, 8, 0, -3, -1, 1, -4, 4, -3, + 7, 0, 1, -5, 1, 6, -10, 1, 8, -5, -8, 6, 4, -2, 5, 2, + -9, 4, -1, -1, 0, -4, -5, 3, 4, -11, 3, -7, -4, 1, 2, 0, + -3, -2, -7, 4, -9, 4, -6, -1, 2, -2, -1, 3, 9, -6, 2, -1, + 3, 4, 2, 3, -1, 0, -1, 1, 4, 0, -3, 3, 6, -7, -4, 4, + -3, 0, -5, -2, 2, 4, -1, -1, 0, -9, -4, -6, 14, -11, -5, -1, + 5, -6, -3, 3, -2, -6, 3, 5, -1, -4, 5, -7, 7, 4, -7, 6, + 4, -2, -4, 5, 8, -12, 3, -1, -5, 3, -3, 2, 10, -7, -12, 3, + -2, 5, -4, 4, 3, -6, -4, -6, 10, -4, 2, -3, 2, 0, -2, 0, + 2, 2, -12, -2, 13, -2, -6, 0, -5, 10, 1, -1, -2, 0, -12, 3, + 11, 0, -5, -9, 7, -4, 2, -3, 0, 9, -2, -6, 0, 3, -2, -13, + 1, 12, -7, -3, 0, -1, -4, -4, -5, 1, 5, -4, -7, 2, 0, -3, + 5, -2, 10, -12, 5, 1, 10, 8, -6, 4, -12, 7, -1, 5, 0, -1, + -2, 7, 4, -4, 5, -4, -20, 6, 1, -6, 5, 0, -14, 3, -12, 3, + -8, 6, -10, 2, -4, -3, 1, 4, -7, 4, 8, 2, 1, 2, 2, 3, + 3, 0, 7, -7, 3, -1, -1, 11, 3, 1, -6, 0, -8, -10, 8, 6, + -4, -1, -5, -11, 3, -1, -14, 6, -4, -13, 10, 0, 1, -5, 0, 0, + 1, -3, 7, 4, 3, 3, -1, 6, 1, -1, -6, 2, 2, -3, -4, 15, + -17, -4, 1, -3, 4, -4, -6, -2, 4, 4, -4, 3, -4, -7, -2, 13, + -1, -4, -2, -3, 9, -7, -12, 13, 10, -12, -3, 4, 13, -14, -6, 12, + -4, -10, 11, -5, 4, -1, -17, 9, -1, 4, -3, -5, 6, 0, -7, 3, + 2, 4, -9, -9, 13, -8, 7, 6, -8, 11, -15, -11, 16, -10, -2, 1, + -8, -1, 11, -1, -4, 2, -13, 9, 3, 11, -16, 4, 7, -9, 9, 4, + -16, 11, 9, -10, 13, 4, -10, -12, 2, 4, 4, -10, 7, -6, 0, -8, + -3, 3, -1, -4, -9, -9, 3, -5, -3, 24, -19, -5, 7, -11, 4, 9, + 1, -3, -1, 7, -4, 4, 4, -4, -7, 22, 0, -1, 10, -19, 3, 1, + -6, 9, -7, 3, -5, -5, 5, 9, -17, -2, 4, -9, -4, 5, -3, -7, + -3, 6, -4, 10, -12, -3, 13, -6, -5, 5, 3, 8, 0, -7, 0, 2, + -3, 12, 3, -10, -4, -8, 8, -1, -16, 13, -5, -5, 0, 3, -6, -8, + -2, 13, -5, 12, -4, -17, 11, 0, 2, 2, 3, -6, -3, -3, 4, 7, + -3, 1, -2, -2, -3, -4, 7, -3, -4, 4, -5, 6, -11, 5, 7, -10, + 0, 2, -6, -1, 5, -3, 3, -5, 5, -8, 4, 10, -8, 3, -4, 7, + -5, 3, -3, -2, 4, 2, -4, -7, 2, -3, -5, 6, -2, 5, -4, 6, + -10, -5, 5, 0, -8, 6, -6, -1, -3, 5, 2, 0, -4, 10, -12, -5, + -21, -1, -4, 5, 3, 2, 18, -14, 8, 5, 1, -4, -5, -2, -9, 0, + -12, 20, -4, 7, 1, 6, 7, -1, -5, 13, -1, -7, 6, -2, -5, 2, + 1, 4, 6, -7, 6, -9, -3, 6, -3, 8, -10, 8, -6, 0, -20, 1, + -5, 5, -4, -8, -12, -13, 8, -2, 17, 3, -5, -20, -1, -7, 3, 22, + 22, 12, -11, -13, -15, -9, 21, -3, 25, 43, -4, -3, -6, -21, -30, -37, + -9, 8, -5, 8, 53, 50, 1, -5, -13, -15, -41, -23, 6, -34, -47, -17, + -2, 2, -13, 22, 29, 32, 44, 51, 55, 10, 15, 7, 0, -31, -48, -38, + -48, -43, -13, 7, 4, -46, -23, -6, 6, 4, 12, 50, 26, 4, 24, 40, + 33, 20, 17, 17, -7, -30, 10, -2, -17, 5, -36, -7, -38, -30, -13, 1, + 9, -1, -6, -29, -15, -11, 7, 3, 6, 16, 27, -22, -8, 5, 24, 27, + 0, 4, -5, -5, -2, 15, 12, 12, 2, 13, 0, -19, -26, 4, -19, -24, + -33, -21, -28, 0, 6, 18, 20, 15, 40, 2, -8, 17, 21, 47, -2, -12, + 11, -9, 22, -19, 3, -27, -29, -10, -38, -36, -42, 33, 12, -29, 10, -15, + 0, -1, -22, 24, 27, 8, 15, 7, 16, -13, 9, 33, 8, -4, 33, 70, + 21, -26, -18, -15, -22, -76, -2, 15, -35, -4, 8, 5, -3, -45, 6, 24, + -20, 6, -15, 8, -1, 2, 7, -4, 39, 4, 22, 34, -25, 26, -1, -31, + -4, 10, 2, 22, -25, -19, -2, -2, -44, -29, -17, 10, -6, 29, -8, 12, + 18, -9, -6, -36, 4, -14, -8, 10, -12, 28, 9, 16, 17, -29, 26, 0, + 1, 11, -13, 11, 1, 7, -7, -3, -5, 22, -10, 10, -29, 22, -29, -30, + 29, -30, 3, -43, 21, 5, -18, 6, -5, 23, 18, -31, 35, 28, -19, 9, + 13, 10, -3, -10, 37, -69, 7, 11, -16, 8, -76, 11, 58, -57, 18, -7, + -11, 26, -40, 100, -53, -1, 14, 3, -26, -35, 21, 20, -30, 10, -26, 37, + 25, -97, 118, -72, 37, 11, -15, 52, -22, 6, 85, -32, 24, -63, 48, -60, + -19, 3, -28, -19, 7, -28, 15, -22, 7, 20, -7, 16, -13, 8, 25, -27, + 2, 7, -18, 15, -30, 23, -3, 28, -31, 34, 22, -23, -6, -6, 28, -68, + -10, -3, -22, 12, -43, 70, -52, 32, 8, -4, 55, -14, 19, 21, 45, -13, + -33, -9, 20, -22, -14, 9, -21, -2, 6, -56, 17, -26, 23, -13, -8, -1, + 3, 31, 16, 20, -12, -10, 50, -27, -17, -13, -26, 29, -23, -7, 58, -40, + -20, 16, 16, -13, -65, 63, 18, -25, 23, -3, 6, 11, -11, -24, -19, 8, + 32, -44, 47, -50, 26, 6, 43, -58, 15, -21, 46, -81, 60, -28, 65, -37, + 42, 42, -55, -6, -23, -9, -52, -25, -5, 7, -67, 26, 59, -62, 31, 63, + -23, 52, -16, 27, 14, -13, 19, -41, -8, 37, -7, 9, -33, 16, 7, 36, + -40, -26, -26, 49, -3, 3, -50, 33, 23, -10, -13, -14, -19, -13, 1, 2, + -41, -19, 32, -3, -29, 9, 58, 1, 9, 15, 19, -19, 59, 2, 6, -6, + -24, 52, -67, 3, 5, -37, 3, 31, -42, 45, -1, -31, -6, 19, 11, -17, + -5, -2, -22, 3, -35, 35, -39, 8, 17, 6, 7, -32, 2, -1, 40, -32, + -2, 26, -5, 2, -5, -12, 18, 21, -15, 29, -28, 13, -23, 36, 28, -75, + 55, -53, 50, -45, 9, -3, 42, -10, -33, 8, -9, -17, 8, 13, -13, 34, + -48, 39, -5, -26, 24, 19, -34, 29, -41, 22, -42, -11, -15, 37, 0, -31, + 15, 4, 11, 18, -28, 23, -3, -52, 33, -1, -8, 19, -39, 44, -3, -16, + 31, 7, -17, 38, -44, 62, -21, 0, -7, -13, 25, 12, -50, -13, 2, 9, + -47, 43, -29, -12, -3, -3, -37, -22, 0, -6, 60, -69, 27, 9, 12, 13, + -7, 46, 43, -2, 3, -5, -5, 17, 13, -37, 35, -39, -38, 33, -44, -10, + 11, -9, 50, -68, 26, -22, 10, -20, 34, -13, -17, 21, -34, -1, 42, -23, + -7, 9, 3, 1, -1, -9, 36, -15, 5, -21, 40, -47, 25, -11, 20, 24, + -19, 16, -13, 6, -25, -2, 19, -17, 7, -36, 28, -8, -28, -11, 9, 25, + -55, 7, 39, -36, -3, 8, 28, 25, -33, 29, 1, -28, -1, -7, 40, -50, + 22, 15, 21, -2, -1, 18, 8, 46, -52, -1, 14, -39, -10, 18, -10, -27, + -15, -9, 2, -7, -47, 23, 17, -40, 12, 37, -24, 22, 9, 5, 27, -14, + -17, -17, 23, 16, -18, 19, 32, -19, -10, 13, 12, -33, 31, -4, 12, -17, + 22, -3, -8, -33, 16, -45, -17, -13, -24, 23, 19, -22, 52, -63, 23, 26, + 8, -11, 30, 40, -35, 28, -5, 11, -10, -16, 18, -35, -21, -6, 9, 0, + -33, 9, -15, -24, 15, -23, -19, 30, 13, -20, 37, 24, -48, 47, 21, -31, + 51, -22, 40, -24, 47, -55, 31, -21, -57, 15, -7, -28, 5, 25, -12, -42, + 46, -43, -21, 6, 4, 14, -15, 11, 51, -27, 6, 21, -27, 42, 17, -35, + 3, 3, -15, 11, 17, -26, 0, 6, 11, 18, -37, 4, 28, -14, -14, -30, + 43, -50, -17, 55, -50, 16, -32, 51, -35, -13, -4, 54, -22, 23, -48, 51, + 2, 10, -16, 7, -10, 15, -48, 25, -5, -4, 6, 21, -17, -2, 30, -23, + 16, -3, -12, -11, 21, -57, 3, 10, -3, 0, -19, 36, -42, 50, 0, -30, + 55, -15, 12, -10, 28, -47, 29, -16, 6, -37, -1, -6, 3, -45, 35, -30, + 8, -4, -12, 32, 42, -23, 3, 5, 30, -38, 15, 16, -36, 60, -1, -53, + 28, -25, -10, 45, -20, 2, -22, 24, -6, -19, -31, 18, 6, -56, -15, -3, + -5, 1, 12, 5, -7, 70, -9, -7, 49, -31, 48, 36, -15, 5, -23, 35, + -51, 4, -32, -40, 7, -20, -15, -7, 17, -32, -2, 17, 1, -8, 46, -4, + 12, 15, 41, -50, 29, -21, -13, 10, -20, 12, 2, -24, 12, -1, 6, 8, + -29, 19, -27, 51, -67, 83, -44, -22, 21, -2, -14, 13, -52, 72, -37, 19, + -25, 43, -37, -22, 19, -12, -36, 14, 17, -3, 27, -39, 58, -23, 1, 14, + 52, -25, 15, -1, 1, -23, -11, -9, 4, 14, -83, 23, 4, -38, -21, 2, + -1, 17, 2, 48, -30, 24, 29, 9, 19, -44, 46, 22, 5, -32, 39, 0, + -28, -27, 16, -32, -31, 7, -17, -13, -9, -6, 14, -33, -18, 35, -39, 52, + -40, 31, 12, 14, -24, 52, -35, 11, 1, 26, 10, -18, 20, 7, -7, -5, + 7, 5, -15, -10, -7, 8, -10, -26, 21, -16, -14, 13, -27, 27, -44, 6, + 18, 6, -12, -4, -11, 12, -1, 7, 6, 3, 20, -5, 11, 15, 9, -10, + 37, -37, -3, 11, -23, 9, -35, 19, -32, 4, 14, -28, 41, -42, 43, -5, + 11, -20, -16, 20, -10, 6, 6, -4, 1, -6, 7, 20, -42, 25, -29, 34, + -31, -10, 14, -4, -9, -4, 13, 7, -7, -2, -19, 25, -10, 0, 16, -1, + -9, -6, 53, -52, 10, -7, 5, -10, 1, 4, 9, -24, 10, -21, 61, -40, + 3, 3, 12, -38, 31, -3, -7, 8, -13, 8, -15, 4, -33, 44, -29, 5, + 5, 37, -52, 16, -13, 25, 7, -34, 17, -7, 14, -11, 24, -32, 22, -23, + 42, 5, -30, 21, 19, -21, 2, -11, 14, -18, -16, -34, 41, -30, 7, 2, + -23, 20, -37, 26, -17, 18, -37, 64, 0, 14, -19, 5, 12, -8, -13, 22, + -9, -26, 24, 17, -8, 3, -5, -14, -14, 17, -30, 14, 26, -67, 38, -9, + -20, 11, 11, -22, 11, 15, 1, 11, -22, 0, 1, 38, -43, 2, 15, -31, + 2, -5, 29, -18, -27, 21, -8, 15, -20, 46, -24, 20, 16, -7, 24, -63, + 40, -8, 9, -8, 14, -10, -11, -28, 4, 10, 8, -26, 13, 11, -35, -1, + 40, -36, -5, -3, 38, -7, -23, 3, 4, 17, 3, -15, 11, 24, -67, 26, + 2, 21, -54, 30, 14, -34, 12, 25, -16, 12, -13, -7, 47, -24, -23, 7, + 18, -4, -19, 31, -18, -14, -11, 21, -15, 5, -31, 40, -53, 21, -4, 30, + -32, -3, 14, -5, 30, -17, 3, 13, 8, -4, -5, -11, -12, 8, -7, 16, + 10, -21, 35, -59, 13, 10, -3, -7, 1, 2, -16, -4, 27, -43, 35, -16, + -14, 36, 0, -51, 13, 31, -19, 14, 21, -19, 14, -3, -27, 29, -10, 34, + -46, 30, -12, -17, 11, -34, 23, -23, 10, -3, 4, -8, -14, 25, -16, 35, + -12, 22, -7, 3, 9, 0, 11, -5, -10, -16, 9, -21, 7, -36, -4, -13, + 4, -6, -7, -2, -1, 0, 14, 16, -15, 7, 27, -28, 43, -32, 17, 7, + -25, 33, -7, 6, -10, 11, -20, 1, 5, 28, -11, -26, 20, -17, 29, -40, + 1, -6, 13, -23, 23, -23, -28, 18, 5, -22, 16, -19, 41, -9, -16, -11, + 45, -17, 6, -51, 34, 36, -44, 29, -33, 22, -13, 3, 5, -26, 2, 11, + 23, -17, 0, -7, 12, 3, -27, 18, 13, -2, -30, 22, -6, 7, 1, -4, + 5, -1, 12, -14, 1, -15, -5, 12, 6, 3, -13, 15, -14, 14, -1, -12, + 3, 3, -4, -18, 7, 2, -7, -5, 9, -15, 7, 17, -27, 45, -52, 60, + -15, -12, -9, -11, -14, 27, -18, -9, 21, -10, 10, 3, -23, -4, 8, -23, + 19, -31, 12, 18, 12, -7, 1, 15, 3, 27, -38, -7, 42, -9, 1, -7, + -22, 5, -10, 0, -28, 5, 12, -6, 0, -12, -15, 18, 19, -14, -27, 47, + -6, -1, -21, 32, -31, 52, -41, 3, -39, 34, -29, 16, 8, -6, 33, 16, + -23, -10, 16, 9, 2, -33, 40, 0, -21, -2, -18, 1, 13, -32, 24, -11, + -14, 24, -20, 0, -19, 11, 23, 1, -30, 4, 38, -23, 11, 0, 9, 18, + -36, 10, -21, -1, -5, -1, 23, -24, 9, 27, -13, 4, -39, 60, -17, -11, + -12, 25, -9, -36, 26, -7, -3, 28, -27, 26, -12, -20, 8, 13, -40, 7, + -23, 38, -33, 14, 8, -1, -23, 36, -19, 15, 13, -36, 4, 17, -32, 31, + -23, 20, 0, 23, -3, 5, -17, -11, 12, -24, 21, -29, 34, -26, -1, 4, + -14, 21, 9, -1, -1, 21, -33, 29, 1, -28, 28, -20, 22, -24, -13, -13, + -6, 10, -22, 33, -49, 17, -24, 1, 22, -11, 43, -27, 28, 28, -33, 36, + 5, -5, 2, 22, -28, 16, -24, -16, 4, -69, 66, -47, -12, 19, -17, -1, + 24, -32, 46, -36, -3, 50, -26, 24, -22, 9, 39, -53, 0, 32, -1, -21, + 29, -26, -4, 29, -45, 12, -10, 11, -12, 20, -23, -11, 20, 10, -1, -24, + 33, -16, 12, 2, 4, 14, -17, -17, 20, -42, 6, -18, 0, -4, -10, 11, + 2, -10, 4, 7, 2, 27, -35, 11, 12, 4, -11, 19, -19, 40, -6, -16, + 44, 2, -10, 32, -37, 1, -23, -8, 23, -59, 11, -5, -9, -9, -1, -8, + 5, -18, 26, -14, 27, -10, 9, 30, 23, -31, 30, -1, -1, -14, -13, 35, + -76, 42, -79, 43, -29, 1, 2, -5, -6, 5, 30, 15, -20, 23, 25, -37, + 39, -5, -20, 24, -7, 2, 20, -38, 20, -31, -12, -2, -12, 13, -31, 10, + -9, 0, -11, 27, -16, 10, -2, 44, -46, 18, 33, -16, -12, 3, 11, 15, + -26, 8, -22, 19, -3, -11, 5, -48, 31, 16, -15, -5, -2, 17, 6, -9, + -8, 9, 25, -7, 0, 7, -8, -5, 10, -11, -26, 26, -15, 17, -31, -11, + 15, -1, -16, 1, 10, 4, -7, 18, -6, 2, 11, -2, 11, -26, -4, 25, + -27, -19, 7, 29, -29, 13, -10, 3, -27, 31, -55, 38, -13, 17, -9, 32, + -27, 17, 18, -3, -10, 17, -45, 58, -12, -18, 25, 4, -40, 35, -61, 10, + -3, 2, -15, -14, 33, -20, -2, -4, -19, 31, -29, 25, 8, -11, -3, 32, + 1, -26, 12, 25, -42, 5, 27, 1, 2, 17, -25, -2, 6, 9, -17, 9, + -11, 9, 9, -21, 11, 15, -55, 34, -24, -6, -1, -9, 17, -13, 1, -11, + 31, -24, -15, 38, -21, 27, -30, 30, -35, 28, 15, -30, 56, -40, -17, 39, + -9, -7, 4, -18, 7, 13, -25, 3, -9, -13, -13, 27, -35, 13, 0, 6, + -3, 26, -20, 27, -23, 25, -25, 38, -2, -3, 8, -11, 0, 0, 0, -28, + 28, -27, -6, 23, -33, -8, -1, -29, 0, 2, 26, -40, 15, 2, 23, 28, + -32, 17, 26, -17, 10, 1, -14, 17, 1, 14, -9, -10, -15, 12, -3, -19, + 2, 20, -19, -19, -14, 4, -2, -8, 13, -16, 22, -9, 28, 7, -9, -22, + 49, -28, 3, -5, 9, -2, 5, -26, 39, -12, -29, 19, -11, 7, -33, 27, + -32, 15, -9, -9, 16, -7, -3, 27, -4, -18, 19, 23, -20, 3, 2, 11, + -21, 14, 4, -13, 8, -15, 9, 4, -37, 9, -11, 22, -20, -12, 17, 12, + -20, -2, 13, 18, -19, -1, 19, -28, 12, 2, 12, 2, -37, 12, 21, -19, + -23, 17, 21, -35, 9, 26, -20, -15, 12, 14, 23, -20, 17, 9, -16, -4, + 5, 3, -8, -24, 13, -5, 5, -7, -11, 31, -24, -34, 28, -8, -26, 16, + -7, 2, -2, 9, -21, 42, -54, 34, 42, -22, 16, -1, 14, -15, -12, 21, + -16, -3, -18, 55, -46, 11, 6, -19, 18, -36, -9, 12, -21, 23, -41, 37, + -12, -10, 1, 13, -5, -7, 42, 2, 1, -2, 4, -3, 15, -53, 27, -3, + -26, -14, 32, -30, -5, 11, 12, -3, -4, -24, 35, -37, 12, 4, 5, -17, + 32, 0, -18, 41, -41, 43, -2, 22, -36, 7, -5, 11, -25, 7, -29, 9, + 2, -4, -11, 5, -2, 15, -31, -11, 24, 3, -15, 26, 11, -10, 18, 5, + -8, -2, -43, 43, 2, -43, -20, 25, 4, -3, 39, -11, -6, -3, -1, -12, + 22, -21, 6, 22, -7, -17, -5, 18, -4, -14, 3, 18, -11, -18, -3, -2, + 2, -5, 1, 10, -28, 17, 8, -8, -12, 23, -13, 10, 0, -12, 14, 11, + -11, 34, -21, 3, 1, -9, -17, 1, 9, -28, 5, -34, 21, -8, 8, 8, + -13, 18, 2, -15, 5, -3, 11, -2, 11, -2, 15, -10, 14, 5, -1, 18, + -6, 1, -26, 13, -25, 2, 6, -39, -14, 0, -5, 13, -22, -14, 34, -22, + -1, 16, -13, 11, 32, -10, 31, -5, 18, -21, 34, -47, 32, -9, 10, 8, + -31, 5, 4, -9, 5, -52, 16, -14, 4, 20, -11, -13, 13, -10, -12, 11, + 16, -20, 13, -12, 14, 10, 1, -15, 32, -24, 18, 0, 5, -26, 6, 16, + -23, -10, 12, -40, 17, -14, -13, 38, -5, 5, -19, -3, 17, 14, -8, 8, + -15, 21, -6, 10, -12, -16, 27, 6, -35, 16, -26, 45, -25, -1, -9, 29, + -25, 8, -31, 9, 25, -10, 4, 11, -22, -5, 1, -12, 6, -10, -11, 17, + -31, 5, 21, -6, 33, -55, 47, 6, -6, 2, 11, 14, -11, 10, -14, -26, + 8, -18, 4, 11, 6, -4, -2, -20, -2, -26, 38, 4, -24, -6, 7, 22, + -15, 30, 0, 13, 3, -11, 4, -10, -28, 38, -14, -9, -5, -45, 40, -21, + -28, 31, 0, -9, 18, -45, 20, 12, -20, 39, -25, 14, 1, 17, -4, 29, + -12, 26, -8, -21, -19, 10, 3, -31, 34, -16, -12, 5, -14, -4, -13, 13, + -7, 13, -15, -23, 40, -27, 15, 4, -11, 23, -20, -2, 7, 8, 3, 2, + -4, 1, 7, -22, 42, -37, 24, 1, -9, 16, -31, 9, 6, -3, -25, 40, + -41, 0, 2, -7, 18, 0, -10, 21, -5, -17, 29, -37, 27, 3, -22, 10, + 11, -5, 13, -17, 15, -19, -23, 17, -10, -35, 20, 4, -4, 3, -10, 7, + 15, -14, 10, -3, 10, -25, 13, 1, 20, -13, 13, 19, -38, 18, -4, 19, + -10, 9, -27, 19, -35, -8, -10, 39, -14, 2, 14, 36, -16, -8, -8, -7, + -2, -11, 4, 1, -42, 51, -17, 10, -15, -33, 29, -25, -7, 6, 2, 11, + 3, -20, 37, -28, 6, 34, -22, 5, 28, -4, 17, 5, -47, 28, 1, -3, + -21, 8, -6, -7, 10, -15, 6, -30, 6, -19, 1, -4, 30, -22, 29, -13, + -4, -2, 11, -1, -15, 38, -4, -9, 25, -29, -17, 10, -2, -3, 7, -15, + 24, -26, 21, 2, 6, -20, 10, -26, 41, -33, 19, -11, 6, -3, -9, 5, + 3, -21, 8, -5, -7, 10, 13, -10, -3, -4, -10, 26, -1, 1, 5, 11, + -3, 2, 23, -35, 21, -43, 17, -4, 2, -24, 14, -22, -3, 3, -5, -2, + 12, -13, 16, -5, 7, 17, 4, -44, 26, 17, -4, 36, -58, 43, -20, 8, + 3, -23, -18, -17, 16, 4, 3, -33, 15, -4, -10, 19, -20, 23, 13, -6, + -4, 25, -12, 21, -9, -4, 6, -1, 23, -7, -15, 3, -15, 3, -13, -23, + -3, -32, 4, 6, -18, 0, 11, -14, 42, -37, 26, -20, 50, -18, 18, 11, + 4, 18, -5, 8, -22, 30, 5, -20, 16, -20, -28, 2, 4, -10, -10, -10, + -27, 38, -38, 14, -17, -20, 34, -11, -5, -5, 10, 5, 25, -20, -2, 28, + -8, 26, -39, 68, -50, 53, -35, -5, 3, -23, 24, 8, -21, -28, 19, 6, + -18, -13, -7, 26, -7, 0, -4, 7, -7, -15, 29, -10, -12, 13, 9, -4, + -34, 39, -49, 38, -31, 29, -26, 2, -18, 45, 3, -16, -2, 29, 4, -27, + 2, 17, 6, -12, -3, 12, -12, -14, -22, 11, -13, 6, -2, 30, -39, 12, + 5, 10, -18, 3, -5, 24, -39, 15, 49, -42, 19, 9, -25, 5, -60, 31, + -19, -8, 9, 28, 28, -34, 21, -4, 25, 24, -18, 17, -35, 1, 7, -28, + 32, -29, 6, 7, 4, -23, 21, -17, -14, 16, -29, 21, -43, -24, 2, 58, + -33, 60, -20, 24, -29, 18, -24, 29, -14, -6, 10, -19, 15, 38, -38, 35, + -15, -11, 20, 9, -57, -4, 0, -8, 15, -8, -20, -6, 9, 21, 8, -21, + 12, 1, 6, -29, 24, 17, 6, -33, 26, 20, -12, 14, -17, 3, -2, -19, + -6, 13, -55, -5, 5, 8, 21, -12, 11, -13, 15, -34, 45, -47, 43, -6, + 5, 34, -32, 28, -15, 12, -38, 30, -16, 1, -4, -2, 6, 4, -26, 2, + 21, -42, 5, 19, -20, 44, -70, 38, -5, -4, -8, 20, -16, 22, -25, 46, + -21, 1, -31, 48, -32, 7, -23, 62, -48, 38, -2, -30, 41, -57, 41, -41, + 9, -5, 16, 9, 1, -50, 80, -48, 5, -20, 11, -9, -19, -8, 1, 20, + -24, 4, 36, -42, 42, -32, 39, 6, -12, 1, 12, 3, -17, 2, -13, 57, + -70, 26, 6, 0, -23, 8, 4, -17, -10, -41, 34, -10, -46, 51, 23, -10, + -4, -10, 16, -9, 4, 32, -14, 6, -7, 23, -18, -9, 5, -14, 4, 15, + -29, 10, 15, -14, 19, -28, 40, -30, -20, 17, 3, 5, 37, -32, 12, 0, + -18, 1, -7, -23, 4, -51, 69, -22, -43, 30, -39, 54, -64, 29, 21, -2, + 2, -22, 29, 2, 14, 5, 8, -7, 7, 34, 2, -25, 10, -7, -5, 24, + -64, -1, -18, -7, 23, -24, 26, -23, -35, -17, 51, -60, 53, -2, 14, 17, + 6, 5, 11, -9, 15, 21, -1, 21, -49, 45, -34, -16, 12, 0, -34, 2, + -67, 50, -48, 23, -20, -12, 20, -22, 32, -15, 15, -23, 65, -9, 33, 26, + -3, 4, 14, 8, -17, -17, -47, 57, -63, 13, 8, -30, -8, -31, -12, 28, + -45, 9, -3, 19, -31, 31, -2, 41, -46, 38, 38, -23, 21, -13, 9, 35, + -2, 5, 13, -36, -2, -10, 15, -16, -48, 22, 29, -49, -21, 15, -10, -15, + -23, 26, 40, -39, 26, -10, 13, 21, -46, 35, -20, 8, -1, 30, 17, -64, + 22, 2, 22, -30, 6, 19, -18, -34, 38, -4, 13, 0, -11, 50, -51, 21, + -10, 13, -42, -9, 45, 4, -82, 12, 37, -11, -12, -8, 21, 6, -33, 32, + -14, 6, 13, -44, 37, -22, 20, 2, 12, -15, 26, 30, -17, -11, -30, 18, + -4, -5, 11, -2, -22, -15, 25, -16, 11, -15, 21, -8, -17, -9, 27, 11, + -43, 2, 4, 31, -59, -5, 44, -16, 26, -13, 3, 1, -1, -40, 70, -44, + 43, -15, 2, 22, -36, 13, 41, -43, -12, 4, 12, -34, -22, 9, 22, -23, + -22, 27, -24, 22, -18, 45, 12, -32, 7, 17, -24, -15, 4, 20, 6, -40, + 29, 48, -64, 28, -3, -6, 43, -22, -34, 36, -41, 13, -2, -59, 72, -53, + 39, -30, -3, 16, 29, -40, 5, 30, -21, 15, -35, 9, 14, 2, 4, -16, + 4, 8, 14, 1, 30, -32, 5, -14, 28, -26, -1, -12, -16, -4, -22, -5, + 28, -8, -24, 7, 42, -22, -3, -9, 16, 38, -42, 25, 8, 10, -9, 38, + -28, 31, -8, -34, 22, -70, 21, 15, -36, -10, -15, -1, 49, -37, -17, 51, + -24, 11, 30, -27, 33, -39, -12, 36, -4, -49, 38, 12, 10, -17, -11, 59, + -26, -59, 33, 28, -37, 17, -39, 40, -16, -29, 28, 14, -19, -14, 18, 23, + -17, -16, 15, -11, 9, -16, 45, -25, -27, -1, 40, -36, 1, 19, -1, -14, + -3, 1, 29, -9, -58, 54, -12, -19, 16, 13, 29, -74, 48, -20, 22, -66, + 3, 23, 2, -31, 11, 41, -41, 2, 25, 4, 8, -3, 8, 23, -10, -6, + 27, -1, -67, 31, -29, 29, -29, 0, 17, -20, -18, -10, 29, -45, 43, -35, + 61, 4, -49, 31, -10, 53, -60, 19, 11, 15, -22, -3, -20, 26, 3, -60, + 59, -41, -26, 17, 22, 12, -6, -12, 30, -14, -8, -7, 16, 54, -34, -18, + 26, -15, -11, 7, -44, 39, -52, 48, -53, 18, -38, 3, 13, -11, 37, -12, + 11, 9, 14, -7, 40, -19, -6, 6, -15, 29, -34, 1, 18, -18, -9, -24, + -30, 17, -50, 31, 4, 8, 17, -7, -5, 0, 17, 25, 16, 15, 43, -54, + 39, -10, 2, -40, -23, 26, 3, -61, -2, 15, -6, -56, 46, -2, 16, -80, + 43, 52, -9, -30, 41, 17, 2, -33, -7, 52, -7, -29, 31, 0, -23, 10, + -24, 44, -82, 18, 45, -14, -40, -40, 40, 12, -66, 0, 74, -35, -5, 17, + 67, -59, 32, -4, 29, -1, -48, 39, 1, 8, -63, 43, -12, -37, -5, -12, + 25, 2, -21, 7, 24, -34, -11, 19, 28, 6, -34, 44, 13, -35, -19, 28, + -50, -13, 56, 7, -32, -12, 19, 6, -1, -6, 6, 0, 17, -26, 41, -20, + -5, -6, 43, -58, 10, -12, -14, 74, -84, 74, -28, -15, -27, 19, -15, -3, + 17, 24, 10, -60, 64, 0, -9, -39, 1, 25, -12, -25, 22, 8, -21, -40, + 73, -32, -18, -11, 6, 57, -52, 36, -19, 37, -40, 9, 2, 14, -15, 27, + -33, 35, 7, -37, 24, 10, -66, 17, 1, -10, 13, -38, 15, -9, 43, -30, + 19, -15, 17, -8, 7, 8, -38, 66, -55, 10, 9, -37, 37, -32, -11, 47, + -14, 11, 37, -41, -33, 12, 3, 34, -59, 35, 14, -4, -7, -2, -21, 48, + -52, 49, -8, -44, 0, 11, -6, -2, 11, -35, 64, -38, -35, 64, 7, -32, + 15, 15, 19, -39, 18, -31, 25, 6, -28, 25, 17, -34, -26, 21, -18, 15, + -15, -31, 24, -4, -26, 41, -2, -18, -24, 75, -21, 1, -6, -2, 16, 12, + -24, 15, 8, -14, 7, 7, -4, -37, 45, -67, 39, -41, 9, 19, 13, -60, + 44, -22, 23, 2, -35, 14, 35, -25, 7, 21, -39, 15, 1, 39, -43, 26, + -18, -14, 36, -10, -16, -15, 29, -34, 16, -1, -13, 24, 0, -43, 55, -18, + -31, 22, -15, -15, 43, -33, 50, -10, -43, 22, -27, 60, -30, 14, 0, 10, + -3, 10, -20, 11, -34, -7, 70, -59, -26, 25, -23, 7, -29, 8, 11, -13, + -8, 3, 13, -13, 35, -8, 34, -33, 9, 30, -5, 33, -37, -10, 56, -38, + -5, 14, -50, -24, 39, -11, -11, -27, -22, 46, -13, -6, -1, -6, 37, -56, + 48, -11, 24, -14, 32, -13, -1, 5, 8, 37, -86, 36, -1, -6, -12, 13, + -40, 3, 9, 15, -13, -23, 3, -15, 61, -50, -12, 29, -14, -2, 25, -31, + 52, -41, 31, 31, -27, -10, 9, 22, -15, 3, -11, 22, -25, 8, -40, 0, + -5, 2, -9, 40, -62, 5, 16, -6, -7, -21, 31, 29, -28, -3, 47, -31, + 51, -34, 59, -32, -8, 44, -7, -2, -20, 3, 64, -51, -58, -3, 0, -39, + 26, -22, 14, -39, 8, 20, -30, -2, 7, 8, 37, 15, -9, 43, -5, 2, + 11, -5, 10, 2, -37, 56, -59, -11, 8, -14, -30, -29, -3, 29, -1, -33, + 42, -44, 53, -58, 85, -28, -5, -2, 41, 5, 15, -49, 30, 26, -46, 17, + 9, -55, 0, 38, -46, 32, -32, 10, 15, -60, 8, 23, -1, 7, -35, 71, + -11, -39, 39, -22, -8, -3, 10, 36, 13, -73, 53, -15, 7, -7, -15, 25, + -7, -24, 21, 9, -51, -11, 27, -15, 11, -6, 26, -26, 27, 16, -33, 47, + -29, -18, 53, -53, -2, 38, -29, 12, -37, 18, 10, -10, -20, -8, 12, 15, + -43, 32, 3, -44, 35, 29, -38, 17, -16, 13, 45, -37, 21, 18, -7, -38, + 32, -21, -6, -4, 20, -14, -9, -16, 14, 1, -19, -13, 22, -4, -39, 58, + -34, 3, 17, -10, 50, -3, -47, 36, 29, -27, -13, 39, -20, -8, 12, -40, + -20, 1, 0, -24, 23, -40, 38, 4, -1, -19, 16, 10, -4, 28, -25, 44, + -17, 19, -21, 50, -10, -16, -13, 7, -28, 11, -9, -17, 13, -52, 22, -3, + -21, -49, 75, -42, 34, -3, 18, 1, 10, -20, 13, 13, 22, -11, -35, 46, + -29, 44, -39, -31, 37, -22, -27, 42, -57, 40, -34, 4, 12, 9, -29, 13, + 6, -10, 4, 21, 7, -17, 3, 25, -18, 44, -26, -1, 20, -38, 19, 24, + -35, -18, -6, -14, 23, -32, -15, 24, -6, -50, 62, -39, -3, 0, -23, 87, + -44, 37, -9, -4, 67, -73, 46, 45, -32, -14, 8, -4, -22, -5, -22, -20, + 36, -34, 6, 26, -35, -18, 15, 0, -12, 0, 12, -10, 28, -15, 24, 13, + -21, 19, 15, -17, 20, -7, 0, -21, 7, -16, 5, -12, -1, -11, 7, 32, + -68, 69, -55, 24, 2, -3, 21, -47, 28, 20, -15, -29, -2, 23, 4, -18, + 15, -22, 36, -38, 17, -23, 14, -18, 17, 31, -37, 30, 8, -1, -3, -5, + -12, 22, -18, -28, 33, 0, -9, -16, 20, 9, -26, -20, 21, 2, -4, 14, + -24, 16, -11, 12, -1, -39, 7, 51, -2, 1, -12, -30, 63, -43, -19, -2, + -6, 20, 10, -18, -2, 23, 15, -3, -34, 1, 9, 10, -22, -29, 28, 28, + -32, -2, 23, -26, 2, 11, 25, -35, -14, 15, 23, -48, 12, 7, 22, -52, + 25, 17, 16, -47, 29, 13, -19, 12, -67, 65, -6, -30, 32, 7, -12, 14, + -19, 27, -52, -2, 15, 40, -69, -5, 33, 15, 6, -51, 36, 21, -2, -24, + 15, -3, -9, -4, 30, -34, -2, -19, 27, -23, 3, -12, 2, 18, -15, -6, + -3, 22, -30, 55, -21, 26, -35, 44, -27, 25, -21, 4, 14, -20, -1, 10, + -42, 12, 7, -12, 5, -37, 13, 1, 3, -33, 24, 15, 0, -4, 10, -14, + -6, 35, -6, -4, -8, 13, 26, -7, -32, 36, -9, 5, -15, 14, -15, -36, + 8, 2, -15, -22, -7, 28, -4, -25, 17, 39, -16, 4, 20, 8, 4, -2, + 4, 31, -46, -12, 15, 0, -9, -36, 18, -10, -12, 7, -17, 3, -13, -4, + 37, -27, 6, -16, 76, -41, 13, -14, 25, 28, -21, -10, 31, -4, -39, 21, + -9, -35, 12, 3, -16, 7, -54, 51, -34, 44, -45, 30, -7, -30, 49, -21, + -1, 27, 12, -8, 9, 8, 5, -27, 42, -30, 32, -28, -27, 19, -18, -36, + 10, -25, 19, -9, -14, -5, 13, 31, -21, 22, -28, 15, 13, 10, -12, 6, + 32, 1, 24, -47, 36, -4, -23, 0, -16, 6, -41, 1, 17, -33, -9, 5, + 34, -5, -15, -1, 30, 13, -30, 20, 7, -12, -16, 11, 20, -4, -19, 21, + 26, -25, -17, -5, 23, -32, -3, -12, 18, -5, -28, 8, 15, -14, -10, 31, + 11, -43, 12, 35, -5, 3, -33, 48, -1, -11, -6, 28, -23, -13, 13, 9, + -7, -22, 2, -25, 32, -38, 17, -16, 10, -54, 69, -62, 61, -30, 4, 24, + 3, -12, 4, 27, -22, 22, 0, 4, -15, 4, -46, 20, -16, 29, -30, 14, + -25, 30, -18, 16, -12, -7, 21, -10, 16, -23, 15, 9, -12, 12, 13, -21, + 19, -28, -2, 5, -15, 0, 3, -17, 6, -6, 18, -11, 6, 13, -1, 15, + -23, 14, 5, -17, -14, 5, 24, -23, 15, -26, 9, -10, 15, -29, 2, -12, + 23, 8, 10, -37, 26, 7, -5, -25, 3, 16, 14, -10, -5, -16, 22, -7, + -8, 18, -58, 86, -15, -5, 4, -30, 40, -7, -21, -12, 9, -10, 16, -48, + 40, -29, -6, -5, -22, 21, 3, -20, 39, -36, 29, -5, 2, 3, 15, 2, + 6, 21, -11, 28, -13, 2, -33, 24, 1, -28, 12, -33, 12, 11, 0, -41, + 11, -5, -9, 26, -34, 15, 2, 18, -7, -25, 5, 11, -4, -7, 35, -6, + 23, 12, -42, 33, -32, 26, -41, 25, -23, 15, -13, 11, -5, -4, 0, -8, + -4, 1, 10, 6, -8, -7, 18, 8, -11, -19, 9, 17, -2, -13, 8, -21, + 31, -16, -24, 3, -12, 10, 23, -8, 12, 8, 23, -7, -22, -8, 5, -5, + -14, -33, 4, 7, -11, -11, 15, -22, 38, -2, -11, 24, -16, 38, 14, -6, + 7, -14, 18, -13, 2, -8, -14, 13, -19, -13, 2, 2, -23, -9, 11, 1, + -12, 16, 1, 2, 18, 1, -20, 9, -5, -14, 16, -11, 2, 8, -2, -9, + 0, 11, 13, -22, 18, -16, 35, -39, 45, -22, -18, 12, 1, -19, 21, -48, + 42, -20, 9, -23, 20, -11, -27, 21, -13, -14, -11, 29, -13, 25, -25, 36, + -13, 8, 17, 34, -14, 11, 4, -4, -15, -9, -12, 1, 19, -69, 7, 10, + -34, -20, 1, -5, 13, 6, 34, -17, 5, 40, -1, 21, -38, 35, 22, 11, + -28, 28, 11, -25, -26, 12, -20, -38, 10, -16, -11, -11, -6, 13, -22, -31, + 43, -42, 49, -33, 20, 17, 13, -22, 44, -21, -4, 14, 9, 33, 10, 0, + -1, 0, 0, -2, 11, 23, 22, 24, 25, 20, 21, 15, 40, -1, -24, -42, + -5, -19, -11, -8, 4, -46, -31, -14, -33, -40, -44, -48, -89, -63, -47, -33, + -27, -10, -6, 22, 25, 26, 28, 37, 11, 15, 51, 44, 54, 66, 66, 71, + 111, 84, 70, 63, 47, 39, 22, 47, -28, -79, -111, -90, -91, -112, -81, -87, + -49, -46, -5, -24, 26, 24, 47, 29, 23, 30, 30, 13, -1, 4, -14, 17, + 35, 62, 31, 53, 59, 72, 64, 27, 26, 9, 9, -61, -44, -88, -74, -81, + -83, -124, -96, -37, -78, -48, -56, -68, -60, 7, 44, 39, 54, 77, 102, 110, + 108, 89, 101, 100, 105, 64, 22, -1, 44, 40, -19, -29, -35, -16, -27, -40, + -77, -82, -113, -104, -93, -57, -72, -56, -3, 1, 7, -1, 49, 39, 30, 31, + 23, 10, 31, 11, 7, -19, -2, -2, 28, 62, 92, 75, 33, 34, -20, -47, + -61, -85, -105, -93, -119, -112, -54, -70, -67, -32, -1, 4, 4, 20, 29, 62, + 70, 54, 62, 78, 115, 92, 85, 78, 52, 21, 19, 27, 2, -8, 13, 0, + 5, 3, 9, 18, 0, -59, -61, -45, -57, -65, -76, -89, -102, -48, -24, 17, + 6, 26, 33, 35, 26, 41, 63, 20, 12, 29, 34, 8, 7, 31, 21, 31, + 39, 33, -5, -8, -55, -57, -98, -94, -88, -64, -82, -74, -39, -14, 3, 16, + 22, 8, 2, 17, 5, 36, 76, 74, 71, 57, 73, 62, 47, 30, 32, 19, + 4, 7, -14, -18, -2, 17, -5, 13, 22, 31, 10, 8, -13, -47, -80, -85, + -86, -71, -73, -60, -35, -10, 9, 19, 49, 53, 47, 60, 73, 43, 33, 20, + 13, -1, -7, -7, 7, 9, -2, 5, -14, -40, -69, -61, -66, -67, -84, -58, + -58, -33, 2, -7, -5, 12, 32, 18, 25, 19, 24, 65, 59, 62, 64, 63, + 55, 60, 52, 31, 19, -12, -26, -4, -7, -10, -3, 6, -22, -14, 12, 19, + 4, -26, -38, -40, -56, -61, -66, -59, -65, -51, -20, 29, 40, 51, 52, 62, + 61, 53, 26, 20, 6, 8, 6, 9, -14, -14, -15, -2, -11, -23, -36, -38, + -60, -77, -69, -60, -51, -56, -44, -27, 10, -2, 14, 10, 22, 16, 41, 60, + 39, 35, 60, 62, 43, 45, 63, 52, 17, 12, 15, -1, -2, 0, -38, -48, + -32, -22, -7, 3, 13, 10, -2, -1, -8, -12, -25, -48, -46, -52, -49, -36, + -17, 9, 17, 26, 48, 57, 55, 69, 60, 32, 6, 4, -6, -20, -24, -9, + -21, -25, -14, -18, -38, -38, -32, -51, -52, -60, -34, -6, -6, -16, -11, -2, + -1, 17, 19, 3, 11, 25, 31, 41, 39, 33, 33, 41, 34, 34, 23, 21, + 15, 6, -13, -24, -28, -20, -8, -12, -19, -12, -5, 9, 14, 2, -12, -25, + -28, -21, -28, -23, -22, -18, -26, -5, 24, 45, 46, 47, 39, 33, 36, 42, + 29, 7, -5, -10, -21, -29, -39, -39, -31, -24, -29, -39, -51, -43, -27, -22, + -18, -25, -26, -20, 9, 19, 18, 4, -2, 19, 30, 38, 25, 24, 28, 33, + 41, 38, 34, 32, 38, 24, 8, 4, -8, -11, -15, -25, -31, -25, -20, -22, + -15, -11, -9, -12, -17, -20, -20, -15, -6, -11, -8, 0, 11, 29, 19, 17, + 17, 18, 28, 31, 25, 18, 23, 18, 10, 1, -7, -18, -26, -24, -30, -41, + -38, -44, -32, -31, -31, -35, -25, -12, -2, -8, -11, -13, -13, -2, 8, 15, + 19, 29, 35, 37, 39, 43, 42, 40, 35, 27, 25, 18, 15, 9, 4, -4, + -15, -28, -28, -26, -28, -18, -15, -25, -23, -12, -11, -14, -10, -2, -4, -1, + 8, 15, 19, 22, 25, 16, 16, 17, 5, 7, 13, 18, 13, 9, 6, 6, + 4, -4, -21, -31, -28, -37, -39, -34, -38, -38, -32, -17, -6, -4, -14, -19, + -9, 3, -2, 3, 4, 7, 8, 13, 23, 35, 38, 43, 42, 31, 25, 23, + 17, 8, 3, 4, -7, -7, -10, -13, -20, -19, -28, -33, -30, -23, -18, -13, + -17, -12, 3, 14, 23, 31, 27, 23, 21, 22, 19, 12, 4, 2, 2, -2, + 0, 4, 11, 11, 6, 4, -2, -5, -14, -17, -30, -38, -44, -42, -28, -21, + -23, -21, -15, -15, -4, 8, 11, 4, -7, -15, -7, 5, 10, 21, 26, 28, + 27, 34, 37, 36, 28, 19, 10, 11, 8, -2, -18, -17, -19, -19, -22, -24, + -21, -24, -18, -17, -13, -19, -13, -1, 12, 19, 22, 21, 19, 19, 30, 34, + 24, 13, 7, 2, 1, 1, 2, -1, -2, -6, 0, 0, -2, -15, -21, -17, + -21, -28, -32, -31, -31, -32, -27, -24, -17, -4, 1, -3, -1, 1, 4, 7, + 8, 15, 16, 15, 15, 20, 32, 36, 38, 32, 19, 12, 3, 2, -2, -4, + -11, -19, -17, -15, -11, -16, -20, -27, -30, -28, -22, -13, -6, -2, 2, 12, + 23, 29, 45, 44, 36, 32, 21, 16, 14, 10, 1, -9, -8, -2, -1, -7, + -13, -13, -12, -9, -11, -18, -24, -26, -28, -30, -24, -21, -21, -21, -11, -11, + -10, 0, -2, 0, 4, 12, 13, 14, 12, 17, 22, 28, 30, 28, 20, 16, + 13, 8, 2, -2, -6, -15, -14, -18, -15, -15, -16, -18, -18, -16, -19, -18, + -17, -10, 0, -1, 4, 13, 22, 37, 39, 36, 27, 27, 32, 26, 15, 6, + -1, -4, -5, -7, -11, -11, -9, -15, -15, -14, -18, -21, -19, -17, -21, -19, + -15, -15, -10, -15, -14, -12, -11, -6, -2, 1, -2, 1, 5, 14, 22, 33, + 35, 23, 18, 16, 13, 11, 6, 1, -9, -18, -11, -6, -7, -8, -9, -11, + -11, -12, -13, -17, -21, -24, -24, -15, -4, 7, 12, 17, 25, 30, 28, 31, + 32, 31, 27, 22, 15, 12, 3, -2, -8, -6, -3, -9, -13, -22, -24, -20, + -18, -22, -24, -18, -14, -13, -10, -11, -9, -3, -2, -3, -5, -10, -10, -5, + -1, 4, 11, 15, 19, 22, 27, 23, 20, 16, 14, 5, -3, -11, -15, -16, + -12, -12, -11, -5, 1, -3, -10, -13, -15, -11, -10, -10, -11, -8, -3, 2, + 7, 9, 15, 25, 30, 33, 31, 25, 21, 20, 16, 13, 7, -2, -8, -5, + -4, -11, -20, -21, -22, -21, -17, -20, -21, -22, -19, -19, -11, -4, -2, -2, + -2, 2, 5, 2, 0, 0, -3, 1, 8, 16, 13, 14, 17, 15, 13, 8, + 5, -1, -6, -10, -13, -14, -14, -13, -10, -7, -8, -8, -6, -6, -3, -1, + -1, -9, -12, -7, 3, 13, 17, 14, 13, 17, 22, 23, 24, 18, 15, 18, + 18, 18, 15, 8, 0, -5, -8, -11, -15, -17, -21, -26, -26, -24, -26, -24, + -13, -9, -6, -3, -2, 3, 4, 6, 7, 5, 2, 4, 2, -2, -4, -3, + 5, 13, 17, 10, 3, -1, -2, -4, -5, -11, -14, -13, -11, -8, -8, -8, + -6, -3, 0, -1, -5, -5, 0, 4, 3, 1, 2, 0, 0, 6, 13, 20, + 17, 17, 18, 21, 18, 14, 13, 11, 11, 7, 9, 3, -5, -12, -14, -18, + -21, -23, -26, -26, -13, -3, -6, -13, -14, -5, 5, 8, 3, 0, 1, 3, + 6, 4, -1, -1, 1, 3, 7, 5, 3, 0, 1, -1, 3, 0, -3, -11, + -11, -9, -10, -9, -8, -5, -7, -7, -10, -9, -6, -1, 4, 6, 4, 2, + 5, 10, 13, 9, 12, 13, 14, 15, 16, 13, 12, 10, 13, 14, 13, 8, + 2, -1, -4, -6, -9, -15, -20, -21, -19, -14, -16, -22, -21, -13, -5, -3, + -3, -1, 3, 5, 10, 9, 9, 6, 8, 7, 7, 7, 3, -4, -6, -4, + -1, -4, -8, -10, -11, -8, -4, -6, -10, -7, -8, -11, -11, -8, -5, -4, + 0, 3, 3, 8, 10, 10, 12, 12, 11, 10, 13, 12, 10, 6, 8, 9, + 9, 11, 13, 11, 9, 10, 7, 2, -3, -8, -9, -14, -16, -16, -19, -18, + -14, -13, -11, -11, -10, -5, -1, 3, 5, 2, 2, 9, 14, 11, 9, 10, + 7, 2, 0, 2, -2, -9, -13, -15, -18, -17, -15, -13, -10, -5, -5, -7, + -7, -4, -1, 0, -2, -4, -2, 1, 4, 9, 10, 10, 11, 11, 13, 14, + 10, 11, 9, 9, 4, 6, 5, 4, 5, 7, 8, 10, 9, 4, -4, -8, + -9, -10, -11, -12, -14, -15, -17, -15, -9, -4, -1, -6, -5, 2, 8, 8, + 6, 5, 3, 4, 5, 9, 10, 10, 5, -1, -5, -10, -12, -14, -16, -18, + -17, -11, -10, -11, -8, -5, -2, -2, 0, 3, 4, 5, 3, 2, 3, 5, + 9, 12, 12, 11, 10, 12, 14, 12, 8, 5, 0, -1, 1, 3, 0, 1, + 3, 5, 6, 5, 0, -5, -11, -10, -13, -12, -13, -15, -14, -8, -4, -3, + -3, -4, 0, 4, 5, 3, 6, 4, 4, 7, 10, 9, 9, 8, 5, 5, + 2, -4, -10, -15, -17, -20, -22, -22, -19, -14, -11, -10, -8, -6, 0, 3, + 5, 3, 4, 8, 11, 11, 12, 13, 12, 12, 15, 15, 16, 16, 13, 11, + 6, 3, -2, -5, -5, -3, -2, -1, 2, 0, -3, -4, -5, -7, -10, -12, + -11, -12, -11, -8, -4, -2, 0, 1, 2, 2, 2, 4, 3, 3, 4, 5, + 9, 10, 6, 2, 1, 2, 0, -3, -7, -13, -18, -19, -18, -16, -18, -20, + -19, -14, -8, -4, -1, 3, 3, 5, 7, 9, 9, 10, 12, 13, 13, 13, + 13, 16, 15, 13, 9, 6, 3, 2, 1, 0, -3, -5, -6, -4, -2, -2, + -4, -4, -5, -5, -3, -3, -4, -6, -6, -7, -4, 0, 2, 3, 2, 2, + 1, 2, 2, 1, 4, 5, 4, 1, 0, 2, 2, 0, -2, -6, -8, -6, + -7, -9, -11, -15, -18, -19, -18, -18, -17, -13, -9, -2, 2, 3, 5, 10, + 12, 13, 14, 14, 15, 17, 17, 16, 16, 15, 13, 11, 7, 2, -6, -10, + -8, -6, -8, -8, -7, -6, -6, -3, -4, -6, -5, -3, -2, -2, 0, 1, + 0, 2, 2, 3, 2, 3, 2, 3, 3, 5, 2, 0, 4, 6, 5, -1, + -4, -2, -1, -2, -6, -8, -9, -10, -12, -10, -14, -17, -22, -22, -21, -19, + -15, -8, -3, 1, 7, 12, 12, 15, 19, 22, 21, 18, 16, 16, 16, 13, + 12, 6, 3, 3, 2, -3, -6, -7, -12, -12, -11, -8, -9, -8, -7, -3, + 0, 0, 0, 0, -2, -2, 0, 1, 2, 2, 4, 6, 6, 7, 5, 4, + 3, 4, 5, 3, 0, -2, -2, -4, -6, -10, -8, -8, -10, -11, -12, -12, + -12, -13, -16, -16, -16, -14, -11, -8, -4, -2, 1, 6, 12, 17, 19, 20, + 20, 21, 21, 19, 13, 10, 9, 5, 0, -3, -4, -4, -5, -6, -6, -4, + -7, -10, -12, -12, -12, -10, -7, -4, -2, 4, 6, 8, 7, 7, 7, 7, + 8, 8, 7, 5, 6, 6, 4, 1, -1, -1, 0, -3, -7, -10, -10, -8, + -11, -14, -14, -12, -11, -9, -6, -8, -8, -8, -11, -13, -12, -9, -8, -5, + 0, 4, 8, 11, 14, 18, 18, 20, 23, 23, 20, 14, 9, 4, 0, -3, + -6, -8, -8, -8, -8, -9, -10, -11, -10, -9, -8, -8, -7, -6, -3, 0, + 3, 6, 12, 16, 16, 14, 10, 8, 9, 7, 4, 1, 0, 0, -2, -1, + 0, 0, -3, -7, -10, -13, -13, -12, -13, -15, -14, -13, -9, -6, -5, -5, + -7, -8, -9, -7, -6, -5, -7, -5, 1, 8, 13, 17, 19, 20, 21, 22, + 22, 18, 12, 9, 5, -1, -5, -9, -11, -13, -12, -12, -11, -10, -8, -7, + -7, -6, -7, -6, -3, 0, 1, 3, 7, 10, 11, 12, 15, 15, 14, 9, + 6, 3, 1, 0, -2, -2, -2, -3, -6, -8, -10, -11, -13, -15, -15, -15, + -13, -12, -12, -7, -5, -5, -5, -4, -3, -3, -4, -4, -1, -1, 1, 4, + 7, 10, 12, 14, 17, 20, 22, 19, 14, 8, 5, 2, -2, -5, -10, -14, + -13, -11, -10, -10, -10, -10, -8, -6, -3, -3, -3, -1, -1, 2, 6, 10, + 13, 14, 15, 15, 15, 13, 11, 8, 5, 1, -1, -3, -3, -6, -10, -12, + -12, -12, -12, -13, -15, -18, -19, -15, -11, -6, -4, -3, -4, -4, -2, 1, + 4, 2, -1, -2, 1, 4, 6, 8, 7, 7, 11, 14, 15, 15, 15, 13, + 10, 6, 1, -3, -6, -9, -13, -15, -15, -13, -11, -9, -9, -9, -7, -3, + 0, 2, 2, 4, 7, 11, 15, 16, 14, 11, 12, 13, 15, 13, 9, 4, + 1, -1, -4, -6, -8, -11, -15, -17, -17, -17, -17, -15, -13, -13, -12, -10, + -7, -6, -4, 1, 2, 2, 3, 4, 5, 4, 4, 3, 5, 6, 6, 8, + 7, 7, 9, 11, 10, 9, 8, 5, 2, 0, -2, -6, -10, -13, -13, -14, + -14, -13, -11, -9, -4, -1, -1, -1, 2, 6, 8, 10, 11, 12, 14, 14, + 14, 13, 11, 10, 7, 4, 2, 3, 1, -3, -6, -10, -14, -17, -18, -18, + -19, -19, -17, -15, -13, -9, -5, -1, 1, 0, 1, 3, 5, 6, 6, 6, + 7, 8, 9, 8, 4, 1, 0, 2, 4, 5, 6, 5, 4, 4, 4, 3, + 1, -3, -7, -9, -11, -12, -12, -12, -11, -10, -7, -4, -2, 1, 4, 5, + 8, 11, 13, 14, 14, 11, 11, 11, 10, 10, 9, 6, 5, 3, 1, -2, + -5, -10, -14, -16, -17, -18, -19, -20, -19, -17, -14, -10, -5, -1, 1, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 4, 2, 0, -1, + 0, 0, 1, 2, 1, 1, 2, 1, -2, -5, -8, -9, -10, -11, -12, -12, + -10, -7, -4, -1, 2, 8, 11, 13, 15, 15, 13, 12, 11, 10, 9, 8, + 6, 5, 4, 4, 3, 0, -3, -6, -10, -14, -18, -21, -22, -21, -18, -16, + -13, -10, -6, -3, 0, 3, 5, 5, 5, 6, 7, 8, 8, 8, 7, 8, + 7, 6, 5, 4, 1, 0, -2, -4, -4, -5, -4, -4, -3, -2, -1, -2, + -3, -4, -7, -8, -9, -9, -9, -8, -5, -2, 2, 4, 8, 11, 14, 15, + 15, 14, 12, 10, 7, 5, 4, 4, 2, 1, 1, 2, -1, -3, -7, -10, + -15, -18, -18, -18, -18, -17, -15, -11, -7, -3, 1, 3, 4, 5, 6, 7, + 7, 8, 8, 9, 10, 10, 9, 6, 4, 2, 0, -3, -4, -6, -7, -7, + -6, -5, -3, -2, -2, -2, -2, -3, -4, -5, -6, -6, -6, -6, -5, -4, + -1, 4, 7, 9, 11, 12, 12, 11, 10, 9, 8, 7, 5, 3, 3, 2, + 1, 0, -1, -4, -7, -8, -10, -13, -14, -15, -15, -15, -14, -11, -9, -6, + -3, 0, 2, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 6, 5, 3, + 1, -3, -6, -8, -8, -7, -7, -7, -6, -4, -2, 0, -1, -2, -3, -3, + -3, -3, -4, -3, -3, -1, 1, 3, 4, 6, 7, 8, 9, 10, 10, 9, + 7, 6, 6, 4, 3, 2, 1, -1, -2, -4, -6, -9, -11, -12, -12, -12, + -11, -11, -10, -9, -8, -7, -5, -4, -1, 1, 3, 5, 7, 9, 10, 11, + 10, 9, 8, 7, 6, 2, -1, -3, -4, -6, -7, -7, -7, -7, -6, -5, + -5, -4, -3, -3, -4, -4, -4, -3, -2, 0, 0, 1, 1, 2, 4, 6, + 6, 7, 7, 8, 7, 7, 7, 7, 7, 6, 5, 2, 0, -2, -4, -5, + -7, -8, -8, -8, -9, -10, -10, -9, -8, -7, -7, -7, -5, -3, -2, 0, + 1, 2, 4, 6, 9, 10, 11, 12, 10, 8, 6, 3, 1, -2, -4, -6, + -7, -7, -7, -7, -8, -7, -7, -6, -6, -5, -4, -3, -3, -2, -1, 1, + 2, 2, 3, 4, 5, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 4, + 3, 2, 1, -1, -3, -4, -6, -8, -9, -9, -8, -8, -6, -5, -5, -5, + -6, -6, -6, -5, -4, -2, 0, 2, 4, 6, 7, 8, 9, 9, 9, 9, + 6, 4, 1, -1, -3, -5, -6, -7, -7, -7, -6, -6, -6, -6, -6, -5, + -4, -3, -3, -2, -1, 1, 3, 4, 5, 5, 5, 5, 5, 5, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 1, -1, -3, -4, -5, -6, -7, -7, + -7, -7, -7, -6, -5, -4, -4, -3, -3, -3, -3, -2, -1, 0, 1, 3, + 5, 7, 8, 8, 8, 7, 6, 4, 2, 0, -2, -3, -4, -5, -6, -7, + -7, -7, -7, -6, -6, -5, -5, -5, -3, -2, 0, 1, 2, 3, 4, 5, + 6, 6, 6, 5, 5, 4, 3, 3, 3, 3, 3, 3, 2, 1, 1, -1, + -2, -3, -4, -5, -6, -6, -7, -6, -5, -4, -3, -3, -3, -3, -3, -2, + -1, -1, 0, 1, 1, 1, 2, 3, 5, 6, 6, 6, 5, 4, 2, 1, + 0, -2, -4, -5, -5, -6, -6, -6, -7, -7, -7, -6, -5, -4, -3, -2, + -1, 0, 2, 3, 3, 4, 4, 5, 5, 5, 4, 4, 4, 4, 3, 3, + 2, 1, 1, 0, 0, -1, -1, -2, -3, -4, -5, -5, -5, -5, -5, -4, + -4, -3, -3, -2, -1, -1, -1, -1, 0, 0, 0, 1, 2, 3, 3, 4, + 4, 4, 4, 4, 3, 1, 0, 0, -2, -3, -4, -5, -5, -6, -6, -6, + -5, -4, -4, -4, -3, -2, -2, -1, 0, 2, 3, 3, 4, 4, 4, 4, + 3, 3, 3, 3, 2, 2, 1, 1, 1, 0, -1, -1, -2, -3, -3, -3, + -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 0, 0, -1, -1, + -2, -3, -3, -3, -4, -4, -4, -4, -3, -3, -2, -1, -1, -1, 0, 1, + 1, 1, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, -8, -33, -24, -25, -25, -26, -27, -32, -28, -36, -31, -36, -22, -34, + 11, -74, -14, 94, 41, 28, 33, 30, 40, 34, 23, 41, 40, 60, 56, 59, + 60, 44, 39, 54, 45, 52, 17, 44, 62, 34, 33, 19, 18, 43, 35, 22, + 36, -15, -10, 32, -7, -12, -6, -8, -50, -47, -44, -4, -25, -48, -76, -58, + -75, -96, -85, -118, -114, -63, -106, -103, -83, -110, -99, -84, -76, -58, -63, -61, + -51, -53, -36, -32, -41, -27, -11, 11, 8, 27, 19, 30, 35, 28, 57, 53, + 38, 71, 51, 68, 110, 78, 89, 109, 97, 82, 94, 115, 114, 79, 70, 79, + 94, 85, 76, 84, 95, 83, 82, 55, 54, 54, 41, 41, 27, 20, 6, -11, + -21, -16, -14, -33, -33, -52, -54, -59, -62, -71, -79, -88, -88, -78, -78, -72, + -71, -94, -99, -93, -90, -78, -87, -105, -103, -79, -62, -71, -78, -63, -61, -66, + -49, -23, -10, -11, -24, -20, -4, -22, 9, 8, 27, 43, 34, 38, 51, 83, + 65, 58, 74, 75, 70, 73, 71, 65, 100, 89, 94, 65, 84, 49, 49, 61, + 54, 43, 51, 58, 53, 35, 40, 36, 38, 34, 23, 14, -12, -10, -1, -1, + -11, -12, -19, -33, -66, -52, -42, -37, -55, -42, -28, -32, -29, -35, -41, -28, + -25, -46, -85, -64, -62, -55, -49, -68, -55, -53, -52, -47, -43, -26, -32, -41, + -34, -35, -40, -26, -8, -1, -6, -11, 5, -2, 8, 3, 8, 6, 4, 20, + 29, 43, 24, 33, 20, 30, 24, 39, 38, 40, 29, 37, 36, 39, 61, 58, + 41, 51, 59, 51, 55, 58, 48, 32, 45, 40, 27, 30, 41, 44, 26, 19, + 23, -3, 7, 0, -3, 2, 3, -6, -5, -14, -6, -10, -27, -45, -47, -41, + -38, -50, -51, -46, -43, -45, -65, -65, -80, -95, -82, -74, -66, -69, -67, -33, + -31, -53, -48, -51, -43, -18, -24, -24, -33, -26, -10, 0, -17, -6, 17, 31, + 2, 23, 45, 46, 12, 75, 38, 63, 69, 31, 38, 80, 57, 48, 59, 81, + 74, 32, 52, 72, 24, 60, 44, 55, 40, 28, 48, 33, 24, 10, -2, 21, + 34, 13, 18, 7, -1, -12, -20, -18, -30, -9, -7, -30, -27, -26, -38, -20, + -54, -55, -64, -53, -36, -62, -37, -71, -47, -42, -71, -45, -55, -50, -54, -56, + -36, -37, -54, -36, -12, -38, -33, -26, -7, -22, -44, -10, 2, 3, 15, 8, + 18, 6, 12, 8, 15, 28, 22, 50, 35, 55, 42, 36, 49, 52, 64, 48, + 60, 49, 60, 62, 40, 47, 68, 52, 59, 61, 44, 53, 44, 35, 31, 31, + 47, 22, 6, 4, -7, 5, -4, -21, -13, -9, -10, -27, -46, -32, -44, -46, + -62, -44, -51, -67, -53, -59, -63, -74, -67, -61, -61, -65, -47, -58, -57, -45, + -41, -46, -41, -38, -22, -25, -34, -16, -10, -18, 0, 1, -6, 5, 17, 15, + 10, 23, 38, 28, 28, 54, 40, 19, 55, 55, 41, 46, 53, 40, 49, 51, + 52, 41, 56, 39, 53, 38, 33, 35, 18, 15, 38, 30, 23, 27, 13, 11, + 7, 16, -1, 0, 0, 13, -6, -10, -15, -10, -10, -24, -20, -16, -38, -36, + -21, -40, -32, -42, -38, -52, -53, -41, -48, -58, -50, -47, -37, -41, -45, -29, + -41, -6, -48, -24, -25, -15, -9, -10, -10, -10, -1, -17, 4, 3, 10, -4, + 9, 15, 25, 24, 19, 23, 34, 28, 33, 37, 38, 26, 36, 47, 35, 46, + 45, 28, 35, 32, 32, 24, 21, 26, 23, 19, 37, 20, 9, 29, -2, 26, + 24, 8, 4, 14, 21, 11, -9, -8, 4, -9, -31, -11, -15, -21, -24, -29, + -22, -33, -26, -29, -48, -32, -44, -28, -22, -35, -30, -38, -31, -46, -44, -36, + -27, -23, -29, -24, -11, -20, -28, -13, -34, -19, -1, 7, -3, -1, 6, -3, + 5, 4, 8, 17, 26, 19, 33, 27, 16, 35, 14, 36, 39, 22, 32, 31, + 19, 32, 23, 29, 21, 30, 29, 23, 31, 13, 24, 17, 11, 26, 18, 12, + 5, 23, 16, 9, 15, -10, 3, 18, -15, -4, -4, 6, -14, -15, -5, -34, + -11, -20, -18, -8, -17, -29, -30, -29, -19, -34, -35, -20, -36, -20, -16, -21, + -38, -16, -30, -24, -25, -19, -18, -15, -7, -5, -5, -10, -23, -3, -14, 0, + -1, -12, -9, 7, 7, 2, 12, 5, 7, 19, 10, 21, 21, 27, 30, 22, + 18, 34, 22, 11, 26, 24, 20, 21, 25, 29, 22, 27, 27, 20, 10, 20, + 16, 22, 15, 16, 16, 5, 19, 10, 3, 22, -5, -5, -7, -16, -4, -11, + -22, -7, -16, -11, -23, -16, -30, -24, -28, -20, -29, -24, -32, -22, -22, -30, + -17, -23, -28, -22, -20, -21, -21, -17, -30, -15, -14, -20, -9, 3, 6, 5, + -20, 10, 13, -2, 11, 8, -1, 7, 16, 5, 22, 23, 13, 22, 13, 22, + 25, 15, 16, 11, 15, 13, 7, 12, 19, 18, 20, 12, 23, 11, 6, 10, + 1, 11, 19, 5, 20, 0, 11, 11, 1, 14, 15, -3, -1, -7, 6, -6, + -9, -9, 4, -3, -10, -20, -14, -9, -14, -7, -10, -5, -4, -29, -14, -12, + -26, -21, -27, -18, -10, -19, -27, -18, -8, -25, -8, -13, -15, -14, -15, 5, + -13, -7, -11, -4, -12, 0, 15, 5, 4, 1, 11, 6, 4, 3, 6, 21, + 19, 8, 15, 13, 6, 14, 16, 18, 17, 20, 15, 11, 15, 24, 13, 11, + 19, 7, 17, 14, 6, 17, 7, 7, 6, 6, 5, 11, 0, 6, 0, -6, + 5, 1, -11, -6, -1, -8, -9, -15, -7, -4, -16, -17, -13, -13, -17, -14, + -12, -12, -28, -13, -19, -25, -31, -24, -17, -17, -16, -7, -15, -12, -8, -15, + -8, -16, -10, -4, -1, -2, 3, 5, 2, -2, 5, 3, 6, 10, 8, 11, + 14, 14, 13, 15, 22, 16, 14, 18, 13, 17, 19, 16, 10, 17, 8, 17, + 14, 3, 14, 7, 10, 10, 7, 6, 6, -1, 6, 1, 0, 12, -6, 6, + 12, -4, -5, -4, -2, -2, -1, -2, -8, -11, -9, -11, -11, -18, -6, -5, + -16, -9, -14, -10, -13, -10, -11, -15, -14, -14, -12, -17, -17, -17, -7, -11, + -14, -15, -12, -6, -15, -5, -13, -9, 0, 12, -2, -2, 6, 2, -7, 4, + 10, 2, 9, 8, 7, 4, 5, 11, 15, 11, 10, 18, 9, 13, 13, 13, + 21, 11, 18, 19, 13, 14, 16, 6, 8, 1, 19, 11, 10, 11, 1, 3, + -1, -1, 5, -11, 5, -1, -5, -3, -13, -10, -6, -7, -5, -15, -10, -11, + -18, -8, -16, -20, -18, -9, -12, -17, -21, -21, -13, -21, -8, -10, -10, -5, + -16, -7, 2, -6, -6, -9, -7, -2, -9, -5, 6, -7, 1, 3, -1, 2, + 1, 2, 9, 8, 5, 15, 12, 1, 11, 9, 8, 10, 15, 14, 5, 13, + 17, 14, 15, 10, 7, 16, 5, 5, 5, 8, 9, 10, 10, 7, 0, 4, + 6, 9, -10, -4, 5, 2, -1, 0, -3, -4, -5, -10, -5, -8, -9, -10, + -3, -13, -6, -9, -20, -15, -11, -18, -14, -10, -12, -20, -14, -14, -7, -12, + -21, -14, -9, -8, -11, -5, -2, -7, -4, 4, -2, -3, -1, 0, -1, 8, + 6, 9, 7, 10, 6, 3, 4, 7, 10, 11, 6, 9, 17, 11, 9, 7, + -2, 16, 13, 12, 18, 5, 16, 9, 4, 9, 6, 8, 9, 4, 4, 3, + -2, -3, 2, -6, -3, 1, -7, -6, -3, -6, -14, -8, -9, -4, -13, -9, + -8, -16, -10, -12, -13, -11, -7, -8, -12, -9, -8, -7, -11, -4, -8, -7, + -8, -3, -13, -10, -3, 6, -5, -5, 0, -5, -3, 6, -2, -2, 4, -2, + 6, 2, -2, 5, 5, -2, 5, 15, 13, 4, 6, 6, 14, 9, 4, 8, + 7, 3, 11, 12, 2, 10, 7, 10, 8, 4, 6, 2, 0, 3, 2, 4, + 2, -6, -2, 2, -4, 3, -5, -6, -5, -5, -5, -4, -8, -7, -4, -4, + -7, -8, -7, -13, -10, -10, -11, -9, -8, -8, -7, -11, -7, -3, -9, -6, + -7, -3, -4, -5, 3, -3, -1, -2, -4, 1, 4, 0, 3, 0, 5, 2, + 0, 5, 4, 1, 3, 1, 0, 1, 7, 3, 0, 4, 3, 6, 5, 0, + 9, 5, 7, 6, 3, 6, 2, 3, 5, -4, 9, 0, 4, 10, 0, 5, + 1, -2, 4, -3, -3, -2, 0, 2, -7, 3, -10, -1, -6, -9, -2, -4, + -10, -3, -7, -6, -4, -10, -6, -6, -11, -6, 0, -6, -8, -4, -1, -9, + -10, 0, -6, -7, -2, -7, 1, -5, -5, -1, 1, -6, 2, 0, -3, -1, + 7, -4, 0, 7, 0, 8, 2, 3, 4, 4, 2, 5, -1, 6, 7, 5, + 6, 4, 2, 4, 6, 8, 6, 3, 1, 8, 9, 2, -1, 4, 3, 4, + 3, -3, 7, 4, 3, -2, 2, -4, -6, -2, -5, -2, -3, 0, -5, -6, + -13, -5, -6, -11, -9, -10, -5, -4, -9, -9, -7, -7, -8, -8, -6, -5, + -7, -5, -1, -3, -4, -2, -2, 2, -3, 1, 2, -3, 1, 2, 1, 0, + 1, 5, 0, 2, 5, 2, 0, 4, 1, 7, 3, 2, 6, 0, 5, 7, + 5, 5, 1, 3, 3, 5, 10, 3, 4, 8, 2, 7, 3, -2, 3, 0, + -1, -1, 1, 0, 1, -3, -2, -5, -4, -3, -1, -7, -8, -4, -4, -10, + -2, -8, -8, -8, -8, -9, -6, -8, -9, -4, -2, -7, -5, -2, -7, -6, + -9, -2, 0, -4, 4, -6, -3, -4, -1, 2, 1, 2, 9, 0, 3, 0, + 6, 4, 0, 5, 6, 2, 7, 7, 5, 7, 6, 8, 6, 6, 5, 5, + 1, 6, 5, -1, 3, 4, -1, 4, 1, 4, 3, -5, 0, 4, 1, 4, + -2, -3, -4, 0, -4, -8, -2, -5, -4, -8, -6, -5, -3, -3, -7, -9, + -6, -10, -10, -6, -6, -5, -4, -7, -6, -4, -10, -3, -10, 0, -2, -2, + -6, -1, 3, -3, -3, 1, 2, 1, 4, 3, 4, 3, 4, 1, 2, 6, + 5, 5, 5, 7, 9, 1, 5, 4, 4, 7, 2, 9, 2, 4, 8, 2, + 5, 6, 3, -2, -2, -1, -2, -1, 1, -2, -4, 1, -6, -2, -5, -3, + -5, -5, -6, -4, -3, -4, -10, -4, -3, -8, -4, 0, -3, -5, -6, -6, + -3, -1, -7, -3, 1, -1, -4, -2, 1, -2, 0, -1, -2, 0, 0, 5, + -2, 0, 3, 3, 1, 5, 2, 4, 1, 4, 1, 2, 3, 3, 3, 4, + 3, 3, 5, 1, 4, 2, 3, 1, 2, 0, 2, 1, -2, -2, -1, 0, + -2, -1, -1, -3, -5, -2, 0, -5, -1, 0, -5, -2, -2, -2, -3, -3, + -1, -4, -1, -2, -4, -2, -1, -2, -1, 0, -3, -1, -1, 0, 1, -1, + -1, 3, -4, -2, -2, 4, -2, -1, -1, -1, 0, 0, -1, -1, -1, -1, + 2, 0, -1, 2, -1, 0, -1, 2, 0, 3, 5, -2, 1, 2, 0, 5, + 0, -3, 4, -3, 1, 2, 0, 4, -1, -2, 1, 0, 0, 0, -1, 1, + -2, 0, 1, 1, 0, -5, 1, -2, -1, 0, -2, -3, -1, -3, 0, -2, + -3, -4, 1, -2, -3, -2, -2, -1, -1, -2, -1, -4, -5, 2, -4, 0, + 1, -1, 2, -2, -1, 0, 0, 1, -3, 3, 2, 0, -2, 2, 1, 2, + -2, 5, 3, -2, -2, -1, 1, 0, 0, 1, 3, 2, 0, 0, -1, -2, + 1, 1, 2, 1, 1, -1, 0, -1, -1, -1, -3, 1, 1, 2, -2, -1, + 0, 0, -2, 0, -1, -1, 2, -2, 1, -1, 0, 0, -1, -1, -2, 0, + -1, 1, -1, -1, 2, -2, 0, -1, -1, 2, -1, 0, -3, -1, 0, 0, + 0, -3, -3, -2, 0, 0, -1, -1, 0, -4, 2, 0, -2, 0, 1, -3, + -1, 2, 1, 0, -1, 0, 0, -1, 0, 2, -1, -1, 0, 0, -2, 1, + 1, 0, 1, 0, 2, -3, -2, 2, -1, -1, 2, -2, 1, 1, 0, 0, + 1, 1, 0, -4, 3, -1, 2, 0, 2, -1, -2, 0, 1, 1, -1, -1, + -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, 1, 0, -5, 0, -1, -1, + -1, 1, -1, 1, -1, 1, 0, -2, 0, -2, 1, -1, 1, 0, -1, -2, + 0, -1, 0, 0, 2, 0, 0, 0, 1, 0, 0, 2, 0, -1, 0, 0, + 0, 2, -1, 1, 1, -1, -1, 0, 0, 1, 1, 0, 0, 0, 0, -1, + 0, 0, -2, 0, 0, -1, 1, -2, -1, -1, -1, -2, -1, -2, 1, -1, + 0, -2, -2, 1, -2, -1, 1, 0, 1, 1, -1, -1, 0, -1, 0, 0, + 0, -2, 0, -1, 0, 0, -1, -2, -2, -2, 1, -1, 0, 0, -1, 1, + 1, -2, -1, -2, -1, 1, -1, -1, -2, -2, 0, 0, 1, -1, -1, -1, + -1, -2, 2, 0, 0, 1, 1, 1, -2, 0, -1, 0, -1, -1, 2, 0, + -1, -1, -1, 1, -1, 2, 0, -1, 1, 1, 0, 1, 0, -1, -1, -1, + -1, -3, 0, 0, -1, 1, 0, 0, -2, -2, -2, 0, -1, 0, 0, -1, + 0, -1, -2, -1, -2, 0, -2, 0, 0, -1, -2, 1, -2, 0, -1, -2, + 2, 0, -1, 2, -1, 1, -1, 0, 0, -1, 0, 0, 0, -1, 0, 1, + 0, 0, 1, 0, -1, -1, 0, -2, -1, 0, 0, 1, 0, 0, 0, 0, + -1, -1, 1, -1, -2, -1, 0, 0, -2, 0, -1, 0, 0, 0, 1, 0, + 0, -1, 1, 0, -1, 0, 1, -1, 0, -1, -2, 0, -1, 0, -1, -1, + -1, 0, -1, 0, 0, 0, -1, -1, 0, -2, 0, 0, 0, -2, -2, 0, + -2, -1, -1, -1, -2, 0, -1, -1, -1, 0, 0, -1, -1, 0, 1, -1, + -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, + -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0, + -1, 0, -1, -1, 0, -2, -1, 0, -1, -1, -1, -1, 0, -1, 0, 0, + 0, 0, -1, 1, 0, 0, 0, -1, -1, 0, -1, -1, 0, 0, 0, 0, + 0, -1, -1, 0, -1, -1, 0, 0, -1, 0, -2, 0, -1, -1, -1, 0, + -1, -1, 0, -1, 0, 0, 0, -2, -1, 0, -1, -1, 0, 1, -1, -1, + 0, 0, 0, 0, -1, -1, -1, -1, 0, 1, 0, 0, 0, 0, 0, -1, + 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, -1, -1, 0, + 0, -1, -1, 0, -1, 0, 0, 0, -1, 0, -1, -1, 0, -2, -1, -1, + -1, 0, -1, 0, -1, -1, 0, 0, -1, 0, -1, 0, -1, -1, -1, 0, + -1, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, + 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, + 0, -1, -1, 0, 0, 0, -1, 0, 1, -1, -1, -1, 0, 0, -1, -1, + -1, -1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 0, + -1, 0, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, 0, -1, + 0, -1, 0, 0, -1, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, -1, + -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, + -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, + -1, -1, 0, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0, -1, -1, -1, + -1, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, + 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, + 0, -1, 0, -1, 0, 0, -1, -1, -1, 0, -1, -1, 0, -1, -1, 0, + 0, -1, -1, -1, -1, 0, -1, -1, 0, 0, -1, 0, 0, 0, -1, -1, + 0, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, 0, -1, 0, 0, -1, + -1, 0, 0, -1, 0, 0, -1, -1, -1, 0, -1, 0, 0, -1, -1, 0, + 0, -1, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, -1, 0, -1, 0, + -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, 11, -3, 47, -12, -15, -34, 3, 12, 38, 5, -24, -26, -9, -12, + 63, -18, 12, -17, -50, 34, -6, 40, -2, -8, -37, -6, 9, 12, 32, -4, + -33, 2, -33, 35, 20, 6, -11, -33, -11, 12, 23, 30, -21, -13, -28, -6, + 33, 14, 7, -18, -22, -11, 18, 23, 5, -4, -22, -30, 29, -11, 40, -12, + -15, -5, -11, 16, 13, -9, 5, -19, 3, 4, 2, 19, -28, 24, -41, 40, + -9, -8, 4, -29, 28, -1, 22, -16, -32, 16, -22, 45, 19, -45, 17, -54, + 25, 28, 33, -19, -30, -21, -25, 83, -20, 15, -3, -74, 12, 33, 4, 53, + -26, -57, -9, 0, 36, 33, 8, -67, -2, -17, 27, 55, -17, -11, -31, -23, + 24, 22, 6, 19, -55, 27, -48, 55, -8, 14, 7, -61, 26, -25, 34, 32, + -26, 11, -50, 5, 14, -1, 67, -75, 47, -79, 29, 15, 8, 42, -49, 2, + -34, -3, 51, -23, 52, -33, -32, -7, -14, 52, 6, 29, -73, 5, -9, -2, + 64, -39, -6, 25, -60, 30, 5, 16, -13, 40, -61, 7, 20, -50, 75, -36, + 10, -12, -4, -17, 23, 16, -18, 31, -38, -21, 33, -37, 56, -11, -5, -1, + -43, 43, -56, 93, -67, 40, -17, -46, 60, -56, 62, -24, 14, -18, -23, 9, + -16, 44, 19, -53, 58, -124, 81, -18, 32, 26, -43, -23, -28, 42, 1, 60, + -27, -61, 14, -37, 42, 64, -32, -2, -43, -31, 25, 59, -7, -1, -19, -73, + 51, 23, 18, 7, -24, -65, 29, 18, -2, 57, -47, -27, 4, -2, 16, 41, + -25, -47, 36, -51, 49, 24, -37, 13, -15, -11, 12, 26, -58, 52, -20, -16, + 31, -24, -20, 52, -16, -9, 32, -69, 5, 48, -34, 52, -12, -59, 20, -10, + 30, 16, 21, -75, 1, 8, -33, 126, -57, 9, -37, -49, 32, 24, 62, -59, + 19, -85, -2, 91, -23, 65, -49, -75, 19, -16, 68, 9, 16, -77, -3, 3, + -13, 111, -69, 17, -30, -59, 56, 1, 19, 23, -26, -21, -24, 25, -31, 97, + -59, 4, -16, -34, 40, 17, 16, -24, -6, -40, 26, 17, 3, 4, -23, -3, + -1, 23, -8, 6, -29, -2, 21, -13, 22, -11, -31, 40, -35, 48, -27, 7, + -39, 4, 28, -12, 55, -68, 9, -9, 2, 51, -21, -20, -18, -15, 33, 20, + 15, -57, 41, -78, 72, -2, -7, 13, -60, 11, 13, 49, -19, 10, -55, -23, + 59, -6, 22, 2, -79, 40, -11, 46, -11, 11, -66, 13, 24, -24, 80, -65, + 5, -22, 1, 19, 23, -8, -27, -11, 2, 0, 64, -61, 21, -52, 34, 23, + 7, -1, -51, 21, -41, 86, -45, 49, -62, -6, 0, 11, 51, -33, 16, -62, + -1, 23, 8, 62, -45, -35, 7, -39, 88, -54, 70, -86, 33, -27, -1, 61, + -60, 58, -62, 10, 15, -28, 65, -48, 11, -2, -44, 78, -64, 75, -78, 26, + -29, 22, 40, -30, 16, -53, -12, 56, -15, 48, -51, -22, -10, 9, 52, -20, + 40, -92, 16, -3, 26, 43, -19, -35, -31, 15, 13, 49, -11, -34, -24, -1, + 9, 50, -12, -25, -17, -10, 15, 44, -20, 0, -28, -22, 32, 5, 27, -33, + 15, -67, 61, -19, 19, 18, -46, -1, -1, 7, 18, 14, -27, -21, 18, -27, + 42, 22, -56, 38, -56, 21, 17, 2, 5, -3, -11, -38, 48, -27, 32, 8, + -50, 1, 10, -3, 38, -10, -16, -36, 34, -45, 74, -12, -30, 16, -52, 22, + 24, 17, -1, -13, -41, -10, 50, -5, 41, -32, -62, 25, -5, 48, 24, -26, + -61, 4, -2, 44, 62, -59, -23, -38, -4, 61, 34, 0, -57, -18, -41, 63, + 36, 6, -1, -69, -11, 10, 19, 60, -31, 3, -64, 18, -19, 61, 10, -17, + 10, -73, 13, 30, -7, 64, -39, -27, -34, 8, 20, 46, 24, -87, 29, -70, + 51, 51, -12, 6, -44, -30, 10, 52, -7, 2, -6, -72, 63, -9, 17, 15, + -37, -24, 14, 24, -11, 43, -55, -29, 42, -19, 47, 1, -49, -13, 13, 6, + 38, 4, -59, -2, 7, 5, 61, -31, -42, 11, -32, 54, 14, -11, -23, -10, + -20, 40, 19, -18, 0, -19, -28, 52, -14, -5, 29, -70, 53, -17, 19, -18, + 15, -30, -2, 37, -41, 38, 7, -61, 67, -67, 35, 11, -12, 11, -34, 38, + -61, 89, -59, 10, 28, -60, 52, -19, -22, 34, -30, 42, -42, 45, -68, 35, + 19, -45, 80, -81, 26, -16, 4, 30, 0, -13, -19, -14, 23, -22, 75, -77, + 47, -45, -5, 48, -36, 48, -50, 18, -35, 25, 5, 4, 14, -16, -33, 40, + -49, 71, -38, 17, -30, -6, 12, 4, 31, -27, -6, -12, -11, 27, 15, -13, + 12, -54, 32, -19, 53, -17, -1, -16, -39, 39, -5, 30, -3, -29, -13, -2, + 23, 16, 4, -18, -41, 26, -11, 35, 18, -48, 13, -33, 28, 1, 38, -45, + 5, -13, -18, 49, 1, -21, 16, -44, 14, 16, 7, -6, -5, -10, -18, 52, + -33, 25, -11, -36, 31, -15, 14, 11, -22, 9, -27, 41, -42, 56, -50, 15, + 10, -28, 30, -18, 3, 7, -7, 7, -16, 13, -27, 29, 5, -25, 42, -71, + 44, -18, 21, 8, -7, -21, -15, 21, -9, 36, -2, -43, 17, -26, 14, 45, + -33, 19, -40, 1, -3, 37, -5, -5, -2, -46, 38, 0, 7, 18, -33, -12, + 11, -11, 33, 2, -16, -15, -3, 1, 18, 26, -32, -4, -14, -17, 54, -1, + -1, -17, -35, 10, 12, 40, -12, -10, -30, -31, 51, -12, 65, -35, -34, -12, + -32, 60, 22, 19, -33, -39, -20, 2, 75, 2, 9, -42, -72, 35, 13, 65, + 5, -28, -60, -15, 23, 40, 44, -33, -34, -34, -5, 48, 33, 2, -21, -47, + -15, 25, 33, 12, 7, -55, -12, 7, 19, 28, 9, -34, -28, 5, 7, 32, + 15, -41, 8, -32, 10, 36, -4, 14, -40, 16, -45, 56, -15, 17, 0, -33, + 2, 0, 7, 23, -12, -1, -26, 3, 6, 10, 24, -32, 21, -50, 33, -9, + 15, 11, -24, 1, -12, 12, 4, 13, -10, -11, -2, -5, 7, 17, -23, 25, + -27, 12, -6, 0, 8, -16, 18, -24, 31, -27, 9, -3, -2, 18, -4, -7, + -11, -12, 10, 12, 15, -17, 7, -34, 18, 8, 4, 9, -18, -14, -3, 15, + 9, 7, 0, -37, 21, -13, 16, 18, -32, 12, -23, 21, 3, 12, -14, -14, + 3, -5, 24, 4, -21, 9, -32, 26, 14, -1, 12, -40, 0, -6, 24, 11, + 3, -11, -34, 17, -8, 28, 18, -36, 9, -38, 13, 26, 11, 7, -20, -13, + -34, 49, -24, 41, -8, -36, 4, -8, 3, 47, -11, -5, -24, -15, -9, 44, + 8, -5, 8, -61, 17, 14, 14, 23, -15, -43, 1, -1, 28, 27, 1, -40, + -6, -20, 18, 45, -22, 4, -20, -34, 39, 12, 3, 9, -31, -23, 15, 17, + -7, 36, -36, -19, 30, -30, 36, 1, -16, -8, 5, -14, 20, 10, -13, 0, + 6, -30, 37, -22, 3, 14, -27, 24, -15, 14, -15, 19, -22, 4, 17, -31, + 29, -14, -10, 27, -26, 22, -14, 8, -17, 9, -2, -11, 33, -27, 14, 0, + -29, 31, -21, 21, -7, -2, -14, -4, 20, -15, 37, -27, -9, 7, -24, 24, + 8, -9, 12, -23, 7, -14, 30, -22, 25, -16, -20, 24, -27, 23, 8, -9, + 6, -11, -18, 12, -3, 22, -14, 28, -61, 41, -32, 21, 29, -26, 8, -31, + 2, 5, 28, 3, -9, -14, -21, -3, 48, -33, 49, -62, 9, -1, 6, 33, + -24, 11, -44, 24, -2, 6, 25, -40, 8, 1, -16, 49, -41, 27, -41, 18, + 0, 3, 31, -50, 36, -42, 22, 15, -18, 24, -34, 5, 12, -21, 52, -56, + 52, -58, 29, -8, -8, 39, -51, 48, -47, 24, 4, -16, 22, -28, 6, 7, + -22, 48, -55, 51, -44, 31, -10, -5, 8, -36, 41, -31, 35, -9, -16, 10, + -17, 6, 21, -13, 10, -26, 5, -17, 39, -3, 3, 1, -43, 12, 1, 17, + 15, -7, -24, -9, 5, 15, 17, 8, -38, 2, -25, 25, 15, 12, -13, -16, + -11, 3, 19, 9, -9, -9, -15, 1, 19, -1, 14, -20, -1, -12, 15, -7, + 11, -10, -2, -3, 10, -9, 18, -17, 2, -4, -3, 4, 3, -2, -5, 9, + -9, 4, 5, -13, 5, 5, -21, 22, -16, 11, -4, 13, -22, 5, 3, -23, + 35, -14, -6, 13, -24, 4, 17, -6, 6, -7, -6, -27, 43, -28, 25, 9, + -45, 28, -23, 8, 25, -14, 0, -15, -4, -3, 27, 3, -15, 18, -59, 34, + 3, -3, 38, -39, -11, 4, -9, 27, 9, -2, -38, 21, -31, 19, 47, -53, + 43, -47, -11, 29, -2, 19, -7, -9, -36, 19, 12, -8, 53, -58, 1, 2, + -33, 67, -23, 25, -44, 5, -25, 28, 32, -29, 32, -60, 0, 25, -7, 39, + -14, -29, -12, 2, 11, 20, 23, -54, 18, -25, 1, 45, -10, -10, -4, -29, + 7, 28, 7, -11, 9, -46, 16, 11, 8, 8, -7, -25, -3, 16, -3, 32, + -25, -7, -20, 12, 0, 30, -14, -4, -15, -6, 6, 24, -9, 3, -16, -24, + 23, -3, 27, -20, 15, -56, 42, -17, 21, 13, -27, -8, -2, 5, 8, 21, + -21, -12, 4, -14, 15, 24, -39, 31, -38, 19, -2, 16, -16, 3, -6, -21, + 30, -14, 16, 4, -30, 11, -7, 7, 12, -5, -10, -9, 9, -17, 37, -15, + -5, 6, -26, 12, 13, -8, 7, -2, -18, 1, 17, -13, 15, 4, -37, 25, + -18, 8, 13, 1, -23, 21, -25, 10, 7, -1, -6, 10, -15, -7, 21, -26, + 29, -12, -3, -3, 0, -16, 29, -18, 21, -15, 1, -23, 22, -4, 3, 21, + -43, 22, -19, 4, 21, -8, 4, -11, -7, -5, 7, 19, -20, 31, -47, 11, + 2, -9, 44, -28, 8, -31, 5, -1, 20, 24, -38, 14, -32, -4, 47, -30, + 38, -41, -1, -12, 12, 27, -16, 29, -57, 12, -1, 3, 38, -29, 3, -25, + -1, 28, -10, 36, -52, 20, -33, 27, 14, -11, 18, -42, 13, 3, 3, 20, + -21, 0, -20, 15, 4, 0, 23, -49, 28, -24, 18, 16, -15, -2, -26, 22, + -10, 33, -7, -26, 11, -25, 19, 21, -14, 8, -33, 6, -2, 30, 2, -12, + -6, -37, 34, -4, 22, 1, -33, -3, -4, 15, 20, 3, -20, -16, 2, -14, + 38, -3, -7, 2, -24, -4, 22, -4, 11, -2, -15, -19, 21, -15, 24, 8, + -21, 1, -12, -3, 9, 21, -22, 17, -26, -2, 6, 14, -8, 19, -24, -10, + 8, -10, 17, 9, -7, -12, 8, -27, 29, -3, 4, -4, -3, -26, 25, -9, + 13, 9, -19, -7, 2, -4, 10, 19, -29, 13, -16, -3, 18, 4, -12, 10, + -24, 1, 6, 10, -9, 19, -26, -3, 16, -15, 20, -4, -16, 1, 3, -4, + 9, 6, -19, 7, 3, -18, 26, -13, -7, 12, -13, 2, 9, -5, -7, 15, + -18, 6, 8, -18, 13, -2, -12, 15, -12, 9, -6, -2, -16, 25, -14, 18, + 1, -29, 11, -4, 14, 2, 3, -26, 6, -3, 1, 19, -3, -15, 12, -29, + 17, -2, 12, -2, -4, -3, -28, 34, -21, 31, -7, -17, -3, -13, 20, 1, + 14, -14, -22, 11, -13, 33, -2, -11, -4, -30, 33, -12, 30, -17, -17, -4, + -4, 25, 2, 3, -20, -22, 20, -13, 42, -15, -11, -9, -16, 23, 8, 16, + -28, -3, -11, 4, 27, -8, 5, -17, -9, 8, -2, 25, -27, 17, -32, 19, + -4, 16, -8, -16, 6, -20, 32, 0, -14, 8, -34, 18, 12, 3, 13, -36, + 11, -34, 49, -14, 22, -12, -38, 17, -21, 42, 5, -10, -12, -34, 8, 18, + 18, 26, -50, 9, -50, 42, 16, 10, 10, -51, 2, -21, 38, 16, 7, -17, + -29, -12, 13, 19, 25, -16, -7, -40, 14, 5, 23, 6, -11, -23, -3, 11, + 2, 25, -26, 0, -12, 5, 4, 9, 2, -18, 10, -15, 5, 20, -26, 23, + -28, 6, 8, 1, 12, -26, 10, -19, 20, 7, -14, 17, -37, 18, 1, -1, + 23, -28, 9, -25, 20, 1, 6, 6, -23, 9, -15, 12, 10, -11, 5, -5, + -12, 15, -8, 4, 4, -4, -6, 8, -11, 3, 6, -6, 0, 6, -12, 1, + 14, -26, 27, -17, -3, 15, -18, 15, -10, 1, -6, 4, 9, -17, 28, -42, + 18, 3, -17, 45, -38, 9, -12, -7, 19, 8, 7, -31, 8, -18, 6, 53, + -51, 34, -41, -13, 32, -4, 17, -10, -6, -28, 25, 0, -2, 23, -32, -7, + 21, -28, 36, -7, -14, 7, -10, -4, 13, -3, -7, 7, -5, -6, 14, -10, + -10, 22, -29, 22, 0, -23, 24, -25, 15, 3, 3, -4, -9, 5, -23, 33, + -10, -6, 22, -48, 31, -8, 7, 10, -15, -5, -14, 20, -7, 16, 3, -32, + 20, -21, 13, 18, -20, 9, -25, 13, -3, 21, -4, -10, -4, -18, 18, 6, + 2, 6, -32, 8, -4, 18, 10, -3, -21, -12, 3, 3, 28, -3, -18, -4, + -14, 10, 19, 5, -9, -10, -21, 8, 21, 2, 11, -23, -12, -8, 14, 12, + -1, 5, -31, 14, -9, 15, 7, -14, 5, -19, 11, -3, 5, 1, -11, 12, + -13, 14, -6, -10, 5, -9, 16, -4, 3, -15, -5, 9, 2, 14, -11, -9, + -7, -7, 22, -2, 12, -14, -15, -2, 2, 19, 0, 6, -28, -3, 0, 5, + 27, -10, -8, -15, -9, 12, 10, 20, -25, 5, -23, 0, 27, -10, 21, -27, + -3, -14, 17, 8, 1, 6, -28, 2, 7, -2, 21, -14, -6, -9, 3, 6, + 2, 16, -33, 19, -17, 7, 10, -6, -3, -4, 0, 0, 11, -1, -13, 5, + -9, -1, 25, -27, 19, -20, 3, 9, 1, 2, -11, 5, -19, 26, -4, -6, + 13, -28, 10, 13, -11, 17, -19, -1, -10, 22, -4, -1, 13, -43, 29, -8, + 3, 18, -25, 5, -13, 16, -5, 12, 0, -29, 25, -23, 14, 17, -29, 23, + -23, 8, 2, 0, 4, -8, 11, -25, 22, -8, -6, 28, -35, 19, -6, -17, + 25, -15, 9, -5, 1, -12, 10, 5, -14, 22, -24, 0, 18, -23, 23, -9, + -10, 8, -1, -1, 4, -4, -13, 8, 6, -7, 22, -27, -8, 10, -6, 23, + 1, -17, -10, -9, 15, 14, 15, -17, -24, -1, -11, 41, 4, -4, -12, -35, + 12, 13, 19, 12, -22, -25, -6, 8, 22, 17, -3, -36, 7, -21, 21, 32, + -22, 8, -23, -17, 17, 15, 1, 10, -19, -20, 2, 10, 3, 23, -13, -21, + 7, -19, 26, 12, -10, 4, -35, 4, 7, 12, 19, -17, -3, -24, 14, 7, + 7, 15, -43, 12, -13, 8, 37, -29, 13, -34, 11, 2, 11, 14, -34, 22, + -31, 20, 14, -14, 18, -29, 5, -4, 3, 13, -11, 13, -23, 9, -3, -5, + 22, -22, 12, -10, -11, 15, -2, 6, 4, -10, -15, 11, -5, 10, 8, -14, + -12, 12, -10, 16, 17, -37, 16, -18, -3, 31, -11, -1, -9, -8, 0, 22, + 6, -21, 9, -32, 14, 26, -19, 27, -40, 6, -4, 13, 14, -14, 3, -34, + 21, 1, 10, 15, -32, 5, -10, 5, 19, -10, 3, -21, 10, -7, 14, 9, + -23, 18, -25, 9, 7, -5, 4, -1, -8, -2, 15, -17, 16, -5, -17, 16, + -13, 9, 3, 2, -17, 13, -10, -2, 29, -33, 17, -15, -10, 23, -6, 12, + -14, -3, -9, 2, 26, -23, 28, -45, 14, -1, 1, 33, -35, 17, -34, 15, + 10, 3, 12, -31, 7, -15, 18, 19, -19, 12, -39, 16, 5, 8, 17, -37, + 16, -35, 39, -3, 8, -5, -31, 9, -4, 26, 0, -3, -18, -15, 19, -2, + 25, -12, -21, 1, -16, 26, 4, 6, -20, -1, -14, 11, 21, -20, 22, -32, + 0, 14, -9, 19, -10, -2, -13, 14, -9, 4, 17, -36, 30, -20, -2, 22, + -21, 13, -11, 7, -12, 15, -6, -15, 25, -29, 20, 3, -18, 17, -17, 7, + -3, 11, -9, -4, 13, -33, 34, -10, -5, 22, -34, 11, -4, 8, -1, 11, + -14, -16, 24, -27, 31, 3, -29, 19, -23, 2, 26, -11, 1, -3, -14, -4, + 27, -14, 3, 9, -38, 26, -1, -7, 20, -15, -12, 14, -8, 4, 7, -11, + -10, 12, -3, 0, 16, -28, 7, 1, -2, 14, -7, -10, -5, 4, 5, 9, + 3, -22, 4, -5, 0, 27, -18, 1, -9, -10, 13, 10, 1, -9, -1, -21, + 15, 11, -8, 15, -21, -8, 12, -4, 13, 0, -12, -5, 2, -1, 9, 2, + -8, 0, -4, 1, 4, -1, -1, -1, -1, -2, -15, 21, -17, 23, -30, 1, + 34, -34, 6, 5, -15, 19, 1, -25, 6, 20, -2, -28, 15, 10, -15, 0, + -7, 10, 7, -5, -9, -6, 19, -3, -21, 3, 20, -4, -20, 1, 16, -3, + -8, -2, 5, 1, -8, -6, 3, 9, 2, -13, -4, 15, -7, -9, 0, 3, + 6, -7, -7, 5, 8, -8, -4, 0, 1, 1, -6, -4, 7, 2, -2, -7, + 0, 4, -3, -4, 0, 2, 0, -2, -4, 1, 4, -2, -4, -3, 1, 3, + -5, -4, 4, 3, -6, -5, 4, -1, -2, -3, 0, 3, -3, -1, -4, 3, + 3, -5, -3, 1, 1, -2, -3, 1, 2, -2, -4, 0, 0, 0, -1, -3, + 1, 1, -3, -2, 1, 0, -2, -2, 0, 0, -2, -1, 0, -1, 1, -2, + -2, 1, 0, -2, 0, -1, 0, -1, -1, -1, 0, 0, -1, -3, 1, 1, + -2, -2, 0, 1, -1, -2, -1, 0, 0, 0, -2, -1, 1, 0, -3, 0, + 2, -1, -2, 0, 0, 0, -2, 0, -1, 0, -1, -1, 1, 0, -1, 0, + -1, 1, 0, -13, 5, 7, -11, 24, -50, 41, 4, -29, 14, -11, 8, 11, + -15, -12, 15, 18, -21, -14, 22, -2, -11, -3, -3, 18, -3, -5, -14, 9, + 22, -24, -16, 23, 12, -23, -8, 9, 10, -4, -8, -3, 11, -4, -14, 0, + 8, 8, -5, -14, 8, 10, -12, -4, -2, 10, 0, -11, -3, 11, 0, -7, + -2, -1, 7, -6, -8, 3, 6, 0, -3, -8, 7, 2, -7, -2, 2, 1, + -2, -4, -1, 3, 3, -4, -5, 1, 3, -3, -6, 2, 5, -1, -7, -1, + 3, -1, -4, -3, 5, 0, -3, -2, -1, 4, -1, -5, -1, 3, -1, -4, + -1, 3, 1, -4, -2, 1, 0, -2, -3, 0, 2, -1, -4, 1, 1, -1, + -2, -2, 1, -1, -3, 0, 0, 0, -1, -2, 0, 0, -2, -1, 0, -1, + 0, -2, -1, 0, -1, 0, -1, -2, 2, -1, -2, -1, 0, 1, -2, 0, + -1, -1, 0, -1, -2, 0, 1, -1, -3, 0, 1, -1, -3, 0, 1, -2, + -1, 0, 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, -1, -1, 0, 0, + -2, 0, 0, 0, 0, -2, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, + 0, 0, -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, -1, -1, 0, + 0, 0, 1, -2, 4, -3, 3, -40, 71, -73, 67, -27, -68, 127, -80, 3, + 5, 1, 17, -14, 1, -30, 53, -3, -42, 15, 19, -9, -17, -1, 13, 16, + -17, 4, -32, 43, 15, -68, 18, 54, -38, -7, -1, 11, 7, -3, -18, 5, + 25, -27, -9, 9, 19, -6, -12, -8, 20, -1, -15, -1, 1, 17, -10, -16, + 12, 12, -13, 0, -6, 10, 2, -16, -1, 14, -4, 4, -11, -2, 12, -6, + -8, 4, 4, -2, -4, 1, -2, 4, 3, -7, -5, 8, 0, -10, 1, 4, + 2, -4, -6, 4, 1, -1, -7, 1, 8, -9, 2, -5, 3, 3, -4, -3, + 0, 3, -3, -5, 4, 3, -3, -4, 0, 2, 0, -3, -4, 5, 0, -5, + -1, 2, 0, -3, 0, -1, 2, -2, -4, 3, 0, -1, -2, -1, 2, -2, + -2, 1, -1, 0, -1, -3, 1, 1, -2, 1, -3, 1, 1, -3, -1, 1, + 0, -1, -2, 1, -1, -1, 1, -2, 1, -1, -1, -1, -1, 0, 1, -3, + 0, 0, 1, -4, 0, 1, -2, 0, -2, 0, 0, 0, -2, 1, -1, 0, + -2, 0, 2, -2, -1, 0, -1, 2, -2, -1, 1, -2, 0, -1, 1, -1, + -1, -1, 1, -2, 1, -1, -1, 2, -3, 0, 0, -1, 1, -1, 0, 1, + 0, -2, 0, -1, 1, -2, 0, 0, -1, 1, 0, -2, 0, 1, -2, 1, + 0, 0, -1, 0, 1, -1, -1, -1, 1, 1, -1, 0, 0, 0, -1, 1, + 0, -1, 1, 0, 0, 1, 0, -1, 1, 0, 3, -40, 58, -39, 12, 42, + -117, 108, 1, -66, 22, 17, 0, -9, 10, -39, 42, 4, -23, -12, 28, 3, + -34, 9, 17, 3, -9, 10, -29, 13, 53, -79, 3, 64, -26, -24, 16, -9, + 14, 2, -8, -15, 31, -9, -30, 11, 29, -15, -7, 0, 3, 6, -4, -9, + -6, 22, 1, -24, 9, 11, -8, 0, -2, 2, 8, -12, -6, 10, 2, 2, + -9, -4, 11, -2, -10, 3, 2, 3, -5, -1, 1, -1, 6, -4, -8, 9, + 2, -8, -3, 6, 3, -4, -3, -1, 6, -2, -8, 0, 9, -4, -3, -2, + 2, 4, -4, -1, -1, 4, -2, -6, 4, 2, -1, -4, 0, 1, 2, -3, + -5, 3, 3, -3, -4, 3, 0, -1, 0, -2, 2, 0, -3, 0, 3, 0, + -3, -1, 2, 0, -3, 1, 0, -1, 2, -2, -2, 2, -1, 0, -1, -1, + 1, -1, -2, 0, 0, 1, -3, 1, 0, -1, 1, -2, -1, 2, -2, -1, + 0, -1, 2, -3, -1, 1, 1, -2, -2, 2, 1, -2, -1, 0, 0, 1, + -3, 1, 0, 0, 0, -2, 3, 0, -2, 0, 0, 1, 0, -1, 1, -2, + 0, 0, 0, -1, 1, 0, 0, 0, -1, 1, -1, 1, 0, -1, 1, -2, + 0, 1, 1, 0, 1, -2, 1, 0, 1, 0, 0, 3, -1, 0, 1, 0, + 0, 3, -29, 35, -12, -16, 56, -88, 39, 62, -79, 5, 29, 1, -13, 12, + -29, 26, 17, -28, -3, 12, 5, -11, -19, 28, 1, -5, 9, -21, -7, 60, + -56, -20, 57, -10, -27, 21, -21, 16, 12, -12, -21, 24, 6, -29, 4, 19, + 2, -7, -5, -3, 7, 6, -11, -9, 11, 13, -18, -4, 13, 1, -3, -6, + -1, 10, -8, -6, 5, 3, 5, -3, -11, 4, 9, -11, 0, 4, 3, -4, + -1, 0, 0, 7, 0, -14, 7, 5, -7, -4, 4, 5, -1, -4, -4, 4, + 1, -4, -4, 7, -1, -1, -3, 0, 5, -1, -4, -1, 2, 0, -3, 1, + 1, 2, -2, -4, 1, 2, 0, -5, 2, 3, -2, -2, 1, 1, -2, 2, + -3, 0, 0, -1, -1, 0, 1, 0, -3, 0, 0, -1, 1, -1, -2, 1, + -1, 0, -2, 2, 1, -2, -1, 1, 0, -1, -1, 0, 1, -1, 0, -2, + 1, 1, -1, 0, -1, -1, 0, 0, -1, -1, 0, -1, -1, 2, -2, -1, + 1, 0, 0, -1, -1, 1, 0, -1, 1, -1, 0, 1, -3, 1, 1, -1, + -1, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 1, 0, 0, 2, -2, + 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, -1, -1, -7, -9, + 35, -52, 59, -33, -32, 64, -15, -41, 19, 22, -20, 9, -11, -3, 33, -27, + 2, 7, -9, 19, -37, 24, 7, -11, 11, -1, -30, 37, 8, -57, 36, 19, + -33, 14, 0, -17, 26, 1, -20, -5, 26, -18, -13, 14, 7, -6, 4, -9, + -4, 11, 3, -14, -7, 20, 0, -18, 10, 1, 4, -5, -7, 6, 0, -3, + -2, -2, 8, 5, -11, -6, 10, -1, -10, 6, -2, -1, 1, -3, 0, 3, + 5, -9, -5, 9, -3, -4, 1, 1, 3, -1, -4, -1, 2, -2, -5, 5, + -3, 0, 1, -5, 4, 2, -3, -3, 0, 0, -2, 1, 0, -2, 3, -2, + -5, 2, 2, -2, -4, 3, 0, -2, 1, -2, -2, 5, -2, -6, 1, 2, + -1, -1, 0, 1, -1, -2, -1, -1, 2, 0, -4, 0, 1, 0, -3, 0, + 2, 0, -3, 0, 0, 1, -1, -1, 1, 0, -1, -2, 1, 0, 0, -1, + 0, -2, 1, 0, -1, 1, -1, 0, -2, 1, 1, -2, -1, 2, -2, 1, + -3, 1, 1, -1, 0, 0, -1, 1, 0, -2, 2, -1, -1, 0, 0, 1, + 0, 1, 0, -2, 1, 0, 0, -1, 1, 0, 0, 0, 0, -3, -20, 45, + -56, 40, -5, -34, 27, 24, -42, -1, 29, -14, -4, 2, -7, 24, -20, -1, + 18, -25, 25, -29, 9, 21, -26, 14, 4, -20, 7, 27, -42, 5, 31, -24, + -2, 19, -30, 21, 8, -11, -17, 20, 1, -22, 11, 7, -7, 6, -5, -7, + 3, 11, -6, -18, 11, 16, -20, 1, 5, 2, -3, -3, 0, -3, 4, -1, + -7, 2, 10, -9, -8, 7, 2, -9, 5, -1, -5, 2, 1, -3, -2, 9, + -5, -8, 4, 1, -5, 0, 1, 2, -1, 0, -5, 4, -1, -5, 4, -3, + 1, 1, -5, 3, 0, 0, -3, 0, -1, -2, 1, 2, -5, 2, 1, -5, + -2, 3, -1, -5, 2, 1, -4, 2, -1, -4, 2, 3, -7, -1, 2, 0, + -2, 1, 0, -2, -1, 0, -3, 1, 2, -3, -2, 3, 0, -3, -1, 1, + 0, -1, -2, -1, 1, 0, 0, -1, 0, 0, -2, 0, 0, 1, -2, 2, + -3, 1, 0, 0, -2, 1, 0, -1, 0, 0, -1, -1, 2, -3, 0, 0, + -1, 0, 0, -1, 1, 0, -4, -13, 32, -41, 31, -10, -10, 4, 22, -25, + -8, 21, -3, -14, 5, 1, 12, -23, 8, 18, -31, 25, -26, 10, 17, -23, + 8, 5, -9, 0, 16, -25, 2, 23, -22, -2, 22, -30, 15, 7, -6, -13, + 12, 1, -17, 9, 5, -6, 4, -3, -7, 5, 7, -6, -13, 7, 10, -11, + 0, 0, 4, -3, -3, 2, -7, 4, 2, -5, 0, 6, -3, -8, 4, 2, + -8, 7, 0, -8, -1, 6, 0, -8, 6, 0, -5, 1, 0, -5, 3, 2, + -3, -2, 4, -5, -1, -1, -2, 3, -4, 1, -1, -3, 3, -1, -2, -2, + 1, -2, -2, 1, 1, -4, 1, 2, -5, -3, 5, -3, -4, 4, -1, -4, + 2, -1, -4, 3, 1, -5, -2, 2, 0, -2, 2, -1, -4, 3, -1, -3, + 0, 1, -2, -2, 1, -1, -1, -1, 0, 0, -1, -1, -1, 0, -1, 1, + -1, -1, 0, -2, 1, 0, -1, -1, 0, -1, -1, -1, 2, -2, -1, 1, + -1, -2, 1, -1, -1, 1, -2, 1, -7, -3, 15, -23, 20, -16, 9, -12, + 16, -12, -8, 11, 5, -18, 6, 8, 0, -18, 16, 4, -19, 16, -17, 10, + 5, -8, -2, 9, -5, -4, 10, -17, 5, 13, -18, 2, 12, -17, 10, 0, + -2, -8, 7, -4, -7, 6, 1, -3, 1, 3, -9, -2, 10, -7, -8, 4, + 6, -6, 1, 0, 0, -2, 1, -1, -8, 6, 1, -5, 2, 4, -2, -4, + 1, 1, -7, 5, -1, -4, -2, 4, 0, -4, 4, -3, -4, 1, 0, -3, + 0, 2, -1, -2, 2, -2, -1, -3, 0, 3, -4, 3, -3, 0, 2, 0, + -3, -1, 1, -3, -1, 2, 0, -1, 0, 0, -3, 0, 1, -4, -1, 2, + 0, -2, 0, 1, -3, 1, 1, -3, -2, 2, -1, -1, 2, -1, -2, 1, + 0, -1, -1, 0, 2, 33, 42, 58, 71, 79, 85, 88, 91, 94, 79, 95, + 82, 106, 86, 105, 47, 16, -6, 13, 44, 31, -15, -38, -36, 20, 70, 41, + 48, 58, 24, -57, -127, -119, -102, -126, -128, -111, -78, -82, -88, -87, -60, -66, + -98, -104, -99, -97, -99, -104, -101, -88, -87, -91, -61, -27, -34, -54, -55, -45, + -24, -10, -5, -4, 5, 34, 63, 101, 94, 78, 52, 51, 52, 74, 81, 77, + 59, 46, 17, 7, 39, 53, 47, 42, 66, 83, 73, 52, 28, 22, 11, 8, + 11, 0, -15, -23, -15, -14, -6, 16, 46, 62, 71, 76, 90, 102, 103, 103, + 101, 100, 90, 75, 63, 67, 49, 37, 28, 12, 5, 6, 15, 15, 8, -7, + -12, -4, -10, -28, -24, -17, -25, -50, -64, -81, -103, -116, -116, -113, -95, -72, + -54, -41, -47, -65, -65, -50, -33, -24, -7, 11, 8, -4, -13, -28, -51, -75, + -90, -91, -90, -90, -87, -88, -83, -84, -82, -81, -81, -76, -65, -71, -85, -84, + -79, -83, -81, -77, -72, -70, -65, -66, -66, -65, -66, -68, -61, -56, -51, -36, + -13, -3, -5, -8, -12, -12, 3, 16, 21, 31, 50, 69, 77, 82, 90, 102, + 110, 114, 116, 117, 118, 119, 116, 112, 109, 105, 98, 99, 103, 102, 91, 73, + 64, 63, 61, 57, 51, 40, 24, 35, 57, 75, 84, 79, 65, 37, 4, -26, + -45, -57, -54, -46, -45, -54, -67, -67, -48, -16, 15, 35, 44, 45, 44, 45, + 46, 38, 23, 2, -15, -34, -52, -60, -70, -77, -80, -79, -74, -77, -84, -86, + -80, -72, -68, -72, -80, -87, -92, -96, -101, -104, -104, -101, -93, -90, -89, -86, + -85, -84, -83, -82, -81, -79, -77, -76, -73, -71, -66, -62, -55, -39, -31, -27, + -25, -31, -37, -46, -51, -53, -54, -48, -45, -38, -20, 3, 24, 35, 39, 32, + 16, 5, 3, 0, -6, -13, -13, -11, -2, 14, 28, 40, 50, 53, 50, 55, + 64, 74, 90, 105, 108, 112, 106, 104, 109, 112, 123, 127, 127, 127, 127, 127, + 127, 118, 113, 107, 110, 114, 111, 104, 101, 101, 102, 103, 99, 99, 89, 73, + 53, 35, 20, 0, -22, -43, -63, -77, -82, -76, -65, -48, -36, -29, -24, -25, + -29, -37, -40, -49, -59, -67, -73, -76, -78, -79, -75, -73, -74, -75, -68, -52, + -44, -30, -19, -9, -6, -9, -13, -24, -33, -35, -31, -30, -35, -40, -44, -45, + -51, -53, -54, -50, -50, -47, -42, -50, -55, -54, -56, -56, -54, -54, -49, -48, + -41, -32, -28, -18, -13, -5, 6, 18, 33, 49, 60, 71, 78, 88, 95, 97, + 93, 88, 91, 93, 97, 98, 97, 94, 91, 85, 81, 72, 70, 66, 61, 60, + 64, 66, 74, 83, 92, 102, 108, 109, 107, 102, 97, 95, 91, 87, 80, 74, + 67, 62, 61, 58, 61, 61, 57, 53, 43, 35, 27, 25, 24, 20, 20, 22, + 27, 34, 36, 32, 21, 8, -3, -10, -16, -18, -16, -16, -19, -15, -11, -11, + -12, -20, -34, -45, -59, -72, -80, -89, -94, -95, -102, -111, -114, -111, -111, -108, + -106, -104, -101, -98, -93, -90, -86, -86, -83, -82, -81, -79, -76, -73, -70, -72, + -78, -81, -79, -79, -72, -60, -43, -31, -25, -27, -34, -37, -40, -42, -41, -39, + -36, -34, -25, -12, -4, 5, 12, 16, 17, 15, 13, 6, -4, -7, -8, -6, + -1, 4, 7, 9, 12, 16, 19, 19, 22, 28, 29, 28, 29, 30, 34, 40, + 49, 57, 71, 78, 85, 92, 96, 95, 89, 85, 86, 93, 99, 104, 102, 100, + 94, 85, 77, 73, 69, 66, 63, 60, 60, 59, 57, 52, 47, 41, 31, 18, + 6, -3, -7, -11, -12, -14, -18, -22, -23, -22, -24, -30, -37, -41, -44, -50, + -56, -64, -67, -65, -62, -58, -58, -58, -59, -61, -62, -66, -72, -78, -79, -77, + -73, -68, -64, -61, -56, -53, -54, -52, -52, -57, -63, -69, -70, -68, -65, -62, + -59, -57, -56, -58, -60, -61, -63, -64, -62, -61, -60, -58, -54, -49, -45, -42, + -39, -36, -32, -28, -22, -13, -7, -3, 2, 13, 28, 41, 52, 64, 71, 73, + 73, 70, 64, 61, 60, 64, 66, 65, 66, 64, 61, 60, 62, 65, 64, 66, + 67, 67, 68, 66, 64, 66, 68, 73, 76, 74, 72, 66, 58, 52, 46, 42, + 38, 38, 41, 47, 52, 52, 48, 45, 42, 40, 38, 34, 29, 27, 26, 28, + 29, 28, 29, 30, 31, 28, 24, 21, 19, 17, 14, 10, 6, 3, -4, -9, + -15, -19, -26, -33, -40, -49, -55, -60, -65, -70, -73, -72, -72, -71, -70, -71, + -75, -78, -81, -83, -86, -86, -85, -84, -82, -80, -77, -72, -69, -66, -63, -61, + -61, -61, -61, -61, -60, -58, -53, -48, -42, -36, -30, -28, -30, -32, -33, -32, + -31, -28, -22, -18, -10, -5, 0, 3, 6, 11, 16, 19, 22, 24, 26, 27, + 29, 34, 40, 46, 48, 48, 48, 45, 40, 36, 33, 31, 33, 35, 40, 48, + 55, 62, 68, 73, 76, 78, 78, 77, 79, 82, 85, 87, 87, 87, 86, 86, + 86, 83, 78, 71, 63, 55, 48, 44, 39, 36, 36, 36, 35, 32, 28, 24, + 18, 13, 9, 6, 4, 1, -2, -5, -11, -17, -20, -21, -20, -21, -24, -28, + -32, -34, -33, -33, -35, -37, -40, -43, -47, -52, -58, -63, -69, -74, -77, -80, + -81, -82, -81, -80, -77, -74, -69, -62, -54, -48, -48, -51, -54, -57, -57, -57, + -56, -55, -55, -56, -57, -56, -55, -54, -54, -54, -54, -52, -49, -45, -41, -38, + -34, -31, -29, -27, -24, -20, -17, -11, -7, -3, 0, 5, 10, 16, 22, 27, + 31, 34, 38, 42, 44, 45, 48, 50, 52, 57, 61, 64, 64, 65, 65, 63, + 60, 57, 55, 55, 58, 61, 63, 65, 67, 69, 71, 74, 77, 79, 79, 77, + 74, 71, 68, 66, 63, 60, 57, 55, 51, 46, 40, 36, 30, 25, 20, 17, + 16, 17, 16, 14, 12, 10, 7, 3, -1, -5, -11, -15, -17, -18, -18, -19, + -21, -25, -29, -32, -33, -33, -36, -39, -43, -46, -50, -53, -56, -58, -59, -60, + -61, -62, -63, -65, -66, -67, -68, -70, -72, -72, -70, -67, -63, -61, -60, -60, + -58, -56, -54, -53, -52, -52, -52, -51, -50, -49, -47, -45, -43, -40, -37, -35, + -34, -32, -29, -25, -21, -18, -14, -9, -4, 0, 4, 7, 11, 15, 18, 21, + 25, 28, 33, 37, 41, 44, 46, 47, 47, 46, 46, 45, 43, 42, 42, 43, + 46, 48, 49, 50, 52, 55, 59, 62, 65, 66, 67, 68, 69, 69, 70, 72, + 74, 74, 73, 72, 71, 69, 65, 61, 57, 53, 50, 46, 43, 38, 35, 32, + 28, 23, 19, 17, 17, 15, 13, 11, 9, 5, 1, -3, -6, -9, -12, -14, + -17, -19, -23, -27, -31, -35, -38, -40, -43, -46, -48, -52, -55, -57, -61, -64, + -66, -67, -68, -69, -70, -70, -70, -69, -69, -70, -71, -70, -66, -62, -59, -55, + -52, -50, -46, -43, -41, -38, -36, -35, -35, -34, -33, -33, -33, -33, -31, -30, + -28, -26, -25, -24, -21, -20, -20, -19, -19, -18, -17, -16, -15, -13, -11, -8, + -3, 2, 9, 15, 21, 27, 33, 38, 41, 45, 48, 51, 53, 55, 56, 56, + 56, 56, 56, 56, 56, 55, 57, 58, 60, 61, 62, 62, 64, 66, 68, 69, + 71, 72, 73, 74, 72, 70, 67, 63, 60, 57, 54, 50, 46, 41, 36, 31, + 27, 23, 19, 16, 14, 12, 11, 9, 8, 5, 2, -1, -4, -8, -10, -15, + -18, -19, -20, -22, -22, -23, -23, -24, -26, -29, -31, -33, -35, -36, -37, -38, + -41, -44, -46, -48, -50, -52, -54, -56, -59, -61, -63, -63, -64, -65, -64, -63, + -62, -61, -60, -59, -58, -57, -58, -57, -57, -55, -53, -50, -49, -47, -46, -43, + -40, -37, -33, -31, -28, -26, -23, -20, -16, -14, -12, -9, -5, -2, 1, 5, + 9, 13, 17, 21, 24, 26, 29, 32, 35, 37, 37, 38, 39, 41, 43, 44, + 45, 46, 48, 50, 51, 53, 52, 52, 50, 48, 47, 46, 46, 46, 46, 47, + 48, 49, 51, 54, 56, 58, 60, 61, 62, 62, 62, 61, 59, 57, 55, 54, + 53, 52, 51, 49, 46, 41, 36, 31, 27, 22, 18, 14, 11, 9, 6, 3, + 0, -2, -5, -8, -11, -16, -20, -25, -28, -31, -34, -37, -39, -41, -41, -42, + -42, -42, -43, -45, -46, -47, -49, -50, -52, -54, -56, -57, -58, -60, -61, -63, + -64, -64, -64, -63, -63, -61, -59, -58, -57, -55, -54, -53, -52, -52, -51, -50, + -49, -47, -46, -45, -44, -42, -40, -38, -35, -32, -30, -28, -25, -22, -19, -17, + -15, -12, -9, -5, -1, 3, 7, 11, 15, 19, 23, 25, 27, 30, 34, 36, + 37, 38, 39, 40, 42, 44, 45, 46, 47, 49, 50, 52, 53, 52, 51, 49, + 47, 47, 46, 46, 46, 47, 47, 48, 50, 52, 55, 57, 59, 61, 62, 62, + 62, 61, 60, 58, 56, 54, 54, 53, 51, 50, 47, 44, 39, 34, 29, 25, + 20, 16, 13, 10, 7, 4, 2, -1, -3, -6, -9, -14, -18, -22, -26, -30, + -33, -35, -38, -40, -41, -41, -42, -42, -43, -44, -46, -47, -48, -49, -51, -53, + -55, -56, -57, -59, -60, -62, -63, -64, -64, -63, -63, -62, -60, -59, -57, -56, + -55, -53, -52, -52, -51, -51, -50, -48, -46, -45, -44, -43, -41, -39, -36, -34, + -31, -29, -26, -24, -21, -16, 1, -2, -1, -9, -9, -6, 5, 6, -1, -10, + 8, 24, 11, -2, -14, -9, -15, -13, 5, 14, 12, -6, -1, -12, 1, -9, + 12, 12, 10, 5, -19, -11, -13, -2, 8, 5, 1, -2, -3, 9, -6, 6, + 5, 6, -3, -17, -7, 3, 2, -1, 0, 7, -7, 5, 4, 6, -18, -24, + 6, 20, -1, -4, -1, 10, 3, -10, 8, 7, -11, -17, -15, 5, 18, 4, + 1, 8, -16, -4, 0, 11, 9, -10, -15, 0, -22, -12, 19, 34, 16, -9, + -16, -7, -12, -10, 13, 23, -1, -10, -2, -3, -11, 13, 7, -6, -9, 3, + 11, -10, -18, 12, 22, 7, -27, -29, -4, 20, 20, 10, 8, -16, -26, -6, + 22, 21, 7, 15, 8, -50, -50, -7, 35, 22, -13, 32, 41, -33, -46, -10, + 23, -7, -25, 23, 21, -38, -36, 14, 44, 2, 2, 34, -14, -51, -29, 11, + 19, 7, 22, 13, -23, -21, -8, -9, 1, 14, 26, 26, -8, -34, -33, 4, + 1, -6, -2, 16, -7, -23, 12, 27, 5, 6, 6, 0, -8, 0, -1, -17, + -13, -12, 3, 9, 4, 11, 23, 36, 0, -43, -16, 4, -21, -26, 27, 16, + -25, 3, 65, 4, -34, 24, -10, -38, -14, 13, 4, -15, 36, 44, -42, -51, + 20, -5, -6, 68, 20, -18, -39, -11, 9, 17, 6, -33, -20, -13, 48, 30, + 22, -4, -9, -53, -20, 32, 32, -16, 17, -11, -36, -8, -5, 39, 28, 33, + 21, -64, -48, 3, -22, 15, 62, -26, 0, 3, 5, 73, -14, -48, -20, -59, + 4, 70, 60, -7, -2, -88, -22, -17, 39, 17, 33, -3, 15, 28, -47, -80, + -37, 5, 7, 104, 16, -99, -92, -36, 109, 78, 26, -15, -92, -21, 62, 48, + -51, -81, -25, 55, 63, 35, 21, -115, -54, 101, 73, -41, -110, -66, 50, 107, + 45, -8, -109, -38, 12, 102, 3, 17, -45, -2, -36, 39, 46, -12, -28, -27, + -17, 17, -18, 82, -5, -3, -25, -5, -14, 15, 9, -3, -17, -6, 2, 7, + -36, -13, 6, 21, -23, -20, 16, -18, 3, -2, 26, 0, 13, -23, -2, -19, + -28, -18, 15, 12, 22, -4, 23, -17, -22, -9, -18, -4, 11, 13, 0, 34, + -16, -20, 26, 23, 15, -4, -25, 7, 8, -9, 8, 44, 1, -40, 17, -32, + 9, -30, -52, 52, 3, 2, -21, 83, 58, -14, -46, -61, -12, -67, -20, 64, + 72, 57, -10, 5, 1, -77, 31, -47, -39, 12, 22, 57, 28, 0, 9, -76, + 15, -74, 33, -12, 39, 114, -35, -36, -38, -23, 27, -21, 14, 56, 47, 6, + -72, -61, -4, 18, -4, 19, 13, 45, 71, 48, -1, -125, -52, -56, -20, -18, + -12, 51, 78, 68, -46, 32, -40, -29, -28, -81, -25, 75, 42, 58, -38, 1, + -29, -34, 31, -36, -14, 10, 64, 37, 2, -31, -72, -17, -33, 30, -52, -54, + 25, 43, 70, 81, -9, -73, 4, -65, 15, -28, 25, 0, 28, 19, 51, -26, + 6, 0, -37, -15, -22, -20, -16, -5, 50, 56, 67, 25, 16, -35, -29, -14, + -39, 19, -24, -52, -13, -32, -10, 39, 33, 59, 6, 37, 55, 11, -9, -35, + -15, -57, -56, -36, -34, 19, 19, 6, 20, 17, -11, 5, 26, 19, 16, 7, + -20, -26, -55, -62, -36, -18, 19, 37, 47, 25, -6, -14, 1, -4, -13, 12, + 23, 34, 38, 41, 33, 31, -10, -56, -52, -49, -31, -40, -21, -12, 0, 5, + 12, 22, 22, 21, 31, 12, 2, -8, -4, -18, -7, 3, 1, -1, 11, 12, + 18, 17, 9, -2, -12, -13, -11, -1, 8, 3, 3, 2, 5, -5, -16, -15, + -13, -8, -12, -9, -2, -1, 2, 7, 10, 7, 11, 14, 7, -1, -4, 5, + -3, -2, 0, -6, -10, -1, -5, 3, 9, 0, -8, -9, -6, -6, 0, 6, + 3, 6, 7, 10, 0, -8, -3, -5, -1, -8, -7, -4, -3, -3, 0, -1, + -6, 2, 7, 7, 5, 4, 10, 5, 8, -1, -11, -15, -11, -15, -10, -1, + -8, -12, -5, 1, 3, 6, 8, 11, 18, 22, 26, 10, -10, -1, -15, -3, + -21, -16, -14, -12, -7, -8, -18, -20, -11, 9, 20, 27, 26, 11, 1, 21, + 6, 3, -9, -15, -9, -20, 3, 5, 21, 14, 6, 11, -21, -22, -6, -21, + -23, -18, 11, 6, 5, 21, 9, 23, 16, -3, -30, -7, -27, -4, 5, 18, + 22, 16, 2, 7, -1, -2, -10, -14, -10, -17, -10, -15, -16, 3, 12, 30, + 18, -1, -6, -15, -3, 5, 11, -18, -2, 8, 21, 11, -13, -4, -30, -7, + 0, 12, 25, -3, 17, 14, -20, -6, -27, -41, -11, -12, 23, -8, 13, 24, + 18, 27, -11, -8, -12, -2, 17, 23, 13, -20, -21, -2, -21, -34, -46, -23, + 28, 48, 9, -10, 8, 29, 27, 5, -29, -12, 13, -5, -2, -35, 1, 3, + 24, 13, 17, -18, -30, -21, 14, -1, 6, -8, 48, 45, -7, -34, -49, -32, + -6, -26, 20, 29, 76, 30, -21, -66, -36, -15, 40, -5, 29, 3, 10, -39, + -25, -2, 24, 19, 19, -4, -8, 3, -22, -23, -18, 13, 17, -3, -25, 23, + 66, 26, -18, -27, -34, -30, -30, 36, 25, 28, -22, -17, -7, -22, 21, 18, + 42, 8, -25, -28, -31, -10, 15, 18, 0, -1, -5, 16, -12, 13, 13, 12, + -8, -37, -9, 13, -5, 8, -3, 13, -8, 4, 24, -16, -43, -18, 26, 26, + -11, -9, 19, 9, -15, 9, 15, -12, -31, -27, 8, 29, 5, 7, 17, -33, + -14, 14, 23, -1, -18, -18, -4, -35, -17, 47, 71, -16, -20, -11, -16, -25, + 6, 37, 14, -18, 1, -8, -14, 10, 14, 2, -20, 0, 20, -10, -25, 14, + 32, 7, -39, -38, -3, 34, 25, 13, 3, -24, -34, 5, 38, 18, 7, 29, + -30, -74, -41, 36, 40, -12, 26, 55, -17, -59, -26, 28, -2, -31, 24, 25, + -44, -39, 21, 44, -1, 10, 33, -34, -50, -12, 18, 13, 20, 17, -6, -31, + -10, -6, -1, 7, 12, 14, 6, -16, -24, 6, 9, -16, -16, 6, 2, -10, + 13, 12, -10, 0, 11, 11, 10, -3, -22, -22, -12, -7, 19, 17, -2, -12, + 6, 16, 7, -11, -1, -20, -22, -8, 26, 16, -3, 12, 1, -33, 2, 30, + -23, -5, 28, -17, -19, 21, 9, -28, -14, 25, -1, 4, 24, 0, -26, -9, + 7, 2, -2, 20, -10, -11, 5, -3, -4, 8, -9, 14, 18, 25, -22, -15, + -22, -3, -12, 27, 30, 15, -11, -26, -4, 15, -7, -14, 23, -23, -4, 34, + -2, -38, 14, -11, -24, 16, 34, 11, -13, 3, -3, -19, -34, 0, -3, 24, + 43, 1, -12, -38, -25, -11, 23, 35, 12, -28, -25, -16, 7, 22, 1, -10, + 8, 8, -3, 6, -24, -20, -13, 9, 31, 12, -16, 7, -29, 5, 8, -28, + 3, 4, 12, 26, -9, -15, -5, -20, 9, 21, 0, 1, -9, 0, 8, -3, + -7, -9, -3, 22, 8, 3, -11, -9, -11, 3, 15, 9, -10, 1, -3, -3, + -2, -5, 9, 0, 12, 7, -15, -7, 0, -8, 5, 9, -5, 7, -7, 10, + 4, -11, -2, -8, -4, 9, 9, 0, -2, -11, -3, -4, 3, 4, 3, -2, + 3, 3, -8, -9, -2, 0, 3, 5, -1, -10, -7, 2, 8, 3, 0, -5, + -5, 2, 4, -2, -5, -3, 2, 3, 0, 2, -5, -3, 3, 2, -2, -4, + -2, 1, 2, 1, 0, -1, 1, -2, -5, 0, 0, 2, 0, -3, -2, 0, + 1, 0, -2, -2, -2, 0, 3, 3, -2, -5, -1, -1, -1, -4, 3, 9, + 1, -1, -2, -11, -7, 1, 9, 11, 8, -4, -11, -12, -9, -4, 18, 15, + 14, 1, -22, -29, -14, 3, 30, 29, 14, -2, -35, -43, -11, 13, 36, 42, + 15, -16, -49, -44, -10, 28, 47, 38, 11, -25, -66, -39, 4, 36, 58, 33, + -3, -44, -65, -29, 19, 52, 54, 23, -13, -59, -65, -15, 32, 69, 49, 8, + -30, -74, -51, 3, 43, 71, 40, -5, -48, -77, -31, 16, 57, 67, 24, -15, + -67, -72, -12, 36, 66, 59, 5, -31, -80, -51, 3, 49, 75, 37, -2, -59, + -81, -28, 20, 67, 66, 22, -23, -76, -65, -10, 41, 78, 48, 4, -36, -85, + -47, 6, 59, 80, 31, -8, -69, -82, -22, 29, 73, 63, 17, -31, -81, -63, + -1, 47, 79, 47, 3, -56, -90, -40, 19, 75, 73, 28, -25, -86, -74, -10, + 48, 85, 56, 6, -51, -93, -48, 11, 67, 86, 33, -11, -78, -87, -29, 36, + 89, 66, 13, -38, -91, -60, 2, 50, 83, 48, 0, -56, -90, -41, 16, 71, + 78, 30, -17, -80, -75, -20, 31, 82, 62, 15, -32, -85, -66, -7, 48, 84, + 50, 4, -53, -87, -44, 8, 62, 78, 35, -8, -65, -83, -30, 23, 70, 71, + 24, -20, -76, -75, -12, 32, 73, 62, 15, -30, -85, -62, -2, 41, 76, 51, + 9, -39, -86, -52, 1, 45, 79, 46, 8, -49, -89, -46, 3, 54, 80, 43, + 7, -55, -83, -50, 0, 53, 76, 54, 11, -52, -83, -55, 0, 40, 67, 58, + 22, -32, -79, -67, -11, 28, 63, 52, 37, -9, -70, -63, -28, 10, 42, 49, + 53, 8, -46, -64, -41, 1, 22, 38, 51, 39, -16, -63, -46, -23, 5, 33, + 38, 48, 14, -42, -57, -29, -5, 22, 37, 40, 28, -23, -53, -39, -10, 14, + 30, 40, 31, -1, -48, -40, -18, 11, 19, 31, 26, 14, -20, -50, -25, -5, + 11, 31, 30, 14, 0, -35, -39, -4, -1, 19, 27, 17, 9, -10, -39, -21, + -8, 9, 24, 26, 13, -5, -19, -30, -12, -1, 17, 25, 16, 3, -19, -26, + -13, -6, 17, 22, 20, 5, -16, -32, -19, -1, 23, 27, 23, 4, -30, -33, + -23, -1, 35, 35, 24, -2, -41, -45, -21, 9, 45, 41, 22, -12, -50, -46, + -18, 28, 55, 45, 10, -27, -78, -42, 0, 53, 66, 32, -1, -61, -74, -28, + 27, 64, 64, 24, -28, -80, -66, -15, 53, 84, 48, 5, -59, -94, -41, 17, + 75, 80, 26, -21, -91, -79, -12, 48, 87, 55, 10, -58, -96, -46, 9, 80, + 81, 30, -23, -84, -80, -15, 49, 90, 49, 9, -57, -95, -45, 17, 76, 79, + 26, -20, -91, -75, -18, 52, 90, 52, 6, -59, -92, -41, 15, 68, 80, 31, + -21, -87, -76, -13, 45, 87, 49, 11, -60, -94, -35, 14, 80, 68, 22, -23, + -89, -66, -7, 47, 93, 44, -8, -61, -95, -31, 24, 86, 75, 10, -35, -96, + -66, -1, 61, 100, 44, -12, -77, -105, -33, 32, 97, 92, 16, -44, -111, -90, + -5, 65, 121, 65, -3, -80, -123, -59, 17, 98, 111, 46, -25, -112, -109, -33, + 42, 112, 90, 30, -55, -115, -84, -17, 66, 105, 71, 13, -73, -113, -61, 0, + 77, 96, 56, 4, -80, -108, -50, 8, 78, 93, 47, 3, -88, -98, -40, 7, + 65, 76, 53, 18, -71, -90, -44, 0, 39, 57, 43, 34, -19, -69, -54, -19, + 18, 32, 31, 34, 7, -40, -36, -21, -1, 12, 12, 25, 27, -9, -32, -14, + -14, 2, 0, 1, 20, 19, -2, -13, -11, -18, -12, -2, 18, 24, 12, -2, + -14, -19, -19, -12, 18, 24, 22, -2, -15, -32, -20, 3, 22, 26, 17, -13, + -31, -27, -13, 17, 33, 32, 5, -29, -47, -29, 2, 33, 42, 32, -6, -53, + -52, -24, 22, 51, 41, 27, -32, -74, -45, 0, 45, 59, 33, -1, -62, -66, + -31, 26, 73, 49, 17, -42, -80, -42, -8, 63, 72, 28, -10, -75, -72, -23, + 32, 88, 47, 13, -56, -93, -38, 10, 76, 69, 26, -20, -96, -66, -10, 48, + 90, 47, 0, -69, -103, -29, 25, 87, 73, 18, -35, -104, -68, -2, 61, 93, + 47, -5, -83, -98, -31, 30, 92, 68, 17, -39, -97, -63, -5, 64, 88, 35, + -9, -74, -86, -22, 31, 85, 54, 13, -44, -93, -46, 9, 65, 75, 23, -17, + -75, -78, -15, 39, 84, 54, 3, -52, -96, -46, 12, 71, 90, 29, -18, -89, + -87, -26, 36, 86, 72, 26, -37, -106, -77, -12, 45, 99, 68, 22, -46, -108, + -73, -10, 43, 87, 69, 19, -27, -92, -79, -12, 27, 63, 57, 26, 4, -53, + -75, -35, 12, 33, 37, 31, 26, -9, -53, -39, -16, 6, 20, 23, 22, 13, + -8, -22, -23, -18, -3, 9, 25, 19, 4, -8, -20, -17, -10, 6, 16, 17, + 13, -8, -34, -21, -6, 17, 33, 23, 6, -32, -51, -23, 11, 36, 46, 31, + -11, -46, -65, -31, 15, 59, 55, 28, -20, -73, -64, -26, 42, 78, 51, 14, + -53, -85, -48, -4, 70, 80, 38, -16, -80, -76, -32, 39, 90, 58, 19, -59, + -99, -50, 14, 71, 75, 36, -21, -94, -70, -23, 51, 88, 53, 9, -68, -97, + -40, 16, 83, 73, 29, -33, -100, -61, -13, 58, 87, 41, 0, -74, -81, -35, + 24, 87, 55, 20, -41, -88, -58, 0, 69, 73, 34, -5, -86, -75, -20, 38, + 79, 49, 13, -48, -90, -39, 2, 71, 68, 31, -16, -84, -67, -15, 38, 79, + 42, 12, -50, -85, -37, 2, 62, 71, 34, -5, -83, -75, -24, 27, 82, 51, + 27, -30, -88, -54, -15, 44, 73, 50, 16, -49, -81, -47, -6, 38, 58, 50, + 27, -31, -69, -52, -13, 15, 36, 45, 33, -5, -41, -44, -23, 2, 14, 27, + 33, 10, -25, -20, -18, -6, 1, -1, 17, 22, 3, -13, -10, -17, -13, -6, + 13, 24, 15, 1, -11, -19, -19, -16, 12, 24, 24, 3, -12, -29, -26, -1, + 18, 27, 19, -4, -31, -28, -19, 11, 30, 35, 12, -21, -46, -35, -6, 28, + 42, 36, 5, -46, -57, -31, 10, 50, 43, 33, -16, -71, -55, -9, 35, 62, + 38, 10, -51, -71, -40, 11, 69, 58, 24, -26, -81, -50, -18, 48, 79, 37, + 1, -62, -81, -32, 16, 84, 59, 20, -37, -96, -50, -2, 63, 78, 33, -4, + -85, -80, -20, 33, 88, 59, 10, -50, -107, -47, 14, 75, 85, 27, -19, -95, + -83, -15, 47, 94, 60, 8, -66, -105, -46, 15, 83, 81, 26, -23, -91, -76, + -18, 48, 92, 47, 1, -59, -94, -36, 18, 78, 66, 19, -27, -91, -60, -3, + 53, 80, 35, -8, -62, -86, -28, 27, 79, 66, 13, -38, -94, -62, 1, 56, + 95, 42, -6, -75, -96, -39, 22, 80, 80, 36, -20, -97, -92, -24, 30, 93, + 79, 32, -27, -102, -87, -22, 31, 81, 79, 29, -14, -81, -91, -25, 19, 56, + 63, 31, 11, -39, -77, -47, 3, 31, 37, 33, 27, 3, -48, -46, -20, 0, + 18, 22, 23, 16, -3, -20, -19, -15, -4, 2, 8, 5, 0, 0, 0, 1, + -1, -1, 3, -4, -2, 1, -1, -2, 2, 3, -6, 1, 2, -6, 2, 2, + -4, -1, 2, -5, 1, 4, -4, 0, -1, 0, -1, -2, 2, 2, -6, 0, + 4, -3, -3, 4, -2, -3, -2, 0, 1, 1, -2, -2, 3, -8, 27, -42, + 11, 21, -35, 34, -25, 12, 9, -24, 14, 13, -38, 53, -42, -3, 46, -73, + 55, -16, -9, 28, -49, 38, -12, -21, 49, -51, 20, 32, -73, 64, -28, -7, + 32, -50, 42, -11, -30, 49, -21, -31, 46, -25, -7, 20, -22, 18, -16, -10, + 21, -23, 5, 28, -35, 8, 0, 8, -26, 19, 6, -11, -20, 64, -46, -18, + 51, -73, 119, -117, 46, 36, -80, 67, -46, 22, 0, -24, 56, -59, 14, 26, + -40, 24, -9, 20, -20, -15, 43, -26, -11, 9, 14, -3, -31, 6, 54, -62, + 3, 67, -78, 20, 21, -25, 31, -41, 18, 27, -53, 32, 15, -48, 37, -11, + 4, -12, -3, 31, -24, -21, 42, -10, -45, 55, -32, 34, -43, -14, 86, -78, + 8, 39, -35, -2, 13, 2, 5, -11, -4, 7, 5, -31, 37, -4, -28, 28, + -9, -11, 10, -1, 4, -18, 17, -9, -13, 24, -18, 20, -18, -30, 59, -25, + -29, 48, -15, -29, 23, 4, -3, -18, 14, 6, -8, -19, 19, 8, -13, 0, + 13, -18, 4, 1, 0, 0, 10, -14, -12, 39, -46, 23, 9, -22, 23, -20, + -22, 63, -42, -28, 77, -66, 12, 38, -56, 31, 27, -77, 66, -11, -39, 59, + -33, -41, 92, -54, -50, 96, -36, -46, 46, -17, 31, -43, -28, 98, -57, -50, + 84, -22, -44, 39, -8, 17, -28, -13, 63, -67, 16, 10, 3, -15, -4, 36, + -34, -1, 26, -27, -2, 13, 7, -22, 0, 27, -11, -19, 6, 26, -42, 14, + 18, -7, -14, -10, 37, -14, -24, 25, -4, -5, -10, 3, 35, -39, -7, 31, + -8, -23, 15, 4, -1, -25, 28, 7, -35, 34, -16, -1, 9, -35, 45, -22, + -17, 48, -52, 24, 22, -65, 48, 7, -45, 47, -19, -33, 71, -70, 46, -7, + -52, 68, -25, -35, 48, -13, -17, 14, 2, -12, 8, -10, 1, 22, -32, 4, + 34, -26, -18, 29, -7, -19, 15, -7, 15, -8, -29, 50, -22, -35, 53, -19, + -37, 47, -9, -40, 41, 1, -27, 7, 3, 0, 0, -7, 13, -7, -21, 26, + 14, -44, 11, 40, -51, 10, 26, -28, 16, -13, -3, 31, -42, 11, 34, -52, + 11, 34, -43, 10, 29, -19, -21, 27, -10, -5, 10, -14, 11, 3, -35, 43, + 3, -52, 37, 22, -66, 49, -12, -19, 50, -58, 16, 42, -70, 50, -2, -42, + 60, -69, 43, 11, -57, 54, -8, -31, 23, -8, -7, 24, -32, 11, 21, -51, + 60, -44, -6, 68, -87, 33, 45, -79, 50, -7, -13, 21, -40, 31, 12, -41, + 18, 24, -39, 15, 7, -17, 25, -20, -12, 43, -47, 17, 6, -16, 10, 4, + -11, -1, 14, -10, -7, 6, 9, -23, 9, 3, 13, -30, 16, 16, -33, 17, + 4, -17, 23, -29, 3, 54, -86, 50, 11, -41, 30, -23, 15, 18, -60, 56, + 7, -65, 49, -4, -12, 1, -6, 19, -4, -33, 35, -10, -12, 13, -2, -2, + -2, 2, -10, 16, -8, -11, 19, -6, -19, 24, -14, 9, 3, -24, 24, -6, + -13, 19, -11, -6, 6, -9, 16, -8, -10, 14, -10, -1, -5, 16, -8, -25, + 37, -11, -27, 37, -14, -13, 19, -17, 14, -5, -15, 26, -27, 10, 11, -23, + 22, -5, -19, 25, -7, -28, 44, -35, 0, 25, -31, 31, -10, -26, 46, -41, + 2, 33, -40, 24, 8, -43, 44, -12, -25, 37, -25, -6, 29, -27, 5, 24, + -40, 24, -1, -25, 23, -1, -6, -2, -1, 14, -24, 8, 13, -11, 0, -13, + 16, 15, -56, 43, 12, -35, 14, -9, 18, -10, -19, 28, -3, -27, 23, -2, + -14, 27, -35, 10, 35, -68, 44, 7, -43, 46, -21, -25, 56, -35, -21, 51, + -33, -8, 28, -27, 19, -2, -26, 36, -26, 3, 13, -12, 6, -10, 8, -14, + 15, -12, 0, 13, -9, -16, 32, -27, 3, 23, -49, 49, -17, -31, 63, -64, + 25, 36, -76, 61, -11, -47, 75, -54, -9, 69, -81, 32, 29, -63, 46, -7, + -26, 39, -31, 6, 18, -26, 13, -5, 5, -5, -2, 5, -12, 17, -17, -2, + 22, -25, 1, 20, -19, 3, 6, -6, 3, -9, 10, -6, -3, 7, -7, -3, + 12, -5, -5, -11, 24, -7, -23, 24, 0, -14, 0, 12, -10, -2, 5, 0, + 1, -10, 10, -2, -17, 26, -11, -16, 28, -22, 6, 4, -17, 30, -27, -7, + 46, -54, 15, 29, -42, 25, -4, -15, 26, -29, 11, 15, -28, 19, -7, 1, + 8, -20, 14, 1, -15, 11, -2, -2, 0, -10, 15, -5, -12, 15, -1, -15, + 12, 4, -15, 9, -1, -9, 9, -5, -6, 13, -12, 1, 6, -6, -3, 6, + -4, 0, -6, 11, -9, -2, 13, -12, -2, -1, 8, -11, 4, 2, -6, 4, + -4, 4, 0, -13, 15, 0, -21, 23, -5, -15, 15, -2, -9, 6, -2, -4, + 2, 3, -1, -7, 7, -2, -9, 6, 2, -9, 4, 5, -12, 10, -9, 4, + 5, -16, 12, -2, -13, 20, -13, -4, 17, -23, 14, 2, -20, 22, -13, -3, + 15, -22, 12, 4, -18, 17, -7, -7, 13, -14, 6, 4, -10, 9, -5, -6, + 7, 0, -7, 8, -4, -1, 0, -6, 4, 7, -14, 2, 13, -16, 3, 10, + -15, 7, -1, -10, 14, -10, -2, 11, -9, -4, 7, -6, 3, -3, -5, 9, + -6, -3, 5, 1, -7, 3, -2, 0, -2, 0, 4, -3, -2, 4, -6, 4, + -2, -2, 0, 1, 0, -7, 7, -2, -7, 9, -7, -4, 11, -15, 11, -2, + -9, 9, -4, -3, 2, 3, -7, 5, 0, -5, 6, -7, 1, 7, -10, -2, + 13, -9, -4, 8, -4, -2, -1, 1, 1, -7, 4, 5, -8, 0, 6, -6, + 0, 3, -4, 0, 1, -2, 2, -4, -4, 8, -7, -1, 6, -9, 8, -3, + -6, 12, -12, 1, 10, -11, 1, 5, -6, 3, -2, -3, 7, -10, 2, 7, + -12, 5, 2, -5, 3, -5, 0, 6, -10, 3, 4, -8, 2, 2, -3, 3, + -8, 8, 2, -14, 10, 3, -12, 8, 2, -11, 8, -2, -6, 9, -7, -4, + 10, -9, -1, 7, -7, 1, 3, -8, 8, -2, -8, 10, -3, -5, 5, -6, + 3, 1, -8, 10, -5, -5, 7, -4, -2, 2, -3, 1, -1, -3, 4, -3, + 0, 0, 0, 0, -4, 3, -2, -3, 3, -5, 3, 0, -7, 5, 1, -8, + 5, 1, -6, 6, -5, 0, 3, -7, 3, 2, -6, 3, 2, -6, 3, 1, + -3, -2, 5, -4, -1, 3, -4, 0, 0, -3, 5, -5, -3, 7, -5, -3, + 6, -4, 0, -1, -3, 3, -2, -1, 2, -1, -2, 1, -2, 1, -1, -7, + 8, -1, 5, -7, 13, -22, 8, -7, 8, -110, -28, 24, 54, 36, 2, 60, + -45, 57, 42, -43, 20, 41, -66, 24, -11, 18, -18, -38, -63, -36, 30, -11, + 33, 25, 30, 18, 11, -18, -5, 5, -46, 40, 1, -13, -18, -20, -31, 20, + 10, 29, -7, -18, 40, -29, -17, 42, -19, 6, -4, 6, -8, 10, -26, -5, + 3, 1, -17, 6, 0, 19, -1, 8, 0, -6, -10, -1, -12, -1, 1, -3, + 8, -7, 4, 11, 4, 14, -13, 16, -19, -4, -13, -13, -14, 6, 4, -1, + 4, 11, -1, 11, -1, 1, -4, -1, -15, 6, -9, 1, -1, 0, 3, 1, + -8, 3, -1, -1, 2, -2, 2, -2, 1, -5, -7, 3, -3, 6, -3, 4, + -1, 0, -4, 2, -7, 3, -6, -1, -1, 4, 0, 3, -2, 2, -5, 5, + -8, -3, -3, 2, -5, 7, -1, 4, -2, 4, -10, 6, -6, -1, -4, 5, + -13, 7, -6, 5, -8, 17, -20, 14, -6, 9, -40, 71, -127, 9, -73, 127, + 76, -28, 74, -32, 8, -62, -49, -38, 40, -68, 22, -12, 68, 10, 39, -10, + 0, 35, -23, 0, -59, -15, -7, -3, -23, 1, -20, 37, 27, 2, 30, -2, + 17, 2, -5, -7, -27, -29, 16, -3, -11, 1, -16, -5, -8, -10, 7, 32, + 9, 5, -4, 16, 5, -8, -17, -16, 5, -13, 8, 11, 15, -10, -9, 0, + -1, 2, 7, -3, -23, 9, 2, 3, 1, -13, -1, -6, 11, -6, 8, 1, + 12, -12, 9, -14, 8, -1, 0, -3, -13, 4, -7, -4, 8, 5, -5, -7, + 4, -2, -3, 2, 3, -6, 8, -3, 1, -3, -2, 2, -6, 2, -4, -3, + -4, 3, 1, 0, 0, 1, -1, -1, 2, -2, 0, -4, -2, 1, 2, 0, + -3, 1, -3, 0, -1, -3, -6, 2, -2, 3, -4, 10, -8, 9, -5, 12, + -19, 46, 37, -128, 60, -90, 102, -65, 40, -57, 39, -6, 23, -8, 19, 24, + 15, -17, -47, -27, -36, -16, 21, 3, 23, 14, 50, -8, 19, 25, 7, -9, + -28, -63, -37, 0, -42, 54, -17, 68, -3, 30, -12, -4, 11, -15, 9, -25, + -15, -2, -27, -25, 38, -8, -13, 33, 24, 12, -38, 39, -12, -3, -17, -44, + 38, 2, 27, 3, -5, -4, -13, -30, -56, -4, 11, 1, 9, 17, 46, 25, + -14, 6, -3, -7, -21, 2, 16, -5, -22, 2, -2, 6, -12, -25, -15, 10, + 9, 8, 11, 43, 8, -5, -22, -16, 14, -31, 16, 7, -7, -26, -20, -2, + 9, 11, 26, 7, 6, -20, -13, 0, 4, 17, -17, -18, 10, 2, -10, 27, + -8, 24, -23, -14, 1, 0, 13, -19, 14, 10, -16, 16, -4, -20, 20, -33, + 2, 2, 24, 21, -3, -26, -24, -18, -18, 10, 10, 24, 18, 2, 9, -24, + 16, -14, -8, 9, -5, -14, 8, -5, 30, -11, 11, -13, -15, -12, 7, 4, + -13, -13, 13, -13, 12, 23, 9, 0, 14, -10, -9, -35, -2, -21, 12, -1, + 17, 19, 11, -4, 0, -18, -24, 11, -10, 1, 11, 12, -13, -16, 10, -23, + 21, 9, -9, 3, 12, -6, 3, -5, 12, 0, -2, 0, -19, -9, 5, -11, + -7, 10, 1, -3, 9, 18, -6, 0, -1, 1, -13, 2, 1, -3, -8, 17, + -4, -9, 18, -15, 8, -1, -11, -5, -14, 11, -5, -7, 12, 16, -7, 7, + -3, -11, -5, -6, 1, 4, -3, -3, 15, 5, 0, 3, 6, -16, 4, -14, + -6, -9, -4, 2, 11, 11, 7, -2, 4, -12, -7, -14, -6, -7, 9, 4, + 7, -2, 6, 5, 6, -4, -3, -4, 7, -7, -11, -9, 0, -3, 7, -2, + -2, 3, 13, -4, -6, -15, 9, -7, -1, 4, 6, 5, 8, -6, -8, 0, + -11, -4, 6, -8, 4, 3, 5, 13, -4, -9, -3, 4, -3, -3, 4, -1, + -12, 6, -14, 2, 3, 15, 2, 6, -7, -8, 3, 1, -2, 3, -3, -12, + -6, -14, 7, -2, 13, 6, 10, 6, 0, -2, -10, -12, -8, -6, -7, -6, + 6, 4, -2, 5, 2, 0, -1, 3, -11, 4, 0, 20, -8, -2, 0, -1, + -3, 7, -3, -4, -2, -6, -10, -10, -8, 1, 2, 5, 8, 2, 5, 8, + 3, 4, 3, -2, -15, 0, -1, -7, -2, -5, -10, 10, -1, 5, 3, 5, + -1, -2, -8, -5, -9, 1, -8, 6, 5, 4, 1, 1, 2, 3, -2, 4, + -7, 1, -7, -9, -2, 0, 2, 3, 6, -8, 8, 3, 0, -2, -9, -3, + -2, 0, 3, -1, -2, -3, 7, -3, 10, -8, 1, -12, 3, -7, 2, -3, + 7, 4, 4, 0, 0, -6, -1, -5, -3, -4, -7, 0, 5, 7, 0, 2, + -3, 10, -1, 3, -7, -5, -4, -9, -3, -7, 5, -4, 9, 2, 1, 4, + 5, 0, -5, 1, -8, 4, -9, 5, -5, 0, 3, -2, -1, 1, 1, -7, + 7, 0, 3, -5, 0, -3, -1, -1, -5, -1, 1, -1, 1, -1, 0, 2, + 0, 2, -7, -7, 4, -1, 0, 3, 4, -1, -3, -4, -6, 3, -2, 4, + -1, 5, -2, -1, -5, -2, -4, 1, 3, 2, 2, 0, -3, 1, 1, -3, + -3, -1, 1, -3, -2, -1, -2, -3, -1, 0, 4, 3, 5, 2, 1, -4, + -9, -3, -7, 1, -2, 7, -2, 3, 3, 3, 1, 0, -1, -6, -7, -6, + -4, -1, 1, 0, 5, 2, -2, 2, -3, -1, 3, -1, 1, -4, -4, -5, + 0, -7, 2, -4, 3, 4, 1, 2, -1, -1, -2, -2, 0, -1, 1, -1, + -1, -3, 1, 1, 3, -3, -1, 1, 1, -2, -3, -8, -5, 0, -1, 5, + 2, 3, 1, -2, -1, -1, -3, 1, 1, -2, -3, -3, -1, 0, -1, 1, + 2, 2, 5, 0, -1, -2, -1, -2, 0, -4, 0, -5, -1, -1, 0, 1, + 5, 4, -2, -1, -2, 0, -6, -1, 0, 1, -1, -2, 1, 0, 0, 3, + 1, -2, 1, -2, -4, -1, 0, -1, -1, -4, -2, -4, 2, -1, 1, 0, + 3, 2, 0, 4, -1, 4, -6, 2, -4, -3, -5, -4, -3, 0, 2, 0, + 1, 4, 2, 2, -2, -2, -5, -6, -5, -3, -2, 1, -1, 0, 0, 2, + 2, 2, 0, 4, -2, 3, 2, -1, -2, -3, -3, -3, -5, -5, -5, -1, + -1, 0, 2, 2, 4, 1, 2, 1, 2, -1, -1, -3, -4, -5, -3, -2, + -2, -1, 1, 4, 2, 2, 2, 1, -1, -2, -6, -2, -3, 2, -1, 1, + -2, 0, 2, 1, 2, -2, 1, 0, -2, -2, -3, 0, -2, -1, -1, 0, + -2, -2, 1, 0, 2, -1, 1, -1, 0, -1, -1, -7, 8, -1, 5, -7, + 13, -22, 8, -7, 8, -110, -28, 24, 54, 36, 2, 60, -45, 57, 42, -43, + 20, 41, -66, 24, -11, 18, -18, -38, -63, -36, 30, -11, 33, 25, 30, 18, + 11, -18, -5, 5, -46, 40, 1, -13, -18, -20, -31, 20, 10, 29, -7, -18, + 40, -29, -17, 42, -19, 6, -4, 6, -8, 10, -26, -5, 3, 1, -17, 6, + 0, 19, -1, 8, 0, -6, -10, -1, -12, -1, 1, -3, 8, -7, 4, 11, + 4, 14, -13, 16, -19, -4, -13, -13, -14, 6, 4, -1, 4, 11, -1, 11, + -1, 1, -4, -1, -15, 6, -9, 1, -1, 0, 3, 1, -8, 3, -1, -1, + 2, -2, 2, -2, 1, -5, -7, 3, -3, 6, -3, 4, -1, 0, -4, 2, + -7, 3, -6, -1, -1, 4, 0, 3, -2, 2, -5, 5, -8, -3, -3, 2, + -5, 7, -1, 4, -2, 4, -10, 6, -6, -1, -4, 5, -13, 7, -6, 5, + -8, 17, -20, 14, -6, 9, -40, 71, -127, 9, -73, 127, 76, -28, 74, -32, + 8, -62, -49, -38, 40, -68, 22, -12, 68, 10, 39, -10, 0, 35, -23, 0, + -59, -15, -7, -3, -23, 1, -20, 37, 27, 2, 30, -2, 17, 2, -5, -7, + -27, -29, 16, -3, -11, 1, -16, -5, -8, -10, 7, 32, 9, 5, -4, 16, + 5, -8, -17, -16, 5, -13, 8, 11, 15, -10, -9, 0, -1, 2, 7, -3, + -23, 9, 2, 3, 1, -13, -1, -6, 11, -6, 8, 1, 12, -12, 9, -14, + 8, -1, 0, -3, -13, 4, -7, -4, 8, 5, -5, -7, 4, -2, -3, 2, + 3, -6, 8, -3, 1, -3, -2, 2, -6, 2, -4, -3, -4, 3, 1, 0, + 0, 1, -1, -1, 2, -2, 0, -4, -2, 1, 2, 0, -3, 1, -3, 0, + -1, -3, -6, 2, -2, 3, -4, 10, -8, 9, -5, 12, -19, 46, 37, -128, + 60, -90, 102, -65, 40, -57, 39, -6, 23, -8, 19, 24, 15, -17, -47, -27, + -36, -16, 21, 3, 23, 14, 50, -8, 19, 25, 7, -9, -28, -63, -37, 0, + -42, 54, -17, 68, -3, 30, -12, -4, 11, -15, 9, -25, -15, -2, -27, -25, + 38, -8, -13, 33, 24, 12, -38, 39, -12, -3, -17, -44, 38, 2, 27, 3, + -5, -4, -13, -30, -56, -4, 11, 1, 9, 17, 46, 25, -14, 6, -3, -7, + -21, 2, 16, -5, -22, 2, -2, 6, -12, -25, -15, 10, 9, 8, 11, 43, + 8, -5, -22, -16, 14, -31, 16, 7, -7, -26, -20, -2, 9, 11, 26, 7, + 6, -20, -13, 0, 4, 17, -17, -18, 10, 2, -10, 27, -8, 24, -23, -14, + 1, 0, 13, -19, 14, 10, -16, 16, -4, -20, 20, -33, 2, 2, 24, 21, + -3, -26, -24, -18, -18, 10, 10, 24, 18, 2, 9, -24, 16, -14, -8, 9, + -5, -14, 8, -5, 30, -11, 11, -13, -15, -12, 7, 4, -13, -13, 13, -13, + 12, 23, 9, 0, 14, -10, -9, -35, -2, -21, 12, -1, 17, 19, 11, -4, + 0, -18, -24, 11, -10, 1, 11, 12, -13, -16, 10, -23, 21, 9, -9, 3, + 12, -6, 3, -5, 12, 0, -2, 0, -19, -9, 5, -11, -7, 10, 1, -3, + 9, 18, -6, 0, -1, 1, -13, 2, 1, -3, -8, 17, -4, -9, 18, -15, + 8, -1, -11, -5, -14, 11, -5, -7, 12, 16, -7, 7, -3, -11, -5, -6, + 1, 4, -3, -3, 15, 5, 0, 3, 6, -16, 4, -14, -6, -9, -4, 2, + 11, 11, 7, -2, 4, -12, -7, -14, -6, -7, 9, 4, 7, -2, 6, 5, + 6, -4, -3, -4, 7, -7, -11, -9, 0, -3, 7, -2, -2, 3, 13, -4, + -6, -15, 9, -7, -1, 4, 6, 5, 8, -6, -8, 0, -11, -4, 6, -8, + 4, 3, 5, 13, -4, -9, -3, 4, -3, -3, 4, -1, -12, 6, -14, 2, + 3, 15, 2, 6, -7, -8, 3, 1, -2, 3, -3, -12, -6, -14, 7, -2, + 13, 6, 10, 6, 0, -2, -10, -12, -8, -6, -7, -6, 6, 4, -2, 5, + 2, 0, -1, 3, -11, 4, 0, 20, -8, -2, 0, -1, -3, 7, -3, -4, + -2, -6, -10, -10, -8, 1, 2, 5, 8, 2, 5, 8, 3, 4, 3, -2, + -15, 0, -1, -7, -2, -5, -10, 10, -1, 5, 3, 5, -1, -2, -8, -5, + -9, 1, -8, 6, 5, 4, 1, 1, 2, 3, -2, 4, -7, 1, -7, -9, + -2, 0, 2, 3, 6, -8, 8, 3, 0, -2, -9, -3, -2, 0, 3, -1, + -2, -3, 7, -3, 10, -8, 1, -12, 3, -7, 2, -3, 7, 4, 4, 0, + 0, -6, -1, -5, -3, -4, -7, 0, 5, 7, 0, 2, -3, 10, -1, 3, + -7, -5, -4, -9, -3, -7, 5, -4, 9, 2, 1, 4, 5, 0, -5, 1, + -8, 4, -9, 5, -5, 0, 3, -2, -1, 1, 1, -7, 7, 0, 3, -5, + 0, -3, -1, -1, -5, -1, 1, -1, 1, -1, 0, 2, 0, 2, -7, -7, + 4, -1, 0, 3, 4, -1, -3, -4, -6, 3, -2, 4, -1, 5, -2, -1, + -5, -2, -4, 1, 3, 2, 2, 0, -3, 1, 1, -3, -3, -1, 1, -3, + -2, -1, -2, -3, -1, 0, 4, 3, 5, 2, 1, -4, -9, -3, -7, 1, + -2, 7, -2, 3, 3, 3, 1, 0, -1, -6, -7, -6, -4, -1, 1, 0, + 5, 2, -2, 2, -3, -1, 3, -1, 1, -4, -4, -5, 0, -7, 2, -4, + 3, 4, 1, 2, -1, -1, -2, -2, 0, -1, 1, -1, -1, -3, 1, 1, + 3, -3, -1, 1, 1, -2, -3, -8, -5, 0, -1, 5, 2, 3, 1, -2, + -1, -1, -3, 1, 1, -2, -3, -3, -1, 0, -1, 1, 2, 2, 5, 0, + -1, -2, -1, -2, 0, -4, 0, -5, -1, -1, 0, 1, 5, 4, -2, -1, + -2, 0, -6, -1, 0, 1, -1, -2, 1, 0, 0, 3, 1, -2, 1, -2, + -4, -1, 0, -1, -1, -4, -2, -4, 2, -1, 1, 0, 3, 2, 0, 4, + -1, 4, -6, 2, -4, -3, -5, -4, -3, 0, 2, 0, 1, 4, 2, 2, + -2, -2, -5, -6, -5, -3, -2, 1, -1, 0, 0, 2, 2, 2, 0, 4, + -2, 3, 2, -1, -2, -3, -3, -3, -5, -5, -5, -1, -1, 0, 2, 2, + 4, 1, 2, 1, 2, -1, -1, -3, -4, -5, -3, -2, -2, -1, 1, 4, + 2, 2, 2, 1, -1, -2, -6, -2, -3, 2, -1, 1, -2, 0, 2, 1, + 2, -2, 1, 0, -2, -2, -3, 0, -2, -1, -1, 0, -2, -2, 1, 0, + 2, -1, 1, -1, 0, -1, -1, 1, -7, 5, -22, -32, -35, -32, -43, -35, + -55, -42, -66, -48, -80, -57, -17, -128, -59, -76, 0, -26, 1, -33, 21, 3, + 16, 15, 26, 43, 28, 66, 6, 97, 40, 103, 67, 101, 102, 98, 94, 21, + 98, 90, 57, 78, 89, 81, 61, -6, 54, 4, 62, 19, 27, 34, 12, 16, + 14, -17, 19, -5, -2, -13, -38, -24, -3, -33, -14, -11, -16, 0, -13, 7, + -26, -13, -16, 6, -57, -23, -28, -13, -9, -34, -32, -20, -87, -62, -28, -38, + -75, -37, -27, -41, -71, -48, -30, -44, -83, -67, -52, -48, -45, -46, -45, -63, + -47, -40, -32, -45, -24, -32, -43, -21, -17, 0, 21, 26, 43, 51, 62, 47, + 41, 55, 57, 68, 34, 53, 63, 62, 71, 60, 61, 56, 53, 56, 54, 38, + 50, 58, 50, 40, 28, 54, 39, 41, 38, 22, 32, 20, -3, 19, -1, -7, + -6, -16, -16, -14, -27, -29, -46, -66, -61, -51, -54, -61, -41, -50, -47, -52, + -55, -45, -44, -28, -58, -56, -31, -37, -36, -32, -18, -16, -34, -29, -9, -21, + -20, -30, -22, -17, -19, -8, -12, -14, -6, -14, -6, -11, -2, 4, -6, 9, + 8, 17, 23, 13, 31, 13, 24, 30, 28, 29, 30, 43, 34, 37, 52, 42, + 44, 50, 67, 59, 49, 54, 48, 43, 51, 45, 42, 62, 47, 39, 37, 36, + 24, 28, 13, 3, 9, -11, -3, -9, -14, -18, -34, -27, -29, -39, -42, -38, + -46, -37, -46, -43, -41, -35, -38, -31, -38, -34, -39, -39, -34, -48, -44, -47, + -49, -54, -52, -44, -53, -37, -47, -38, -31, -38, -27, -19, -19, -15, -16, 0, + 0, 2, 7, 13, 29, 22, 32, 32, 39, 47, 41, 40, 55, 48, 41, 44, + 57, 43, 36, 47, 43, 42, 37, 32, 32, 27, 33, 36, 30, 23, 25, 25, + 22, 18, 22, 20, 16, 8, 6, 12, 7, 0, 1, 3, -5, -14, -9, -7, + -8, -19, -15, -16, -23, -21, -21, -32, -31, -29, -26, -27, -29, -33, -26, -29, + -30, -39, -28, -41, -43, -35, -34, -32, -29, -28, -28, -25, -27, -24, -27, -27, + -27, -22, -23, -17, -9, -10, -14, -10, -8, -4, -2, -1, -3, 5, 4, 10, + 11, 7, 13, 11, 14, 27, 22, 22, 22, 27, 36, 34, 36, 37, 45, 44, + 47, 48, 51, 49, 52, 51, 52, 48, 50, 47, 48, 42, 40, 29, 33, 24, + 22, 12, 5, 0, -3, -5, -9, -21, -21, -25, -19, -28, -28, -30, -33, -39, + -42, -42, -46, -46, -45, -42, -43, -47, -47, -36, -32, -30, -34, -31, -22, -29, + -29, -30, -26, -28, -30, -21, -26, -27, -21, -19, -16, -11, -12, -8, -2, 1, + -4, 1, 0, 1, 9, 8, 7, 12, 10, 13, 20, 17, 18, 21, 26, 29, + 30, 30, 29, 34, 33, 34, 33, 30, 32, 33, 28, 33, 29, 35, 32, 31, + 30, 31, 30, 25, 27, 24, 21, 21, 20, 16, 17, 12, 6, 4, -3, 1, + -6, -7, -11, -13, -11, -10, -8, -13, -12, -9, -17, -14, -19, -24, -22, -24, + -30, -32, -30, -33, -37, -39, -40, -42, -39, -41, -39, -40, -41, -35, -35, -35, + -37, -36, -33, -30, -25, -25, -19, -16, -16, -10, -6, -7, -4, -2, 1, 3, + 6, 10, 9, 15, 17, 18, 17, 13, 19, 18, 17, 19, 20, 24, 24, 27, + 27, 29, 30, 26, 28, 28, 27, 28, 26, 25, 24, 25, 20, 19, 17, 18, + 15, 12, 13, 10, 6, 8, 6, 3, 4, 3, 0, -3, 0, -1, -2, -5, + -4, -5, -4, -5, -6, -8, -9, -9, -12, -11, -16, -16, -15, -15, -13, -17, + -16, -17, -17, -21, -20, -25, -24, -24, -24, -26, -30, -30, -27, -30, -26, -26, + -27, -27, -25, -24, -19, -20, -17, -13, -12, -8, -8, -8, -6, -5, -2, -1, + 0, 3, 8, 10, 12, 16, 18, 24, 25, 25, 28, 30, 28, 32, 33, 31, + 32, 31, 35, 33, 31, 31, 27, 28, 26, 23, 23, 20, 22, 18, 16, 13, + 11, 9, 5, 4, -2, -2, -3, -8, -9, -11, -12, -13, -15, -15, -15, -15, + -15, -14, -12, -12, -13, -13, -8, -11, -10, -12, -10, -12, -12, -8, -8, -9, + -9, -9, -8, -9, -10, -11, -11, -10, -13, -14, -13, -16, -16, -17, -17, -18, + -19, -18, -17, -16, -16, -15, -15, -13, -12, -10, -12, -10, -9, -8, -6, -6, + -3, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 15, 15, 14, 13, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, + 3, 2, 1, 0, -1, -1, -2, -3, -4, -5, -5, -6, -7, -7, -8, -9, + -9, -10, -11, -11, -12, -12, -13, -13, -13, -13, -14, -14, -14, -15, -15, -15, + -15, -15, -15, -16, -16, -16, -15, -15, -15, -14, -13, -13, -12, -11, -10, -9, + -8, -7, -6, -5, -4, -2, -1, 0, 1, 2, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 13, 12, 11, 10, + 9, 7, 6, 5, 3, 1, 0, -2, -4, -5, -7, -9, -10, -11, -13, -14, + -15, -15, -16, -17, -17, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -17, -17, -16, -16, -15, -14, -14, -13, -12, -11, -10, -9, -8, -7, -6, + -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, + 11, 11, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 14, 14, 14, 13, 12, 12, 11, 10, 9, 8, 8, 7, + 6, 5, 4, 3, 2, 1, 0, 0, -1, 10, -20, 30, 25, 21, 14, 4, + 15, -48, -33, 11, -70, 54, -5, -21, -8, -3, 73, -52, 65, -55, 80, -28, + -67, -3, -13, 21, -49, -2, 11, 36, 59, -60, 34, -28, 21, -25, -45, 54, + 5, 0, -19, -12, 20, 54, -51, -23, 22, 36, -59, -20, 8, 28, -9, -54, + 127, -44, 69, -128, 5, 69, -8, -98, 45, 69, 20, -97, 23, -7, 121, -81, + -2, -21, 51, -67, -14, -24, 127, -60, 45, -116, 127, -29, -93, -23, 107, -5, + -21, -62, 37, 41, 29, -74, -63, 103, 24, -59, -44, 62, 43, -28, -46, 7, + 72, 19, -70, -47, 42, 53, -68, -13, 37, 59, -38, -60, 39, 66, 27, -128, + 36, 77, 15, -74, -15, 75, 38, -49, -11, -39, 16, -8, -30, 35, 41, -1, + -2, 17, -68, 99, -97, 60, -49, 32, -44, -29, 82, -26, 39, -35, 10, 38, + -20, -21, -92, 83, -24, 13, 31, -33, 22, 45, -31, -24, 9, -24, -32, 42, + -17, 34, 7, -27, 6, 61, -9, -34, -5, -8, -17, -6, -34, 17, 43, -9, + 35, -34, 16, 27, -24, -17, -17, 5, -17, 42, -31, 22, 17, -26, -22, 32, + 41, -27, -25, -10, -5, 16, -2, 13, -1, 48, -33, -27, 6, 16, 13, -37, + -11, 18, 25, -42, -11, 46, -7, -15, 9, 15, 4, -3, -36, -24, 31, -8, + 14, 12, 27, -19, -17, -14, -7, 42, -5, -15, 5, 1, -15, 14, 43, -19, + 1, -25, -35, 16, 16, 29, -12, 8, -14, 1, 21, -8, -12, -22, -4, 24, + 26, -16, -22, 37, 3, -41, 7, 4, 3, 30, 4, -27, 11, -6, -26, 33, + 23, -23, -14, -20, -7, -4, 36, 0, 18, 10, -27, 1, 1, 16, -1, -4, + -44, -5, 17, 9, 13, -4, -3, 31, 24, -14, -26, 9, -27, -28, 19, 22, + 32, -11, -15, 5, 15, -23, -21, 16, 14, 18, -11, -26, 13, 10, -12, -12, + 11, 14, -6, -13, -3, 6, -6, 3, 12, 32, 14, -22, -45, -10, 37, 11, + -50, -11, 50, 22, -13, -4, -4, 15, -16, -33, 7, 34, -9, -14, -1, 21, + 15, -14, -12, -6, 7, 8, 2, 0, -5, 6, 15, 4, -9, 13, 3, -51, + -18, 27, 10, 5, -11, 6, -1, 5, 22, 2, -14, -39, -12, 19, 17, 4, + 11, 5, -25, 2, 23, 8, 2, -3, -39, -22, 4, 18, 6, 14, 25, 20, + -17, -20, 17, 7, -43, -38, -18, 17, 24, -6, 30, 44, 6, -36, -20, 7, + 24, 1, -69, -25, 47, 15, -4, 35, 19, -18, -22, -12, 20, 39, -36, -49, + 9, 28, -16, 9, 34, 36, -22, -69, -16, 39, 7, -28, -3, 33, -18, -7, + 18, 53, 24, -37, -61, -10, 38, 2, -24, -11, 12, 17, 0, 28, 50, -5, + -59, -57, 22, 14, -15, -5, 22, 9, -20, 19, 33, 31, -33, -62, -13, -2, + 45, -9, -4, -3, 19, 8, -8, 40, 8, -16, -44, -19, 16, 3, 23, -32, + 22, 5, -9, 5, 26, 21, -27, -18, -45, 3, 15, 0, 7, 7, 7, 13, + 18, -10, 3, -5, -30, -30, -3, 9, 31, 17, -10, 19, 28, -33, -20, 31, + 14, -67, -27, 13, 20, 29, 1, -2, 24, -3, -26, -12, 32, -7, -31, -17, + 5, 22, 11, -6, 6, 7, 2, 7, 5, -12, -22, -17, -24, 22, 47, 1, + 2, 10, 5, -29, -5, 13, 1, -30, -28, -5, 23, 25, 6, 5, 1, 7, + 0, 5, 3, -33, -37, -6, 19, 20, 26, -1, -15, 21, 9, -14, -13, 0, + -11, -24, -9, 9, 23, 1, 1, 32, 11, -25, -18, 5, -5, -6, -9, -10, + 2, 18, 4, 12, 6, -2, -8, 2, 2, -7, 2, -22, -5, 17, 25, 15, + -5, -1, -24, -8, -10, -5, 12, 7, -4, -10, 4, 8, 22, 11, -1, -12, + -31, -17, 6, 12, 11, 5, -3, -1, 22, 0, -4, 3, -18, -17, -3, 16, + 9, 2, -5, 0, 4, -9, 18, 17, -22, -19, -8, -6, 21, 11, -6, -16, + 33, 13, -15, -3, -15, 1, -3, -10, -7, 8, 17, -11, 9, 19, 0, 5, + 0, -18, -13, 2, -20, 10, 29, -11, -13, 5, 11, 16, 4, -25, -21, 13, + -5, 1, 3, -1, 6, 13, -7, -1, 17, -6, -6, -9, -6, -3, -1, 1, + 18, 11, -22, 2, 18, -2, -15, 1, 5, -12, -10, -7, 9, 26, 10, -11, + 5, 0, -7, -3, -11, -9, -3, 2, -10, 19, 28, -3, -3, -4, 9, -14, + -5, -7, 8, -3, -27, 5, 37, 11, -2, 3, -27, -15, 12, -2, 14, 2, + -8, -16, 22, 11, -1, 10, -17, -8, -5, -23, 2, 29, 8, -21, 8, 12, + 6, 8, -17, 3, -2, -12, -27, 16, 25, -5, -7, 2, 19, 1, -15, 7, + 2, -5, -34, 2, 18, 17, -10, 2, 18, -1, -12, -10, 5, 1, -16, -9, + 12, 21, 4, -10, 2, 12, 1, -19, -11, 20, 5, -14, -21, 5, 17, -5, + 3, 17, 4, -25, -5, 5, 4, 0, -5, 2, 2, -1, 1, 13, 0, -11, + -8, 3, 2, -1, -3, -3, 11, 8, -6, 2, 7, 4, -5, -23, -2, 14, + -1, -15, -2, 15, 10, 1, -4, 16, 1, -24, -12, 8, 8, -20, -2, 14, + 13, 10, 2, 2, -9, -6, -9, -3, 5, 7, -3, -9, 0, 2, 8, 3, + -1, 2, -4, 0, -2, 0, -2, 3, 5, -4, -28, 22, -43, 36, -13, -127, + -43, 2, -18, 126, 78, -127, -48, 68, -74, -67, 33, 62, 83, 42, -32, -46, + -70, -26, 115, 21, -66, 72, 52, -27, 44, 50, 50, 61, 28, -12, 3, -59, + 49, 3, -19, 39, 94, 16, 31, 6, 29, 3, -100, -1, -4, -60, 19, 7, + -29, -28, -38, -3, -47, -20, -21, -1, 5, -55, -12, -55, -39, 26, 47, -22, + -9, -41, -21, -19, -37, 0, 45, -56, 24, 75, -50, -9, 31, 28, 26, 13, + -3, -15, -27, 1, 1, -31, -10, 38, -1, 7, 43, 19, 21, 41, 33, 9, + -17, -3, -42, -76, -30, -8, -9, -1, 21, 22, 38, 32, 22, 0, -18, -32, + -58, -12, 5, -48, -13, 64, 29, -2, 2, 19, 43, 25, -19, -39, -69, -92, + -15, 23, 30, 30, 51, 37, 35, 37, 30, -27, -63, 5, -30, -56, -16, 26, + 52, 20, 14, 59, 27, -9, 22, -4, -20, -37, -17, -34, -34, -1, 35, 26, + 31, 5, -16, 4, 33, 22, 8, 5, -28, -41, -20, -10, -6, -2, -16, 12, + 31, -23, 7, -2, -39, -28, -13, 8, 5, 16, -4, -6, -18, -24, -27, -50, + -6, 5, 12, 0, -2, -14, -23, 5, -28, -10, 2, 28, 15, 2, 22, 27, + 41, 31, 2, 12, 31, 5, 12, -6, 15, 40, 34, 18, 26, 26, 12, 34, + 23, 34, 30, 22, 10, -26, -22, 1, 0, -1, 12, -4, -21, -5, -5, -20, + -31, -25, -24, -42, -44, -41, -41, -37, -29, -28, -29, -40, -17, -21, -38, -42, + -38, -40, -36, -13, -14, -8, -15, -7, -6, 5, 12, -1, -17, -1, 9, 2, + 16, 30, 27, 37, 36, 38, 36, 36, 19, 45, 45, 33, 26, 33, 28, 36, + 31, 17, 12, 22, 11, 11, 17, 5, -13, 6, 10, 2, -6, 2, 9, 15, + -6, -8, -23, -44, -3, -11, -35, -25, -35, -23, -21, 0, -11, -21, -17, 11, + -6, -11, -17, -33, -16, -16, -4, -7, -7, -9, -4, 1, 1, -3, 6, 7, + 4, -17, -11, -6, -4, 1, 3, 6, 4, 5, -4, 17, 7, 3, 9, -20, + 0, -7, -3, -5, 4, 9, 16, 2, 3, 8, 15, 15, 1, -3, 8, -1, + 5, 14, 7, 4, 8, -8, 2, -3, 5, 11, 5, 3, -4, 10, 17, 13, + -11, -5, 1, -3, 0, -6, -12, 2, -3, 13, -5, -25, -15, -7, 4, 1, + -8, -4, -12, -16, 3, 9, -6, 3, -21, -4, 4, -14, 1, -1, -2, 3, + -8, -5, 0, 7, -2, -3, -1, 3, -9, 5, -4, -17, -1, 9, 3, 7, + 1, -4, -3, 5, 2, -7, -9, 12, -6, -14, -16, 2, -1, 16, 2, 2, + 7, -6, -26, 3, -2, -4, -2, 10, 3, -7, 3, 8, 9, 5, 4, 1, + -5, -5, 11, 8, 7, 11, 12, -1, -5, -16, 13, 7, 2, 11, 4, -4, + 9, -8, -8, 14, 11, -8, 0, -1, -5, -2, -1, -10, -5, -9, -9, -16, + -12, -8, -16, 5, -10, -4, -11, -3, 1, 0, -3, -5, -13, -9, -2, -8, + 5, -9, -7, -2, 2, -11, -7, 13, 8, -3, 2, 7, -2, -1, 5, 0, + 11, 6, 13, 15, 1, -4, 9, 5, 3, 8, -3, -4, 16, 4, 11, 9, + 0, 8, 1, -6, -5, -18, 3, 7, -18, -4, 0, -3, -3, -6, -4, -5, + -5, -10, -2, -9, -5, -2, -4, -11, -2, 1, -5, -2, 11, -6, -9, 1, + 4, -6, -1, -5, 1, 2, 9, 5, 0, 4, 4, -2, 7, 0, -10, 5, + 2, -3, 0, -6, 7, -4, -3, 6, -1, -6, -1, -1, 2, -2, -6, -3, + 0, 8, -6, 4, -1, -5, -3, 3, 1, -5, -6, -2, -3, 5, 6, 0, + 7, -3, 3, -1, 0, -2, 9, 1, 1, -3, 4, 5, -5, 2, -2, 2, + -11, -2, -4, 11, 4, 5, 0, -5, -12, -6, -5, -5, 3, -2, -2, 2, + 2, 1, 0, -1, -8, -5, -5, -3, 2, -1, 3, -1, 3, 0, -1, 0, + -1, 1, 1, -4, -4, 2, -2, 1, -6, 1, 2, 4, 2, 2, -5, -1, + 6, -3, -1, -4, 11, 3, -9, -2, -6, -3, 2, 4, 2, 1, 2, 4, + 3, -6, -4, -3, -2, 0, 2, -2, 5, 2, -1, 3, -9, -3, -3, -4, + -4, -1, 0, -2, 7, 3, 1, 1, -2, -4, -2, -3, -2, -4, 2, 4, + -1, 2, 3, 0, 3, -1, 0, -2, -2, -3, 1, -1, -4, 5, -1, 5, + 0, -3, -2, -1, -4, 3, -1, -3, -2, -2, -1, 0, 0, 1, -1, 0, + -2, -2, 0, -3, -1, 0, 0, 1, 1, -2, -1, 1, -3, 1, 2, 0, + -1, 0, -1, 1, 5, -2, 1, -3, -3, -1, -3, 0, 1, 3, 2, -1, + -1, -2, -2, -1, 1, 30, -9, -44, 13, 26, -53, -41, 2, 76, 47, 40, + -52, -53, -5, 12, -33, 15, 62, 53, -27, -98, -26, -42, 52, 75, 43, -32, + -3, -83, -13, -36, 35, 39, 56, 25, -9, -122, -22, -3, 79, -6, 6, 25, + -20, -12, -40, -19, 15, 74, 37, -14, -33, 6, 25, 7, -10, -4, 42, 4, + -33, -87, -55, 29, 39, 21, -34, -27, 1, 26, 5, -22, -13, 10, 56, 0, + -26, -40, 30, 42, 23, -7, -23, 28, 21, 9, -37, -25, 11, 25, 8, -48, + -19, -15, 41, -2, -30, -28, 4, 30, -12, -23, -28, 17, 38, 3, -12, -8, + 17, 26, 9, -32, 0, 12, 49, -3, -29, -17, 2, 41, -17, -24, -17, 9, + 30, -23, -22, -21, 19, 17, -12, -35, -18, 12, 29, 2, -27, 7, 14, 42, + -11, -24, -3, 15, 40, -23, -24, -17, 21, 22, -10, -23, -10, 23, 13, -4, + -37, 0, 15, 19, -12, -40, -2, 13, 30, -16, -22, -3, 22, 22, -13, -16, + -7, 34, 9, -5, -34, -5, 29, 10, -3, -39, 3, 17, 14, -13, -25, 5, + 21, 12, -18, -22, -8, 31, 8, -5, -27, -9, 30, 1, -3, -30, 6, 27, + 4, -14, -31, 8, 25, 10, -14, -21, -3, 24, 4, -11, -17, -1, 30, -1, + -12, -26, 3, 32, 3, -13, -26, 5, 23, 3, -14, -17, 6, 22, 1, -17, + -16, 4, 25, 4, -18, -19, 4, 23, 5, -17, -14, 5, 21, 1, -20, -11, + 7, 23, 2, -19, -17, 8, 19, 6, -18, -15, 10, 14, 6, -26, -5, 11, + 15, 4, -27, -5, 4, 22, 1, -17, -12, 6, 15, 1, -16, -13, 20, 8, + 4, -28, -7, 17, 9, 10, -31, 3, 1, 13, 0, -18, 0, 6, 17, -10, + -14, -15, 21, 10, 3, -19, -14, 22, -4, 11, -27, 8, 9, 7, -2, -26, + 8, 2, 23, -13, -7, -13, 12, 11, -11, -2, -15, 27, -8, 2, -22, 0, + 18, 0, 6, -27, 10, -4, 19, -13, -7, 1, 2, 19, -26, 7, -17, 28, + -2, -8, -6, -11, 23, -9, 10, -24, 12, -2, 10, -8, -14, 13, -5, 25, + -33, 7, -11, 17, 8, -19, 9, -18, 26, -17, 6, -12, 8, 8, -5, 0, + -23, 20, -10, 25, -24, 2, 0, -2, 17, -30, 22, -16, 25, -15, -7, -2, + -4, 21, -15, 13, -25, 19, -11, 9, -8, -7, 19, -15, 20, -34, 17, -9, + 15, 0, -15, 11, -17, 24, -24, 16, -15, 15, 0, -11, 6, -21, 30, -18, + 18, -22, 6, 3, -6, 10, -20, 23, -17, 20, -23, 7, -3, 2, 16, -24, + 18, -26, 27, -15, 5, -2, -5, 19, -21, 12, -22, 22, -9, 9, -11, -5, + 11, -13, 21, -27, 22, -17, 13, -5, -13, 14, -14, 28, -24, 9, -16, 12, + 3, -7, 5, -14, 22, -20, 14, -21, 14, 3, -2, 6, -26, 20, -17, 23, + -17, 3, 0, -2, 11, -23, 14, -14, 26, -14, 0, -10, -3, 18, -14, 15, + -24, 19, -9, 4, -8, -9, 18, -6, 15, -29, 11, -10, 16, -1, -11, 9, + -13, 23, -23, 8, -13, 12, 10, -11, 0, -20, 22, -7, 12, -19, 4, 4, + 1, 4, -23, 18, -10, 22, -17, -7, 0, -1, 23, -20, 6, -18, 18, 0, + -3, -8, -5, 20, -8, 6, -27, 14, 2, 11, -5, -20, 13, -10, 24, -22, + 3, -5, 11, 8, -20, 1, -12, 28, -7, 0, -19, 2, 15, -5, 6, -25, + 20, -4, 13, -19, -10, 10, 5, 17, -27, 1, -10, 22, -2, -10, -2, -7, + 26, -18, 4, -24, 18, 10, 1, -8, -23, 16, 2, 15, -22, -1, 3, 10, + 5, -27, 9, -8, 35, -19, -3, -18, 7, 19, -7, -3, -16, 14, 6, -5, + -9, -12, 23, -5, 11, -33, 19, -10, 23, -22, 3, -5, 14, -2, -8, -8, + 7, 7, 2, -14, 0, -2, 17, -14, 3, -17, 20, -5, 7, -19, 3, 3, + 10, -5, -9, -4, 6, 6, -2, -10, 1, 2, 12, -13, 0, -11, 18, -3, + 3, -16, 2, 4, 7, -5, -6, 0, 6, 1, -6, -6, 4, 6, 5, -11, + -2, -4, 12, -6, 1, -9, 9, 0, 1, -11, 0, 6, 5, -2, -11, 1, + 2, 7, -5, -7, 3, 1, 8, -13, 0, -6, 15, -3, -2, -11, 1, 9, + 1, -2, -12, 6, 2, 5, -9, -5, 3, 6, 5, -12, -3, -3, 12, 0, + -5, -7, 0, 8, -2, -2, -9, 7, 3, 5, -11, -4, 0, 9, 2, -7, + -6, 0, 7, 1, -6, -3, 1, 8, -4, -5, -7, 7, 4, 4, -11, -1, + -2, 10, -5, -1, -7, 8, 1, 1, -12, 1, 4, 7, -4, -8, -4, 8, + 0, 3, -16, 11, -7, 1, 0, 0, -1, -1, -4, 1, -1, -3, -13, -8, + -14, -3, -2, -2, 1, 8, 5, 7, -21, -13, -2, -6, -8, -22, -6, 5, + 11, 34, 41, 33, 13, 28, 33, 48, 35, 21, -3, -26, -18, -10, 3, 7, + 22, 21, 63, 40, 41, 43, 4, -8, -43, -63, -77, -77, -59, -18, 3, 2, + -21, -46, -74, -90, -108, -101, -94, -89, -84, -85, -77, -59, -50, -33, -7, 18, + 37, 47, 64, 101, 127, 125, 127, 126, 126, 126, 122, 100, 87, 62, 37, 28, + 27, 25, 27, 34, 25, -4, -45, -85, -123, -128, -126, -128, -127, -123, -92, -73, + -55, -45, -37, -33, -32, -33, -43, -53, -55, -43, -20, 3, 20, 34, 42, 49, + 55, 63, 74, 84, 93, 101, 107, 112, 117, 109, 92, 63, 33, 8, -13, -25, + -29, -30, -27, -27, -32, -46, -63, -82, -98, -109, -116, -121, -118, -104, -80, -49, + -12, 21, 45, 58, 64, 66, 66, 61, 51, 44, 37, 32, 32, 33, 33, 28, + 23, 15, 8, 3, 2, 9, 16, 20, 24, 23, 14, -1, -20, -37, -48, -53, + -52, -47, -38, -26, -13, -5, -1, -4, -10, -22, -34, -43, -48, -46, -34, -16, + 5, 25, 45, 65, 78, 84, 83, 71, 55, 39, 24, 9, -3, -12, -23, -34, + -45, -57, -65, -71, -71, -63, -49, -34, -21, -11, -2, 2, 8, 11, 12, 14, + 14, 20, 28, 38, 50, 58, 63, 61, 56, 46, 33, 17, -1, -19, -34, -45, + -48, -44, -32, -19, -5, 5, 7, 4, -2, -7, -11, -15, -18, -21, -23, -26, + -28, -30, -31, -29, -26, -20, -12, -1, 11, 21, 32, 42, 51, 55, 55, 52, + 46, 41, 37, 32, 30, 28, 27, 24, 19, 12, -1, -21, -45, -67, -89, -103, + -107, -101, -90, -70, -51, -33, -18, -2, 11, 23, 33, 39, 44, 49, 52, 57, + 59, 59, 56, 52, 48, 41, 35, 28, 20, 15, 11, 4, 0, -5, -11, -18, + -25, -34, -42, -47, -48, -46, -40, -33, -27, -24, -21, -24, -32, -42, -51, -56, + -58, -56, -47, -35, -18, 2, 24, 48, 70, 88, 99, 104, 102, 97, 89, 79, + 69, 59, 49, 37, 27, 14, 0, -14, -29, -44, -58, -71, -81, -87, -88, -88, + -85, -81, -77, -72, -63, -51, -37, -21, -5, 12, 29, 43, 53, 59, 61, 57, + 48, 36, 24, 13, 8, 8, 15, 25, 38, 48, 54, 54, 50, 43, 33, 22, + 11, 3, -6, -15, -25, -35, -46, -54, -61, -65, -68, -69, -69, -68, -64, -59, + -52, -43, -32, -20, -7, 6, 19, 31, 42, 51, 58, 62, 64, 62, 58, 52, + 44, 35, 26, 17, 9, 1, -5, -10, -15, -18, -19, -20, -19, -18, -16, -15, + -14, -14, -15, -16, -17, -18, -19, -19, -19, -19, -18, -16, -14, -11, -9, -6, + -3, 0, 3, 6, 10, 14, 18, 22, 27, 32, 35, 37, 37, 35, 30, 23, + 14, 4, -6, -15, -24, -31, -36, -39, -40, -39, -37, -32, -26, -19, -10, -1, + 8, 17, 24, 29, 32, 33, 32, 29, 25, 20, 15, 11, 7, 3, -1, -5, + -9, -14, -19, -24, -28, -31, -32, -31, -27, -23, -16, -10, -3, 2, 7, 10, + 12, 13, 13, 13, 12, 10, 8, 7, 5, 5, 5, 5, 6, 8, 10, 13, + 17, 20, 23, 25, 26, 25, 21, 16, 9, 1, -7, -16, -24, -31, -37, -42, + -47, -49, -51, -52, -51, -48, -43, -37, -30, -20, -7, 6, 19, 0, -4, 10, + 10, 11, -15, 4, -1, 3, -11, 11, 2, -12, 3, 18, -10, -62, 89, -16, + -95, 118, -128, 122, -128, 112, -100, 109, -121, 120, -104, 58, 10, -88, 127, -102, + 6, 98, -126, 35, 89, -111, -7, 112, -53, -94, 92, 64, -106, -53, 109, 52, + -100, -75, 86, 95, -45, -119, -12, 111, 74, -58, -118, -27, 97, 100, -4, -107, + -95, 17, 109, 92, -4, -99, -109, -26, 78, 115, 66, -27, -104, -109, -41, 55, + 112, 98, 32, -53, -109, -105, -44, 41, 102, 109, 67, -4, -74, -112, -102, -47, + 27, 88, 112, 93, 45, -19, -78, -110, -105, -65, -4, 59, 101, 110, 87, 43, + -13, -67, -103, -111, -89, -44, 13, 65, 100, 109, 93, 59, 14, -36, -78, -104, + -108, -90, -53, -6, 43, 83, 104, 106, 88, 57, 17, -27, -66, -95, -108, -102, + -80, -44, -2, 41, 77, 99, 106, 98, 77, 46, 10, -29, -64, -91, -105, -105, + -91, -64, -29, 10, 48, 78, 98, 105, 100, 84, 59, 30, -3, -36, -65, -88, + -101, -105, -99, -83, -60, -32, -1, 30, 58, 80, 96, 103, 102, 94, 80, 62, + 40, 16, -10, -35, -58, -78, -92, -101, -104, -100, -91, -77, -58, -36, -13, 12, + 36, 57, 75, 89, 98, 102, 102, 97, 88, 76, 61, 44, 25, 5, -15, -35, + -54, -70, -84, -94, -101, -104, -103, -98, -89, -77, -63, -46, -27, -8, 12, 31, + 49, 65, 79, 90, 97, 102, 104, 102, 97, 90, 81, 70, 57, 42, 27, 10, + -7, -24, -40, -56, -70, -81, -91, -99, -103, -105, -105, -101, -95, -87, -76, -63, + -49, -34, -18, -1, 16, 32, 48, 62, 74, 85, 93, 100, 104, 105, 105, 102, + 97, 90, 82, 72, 61, 48, 35, 21, 6, -9, -24, -38, -52, -65, -76, -86, + -94, -101, -105, -108, -108, -106, -102, -96, -87, -78, -66, -54, -40, -26, -11, 4, + 19, 34, 48, 61, 73, 83, 92, 99, 104, 107, 108, 108, 105, 101, 96, 89, + 80, 70, 60, 48, 36, 22, 9, -5, -19, -33, -46, -58, -69, -80, -89, -96, + -102, -107, -109, -110, -110, -107, -102, -97, -89, -80, -70, -59, -47, -33, -20, -6, + 7, 19, 30, 41, 50, 58, 65, 71, 75, 78, 79, 80, 79, 77, 74, 70, + 65, 60, 54, 48, 42, 36, 29, 22, 16, 10, 4, -2, -7, -12, -16, -19, + -22, -24, -26, -27, -27, -27, -26, -25, -23, -22, -19, -17, -14, -12, -10, 0, + -5, -2, -5, 2, -29, 22, 0, -27, 67, -59, 45, -13, -37, 28, 65, -4, + 6, 60, 5, 58, 44, 60, 27, 43, 96, 71, 81, 48, 96, 70, 23, 90, + 66, 80, 88, 40, 20, 61, 64, 12, 36, 24, 4, 7, 5, -27, -38, -26, + -33, -49, -50, -70, -69, -93, -92, -94, -104, -104, -101, -110, -107, -111, -111, -126, + -87, -119, -100, -94, -112, -93, -93, -80, -81, -76, -58, -56, -70, -30, -21, -42, + -13, -3, 2, 8, 20, 28, 41, 45, 59, 62, 69, 84, 85, 90, 103, 109, + 111, 118, 121, 121, 123, 121, 122, 121, 122, 121, 122, 121, 121, 120, 121, 120, + 121, 120, 121, 120, 120, 119, 120, 119, 120, 118, 105, 106, 110, 83, 89, 92, + 75, 67, 61, 57, 47, 40, 33, 24, 17, 10, 3, -2, -10, -20, -31, -31, + -37, -49, -50, -63, -66, -69, -74, -79, -91, -89, -92, -95, -102, -106, -104, -107, + -113, -113, -110, -113, -116, -114, -115, -114, -115, -114, -113, -114, -113, -114, -113, -112, + -113, -109, -105, -111, -106, -107, -103, -100, -103, -99, -97, -98, -99, -92, -92, -93, + -92, -92, -90, -88, -90, -88, -86, -89, -85, -85, -87, -85, -85, -82, -83, -82, + -80, -78, -79, -76, -74, -73, -73, -69, -68, -66, -64, -65, -62, -58, -56, -56, + -52, -50, -47, -43, -42, -39, -35, -33, -31, -27, -23, -21, -16, -16, -8, -7, + -3, 1, 0, 10, 15, 15, 19, 26, 29, 30, 38, 41, 42, 47, 54, 54, + 57, 63, 68, 69, 72, 77, 78, 80, 85, 84, 86, 87, 86, 87, 86, 85, + 86, 85, 84, 85, 84, 83, 84, 83, 82, 82, 83, 82, 81, 82, 81, 80, + 81, 80, 79, 80, 79, 79, 78, 79, 78, 78, 77, 74, 70, 66, 64, 61, + 55, 52, 49, 45, 40, 35, 32, 29, 24, 19, 15, 12, 8, 4, 0, -4, + -8, -11, -15, -17, -20, -25, -26, -29, -32, -34, -37, -39, -41, -43, -45, -46, + -48, -49, -50, -50, -52, -52, -53, -52, -53, -54, -53, -53, -52, -52, -51, -50, + -50, -49, -48, -48, -46, -45, -44, -42, -41, -40, -39, -37, -35, -34, -32, -30, + -28, -27, -24, -23, -22, -20, -19, -17, -15, -14, -13, -12, -10, -9, -8, -8, + -6, -6, -5, -4, -4, -3, -3, -2, -2, -1, -2, -1, -2, -1, -1, 0, + -1, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, 1, 9, -6, -3, 11, + -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, 24, -28, 27, -12, -1, + -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, 14, -16, 4, 8, -9, + 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, -20, 21, -16, 1, 17, + -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, -4, 13, -23, 29, -40, + 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, 4, -13, 20, -29, 37, + -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, 9, -4, -12, 22, -19, + -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, -10, 18, -40, 66, -91, + 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, 7, -9, -4, -2, -5, + 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, 38, -16, -20, 53, -75, + 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, 9, 4, -46, 70, -85, + 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, 14, -58, 93, -118, 127, + -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, -120, 56, 15, -85, 116, + -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, 29, -37, 42, -50, 63, + -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, -3, 3, -24, 24, -34, + 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, 14, -29, 42, -58, 58, + -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, 32, -20, -4, 4, -14, + 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, 24, -7, -25, 31, -29, + 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, 32, 2, -29, 23, -21, + 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, -10, -7, 17, -42, 34, + -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, 3, -24, 31, -44, 27, + -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, -7, 7, -25, 17, -17, + 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, -6, 8, -18, 18, -36, + 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, 16, -40, 47, -52, 34, + -12, -4, 2, -13, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, 1, 9, + -6, -3, 11, -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, 24, -28, + 27, -12, -1, -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, 14, -16, + 4, 8, -9, 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, -20, 21, + -16, 1, 17, -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, -4, 13, + -23, 29, -40, 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, 4, -13, + 20, -29, 37, -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, 9, -4, + -12, 22, -19, -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, -10, 18, + -40, 66, -91, 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, 7, -9, + -4, -2, -5, 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, 38, -16, + -20, 53, -75, 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, 9, 4, + -46, 70, -85, 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, 14, -58, + 93, -118, 127, -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, -120, 56, + 15, -85, 116, -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, 29, -37, + 42, -50, 63, -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, -3, 3, + -24, 24, -34, 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, 14, -29, + 42, -58, 58, -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, 32, -20, + -4, 4, -14, 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, 24, -7, + -25, 31, -29, 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, 32, 2, + -29, 23, -21, 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, -10, -7, + 17, -42, 34, -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, 3, -24, + 31, -44, 27, -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, -7, 7, + -25, 17, -17, 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, -6, 8, + -18, 18, -36, 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, 16, -40, + 47, -52, 34, -12, -4, 2, -13, -1, -9, -21, -32, -43, -55, -58, -40, -8, + 15, 29, 38, 44, 59, 63, 51, 20, -20, -47, -61, -58, -48, -42, -43, -35, + -15, 15, 41, 55, 61, 62, 70, 67, 45, 11, -31, -62, -80, -78, -71, -62, + -54, -39, -15, 18, 50, 68, 79, 83, 92, 88, 57, 16, -31, -71, -94, -95, + -90, -83, -71, -55, -28, 7, 49, 77, 93, 100, 109, 107, 78, 36, -20, -71, + -99, -104, -100, -92, -83, -69, -43, -5, 42, 79, 100, 108, 114, 112, 90, 51, + -9, -65, -100, -110, -105, -95, -87, -76, -52, -11, 35, 75, 100, 107, 111, 106, + 90, 52, -4, -60, -97, -109, -99, -87, -80, -65, -35, 5, 43, 75, 91, 95, + 93, 87, 71, 31, -19, -64, -93, -99, -88, -76, -66, -44, -9, 28, 59, 79, + 84, 80, 71, 59, 35, -5, -45, -76, -96, -95, -77, -59, -39, -9, 28, 61, + 86, 98, 93, 74, 52, 28, -6, -43, -72, -94, -108, -99, -77, -52, -20, 19, + 56, 84, 106, 115, 106, 79, 45, 3, -40, -74, -93, -108, -112, -100, -79, -46, + -1, 45, 78, 100, 113, 118, 108, 81, 39, -19, -67, -93, -103, -108, -104, -94, + -74, -32, 19, 61, 88, 102, 108, 109, 100, 73, 21, -44, -87, -102, -104, -97, + -90, -78, -49, 0, 46, 78, 90, 92, 89, 87, 77, 43, -15, -72, -101, -104, + -93, -79, -69, -47, -3, 47, 84, 96, 89, 74, 65, 58, 37, -7, -61, -99, + -110, -101, -82, -62, -38, 2, 49, 92, 112, 106, 82, 59, 41, 18, -19, -61, + -95, -111, -110, -98, -74, -39, 6, 54, 99, 122, 123, 104, 79, 50, 12, -32, + -72, -100, -111, -110, -106, -90, -54, -4, 49, 99, 123, 126, 113, 95, 69, 24, + -27, -72, -102, -114, -109, -104, -94, -64, -16, 36, 87, 116, 121, 111, 97, 76, + 36, -15, -61, -94, -110, -108, -98, -86, -60, -19, 29, 77, 104, 109, 99, 86, + 67, 35, -7, -47, -82, -98, -101, -92, -77, -48, -14, 25, 67, 92, 95, 83, + 66, 45, 18, -9, -37, -62, -77, -81, -78, -54, -16, 0, 0, 0, 12, -10, + 16, -14, -18, 17, -31, -2, 3, -19, -8, 17, 28, 37, 31, -1, -25, -16, + -47, -13, -43, -22, 6, 34, 41, 49, 41, 27, 6, -33, -62, -54, -59, -32, + -13, 29, 53, 73, 60, 54, 16, -19, -58, -77, -89, -42, -46, 17, 55, 78, + 86, 81, 33, -3, -35, -84, -110, -75, -70, 0, 39, 78, 92, 105, 70, 13, + -15, -82, -107, -103, -84, -41, 20, 81, 85, 127, 86, 39, -4, -63, -103, -99, + -107, -69, 2, 68, 82, 127, 84, 58, 28, -44, -88, -104, -108, -83, -13, 29, + 69, 116, 87, 77, 40, -16, -65, -89, -104, -89, -40, -1, 47, 96, 90, 85, + 52, 9, -38, -62, -96, -95, -62, -22, 21, 73, 78, 86, 65, 35, -15, -41, + -80, -92, -69, -48, 1, 43, 65, 80, 73, 49, 8, -23, -59, -75, -74, -60, + -22, 17, 49, 69, 65, 60, 25, -1, -36, -59, -70, -61, -40, -9, 30, 52, + 57, 63, 37, 17, -12, -41, -61, -57, -50, -30, 9, 30, 49, 60, 47, 28, + 6, -20, -49, -51, -53, -42, -11, 13, 34, 53, 50, 34, 18, -3, -35, -39, + -52, -49, -23, 0, 18, 41, 47, 36, 31, 10, -21, -28, -43, -49, -31, -13, + 2, 28, 39, 35, 38, 19, -7, -18, -33, -42, -36, -26, -12, 19, 30, 34, + 36, 22, 6, -5, -25, -38, -36, -29, -17, 8, 19, 26, 35, 28, 12, 3, + -17, -30, -29, -29, -22, -3, 9, 19, 33, 26, 14, 8, -9, -18, -22, -28, + -25, -9, 3, 15, 22, 20, 18, 12, 1, -11, -22, -24, -21, -13, -3, 8, + 11, 20, 21, 12, 5, -6, -19, -16, -17, -17, -7, 3, 8, 20, 17, 7, + 7, -2, -11, -13, -16, -17, -5, 2, 5, 12, 13, 8, 6, 3, -9, -11, + -9, -14, -5, 1, -3, 6, 11, 6, 7, 2, -6, -4, -4, -10, -6, -3, + -4, 5, 8, 2, 5, 4, -2, 0, -3, -9, -4, -3, -3, 2, 3, 0, + 6, 4, 0, -1, -2, -2, 0, -4, 8, -1, 9, 14, 53, 57, 33, -4, + -20, -14, -31, -71, -112, -43, 30, -22, -102, -74, 38, 90, 35, -22, 20, 99, + 96, 22, -42, -5, 48, 16, -74, -97, -51, 10, -21, -80, -68, 24, 77, 43, + -9, 20, 90, 99, 32, -28, -8, 41, 18, -63, -97, -55, -2, -18, -74, -67, + 11, 69, 44, -1, 17, 83, 98, 40, -20, -8, 35, 20, -55, -95, -60, -8, + -19, -69, -68, 3, 61, 45, 1, 15, 78, 99, 46, -14, -8, 33, 22, -48, + -93, -62, -13, -19, -67, -70, -5, 56, 44, 3, 13, 73, 99, 51, -10, -7, + 32, 25, -42, -91, -66, -15, -18, -65, -73, -11, 51, 44, 3, 9, 69, 100, + 55, -6, -8, 32, 30, -36, -89, -68, -17, -17, -64, -77, -18, 47, 45, 3, + 5, 64, 100, 60, -2, -8, 32, 34, -30, -87, -70, -19, -14, -63, -80, -25, + 43, 45, 3, 1, 59, 100, 66, 1, -9, 31, 39, -23, -84, -74, -20, -12, + -59, -84, -32, 38, 46, 3, -3, 53, 101, 71, 6, -10, 31, 43, -14, -81, + -76, -24, -9, -57, -86, -41, 33, 46, 5, -9, 47, 99, 77, 9, -11, 28, + 49, -6, -76, -79, -25, -9, -50, -91, -46, 9, -41, 2, 6, -33, 33, -4, + -1, 34, -93, 60, -49, 68, -21, 41, -38, -38, 27, -87, 127, -34, 38, -3, + -34, -2, -85, 79, -24, 4, 75, -23, 11, -70, 1, -6, -6, 63, -48, 76, + -71, 2, -7, -15, 46, -32, 48, -25, -5, 10, -31, 18, -23, 5, 6, 17, + 11, 3, 24, -46, -21, -1, -5, 31, 1, 36, -23, -11, -4, -29, 14, -5, + 29, 9, -2, -2, -20, -2, -15, 13, 7, 4, 15, -11, 4, -13, -1, 1, + -13, 15, -6, 9, 9, -2, -4, -11, -2, -11, 7, 12, 9, 5, -6, -6, + -16, -2, 3, 6, 13, 1, 7, -14, -3, -11, -1, 8, 0, 18, -3, -3, + -6, -13, 0, 4, 2, 9, 2, 2, -6, -4, -1, -8, 2, 4, 2, 7, + -4, 2, 1, -7, -3, -2, 0, 2, 8, -2, 2, -1, -7, -3, -1, 3, + 4, 3, 3, -3, -4, -4, 0, 2, 1, 5, -1, -2, 1, -4, -1, 1, + 0, 2, 8, -22, 25, 30, 6, -19, -62, -19, 10, 83, 57, -67, -88, -52, + 63, 127, 42, -63, -121, -70, 82, 111, 46, -43, -114, -35, 45, 73, 39, -19, + -54, -41, 9, 49, 24, -16, -14, -9, -6, 10, 8, -22, 25, 30, 6, -19, + -62, -19, 10, 83, 57, -67, -88, -52, 63, 127, 42, -63, -121, -70, 82, 111, + 46, -43, -114, -35, 45, 73, 39, -19, -54, -41, 9, 49, 24, -16, -14, -9, + -6, 10, 94, 127, 124, 127, 127, 114, 73, 35, -11, -52, -98, -118, -125, -128, + -128, -128, -128, -128, -128, -128, -124, -86, -47, 0, 40, 87, 106, 116, 119, 125, + 37, -7, 122, 72, -57, -71, -88, -28, 48, 127, 36, -30, -53, -126, -16, 71, + 92, 51, -1, -83, -128, 14, 43, 83, 86, -14, -106, -87, -7, 28, 1, 122, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +const EAS_U32 eas_sampleLengths[] = +{ + 9922, 9338, 6793, 5242, 3057, 2818, 2806, 1835, + 1603, 1262, 1227, 1168, 1132, 1132, 994, 907, + 817, 801, 583, 418, 402, 387, 387, 357, + 347, 212, 167, 40, 40, 32, 30 +}; + +const EAS_U32 eas_sampleOffsets[] = +{ + 0x00000000, 0x000026c2, 0x00004b3c, 0x000065c5, 0x00007a3f, 0x00008630, 0x00009132, 0x00009c28, + 0x0000a353, 0x0000a996, 0x0000ae84, 0x0000b34f, 0x0000b7df, 0x0000bc4b, 0x0000c0b7, 0x0000c499, + 0x0000c824, 0x0000cb55, 0x0000ce76, 0x0000d0bd, 0x0000d25f, 0x0000d3f1, 0x0000d574, 0x0000d6f7, + 0x0000d85c, 0x0000d9b7, 0x0000da8b, 0x0000db32, 0x0000db5a, 0x0000db82, 0x0000dba2 +}; + +/*---------------------------------------------------------------------------- + * S_EAS (hybrid) + *---------------------------------------------------------------------------- +*/ +const S_EAS easSoundLib = +{ + 0x01534145, + 0x00105622, + eas_banks, + eas_programs, + eas_regions, + eas_articulations, + eas_sampleLengths, + eas_sampleOffsets, + eas_samples, + eas_fmRegions, + 1, + 1, + 61, + 53, + 31, + 128 +}; /* end S_EAS */ + +/*---------------------------------------------------------------------------- + * Statistics + * + * Number of banks: 1 + * Number of programs: 1 + * Number of regions: 61 + * Number of articulations: 53 + * Number of samples: 31 + * Size of sample pool: 56276 + *---------------------------------------------------------------------------- +*/ +/* end C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c */ -- cgit v1.2.3