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"
2023-01-24 09:22:49 -05:00
# include "game/debug.h"
2021-12-30 10:57:51 -06:00
# include "engine/math_util.h"
2019-08-25 00:46:40 -04:00
2020-02-03 00:51:26 -05:00
2019-11-03 14:36:27 -05:00
# define DMEM_ADDR_TEMP 0x0
2020-07-04 11:18:55 -04:00
# define DMEM_ADDR_RESAMPLED 0x20
# define DMEM_ADDR_RESAMPLED2 0x160
2020-12-03 14:26:38 -05:00
# define DMEM_ADDR_UNCOMPRESSED_NOTE 0x180
2019-11-03 14:36:27 -05:00
# define DMEM_ADDR_NOTE_PAN_TEMP 0x200
# define DMEM_ADDR_STEREO_STRONG_TEMP_DRY 0x200
# define DMEM_ADDR_STEREO_STRONG_TEMP_WET 0x340
# define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x3f0
# define DMEM_ADDR_LEFT_CH 0x4c0
# define DMEM_ADDR_RIGHT_CH 0x600
# define DMEM_ADDR_WET_LEFT_CH 0x740
# define DMEM_ADDR_WET_RIGHT_CH 0x880
2019-08-25 00:46:40 -04:00
# define aSetLoadBufferPair(pkt, c, off) \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , c + DMEM_ADDR_WET_LEFT_CH , 0 , DEFAULT_LEN_1CH - c ) ; \
2020-04-03 14:57:26 -04:00
aLoadBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . left + ( off ) ) ) ; \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , c + DMEM_ADDR_WET_RIGHT_CH , 0 , DEFAULT_LEN_1CH - c ) ; \
2021-12-30 10:57:51 -06:00
aLoadBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . right + ( off ) ) ) ;
2019-08-25 00:46:40 -04:00
# define aSetSaveBufferPair(pkt, c, d, off) \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , 0 , c + DMEM_ADDR_WET_LEFT_CH , d ) ; \
2020-04-03 14:57:26 -04:00
aSaveBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . left + ( off ) ) ) ; \
2019-11-03 14:36:27 -05:00
aSetBuffer ( pkt , 0 , 0 , c + DMEM_ADDR_WET_RIGHT_CH , d ) ; \
2020-04-03 14:57:26 -04:00
aSaveBuffer ( pkt , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . ringBuffer . right + ( off ) ) ) ;
2019-08-25 00:46:40 -04:00
2023-06-07 06:46:25 -04:00
# define VOLRAMPING_MASK (~(0x8000 | ((1 << (15 - VOL_RAMPING_EXPONENT)) - 1)))
2022-02-26 01:56:07 -05:00
# ifdef BETTER_REVERB
2021-08-05 00:02:00 -05:00
// Do not touch these values manually, unless you want potential for problems.
2023-06-28 15:15:38 -04:00
u8 gBetterReverbPresetValue = 0 ;
2023-01-24 09:22:49 -05:00
u8 toggleBetterReverb = FALSE ;
2023-03-15 10:52:05 -04:00
u8 betterReverbLightweight = FALSE ;
2023-01-24 09:22:49 -05:00
u8 monoReverb ;
s8 betterReverbDownsampleRate ;
2023-06-05 18:09:03 -04:00
static s32 reverbMults [ SYNTH_CHANNEL_STEREO_COUNT ] [ NUM_ALLPASS / 3 ] = { 0 } ;
static s32 allpassIdx [ SYNTH_CHANNEL_STEREO_COUNT ] [ NUM_ALLPASS ] = { 0 } ;
static s32 betterReverbDelays [ SYNTH_CHANNEL_STEREO_COUNT ] [ NUM_ALLPASS ] = { 0 } ;
static s32 * * delayBufs [ SYNTH_CHANNEL_STEREO_COUNT ] ;
static s32 lastDelayLight [ SYNTH_CHANNEL_STEREO_COUNT ] ;
u8 * gReverbMults [ SYNTH_CHANNEL_STEREO_COUNT ] ;
2023-01-24 09:22:49 -05:00
s32 reverbLastFilterIndex ;
s32 reverbFilterCount ;
s32 betterReverbWindowsSize ;
s32 betterReverbRevIndex ; // This one is okay to adjust whenever
s32 betterReverbGainIndex ; // This one is okay to adjust whenever
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 ) ;
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 ) ;
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
u64 * process_envelope ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf , s32 headsetPanSettings ) ;
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 ) ;
u64 * note_apply_headset_pan_effects ( u64 * cmd , struct Note * note , s32 bufLen , s32 flags , s32 leftRight ) ;
2023-06-07 13:58:59 -04:00
# else
u64 * process_envelope ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf ) ;
u64 * process_envelope_inner ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf , struct VolumeChange * vol ) ;
# endif
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
struct SynthesisReverb gSynthesisReverbs [ 4 ] ;
u8 sAudioSynthesisPad [ 0x10 ] ;
2020-12-03 14:26:38 -05:00
# else
struct SynthesisReverb gSynthesisReverb ;
u8 sAudioSynthesisPad [ 0x20 ] ;
# endif
2022-02-26 01:56:07 -05:00
# ifdef BETTER_REVERB
2023-06-05 18:09:03 -04:00
static void reverb_samples ( s16 * start , s16 * end , s16 * downsampleBuffer , s32 channel ) {
s32 * curDelaySample ;
s32 historySample ;
s32 tmpCarryover ;
s32 outSampleTotal ;
s32 i ;
s32 j ;
s32 k ;
s32 downsampleIncrement = gReverbDownsampleRate ;
s32 * * delayBufsLocal = delayBufs [ channel ] ;
s32 * delaysLocal = betterReverbDelays [ channel ] ;
s32 * reverbMultsLocal = reverbMults [ channel ] ;
s32 * allpassIdxLocal = allpassIdx [ channel ] ;
s32 lastFilterIndex = reverbLastFilterIndex ;
s32 revIndex = betterReverbRevIndex ;
s32 gainIndex = betterReverbGainIndex ;
// Set j outside of the loop only. Because we're forcing filter count to always be a multiple of 3, we can count on j always being 0 when exiting the second for loop.
j = 0 ;
for ( ; start < end ; start + + , downsampleBuffer + = downsampleIncrement ) {
tmpCarryover = ( ( delayBufsLocal [ lastFilterIndex ] [ allpassIdxLocal [ lastFilterIndex ] ] * revIndex ) > > 8 ) + * downsampleBuffer ;
outSampleTotal = 0 ;
i = 0 ;
k = 0 ;
for ( ; i < = lastFilterIndex ; + + i , + + j ) {
curDelaySample = & delayBufsLocal [ i ] [ allpassIdxLocal [ i ] ] ;
historySample = * curDelaySample ;
if ( j = = 2 ) {
j = - 1 ;
outSampleTotal + = ( ( historySample * reverbMultsLocal [ k + + ] ) > > 8 ) ;
* curDelaySample = tmpCarryover ;
if ( i ! = lastFilterIndex )
tmpCarryover = ( ( historySample * revIndex ) > > 8 ) /* + *downsampleBuffer*/ ;
} else {
* curDelaySample = ( ( historySample * ( - gainIndex ) ) > > 8 ) + tmpCarryover ;
tmpCarryover = ( ( * curDelaySample * gainIndex ) > > 8 ) + historySample ;
2021-08-03 22:30:11 -05:00
}
2023-06-05 18:09:03 -04:00
if ( + + allpassIdxLocal [ i ] = = delaysLocal [ i ] ) allpassIdxLocal [ i ] = 0 ;
2021-08-03 22:30:11 -05:00
}
2023-06-05 18:09:03 -04:00
* start = CLAMP_S16 ( outSampleTotal ) ;
2021-08-03 22:30:11 -05:00
}
}
2023-06-05 18:09:03 -04:00
# define FILTERS_MINUS_1 (BETTER_REVERB_FILTER_COUNT_LIGHT - 1)
static void reverb_samples_light ( s16 * start , s16 * end , s16 * downsampleBuffer , s32 channel ) {
2022-06-17 01:05:40 -04:00
s32 * curDelaySample ;
s32 historySample ;
2023-06-05 18:09:03 -04:00
s32 tmpCarryover ;
s32 i ;
2022-06-17 01:05:40 -04:00
2023-06-05 18:09:03 -04:00
s32 downsampleIncrement = gReverbDownsampleRate ;
s32 * * delayBufsLocal = delayBufs [ channel ] ;
s32 * delaysLocal = betterReverbDelays [ channel ] ;
s32 * allpassIdxLocal = allpassIdx [ channel ] ;
s32 lastDelayLightLocal = lastDelayLight [ channel ] ;
2022-06-17 01:05:40 -04:00
2023-06-05 18:09:03 -04:00
for ( ; start < end ; start + + , downsampleBuffer + = downsampleIncrement ) {
tmpCarryover = ( ( ( delayBufsLocal [ FILTERS_MINUS_1 ] [ allpassIdxLocal [ FILTERS_MINUS_1 ] ] * BETTER_REVERB_REVERB_INDEX_LIGHT ) > > 8 ) + * downsampleBuffer ) ;
i = 0 ;
2023-03-15 10:52:05 -04:00
2023-06-05 18:09:03 -04:00
for ( ; i < FILTERS_MINUS_1 ; + + i ) {
curDelaySample = & delayBufsLocal [ i ] [ allpassIdxLocal [ i ] ] ;
historySample = * curDelaySample ;
2023-03-15 10:52:05 -04:00
2023-06-05 18:09:03 -04:00
* curDelaySample = ( ( ( historySample * ( - BETTER_REVERB_GAIN_INDEX_LIGHT ) ) > > 8 ) + tmpCarryover ) ;
tmpCarryover = ( ( ( * curDelaySample * BETTER_REVERB_GAIN_INDEX_LIGHT ) > > 8 ) + historySample ) ;
2023-03-15 10:52:05 -04:00
2023-06-05 18:09:03 -04:00
if ( + + allpassIdxLocal [ i ] = = delaysLocal [ i ] ) allpassIdxLocal [ i ] = 0 ;
}
2023-03-15 10:52:05 -04:00
2023-06-05 18:09:03 -04:00
curDelaySample = & delayBufsLocal [ FILTERS_MINUS_1 ] [ allpassIdxLocal [ FILTERS_MINUS_1 ] ] ;
historySample = ( ( * curDelaySample * BETTER_REVERB_MULTIPLE_LIGHT ) > > 8 ) ; // outSampleTotal variable not needed, as there is no sample addition happening here. Not really a history sample though.
* curDelaySample = tmpCarryover ;
2023-03-15 10:52:05 -04:00
2023-06-05 18:09:03 -04:00
if ( + + allpassIdxLocal [ FILTERS_MINUS_1 ] = = lastDelayLightLocal ) allpassIdxLocal [ FILTERS_MINUS_1 ] = 0 ;
2023-03-15 10:52:05 -04:00
2023-06-05 18:09:03 -04:00
* start = CLAMP_S16 ( historySample ) ;
2023-03-15 10:52:05 -04:00
}
}
# undef FILTERS_MINUS_1
2022-06-17 01:05:40 -04:00
void initialize_better_reverb_buffers ( void ) {
2023-06-05 18:09:03 -04:00
delayBufs [ SYNTH_CHANNEL_LEFT ] = ( s32 * * ) soundAlloc ( & gBetterReverbPool , BETTER_REVERB_PTR_SIZE ) ;
delayBufs [ SYNTH_CHANNEL_RIGHT ] = & delayBufs [ SYNTH_CHANNEL_LEFT ] [ NUM_ALLPASS ] ;
2022-06-17 01:05:40 -04:00
}
2023-01-24 09:22:49 -05:00
void set_better_reverb_buffers ( u32 * inputDelaysL , u32 * inputDelaysR ) {
2022-06-17 01:05:40 -04:00
s32 bufOffset = 0 ;
s32 i ;
2023-03-15 10:52:05 -04:00
s32 filterCount = reverbFilterCount ;
if ( betterReverbLightweight )
filterCount = BETTER_REVERB_FILTER_COUNT_LIGHT ;
2022-06-17 01:05:40 -04:00
2023-01-24 09:22:49 -05:00
gBetterReverbPool . cur = gBetterReverbPool . start + ALIGN16 ( BETTER_REVERB_PTR_SIZE ) ; // Reset reverb data pool
// Don't bother setting any buffers if BETTER_REVERB is disabled
if ( ! toggleBetterReverb )
return ;
2023-03-15 10:52:05 -04:00
// NOTE: Using filterCount over NUM_ALLPASS will report less memory usage with fewer filters, but poses an additional
2023-01-24 09:22:49 -05:00
// risk to anybody testing on console with performance compromises, as emulator can be easily overlooked.
2023-03-15 10:52:05 -04:00
for ( i = 0 ; i < filterCount ; + + i ) {
2023-06-05 18:09:03 -04:00
betterReverbDelays [ SYNTH_CHANNEL_LEFT ] [ i ] = ( s32 ) ( inputDelaysL [ i ] / gReverbDownsampleRate ) ;
betterReverbDelays [ SYNTH_CHANNEL_RIGHT ] [ i ] = ( s32 ) ( inputDelaysR [ i ] / gReverbDownsampleRate ) ;
delayBufs [ SYNTH_CHANNEL_LEFT ] [ i ] = soundAlloc ( & gBetterReverbPool , betterReverbDelays [ SYNTH_CHANNEL_LEFT ] [ i ] * sizeof ( s32 ) ) ;
bufOffset + = betterReverbDelays [ SYNTH_CHANNEL_LEFT ] [ i ] ;
delayBufs [ SYNTH_CHANNEL_RIGHT ] [ i ] = soundAlloc ( & gBetterReverbPool , betterReverbDelays [ SYNTH_CHANNEL_RIGHT ] [ i ] * sizeof ( s32 ) ) ;
bufOffset + = betterReverbDelays [ SYNTH_CHANNEL_RIGHT ] [ i ] ;
2022-06-17 01:05:40 -04:00
}
2023-01-24 09:22:49 -05:00
aggress ( bufOffset * sizeof ( s32 ) < = BETTER_REVERB_SIZE - ALIGN16 ( BETTER_REVERB_PTR_SIZE ) , " BETTER_REVERB_SIZE is too small for this preset! " ) ;
2023-06-05 18:09:03 -04:00
lastDelayLight [ SYNTH_CHANNEL_LEFT ] = betterReverbDelays [ SYNTH_CHANNEL_LEFT ] [ filterCount - 1 ] ;
lastDelayLight [ SYNTH_CHANNEL_RIGHT ] = betterReverbDelays [ SYNTH_CHANNEL_RIGHT ] [ filterCount - 1 ] ;
2023-03-15 10:52:05 -04:00
2023-06-05 18:09:03 -04:00
bzero ( allpassIdx , sizeof ( allpassIdx ) ) ;
2022-06-17 01:05:40 -04:00
}
2021-08-04 18:15:38 -05:00
# endif
2021-08-02 21:14:31 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
s16 gVolume ;
s8 gUseReverb ;
s8 gNumSynthesisReverbs ;
struct NoteSubEu * gNoteSubsEu ;
2020-12-03 14:26:38 -05:00
# endif
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
f32 gLeftVolRampings [ 3 ] [ 1024 ] ;
f32 gRightVolRampings [ 3 ] [ 1024 ] ;
f32 * gCurrentLeftVolRamping ; // Points to any of the three left buffers above
f32 * gCurrentRightVolRamping ; // Points to any of the three right buffers above
2020-09-20 11:15:47 -04:00
u8 audioString1 [ ] = " pitch %x: delaybytes %d : olddelay %d \n " ;
u8 audioString2 [ ] = " cont %x: delaybytes %d : olddelay %d \n " ;
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
// Equivalent functionality as the US/JP version,
// just that the reverb structure is chosen from an array with index
void prepare_reverb_ring_buffer ( s32 chunkLen , u32 updateIndex , s32 reverbIndex ) {
struct ReverbRingBufferItem * item ;
2020-03-01 22:42:52 -05:00
struct SynthesisReverb * reverb = & gSynthesisReverbs [ reverbIndex ] ;
2021-12-30 10:57:51 -06:00
s32 srcPos , dstPos ;
2020-02-03 00:51:26 -05:00
s32 nSamples ;
s32 excessiveSamples ;
if ( reverb - > downsampleRate ! = 1 ) {
if ( reverb - > framesLeftToIgnore = = 0 ) {
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
// samples.
item = & reverb - > items [ reverb - > curFrame ] [ updateIndex ] ;
// Touches both left and right since they are adjacent in memory
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
2020-07-04 11:18:55 -04:00
for ( srcPos = 0 , dstPos = 0 ; dstPos < item - > lengthA / 2 ;
2020-02-03 00:51:26 -05:00
srcPos + = reverb - > downsampleRate , dstPos + + ) {
2021-12-30 10:57:51 -06:00
reverb - > ringBuffer . left [ item - > startPos + dstPos ] = item - > toDownsampleLeft [ srcPos ] ;
reverb - > ringBuffer . right [ item - > startPos + dstPos ] = item - > toDownsampleRight [ srcPos ] ;
2020-02-03 00:51:26 -05:00
}
2020-07-04 11:18:55 -04:00
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; srcPos + = reverb - > downsampleRate , dstPos + + ) {
2020-02-03 00:51:26 -05:00
reverb - > ringBuffer . left [ dstPos ] = item - > toDownsampleLeft [ srcPos ] ;
reverb - > ringBuffer . right [ dstPos ] = item - > toDownsampleRight [ srcPos ] ;
}
}
}
item = & reverb - > items [ reverb - > curFrame ] [ updateIndex ] ;
2020-03-01 22:42:52 -05:00
nSamples = chunkLen / reverb - > downsampleRate ;
excessiveSamples = ( nSamples + reverb - > nextRingBufferPos ) - reverb - > bufSizePerChannel ;
2020-02-03 00:51:26 -05:00
if ( excessiveSamples < 0 ) {
// There is space in the ring buffer before it wraps around
2020-07-04 11:18:55 -04:00
item - > lengthA = nSamples * 2 ;
item - > lengthB = 0 ;
2020-02-03 00:51:26 -05:00
item - > startPos = ( s32 ) reverb - > nextRingBufferPos ;
reverb - > nextRingBufferPos + = nSamples ;
} else {
// Ring buffer wrapped around
2020-07-04 11:18:55 -04:00
item - > lengthA = ( nSamples - excessiveSamples ) * 2 ;
item - > lengthB = excessiveSamples * 2 ;
2020-02-03 00:51:26 -05:00
item - > startPos = reverb - > nextRingBufferPos ;
reverb - > nextRingBufferPos = excessiveSamples ;
}
// These fields are never read later
item - > numSamplesAfterDownsampling = nSamples ;
item - > chunkLen = chunkLen ;
}
# else
2019-11-03 14:36:27 -05:00
void prepare_reverb_ring_buffer ( s32 chunkLen , u32 updateIndex ) {
struct ReverbRingBufferItem * item ;
2021-12-30 10:57:51 -06:00
s32 srcPos , dstPos ;
2019-11-03 14:36:27 -05:00
s32 nSamples ;
s32 excessiveSamples ;
2021-08-02 21:14:31 -05:00
2023-01-24 09:22:49 -05:00
if ( gSynthesisReverb . framesLeftToIgnore = = 0 ) {
2021-08-03 02:55:48 -05:00
# ifdef BETTER_REVERB
2023-01-24 09:22:49 -05:00
if ( ! toggleBetterReverb & & gReverbDownsampleRate ! = 1 ) {
2021-08-03 02:55:48 -05:00
# else
2023-01-24 09:22:49 -05:00
if ( gReverbDownsampleRate ! = 1 ) {
2021-08-03 02:55:48 -05:00
# endif
2019-11-03 14:36:27 -05:00
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
// samples.
item = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
// Touches both left and right since they are adjacent in memory
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
2020-07-04 11:18:55 -04:00
for ( srcPos = 0 , dstPos = 0 ; dstPos < item - > lengthA / 2 ;
2019-11-03 14:36:27 -05:00
srcPos + = gReverbDownsampleRate , dstPos + + ) {
2021-12-30 10:57:51 -06:00
gSynthesisReverb . ringBuffer . left [ dstPos + item - > startPos ] = item - > toDownsampleLeft [ srcPos ] ;
gSynthesisReverb . ringBuffer . right [ dstPos + item - > startPos ] = item - > toDownsampleRight [ srcPos ] ;
2019-08-25 00:46:40 -04:00
}
2020-07-04 11:18:55 -04:00
for ( dstPos = 0 ; dstPos < item - > lengthB / 2 ; srcPos + = gReverbDownsampleRate , dstPos + + ) {
2019-11-03 14:36:27 -05:00
gSynthesisReverb . ringBuffer . left [ dstPos ] = item - > toDownsampleLeft [ srcPos ] ;
gSynthesisReverb . ringBuffer . right [ dstPos ] = item - > toDownsampleRight [ srcPos ] ;
2019-08-25 00:46:40 -04:00
}
}
2021-08-03 02:55:48 -05:00
# ifdef BETTER_REVERB
2023-01-24 09:22:49 -05:00
else if ( toggleBetterReverb ) {
2023-06-05 18:09:03 -04:00
s32 loopCounts [ 2 ] ;
s16 * betterReverbDownampleBuffers [ SYNTH_CHANNEL_STEREO_COUNT ] [ ARRAY_COUNT ( loopCounts ) ] ; // StartA and StartB for both channels
s16 * betterReverbSampleBuffers [ SYNTH_CHANNEL_STEREO_COUNT ] [ ARRAY_COUNT ( loopCounts ) ] ; // Output reverb buffers
void ( * reverbFunc ) ( s16 * , s16 * , s16 * , s32 ) = betterReverbLightweight ? reverb_samples_light : reverb_samples ; // Function pointers for both heavy and lightweight reverb functions
2023-01-24 09:22:49 -05:00
item = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
2023-06-05 18:09:03 -04:00
loopCounts [ 0 ] = item - > lengthA / 2 ;
loopCounts [ 1 ] = item - > lengthB / 2 ;
if ( gReverbDownsampleRate ! = 1 ) {
// NOTE: / HACKERSM64 TODO: Commenting this check seems to improve runtime by about 100 microseconds (per 30fps frame),
// but idk enough about why it was added here in vanilla to comfortably remove it. Is it supposed to act as an
// optimization (that isn't actually an optimization) or is it a safety measure since it's loaded from the RSP?
osInvalDCache ( item - > toDownsampleLeft , DEFAULT_LEN_2CH ) ;
}
betterReverbSampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 0 ] = & gSynthesisReverb . ringBuffer . left [ item - > startPos ] ;
betterReverbSampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 1 ] = & gSynthesisReverb . ringBuffer . left [ 0 ] ;
betterReverbSampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 0 ] = & gSynthesisReverb . ringBuffer . right [ item - > startPos ] ;
betterReverbSampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 1 ] = & gSynthesisReverb . ringBuffer . right [ 0 ] ;
if ( gReverbDownsampleRate > 1 ) {
betterReverbDownampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 0 ] = & item - > toDownsampleLeft [ 0 ] ;
betterReverbDownampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 1 ] = & item - > toDownsampleLeft [ loopCounts [ 0 ] * gReverbDownsampleRate ] ;
betterReverbDownampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 0 ] = & item - > toDownsampleRight [ 0 ] ;
betterReverbDownampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 1 ] = & item - > toDownsampleRight [ loopCounts [ 0 ] * gReverbDownsampleRate ] ;
} else {
betterReverbDownampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 0 ] = betterReverbSampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 0 ] ;
betterReverbDownampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 1 ] = betterReverbSampleBuffers [ SYNTH_CHANNEL_LEFT ] [ 1 ] ;
betterReverbDownampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 0 ] = betterReverbSampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 0 ] ;
betterReverbDownampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 1 ] = betterReverbSampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ 1 ] ;
}
if ( gSoundMode = = SOUND_MODE_MONO | | monoReverb ) {
for ( srcPos = 0 ; srcPos < ARRAY_COUNT ( loopCounts ) ; srcPos + + ) { // LengthA and LengthB processing
s16 * downsampleBufferL = betterReverbDownampleBuffers [ SYNTH_CHANNEL_LEFT ] [ srcPos ] ;
s16 * downsampleBufferR = betterReverbDownampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ srcPos ] ;
for ( dstPos = 0 ; dstPos < loopCounts [ srcPos ] ; dstPos + = gReverbDownsampleRate ) { // Individual sample processing
downsampleBufferL [ dstPos ] = ( ( s32 ) downsampleBufferL [ dstPos ] + ( s32 ) downsampleBufferR [ dstPos ] ) > > 1 ; // Merge stereo samples into left channel
2023-01-24 09:22:49 -05:00
}
2021-08-04 01:03:07 -05:00
}
2023-06-05 18:09:03 -04:00
for ( srcPos = 0 ; srcPos < ARRAY_COUNT ( loopCounts ) ; srcPos + + ) { // LengthA and LengthB processing
// Call core reverb processing function, either reverb_samples() or reverb_samples_light()
( * reverbFunc ) ( betterReverbSampleBuffers [ SYNTH_CHANNEL_LEFT ] [ srcPos ] , betterReverbSampleBuffers [ SYNTH_CHANNEL_LEFT ] [ srcPos ] + loopCounts [ srcPos ] , betterReverbDownampleBuffers [ SYNTH_CHANNEL_LEFT ] [ srcPos ] , SYNTH_CHANNEL_LEFT ) ;
bcopy ( betterReverbSampleBuffers [ SYNTH_CHANNEL_LEFT ] [ srcPos ] , betterReverbSampleBuffers [ SYNTH_CHANNEL_RIGHT ] [ srcPos ] , loopCounts [ srcPos ] * sizeof ( s16 ) ) ;
}
2023-01-20 15:36:19 +01:00
} else {
2023-06-05 18:09:03 -04:00
for ( dstPos = 0 ; dstPos < SYNTH_CHANNEL_STEREO_COUNT ; dstPos + + ) { // left and right channels
for ( srcPos = 0 ; srcPos < ARRAY_COUNT ( loopCounts ) ; srcPos + + ) { // LengthA and LengthB processing
// Call core reverb processing function, either reverb_samples() or reverb_samples_light()
( * reverbFunc ) ( betterReverbSampleBuffers [ dstPos ] [ srcPos ] , betterReverbSampleBuffers [ dstPos ] [ srcPos ] + loopCounts [ srcPos ] , betterReverbDownampleBuffers [ dstPos ] [ srcPos ] , dstPos ) ;
2023-03-15 10:52:05 -04:00
}
2021-08-04 01:03:07 -05:00
}
}
2021-08-03 21:29:06 -05:00
}
2021-08-02 21:14:31 -05:00
# endif
2023-01-24 09:22:49 -05:00
}
2019-11-03 14:36:27 -05:00
item = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
2021-12-30 10:57:51 -06:00
s32 numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate ;
2020-04-03 14:57:26 -04:00
if ( ( ( numSamplesAfterDownsampling + gSynthesisReverb . nextRingBufferPos ) - gSynthesisReverb . bufSizePerChannel ) < 0 ) {
2019-11-03 14:36:27 -05:00
// There is space in the ring buffer before it wraps around
2020-07-04 11:18:55 -04:00
item - > lengthA = numSamplesAfterDownsampling * 2 ;
item - > lengthB = 0 ;
2019-11-03 14:36:27 -05:00
item - > startPos = ( s32 ) gSynthesisReverb . nextRingBufferPos ;
2020-04-03 14:57:26 -04:00
gSynthesisReverb . nextRingBufferPos + = numSamplesAfterDownsampling ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
// Ring buffer wrapped around
excessiveSamples =
2020-04-03 14:57:26 -04:00
( numSamplesAfterDownsampling + gSynthesisReverb . nextRingBufferPos ) - gSynthesisReverb . bufSizePerChannel ;
2019-11-03 14:36:27 -05:00
nSamples = numSamplesAfterDownsampling - excessiveSamples ;
2020-07-04 11:18:55 -04:00
item - > lengthA = nSamples * 2 ;
item - > lengthB = excessiveSamples * 2 ;
2019-11-03 14:36:27 -05:00
item - > startPos = gSynthesisReverb . nextRingBufferPos ;
gSynthesisReverb . nextRingBufferPos = excessiveSamples ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
// These fields are never read later
item - > numSamplesAfterDownsampling = numSamplesAfterDownsampling ;
item - > chunkLen = chunkLen ;
2019-08-25 00:46:40 -04:00
}
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * synthesis_load_reverb_ring_buffer ( u64 * cmd , u16 addr , u16 srcOffset , s32 len , s32 reverbIndex ) {
aSetBuffer ( cmd + + , 0 , addr , 0 , len ) ;
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . left [ srcOffset ] ) ) ;
aSetBuffer ( cmd + + , 0 , addr + DEFAULT_LEN_1CH , 0 , len ) ;
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . right [ srcOffset ] ) ) ;
return cmd ;
}
2020-12-03 14:26:38 -05:00
# endif
2020-02-03 00:51:26 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * synthesis_save_reverb_ring_buffer ( u64 * cmd , u16 addr , u16 destOffset , s32 len , s32 reverbIndex ) {
aSetBuffer ( cmd + + , 0 , 0 , addr , len ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . left [ destOffset ] ) ) ;
aSetBuffer ( cmd + + , 0 , 0 , addr + DEFAULT_LEN_1CH , len ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( & gSynthesisReverbs [ reverbIndex ] . ringBuffer . right [ destOffset ] ) ) ;
return cmd ;
}
2020-12-03 14:26:38 -05:00
# endif
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
void synthesis_load_note_subs_eu ( s32 updateIndex ) {
struct NoteSubEu * src ;
struct NoteSubEu * dest ;
s32 i ;
for ( i = 0 ; i < gMaxSimultaneousNotes ; i + + ) {
src = & gNotes [ i ] . noteSubEu ;
dest = & gNoteSubsEu [ gMaxSimultaneousNotes * updateIndex + i ] ;
if ( src - > enabled ) {
* dest = * src ;
2020-12-03 14:26:38 -05:00
src - > needsInit = FALSE ;
2020-02-03 00:51:26 -05:00
} else {
2020-12-03 14:26:38 -05:00
dest - > enabled = FALSE ;
2020-02-03 00:51:26 -05:00
}
}
}
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# 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 ;
2022-04-15 09:46:17 -07:00
s32 nextVolRampTable = 0 ;
2020-02-03 00:51:26 -05:00
for ( i = gAudioBufferParameters . updatesPerFrame ; i > 0 ; i - - ) {
process_sequences ( i - 1 ) ;
synthesis_load_note_subs_eu ( gAudioBufferParameters . updatesPerFrame - i ) ;
}
aSegment ( cmd + + , 0 , 0 ) ;
aiBufPtr = ( u32 * ) aiBuf ;
for ( i = gAudioBufferParameters . updatesPerFrame ; i > 0 ; i - - ) {
if ( i = = 1 ) {
2020-03-01 22:42:52 -05:00
// self-assignment has no affect when added here, could possibly simplify a macro definition
2021-12-30 10:57:51 -06:00
chunkLen = bufLen ;
leftVolRamp = gLeftVolRampings [ nextVolRampTable ] ;
rightVolRamp = gRightVolRampings [ nextVolRampTable & 0xFFFFFFFF ] ;
2020-02-03 00:51:26 -05:00
} else {
2020-03-01 22:42:52 -05:00
if ( bufLen / i > = gAudioBufferParameters . samplesPerUpdateMax ) {
chunkLen = gAudioBufferParameters . samplesPerUpdateMax ; nextVolRampTable = 2 ; leftVolRamp = gLeftVolRampings [ 2 ] ; rightVolRamp = gRightVolRampings [ 2 ] ;
} else if ( bufLen / i < = gAudioBufferParameters . samplesPerUpdateMin ) {
chunkLen = gAudioBufferParameters . samplesPerUpdateMin ; nextVolRampTable = 0 ; leftVolRamp = gLeftVolRampings [ 0 ] ; rightVolRamp = gRightVolRampings [ 0 ] ;
2020-02-03 00:51:26 -05:00
} else {
2020-03-01 22:42:52 -05:00
chunkLen = gAudioBufferParameters . samplesPerUpdate ; nextVolRampTable = 1 ; leftVolRamp = gLeftVolRampings [ 1 ] ; rightVolRamp = gRightVolRampings [ 1 ] ;
2020-02-03 00:51:26 -05:00
}
}
gCurrentLeftVolRamping = leftVolRamp ;
gCurrentRightVolRamping = rightVolRamp ;
for ( j = 0 ; j < gNumSynthesisReverbs ; j + + ) {
2023-01-24 09:22:49 -05:00
if ( gSynthesisReverbs [ j ] . useReverb ) {
2020-02-03 00:51:26 -05:00
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
2023-01-24 09:22:49 -05:00
s32 filterCountDiv3 = reverbFilterCount / 3 ;
reverbFilterCount = filterCountDiv3 * 3 ; // reverbFilterCount should always be a multiple of 3.
2021-12-30 10:57:51 -06:00
if ( reverbFilterCount > NUM_ALLPASS ) {
2021-08-05 01:14:01 -05:00
reverbFilterCount = NUM_ALLPASS ;
2022-06-17 01:05:40 -04:00
} else if ( reverbFilterCount < 3 ) {
reverbFilterCount = 3 ;
2021-12-30 10:57:51 -06:00
}
2022-06-17 01:05:40 -04:00
2023-01-24 09:22:49 -05:00
reverbLastFilterIndex = reverbFilterCount - 1 ;
2022-06-17 01:05:40 -04:00
2023-06-05 18:09:03 -04:00
// Update reverbMults every audio frame just in case gReverbMults is ever to change.
if ( gReverbMults [ SYNTH_CHANNEL_LEFT ] ! = NULL & & gReverbMults [ SYNTH_CHANNEL_RIGHT ] ! = NULL ) {
2023-01-24 09:22:49 -05:00
for ( i = 0 ; i < filterCountDiv3 ; + + i ) {
2023-06-05 18:09:03 -04:00
reverbMults [ SYNTH_CHANNEL_LEFT ] [ i ] = gReverbMults [ SYNTH_CHANNEL_LEFT ] [ i ] ;
reverbMults [ SYNTH_CHANNEL_RIGHT ] [ i ] = gReverbMults [ SYNTH_CHANNEL_RIGHT ] [ i ] ;
2023-01-24 09:22:49 -05:00
}
2022-06-17 01:05:40 -04:00
}
// If there's only one reverb multiplier set, adjust these to match so one channel doesn't end up potentially overpowering the other.
if ( filterCountDiv3 = = 1 ) {
2023-06-05 18:09:03 -04:00
reverbMults [ SYNTH_CHANNEL_LEFT ] [ 0 ] = ( reverbMults [ SYNTH_CHANNEL_RIGHT ] [ 0 ] + reverbMults [ SYNTH_CHANNEL_LEFT ] [ 0 ] ) / 2 ;
reverbMults [ SYNTH_CHANNEL_RIGHT ] [ 0 ] = reverbMults [ SYNTH_CHANNEL_LEFT ] [ 0 ] ;
2021-12-30 10:57:51 -06:00
}
2021-08-05 00:02:00 -05:00
# endif
2019-08-25 00:46:40 -04:00
for ( i = gAudioUpdatesPerFrame ; i > 0 ; i - - ) {
if ( i = = 1 ) {
2020-04-03 14:57:26 -04:00
// 'bufLen' will automatically be divisible by 8, no need to round
chunkLen = bufLen ;
2019-08-25 00:46:40 -04:00
} else {
2020-04-03 14:57:26 -04:00
v0 = bufLen / i ;
2019-08-25 00:46:40 -04:00
// chunkLen = v0 rounded to nearest multiple of 8
chunkLen = v0 - ( v0 & 7 ) ;
2019-09-01 15:50:50 -04:00
if ( ( v0 & 7 ) > = 4 ) {
2019-08-25 00:46:40 -04:00
chunkLen + = 8 ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
}
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_UPDATE , PROFILER_TIME_SUB_AUDIO_SEQUENCES ) ;
AUDIO_PROFILER_START_SHARED ( PROFILER_TIME_SUB_AUDIO_SEQUENCES , PROFILER_TIME_SUB_AUDIO_SEQUENCES_SCRIPT ) ;
2019-08-25 00:46:40 -04:00
process_sequences ( i - 1 ) ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_COMPLETE_AND_SWITCH ( PROFILER_TIME_SUB_AUDIO_SEQUENCES_PROCESSING , PROFILER_TIME_SUB_AUDIO_SEQUENCES , PROFILER_TIME_SUB_AUDIO_SYNTHESIS ) ;
AUDIO_PROFILER_START_SHARED ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB ) ;
2023-01-24 09:22:49 -05:00
if ( gSynthesisReverb . useReverb ) {
2019-11-03 14:36:27 -05:00
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 ) ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_COMPLETE_AND_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB , PROFILER_TIME_SUB_AUDIO_SYNTHESIS , PROFILER_TIME_SUB_AUDIO_UPDATE ) ;
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 {
2022-04-15 09:46:17 -07:00
startPad = ( item - > startPos & 0x7 ) * 2 ;
2023-01-31 15:50:19 -05:00
paddedLengthA = ALIGN16 ( startPad + item - > lengthA ) ;
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 ] ;
2023-01-24 09:22:49 -05:00
if ( gSynthesisReverbs [ reverbIndex ] . useReverb ) {
2020-12-03 14:26:38 -05:00
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 ;
2023-01-24 09:22:49 -05:00
if ( gUseReverb ) {
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 ;
}
}
2023-01-24 09:22:49 -05:00
if ( gSynthesisReverbs [ j ] . useReverb ) {
2020-03-01 22:42:52 -05:00
cmd = synthesis_save_reverb_samples ( cmd , j , updateIndex ) ;
2020-02-03 00:51:26 -05:00
}
}
2020-03-01 22:42:52 -05:00
for ( ; i < notePos ; i + + ) {
2020-12-03 14:26:38 -05:00
temp = updateIndex * gMaxSimultaneousNotes ;
2021-12-30 10:57:51 -06:00
if ( IS_BANK_LOAD_COMPLETE ( gNoteSubsEu [ temp + noteIndices [ i ] ] . bankId ) ) {
2020-03-01 22:42:52 -05:00
cmd = synthesis_process_note ( & gNotes [ noteIndices [ i ] ] ,
& gNoteSubsEu [ temp + noteIndices [ i ] ] ,
& gNotes [ noteIndices [ i ] ] . synthesisState ,
aiBuf , bufLen , cmd ) ;
2020-02-03 00:51:26 -05:00
} else {
2020-03-01 22:42:52 -05:00
gAudioErrorFlags = ( gNoteSubsEu [ temp + noteIndices [ i ] ] . bankId + ( i < < 8 ) ) + 0x10000000 ;
2020-02-03 00:51:26 -05:00
}
}
2020-03-01 22:42:52 -05:00
temp = bufLen * 2 ;
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , temp ) ;
2020-02-03 00:51:26 -05:00
aInterleave ( cmd + + , DMEM_ADDR_LEFT_CH , DMEM_ADDR_RIGHT_CH ) ;
2020-03-01 22:42:52 -05:00
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , temp * 2 ) ;
2020-02-03 00:51:26 -05:00
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( aiBuf ) ) ;
return cmd ;
}
2021-07-12 23:17:54 -04:00
# else
2020-12-03 14:26:38 -05:00
u64 * synthesis_do_one_audio_update ( s16 * aiBuf , s32 bufLen , u64 * cmd , s32 updateIndex ) {
2019-08-25 00:46:40 -04:00
s16 ra ;
s16 t4 ;
2019-11-03 14:36:27 -05:00
struct ReverbRingBufferItem * v1 ;
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
v1 = & gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] ;
2019-08-25 00:46:40 -04:00
2023-01-24 09:22:49 -05:00
if ( ! gSynthesisReverb . useReverb ) {
2019-11-03 14:36:27 -05:00
aClearBuffer ( cmd + + , DMEM_ADDR_LEFT_CH , DEFAULT_LEN_2CH ) ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING ) ;
2019-12-01 21:52:53 -05:00
cmd = synthesis_process_notes ( aiBuf , bufLen , cmd ) ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB ) ;
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 ;
2023-01-31 15:50:19 -05:00
ra = ALIGN16 ( v1 - > lengthA + t4 ) ;
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
aDMEMMove ( cmd + + , DMEM_ADDR_LEFT_CH , DMEM_ADDR_WET_LEFT_CH , DEFAULT_LEN_2CH ) ;
2023-06-28 15:15:38 -04:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , DEFAULT_LEN_2CH ) ;
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
}
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING ) ;
2019-12-01 21:52:53 -05:00
cmd = synthesis_process_notes ( aiBuf , bufLen , cmd ) ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB ) ;
2019-11-03 14:36:27 -05:00
if ( gReverbDownsampleRate = = 1 ) {
2020-07-04 11:18:55 -04:00
aSetSaveBufferPair ( cmd + + , 0 , v1 - > lengthA , v1 - > startPos ) ;
if ( v1 - > lengthB ! = 0 ) {
2019-11-03 14:36:27 -05:00
// Ring buffer wrapped
2020-07-04 11:18:55 -04:00
aSetSaveBufferPair ( cmd + + , v1 - > lengthA , v1 - > lengthB , 0 ) ;
2019-08-25 00:46:40 -04:00
}
} else {
2019-11-03 14:36:27 -05:00
// Downsampling is done later by CPU when RSP is done, therefore we need to have double
// buffering. Left and right buffers are adjacent in memory.
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_WET_LEFT_CH , DEFAULT_LEN_2CH ) ;
2020-04-03 14:57:26 -04:00
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( gSynthesisReverb . items [ gSynthesisReverb . curFrame ] [ updateIndex ] . toDownsampleLeft ) ) ;
2019-11-03 14:36:27 -05:00
gSynthesisReverb . resampleFlags = 0 ;
2019-08-25 00:46:40 -04:00
}
}
return cmd ;
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
// Processes just one note, not all
2021-07-12 23:17:54 -04:00
u64 * synthesis_process_note ( struct Note * note , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * synthesisState , UNUSED s16 * aiBuf , s32 bufLen , u64 * cmd ) {
2020-02-03 00:51:26 -05:00
# else
2020-06-02 12:44:34 -04:00
u64 * synthesis_process_notes ( s16 * aiBuf , s32 bufLen , u64 * cmd ) {
2019-11-03 14:36:27 -05:00
s32 noteIndex ; // sp174
struct Note * note ; // s7
2020-04-03 14:57:26 -04:00
# endif
struct AudioBankSample * audioBookSample ; // sp164, sp138
struct AdpcmLoop * loopInfo ; // sp160, sp134
s16 * curLoadedBook = NULL ; // sp154, sp130
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2020-04-03 14:57:26 -04:00
u16 resamplingRateFixedPoint ; // sp5c, sp11A
# endif
s32 noteFinished ; // 150 t2, sp124
s32 restart ; // 14c t3, sp120
s32 flags ; // sp148, sp11C
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
u16 resamplingRateFixedPoint ; // sp5c, sp11A
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
UNUSED s32 tempBufLen ;
2021-07-18 04:57:37 -05:00
s32 sp130 = 0 ; //sp128, sp104
2020-04-03 14:57:26 -04:00
s32 nAdpcmSamplesProcessed ; // signed required for US
2019-08-25 00:46:40 -04:00
s32 t0 ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
u8 * sampleAddr ; // sp120, spF4
s32 s6 ;
# else
s32 s6 ;
u8 * sampleAddr ; // sp120, spF4
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
s32 samplesLenAdjusted ; // 108, spEC
// Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
// behavior with the break near the end of the loop, causing US and JP to need a goto instead
UNUSED s32 samplesLenInt ;
s32 endPos ; // sp110, spE4
s32 nSamplesToProcess ; // sp10c/a0, spE0
s32 s2 ;
# else
// Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
// behavior with the break near the end of the loop, causing US and JP to need a goto instead
UNUSED s32 samplesLenInt ;
s32 samplesLenAdjusted ; // 108
2019-08-25 00:46:40 -04:00
s32 s2 ;
2020-04-03 14:57:26 -04:00
s32 endPos ; // sp110, spE4
s32 nSamplesToProcess ; // sp10c/a0, spE0
# endif
2019-08-25 00:46:40 -04:00
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
2020-12-03 14:26:38 -05:00
s32 leftRight ;
2023-06-07 13:58:59 -04:00
# endif
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
2022-06-29 00:17:04 -04:00
u16 noteSamplesDmemAddrBeforeResampling = 0 ; // spD6, spAA
2020-02-03 00:51:26 -05:00
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2020-04-03 14:57:26 -04:00
for ( noteIndex = 0 ; noteIndex < gMaxSimultaneousNotes ; noteIndex + + ) {
2019-11-03 14:36:27 -05:00
note = & gNotes [ noteIndex ] ;
2020-04-03 14:57:26 -04:00
# ifdef VERSION_US
//! This function requires note->enabled to be volatile, but it breaks other functions like note_enable.
//! Casting to a struct with just the volatile bitfield works, but there may be a better way to match.
2021-12-30 10:57:51 -06:00
if ( ( ( struct vNote * ) note ) - > enabled & & ! IS_BANK_LOAD_COMPLETE ( note - > bankId ) ) {
2020-04-03 14:57:26 -04:00
# else
2021-12-30 10:57:51 -06:00
if ( ! IS_BANK_LOAD_COMPLETE ( note - > bankId ) ) {
2020-04-03 14:57:26 -04:00
# endif
2019-11-03 14:36:27 -05:00
gAudioErrorFlags = ( note - > bankId < < 8 ) + noteIndex + 0x1000000 ;
2020-04-03 14:57:26 -04:00
} else if ( ( ( struct vNote * ) note ) - > enabled ) {
2020-02-03 00:51:26 -05:00
# else
2020-04-03 14:57:26 -04:00
if ( note - > noteSubEu . enabled = = FALSE ) {
return cmd ;
} else {
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
flags = 0 ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
tempBufLen = bufLen ;
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( noteSubEu - > needsInit = = TRUE ) {
# else
2019-11-03 14:36:27 -05:00
if ( note - > needsInit = = TRUE ) {
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
flags = A_INIT ;
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-11-03 14:36:27 -05:00
note - > samplePosInt = 0 ;
note - > samplePosFrac = 0 ;
2020-02-03 00:51:26 -05:00
# else
synthesisState - > restart = FALSE ;
synthesisState - > samplePosInt = 0 ;
synthesisState - > samplePosFrac = 0 ;
synthesisState - > curVolLeft = 1 ;
synthesisState - > curVolRight = 1 ;
synthesisState - > prevHeadsetPanRight = 0 ;
synthesisState - > prevHeadsetPanLeft = 0 ;
# endif
2019-08-25 00:46:40 -04:00
}
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2021-12-30 10:57:51 -06:00
if ( note - > frequency < 2.0f ) {
2019-11-03 14:36:27 -05:00
nParts = 1 ;
2021-12-30 10:57:51 -06:00
if ( note - > frequency > 1.99996f ) {
note - > frequency = 1.99996f ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
resamplingRate = note - > frequency ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
// If frequency is > 2.0, the processing must be split into two parts
nParts = 2 ;
2021-12-30 10:57:51 -06:00
if ( note - > frequency > = 3.99993f ) {
note - > frequency = 3.99993f ;
2019-08-25 00:46:40 -04:00
}
2021-12-30 10:57:51 -06:00
resamplingRate = note - > frequency * 0.5f ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
resamplingRateFixedPoint = ( u16 ) ( s32 ) ( resamplingRate * 32768.0f ) ;
samplesLenFixedPoint = note - > samplePosFrac + ( resamplingRateFixedPoint * bufLen ) * 2 ;
2020-04-03 14:57:26 -04:00
note - > samplePosFrac = samplesLenFixedPoint & 0xFFFF ; // 16-bit store, can't reuse
2020-02-03 00:51:26 -05:00
# else
resamplingRateFixedPoint = noteSubEu - > resamplingRateFixedPoint ;
nParts = noteSubEu - > hasTwoAdpcmParts + 1 ;
2020-04-03 14:57:26 -04:00
samplesLenFixedPoint = ( resamplingRateFixedPoint * tempBufLen * 2 ) + synthesisState - > samplePosFrac ;
synthesisState - > samplePosFrac = samplesLenFixedPoint & 0xFFFF ;
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( noteSubEu - > isSyntheticWave ) {
2020-03-01 22:42:52 -05:00
cmd = load_wave_samples ( cmd , noteSubEu , synthesisState , samplesLenFixedPoint > > 0x10 ) ;
2020-04-03 14:57:26 -04:00
noteSamplesDmemAddrBeforeResampling = ( synthesisState - > samplePosInt * 2 ) + DMEM_ADDR_UNCOMPRESSED_NOTE ;
synthesisState - > samplePosInt + = samplesLenFixedPoint > > 0x10 ;
2020-02-03 00:51:26 -05:00
}
# else
2019-11-03 14:36:27 -05:00
if ( note - > sound = = NULL ) {
// A wave synthesis note (not ADPCM)
2020-04-03 14:57:26 -04:00
2019-11-03 14:36:27 -05:00
cmd = load_wave_samples ( cmd , note , samplesLenFixedPoint > > 0x10 ) ;
2020-04-03 14:57:26 -04:00
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + note - > samplePosInt * 2 ;
2019-11-03 14:36:27 -05:00
note - > samplePosInt + = ( samplesLenFixedPoint > > 0x10 ) ;
flags = 0 ;
2020-02-03 00:51:26 -05:00
}
# endif
else {
2019-11-03 14:36:27 -05:00
// ADPCM note
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
audioBookSample = noteSubEu - > sound . audioBankSound - > sample ;
# else
2019-11-03 14:36:27 -05:00
audioBookSample = note - > sound - > sample ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
loopInfo = audioBookSample - > loop ;
endPos = loopInfo - > end ;
sampleAddr = audioBookSample - > sampleAddr ;
resampledTempLen = 0 ;
for ( curPart = 0 ; curPart < nParts ; curPart + + ) {
2020-04-03 14:57:26 -04:00
nAdpcmSamplesProcessed = 0 ; // s8
s5 = 0 ; // s4
if ( nParts = = 1 ) {
samplesLenAdjusted = samplesLenFixedPoint > > 0x10 ;
} else if ( ( samplesLenFixedPoint > > 0x10 ) & 1 ) {
samplesLenAdjusted = ( ( samplesLenFixedPoint > > 0x10 ) & ~ 1 ) + ( curPart * 2 ) ;
}
else {
samplesLenAdjusted = ( samplesLenFixedPoint > > 0x10 ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
if ( curLoadedBook ! = audioBookSample - > book - > book ) {
u32 nEntries ; // v1
curLoadedBook = audioBookSample - > book - > book ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
nEntries = 16 * audioBookSample - > book - > order * audioBookSample - > book - > npredictors ;
aLoadADPCM ( cmd + + , nEntries , VIRTUAL_TO_PHYSICAL2 ( curLoadedBook + noteSubEu - > bookOffset ) ) ;
2020-03-01 22:42:52 -05:00
# else
2020-04-03 14:57:26 -04:00
nEntries = audioBookSample - > book - > order * audioBookSample - > book - > npredictors ;
2019-11-03 14:36:27 -05:00
aLoadADPCM ( cmd + + , nEntries * 16 , VIRTUAL_TO_PHYSICAL2 ( curLoadedBook ) ) ;
2020-03-01 22:42:52 -05:00
# endif
2019-08-25 00:46:40 -04:00
}
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-03-01 22:42:52 -05:00
if ( noteSubEu - > bookOffset ) {
2020-12-03 14:26:38 -05:00
curLoadedBook = euUnknownData_80301950 ; // what's this? never read
2020-02-03 00:51:26 -05:00
}
# endif
2019-11-03 14:36:27 -05:00
while ( nAdpcmSamplesProcessed ! = samplesLenAdjusted ) {
s32 samplesRemaining ; // v1
2019-08-25 00:46:40 -04:00
s32 s0 ;
2020-04-03 14:57:26 -04:00
2019-11-03 14:36:27 -05:00
noteFinished = FALSE ;
restart = FALSE ;
nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
s2 = synthesisState - > samplePosInt & 0xf ;
samplesRemaining = endPos - synthesisState - > samplePosInt ;
# else
2019-11-03 14:36:27 -05:00
s2 = note - > samplePosInt & 0xf ;
samplesRemaining = endPos - note - > samplePosInt ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
if ( s2 = = 0 & & synthesisState - > restart = = FALSE ) {
2020-02-03 00:51:26 -05:00
s2 = 16 ;
}
# else
2020-04-03 14:57:26 -04:00
if ( s2 = = 0 & & note - > restart = = FALSE ) {
2019-08-25 00:46:40 -04:00
s2 = 16 ;
}
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
s6 = 16 - s2 ; // a1
2019-11-03 14:36:27 -05:00
if ( nSamplesToProcess < samplesRemaining ) {
t0 = ( nSamplesToProcess - s6 + 0xf ) / 16 ;
2019-08-25 00:46:40 -04:00
s0 = t0 * 16 ;
2019-11-03 14:36:27 -05:00
s3 = s6 + s0 - nSamplesToProcess ;
2019-08-25 00:46:40 -04:00
} else {
2021-07-12 23:17:54 -04:00
# ifndef VERSION_EU
2019-11-03 14:36:27 -05:00
s0 = samplesRemaining + s2 - 0x10 ;
2020-04-03 14:57:26 -04:00
# else
s0 = samplesRemaining - s6 ;
# endif
2019-08-25 00:46:40 -04:00
s3 = 0 ;
if ( s0 < = 0 ) {
s0 = 0 ;
2019-11-03 14:36:27 -05:00
s6 = samplesRemaining ;
2019-08-25 00:46:40 -04:00
}
t0 = ( s0 + 0xf ) / 16 ;
2019-11-03 14:36:27 -05:00
if ( loopInfo - > count ! = 0 ) {
// Loop around and restart
restart = 1 ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
noteFinished = 1 ;
2019-08-25 00:46:40 -04:00
}
}
if ( t0 ! = 0 ) {
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-04-03 14:57:26 -04:00
temp = ( synthesisState - > samplePosInt - s2 + 0x10 ) / 16 ;
2020-02-03 00:51:26 -05:00
if ( audioBookSample - > loaded = = 0x81 ) {
2020-04-03 14:57:26 -04:00
v0_2 = sampleAddr + temp * 9 ;
2020-02-03 00:51:26 -05:00
} else {
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_DMA ) ;
2020-02-03 00:51:26 -05:00
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 ) ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_DMA , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING ) ;
2020-02-03 00:51:26 -05:00
}
# else
2023-03-12 16:29:08 +00:00
// HACKERSM64_TODO: Is the EU thing above applicable to US? Could potentially save some resources.
2020-04-03 14:57:26 -04:00
temp = ( note - > samplePosInt - s2 + 0x10 ) / 16 ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_DMA ) ;
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 ) ;
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_DMA , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING ) ;
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 {
2023-01-31 15:50:19 -05:00
s5Aligned = ALIGN32 ( s5 ) ;
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 {
2023-01-31 15:50:19 -05:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3 , DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN32 ( s5 ) , s0 * 2 ) ;
2020-04-03 14:57:26 -04:00
aADPCMdec ( cmd + + , flags , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > adpcmdecState ) ) ;
2023-01-31 15:50:19 -05:00
aDMEMMove ( cmd + + , DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN32 ( s5 ) + ( 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
2023-05-05 18:10:26 -04:00
/**
* ! NOTE : Removing this seems to produce a more accurate waveform , however I have no idea why Nintendo decided to add this originally .
* I can only speculate ( and hope ) that this was just an oversight on their part and this has no reason to exist , given my testing .
* I ' m leaving it commented out here just in case though .
*/
// 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
2023-03-12 16:29:08 +00:00
// final resample
aSetBuffer ( cmd + + , /*flags*/ 0 , noteSamplesDmemAddrBeforeResampling , /*dmemout*/ DMEM_ADDR_TEMP , bufLen * 2 ) ;
aResample ( cmd + + , flags , resamplingRateFixedPoint , VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > finalResampleState ) ) ;
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
}
2023-03-12 16:29:08 +00:00
// final resample
aSetBuffer ( cmd + + , /*flags*/ 0 , noteSamplesDmemAddrBeforeResampling , /*dmemout*/ DMEM_ADDR_TEMP , bufLen * 2 ) ;
aResample ( cmd + + , flags , resamplingRateFixedPoint , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > finalResampleState ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
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
}
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB ) ;
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
2023-06-07 13:58:59 -04:00
cmd = process_envelope ( cmd , note , bufLen , 0 , leftRight ) ;
2020-02-03 00:51:26 -05:00
# endif
2023-03-12 16:29:08 +00:00
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING ) ;
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 ( 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
}
2023-06-07 13:58:59 -04:00
# endif
# else
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB ) ;
cmd = process_envelope ( cmd , note , bufLen , 0 ) ;
AUDIO_PROFILER_SWITCH ( PROFILER_TIME_SUB_AUDIO_SYNTHESIS_ENVELOPE_REVERB , PROFILER_TIME_SUB_AUDIO_SYNTHESIS_PROCESSING ) ;
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
# ifndef VERSION_EU
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
u64 * process_envelope ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf , s32 headsetPanSettings ) {
# else
u64 * process_envelope ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf ) {
# endif
2019-08-25 00:46:40 -04:00
struct VolumeChange vol ;
2023-05-05 18:10:26 -04:00
if ( note - > initFullVelocity ) {
note - > initFullVelocity = FALSE ;
vol . sourceLeft = note - > targetVolLeft ;
vol . sourceRight = note - > targetVolRight ;
} else {
vol . sourceLeft = note - > curVolLeft ;
vol . sourceRight = note - > curVolRight ;
}
2019-08-25 00:46:40 -04:00
vol . targetLeft = note - > targetVolLeft ;
vol . targetRight = note - > targetVolRight ;
note - > curVolLeft = vol . targetLeft ;
note - > curVolRight = vol . targetRight ;
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
2019-11-03 14:36:27 -05:00
return process_envelope_inner ( cmd , note , nSamples , inBuf , headsetPanSettings , & vol ) ;
2023-06-07 13:58:59 -04:00
# else
return process_envelope_inner ( cmd , note , nSamples , inBuf , & vol ) ;
# endif
2019-08-25 00:46:40 -04:00
}
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
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 ) {
2023-06-07 13:58:59 -04:00
# else
u64 * process_envelope_inner ( u64 * cmd , struct Note * note , s32 nSamples , u16 inBuf ,
struct VolumeChange * vol ) {
# endif
2019-08-25 00:46:40 -04:00
u8 mixerFlags ;
s32 rampLeft , rampRight ;
2020-12-03 14:26:38 -05:00
# elif defined(VERSION_EU)
2020-04-03 14:57:26 -04:00
u64 * process_envelope ( u64 * cmd , struct NoteSubEu * note , struct NoteSynthesisState * synthesisState , s32 nSamples , u16 inBuf , s32 headsetPanSettings , UNUSED u32 flags ) {
2020-02-03 00:51:26 -05:00
u16 sourceRight ;
u16 sourceLeft ;
u16 targetLeft ;
u16 targetRight ;
s32 mixerFlags ;
s32 rampLeft ;
s32 rampRight ;
sourceLeft = synthesisState - > curVolLeft ;
sourceRight = synthesisState - > curVolRight ;
targetLeft = ( note - > targetVolLeft < < 5 ) ;
targetRight = ( note - > targetVolRight < < 5 ) ;
if ( targetLeft = = 0 ) {
targetLeft + + ;
}
if ( targetRight = = 0 ) {
targetRight + + ;
}
synthesisState - > curVolLeft = targetLeft ;
synthesisState - > curVolRight = targetRight ;
# endif
2019-08-25 00:46:40 -04:00
2019-11-03 14:36:27 -05:00
// For aEnvMixer, five buffers and count are set using aSetBuffer.
// in, dry left, count without A_AUX flag.
// dry right, wet left, wet right with A_AUX flag.
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
2019-11-03 14:36:27 -05:00
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
}
}
2023-06-07 13:58:59 -04:00
# else
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 ) ;
# 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 ( 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
2023-03-12 16:29:08 +00:00
// volume ramping
// This roughly computes 2^16 * (targetVol / sourceVol) ^ (8 / arg2),
// but with discretizations of targetVol, sourceVol and arg2.
switch ( nSamples ) {
case 128 :
2023-06-07 06:46:25 -04:00
rampLeft = gVolRampingLhs128 [ vol - > targetLeft > > ( 15 - VOL_RAMPING_EXPONENT ) ] * gVolRampingRhs128 [ vol - > sourceLeft > > ( 15 - VOL_RAMPING_EXPONENT ) ] ;
rampRight = gVolRampingLhs128 [ vol - > targetRight > > ( 15 - VOL_RAMPING_EXPONENT ) ] * gVolRampingRhs128 [ vol - > sourceRight > > ( 15 - VOL_RAMPING_EXPONENT ) ] ;
2023-03-12 16:29:08 +00:00
break ;
case 144 :
2023-06-07 06:46:25 -04:00
rampLeft = gVolRampingLhs144 [ vol - > targetLeft > > ( 15 - VOL_RAMPING_EXPONENT ) ] * gVolRampingRhs144 [ vol - > sourceLeft > > ( 15 - VOL_RAMPING_EXPONENT ) ] ;
rampRight = gVolRampingLhs144 [ vol - > targetRight > > ( 15 - VOL_RAMPING_EXPONENT ) ] * gVolRampingRhs144 [ vol - > sourceRight > > ( 15 - VOL_RAMPING_EXPONENT ) ] ;
2023-03-12 16:29:08 +00:00
break ;
case 136 :
default :
2023-06-07 06:46:25 -04:00
rampLeft = gVolRampingLhs136 [ vol - > targetLeft > > ( 15 - VOL_RAMPING_EXPONENT ) ] * gVolRampingRhs136 [ vol - > sourceLeft > > ( 15 - VOL_RAMPING_EXPONENT ) ] ;
rampRight = gVolRampingLhs136 [ vol - > targetRight > > ( 15 - VOL_RAMPING_EXPONENT ) ] * gVolRampingRhs136 [ vol - > sourceRight > > ( 15 - VOL_RAMPING_EXPONENT ) ] ;
2023-03-12 16:29:08 +00:00
break ;
}
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
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
if ( gUseReverb & & note - > reverbVol ! = 0 ) {
aEnvMixer ( cmd + + , mixerFlags | A_AUX ,
VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > mixEnvelopeState ) ) ;
# else
2021-07-12 23:17:54 -04:00
if ( gSynthesisReverb . useReverb & & note - > reverbVol ! = 0 ) {
2019-11-03 14:36:27 -05:00
aEnvMixer ( cmd + + , mixerFlags | A_AUX ,
VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > mixEnvelopeState ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
if ( note - > stereoStrongRight ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
// 0x8000 is -100%, so subtract sound instead of adding...
2021-12-30 10:57:51 -06:00
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY , /*out*/ DMEM_ADDR_LEFT_CH ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET , /*out*/ DMEM_ADDR_WET_LEFT_CH ) ;
2019-08-25 00:46:40 -04:00
} else if ( note - > stereoStrongLeft ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
2021-12-30 10:57:51 -06:00
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY , /*out*/ DMEM_ADDR_RIGHT_CH ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET , /*out*/ DMEM_ADDR_WET_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
}
} else {
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
aEnvMixer ( cmd + + , mixerFlags , VIRTUAL_TO_PHYSICAL2 ( synthesisState - > synthesisBuffers - > mixEnvelopeState ) ) ;
# else
2019-11-03 14:36:27 -05:00
aEnvMixer ( cmd + + , mixerFlags , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > mixEnvelopeState ) ) ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
if ( note - > stereoStrongRight ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY ,
/*out*/ DMEM_ADDR_LEFT_CH ) ;
2019-08-25 00:46:40 -04:00
} else if ( note - > stereoStrongLeft ) {
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , nSamples * 2 ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x8000 , /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY ,
/*out*/ DMEM_ADDR_RIGHT_CH ) ;
2019-08-25 00:46:40 -04:00
}
}
2023-06-07 13:58:59 -04:00
# else
if ( gSynthesisReverb . useReverb & & note - > reverbVol ! = 0 ) {
mixerFlags | = A_AUX ;
}
aEnvMixer ( cmd + + , mixerFlags , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > mixEnvelopeState ) ) ;
# endif
2019-08-25 00:46:40 -04:00
return cmd ;
}
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
u64 * note_apply_headset_pan_effects ( u64 * cmd , struct NoteSubEu * noteSubEu , struct NoteSynthesisState * note , s32 bufLen , s32 flags , s32 leftRight ) {
# else
2019-11-03 14:36:27 -05:00
u64 * note_apply_headset_pan_effects ( u64 * cmd , struct Note * note , s32 bufLen , s32 flags , s32 leftRight ) {
2020-02-03 00:51:26 -05:00
# endif
2019-11-03 14:36:27 -05:00
u16 dest ;
2020-12-03 14:26:38 -05:00
u16 pitch ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-03-01 22:42:52 -05:00
u8 prevPanShift ;
u8 panShift ;
UNUSED u8 unkDebug ;
2021-07-12 23:17:54 -04:00
# else
u16 prevPanShift ;
u16 panShift ;
2020-02-03 00:51:26 -05:00
# endif
2019-08-25 00:46:40 -04:00
switch ( leftRight ) {
case 1 :
2019-11-03 14:36:27 -05:00
dest = DMEM_ADDR_LEFT_CH ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
panShift = noteSubEu - > headsetPanRight ;
2021-07-12 23:17:54 -04:00
# else
panShift = note - > headsetPanRight ;
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
note - > prevHeadsetPanLeft = 0 ;
2019-11-03 14:36:27 -05:00
prevPanShift = note - > prevHeadsetPanRight ;
note - > prevHeadsetPanRight = panShift ;
2019-08-25 00:46:40 -04:00
break ;
case 2 :
2019-11-03 14:36:27 -05:00
dest = DMEM_ADDR_RIGHT_CH ;
2021-07-12 23:17:54 -04:00
# ifdef VERSION_EU
2020-02-03 00:51:26 -05:00
panShift = noteSubEu - > headsetPanLeft ;
2021-07-12 23:17:54 -04:00
# else
panShift = note - > headsetPanLeft ;
2020-02-03 00:51:26 -05:00
# endif
2020-04-03 14:57:26 -04:00
note - > prevHeadsetPanRight = 0 ;
2020-02-03 00:51:26 -05:00
2019-11-03 14:36:27 -05:00
prevPanShift = note - > prevHeadsetPanLeft ;
note - > prevHeadsetPanLeft = panShift ;
2019-08-25 00:46:40 -04:00
break ;
default :
return cmd ;
}
2021-07-12 23:17:54 -04:00
if ( flags ! = 1 ) { // A_INIT?
2019-11-03 14:36:27 -05:00
// Slightly adjust the sample rate in order to fit a change in pan shift
if ( prevPanShift = = 0 ) {
// Kind of a hack that moves the first samples into the resample state
aDMEMMove ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP , 8 ) ;
aClearBuffer ( cmd + + , 8 , 8 ) ; // Set pitch accumulator to 0 in the resample state
aDMEMMove ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP + 0x10 ,
0x10 ) ; // No idea, result seems to be overwritten later
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_TEMP , 32 ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panResampleState ) ) ;
2020-03-01 22:42:52 -05:00
pitch = ( bufLen < < 0xf ) / ( bufLen + panShift - prevPanShift + 8 ) ;
2020-04-03 14:57:26 -04:00
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_NOTE_PAN_TEMP + 8 , DMEM_ADDR_TEMP , panShift + bufLen - prevPanShift ) ;
2019-11-03 14:36:27 -05:00
aResample ( cmd + + , 0 , pitch , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panResampleState ) ) ;
2019-08-25 00:46:40 -04:00
} else {
2020-04-03 14:57:26 -04:00
if ( panShift = = 0 ) {
pitch = ( bufLen < < 0xf ) / ( bufLen - prevPanShift - 4 ) ;
} else {
pitch = ( bufLen < < 0xf ) / ( bufLen + panShift - prevPanShift ) ;
}
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP , panShift + bufLen - prevPanShift ) ;
2019-11-03 14:36:27 -05:00
aResample ( cmd + + , 0 , pitch , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panResampleState ) ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
if ( prevPanShift ! = 0 ) {
aSetBuffer ( cmd + + , 0 , DMEM_ADDR_NOTE_PAN_TEMP , 0 , prevPanShift ) ;
aLoadBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panSamplesBuffer ) ) ;
2020-04-03 14:57:26 -04:00
aDMEMMove ( cmd + + , DMEM_ADDR_TEMP , DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift , panShift + bufLen - prevPanShift ) ;
2019-08-25 00:46:40 -04:00
} else {
2019-11-03 14:36:27 -05:00
aDMEMMove ( cmd + + , DMEM_ADDR_TEMP , DMEM_ADDR_NOTE_PAN_TEMP , panShift + bufLen - prevPanShift ) ;
2019-08-25 00:46:40 -04:00
}
} else {
2019-11-03 14:36:27 -05:00
// Just shift right
aDMEMMove ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , DMEM_ADDR_TEMP , bufLen ) ;
aDMEMMove ( cmd + + , DMEM_ADDR_TEMP , DMEM_ADDR_NOTE_PAN_TEMP + panShift , bufLen ) ;
aClearBuffer ( cmd + + , DMEM_ADDR_NOTE_PAN_TEMP , panShift ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
if ( panShift ) {
// Save excessive samples for next iteration
aSetBuffer ( cmd + + , 0 , 0 , DMEM_ADDR_NOTE_PAN_TEMP + bufLen , panShift ) ;
aSaveBuffer ( cmd + + , VIRTUAL_TO_PHYSICAL2 ( note - > synthesisBuffers - > panSamplesBuffer ) ) ;
2019-08-25 00:46:40 -04:00
}
2019-11-03 14:36:27 -05:00
aSetBuffer ( cmd + + , 0 , 0 , 0 , bufLen ) ;
aMix ( cmd + + , 0 , /*gain*/ 0x7fff , /*in*/ DMEM_ADDR_NOTE_PAN_TEMP , /*out*/ dest ) ;
2019-08-25 00:46:40 -04:00
return cmd ;
}
2023-06-07 13:58:59 -04:00
# endif
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 - > curVolLeft = 1 ;
note - > curVolRight = 1 ;
note - > frequency = 0.0f ;
}
2021-07-12 23:17:54 -04:00
void note_set_vel_pan_reverb ( struct Note * note , f32 velocity , f32 pan , u8 reverbVol ) {
2021-12-30 10:57:51 -06:00
f32 volLeft , volRight ;
s32 panIndex = ( s32 ) ( pan * 127.5f ) & 127 ;
2023-06-07 13:58:59 -04:00
if ( gSoundMode = = SOUND_MODE_MONO ) {
volLeft = 0.707f ;
volRight = 0.707f ;
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
} else if ( note - > stereoHeadsetEffects & & gSoundMode = = SOUND_MODE_HEADSET ) {
2019-08-25 00:46:40 -04:00
s8 smallPanIndex ;
2020-04-03 14:57:26 -04:00
s8 temp = ( s8 ) ( pan * 10.0f ) ;
if ( temp < 9 ) {
smallPanIndex = temp ;
} else {
smallPanIndex = 9 ;
}
2019-08-25 00:46:40 -04:00
note - > headsetPanLeft = gHeadsetPanQuantization [ smallPanIndex ] ;
note - > headsetPanRight = gHeadsetPanQuantization [ 9 - smallPanIndex ] ;
note - > stereoStrongRight = FALSE ;
note - > stereoStrongLeft = FALSE ;
2019-11-03 14:36:27 -05:00
note - > usesHeadsetPanEffects = TRUE ;
2019-08-25 00:46:40 -04:00
volLeft = gHeadsetPanVolume [ panIndex ] ;
volRight = gHeadsetPanVolume [ 127 - panIndex ] ;
} else if ( note - > stereoHeadsetEffects & & gSoundMode = = SOUND_MODE_STEREO ) {
2021-12-30 10:57:51 -06:00
u8 strongLeft = FALSE ;
u8 strongRight = FALSE ;
2019-08-25 00:46:40 -04:00
note - > headsetPanLeft = 0 ;
note - > headsetPanRight = 0 ;
2019-11-03 14:36:27 -05:00
note - > usesHeadsetPanEffects = FALSE ;
2019-08-25 00:46:40 -04:00
volLeft = gStereoPanVolume [ panIndex ] ;
volRight = gStereoPanVolume [ 127 - panIndex ] ;
if ( panIndex < 0x20 ) {
strongLeft = TRUE ;
} else if ( panIndex > 0x60 ) {
strongRight = TRUE ;
}
note - > stereoStrongRight = strongRight ;
note - > stereoStrongLeft = strongLeft ;
2023-06-07 13:58:59 -04:00
# endif
2019-08-25 00:46:40 -04:00
} else {
volLeft = gDefaultPanVolume [ panIndex ] ;
volRight = gDefaultPanVolume [ 127 - panIndex ] ;
}
2020-04-03 14:57:26 -04:00
if ( velocity < 0 ) {
velocity = 0 ;
}
2023-06-07 06:46:25 -04:00
note - > targetVolLeft = ( u16 ) ( s32 ) ( velocity * volLeft ) & VOLRAMPING_MASK ;
note - > targetVolRight = ( u16 ) ( s32 ) ( velocity * volRight ) & VOLRAMPING_MASK ;
2019-08-25 00:46:40 -04:00
if ( note - > targetVolLeft = = 0 ) {
note - > targetVolLeft + + ;
}
if ( note - > targetVolRight = = 0 ) {
note - > targetVolRight + + ;
}
2021-07-12 23:17:54 -04:00
if ( note - > reverbVol ! = reverbVol ) {
note - > reverbVol = reverbVol ;
note - > reverbVolShifted = reverbVol < < 8 ;
2019-11-03 14:36:27 -05:00
note - > envMixerNeedsInit = TRUE ;
2019-08-25 00:46:40 -04:00
return ;
}
2021-12-30 10:57:51 -06:00
note - > envMixerNeedsInit = note - > needsInit ;
2019-08-25 00:46:40 -04:00
}
void note_set_frequency ( struct Note * note , f32 frequency ) {
note - > frequency = frequency ;
}
void note_enable ( struct Note * note ) {
note - > enabled = TRUE ;
2019-11-03 14:36:27 -05:00
note - > needsInit = TRUE ;
note - > restart = FALSE ;
note - > finished = FALSE ;
2023-06-07 13:58:59 -04:00
# ifdef ENABLE_STEREO_HEADSET_EFFECTS
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 ;
2023-05-05 18:10:26 -04:00
note - > initFullVelocity = FALSE ;
2019-08-25 00:46:40 -04:00
note - > headsetPanLeft = 0 ;
note - > headsetPanRight = 0 ;
note - > prevHeadsetPanRight = 0 ;
note - > prevHeadsetPanLeft = 0 ;
2023-06-07 13:58:59 -04:00
# endif
2019-08-25 00:46:40 -04:00
}
void note_disable ( struct Note * note ) {
2021-12-30 10:57:51 -06:00
if ( note - > needsInit ) {
2019-11-03 14:36:27 -05:00
note - > needsInit = FALSE ;
2019-08-25 00:46:40 -04:00
} else {
2021-12-30 10:57:51 -06:00
note_set_vel_pan_reverb ( note , 0 , 0.5f , 0 ) ;
2019-08-25 00:46:40 -04:00
}
note - > priority = NOTE_PRIORITY_DISABLED ;
note - > enabled = FALSE ;
2019-11-03 14:36:27 -05:00
note - > finished = FALSE ;
2019-08-25 00:46:40 -04:00
note - > parentLayer = NO_LAYER ;
note - > prevParentLayer = NO_LAYER ;
}
2020-02-03 00:51:26 -05:00
# endif
2021-07-12 23:17:54 -04:00
# endif