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"
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 ) ; \
2020-04-03 14:57:26 -04: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
2021-09-01 14:12:03 -07:00
# if defined(BETTER_REVERB) && (defined(VERSION_US) || defined(VERSION_JP))
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-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.
// Using a value of 1 is not recommended except in very specific situations. If you do decide to use 1 here, you must adjust BETTER_REVERB_SIZE appropriately.
// 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.
2021-08-05 00:02:00 -05:00
// This can be changed at any time, but is best set when calling audio_reset_session.
2021-09-01 15:03:08 -07: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.
2021-08-05 00:02:00 -05:00
// This can be changed at any time, but is best set when calling audio_reset_session.
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.
2021-08-04 18:15:38 -05:00
// This can be changed at any time, but is best set when 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.
2021-08-05 00:02:00 -05:00
// This can be changed at any time, but is best set when calling audio_reset_session.
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.
2021-08-04 05:38:16 -05:00
// It is not recommended setting this to values greater than 0x1000 * 2^(downsample factor - 1), as you run the risk of running into a memory issue (though this is far from a guarantee).
2021-08-04 17:01:30 -05:00
// 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.
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.
# define REVERB_REV_INDEX 0x60 // Affects decay time mostly (large values can cause terrible feedback!); can be messed with at any time
# 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.
2021-08-04 03:17:51 -05:00
// These values should never be changed unless in this declaration or during a call to audio_reset_session, as it could otherwise lead to a major memory leak or garbage audio.
// None of the delay values should ever be smaller than 1 either; these are s32s purely to avoid typecasts.
// These values are currently set by using delaysBaseline in the audio_reset_session function, so its behavior must be overridden to use dynamically (or at all).
2021-08-05 01:14:01 -05:00
s32 delaysL [ 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-08-03 01:45:33 -05:00
928 , 1504 , 1512
} ;
2021-08-05 01:14:01 -05:00
s32 delaysR [ NUM_ALLPASS ] = {
2021-08-05 02:17:01 -05:00
1384 , 1352 , 1048 ,
928 , 1512 , 1504 ,
1080 , 1200 , 1352 ,
1200 , 1432 , 1232
2021-08-05 01:14:01 -05:00
} ;
2021-08-04 03:17:51 -05:00
// Like the delays array, but represents default max values that don't change (also probably somewhat redundant)
// Change this array rather than the delays array to customize reverb delay times globally.
2021-08-05 01:19:55 -05:00
// Similarly to delaysL/R, these should be kept within the memory constraints defined by BETTER_REVERB_SIZE.
2021-08-05 01:14:01 -05:00
const 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-08-03 01:45:33 -05:00
928 , 1504 , 1512
2021-08-02 21:14:31 -05:00
} ;
2021-08-05 01:14:01 -05:00
const s32 delaysBaselineR [ NUM_ALLPASS ] = {
2021-08-05 02:17:01 -05:00
1384 , 1352 , 1048 ,
2021-08-05 01:14:01 -05:00
928 , 1512 , 1504 ,
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-09-12 00:59:36 -04: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 ;
2021-08-05 01:14:01 -05:00
s32 allpassIdxL [ NUM_ALLPASS ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
s32 allpassIdxR [ NUM_ALLPASS ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2021-08-03 22:30:11 -05:00
s32 tmpBufL [ NUM_ALLPASS ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
s32 tmpBufR [ NUM_ALLPASS ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 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
2021-09-01 14:12:03 -07:00
# if defined(BETTER_REVERB) && (defined(VERSION_US) || defined(VERSION_JP))
2021-08-05 01:43:25 -05:00
static inline s16 clamp16 ( s32 x ) {
2021-08-02 21:14:31 -05:00
if ( x > = 32767 )
return 32767 ;
if ( x < = - 32768 )
return - 32768 ;
return ( s16 ) x ;
}
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-09-12 00:59:36 -04: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-08-05 00:02:00 -05: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-09-12 00:59:36 -04:00
tmpCarryoverL = ( tmpBufL [ i ] * REVERB_REV_INDEX ) / 256 ;
tmpCarryoverR = ( tmpBufR [ i ] * REVERB_REV_INDEX ) / 256 ;
2021-08-03 22:30:11 -05:00
}
}
else {
2021-09-12 00:59:36 -04:00
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-08-05 01:14:01 -05: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-09-12 00:59:36 -04:00
* outSampleL = clamp16 ( ( outTmpL * REVERB_WET_SIGNAL /* + inSampleL * REVERB_DRY_SIGNAL*/ ) / 256 ) ;
* outSampleR = clamp16 ( ( outTmpR * REVERB_WET_SIGNAL /* + inSampleR * REVERB_DRY_SIGNAL*/ ) / 256 ) ;
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-09-12 00:59:36 -04: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-08-05 00:02:00 -05:00
outTmp + = ( tmpBufL [ i ] * reverbMultsL [ k + + ] ) / 256 ;
2021-08-05 01:14:01 -05:00
delayBufsL [ i ] [ allpassIdxL [ i ] ] = tmpCarryover ;
if ( i ! = reverbFilterCountm1 )
2021-09-12 00:59:36 -04:00
tmpCarryover = ( tmpBufL [ i ] * REVERB_REV_INDEX ) / 256 ;
2021-08-02 21:14:31 -05:00
}
else {
2021-09-12 00:59:36 -04:00
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-09-12 00:59:36 -04:00
* outSample = clamp16 ( ( outTmp * REVERB_WET_SIGNAL /* + inSample * REVERB_DRY_SIGNAL*/ ) / 256 ) ;
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 ] ;
2020-02-03 00:51:26 -05:00
s32 srcPos ;
s32 dstPos ;
s32 nSamples ;
s32 excessiveSamples ;
2020-03-01 22:42:52 -05:00
s32 UNUSED pad [ 3 ] ;
2020-02-03 00:51:26 -05:00
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 + + ) {
2020-03-01 22:42:52 -05:00
reverb - > ringBuffer . left [ item - > startPos + dstPos ] =
2020-02-03 00:51:26 -05:00
item - > toDownsampleLeft [ srcPos ] ;
2020-03-01 22:42:52 -05:00
reverb - > ringBuffer . right [ item - > startPos + dstPos ] =
2020-02-03 00:51:26 -05:00
item - > toDownsampleRight [ srcPos ] ;
}
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 ;
s32 srcPos ;
s32 dstPos ;
s32 nSamples ;
s32 numSamplesAfterDownsampling ;
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 + + ) {
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 ) ;
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 ] ;
}
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 ] ;
}
}
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 ] ;
}
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-08-02 21:14:31 -05:00
}
2021-08-04 01:03:07 -05:00
else {
if ( gReverbDownsampleRate ! = 1 ) {
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
for ( srcPos = 0 , dstPos = item - > startPos ; dstPos < item - > lengthA / 2 + item - > startPos ; srcPos + = gReverbDownsampleRate , dstPos + + )
reverb_samples ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , & gSynthesisReverb . ringBuffer . right [ dstPos ] , item - > toDownsampleLeft [ srcPos ] , item - > toDownsampleRight [ srcPos ] ) ;
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; srcPos + = gReverbDownsampleRate , dstPos + + )
reverb_samples ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , & gSynthesisReverb . ringBuffer . right [ dstPos ] , item - > toDownsampleLeft [ srcPos ] , item - > toDownsampleRight [ srcPos ] ) ;
}
else { // Too slow for practical use, not recommended most of the time.
for ( dstPos = item - > startPos ; dstPos < item - > lengthA / 2 + item - > startPos ; dstPos + + )
reverb_samples ( & gSynthesisReverb . ringBuffer . left [ dstPos ] , & gSynthesisReverb . ringBuffer . right [ dstPos ] , gSynthesisReverb . ringBuffer . left [ dstPos ] , gSynthesisReverb . ringBuffer . right [ dstPos ] ) ;
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; dstPos + + )
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 ] ;
2020-04-03 14:57:26 -04:00
numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate ;
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 ) {
2021-07-12 23:17:54 -04:00
# pragma GCC diagnostic push
# if defined(__clang__)
# pragma GCC diagnostic ignored "-Wself-assign"
# endif
2020-03-01 22:42:52 -05:00
// self-assignment has no affect when added here, could possibly simplify a macro definition
chunkLen = bufLen ; nextVolRampTable = nextVolRampTable ; leftVolRamp = gLeftVolRampings [ nextVolRampTable ] ; rightVolRamp = gRightVolRampings [ nextVolRampTable & 0xFFFFFFFF ] ;
2021-07-12 23:17:54 -04:00
# pragma GCC diagnostic pop
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 ;
}
else {
2021-09-12 00:59:36 -04:00
reverbFilterCount = ( s32 ) reverbFilterCountEmulator ;
2021-08-05 00:02:00 -05:00
monoReverb = monoReverbEmulator ;
}
2021-08-05 01:14:01 -05:00
if ( reverbFilterCount > NUM_ALLPASS )
reverbFilterCount = NUM_ALLPASS ;
reverbFilterCountm1 = reverbFilterCount - 1 ;
if ( reverbFilterCount < 3 )
reverbFilterCountm1 = 0 ;
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 {
2020-07-04 11:18:55 -04:00
startPad = ( item - > startPos % 8u ) * 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 ;
2020-03-01 22:42:52 -05:00
if ( IS_BANK_LOAD_COMPLETE ( gNoteSubsEu [ temp + noteIndices [ i ] ] . bankId ) = = TRUE ) {
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-04-03 14:57:26 -04:00
UNUSED s32 pad0 [ 3 ] ;
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
UNUSED u8 pad0 [ 0x08 ] ;
# endif
struct AudioBankSample * audioBookSample ; // sp164, sp138
struct AdpcmLoop * loopInfo ; // sp160, sp134
s16 * curLoadedBook = NULL ; // sp154, sp130
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
UNUSED u8 padEU [ 0x04 ] ;
# endif
UNUSED u8 pad8 [ 0x04 ] ;
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 u8 pad7 [ 0x0c ] ; // sp100
UNUSED s32 tempBufLen ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2021-07-18 04:57:37 -05:00
s32 sp130 = 0 ; //sp128, sp104
2020-04-03 14:57:26 -04:00
UNUSED u32 pad9 ;
# else
UNUSED u32 pad9 ;
2021-07-18 04:57:37 -05:00
s32 sp130 = 0 ; //sp128, sp104
2020-04-03 14:57:26 -04:00
# endif
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.
if ( ( ( struct vNote * ) note ) - > enabled & & IS_BANK_LOAD_COMPLETE ( note - > bankId ) = = FALSE ) {
# else
2019-11-03 14:36:27 -05:00
if ( IS_BANK_LOAD_COMPLETE ( note - > bankId ) = = FALSE ) {
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
2019-11-03 14:36:27 -05:00
if ( note - > frequency < US_FLOAT ( 2.0 ) ) {
nParts = 1 ;
if ( note - > frequency > US_FLOAT ( 1.99996 ) ) {
note - > frequency = US_FLOAT ( 1.99996 ) ;
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 ;
if ( note - > frequency > = US_FLOAT ( 3.99993 ) ) {
note - > frequency = US_FLOAT ( 3.99993 ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
resamplingRate = note - > frequency * US_FLOAT ( .5 ) ;
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
2019-11-03 14:36:27 -05: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
UNUSED u8 pad [ 16 ] ;
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
UNUSED u8 pad [ 3 ] ;
u8 mixerFlags ;
UNUSED u8 pad2 [ 8 ] ;
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
UNUSED u8 pad1 [ 20 ] ;
u16 sourceRight ;
u16 sourceLeft ;
UNUSED u8 pad2 [ 4 ] ;
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...
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 ) ;
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 ) ) ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-03-01 22:42:52 -05:00
pitch = ( bufLen < < 0xf ) / ( bufLen + panShift - prevPanShift + 8 ) ;
if ( pitch ) {
}
# else
2019-11-03 14:36:27 -05:00
pitch = ( bufLen < < 0xf ) / ( panShift + bufLen - prevPanShift + 8 ) ;
2020-03-01 22:42:52 -05:00
# endif
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 ) {
2019-08-25 00:46:40 -04:00
s32 panIndex ;
f32 volLeft ;
f32 volRight ;
2021-07-12 23:17:54 -04:00
// Anding with 127 avoids out-of-bounds reads when pan is outside of [0, 1].
// This can occur during PU movement -- see the bug comment in get_sound_pan
// in external.c. An out-of-bounds read by itself doesn't crash, but if the
// resulting value is a nan or denormal, performing arithmetic on it crashes
// on console.
2019-08-25 00:46:40 -04:00
# ifdef VERSION_JP
panIndex = MIN ( ( s32 ) ( pan * 127.5 ) , 127 ) ;
# else
panIndex = ( s32 ) ( pan * 127.5f ) & 127 ;
# endif
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 ) {
2020-04-03 14:57:26 -04:00
u8 strongLeft ;
u8 strongRight ;
strongLeft = FALSE ;
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 ) {
volLeft = .707f ;
volRight = .707f ;
} 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
# ifdef VERSION_JP
note - > targetVolLeft = ( u16 ) ( velocity * volLeft ) & ~ 0x80FF ; // 0x7F00, but that doesn't match
note - > targetVolRight = ( u16 ) ( velocity * volRight ) & ~ 0x80FF ;
# else
note - > targetVolLeft = ( u16 ) ( s32 ) ( velocity * volLeft ) & ~ 0x80FF ;
note - > targetVolRight = ( u16 ) ( s32 ) ( velocity * volRight ) & ~ 0x80FF ;
# endif
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 ;
}
2019-11-03 14:36:27 -05:00
if ( note - > needsInit ) {
note - > envMixerNeedsInit = TRUE ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
note - > envMixerNeedsInit = FALSE ;
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 ) {
2019-11-03 14:36:27 -05:00
if ( note - > needsInit = = TRUE ) {
note - > needsInit = FALSE ;
2019-08-25 00:46:40 -04:00
} else {
note_set_vel_pan_reverb ( note , 0 , .5 , 0 ) ;
}
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