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"
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-08-04 03:17:51 -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 .
*
* 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-08-03 02:55:48 -05:00
2021-08-04 01:03:07 -05:00
s32 gReverbRevIndex = 0x7F ; // Affects decay time mostly; can be messed with at any time (and also probably the most useful parameter here)
2021-08-04 03:17:51 -05:00
s32 gReverbGainIndex = 0xA3 ; // Affects signal immediately retransmitted back into buffers; can be messed with at any time
s32 gReverbWetSignal = 0xEF ; // Amount of reverb specific output in final signal; can be messed with at any time
2021-08-04 01:03:07 -05:00
s32 gReverbDrySignal = 0x00 ; // Amount of original input in final signal (large values can cause terrible feedback!); can be messed with at any time
2021-08-02 21:14:31 -05:00
2021-08-04 05:38:16 -05:00
// This value controls the size of the reverb buffer. It affects the global reverb delay time. This is probably the easiest parameter to control usefully.
// 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).
// Setting the value lower than the downsample buffer size will destroy the game audio, so this is taken into account automatically but may limit the lower possibilities.
// 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-08-04 03:17:51 -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/4.
// If setting a reverb downsample value to 1, this must be smaller than BETTER_REVERB_SIZE/8.
// 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-03 22:30:11 -05:00
s32 delays [ NUM_ALLPASS ] = {
2021-08-03 01:45:33 -05:00
1080 , 1352 , 1200 ,
1384 , 1048 , 1352 ,
1200 , 1232 , 1432 ,
928 , 1504 , 1512
} ;
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.
// Similarly to delays, these should be kept within the memory constraints defined by BETTER_REVERB_SIZE.
const s32 delaysBaseline [ NUM_ALLPASS ] = {
2021-08-03 01:45:33 -05:00
1080 , 1352 , 1200 ,
1384 , 1048 , 1352 ,
1200 , 1232 , 1432 ,
928 , 1504 , 1512
2021-08-02 21:14:31 -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
const s32 reverbMults [ 2 ] [ NUM_ALLPASS / 3 ] = {
{ 0xD2 , 0x6E , 0x36 , 0x1F } , // Left Channel
{ 0x38 , 0x26 , 0xCF , 0x71 } // Right Channel
2021-08-02 21:14:31 -05:00
} ;
2021-08-04 03:17:51 -05:00
2021-08-04 05:38:16 -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.
2021-08-04 03:17:51 -05:00
// You can change this value before audio_reset_session gets called if different levels can tolerate the demand better than others or just have different reverb goals.
// A higher downsample value hits the game's frequency limit sooner, which can cause the reverb sometimes to be off pitch. This is a vanilla level issue (and also counter intuitive).
// Higher downsample values also result in slightly shorter reverb decay times.
s8 betterReverbConsoleDownsample = 3 ;
// 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.
s8 betterReverbEmulatorDownsample = 2 ;
/* --------------------------------------------------------END REVERB PARAMETERS--------------------------------------------------------------- */
// Do not touch these values.
u8 toggleBetterReverb = TRUE ;
2021-08-03 22:30:11 -05:00
s32 allpassIdx [ 2 ] [ NUM_ALLPASS ] = {
2021-08-02 21:14:31 -05:00
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 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-02 21:14:31 -05:00
s32 * * * delayBufs ;
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-08-03 00:58:22 -05:00
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-03 22:30:11 -05:00
inline void reverb_samples ( s16 * outSampleL , s16 * outSampleR , s32 inSampleL , s32 inSampleR ) {
u32 i = 0 ;
s32 j = 0 ;
u8 k = 0 ;
s32 outTmpL = 0 ;
s32 outTmpR = 0 ;
s32 tmpCarryoverL = ( ( tmpBufL [ NUM_ALLPASS - 1 ] * gReverbRevIndex ) / 256 ) + inSampleL ; // Unique to left channel
s32 tmpCarryoverR = ( ( tmpBufR [ NUM_ALLPASS - 1 ] * gReverbRevIndex ) / 256 ) ;
for ( ; i < NUM_ALLPASS ; + + i , + + j ) {
tmpBufL [ i ] = delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ i ] ] ;
tmpBufR [ i ] = delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] ;
if ( j = = 2 ) {
j = - 1 ;
outTmpL + = ( tmpBufL [ i ] * reverbMults [ 0 ] [ k ] ) / 256 ;
outTmpR + = ( tmpBufR [ i ] * reverbMults [ 1 ] [ k + + ] ) / 256 ;
delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ i ] ] = tmpCarryoverL ;
delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] = tmpCarryoverR ;
if ( i ! = NUM_ALLPASS - 1 ) {
tmpCarryoverL = ( tmpBufL [ i ] * gReverbRevIndex ) / 256 ;
tmpCarryoverR = ( tmpBufR [ i ] * gReverbRevIndex ) / 256 ;
}
}
else {
delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ i ] ] = ( tmpBufL [ i ] * ( - gReverbGainIndex ) ) / 256 + tmpCarryoverL ;
delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] = ( tmpBufR [ i ] * ( - gReverbGainIndex ) ) / 256 + tmpCarryoverR ;
if ( i = = 6 )
delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] + = inSampleR ; // Unique to right channel
tmpCarryoverL = ( delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ i ] ] * gReverbGainIndex ) / 256 + tmpBufL [ i ] ;
tmpCarryoverR = ( delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] * gReverbGainIndex ) / 256 + tmpBufR [ i ] ;
}
if ( + + allpassIdx [ 0 ] [ i ] = = delays [ i ] ) {
allpassIdx [ 0 ] [ i ] = 0 ;
allpassIdx [ 1 ] [ i ] = - 1 ; // To avoid an else branch
}
+ + allpassIdx [ 1 ] [ i ] ;
}
* outSampleL = clamp16 ( ( outTmpL * gReverbWetSignal + inSampleL * gReverbDrySignal ) / 256 ) ;
* outSampleR = clamp16 ( ( outTmpR * gReverbWetSignal + inSampleR * gReverbDrySignal ) / 256 ) ;
}
2021-08-03 02:12:10 -05:00
inline s16 reverb_sample_left ( s32 inSample ) {
2021-08-02 21:14:31 -05:00
u32 i = 0 ;
2021-08-03 06:52:21 -05:00
s32 j = 0 ;
u8 k = 0 ;
2021-08-02 21:14:31 -05:00
s32 outTmp = 0 ;
2021-08-03 22:30:11 -05:00
s32 tmpCarryover = ( ( tmpBufL [ NUM_ALLPASS - 1 ] * gReverbRevIndex ) / 256 ) + inSample ;
2021-08-02 21:14:31 -05:00
2021-08-03 21:29:06 -05:00
for ( ; i < NUM_ALLPASS ; + + i , + + j ) {
2021-08-03 22:30:11 -05:00
tmpBufL [ i ] = delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ 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-03 22:30:11 -05:00
outTmp + = ( tmpBufL [ i ] * reverbMults [ 0 ] [ k + + ] ) / 256 ;
2021-08-02 21:14:31 -05:00
delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ i ] ] = tmpCarryover ;
if ( i ! = NUM_ALLPASS - 1 )
2021-08-03 22:30:11 -05:00
tmpCarryover = ( tmpBufL [ i ] * gReverbRevIndex ) / 256 ;
2021-08-02 21:14:31 -05:00
}
else {
2021-08-03 22:30:11 -05:00
delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ i ] ] = ( tmpBufL [ i ] * ( - gReverbGainIndex ) ) / 256 + tmpCarryover ;
tmpCarryover = ( delayBufs [ 0 ] [ i ] [ allpassIdx [ 0 ] [ i ] ] * gReverbGainIndex ) / 256 + tmpBufL [ i ] ;
2021-08-02 21:14:31 -05:00
}
if ( + + allpassIdx [ 0 ] [ i ] = = delays [ i ] )
allpassIdx [ 0 ] [ i ] = 0 ;
}
2021-08-03 02:12:10 -05:00
return clamp16 ( ( outTmp * gReverbWetSignal + inSample * gReverbDrySignal ) / 256 ) ;
2021-08-02 21:14:31 -05:00
}
2021-08-03 02:12:10 -05:00
inline s16 reverb_sample_right ( s32 inSample ) {
2021-08-02 21:14:31 -05:00
u32 i = 0 ;
2021-08-03 06:52:21 -05:00
s32 j = 0 ;
u8 k = 0 ;
2021-08-02 21:14:31 -05:00
s32 outTmp = 0 ;
2021-08-03 22:30:11 -05:00
s32 tmpCarryover = ( ( tmpBufR [ NUM_ALLPASS - 1 ] * gReverbRevIndex ) / 256 ) ;
2021-08-02 21:14:31 -05:00
2021-08-03 21:29:06 -05:00
for ( ; i < NUM_ALLPASS ; + + i , + + j ) {
2021-08-03 22:30:11 -05:00
tmpBufR [ i ] = delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ 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-03 22:30:11 -05:00
outTmp + = ( tmpBufR [ i ] * reverbMults [ 1 ] [ k + + ] ) / 256 ;
2021-08-02 21:14:31 -05:00
delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] = tmpCarryover ;
if ( i ! = NUM_ALLPASS - 1 )
2021-08-03 22:30:11 -05:00
tmpCarryover = ( tmpBufR [ i ] * gReverbRevIndex ) / 256 ;
2021-08-02 21:14:31 -05:00
}
else {
2021-08-03 22:30:11 -05:00
delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] = ( tmpBufR [ i ] * ( - gReverbGainIndex ) ) / 256 + tmpCarryover ;
2021-08-02 21:14:31 -05:00
2021-08-03 06:52:21 -05:00
if ( i = = 6 )
2021-08-02 21:14:31 -05:00
delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] + = inSample ;
2021-08-03 22:30:11 -05:00
tmpCarryover = ( delayBufs [ 1 ] [ i ] [ allpassIdx [ 1 ] [ i ] ] * gReverbGainIndex ) / 256 + tmpBufR [ i ] ;
2021-08-02 21:14:31 -05:00
}
if ( + + allpassIdx [ 1 ] [ i ] = = delays [ i ] )
allpassIdx [ 1 ] [ i ] = 0 ;
}
2021-08-03 02:12:10 -05:00
return clamp16 ( ( outTmp * gReverbWetSignal + inSample * gReverbDrySignal ) / 256 ) ;
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 01:03:07 -05:00
if ( gSoundMode = = SOUND_MODE_MONO ) {
if ( gReverbDownsampleRate ! = 1 ) {
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
for ( srcPos = 0 , dstPos = item - > startPos ; dstPos < item - > lengthA / 2 + item - > startPos ; srcPos + = gReverbDownsampleRate , dstPos + + ) {
gSynthesisReverb . ringBuffer . left [ dstPos ] = reverb_sample_left ( ( ( s32 ) item - > toDownsampleLeft [ srcPos ] + ( s32 ) item - > toDownsampleRight [ srcPos ] ) / 2 ) ;
gSynthesisReverb . ringBuffer . right [ dstPos ] = gSynthesisReverb . ringBuffer . left [ dstPos ] ;
}
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; srcPos + = gReverbDownsampleRate , dstPos + + ) {
gSynthesisReverb . ringBuffer . left [ dstPos ] = reverb_sample_left ( ( ( s32 ) item - > toDownsampleLeft [ srcPos ] + ( s32 ) item - > toDownsampleRight [ srcPos ] ) / 2 ) ;
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 + + ) {
gSynthesisReverb . ringBuffer . left [ dstPos ] = reverb_sample_left ( ( ( s32 ) gSynthesisReverb . ringBuffer . left [ dstPos ] + ( s32 ) gSynthesisReverb . ringBuffer . right [ dstPos ] ) / 2 ) ;
gSynthesisReverb . ringBuffer . right [ dstPos ] = gSynthesisReverb . ringBuffer . left [ dstPos ] ;
}
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; dstPos + + ) {
gSynthesisReverb . ringBuffer . left [ dstPos ] = reverb_sample_left ( ( ( s32 ) gSynthesisReverb . ringBuffer . left [ dstPos ] + ( s32 ) gSynthesisReverb . ringBuffer . right [ dstPos ] ) / 2 ) ;
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 ] ) ;
// for (srcPos = 0, dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos;
// srcPos += gReverbDownsampleRate, dstPos++) {
// gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(item->toDownsampleLeft[srcPos]);
// gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(item->toDownsampleRight[srcPos]);
// }
// for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) {
// gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(item->toDownsampleLeft[srcPos]);
// gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(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 ] ) ;
// for (dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos; dstPos++) {
// gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(gSynthesisReverb.ringBuffer.left[dstPos]);
// gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(gSynthesisReverb.ringBuffer.right[dstPos]);
// }
// for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) {
// gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(gSynthesisReverb.ringBuffer.left[dstPos]);
// gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(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
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
UNUSED s32 pad1 [ 1 ] ;
s16 ra ;
s16 t4 ;
UNUSED s32 pad [ 2 ] ;
2019-11-03 14:36:27 -05:00
struct ReverbRingBufferItem * v1 ;
2020-04-03 14:57:26 -04:00
UNUSED s32 pad2 [ 1 ] ;
s16 temp ;
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 ) ;
2020-04-03 14:57:26 -04:00
temp = 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
2020-04-03 14:57:26 -04:00
temp = 0 ; //! jesus christ
2019-11-03 14:36:27 -05:00
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 ) ;
2020-04-03 14:57:26 -04:00
//! We need an empty statement (even an empty ';') here to make the function match (because IDO).
//! However, copt removes extraneous statements and dead code. So we need to trick copt
//! into thinking 'temp' could be undefined, and luckily the compiler optimizes out the
//! useless assignment.
ra = ra + temp ;
2019-08-25 00:46:40 -04:00
}
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 ) ;
}
2020-03-01 22:42:52 -05:00
# if defined(VERSION_EU) && !defined(AVOID_UB)
if ( unkDebug ) { // UB
}
# endif
2020-04-03 14:57:26 -04:00
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