2021-07-12 23:17:54 -04:00
# ifndef VERSION_SH
2019-08-25 00:46:40 -04:00
# include <ultra64.h>
# include "synthesis.h"
2020-03-01 22:42:52 -05:00
# include "heap.h"
2019-08-25 00:46:40 -04:00
# include "data.h"
# include "load.h"
# include "seqplayer.h"
2020-12-03 20:57:48 -05:00
# include "internal.h"
2019-08-25 00:46:40 -04:00
# include "external.h"
2021-08-05 00:02:00 -05:00
# include "game/game_init.h"
2021-12-30 10:57:51 -06:00
# include "engine/math_util.h"
2019-08-25 00:46:40 -04:00
2020-02-03 00:51:26 -05:00
2019-11-03 14:36:27 -05:00
# define DMEM_ADDR_TEMP 0x0
2020-07-04 11:18:55 -04:00
# define DMEM_ADDR_RESAMPLED 0x20
# define DMEM_ADDR_RESAMPLED2 0x160
2020-12-03 14:26:38 -05:00
# define DMEM_ADDR_UNCOMPRESSED_NOTE 0x180
2019-11-03 14:36:27 -05:00
# define DMEM_ADDR_NOTE_PAN_TEMP 0x200
# define DMEM_ADDR_STEREO_STRONG_TEMP_DRY 0x200
# define DMEM_ADDR_STEREO_STRONG_TEMP_WET 0x340
# define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x3f0
# define DMEM_ADDR_LEFT_CH 0x4c0
# define DMEM_ADDR_RIGHT_CH 0x600
# define DMEM_ADDR_WET_LEFT_CH 0x740
# define DMEM_ADDR_WET_RIGHT_CH 0x880
2019-08-25 00:46:40 -04:00
# define aSetLoadBufferPair(pkt, c, off) \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , c + DMEM_ADDR_WET_LEFT_CH , 0 , DEFAULT_LEN_1CH - c ) ; \
2020-04-03 14:57:26 -04:00
aLoadBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . left + ( off ) ) ) ; \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , c + DMEM_ADDR_WET_RIGHT_CH , 0 , DEFAULT_LEN_1CH - c ) ; \
2021-12-30 10:57:51 -06:00
aLoadBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . right + ( off ) ) ) ;
2019-08-25 00:46:40 -04:00
# define aSetSaveBufferPair(pkt, c, d, off) \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , 0 , c + DMEM_ADDR_WET_LEFT_CH , d ) ; \
2020-04-03 14:57:26 -04:00
aSaveBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . left + ( off ) ) ) ; \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , 0 , c + DMEM_ADDR_WET_RIGHT_CH , d ) ; \
2020-04-03 14:57:26 -04:00
aSaveBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . right + ( off ) ) ) ;
2019-08-25 00:46:40 -04:00
2021-07-18 04:57:37 -05:00
# define AUDIO_ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1))
2019-08-25 00:46:40 -04:00
2022-02-26 01:56:07 -05:00
# ifdef BETTER_REVERB
2021-08-04 14:59:10 -05:00
/* ----------------------------------------------------------------------BEGIN REVERB PARAMETERS---------------------------------------------------------------------- */
2019-08-25 00:46:40 -04:00
2021-08-04 03:17:51 -05:00
/**
* This reverb is a much more natural , ambient implementation over vanilla ' s , though at the cost of some memory and performance .
* These parameters are here to provide maximum control over the usage of the reverb effect , as well as with game performance .
2021-09-10 20:39:49 +01:00
*
2021-08-04 03:17:51 -05:00
* To take advantage of the reverb effect , you can change the echo parameters set in levels / level_defines . h to tailor the reverb to each specific level area .
* To adjust reverb presence with individual sound effects , apply the . set_reverb command within sound / sequences / 00 _sound_player . s ( see examples of other sounds that use it ) .
* To use with M64 sequences , set the Effect parameter for each channel accordingly ( CC 91 for MIDI files ) .
2021-09-10 20:39:49 +01:00
*
2021-08-04 18:15:38 -05:00
* Most parameter configuration is to be done here , though BETTER_REVERB_SIZE can be adjusted in audio / synthesis . h .
2021-09-10 20:39:49 +01:00
*
2021-08-05 02:17:01 -05:00
* If after changing the parameters , you hear increasing noise followed by a sudden disappearance of reverb and / or scratchy audio , this indicates an s16 overflow .
* If this happens , stop immediately and reduce the parameters at fault . This becomes a ticking time bomb , and may eventually result in very loud noise if it reaches the point of s32 overflow .
2021-09-01 15:03:08 -07:00
* Depending on the violating parameters chosen , you probably won ' t ever experience s32 overflow , but s16 overflow still isn ' t a pleasant experience .
* Checks to prevent this have not been implemented to maximize performance potential , so choose your parameters wisely . The current defaults are unlikely to have this problem .
* Generally speaking , a sound that doesn ' t seem to be fading at a natural rate is a parameter red flag ( also known as feedback ) .
2021-12-30 10:57:51 -06:00
*
* This is also known to cause severe lag on emulators that have counter factor set to 2 or greater .
* Be sure either you alert the user in advance , or check for and set betterReverbDownsampleEmulator to - 1 if it ' s detected the user isn ' t using good settings .
2022-03-08 00:49:13 -05:00
* Reducing performance heavy parameters or using RCVI hack may be another working solution to this problem .
2021-08-04 03:17:51 -05:00
*/
2021-08-03 02:55:48 -05:00
2021-08-04 14:59:10 -05:00
// Setting this to 4 corrupts the game, so set this value to -1 to use vanilla reverb if this is too slow, or if it just doesn't fit the desired aesthetic of a level.
// You can change this value before audio_reset_session gets called if different levels can tolerate the demand better than others or just have different reverb goals.
// A higher downsample value hits the game's frequency limit sooner, which can cause the reverb sometimes to be off pitch. This is a vanilla level issue (and also counter intuitive).
// Higher downsample values also result in slightly shorter reverb decay times.
2021-08-05 00:02:00 -05:00
s8 betterReverbDownsampleConsole = 3 ;
2021-08-04 14:59:10 -05:00
// Most emulators can handle a default value of 2, but 3 may be advisable in some cases if targeting older emulators (e.g. PJ64 1.6). Setting this to -1 also uses vanilla reverb.
2021-12-30 10:57:51 -06:00
// Using a value of 1 is not recommended on emulator unless reducing other parameters to compensate. If you do decide to use 1 here, you must adjust BETTER_REVERB_SIZE appropriately.
2021-08-04 14:59:10 -05:00
// You can change this value before audio_reset_session gets called if different levels can tolerate the demand better than others or just have different reverb goals.
// A higher downsample value hits the game's frequency limit sooner, which can cause the reverb sometimes to be off pitch. This is a vanilla level issue (and also counter intuitive).
// Higher downsample values also result in slightly shorter reverb decay times.
2021-08-05 00:02:00 -05:00
s8 betterReverbDownsampleEmulator = 2 ;
// This value represents the number of filters to use with the reverb. This can be decreased to improve performance, but at the cost of a lesser presence of reverb in the final audio.
// Filter count should always be a multiple of 3. Never ever set this value to be greater than NUM_ALLPASS.
2021-09-01 15:39:27 -07:00
// Setting it to anything less than 3 will disable reverb outright.
2022-03-08 00:49:13 -05:00
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
2021-12-30 10:57:51 -06:00
u32 reverbFilterCountConsole = ( NUM_ALLPASS - 6 ) ;
2021-08-05 00:02:00 -05:00
// This value represents the number of filters to use with the reverb. This can be decreased to improve performance, but at the cost of a lesser presence of reverb in the final audio.
// Filter count should always be a multiple of 3. Never ever set this value to be greater than NUM_ALLPASS.
2021-09-01 15:39:27 -07:00
// Setting it to anything less than 3 will disable reverb outright.
2022-03-08 00:49:13 -05:00
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
2021-08-05 00:02:00 -05:00
u32 reverbFilterCountEmulator = NUM_ALLPASS ;
2021-08-04 14:59:10 -05:00
2021-08-04 18:15:38 -05:00
// Set this to TRUE to use mono over stereo for reverb. This should increase performance, but at the cost of a less fullfilling reverb experience.
2021-08-05 01:14:01 -05:00
// If performance is desirable, it is recommended to change reverbFilterCountConsole or betterReverbDownsampleConsole first.
2022-03-08 00:49:13 -05:00
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
2021-08-05 00:02:00 -05:00
u8 monoReverbConsole = FALSE ;
// Set this to TRUE to use mono over stereo for reverb. This should increase performance, but at the cost of a less fullfilling reverb experience.
2021-08-05 01:14:01 -05:00
// If performance is desirable, it is recommended to change reverbFilterCountEmulator or betterReverbDownsampleEmulator first.
2022-03-08 00:49:13 -05:00
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
2021-08-05 00:02:00 -05:00
u8 monoReverbEmulator = FALSE ;
2021-08-04 18:15:38 -05:00
2021-08-04 17:01:30 -05:00
// This value controls the size of the reverb buffer. It affects the global reverb delay time. This variable is one of the easiest to control.
// Setting the value lower than the downsample buffer size will destroy the game audio. This is taken into account automatically, but also means the value set here isn't what always gets used.
2022-03-08 00:49:13 -05:00
// Similarly, this value maxes out at (REVERB_WINDOW_SIZE_MAX * 2^(downsample factor - 1)).
2021-08-04 05:38:16 -05:00
// If this value is changed, it will go into effect the next time audio_reset_session is called.
// Set to -1 to use a default preset instead. Higher values represent more audio delay (usually better for echoey spaces).
s32 betterReverbWindowsSize = - 1 ;
2021-09-12 00:59:36 -04:00
// These are set to defines rather than variables to increase performance. Change these to s32 if you want them to be configurable in-game. (Maybe extern them in synthesis.h)
// Setting these to values larger than 0xFF (255) or less than 0 may cause issues and is not recommended.
2021-12-30 10:57:51 -06:00
# define REVERB_REV_INDEX 0x60 // Affects decay time mostly (large values can cause terrible feedback!); can be messed with at any time
2021-09-12 00:59:36 -04:00
# define REVERB_GAIN_INDEX 0xA0 // Affects signal immediately retransmitted back into buffers (mid-high values yield the strongest effect); can be messed with at any time
# define REVERB_WET_SIGNAL 0xE8 // Amount of reverb specific output in final signal (also affects decay); can be messed with at any time, also very easy to control
2021-08-04 23:05:39 -05:00
2021-09-12 00:59:36 -04:00
// #define REVERB_DRY_SIGNAL = 0x00; // Amount of original input in final signal (large values can cause terrible feedback!); declaration and uses commented out by default to improve compiler optimization
2021-08-04 23:05:39 -05:00
2021-08-04 14:59:10 -05:00
/* ---------------------------------------------------------------------ADVANCED REVERB PARAMETERS-------------------------------------------------------------------- */
2021-08-05 01:19:55 -05:00
// These values affect filter delays. Bigger values will result in fatter echo (and more memory); must be cumulatively smaller than BETTER_REVERB_SIZE/2.
// If setting a reverb downsample value to 1, these must be cumulatively smaller than BETTER_REVERB_SIZE/4.
2022-03-08 00:49:13 -05:00
// None of the delay values should ever be smaller than 1; these are s32s purely to avoid typecasts.
// These values are applied any time audio_reset_session is called, and as such can be changed at any time without issues.
s32 delaysBaselineL [ NUM_ALLPASS ] = {
2021-08-03 01:45:33 -05:00
1080 , 1352 , 1200 ,
1200 , 1232 , 1432 ,
2021-08-05 02:17:01 -05:00
1384 , 1048 , 1352 ,
2021-12-30 10:57:51 -06:00
928 , 1504 , 1512
2021-08-03 01:45:33 -05:00
} ;
2022-03-08 00:49:13 -05:00
s32 delaysBaselineR [ NUM_ALLPASS ] = {
2021-08-05 02:17:01 -05:00
1384 , 1352 , 1048 ,
2021-12-30 10:57:51 -06:00
928 , 1512 , 1504 ,
2021-08-05 01:14:01 -05:00
1080 , 1200 , 1352 ,
2021-08-05 02:17:01 -05:00
1200 , 1432 , 1232
2021-08-05 01:14:01 -05:00
} ;
2021-08-04 03:17:51 -05:00
// These values affect reverb decay depending on the filter index; can be messed with at any time
2021-08-05 02:17:01 -05:00
s32 reverbMultsL [ NUM_ALLPASS / 3 ] = { 0xD7 , 0x6F , 0x36 , 0x22 } ;
s32 reverbMultsR [ NUM_ALLPASS / 3 ] = { 0xCF , 0x73 , 0x38 , 0x1F } ;
2021-08-04 03:17:51 -05:00
2021-08-04 14:59:10 -05:00
/* -----------------------------------------------------------------------END REVERB PARAMETERS----------------------------------------------------------------------- */
2021-08-04 03:17:51 -05:00
2021-08-05 00:02:00 -05:00
// Do not touch these values manually, unless you want potential for problems.
2021-12-30 10:57:51 -06:00
s32 reverbFilterCount = NUM_ALLPASS ;
s32 reverbFilterCountm1 = ( NUM_ALLPASS - 1 ) ;
2021-08-05 00:02:00 -05:00
u8 monoReverb = FALSE ;
2021-08-04 03:17:51 -05:00
u8 toggleBetterReverb = TRUE ;
2022-03-08 00:49:13 -05:00
s32 allpassIdxL [ NUM_ALLPASS ] = { 0 } ;
s32 allpassIdxR [ NUM_ALLPASS ] = { 0 } ;
s32 tmpBufL [ NUM_ALLPASS ] = { 0 } ;
s32 tmpBufR [ NUM_ALLPASS ] = { 0 } ;
s32 delaysL [ NUM_ALLPASS ] = { 0 } ;
s32 delaysR [ NUM_ALLPASS ] = { 0 } ;
2021-08-04 23:16:03 -05:00
s32 * * delayBufsL ;
s32 * * delayBufsR ;
2021-08-04 18:15:38 -05:00
# endif
2021-08-02 21:14:31 -05:00
2021-08-03 02:55:48 -05:00
2021-08-04 03:17:51 -05:00
struct VolumeChange {
u16 sourceLeft ;
u16 sourceRight ;
u16 targetLeft ;
u16 targetRight ;
} ;
2021-08-03 02:55:48 -05:00
2020-12-03 14:26:38 -05:00
u64 * synthesis_do_one_audio_update ( s16 * aiBuf , s32 bufLen , u64 * cmd , s32 updateIndex ) ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
u64 * synthesis_process_note ( struct Note * note , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * synthesisState , s16 * aiBuf , s32 bufLen , u64 * cmd ) ;
2020-02-03 00:51:26 -05:00
u64 * load_wave_samples ( u64 * cmd , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * synthesisState , s32 nSamplesToLoad ) ;
u64 * final_resample ( u64 * cmd , struct NoteSynthesisState * synthesisState , s32 count , u16 pitch , u16 dmemIn , u32 flags ) ;
2020-04-03 14:57:26 -04:00
u64 * process_envelope ( u64 * cmd , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * synthesisState , s32 nSamples , u16 inBuf , s32 headsetPanSettings , u32 flags ) ;
2020-02-03 00:51:26 -05:00
u64 * note_apply_headset_pan_effects ( u64 * cmd , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * note , s32 bufLen , s32 flags , s32 leftRight ) ;
# else
2020-06-02 12:44:34 -04:00
u64 * synthesis_process_notes ( s16 * aiBuf , s32 bufLen , u64 * cmd ) ;
2019-11-03 14:36:27 -05:00
u64 * load_wave_samples ( u64 * cmd , struct Note * note , s32 nSamplesToLoad ) ;
u64 * final_resample ( u64 * cmd , struct Note * note , s32 count , u16 pitch , u16 dmemIn , u32 flags ) ;
u64 * process_envelope ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf , s32 headsetPanSettings ,
u32 flags ) ;
u64 * process_envelope_inner ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf ,
s32 headsetPanSettings , struct VolumeChange * vol ) ;
u64 * note_apply_headset_pan_effects ( u64 * cmd , struct Note * note , s32 bufLen , s32 flags , s32 leftRight ) ;
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
struct SynthesisReverb gSynthesisReverbs [ 4 ] ;
u8 sAudioSynthesisPad [ 0x10 ] ;
2020-12-03 14:26:38 -05:00
# else
struct SynthesisReverb gSynthesisReverb ;
u8 sAudioSynthesisPad [ 0x20 ] ;
# endif
2022-02-26 01:56:07 -05:00
# ifdef BETTER_REVERB
2021-08-05 01:43:25 -05:00
static inline void reverb_samples ( s16 * outSampleL , s16 * outSampleR , s32 inSampleL , s32 inSampleR ) {
2021-09-12 00:59:36 -04:00
s32 i = 0 ;
2021-08-03 22:30:11 -05:00
s32 j = 0 ;
2021-09-12 00:59:36 -04:00
s32 k = 0 ;
2021-08-03 22:30:11 -05:00
s32 outTmpL = 0 ;
s32 outTmpR = 0 ;
2021-12-30 10:57:51 -06:00
s32 tmpCarryoverL = ( ( ( tmpBufL [ reverbFilterCountm1 ] * REVERB_REV_INDEX ) / 256 ) + inSampleL ) ;
s32 tmpCarryoverR = ( ( ( tmpBufR [ reverbFilterCountm1 ] * REVERB_REV_INDEX ) / 256 ) + inSampleR ) ;
2021-08-03 22:30:11 -05:00
2021-09-12 00:59:36 -04:00
for ( ; i ! = reverbFilterCount ; + + i , + + j ) {
2021-08-05 01:14:01 -05:00
tmpBufL [ i ] = delayBufsL [ i ] [ allpassIdxL [ i ] ] ;
tmpBufR [ i ] = delayBufsR [ i ] [ allpassIdxR [ i ] ] ;
2021-08-03 22:30:11 -05:00
if ( j = = 2 ) {
j = - 1 ;
2021-12-30 10:57:51 -06:00
outTmpL + = ( ( tmpBufL [ i ] * reverbMultsL [ k ] ) / 256 ) ;
outTmpR + = ( ( tmpBufR [ i ] * reverbMultsR [ k + + ] ) / 256 ) ;
2021-08-05 01:14:01 -05:00
delayBufsL [ i ] [ allpassIdxL [ i ] ] = tmpCarryoverL ;
delayBufsR [ i ] [ allpassIdxR [ i ] ] = tmpCarryoverR ;
if ( i ! = reverbFilterCountm1 ) {
2021-12-30 10:57:51 -06:00
tmpCarryoverL = ( ( tmpBufL [ i ] * REVERB_REV_INDEX ) / 256 ) ;
tmpCarryoverR = ( ( tmpBufR [ i ] * REVERB_REV_INDEX ) / 256 ) ;
2021-08-03 22:30:11 -05:00
}
2021-12-30 10:57:51 -06:00
} else {
delayBufsL [ i ] [ allpassIdxL [ i ] ] = ( ( ( tmpBufL [ i ] * ( - REVERB_GAIN_INDEX ) ) / 256 ) + tmpCarryoverL ) ;
delayBufsR [ i ] [ allpassIdxR [ i ] ] = ( ( ( tmpBufR [ i ] * ( - REVERB_GAIN_INDEX ) ) / 256 ) + tmpCarryoverR ) ;
tmpCarryoverL = ( ( ( delayBufsL [ i ] [ allpassIdxL [ i ] ] * REVERB_GAIN_INDEX ) / 256 ) + tmpBufL [ i ] ) ;
tmpCarryoverR = ( ( ( delayBufsR [ i ] [ allpassIdxR [ i ] ] * REVERB_GAIN_INDEX ) / 256 ) + tmpBufR [ i ] ) ;
2021-08-03 22:30:11 -05:00
}
2021-12-30 10:57:51 -06:00
if ( + + allpassIdxL [ i ] = = delaysL [ i ] ) allpassIdxL [ i ] = 0 ;
if ( + + allpassIdxR [ i ] = = delaysR [ i ] ) allpassIdxR [ i ] = 0 ;
2021-08-03 22:30:11 -05:00
}
2021-12-30 10:57:51 -06:00
s32 outUnclamped = ( ( outTmpL * REVERB_WET_SIGNAL /* + inSampleL * REVERB_DRY_SIGNAL*/ ) / 256 ) ;
* outSampleL = CLAMP_S16 ( outUnclamped ) ;
outUnclamped = ( ( outTmpR * REVERB_WET_SIGNAL /* + inSampleL * REVERB_DRY_SIGNAL*/ ) / 256 ) ;
* outSampleR = CLAMP_S16 ( outUnclamped ) ;
2021-08-03 22:30:11 -05:00
}
2021-08-05 01:43:25 -05:00
static inline void reverb_mono_sample ( s16 * outSample , s32 inSample ) {
2021-09-12 00:59:36 -04:00
s32 i = 0 ;
2021-08-03 06:52:21 -05:00
s32 j = 0 ;
2021-09-12 00:59:36 -04:00
s32 k = 0 ;
2021-08-02 21:14:31 -05:00
s32 outTmp = 0 ;
2021-12-30 10:57:51 -06:00
s32 tmpCarryover = ( ( ( tmpBufL [ reverbFilterCountm1 ] * REVERB_REV_INDEX ) / 256 ) + inSample ) ;
2021-08-02 21:14:31 -05:00
2021-09-12 00:59:36 -04:00
for ( ; i ! = reverbFilterCount ; + + i , + + j ) {
2021-08-05 01:14:01 -05:00
tmpBufL [ i ] = delayBufsL [ i ] [ allpassIdxL [ i ] ] ;
2021-08-02 21:14:31 -05:00
2021-08-03 06:52:21 -05:00
if ( j = = 2 ) {
2021-08-03 21:29:06 -05:00
j = - 1 ;
2021-12-30 10:57:51 -06:00
outTmp + = ( ( tmpBufL [ i ] * reverbMultsL [ k + + ] ) / 256 ) ;
2021-08-05 01:14:01 -05:00
delayBufsL [ i ] [ allpassIdxL [ i ] ] = tmpCarryover ;
if ( i ! = reverbFilterCountm1 )
2021-12-30 10:57:51 -06:00
tmpCarryover = ( ( tmpBufL [ i ] * REVERB_REV_INDEX ) / 256 ) ;
} else {
delayBufsL [ i ] [ allpassIdxL [ i ] ] = ( ( ( tmpBufL [ i ] * ( - REVERB_GAIN_INDEX ) ) / 256 ) + tmpCarryover ) ;
tmpCarryover = ( ( ( delayBufsL [ i ] [ allpassIdxL [ i ] ] * REVERB_GAIN_INDEX ) / 256 ) + tmpBufL [ i ] ) ;
2021-08-02 21:14:31 -05:00
}
2021-08-05 01:14:01 -05:00
if ( + + allpassIdxL [ i ] = = delaysL [ i ] )
allpassIdxL [ i ] = 0 ;
2021-08-02 21:14:31 -05:00
}
2021-12-30 10:57:51 -06:00
s32 outUnclamped = ( ( outTmp * REVERB_WET_SIGNAL /* + inSample * REVERB_DRY_SIGNAL*/ ) / 256 ) ;
* outSample = CLAMP_S16 ( outUnclamped ) ;
2021-08-02 21:14:31 -05:00
}
2021-08-04 18:15:38 -05:00
# endif
2021-08-02 21:14:31 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
s16 gVolume ;
s8 gUseReverb ;
s8 gNumSynthesisReverbs ;
struct NoteSubEu * gNoteSubsEu ;
2020-12-03 14:26:38 -05:00
# endif
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
f32 gLeftVolRampings [ 3 ] [ 1024 ] ;
f32 gRightVolRampings [ 3 ] [ 1024 ] ;
f32 * gCurrentLeftVolRamping ; // Points to any of the three left buffers above
f32 * gCurrentRightVolRamping ; // Points to any of the three right buffers above
2020-09-20 11:15:47 -04:00
u8 audioString1 [ ] = " pitch %x: delaybytes %d : olddelay %d \n " ;
u8 audioString2 [ ] = " cont %x: delaybytes %d : olddelay %d \n " ;
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
// Equivalent functionality as the US/JP version,
// just that the reverb structure is chosen from an array with index
void prepare_reverb_ring_buffer ( s32 chunkLen , u32 updateIndex , s32 reverbIndex ) {
struct ReverbRingBufferItem * item ;
2020-03-01 22:42:52 -05:00
struct SynthesisReverb * reverb = & gSynthesisReverbs [ reverbIndex ] ;
2021-12-30 10:57:51 -06:00
s32 srcPos , dstPos ;
2020-02-03 00:51:26 -05:00
s32 nSamples ;
s32 excessiveSamples ;
if ( reverb - > downsampleRate ! = 1 ) {
if ( reverb - > framesLeftToIgnore = = 0 ) {
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
// samples.
item = & reverb - > items [ reverb - > curFrame ] [ updateIndex ] ;
// Touches both left and right since they are adjacent in memory
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
2020-07-04 11:18:55 -04:00
for ( srcPos = 0 , dstPos = 0 ; dstPos < item - > lengthA / 2 ;
2020-02-03 00:51:26 -05:00
srcPos + = reverb - > downsampleRate , dstPos + + ) {
2021-12-30 10:57:51 -06:00
reverb - > ringBuffer . left [ item - > startPos + dstPos ] = item - > toDownsampleLeft [ srcPos ] ;
reverb - > ringBuffer . right [ item - > startPos + dstPos ] = item - > toDownsampleRight [ srcPos ] ;
2020-02-03 00:51:26 -05:00
}
2020-07-04 11:18:55 -04:00
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; srcPos + = reverb - > downsampleRate , dstPos + + ) {
2020-02-03 00:51:26 -05:00
reverb - > ringBuffer . left [ dstPos ] = item - > toDownsampleLeft [ srcPos ] ;
reverb - > ringBuffer . right [ dstPos ] = item - > toDownsampleRight [ srcPos ] ;
}
}
}
item = & reverb - > items [ reverb - > curFrame ] [ updateIndex ] ;
2020-03-01 22:42:52 -05:00
nSamples = chunkLen / reverb - > downsampleRate ;
excessiveSamples = ( nSamples + reverb - > nextRingBufferPos ) - reverb - > bufSizePerChannel ;
2020-02-03 00:51:26 -05:00
if ( excessiveSamples < 0 ) {
// There is space in the ring buffer before it wraps around
2020-07-04 11:18:55 -04:00
item - > lengthA = nSamples * 2 ;
item - > lengthB = 0 ;
2020-02-03 00:51:26 -05:00
item - > startPos = ( s32 ) reverb - > nextRingBufferPos ;
reverb - > nextRingBufferPos + = nSamples ;
} else {
// Ring buffer wrapped around
2020-07-04 11:18:55 -04:00
item - > lengthA = ( nSamples - excessiveSamples ) * 2 ;
item - > lengthB = excessiveSamples * 2 ;
2020-02-03 00:51:26 -05:00
item - > startPos = reverb - > nextRingBufferPos ;
reverb - > nextRingBufferPos = excessiveSamples ;
}
// These fields are never read later
item - > numSamplesAfterDownsampling = nSamples ;
item - > chunkLen = chunkLen ;
}
# else
2019-11-03 14:36:27 -05:00
void prepare_reverb_ring_buffer ( s32 chunkLen , u32 updateIndex ) {
struct ReverbRingBufferItem * item ;
2021-12-30 10:57:51 -06:00
s32 srcPos , dstPos ;
2019-11-03 14:36:27 -05:00
s32 nSamples ;
s32 excessiveSamples ;
2021-08-02 21:14:31 -05:00
2021-08-03 02:55:48 -05:00
# ifdef BETTER_REVERB
2021-08-04 03:17:51 -05:00
if ( ! toggleBetterReverb & & gReverbDownsampleRate ! = 1 ) {
2021-08-03 02:55:48 -05:00
# else
2019-11-03 14:36:27 -05:00
if ( gReverbDownsampleRate ! = 1 ) {
2021-08-03 02:55:48 -05:00
# endif
2019-11-03 14:36:27 -05:00
if ( gSynthesisReverb . framesLeftToIgnore = = 0 ) {
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
// samples.
item = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
// Touches both left and right since they are adjacent in memory
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
2020-07-04 11:18:55 -04:00
for ( srcPos = 0 , dstPos = 0 ; dstPos < item - > lengthA / 2 ;
2019-11-03 14:36:27 -05:00
srcPos + = gReverbDownsampleRate , dstPos + + ) {
2021-12-30 10:57:51 -06:00
gSynthesisReverb . ringBuffer . left [ dstPos + item - > startPos ] = item - > toDownsampleLeft [ srcPos ] ;
gSynthesisReverb . ringBuffer . right [ dstPos + item - > startPos ] = item - > toDownsampleRight [ srcPos ] ;
2019-08-25 00:46:40 -04:00
}
2020-07-04 11:18:55 -04:00
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; srcPos + = gReverbDownsampleRate , dstPos + + ) {
2019-11-03 14:36:27 -05:00
gSynthesisReverb . ringBuffer . left [ dstPos ] = item - > toDownsampleLeft [ srcPos ] ;
gSynthesisReverb . ringBuffer . right [ dstPos ] = item - > toDownsampleRight [ srcPos ] ;
2019-08-25 00:46:40 -04:00
}
}
}
2021-08-03 02:55:48 -05:00
# ifdef BETTER_REVERB
2021-08-04 03:17:51 -05:00
else if ( toggleBetterReverb ) {
2021-08-03 02:55:48 -05:00
item = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
2021-08-04 18:15:38 -05:00
if ( gSoundMode = = SOUND_MODE_MONO | | monoReverb ) {
2021-08-04 01:03:07 -05:00
if ( gReverbDownsampleRate ! = 1 ) {
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
2021-12-30 10:57:51 -06:00
for ( srcPos = 0 , dstPos = item - > startPos ; dstPos < ( ( item - > lengthA / 2 ) + item - > startPos ) ; srcPos + = gReverbDownsampleRate , dstPos + + ) {
2021-08-04 23:05:39 -05:00
reverb_mono_sample ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , ( ( s32 ) item - > toDownsampleLeft [ srcPos ] + ( s32 ) item - > toDownsampleRight [ srcPos ] ) / 2 ) ;
2021-08-04 01:03:07 -05:00
gSynthesisReverb . ringBuffer . right [ dstPos ] = gSynthesisReverb . ringBuffer . left [ dstPos ] ;
}
2021-12-30 10:57:51 -06:00
for ( dstPos = 0 ; dstPos < ( item - > lengthB / 2 ) ; srcPos + = gReverbDownsampleRate , dstPos + + ) {
2021-08-04 23:05:39 -05:00
reverb_mono_sample ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , ( ( s32 ) item - > toDownsampleLeft [ srcPos ] + ( s32 ) item - > toDownsampleRight [ srcPos ] ) / 2 ) ;
2021-08-04 01:03:07 -05:00
gSynthesisReverb . ringBuffer . right [ dstPos ] = gSynthesisReverb . ringBuffer . left [ dstPos ] ;
}
2021-12-30 10:57:51 -06:00
} else { // Too slow for practical use, not recommended most of the time.
for ( dstPos = item - > startPos ; dstPos < ( ( item - > lengthA / 2 ) + item - > startPos ) ; dstPos + + ) {
2021-08-04 23:05:39 -05:00
reverb_mono_sample ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , ( ( s32 ) gSynthesisReverb . ringBuffer . left [ dstPos ] + ( s32 ) gSynthesisReverb . ringBuffer . right [ dstPos ] ) / 2 ) ;
2021-08-04 01:03:07 -05:00
gSynthesisReverb . ringBuffer . right [ dstPos ] = gSynthesisReverb . ringBuffer . left [ dstPos ] ;
}
2021-12-30 10:57:51 -06:00
for ( dstPos = 0 ; dstPos < ( item - > lengthB / 2 ) ; dstPos + + ) {
2021-08-04 23:05:39 -05:00
reverb_mono_sample ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , ( ( s32 ) gSynthesisReverb . ringBuffer . left [ dstPos ] + ( s32 ) gSynthesisReverb . ringBuffer . right [ dstPos ] ) / 2 ) ;
2021-08-04 01:03:07 -05:00
gSynthesisReverb . ringBuffer . right [ dstPos ] = gSynthesisReverb . ringBuffer . left [ dstPos ] ;
}
}
2021-12-30 10:57:51 -06:00
} else {
2021-08-04 01:03:07 -05:00
if ( gReverbDownsampleRate ! = 1 ) {
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
2021-12-30 10:57:51 -06:00
for ( srcPos = 0 , dstPos = item - > startPos ; dstPos < ( ( item - > lengthA / 2 ) + item - > startPos ) ; srcPos + = gReverbDownsampleRate , dstPos + + )
2021-08-04 01:03:07 -05:00
reverb_samples ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , & gSynthesisReverb . ringBuffer . right [ dstPos ] , item - > toDownsampleLeft [ srcPos ] , item - > toDownsampleRight [ srcPos ] ) ;
2021-12-30 10:57:51 -06:00
for ( dstPos = 0 ; dstPos < ( item - > lengthB / 2 ) ; srcPos + = gReverbDownsampleRate , dstPos + + )
2021-08-04 01:03:07 -05:00
reverb_samples ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , & gSynthesisReverb . ringBuffer . right [ dstPos ] , item - > toDownsampleLeft [ srcPos ] , item - > toDownsampleRight [ srcPos ] ) ;
2021-12-30 10:57:51 -06:00
} else { // Too slow for practical use, not recommended most of the time.
for ( dstPos = item - > startPos ; dstPos < ( ( item - > lengthA / 2 ) + item - > startPos ) ; dstPos + + )
2021-08-04 01:03:07 -05:00
reverb_samples ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , & gSynthesisReverb . ringBuffer . right [ dstPos ] , gSynthesisReverb . ringBuffer . left [ dstPos ] , gSynthesisReverb . ringBuffer . right [ dstPos ] ) ;
2021-12-30 10:57:51 -06:00
for ( dstPos = 0 ; dstPos < ( item - > lengthB / 2 ) ; dstPos + + )
2021-08-04 01:03:07 -05:00
reverb_samples ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , & gSynthesisReverb . ringBuffer . right [ dstPos ] , gSynthesisReverb . ringBuffer . left [ dstPos ] , gSynthesisReverb . ringBuffer . right [ dstPos ] ) ;
}
2021-08-03 21:29:06 -05:00
}
2021-08-02 21:14:31 -05:00
}
# endif
2019-11-03 14:36:27 -05:00
item = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
2021-12-30 10:57:51 -06:00
s32 numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate ;
2020-04-03 14:57:26 -04:00
if ( ( ( numSamplesAfterDownsampling + gSynthesisReverb . nextRingBufferPos ) - gSynthesisReverb . bufSizePerChannel ) < 0 ) {
2019-11-03 14:36:27 -05:00
// There is space in the ring buffer before it wraps around
2020-07-04 11:18:55 -04:00
item - > lengthA = numSamplesAfterDownsampling * 2 ;
item - > lengthB = 0 ;
2019-11-03 14:36:27 -05:00
item - > startPos = ( s32 ) gSynthesisReverb . nextRingBufferPos ;
2020-04-03 14:57:26 -04:00
gSynthesisReverb . nextRingBufferPos + = numSamplesAfterDownsampling ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
// Ring buffer wrapped around
excessiveSamples =
2020-04-03 14:57:26 -04:00
( numSamplesAfterDownsampling + gSynthesisReverb . nextRingBufferPos ) - gSynthesisReverb . bufSizePerChannel ;
2019-11-03 14:36:27 -05:00
nSamples = numSamplesAfterDownsampling - excessiveSamples ;
2020-07-04 11:18:55 -04:00
item - > lengthA = nSamples * 2 ;
item - > lengthB = excessiveSamples * 2 ;
2019-11-03 14:36:27 -05:00
item - > startPos = gSynthesisReverb . nextRingBufferPos ;
gSynthesisReverb . nextRingBufferPos = excessiveSamples ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
// These fields are never read later
item - > numSamplesAfterDownsampling = numSamplesAfterDownsampling ;
item - > chunkLen = chunkLen ;
2019-08-25 00:46:40 -04:00
}
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * synthesis_load_reverb_ring_buffer ( u64 * cmd , u16 addr , u16 srcOffset , s32 len , s32 reverbIndex ) {
aSetBuffer ( cmd + + , 0 , addr , 0 , len ) ;
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . left [ srcOffset ] ) ) ;
aSetBuffer ( cmd + + , 0 , addr + DEFAULT_LEN_1CH , 0 , len ) ;
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . right [ srcOffset ] ) ) ;
return cmd ;
}
2020-12-03 14:26:38 -05:00
# endif
2020-02-03 00:51:26 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * synthesis_save_reverb_ring_buffer ( u64 * cmd , u16 addr , u16 destOffset , s32 len , s32 reverbIndex ) {
aSetBuffer ( cmd + + , 0 , 0 , addr , len ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . left [ destOffset ] ) ) ;
aSetBuffer ( cmd + + , 0 , 0 , addr + DEFAULT_LEN_1CH , len ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . right [ destOffset ] ) ) ;
return cmd ;
}
2020-12-03 14:26:38 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
void synthesis_load_note_subs_eu ( s32 updateIndex ) {
struct NoteSubEu * src ;
struct NoteSubEu * dest ;
s32 i ;
for ( i = 0 ; i < gMaxSimultaneousNotes ; i + + ) {
src = & gNotes [ i ] . noteSubEu ;
dest = & gNoteSubsEu [ gMaxSimultaneousNotes * updateIndex + i ] ;
if ( src - > enabled ) {
* dest = * src ;
2020-12-03 14:26:38 -05:00
src - > needsInit = FALSE ;
2020-02-03 00:51:26 -05:00
} else {
2020-12-03 14:26:38 -05:00
dest - > enabled = FALSE ;
2020-02-03 00:51:26 -05:00
}
}
}
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-08-25 00:46:40 -04:00
s32 get_volume_ramping ( u16 sourceVol , u16 targetVol , s32 arg2 ) {
// This roughly computes 2^16 * (targetVol / sourceVol) ^ (8 / arg2),
// but with discretizations of targetVol, sourceVol and arg2.
f32 ret ;
switch ( arg2 ) {
default :
ret = gVolRampingLhs136 [ targetVol > > 8 ] * gVolRampingRhs136 [ sourceVol > > 8 ] ;
break ;
case 128 :
ret = gVolRampingLhs128 [ targetVol > > 8 ] * gVolRampingRhs128 [ sourceVol > > 8 ] ;
break ;
case 136 :
ret = gVolRampingLhs136 [ targetVol > > 8 ] * gVolRampingRhs136 [ sourceVol > > 8 ] ;
break ;
case 144 :
ret = gVolRampingLhs144 [ targetVol > > 8 ] * gVolRampingRhs144 [ sourceVol > > 8 ] ;
break ;
}
return ret ;
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-12-03 14:26:38 -05:00
// TODO: (Scrub C) pointless mask and whitespace
2020-06-02 12:44:34 -04:00
u64 * synthesis_execute ( u64 * cmdBuf , s32 * writtenCmds , s16 * aiBuf , s32 bufLen ) {
2020-03-01 22:42:52 -05:00
s32 i , j ;
2020-02-03 00:51:26 -05:00
f32 * leftVolRamp ;
f32 * rightVolRamp ;
u32 * aiBufPtr ;
u64 * cmd = cmdBuf ;
2020-03-01 22:42:52 -05:00
s32 chunkLen ;
s32 nextVolRampTable ;
2020-02-03 00:51:26 -05:00
for ( i = gAudioBufferParameters . updatesPerFrame ; i > 0 ; i - - ) {
process_sequences ( i - 1 ) ;
synthesis_load_note_subs_eu ( gAudioBufferParameters . updatesPerFrame - i ) ;
}
aSegment ( cmd + + , 0 , 0 ) ;
aiBufPtr = ( u32 * ) aiBuf ;
for ( i = gAudioBufferParameters . updatesPerFrame ; i > 0 ; i - - ) {
if ( i = = 1 ) {
2020-03-01 22:42:52 -05:00
// self-assignment has no affect when added here, could possibly simplify a macro definition
2021-12-30 10:57:51 -06:00
chunkLen = bufLen ;
leftVolRamp = gLeftVolRampings [ nextVolRampTable ] ;
rightVolRamp = gRightVolRampings [ nextVolRampTable & 0xFFFFFFFF ] ;
2020-02-03 00:51:26 -05:00
} else {
2020-03-01 22:42:52 -05:00
if ( bufLen / i > = gAudioBufferParameters . samplesPerUpdateMax ) {
chunkLen = gAudioBufferParameters . samplesPerUpdateMax ; nextVolRampTable = 2 ; leftVolRamp = gLeftVolRampings [ 2 ] ; rightVolRamp = gRightVolRampings [ 2 ] ;
} else if ( bufLen / i < = gAudioBufferParameters . samplesPerUpdateMin ) {
chunkLen = gAudioBufferParameters . samplesPerUpdateMin ; nextVolRampTable = 0 ; leftVolRamp = gLeftVolRampings [ 0 ] ; rightVolRamp = gRightVolRampings [ 0 ] ;
2020-02-03 00:51:26 -05:00
} else {
2020-03-01 22:42:52 -05:00
chunkLen = gAudioBufferParameters . samplesPerUpdate ; nextVolRampTable = 1 ; leftVolRamp = gLeftVolRampings [ 1 ] ; rightVolRamp = gRightVolRampings [ 1 ] ;
2020-02-03 00:51:26 -05:00
}
}
gCurrentLeftVolRamping = leftVolRamp ;
gCurrentRightVolRamping = rightVolRamp ;
for ( j = 0 ; j < gNumSynthesisReverbs ; j + + ) {
if ( gSynthesisReverbs [ j ] . useReverb ! = 0 ) {
prepare_reverb_ring_buffer ( chunkLen , gAudioBufferParameters . updatesPerFrame - i , j ) ;
}
}
2020-06-02 12:44:34 -04:00
cmd = synthesis_do_one_audio_update ( ( s16 * ) aiBufPtr , chunkLen , cmd , gAudioBufferParameters . updatesPerFrame - i ) ;
2020-03-01 22:42:52 -05:00
bufLen - = chunkLen ;
2020-02-03 00:51:26 -05:00
aiBufPtr + = chunkLen ;
}
2020-03-01 22:42:52 -05:00
for ( j = 0 ; j < gNumSynthesisReverbs ; j + + ) {
if ( gSynthesisReverbs [ j ] . framesLeftToIgnore ! = 0 ) {
gSynthesisReverbs [ j ] . framesLeftToIgnore - - ;
2020-02-03 00:51:26 -05:00
}
2020-03-01 22:42:52 -05:00
gSynthesisReverbs [ j ] . curFrame ^ = 1 ;
2020-02-03 00:51:26 -05:00
}
* writtenCmds = cmd - cmdBuf ;
return cmd ;
}
# else
2019-08-25 00:46:40 -04:00
// bufLen will be divisible by 16
2020-06-02 12:44:34 -04:00
u64 * synthesis_execute ( u64 * cmdBuf , s32 * writtenCmds , s16 * aiBuf , s32 bufLen ) {
2019-08-25 00:46:40 -04:00
s32 chunkLen ;
s32 i ;
u32 * aiBufPtr = ( u32 * ) aiBuf ;
2020-04-03 14:57:26 -04:00
u64 * cmd = cmdBuf + 1 ;
2019-08-25 00:46:40 -04:00
s32 v0 ;
2020-04-03 14:57:26 -04:00
aSegment ( cmdBuf , 0 , 0 ) ;
2019-08-25 00:46:40 -04:00
2021-08-05 00:02:00 -05:00
# ifdef BETTER_REVERB
if ( gIsConsole ) {
2021-09-12 00:59:36 -04:00
reverbFilterCount = ( s32 ) reverbFilterCountConsole ;
2021-08-05 00:02:00 -05:00
monoReverb = monoReverbConsole ;
2021-12-30 10:57:51 -06:00
} else {
2021-09-12 00:59:36 -04:00
reverbFilterCount = ( s32 ) reverbFilterCountEmulator ;
2021-08-05 00:02:00 -05:00
monoReverb = monoReverbEmulator ;
}
2021-12-30 10:57:51 -06:00
if ( reverbFilterCount > NUM_ALLPASS ) {
2021-08-05 01:14:01 -05:00
reverbFilterCount = NUM_ALLPASS ;
2021-12-30 10:57:51 -06:00
}
reverbFilterCountm1 = ( reverbFilterCount - 1 ) ;
if ( reverbFilterCount < 3 ) {
2021-08-05 01:14:01 -05:00
reverbFilterCountm1 = 0 ;
2021-12-30 10:57:51 -06:00
}
2021-08-05 00:02:00 -05:00
# endif
2019-08-25 00:46:40 -04:00
for ( i = gAudioUpdatesPerFrame ; i > 0 ; i - - ) {
if ( i = = 1 ) {
2020-04-03 14:57:26 -04:00
// 'bufLen' will automatically be divisible by 8, no need to round
chunkLen = bufLen ;
2019-08-25 00:46:40 -04:00
} else {
2020-04-03 14:57:26 -04:00
v0 = bufLen / i ;
2019-08-25 00:46:40 -04:00
// chunkLen = v0 rounded to nearest multiple of 8
chunkLen = v0 - ( v0 & 7 ) ;
2019-09-01 15:50:50 -04:00
if ( ( v0 & 7 ) > = 4 ) {
2019-08-25 00:46:40 -04:00
chunkLen + = 8 ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
}
process_sequences ( i - 1 ) ;
2019-11-03 14:36:27 -05:00
if ( gSynthesisReverb . useReverb ! = 0 ) {
prepare_reverb_ring_buffer ( chunkLen , gAudioUpdatesPerFrame - i ) ;
2019-08-25 00:46:40 -04:00
}
2020-06-02 12:44:34 -04:00
cmd = synthesis_do_one_audio_update ( ( s16 * ) aiBufPtr , chunkLen , cmd , gAudioUpdatesPerFrame - i ) ;
2020-04-03 14:57:26 -04:00
bufLen - = chunkLen ;
2019-08-25 00:46:40 -04:00
aiBufPtr + = chunkLen ;
}
2019-11-03 14:36:27 -05:00
if ( gSynthesisReverb . framesLeftToIgnore ! = 0 ) {
gSynthesisReverb . framesLeftToIgnore - - ;
2019-09-01 15:50:50 -04:00
}
2019-11-03 14:36:27 -05:00
gSynthesisReverb . curFrame ^ = 1 ;
2019-08-25 00:46:40 -04:00
* writtenCmds = cmd - cmdBuf ;
return cmd ;
}
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * synthesis_resample_and_mix_reverb ( u64 * cmd , s32 bufLen , s16 reverbIndex , s16 updateIndex ) {
2020-03-01 22:42:52 -05:00
struct ReverbRingBufferItem * item ;
2020-07-04 11:18:55 -04:00
s16 startPad ;
s16 paddedLengthA ;
2020-02-03 00:51:26 -05:00
2020-03-01 22:42:52 -05:00
item = & gSynthesisReverbs [ reverbIndex ] . items [ gSynthesisReverbs [ reverbIndex ] . curFrame ] [ updateIndex ] ;
2020-02-03 00:51:26 -05:00
aClearBuffer ( cmd + + , DMEM_ADDR_WET_LEFT_CH , DEFAULT_LEN_2CH ) ;
2020-03-01 22:42:52 -05:00
if ( gSynthesisReverbs [ reverbIndex ] . downsampleRate = = 1 ) {
2020-07-04 11:18:55 -04:00
cmd = synthesis_load_reverb_ring_buffer ( cmd , DMEM_ADDR_WET_LEFT_CH , item - > startPos , item - > lengthA , reverbIndex ) ;
if ( item - > lengthB ! = 0 ) {
cmd = synthesis_load_reverb_ring_buffer ( cmd , DMEM_ADDR_WET_LEFT_CH + item - > lengthA , 0 , item - > lengthB , reverbIndex ) ;
2020-02-03 00:51:26 -05:00
}
aSetBuffer ( cmd + + , 0 , 0 , 0 , DEFAULT_LEN_2CH ) ;
aMix ( cmd + + , 0 , 0x7fff , DMEM_ADDR_WET_LEFT_CH , DMEM_ADDR_LEFT_CH ) ;
2020-03-01 22:42:52 -05:00
aMix ( cmd + + , 0 , 0x8000 + gSynthesisReverbs [ reverbIndex ] . reverbGain , DMEM_ADDR_WET_LEFT_CH , DMEM_ADDR_WET_LEFT_CH ) ;
2020-02-03 00:51:26 -05:00
} else {
2021-12-30 10:57:51 -06:00
startPad = ( item - > startPos & 0x7 ) * 2
2021-07-18 04:57:37 -05:00
paddedLengthA = AUDIO_ALIGN ( startPad + item - > lengthA , 4 ) ;
2020-03-01 22:42:52 -05:00
2020-07-04 11:18:55 -04:00
cmd = synthesis_load_reverb_ring_buffer ( cmd , DMEM_ADDR_RESAMPLED , ( item - > startPos - startPad / 2 ) , DEFAULT_LEN_1CH , reverbIndex ) ;
if ( item - > lengthB ! = 0 ) {
cmd = synthesis_load_reverb_ring_buffer ( cmd , DMEM_ADDR_RESAMPLED + paddedLengthA , 0 , DEFAULT_LEN_1CH - paddedLengthA , reverbIndex ) ;
2020-02-03 00:51:26 -05:00
}
2020-07-04 11:18:55 -04:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_RESAMPLED + startPad , DMEM_ADDR_WET_LEFT_CH , bufLen * 2 ) ;
2020-03-01 22:42:52 -05:00
aResample ( cmd + + , gSynthesisReverbs [ reverbIndex ] . resampleFlags , gSynthesisReverbs [ reverbIndex ] . resampleRate , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverbs [ reverbIndex ] . resampleStateLeft ) ) ;
2020-02-03 00:51:26 -05:00
2020-07-04 11:18:55 -04:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_RESAMPLED2 + startPad , DMEM_ADDR_WET_RIGHT_CH , bufLen * 2 ) ;
2020-03-01 22:42:52 -05:00
aResample ( cmd + + , gSynthesisReverbs [ reverbIndex ] . resampleFlags , gSynthesisReverbs [ reverbIndex ] . resampleRate , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverbs [ reverbIndex ] . resampleStateRight ) ) ;
2020-02-03 00:51:26 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , DEFAULT_LEN_2CH ) ;
aMix ( cmd + + , 0 , 0x7fff , DMEM_ADDR_WET_LEFT_CH , DMEM_ADDR_LEFT_CH ) ;
2020-03-01 22:42:52 -05:00
aMix ( cmd + + , 0 , 0x8000 + gSynthesisReverbs [ reverbIndex ] . reverbGain , DMEM_ADDR_WET_LEFT_CH , DMEM_ADDR_WET_LEFT_CH ) ;
2020-12-03 14:26:38 -05:00
}
return cmd ;
}
u64 * synthesis_save_reverb_samples ( u64 * cmd , s16 reverbIndex , s16 updateIndex ) {
struct ReverbRingBufferItem * item ;
item = & gSynthesisReverbs [ reverbIndex ] . items [ gSynthesisReverbs [ reverbIndex ] . curFrame ] [ updateIndex ] ;
if ( gSynthesisReverbs [ reverbIndex ] . useReverb ! = 0 ) {
switch ( gSynthesisReverbs [ reverbIndex ] . downsampleRate ) {
case 1 :
// Put the oldest samples in the ring buffer into the wet channels
cmd = synthesis_save_reverb_ring_buffer ( cmd , DMEM_ADDR_WET_LEFT_CH , item - > startPos , item - > lengthA , reverbIndex ) ;
if ( item - > lengthB ! = 0 ) {
// Ring buffer wrapped
cmd = synthesis_save_reverb_ring_buffer ( cmd , DMEM_ADDR_WET_LEFT_CH + item - > lengthA , 0 , item - > lengthB , reverbIndex ) ;
}
break ;
default :
2021-07-12 23:17:54 -04:00
// Downsampling is done later by CPU when RSP is done, therefore we need to have double
// buffering. Left and right buffers are adjacent in memory.
2020-12-03 14:26:38 -05:00
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_WET_LEFT_CH , DEFAULT_LEN_2CH ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverbs [ reverbIndex ] . items [ gSynthesisReverbs [ reverbIndex ] . curFrame ] [ updateIndex ] . toDownsampleLeft ) ) ;
gSynthesisReverbs [ reverbIndex ] . resampleFlags = 0 ;
break ;
2020-03-01 22:42:52 -05:00
}
2020-12-03 14:26:38 -05:00
}
return cmd ;
}
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-12-03 14:26:38 -05:00
u64 * synthesis_do_one_audio_update ( s16 * aiBuf , s32 bufLen , u64 * cmd , s32 updateIndex ) {
2020-03-01 22:42:52 -05:00
struct NoteSubEu * noteSubEu ;
u8 noteIndices [ 56 ] ;
s32 temp ;
s32 i ;
s16 j ;
s16 notePos = 0 ;
2020-02-03 00:51:26 -05:00
if ( gNumSynthesisReverbs = = 0 ) {
2020-03-01 22:42:52 -05:00
for ( i = 0 ; i < gMaxSimultaneousNotes ; i + + ) {
2020-12-03 14:26:38 -05:00
if ( gNoteSubsEu [ gMaxSimultaneousNotes * updateIndex + i ] . enabled ) {
2020-03-01 22:42:52 -05:00
noteIndices [ notePos + + ] = i ;
2020-02-03 00:51:26 -05:00
}
}
} else {
2020-03-01 22:42:52 -05:00
for ( j = 0 ; j < gNumSynthesisReverbs ; j + + ) {
for ( i = 0 ; i < gMaxSimultaneousNotes ; i + + ) {
2020-12-03 14:26:38 -05:00
noteSubEu = & gNoteSubsEu [ gMaxSimultaneousNotes * updateIndex + i ] ;
2020-03-01 22:42:52 -05:00
if ( noteSubEu - > enabled & & j = = noteSubEu - > reverbIndex ) {
noteIndices [ notePos + + ] = i ;
2020-02-03 00:51:26 -05:00
}
}
}
2020-03-01 22:42:52 -05:00
for ( i = 0 ; i < gMaxSimultaneousNotes ; i + + ) {
2020-12-03 14:26:38 -05:00
noteSubEu = & gNoteSubsEu [ gMaxSimultaneousNotes * updateIndex + i ] ;
2020-03-01 22:42:52 -05:00
if ( noteSubEu - > enabled & & noteSubEu - > reverbIndex > = gNumSynthesisReverbs ) {
noteIndices [ notePos + + ] = i ;
2020-02-03 00:51:26 -05:00
}
}
}
aClearBuffer ( cmd + + , DMEM_ADDR_LEFT_CH , DEFAULT_LEN_2CH ) ;
2020-03-01 22:42:52 -05:00
i = 0 ;
for ( j = 0 ; j < gNumSynthesisReverbs ; j + + ) {
gUseReverb = gSynthesisReverbs [ j ] . useReverb ;
2020-02-03 00:51:26 -05:00
if ( gUseReverb ! = 0 ) {
2020-03-01 22:42:52 -05:00
cmd = synthesis_resample_and_mix_reverb ( cmd , bufLen , j , updateIndex ) ;
2020-02-03 00:51:26 -05:00
}
2020-03-01 22:42:52 -05:00
for ( ; i < notePos ; i + + ) {
2020-12-03 14:26:38 -05:00
temp = updateIndex * gMaxSimultaneousNotes ;
2020-03-01 22:42:52 -05:00
if ( j = = gNoteSubsEu [ temp + noteIndices [ i ] ] . reverbIndex ) {
cmd = synthesis_process_note ( & gNotes [ noteIndices [ i ] ] ,
& gNoteSubsEu [ temp + noteIndices [ i ] ] ,
& gNotes [ noteIndices [ i ] ] . synthesisState ,
aiBuf , bufLen , cmd ) ;
continue ;
2020-02-03 00:51:26 -05:00
} else {
break ;
}
}
2020-03-01 22:42:52 -05:00
if ( gSynthesisReverbs [ j ] . useReverb ! = 0 ) {
cmd = synthesis_save_reverb_samples ( cmd , j , updateIndex ) ;
2020-02-03 00:51:26 -05:00
}
}
2020-03-01 22:42:52 -05:00
for ( ; i < notePos ; i + + ) {
2020-12-03 14:26:38 -05:00
temp = updateIndex * gMaxSimultaneousNotes ;
2021-12-30 10:57:51 -06:00
if ( IS_BANK_LOAD_COMPLETE ( gNoteSubsEu [ temp + noteIndices [ i ] ] . bankId ) ) {
2020-03-01 22:42:52 -05:00
cmd = synthesis_process_note ( & gNotes [ noteIndices [ i ] ] ,
& gNoteSubsEu [ temp + noteIndices [ i ] ] ,
& gNotes [ noteIndices [ i ] ] . synthesisState ,
aiBuf , bufLen , cmd ) ;
2020-02-03 00:51:26 -05:00
} else {
2020-03-01 22:42:52 -05:00
gAudioErrorFlags = ( gNoteSubsEu [ temp + noteIndices [ i ] ] . bankId + ( i < < 8 ) ) + 0x10000000 ;
2020-02-03 00:51:26 -05:00
}
}
2020-03-01 22:42:52 -05:00
temp = bufLen * 2 ;
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , temp ) ;
2020-02-03 00:51:26 -05:00
aInterleave ( cmd + + , DMEM_ADDR_LEFT_CH , DMEM_ADDR_RIGHT_CH ) ;
2020-03-01 22:42:52 -05:00
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , temp * 2 ) ;
2020-02-03 00:51:26 -05:00
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( aiBuf ) ) ;
return cmd ;
}
2021-07-12 23:17:54 -04:00
# else
2020-12-03 14:26:38 -05:00
u64 * synthesis_do_one_audio_update ( s16 * aiBuf , s32 bufLen , u64 * cmd , s32 updateIndex ) {
2019-08-25 00:46:40 -04:00
s16 ra ;
s16 t4 ;
2019-11-03 14:36:27 -05:00
struct ReverbRingBufferItem * v1 ;
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
v1 = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
if ( gSynthesisReverb . useReverb = = 0 ) {
aClearBuffer ( cmd + + , DMEM_ADDR_LEFT_CH , DEFAULT_LEN_2CH ) ;
2019-12-01 21:52:53 -05:00
cmd = synthesis_process_notes ( aiBuf , bufLen , cmd ) ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
if ( gReverbDownsampleRate = = 1 ) {
// Put the oldest samples in the ring buffer into the wet channels
aSetLoadBufferPair ( cmd + + , 0 , v1 - > startPos ) ;
2020-07-04 11:18:55 -04:00
if ( v1 - > lengthB ! = 0 ) {
2019-11-03 14:36:27 -05:00
// Ring buffer wrapped
2020-07-04 11:18:55 -04:00
aSetLoadBufferPair ( cmd + + , v1 - > lengthA , 0 ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
// Use the reverb sound as initial sound for this audio update
aDMEMMove ( cmd + + , DMEM_ADDR_WET_LEFT_CH , DMEM_ADDR_LEFT_CH , DEFAULT_LEN_2CH ) ;
// (Hopefully) lower the volume of the wet channels. New reverb will later be mixed into
// these channels.
aSetBuffer ( cmd + + , 0 , 0 , 0 , DEFAULT_LEN_2CH ) ;
// 0x8000 here is -100%
aMix ( cmd + + , 0 , /*gain*/ 0x8000 + gSynthesisReverb . reverbGain , /*in*/ DMEM_ADDR_WET_LEFT_CH ,
/*out*/ DMEM_ADDR_WET_LEFT_CH ) ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
// Same as above but upsample the previously downsampled samples used for reverb first
t4 = ( v1 - > startPos & 7 ) * 2 ;
2021-07-18 04:57:37 -05:00
ra = AUDIO_ALIGN ( v1 - > lengthA + t4 , 4 ) ;
2019-11-03 14:36:27 -05:00
aSetLoadBufferPair ( cmd + + , 0 , v1 - > startPos - t4 / 2 ) ;
2020-07-04 11:18:55 -04:00
if ( v1 - > lengthB ! = 0 ) {
2019-11-03 14:36:27 -05:00
// Ring buffer wrapped
2019-08-25 00:46:40 -04:00
aSetLoadBufferPair ( cmd + + , ra , 0 ) ;
}
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , t4 + DMEM_ADDR_WET_LEFT_CH , DMEM_ADDR_LEFT_CH , bufLen < < 1 ) ;
2020-04-03 14:57:26 -04:00
aResample ( cmd + + , gSynthesisReverb . resampleFlags , ( u16 ) gSynthesisReverb . resampleRate , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . resampleStateLeft ) ) ;
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , t4 + DMEM_ADDR_WET_RIGHT_CH , DMEM_ADDR_RIGHT_CH , bufLen < < 1 ) ;
2020-04-03 14:57:26 -04:00
aResample ( cmd + + , gSynthesisReverb . resampleFlags , ( u16 ) gSynthesisReverb . resampleRate , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . resampleStateRight ) ) ;
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , DEFAULT_LEN_2CH ) ;
2020-04-03 14:57:26 -04:00
aMix ( cmd + + , 0 , /*gain*/ 0x8000 + gSynthesisReverb . reverbGain , /*in*/ DMEM_ADDR_LEFT_CH , /*out*/ DMEM_ADDR_LEFT_CH ) ;
2019-11-03 14:36:27 -05:00
aDMEMMove ( cmd + + , DMEM_ADDR_LEFT_CH , DMEM_ADDR_WET_LEFT_CH , DEFAULT_LEN_2CH ) ;
2019-08-25 00:46:40 -04:00
}
2019-12-01 21:52:53 -05:00
cmd = synthesis_process_notes ( aiBuf , bufLen , cmd ) ;
2019-11-03 14:36:27 -05:00
if ( gReverbDownsampleRate = = 1 ) {
2020-07-04 11:18:55 -04:00
aSetSaveBufferPair ( cmd + + , 0 , v1 - > lengthA , v1 - > startPos ) ;
if ( v1 - > lengthB ! = 0 ) {
2019-11-03 14:36:27 -05:00
// Ring buffer wrapped
2020-07-04 11:18:55 -04:00
aSetSaveBufferPair ( cmd + + , v1 - > lengthA , v1 - > lengthB , 0 ) ;
2019-08-25 00:46:40 -04:00
}
} else {
2019-11-03 14:36:27 -05:00
// Downsampling is done later by CPU when RSP is done, therefore we need to have double
// buffering. Left and right buffers are adjacent in memory.
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_WET_LEFT_CH , DEFAULT_LEN_2CH ) ;
2020-04-03 14:57:26 -04:00
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] . toDownsampleLeft ) ) ;
2019-11-03 14:36:27 -05:00
gSynthesisReverb . resampleFlags = 0 ;
2019-08-25 00:46:40 -04:00
}
}
return cmd ;
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
// Processes just one note, not all
2021-07-12 23:17:54 -04:00
u64 * synthesis_process_note ( struct Note * note , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * synthesisState , UNUSED s16 * aiBuf , s32 bufLen , u64 * cmd ) {
2020-02-03 00:51:26 -05:00
# else
2020-06-02 12:44:34 -04:00
u64 * synthesis_process_notes ( s16 * aiBuf , s32 bufLen , u64 * cmd ) {
2019-11-03 14:36:27 -05:00
s32 noteIndex ; // sp174
struct Note * note ; // s7
2020-04-03 14:57:26 -04:00
# endif
struct AudioBankSample * audioBookSample ; // sp164, sp138
struct AdpcmLoop * loopInfo ; // sp160, sp134
s16 * curLoadedBook = NULL ; // sp154, sp130
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2020-04-03 14:57:26 -04:00
u16 resamplingRateFixedPoint ; // sp5c, sp11A
# endif
s32 noteFinished ; // 150 t2, sp124
s32 restart ; // 14c t3, sp120
s32 flags ; // sp148, sp11C
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
u16 resamplingRateFixedPoint ; // sp5c, sp11A
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
UNUSED s32 tempBufLen ;
2021-07-18 04:57:37 -05:00
s32 sp130 = 0 ; //sp128, sp104
2020-04-03 14:57:26 -04:00
s32 nAdpcmSamplesProcessed ; // signed required for US
2019-08-25 00:46:40 -04:00
s32 t0 ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
u8 * sampleAddr ; // sp120, spF4
s32 s6 ;
# else
s32 s6 ;
u8 * sampleAddr ; // sp120, spF4
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
s32 samplesLenAdjusted ; // 108, spEC
// Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
// behavior with the break near the end of the loop, causing US and JP to need a goto instead
UNUSED s32 samplesLenInt ;
s32 endPos ; // sp110, spE4
s32 nSamplesToProcess ; // sp10c/a0, spE0
s32 s2 ;
# else
// Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
// behavior with the break near the end of the loop, causing US and JP to need a goto instead
UNUSED s32 samplesLenInt ;
s32 samplesLenAdjusted ; // 108
2019-08-25 00:46:40 -04:00
s32 s2 ;
2020-04-03 14:57:26 -04:00
s32 endPos ; // sp110, spE4
s32 nSamplesToProcess ; // sp10c/a0, spE0
# endif
2019-08-25 00:46:40 -04:00
2020-12-03 14:26:38 -05:00
s32 leftRight ;
2019-08-25 00:46:40 -04:00
s32 s3 ;
2020-04-03 14:57:26 -04:00
s32 s5 ; //s4
2019-11-03 14:36:27 -05:00
u32 samplesLenFixedPoint ; // v1_1
s32 nSamplesInThisIteration ; // v1_2
2019-08-25 00:46:40 -04:00
u32 a3 ;
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-08-25 00:46:40 -04:00
s32 t9 ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
u8 * v0_2 ;
2020-04-03 14:57:26 -04:00
s32 nParts ; // spE8, spBC
s32 curPart ; // spE4, spB8
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-11-03 14:36:27 -05:00
f32 resamplingRate ; // f12
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
s32 temp ;
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
s32 s5Aligned ;
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
s32 resampledTempLen ; // spD8, spAC
u16 noteSamplesDmemAddrBeforeResampling ; // spD6, spAA
2020-02-03 00:51:26 -05:00
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2020-04-03 14:57:26 -04:00
for ( noteIndex = 0 ; noteIndex < gMaxSimultaneousNotes ; noteIndex + + ) {
2019-11-03 14:36:27 -05:00
note = & gNotes [ noteIndex ] ;
2020-04-03 14:57:26 -04:00
# ifdef VERSION_US
//! This function requires note->enabled to be volatile, but it breaks other functions like note_enable.
//! Casting to a struct with just the volatile bitfield works, but there may be a better way to match.
2021-12-30 10:57:51 -06:00
if ( ( ( struct vNote * ) note ) - > enabled & & ! IS_BANK_LOAD_COMPLETE ( note - > bankId ) ) {
2020-04-03 14:57:26 -04:00
# else
2021-12-30 10:57:51 -06:00
if ( ! IS_BANK_LOAD_COMPLETE ( note - > bankId ) ) {
2020-04-03 14:57:26 -04:00
# endif
2019-11-03 14:36:27 -05:00
gAudioErrorFlags = ( note - > bankId < < 8 ) + noteIndex + 0x1000000 ;
2020-04-03 14:57:26 -04:00
} else if ( ( ( struct vNote * ) note ) - > enabled ) {
2020-02-03 00:51:26 -05:00
# else
2020-04-03 14:57:26 -04:00
if ( note - > noteSubEu . enabled = = FALSE ) {
return cmd ;
} else {
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
flags = 0 ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
tempBufLen = bufLen ;
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( noteSubEu - > needsInit = = TRUE ) {
# else
2019-11-03 14:36:27 -05:00
if ( note - > needsInit = = TRUE ) {
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
flags = A_INIT ;
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-11-03 14:36:27 -05:00
note - > samplePosInt = 0 ;
note - > samplePosFrac = 0 ;
2020-02-03 00:51:26 -05:00
# else
synthesisState - > restart = FALSE ;
synthesisState - > samplePosInt = 0 ;
synthesisState - > samplePosFrac = 0 ;
synthesisState - > curVolLeft = 1 ;
synthesisState - > curVolRight = 1 ;
synthesisState - > prevHeadsetPanRight = 0 ;
synthesisState - > prevHeadsetPanLeft = 0 ;
# endif
2019-08-25 00:46:40 -04:00
}
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2021-12-30 10:57:51 -06:00
if ( note - > frequency < 2.0f ) {
2019-11-03 14:36:27 -05:00
nParts = 1 ;
2021-12-30 10:57:51 -06:00
if ( note - > frequency > 1.99996f ) {
note - > frequency = 1.99996f ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
resamplingRate = note - > frequency ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
// If frequency is > 2.0, the processing must be split into two parts
nParts = 2 ;
2021-12-30 10:57:51 -06:00
if ( note - > frequency > = 3.99993f ) {
note - > frequency = 3.99993f ;
2019-08-25 00:46:40 -04:00
}
2021-12-30 10:57:51 -06:00
resamplingRate = note - > frequency * 0.5f ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
resamplingRateFixedPoint = ( u16 ) ( s32 ) ( resamplingRate * 32768.0f ) ;
samplesLenFixedPoint = note - > samplePosFrac + ( resamplingRateFixedPoint * bufLen ) * 2 ;
2020-04-03 14:57:26 -04:00
note - > samplePosFrac = samplesLenFixedPoint & 0xFFFF ; // 16-bit store, can't reuse
2020-02-03 00:51:26 -05:00
# else
resamplingRateFixedPoint = noteSubEu - > resamplingRateFixedPoint ;
nParts = noteSubEu - > hasTwoAdpcmParts + 1 ;
2020-04-03 14:57:26 -04:00
samplesLenFixedPoint = ( resamplingRateFixedPoint * tempBufLen * 2 ) + synthesisState - > samplePosFrac ;
synthesisState - > samplePosFrac = samplesLenFixedPoint & 0xFFFF ;
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( noteSubEu - > isSyntheticWave ) {
2020-03-01 22:42:52 -05:00
cmd = load_wave_samples ( cmd , noteSubEu , synthesisState , samplesLenFixedPoint > > 0x10 ) ;
2020-04-03 14:57:26 -04:00
noteSamplesDmemAddrBeforeResampling = ( synthesisState - > samplePosInt * 2 ) + DMEM_ADDR_UNCOMPRESSED_NOTE ;
synthesisState - > samplePosInt + = samplesLenFixedPoint > > 0x10 ;
2020-02-03 00:51:26 -05:00
}
# else
2019-11-03 14:36:27 -05:00
if ( note - > sound = = NULL ) {
// A wave synthesis note (not ADPCM)
2020-04-03 14:57:26 -04:00
2019-11-03 14:36:27 -05:00
cmd = load_wave_samples ( cmd , note , samplesLenFixedPoint > > 0x10 ) ;
2020-04-03 14:57:26 -04:00
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + note - > samplePosInt * 2 ;
2019-11-03 14:36:27 -05:00
note - > samplePosInt + = ( samplesLenFixedPoint > > 0x10 ) ;
flags = 0 ;
2020-02-03 00:51:26 -05:00
}
# endif
else {
2019-11-03 14:36:27 -05:00
// ADPCM note
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
audioBookSample = noteSubEu - > sound . audioBankSound - > sample ;
# else
2019-11-03 14:36:27 -05:00
audioBookSample = note - > sound - > sample ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
loopInfo = audioBookSample - > loop ;
endPos = loopInfo - > end ;
sampleAddr = audioBookSample - > sampleAddr ;
resampledTempLen = 0 ;
for ( curPart = 0 ; curPart < nParts ; curPart + + ) {
2020-04-03 14:57:26 -04:00
nAdpcmSamplesProcessed = 0 ; // s8
s5 = 0 ; // s4
if ( nParts = = 1 ) {
samplesLenAdjusted = samplesLenFixedPoint > > 0x10 ;
} else if ( ( samplesLenFixedPoint > > 0x10 ) & 1 ) {
samplesLenAdjusted = ( ( samplesLenFixedPoint > > 0x10 ) & ~ 1 ) + ( curPart * 2 ) ;
}
else {
samplesLenAdjusted = ( samplesLenFixedPoint > > 0x10 ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
if ( curLoadedBook ! = audioBookSample - > book - > book ) {
u32 nEntries ; // v1
curLoadedBook = audioBookSample - > book - > book ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
nEntries = 16 * audioBookSample - > book - > order * audioBookSample - > book - > npredictors ;
aLoadADPCM ( cmd + + , nEntries , VIRTUAL_TO_PHYSICAL2 ( curLoadedBook + noteSubEu - > bookOffset ) ) ;
2020-03-01 22:42:52 -05:00
# else
2020-04-03 14:57:26 -04:00
nEntries = audioBookSample - > book - > order * audioBookSample - > book - > npredictors ;
2019-11-03 14:36:27 -05:00
aLoadADPCM ( cmd + + , nEntries * 16 , VIRTUAL_TO_PHYSICAL2 ( curLoadedBook ) ) ;
2020-03-01 22:42:52 -05:00
# endif
2019-08-25 00:46:40 -04:00
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-03-01 22:42:52 -05:00
if ( noteSubEu - > bookOffset ) {
2020-12-03 14:26:38 -05:00
curLoadedBook = euUnknownData_80301950 ; // what's this? never read
2020-02-03 00:51:26 -05:00
}
# endif
2019-11-03 14:36:27 -05:00
while ( nAdpcmSamplesProcessed ! = samplesLenAdjusted ) {
s32 samplesRemaining ; // v1
2019-08-25 00:46:40 -04:00
s32 s0 ;
2020-04-03 14:57:26 -04:00
2019-11-03 14:36:27 -05:00
noteFinished = FALSE ;
restart = FALSE ;
nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
s2 = synthesisState - > samplePosInt & 0xf ;
samplesRemaining = endPos - synthesisState - > samplePosInt ;
# else
2019-11-03 14:36:27 -05:00
s2 = note - > samplePosInt & 0xf ;
samplesRemaining = endPos - note - > samplePosInt ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
if ( s2 = = 0 & & synthesisState - > restart = = FALSE ) {
2020-02-03 00:51:26 -05:00
s2 = 16 ;
}
# else
2020-04-03 14:57:26 -04:00
if ( s2 = = 0 & & note - > restart = = FALSE ) {
2019-08-25 00:46:40 -04:00
s2 = 16 ;
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
s6 = 16 - s2 ; // a1
2019-11-03 14:36:27 -05:00
if ( nSamplesToProcess < samplesRemaining ) {
t0 = ( nSamplesToProcess - s6 + 0xf ) / 16 ;
2019-08-25 00:46:40 -04:00
s0 = t0 * 16 ;
2019-11-03 14:36:27 -05:00
s3 = s6 + s0 - nSamplesToProcess ;
2019-08-25 00:46:40 -04:00
} else {
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-11-03 14:36:27 -05:00
s0 = samplesRemaining + s2 - 0x10 ;
2020-04-03 14:57:26 -04:00
# else
s0 = samplesRemaining - s6 ;
# endif
2019-08-25 00:46:40 -04:00
s3 = 0 ;
if ( s0 < = 0 ) {
s0 = 0 ;
2019-11-03 14:36:27 -05:00
s6 = samplesRemaining ;
2019-08-25 00:46:40 -04:00
}
t0 = ( s0 + 0xf ) / 16 ;
2019-11-03 14:36:27 -05:00
if ( loopInfo - > count ! = 0 ) {
// Loop around and restart
restart = 1 ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
noteFinished = 1 ;
2019-08-25 00:46:40 -04:00
}
}
if ( t0 ! = 0 ) {
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
temp = ( synthesisState - > samplePosInt - s2 + 0x10 ) / 16 ;
2020-02-03 00:51:26 -05:00
if ( audioBookSample - > loaded = = 0x81 ) {
2020-04-03 14:57:26 -04:00
v0_2 = sampleAddr + temp * 9 ;
2020-02-03 00:51:26 -05:00
} else {
v0_2 = dma_sample_data (
2020-04-03 14:57:26 -04:00
( uintptr_t ) ( sampleAddr + temp * 9 ) ,
2020-02-03 00:51:26 -05:00
t0 * 9 , flags , & synthesisState - > sampleDmaIndex ) ;
}
# else
2020-04-03 14:57:26 -04:00
temp = ( note - > samplePosInt - s2 + 0x10 ) / 16 ;
2019-11-03 14:36:27 -05:00
v0_2 = dma_sample_data (
2020-04-03 14:57:26 -04:00
( uintptr_t ) ( sampleAddr + temp * 9 ) ,
2019-11-03 14:36:27 -05:00
t0 * 9 , flags , & note - > sampleDmaIndex ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-10-05 15:08:05 -04:00
a3 = ( u32 ) ( ( uintptr_t ) v0_2 & 0xf ) ;
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_COMPRESSED_ADPCM_DATA , 0 , t0 * 9 + a3 ) ;
2019-10-05 15:08:05 -04:00
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( v0_2 - a3 ) ) ;
2019-08-25 00:46:40 -04:00
} else {
s0 = 0 ;
a3 = 0 ;
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( synthesisState - > restart ! = FALSE ) {
aSetLoop ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( audioBookSample - > loop - > state ) ) ;
flags = A_LOOP ; // = 2
synthesisState - > restart = FALSE ;
}
2020-04-03 14:57:26 -04:00
# else
if ( note - > restart ! = FALSE ) {
aSetLoop ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( audioBookSample - > loop - > state ) ) ;
flags = A_LOOP ; // = 2
note - > restart = FALSE ;
}
# endif
2020-02-03 00:51:26 -05:00
2020-04-03 14:57:26 -04:00
nSamplesInThisIteration = s0 + s6 - s3 ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( nAdpcmSamplesProcessed = = 0 ) {
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3 ,
DMEM_ADDR_UNCOMPRESSED_NOTE , s0 * 2 ) ;
aADPCMdec ( cmd + + , flags ,
VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > adpcmdecState ) ) ;
sp130 = s2 * 2 ;
} else {
2021-07-18 04:57:37 -05:00
s5Aligned = AUDIO_ALIGN ( s5 , 5 ) ;
2020-02-03 00:51:26 -05:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3 ,
2020-04-03 14:57:26 -04:00
DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned , s0 * 2 ) ;
2020-02-03 00:51:26 -05:00
aADPCMdec ( cmd + + , flags ,
VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > adpcmdecState ) ) ;
2020-04-03 14:57:26 -04:00
aDMEMMove ( cmd + + , DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned + ( s2 * 2 ) ,
DMEM_ADDR_UNCOMPRESSED_NOTE + s5 , ( nSamplesInThisIteration ) * 2 ) ;
2020-02-03 00:51:26 -05:00
}
# else
2019-11-03 14:36:27 -05:00
if ( nAdpcmSamplesProcessed = = 0 ) {
2020-04-03 14:57:26 -04:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3 , DMEM_ADDR_UNCOMPRESSED_NOTE , s0 * 2 ) ;
aADPCMdec ( cmd + + , flags , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > adpcmdecState ) ) ;
2019-08-25 00:46:40 -04:00
sp130 = s2 * 2 ;
} else {
2021-07-18 04:57:37 -05:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3 , DMEM_ADDR_UNCOMPRESSED_NOTE + AUDIO_ALIGN ( s5 , 5 ) , s0 * 2 ) ;
2020-04-03 14:57:26 -04:00
aADPCMdec ( cmd + + , flags , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > adpcmdecState ) ) ;
2021-07-18 04:57:37 -05:00
aDMEMMove ( cmd + + , DMEM_ADDR_UNCOMPRESSED_NOTE + AUDIO_ALIGN ( s5 , 5 ) + ( s2 * 2 ) , DMEM_ADDR_UNCOMPRESSED_NOTE + s5 , ( nSamplesInThisIteration ) * 2 ) ;
2019-08-25 00:46:40 -04:00
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2020-04-03 14:57:26 -04:00
nAdpcmSamplesProcessed + = nSamplesInThisIteration ;
2019-11-03 14:36:27 -05:00
switch ( flags ) {
case A_INIT : // = 1
2019-08-25 00:46:40 -04:00
sp130 = 0 ;
2020-04-03 14:57:26 -04:00
s5 = s0 * 2 + s5 ;
2019-08-25 00:46:40 -04:00
break ;
case A_LOOP : // = 2
2020-04-03 14:57:26 -04:00
s5 = nSamplesInThisIteration * 2 + s5 ;
2019-08-25 00:46:40 -04:00
break ;
default :
if ( s5 ! = 0 ) {
2020-04-03 14:57:26 -04:00
s5 = nSamplesInThisIteration * 2 + s5 ;
2019-08-25 00:46:40 -04:00
} else {
2020-04-03 14:57:26 -04:00
s5 = ( s2 + nSamplesInThisIteration ) * 2 ;
2019-08-25 00:46:40 -04:00
}
break ;
}
2019-11-03 14:36:27 -05:00
flags = 0 ;
if ( noteFinished ) {
aClearBuffer ( cmd + + , DMEM_ADDR_UNCOMPRESSED_NOTE + s5 ,
( samplesLenAdjusted - nAdpcmSamplesProcessed ) * 2 ) ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
noteSubEu - > finished = 1 ;
2020-03-01 22:42:52 -05:00
note - > noteSubEu . finished = 1 ;
note - > noteSubEu . enabled = 0 ;
2020-02-03 00:51:26 -05:00
# else
2019-11-03 14:36:27 -05:00
note - > samplePosInt = 0 ;
note - > finished = 1 ;
2020-04-03 14:57:26 -04:00
( ( struct vNote * ) note ) - > enabled = 0 ;
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
break ;
2019-08-25 00:46:40 -04:00
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( restart ) {
synthesisState - > restart = TRUE ;
synthesisState - > samplePosInt = loopInfo - > start ;
} else {
synthesisState - > samplePosInt + = nSamplesToProcess ;
}
# else
2019-11-03 14:36:27 -05:00
if ( restart ) {
note - > restart = TRUE ;
note - > samplePosInt = loopInfo - > start ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
note - > samplePosInt + = nSamplesToProcess ;
2019-08-25 00:46:40 -04:00
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
switch ( nParts ) {
2019-08-25 00:46:40 -04:00
case 1 :
2019-11-03 14:36:27 -05:00
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + sp130 ;
2019-08-25 00:46:40 -04:00
break ;
case 2 :
2019-11-03 14:36:27 -05:00
switch ( curPart ) {
2019-08-25 00:46:40 -04:00
case 0 :
2020-07-04 11:18:55 -04:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_UNCOMPRESSED_NOTE + sp130 , DMEM_ADDR_RESAMPLED , samplesLenAdjusted + 4 ) ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
aResample ( cmd + + , A_INIT , 0xff60 , VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > dummyResampleState ) ) ;
2020-02-03 00:51:26 -05:00
# else
2020-04-03 14:57:26 -04:00
aResample ( cmd + + , A_INIT , 0xff60 , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > dummyResampleState ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
resampledTempLen = samplesLenAdjusted + 4 ;
2020-07-04 11:18:55 -04:00
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED + 4 ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
if ( noteSubEu - > finished ! = FALSE ) {
2020-02-03 00:51:26 -05:00
# else
2020-04-03 14:57:26 -04:00
if ( note - > finished ! = FALSE ) {
2020-02-03 00:51:26 -05:00
# endif
2020-07-04 11:18:55 -04:00
aClearBuffer ( cmd + + , DMEM_ADDR_RESAMPLED + resampledTempLen , samplesLenAdjusted + 0x10 ) ;
2019-08-25 00:46:40 -04:00
}
break ;
case 1 :
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_UNCOMPRESSED_NOTE + sp130 ,
2020-07-04 11:18:55 -04:00
DMEM_ADDR_RESAMPLED2 ,
2020-04-03 14:57:26 -04:00
samplesLenAdjusted + 8 ) ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
aResample ( cmd + + , A_INIT , 0xff60 ,
VIRTUAL_TO_PHYSICAL2 (
synthesisState - > synthesisBuffers - > dummyResampleState ) ) ;
# else
2019-11-03 14:36:27 -05:00
aResample ( cmd + + , A_INIT , 0xff60 ,
VIRTUAL_TO_PHYSICAL2 (
note - > synthesisBuffers - > dummyResampleState ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2020-07-04 11:18:55 -04:00
aDMEMMove ( cmd + + , DMEM_ADDR_RESAMPLED2 + 4 ,
DMEM_ADDR_RESAMPLED + resampledTempLen ,
2019-11-03 14:36:27 -05:00
samplesLenAdjusted + 4 ) ;
2019-08-25 00:46:40 -04:00
break ;
}
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
if ( noteSubEu - > finished ! = FALSE ) {
2020-02-03 00:51:26 -05:00
# else
2020-04-03 14:57:26 -04:00
if ( note - > finished ! = FALSE ) {
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
break ;
2019-08-25 00:46:40 -04:00
}
}
}
2020-04-03 14:57:26 -04:00
flags = 0 ;
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( noteSubEu - > needsInit = = TRUE ) {
flags = A_INIT ;
noteSubEu - > needsInit = FALSE ;
}
2020-03-01 22:42:52 -05:00
cmd = final_resample ( cmd , synthesisState , bufLen * 2 , resamplingRateFixedPoint ,
noteSamplesDmemAddrBeforeResampling , flags ) ;
2020-02-03 00:51:26 -05:00
# else
2019-11-03 14:36:27 -05:00
if ( note - > needsInit = = TRUE ) {
flags = A_INIT ;
note - > needsInit = FALSE ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
cmd = final_resample ( cmd , note , bufLen * 2 , resamplingRateFixedPoint ,
noteSamplesDmemAddrBeforeResampling , flags ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
if ( noteSubEu - > headsetPanRight ! = 0 | | synthesisState - > prevHeadsetPanRight ! = 0 ) {
2020-12-03 14:26:38 -05:00
leftRight = 1 ;
2021-07-12 23:17:54 -04:00
} else if ( noteSubEu - > headsetPanLeft ! = 0 | | synthesisState - > prevHeadsetPanLeft ! = 0 ) {
2020-12-03 14:26:38 -05:00
leftRight = 2 ;
2020-02-03 00:51:26 -05:00
# else
2021-07-12 23:17:54 -04:00
if ( note - > headsetPanRight ! = 0 | | note - > prevHeadsetPanRight ! = 0 ) {
2020-12-03 14:26:38 -05:00
leftRight = 1 ;
2021-07-12 23:17:54 -04:00
} else if ( note - > headsetPanLeft ! = 0 | | note - > prevHeadsetPanLeft ! = 0 ) {
2020-12-03 14:26:38 -05:00
leftRight = 2 ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
} else {
2020-12-03 14:26:38 -05:00
leftRight = 0 ;
2019-08-25 00:46:40 -04:00
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-12-03 14:26:38 -05:00
cmd = process_envelope ( cmd , noteSubEu , synthesisState , bufLen , 0 , leftRight , flags ) ;
2020-02-03 00:51:26 -05:00
# else
2020-12-03 14:26:38 -05:00
cmd = process_envelope ( cmd , note , bufLen , 0 , leftRight , flags ) ;
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( noteSubEu - > usesHeadsetPanEffects ) {
2020-12-03 14:26:38 -05:00
cmd = note_apply_headset_pan_effects ( cmd , noteSubEu , synthesisState , bufLen * 2 , flags , leftRight ) ;
2020-02-03 00:51:26 -05:00
}
# else
2019-11-03 14:36:27 -05:00
if ( note - > usesHeadsetPanEffects ) {
2020-12-03 14:26:38 -05:00
cmd = note_apply_headset_pan_effects ( cmd , note , bufLen * 2 , flags , leftRight ) ;
2019-08-25 00:46:40 -04:00
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
}
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-08-25 00:46:40 -04:00
}
t9 = bufLen * 2 ;
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , t9 ) ;
aInterleave ( cmd + + , DMEM_ADDR_LEFT_CH , DMEM_ADDR_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
t9 * = 2 ;
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , t9 ) ;
2019-10-05 15:08:05 -04:00
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( aiBuf ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
return cmd ;
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * load_wave_samples ( u64 * cmd , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * synthesisState , s32 nSamplesToLoad ) {
s32 a3 ;
s32 repeats ;
2020-12-03 14:26:38 -05:00
s32 i ;
2020-02-03 00:51:26 -05:00
aSetBuffer ( cmd + + , /*flags*/ 0 , /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE , /*dmemout*/ 0 , /*count*/ 128 ) ;
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( noteSubEu - > sound . samples ) ) ;
2020-12-03 14:26:38 -05:00
2020-02-03 00:51:26 -05:00
synthesisState - > samplePosInt & = 0x3f ;
a3 = 64 - synthesisState - > samplePosInt ;
if ( a3 < nSamplesToLoad ) {
repeats = ( nSamplesToLoad - a3 + 63 ) / 64 ;
for ( i = 0 ; i < repeats ; i + + ) {
aDMEMMove ( cmd + + ,
/*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE ,
/*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + ( 1 + i ) * 128 ,
/*count*/ 128 ) ;
}
}
return cmd ;
}
# else
2019-11-03 14:36:27 -05:00
u64 * load_wave_samples ( u64 * cmd , struct Note * note , s32 nSamplesToLoad ) {
2019-08-25 00:46:40 -04:00
s32 a3 ;
s32 i ;
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , /*flags*/ 0 , /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE , /*dmemout*/ 0 ,
2020-02-03 00:51:26 -05:00
/*count*/ sizeof ( note - > synthesisBuffers - > samples ) ) ;
2019-11-03 14:36:27 -05:00
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > samples ) ) ;
2020-04-03 14:57:26 -04:00
note - > samplePosInt & = ( note - > sampleCount - 1 ) ;
2019-11-03 14:36:27 -05:00
a3 = 64 - note - > samplePosInt ;
if ( a3 < nSamplesToLoad ) {
for ( i = 0 ; i < = ( nSamplesToLoad - a3 + 63 ) / 64 - 1 ; i + + ) {
2020-04-03 14:57:26 -04:00
aDMEMMove ( cmd + + , /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE , /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + ( 1 + i ) * sizeof ( note - > synthesisBuffers - > samples ) , /*count*/ sizeof ( note - > synthesisBuffers - > samples ) ) ;
2019-08-25 00:46:40 -04:00
}
}
return cmd ;
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * final_resample ( u64 * cmd , struct NoteSynthesisState * synthesisState , s32 count , u16 pitch , u16 dmemIn , u32 flags ) {
2021-07-12 23:17:54 -04:00
aSetBuffer ( cmd + + , /*flags*/ 0 , dmemIn , /*dmemout*/ DMEM_ADDR_TEMP , count ) ;
aResample ( cmd + + , flags , pitch , VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > finalResampleState ) ) ;
2020-02-03 00:51:26 -05:00
return cmd ;
}
# else
2019-11-03 14:36:27 -05:00
u64 * final_resample ( u64 * cmd , struct Note * note , s32 count , u16 pitch , u16 dmemIn , u32 flags ) {
2020-12-03 14:26:38 -05:00
aSetBuffer ( cmd + + , /*flags*/ 0 , dmemIn , /*dmemout*/ DMEM_ADDR_TEMP , count ) ;
2019-11-03 14:36:27 -05:00
aResample ( cmd + + , flags , pitch , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > finalResampleState ) ) ;
2019-08-25 00:46:40 -04:00
return cmd ;
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2021-12-30 10:57:51 -06:00
u64 * process_envelope ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf , s32 headsetPanSettings ,
UNUSED u32 flags ) {
2019-08-25 00:46:40 -04:00
struct VolumeChange vol ;
vol . sourceLeft = note - > curVolLeft ;
vol . sourceRight = note - > curVolRight ;
vol . targetLeft = note - > targetVolLeft ;
vol . targetRight = note - > targetVolRight ;
note - > curVolLeft = vol . targetLeft ;
note - > curVolRight = vol . targetRight ;
2019-11-03 14:36:27 -05:00
return process_envelope_inner ( cmd , note , nSamples , inBuf , headsetPanSettings , & vol ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
u64 * process_envelope_inner ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf ,
s32 headsetPanSettings , struct VolumeChange * vol ) {
2019-08-25 00:46:40 -04:00
u8 mixerFlags ;
s32 rampLeft , rampRight ;
2020-12-03 14:26:38 -05:00
# elif defined(VERSION_EU)
2020-04-03 14:57:26 -04:00
u64 * process_envelope ( u64 * cmd , struct NoteSubEu * note , struct NoteSynthesisState * synthesisState , s32 nSamples , u16 inBuf , s32 headsetPanSettings , UNUSED u32 flags ) {
2020-02-03 00:51:26 -05:00
u16 sourceRight ;
u16 sourceLeft ;
u16 targetLeft ;
u16 targetRight ;
s32 mixerFlags ;
s32 rampLeft ;
s32 rampRight ;
sourceLeft = synthesisState - > curVolLeft ;
sourceRight = synthesisState - > curVolRight ;
targetLeft = ( note - > targetVolLeft < < 5 ) ;
targetRight = ( note - > targetVolRight < < 5 ) ;
if ( targetLeft = = 0 ) {
targetLeft + + ;
}
if ( targetRight = = 0 ) {
targetRight + + ;
}
synthesisState - > curVolLeft = targetLeft ;
synthesisState - > curVolRight = targetRight ;
# endif
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
// For aEnvMixer, five buffers and count are set using aSetBuffer.
// in, dry left, count without A_AUX flag.
// dry right, wet left, wet right with A_AUX flag.
if ( note - > usesHeadsetPanEffects ) {
aClearBuffer ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , DEFAULT_LEN_1CH ) ;
switch ( headsetPanSettings ) {
2019-08-25 00:46:40 -04:00
case 1 :
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , inBuf , DMEM_ADDR_NOTE_PAN_TEMP , nSamples * 2 ) ;
aSetBuffer ( cmd + + , A_AUX , DMEM_ADDR_RIGHT_CH , DMEM_ADDR_WET_LEFT_CH ,
DMEM_ADDR_WET_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
break ;
case 2 :
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , inBuf , DMEM_ADDR_LEFT_CH , nSamples * 2 ) ;
aSetBuffer ( cmd + + , A_AUX , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_WET_LEFT_CH ,
DMEM_ADDR_WET_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
break ;
default :
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , inBuf , DMEM_ADDR_LEFT_CH , nSamples * 2 ) ;
aSetBuffer ( cmd + + , A_AUX , DMEM_ADDR_RIGHT_CH , DMEM_ADDR_WET_LEFT_CH ,
DMEM_ADDR_WET_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
break ;
}
} else {
2019-11-03 14:36:27 -05:00
// It's a bit unclear what the "stereo strong" concept does.
// Instead of mixing the opposite channel to the normal buffers, the sound is first
// mixed into a temporary buffer and then subtracted from the normal buffer.
2019-08-25 00:46:40 -04:00
if ( note - > stereoStrongRight ) {
2019-11-03 14:36:27 -05:00
aClearBuffer ( cmd + + , DMEM_ADDR_STEREO_STRONG_TEMP_DRY , DEFAULT_LEN_2CH ) ;
aSetBuffer ( cmd + + , 0 , inBuf , DMEM_ADDR_STEREO_STRONG_TEMP_DRY , nSamples * 2 ) ;
aSetBuffer ( cmd + + , A_AUX , DMEM_ADDR_RIGHT_CH , DMEM_ADDR_STEREO_STRONG_TEMP_WET ,
DMEM_ADDR_WET_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
} else if ( note - > stereoStrongLeft ) {
2019-11-03 14:36:27 -05:00
aClearBuffer ( cmd + + , DMEM_ADDR_STEREO_STRONG_TEMP_DRY , DEFAULT_LEN_2CH ) ;
aSetBuffer ( cmd + + , 0 , inBuf , DMEM_ADDR_LEFT_CH , nSamples * 2 ) ;
aSetBuffer ( cmd + + , A_AUX , DMEM_ADDR_STEREO_STRONG_TEMP_DRY , DMEM_ADDR_WET_LEFT_CH ,
DMEM_ADDR_STEREO_STRONG_TEMP_WET ) ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , inBuf , DMEM_ADDR_LEFT_CH , nSamples * 2 ) ;
aSetBuffer ( cmd + + , A_AUX , DMEM_ADDR_RIGHT_CH , DMEM_ADDR_WET_LEFT_CH , DMEM_ADDR_WET_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
}
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( targetLeft = = sourceLeft & & targetRight = = sourceRight & & ! note - > envMixerNeedsInit ) {
# else
2020-04-03 14:57:26 -04:00
if ( vol - > targetLeft = = vol - > sourceLeft & & vol - > targetRight = = vol - > sourceRight
2019-11-03 14:36:27 -05:00
& & ! note - > envMixerNeedsInit ) {
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
mixerFlags = A_CONTINUE ;
} else {
mixerFlags = A_INIT ;
2020-02-03 00:51:26 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
rampLeft = gCurrentLeftVolRamping [ targetLeft > > 5 ] * gCurrentRightVolRamping [ sourceLeft > > 5 ] ;
rampRight = gCurrentLeftVolRamping [ targetRight > > 5 ] * gCurrentRightVolRamping [ sourceRight > > 5 ] ;
# else
2019-11-03 14:36:27 -05:00
rampLeft = get_volume_ramping ( vol - > sourceLeft , vol - > targetLeft , nSamples ) ;
rampRight = get_volume_ramping ( vol - > sourceRight , vol - > targetRight , nSamples ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
// The operation's parameters change meanings depending on flags
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
aSetVolume ( cmd + + , A_VOL | A_LEFT , sourceLeft , 0 , 0 ) ;
aSetVolume ( cmd + + , A_VOL | A_RIGHT , sourceRight , 0 , 0 ) ;
aSetVolume32 ( cmd + + , A_RATE | A_LEFT , targetLeft , rampLeft ) ;
aSetVolume32 ( cmd + + , A_RATE | A_RIGHT , targetRight , rampRight ) ;
aSetVolume ( cmd + + , A_AUX , gVolume , 0 , note - > reverbVol < < 8 ) ;
# else
2019-08-25 00:46:40 -04:00
aSetVolume ( cmd + + , A_VOL | A_LEFT , vol - > sourceLeft , 0 , 0 ) ;
aSetVolume ( cmd + + , A_VOL | A_RIGHT , vol - > sourceRight , 0 , 0 ) ;
aSetVolume32 ( cmd + + , A_RATE | A_LEFT , vol - > targetLeft , rampLeft ) ;
aSetVolume32 ( cmd + + , A_RATE | A_RIGHT , vol - > targetRight , rampRight ) ;
2021-07-12 23:17:54 -04:00
aSetVolume ( cmd + + , A_AUX , gVolume , 0 , note - > reverbVolShifted ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
}
2020-02-03 00:51:26 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( gUseReverb & & note - > reverbVol ! = 0 ) {
aEnvMixer ( cmd + + , mixerFlags | A_AUX ,
VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > mixEnvelopeState ) ) ;
# else
2021-07-12 23:17:54 -04:00
if ( gSynthesisReverb . useReverb & & note - > reverbVol ! = 0 ) {
2019-11-03 14:36:27 -05:00
aEnvMixer ( cmd + + , mixerFlags | A_AUX ,
VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > mixEnvelopeState ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
if ( note - > stereoStrongRight ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
// 0x8000 is -100%, so subtract sound instead of adding...
2021-12-30 10:57:51 -06:00
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY , /*out*/ DMEM_ADDR_LEFT_CH ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET , /*out*/ DMEM_ADDR_WET_LEFT_CH ) ;
2019-08-25 00:46:40 -04:00
} else if ( note - > stereoStrongLeft ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
2021-12-30 10:57:51 -06:00
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY , /*out*/ DMEM_ADDR_RIGHT_CH ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET , /*out*/ DMEM_ADDR_WET_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
}
} else {
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
aEnvMixer ( cmd + + , mixerFlags , VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > mixEnvelopeState ) ) ;
# else
2019-11-03 14:36:27 -05:00
aEnvMixer ( cmd + + , mixerFlags , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > mixEnvelopeState ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
if ( note - > stereoStrongRight ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY ,
/*out*/ DMEM_ADDR_LEFT_CH ) ;
2019-08-25 00:46:40 -04:00
} else if ( note - > stereoStrongLeft ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY ,
/*out*/ DMEM_ADDR_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
}
}
return cmd ;
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * note_apply_headset_pan_effects ( u64 * cmd , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * note , s32 bufLen , s32 flags , s32 leftRight ) {
# else
2019-11-03 14:36:27 -05:00
u64 * note_apply_headset_pan_effects ( u64 * cmd , struct Note * note , s32 bufLen , s32 flags , s32 leftRight ) {
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
u16 dest ;
2020-12-03 14:26:38 -05:00
u16 pitch ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-03-01 22:42:52 -05:00
u8 prevPanShift ;
u8 panShift ;
UNUSED u8 unkDebug ;
2021-07-12 23:17:54 -04:00
# else
u16 prevPanShift ;
u16 panShift ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
switch ( leftRight ) {
case 1 :
2019-11-03 14:36:27 -05:00
dest = DMEM_ADDR_LEFT_CH ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
panShift = noteSubEu - > headsetPanRight ;
2021-07-12 23:17:54 -04:00
# else
panShift = note - > headsetPanRight ;
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
note - > prevHeadsetPanLeft = 0 ;
2019-11-03 14:36:27 -05:00
prevPanShift = note - > prevHeadsetPanRight ;
note - > prevHeadsetPanRight = panShift ;
2019-08-25 00:46:40 -04:00
break ;
case 2 :
2019-11-03 14:36:27 -05:00
dest = DMEM_ADDR_RIGHT_CH ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
panShift = noteSubEu - > headsetPanLeft ;
2021-07-12 23:17:54 -04:00
# else
panShift = note - > headsetPanLeft ;
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
note - > prevHeadsetPanRight = 0 ;
2020-02-03 00:51:26 -05:00
2019-11-03 14:36:27 -05:00
prevPanShift = note - > prevHeadsetPanLeft ;
note - > prevHeadsetPanLeft = panShift ;
2019-08-25 00:46:40 -04:00
break ;
default :
return cmd ;
}
2021-07-12 23:17:54 -04:00
if ( flags ! = 1 ) { // A_INIT?
2019-11-03 14:36:27 -05:00
// Slightly adjust the sample rate in order to fit a change in pan shift
if ( prevPanShift = = 0 ) {
// Kind of a hack that moves the first samples into the resample state
aDMEMMove ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP , 8 ) ;
aClearBuffer ( cmd + + , 8 , 8 ) ; // Set pitch accumulator to 0 in the resample state
aDMEMMove ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP + 0x10 ,
0x10 ) ; // No idea, result seems to be overwritten later
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , 32 ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panResampleState ) ) ;
2020-03-01 22:42:52 -05:00
pitch = ( bufLen < < 0xf ) / ( bufLen + panShift - prevPanShift + 8 ) ;
2020-04-03 14:57:26 -04:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_NOTE_PAN_TEMP + 8 , DMEM_ADDR_TEMP , panShift + bufLen - prevPanShift ) ;
2019-11-03 14:36:27 -05:00
aResample ( cmd + + , 0 , pitch , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panResampleState ) ) ;
2019-08-25 00:46:40 -04:00
} else {
2020-04-03 14:57:26 -04:00
if ( panShift = = 0 ) {
pitch = ( bufLen < < 0xf ) / ( bufLen - prevPanShift - 4 ) ;
} else {
pitch = ( bufLen < < 0xf ) / ( bufLen + panShift - prevPanShift ) ;
}
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP , panShift + bufLen - prevPanShift ) ;
2019-11-03 14:36:27 -05:00
aResample ( cmd + + , 0 , pitch , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panResampleState ) ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
if ( prevPanShift ! = 0 ) {
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_NOTE_PAN_TEMP , 0 , prevPanShift ) ;
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panSamplesBuffer ) ) ;
2020-04-03 14:57:26 -04:00
aDMEMMove ( cmd + + , DMEM_ADDR_TEMP , DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift , panShift + bufLen - prevPanShift ) ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
aDMEMMove ( cmd + + , DMEM_ADDR_TEMP , DMEM_ADDR_NOTE_PAN_TEMP , panShift + bufLen - prevPanShift ) ;
2019-08-25 00:46:40 -04:00
}
} else {
2019-11-03 14:36:27 -05:00
// Just shift right
aDMEMMove ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP , bufLen ) ;
aDMEMMove ( cmd + + , DMEM_ADDR_TEMP , DMEM_ADDR_NOTE_PAN_TEMP + panShift , bufLen ) ;
aClearBuffer ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , panShift ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
if ( panShift ) {
// Save excessive samples for next iteration
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_NOTE_PAN_TEMP + bufLen , panShift ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panSamplesBuffer ) ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , bufLen ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x7fff , /*in*/ DMEM_ADDR_NOTE_PAN_TEMP , /*out*/ dest ) ;
2019-08-25 00:46:40 -04:00
return cmd ;
}
2020-02-03 00:51:26 -05:00
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2020-02-03 00:51:26 -05:00
// Moved to playback.c in EU
2019-08-25 00:46:40 -04:00
void note_init_volume ( struct Note * note ) {
note - > targetVolLeft = 0 ;
note - > targetVolRight = 0 ;
note - > reverbVol = 0 ;
2021-07-12 23:17:54 -04:00
note - > reverbVolShifted = 0 ;
2019-08-25 00:46:40 -04:00
note - > unused2 = 0 ;
note - > curVolLeft = 1 ;
note - > curVolRight = 1 ;
note - > frequency = 0.0f ;
}
2021-07-12 23:17:54 -04:00
void note_set_vel_pan_reverb ( struct Note * note , f32 velocity , f32 pan , u8 reverbVol ) {
2021-12-30 10:57:51 -06:00
f32 volLeft , volRight ;
s32 panIndex = ( s32 ) ( pan * 127.5f ) & 127 ;
2019-08-25 00:46:40 -04:00
if ( note - > stereoHeadsetEffects & & gSoundMode = = SOUND_MODE_HEADSET ) {
s8 smallPanIndex ;
2020-04-03 14:57:26 -04:00
s8 temp = ( s8 ) ( pan * 10.0f ) ;
if ( temp < 9 ) {
smallPanIndex = temp ;
} else {
smallPanIndex = 9 ;
}
2019-08-25 00:46:40 -04:00
note - > headsetPanLeft = gHeadsetPanQuantization [ smallPanIndex ] ;
note - > headsetPanRight = gHeadsetPanQuantization [ 9 - smallPanIndex ] ;
note - > stereoStrongRight = FALSE ;
note - > stereoStrongLeft = FALSE ;
2019-11-03 14:36:27 -05:00
note - > usesHeadsetPanEffects = TRUE ;
2019-08-25 00:46:40 -04:00
volLeft = gHeadsetPanVolume [ panIndex ] ;
volRight = gHeadsetPanVolume [ 127 - panIndex ] ;
} else if ( note - > stereoHeadsetEffects & & gSoundMode = = SOUND_MODE_STEREO ) {
2021-12-30 10:57:51 -06:00
u8 strongLeft = FALSE ;
u8 strongRight = FALSE ;
2019-08-25 00:46:40 -04:00
note - > headsetPanLeft = 0 ;
note - > headsetPanRight = 0 ;
2019-11-03 14:36:27 -05:00
note - > usesHeadsetPanEffects = FALSE ;
2019-08-25 00:46:40 -04:00
volLeft = gStereoPanVolume [ panIndex ] ;
volRight = gStereoPanVolume [ 127 - panIndex ] ;
if ( panIndex < 0x20 ) {
strongLeft = TRUE ;
} else if ( panIndex > 0x60 ) {
strongRight = TRUE ;
}
note - > stereoStrongRight = strongRight ;
note - > stereoStrongLeft = strongLeft ;
} else if ( gSoundMode = = SOUND_MODE_MONO ) {
2021-12-30 10:57:51 -06:00
volLeft = 0.707f ;
volRight = 0.707f ;
2019-08-25 00:46:40 -04:00
} else {
volLeft = gDefaultPanVolume [ panIndex ] ;
volRight = gDefaultPanVolume [ 127 - panIndex ] ;
}
2020-04-03 14:57:26 -04:00
if ( velocity < 0 ) {
velocity = 0 ;
}
2019-08-25 00:46:40 -04:00
note - > targetVolLeft = ( u16 ) ( s32 ) ( velocity * volLeft ) & ~ 0x80FF ;
note - > targetVolRight = ( u16 ) ( s32 ) ( velocity * volRight ) & ~ 0x80FF ;
if ( note - > targetVolLeft = = 0 ) {
note - > targetVolLeft + + ;
}
if ( note - > targetVolRight = = 0 ) {
note - > targetVolRight + + ;
}
2021-07-12 23:17:54 -04:00
if ( note - > reverbVol ! = reverbVol ) {
note - > reverbVol = reverbVol ;
note - > reverbVolShifted = reverbVol < < 8 ;
2019-11-03 14:36:27 -05:00
note - > envMixerNeedsInit = TRUE ;
2019-08-25 00:46:40 -04:00
return ;
}
2021-12-30 10:57:51 -06:00
note - > envMixerNeedsInit = note - > needsInit ;
2019-08-25 00:46:40 -04:00
}
void note_set_frequency ( struct Note * note , f32 frequency ) {
note - > frequency = frequency ;
}
void note_enable ( struct Note * note ) {
note - > enabled = TRUE ;
2019-11-03 14:36:27 -05:00
note - > needsInit = TRUE ;
note - > restart = FALSE ;
note - > finished = FALSE ;
2019-08-25 00:46:40 -04:00
note - > stereoStrongRight = FALSE ;
note - > stereoStrongLeft = FALSE ;
2019-11-03 14:36:27 -05:00
note - > usesHeadsetPanEffects = FALSE ;
2019-08-25 00:46:40 -04:00
note - > headsetPanLeft = 0 ;
note - > headsetPanRight = 0 ;
note - > prevHeadsetPanRight = 0 ;
note - > prevHeadsetPanLeft = 0 ;
}
void note_disable ( struct Note * note ) {
2021-12-30 10:57:51 -06:00
if ( note - > needsInit ) {
2019-11-03 14:36:27 -05:00
note - > needsInit = FALSE ;
2019-08-25 00:46:40 -04:00
} else {
2021-12-30 10:57:51 -06:00
note_set_vel_pan_reverb ( note , 0 , 0.5f , 0 ) ;
2019-08-25 00:46:40 -04:00
}
note - > priority = NOTE_PRIORITY_DISABLED ;
note - > enabled = FALSE ;
2019-11-03 14:36:27 -05:00
note - > finished = FALSE ;
2019-08-25 00:46:40 -04:00
note - > parentLayer = NO_LAYER ;
note - > prevParentLayer = NO_LAYER ;
}
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# endif