sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

synthesis.c (64091B)


      1 #if !defined(VERSION_SH) && !defined(VERSION_CN)
      2 #include <ultra64.h>
      3 
      4 #include "synthesis.h"
      5 #include "heap.h"
      6 #include "data.h"
      7 #include "load.h"
      8 #include "seqplayer.h"
      9 #include "internal.h"
     10 #include "external.h"
     11 
     12 
     13 #define DMEM_ADDR_TEMP 0x0
     14 #define DMEM_ADDR_RESAMPLED 0x20
     15 #define DMEM_ADDR_RESAMPLED2 0x160
     16 #define DMEM_ADDR_UNCOMPRESSED_NOTE 0x180
     17 #define DMEM_ADDR_NOTE_PAN_TEMP 0x200
     18 #define DMEM_ADDR_STEREO_STRONG_TEMP_DRY 0x200
     19 #define DMEM_ADDR_STEREO_STRONG_TEMP_WET 0x340
     20 #define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x3f0
     21 #define DMEM_ADDR_LEFT_CH 0x4c0
     22 #define DMEM_ADDR_RIGHT_CH 0x600
     23 #define DMEM_ADDR_WET_LEFT_CH 0x740
     24 #define DMEM_ADDR_WET_RIGHT_CH 0x880
     25 
     26 #define aSetLoadBufferPair(pkt, c, off)                                                                \
     27     aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_LEFT_CH, 0, DEFAULT_LEN_1CH - c);                             \
     28     aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off)));                  \
     29     aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_RIGHT_CH, 0, DEFAULT_LEN_1CH - c);                            \
     30     aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)))
     31 
     32 #define aSetSaveBufferPair(pkt, c, d, off)                                                             \
     33     aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_LEFT_CH, d);                                               \
     34     aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left +  (off)));                 \
     35     aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_RIGHT_CH, d);                                              \
     36     aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)));
     37 
     38 #define ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1))
     39 
     40 struct VolumeChange {
     41     u16 sourceLeft;
     42     u16 sourceRight;
     43     u16 targetLeft;
     44     u16 targetRight;
     45 };
     46 
     47 u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex);
     48 #ifdef VERSION_EU
     49 u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s16 *aiBuf, s32 bufLen, u64 *cmd);
     50 u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad);
     51 u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags);
     52 u64 *process_envelope(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, u32 flags);
     53 u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight);
     54 #else
     55 u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd);
     56 u64 *load_wave_samples(u64 *cmd, struct Note *note, s32 nSamplesToLoad);
     57 u64 *final_resample(u64 *cmd, struct Note *note, s32 count, u16 pitch, u16 dmemIn, u32 flags);
     58 u64 *process_envelope(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf, s32 headsetPanSettings,
     59                       u32 flags);
     60 u64 *process_envelope_inner(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf,
     61                             s32 headsetPanSettings, struct VolumeChange *vol);
     62 u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 flags, s32 leftRight);
     63 #endif
     64 
     65 #ifdef VERSION_EU
     66 struct SynthesisReverb gSynthesisReverbs[4];
     67 u8 sAudioSynthesisPad[0x10];
     68 #else
     69 struct SynthesisReverb gSynthesisReverb;
     70 u8 sAudioSynthesisPad[0x20];
     71 #endif
     72 
     73 #ifdef VERSION_EU
     74 s16 gVolume;
     75 s8 gUseReverb;
     76 s8 gNumSynthesisReverbs;
     77 struct NoteSubEu *gNoteSubsEu;
     78 #endif
     79 
     80 #ifdef VERSION_EU
     81 f32 gLeftVolRampings[3][1024];
     82 f32 gRightVolRampings[3][1024];
     83 f32 *gCurrentLeftVolRamping; // Points to any of the three left buffers above
     84 f32 *gCurrentRightVolRamping; // Points to any of the three right buffers above
     85 
     86 u8 audioString1[] = "pitch %x: delaybytes %d : olddelay %d\n";
     87 u8 audioString2[] = "cont %x: delaybytes %d : olddelay %d\n";
     88 #endif
     89 
     90 #ifdef VERSION_EU
     91 // Equivalent functionality as the US/JP version,
     92 // just that the reverb structure is chosen from an array with index
     93 void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex) {
     94     struct ReverbRingBufferItem *item;
     95     struct SynthesisReverb *reverb = &gSynthesisReverbs[reverbIndex];
     96     s32 srcPos;
     97     s32 dstPos;
     98     s32 nSamples;
     99     s32 excessiveSamples;
    100     s32 UNUSED pad[3];
    101     if (reverb->downsampleRate != 1) {
    102         if (reverb->framesLeftToIgnore == 0) {
    103             // Now that the RSP has finished, downsample the samples produced two frames ago by skipping
    104             // samples.
    105             item = &reverb->items[reverb->curFrame][updateIndex];
    106 
    107             // Touches both left and right since they are adjacent in memory
    108             osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
    109 
    110             for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
    111                  srcPos += reverb->downsampleRate, dstPos++) {
    112                 reverb->ringBuffer.left[item->startPos + dstPos] =
    113                     item->toDownsampleLeft[srcPos];
    114                 reverb->ringBuffer.right[item->startPos + dstPos] =
    115                     item->toDownsampleRight[srcPos];
    116             }
    117             for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += reverb->downsampleRate, dstPos++) {
    118                 reverb->ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
    119                 reverb->ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
    120             }
    121         }
    122     }
    123 
    124     item = &reverb->items[reverb->curFrame][updateIndex];
    125     nSamples = chunkLen / reverb->downsampleRate;
    126     excessiveSamples = (nSamples + reverb->nextRingBufferPos) - reverb->bufSizePerChannel;
    127     if (excessiveSamples < 0) {
    128         // There is space in the ring buffer before it wraps around
    129         item->lengthA = nSamples * 2;
    130         item->lengthB = 0;
    131         item->startPos = (s32) reverb->nextRingBufferPos;
    132         reverb->nextRingBufferPos += nSamples;
    133     } else {
    134         // Ring buffer wrapped around
    135         item->lengthA = (nSamples - excessiveSamples) * 2;
    136         item->lengthB = excessiveSamples * 2;
    137         item->startPos = reverb->nextRingBufferPos;
    138         reverb->nextRingBufferPos = excessiveSamples;
    139     }
    140     // These fields are never read later
    141     item->numSamplesAfterDownsampling = nSamples;
    142     item->chunkLen = chunkLen;
    143 }
    144 #else
    145 void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) {
    146     struct ReverbRingBufferItem *item;
    147     s32 srcPos;
    148     s32 dstPos;
    149     s32 nSamples;
    150     s32 numSamplesAfterDownsampling;
    151     s32 excessiveSamples;
    152     if (gReverbDownsampleRate != 1) {
    153         if (gSynthesisReverb.framesLeftToIgnore == 0) {
    154             // Now that the RSP has finished, downsample the samples produced two frames ago by skipping
    155             // samples.
    156             item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
    157 
    158             // Touches both left and right since they are adjacent in memory
    159             osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
    160 
    161             for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
    162                  srcPos += gReverbDownsampleRate, dstPos++) {
    163                 gSynthesisReverb.ringBuffer.left[dstPos + item->startPos] =
    164                     item->toDownsampleLeft[srcPos];
    165                 gSynthesisReverb.ringBuffer.right[dstPos + item->startPos] =
    166                     item->toDownsampleRight[srcPos];
    167             }
    168             for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) {
    169                 gSynthesisReverb.ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
    170                 gSynthesisReverb.ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
    171             }
    172         }
    173     }
    174     item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
    175 
    176     numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate;
    177     if (((numSamplesAfterDownsampling + gSynthesisReverb.nextRingBufferPos) - gSynthesisReverb.bufSizePerChannel) < 0) {
    178         // There is space in the ring buffer before it wraps around
    179         item->lengthA = numSamplesAfterDownsampling * 2;
    180         item->lengthB = 0;
    181         item->startPos = (s32) gSynthesisReverb.nextRingBufferPos;
    182         gSynthesisReverb.nextRingBufferPos += numSamplesAfterDownsampling;
    183     } else {
    184         // Ring buffer wrapped around
    185         excessiveSamples =
    186             (numSamplesAfterDownsampling + gSynthesisReverb.nextRingBufferPos) - gSynthesisReverb.bufSizePerChannel;
    187         nSamples = numSamplesAfterDownsampling - excessiveSamples;
    188         item->lengthA = nSamples * 2;
    189         item->lengthB = excessiveSamples * 2;
    190         item->startPos = gSynthesisReverb.nextRingBufferPos;
    191         gSynthesisReverb.nextRingBufferPos = excessiveSamples;
    192     }
    193     // These fields are never read later
    194     item->numSamplesAfterDownsampling = numSamplesAfterDownsampling;
    195     item->chunkLen = chunkLen;
    196 }
    197 #endif
    198 
    199 #ifdef VERSION_EU
    200 u64 *synthesis_load_reverb_ring_buffer(u64 *cmd, u16 addr, u16 srcOffset, s32 len, s32 reverbIndex) {
    201     aSetBuffer(cmd++, 0, addr, 0, len);
    202     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[srcOffset]));
    203 
    204     aSetBuffer(cmd++, 0, addr + DEFAULT_LEN_1CH, 0, len);
    205     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[srcOffset]));
    206 
    207     return cmd;
    208 }
    209 #endif
    210 
    211 #ifdef VERSION_EU
    212 u64 *synthesis_save_reverb_ring_buffer(u64 *cmd, u16 addr, u16 destOffset, s32 len, s32 reverbIndex) {
    213     aSetBuffer(cmd++, 0, 0, addr, len);
    214     aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[destOffset]));
    215 
    216     aSetBuffer(cmd++, 0, 0, addr + DEFAULT_LEN_1CH, len);
    217     aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[destOffset]));
    218 
    219     return cmd;
    220 }
    221 #endif
    222 
    223 #ifdef VERSION_EU
    224 void synthesis_load_note_subs_eu(s32 updateIndex) {
    225     struct NoteSubEu *src;
    226     struct NoteSubEu *dest;
    227     s32 i;
    228 
    229     for (i = 0; i < gMaxSimultaneousNotes; i++) {
    230         src = &gNotes[i].noteSubEu;
    231         dest = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
    232         if (src->enabled) {
    233             *dest = *src;
    234             src->needsInit = FALSE;
    235         } else {
    236             dest->enabled = FALSE;
    237         }
    238     }
    239 }
    240 #endif
    241 
    242 #ifndef VERSION_EU
    243 s32 get_volume_ramping(u16 sourceVol, u16 targetVol, s32 arg2) {
    244     // This roughly computes 2^16 * (targetVol / sourceVol) ^ (8 / arg2),
    245     // but with discretizations of targetVol, sourceVol and arg2.
    246     f32 ret;
    247     switch (arg2) {
    248         default:
    249             ret = gVolRampingLhs136[targetVol >> 8] * gVolRampingRhs136[sourceVol >> 8];
    250             break;
    251         case 128:
    252             ret = gVolRampingLhs128[targetVol >> 8] * gVolRampingRhs128[sourceVol >> 8];
    253             break;
    254         case 136:
    255             ret = gVolRampingLhs136[targetVol >> 8] * gVolRampingRhs136[sourceVol >> 8];
    256             break;
    257         case 144:
    258             ret = gVolRampingLhs144[targetVol >> 8] * gVolRampingRhs144[sourceVol >> 8];
    259             break;
    260     }
    261     return ret;
    262 }
    263 #endif
    264 
    265 #ifdef VERSION_EU
    266 // TODO: (Scrub C) pointless mask and whitespace
    267 u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
    268     s32 i, j;
    269     f32 *leftVolRamp;
    270     f32 *rightVolRamp;
    271     u32 *aiBufPtr;
    272     u64 *cmd = cmdBuf;
    273     s32 chunkLen;
    274     s32 nextVolRampTable;
    275 
    276     for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
    277         process_sequences(i - 1);
    278         synthesis_load_note_subs_eu(gAudioBufferParameters.updatesPerFrame - i);
    279     }
    280     aSegment(cmd++, 0, 0);
    281     aiBufPtr = (u32 *) aiBuf;
    282     for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
    283         if (i == 1) {
    284 #pragma GCC diagnostic push
    285 #if defined(__clang__)
    286 #pragma GCC diagnostic ignored "-Wself-assign"
    287 #endif
    288             // self-assignment has no affect when added here, could possibly simplify a macro definition
    289             chunkLen = bufLen; nextVolRampTable = nextVolRampTable; leftVolRamp = gLeftVolRampings[nextVolRampTable]; rightVolRamp = gRightVolRampings[nextVolRampTable & 0xFFFFFFFF];
    290 #pragma GCC diagnostic pop
    291         } else {
    292             if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) {
    293                 chunkLen = gAudioBufferParameters.samplesPerUpdateMax; nextVolRampTable = 2; leftVolRamp = gLeftVolRampings[2]; rightVolRamp = gRightVolRampings[2];
    294             } else if (bufLen / i <= gAudioBufferParameters.samplesPerUpdateMin) {
    295                 chunkLen = gAudioBufferParameters.samplesPerUpdateMin; nextVolRampTable = 0; leftVolRamp = gLeftVolRampings[0]; rightVolRamp = gRightVolRampings[0];
    296             } else {
    297                 chunkLen = gAudioBufferParameters.samplesPerUpdate; nextVolRampTable = 1; leftVolRamp = gLeftVolRampings[1]; rightVolRamp = gRightVolRampings[1];
    298             }
    299         }
    300         gCurrentLeftVolRamping = leftVolRamp;
    301         gCurrentRightVolRamping = rightVolRamp;
    302         for (j = 0; j < gNumSynthesisReverbs; j++) {
    303             if (gSynthesisReverbs[j].useReverb != 0) {
    304                 prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j);
    305             }
    306         }
    307         cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioBufferParameters.updatesPerFrame - i);
    308         bufLen -= chunkLen;
    309         aiBufPtr += chunkLen;
    310     }
    311 
    312     for (j = 0; j < gNumSynthesisReverbs; j++) {
    313         if (gSynthesisReverbs[j].framesLeftToIgnore != 0) {
    314             gSynthesisReverbs[j].framesLeftToIgnore--;
    315         }
    316         gSynthesisReverbs[j].curFrame ^= 1;
    317     }
    318     *writtenCmds = cmd - cmdBuf;
    319     return cmd;
    320 }
    321 #else
    322 // bufLen will be divisible by 16
    323 u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
    324     s32 chunkLen;
    325     s32 i;
    326     u32 *aiBufPtr = (u32 *) aiBuf;
    327     u64 *cmd = cmdBuf + 1;
    328     s32 v0;
    329 
    330     aSegment(cmdBuf, 0, 0);
    331 
    332     for (i = gAudioUpdatesPerFrame; i > 0; i--) {
    333         if (i == 1) {
    334             // 'bufLen' will automatically be divisible by 8, no need to round
    335             chunkLen = bufLen;
    336         } else {
    337             v0 = bufLen / i;
    338             // chunkLen = v0 rounded to nearest multiple of 8
    339             chunkLen = v0 - (v0 & 7);
    340 
    341             if ((v0 & 7) >= 4) {
    342                 chunkLen += 8;
    343             }
    344         }
    345         process_sequences(i - 1);
    346         if (gSynthesisReverb.useReverb != 0) {
    347             prepare_reverb_ring_buffer(chunkLen, gAudioUpdatesPerFrame - i);
    348         }
    349         cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioUpdatesPerFrame - i);
    350         bufLen -= chunkLen;
    351         aiBufPtr += chunkLen;
    352     }
    353     if (gSynthesisReverb.framesLeftToIgnore != 0) {
    354         gSynthesisReverb.framesLeftToIgnore--;
    355     }
    356     gSynthesisReverb.curFrame ^= 1;
    357     *writtenCmds = cmd - cmdBuf;
    358     return cmd;
    359 }
    360 #endif
    361 
    362 
    363 #ifdef VERSION_EU
    364 u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s16 updateIndex) {
    365     struct ReverbRingBufferItem *item;
    366     s16 startPad;
    367     s16 paddedLengthA;
    368 
    369     item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
    370 
    371     aClearBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
    372     if (gSynthesisReverbs[reverbIndex].downsampleRate == 1) {
    373         cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
    374         if (item->lengthB != 0) {
    375             cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
    376         }
    377         aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
    378         aMix(cmd++, 0, 0x7fff, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH);
    379         aMix(cmd++, 0, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH);
    380     } else {
    381         startPad = (item->startPos % 8u) * 2;
    382         paddedLengthA = ALIGN(startPad + item->lengthA, 4);
    383 
    384         cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, (item->startPos - startPad / 2), DEFAULT_LEN_1CH, reverbIndex);
    385         if (item->lengthB != 0) {
    386             cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + paddedLengthA, 0, DEFAULT_LEN_1CH - paddedLengthA, reverbIndex);
    387         }
    388 
    389         aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED + startPad, DMEM_ADDR_WET_LEFT_CH, bufLen * 2);
    390         aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateLeft));
    391 
    392         aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED2 + startPad, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2);
    393         aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateRight));
    394 
    395         aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
    396         aMix(cmd++, 0, 0x7fff, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH);
    397         aMix(cmd++, 0, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH);
    398     }
    399     return cmd;
    400 }
    401 
    402 u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
    403     struct ReverbRingBufferItem *item;
    404 
    405     item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
    406     if (gSynthesisReverbs[reverbIndex].useReverb != 0) {
    407         switch (gSynthesisReverbs[reverbIndex].downsampleRate) {
    408             case 1:
    409                 // Put the oldest samples in the ring buffer into the wet channels
    410                 cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
    411                 if (item->lengthB != 0) {
    412                     // Ring buffer wrapped
    413                     cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
    414                 }
    415                 break;
    416 
    417             default:
    418                 // Downsampling is done later by CPU when RSP is done, therefore we need to have double
    419                 // buffering. Left and right buffers are adjacent in memory.
    420                 aSetBuffer(cmd++, 0, 0, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
    421                 aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex].toDownsampleLeft));
    422                 gSynthesisReverbs[reverbIndex].resampleFlags = 0;
    423                 break;
    424         }
    425     }
    426     return cmd;
    427 }
    428 #endif
    429 
    430 #ifdef VERSION_EU
    431 u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
    432     struct NoteSubEu *noteSubEu;
    433     u8 noteIndices[56];
    434     s32 temp;
    435     s32 i;
    436     s16 j;
    437     s16 notePos = 0;
    438 
    439     if (gNumSynthesisReverbs == 0) {
    440         for (i = 0; i < gMaxSimultaneousNotes; i++) {
    441             if (gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i].enabled) {
    442                 noteIndices[notePos++] = i;
    443             }
    444         }
    445     } else {
    446         for (j = 0; j < gNumSynthesisReverbs; j++) {
    447             for (i = 0; i < gMaxSimultaneousNotes; i++) {
    448                 noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
    449                 if (noteSubEu->enabled && j == noteSubEu->reverbIndex) {
    450                     noteIndices[notePos++] = i;
    451                 }
    452             }
    453         }
    454 
    455         for (i = 0; i < gMaxSimultaneousNotes; i++) {
    456             noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
    457             if (noteSubEu->enabled && noteSubEu->reverbIndex >= gNumSynthesisReverbs) {
    458                 noteIndices[notePos++] = i;
    459             }
    460         }
    461     }
    462     aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
    463     i = 0;
    464     for (j = 0; j < gNumSynthesisReverbs; j++) {
    465         gUseReverb = gSynthesisReverbs[j].useReverb;
    466         if (gUseReverb != 0) {
    467             cmd = synthesis_resample_and_mix_reverb(cmd, bufLen, j, updateIndex);
    468         }
    469         for (; i < notePos; i++) {
    470             temp = updateIndex * gMaxSimultaneousNotes;
    471             if (j == gNoteSubsEu[temp + noteIndices[i]].reverbIndex) {
    472                 cmd = synthesis_process_note(&gNotes[noteIndices[i]],
    473                                              &gNoteSubsEu[temp + noteIndices[i]],
    474                                              &gNotes[noteIndices[i]].synthesisState,
    475                                              aiBuf, bufLen, cmd);
    476                 continue;
    477             } else {
    478                 break;
    479             }
    480         }
    481         if (gSynthesisReverbs[j].useReverb != 0) {
    482             cmd = synthesis_save_reverb_samples(cmd, j, updateIndex);
    483         }
    484     }
    485     for (; i < notePos; i++) {
    486         temp = updateIndex * gMaxSimultaneousNotes;
    487         if (IS_BANK_LOAD_COMPLETE(gNoteSubsEu[temp + noteIndices[i]].bankId) == TRUE) {
    488             cmd = synthesis_process_note(&gNotes[noteIndices[i]],
    489                                          &gNoteSubsEu[temp + noteIndices[i]],
    490                                          &gNotes[noteIndices[i]].synthesisState,
    491                                          aiBuf, bufLen, cmd);
    492         } else {
    493             gAudioErrorFlags = (gNoteSubsEu[temp + noteIndices[i]].bankId + (i << 8)) + 0x10000000;
    494         }
    495     }
    496 
    497     temp = bufLen * 2;
    498     aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, temp);
    499     aInterleave(cmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH);
    500     aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, temp * 2);
    501     aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(aiBuf));
    502     return cmd;
    503 }
    504 #else
    505 u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
    506     UNUSED s32 pad1[1];
    507     s16 ra;
    508     s16 t4;
    509     UNUSED s32 pad[2];
    510     struct ReverbRingBufferItem *v1;
    511     UNUSED s32 pad2[1];
    512     s16 temp;
    513 
    514     v1 = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
    515 
    516     if (gSynthesisReverb.useReverb == 0) {
    517         aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
    518         cmd = synthesis_process_notes(aiBuf, bufLen, cmd);
    519     } else {
    520         if (gReverbDownsampleRate == 1) {
    521             // Put the oldest samples in the ring buffer into the wet channels
    522             aSetLoadBufferPair(cmd++, 0, v1->startPos);
    523             if (v1->lengthB != 0) {
    524                 // Ring buffer wrapped
    525                 aSetLoadBufferPair(cmd++, v1->lengthA, 0);
    526                 temp = 0;
    527             }
    528 
    529             // Use the reverb sound as initial sound for this audio update
    530             aDMEMMove(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
    531 
    532             // (Hopefully) lower the volume of the wet channels. New reverb will later be mixed into
    533             // these channels.
    534             aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
    535             // 0x8000 here is -100%
    536             aMix(cmd++, 0, /*gain*/ 0x8000 + gSynthesisReverb.reverbGain, /*in*/ DMEM_ADDR_WET_LEFT_CH,
    537                  /*out*/ DMEM_ADDR_WET_LEFT_CH);
    538         } else {
    539             // Same as above but upsample the previously downsampled samples used for reverb first
    540             temp = 0; //! jesus christ
    541             t4 = (v1->startPos & 7) * 2;
    542             ra = ALIGN(v1->lengthA + t4, 4);
    543             aSetLoadBufferPair(cmd++, 0, v1->startPos - t4 / 2);
    544             if (v1->lengthB != 0) {
    545                 // Ring buffer wrapped
    546                 aSetLoadBufferPair(cmd++, ra, 0);
    547                 //! We need an empty statement (even an empty ';') here to make the function match (because IDO).
    548                 //! However, copt removes extraneous statements and dead code. So we need to trick copt
    549                 //! into thinking 'temp' could be undefined, and luckily the compiler optimizes out the
    550                 //! useless assignment.
    551                 ra = ra + temp;
    552             }
    553             aSetBuffer(cmd++, 0, t4 + DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, bufLen << 1);
    554             aResample(cmd++, gSynthesisReverb.resampleFlags, (u16) gSynthesisReverb.resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.resampleStateLeft));
    555             aSetBuffer(cmd++, 0, t4 + DMEM_ADDR_WET_RIGHT_CH, DMEM_ADDR_RIGHT_CH, bufLen << 1);
    556             aResample(cmd++, gSynthesisReverb.resampleFlags, (u16) gSynthesisReverb.resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.resampleStateRight));
    557             aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
    558             aMix(cmd++, 0, /*gain*/ 0x8000 + gSynthesisReverb.reverbGain, /*in*/ DMEM_ADDR_LEFT_CH, /*out*/ DMEM_ADDR_LEFT_CH);
    559             aDMEMMove(cmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
    560         }
    561         cmd = synthesis_process_notes(aiBuf, bufLen, cmd);
    562         if (gReverbDownsampleRate == 1) {
    563             aSetSaveBufferPair(cmd++, 0, v1->lengthA, v1->startPos);
    564             if (v1->lengthB != 0) {
    565                 // Ring buffer wrapped
    566                 aSetSaveBufferPair(cmd++, v1->lengthA, v1->lengthB, 0);
    567             }
    568         } else {
    569             // Downsampling is done later by CPU when RSP is done, therefore we need to have double
    570             // buffering. Left and right buffers are adjacent in memory.
    571             aSetBuffer(cmd++, 0, 0, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
    572             aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex].toDownsampleLeft));
    573             gSynthesisReverb.resampleFlags = 0;
    574         }
    575     }
    576     return cmd;
    577 }
    578 #endif
    579 
    580 #ifdef VERSION_EU
    581 // Processes just one note, not all
    582 u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, UNUSED s16 *aiBuf, s32 bufLen, u64 *cmd) {
    583     UNUSED s32 pad0[3];
    584 #else
    585 u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) {
    586     s32 noteIndex;                           // sp174
    587     struct Note *note;                       // s7
    588     UNUSED u8 pad0[0x08];
    589 #endif
    590     struct AudioBankSample *audioBookSample; // sp164, sp138
    591     struct AdpcmLoop *loopInfo;              // sp160, sp134
    592     s16 *curLoadedBook = NULL;               // sp154, sp130
    593 #ifdef VERSION_EU
    594     UNUSED u8 padEU[0x04];
    595 #endif
    596     UNUSED u8 pad8[0x04];
    597 #ifndef VERSION_EU
    598     u16 resamplingRateFixedPoint;            // sp5c, sp11A
    599 #endif
    600     s32 noteFinished;                        // 150 t2, sp124
    601     s32 restart;                             // 14c t3, sp120
    602     s32 flags;                               // sp148, sp11C
    603 #ifdef VERSION_EU
    604     u16 resamplingRateFixedPoint;            // sp5c, sp11A
    605 #endif
    606     UNUSED u8 pad7[0x0c];                    // sp100
    607     UNUSED s32 tempBufLen;
    608 #ifdef VERSION_EU
    609     s32 sp130;  //sp128, sp104
    610     UNUSED u32 pad9;
    611 #else
    612     UNUSED u32 pad9;
    613     s32 sp130;  //sp128, sp104
    614 #endif
    615     s32 nAdpcmSamplesProcessed; // signed required for US
    616     s32 t0;
    617 #ifdef VERSION_EU
    618     u8 *sampleAddr;                          // sp120, spF4
    619     s32 s6;
    620 #else
    621     s32 s6;
    622     u8 *sampleAddr;                          // sp120, spF4
    623 #endif
    624 
    625 #ifdef VERSION_EU
    626     s32 samplesLenAdjusted; // 108,      spEC
    627     // Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
    628     // behavior with the break near the end of the loop, causing US and JP to need a goto instead
    629     UNUSED s32 samplesLenInt;
    630     s32 endPos;             // sp110,    spE4
    631     s32 nSamplesToProcess;  // sp10c/a0, spE0
    632     s32 s2;
    633 #else
    634     // Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
    635     // behavior with the break near the end of the loop, causing US and JP to need a goto instead
    636     UNUSED s32 samplesLenInt;
    637     s32 samplesLenAdjusted; // 108
    638     s32 s2;
    639     s32 endPos;             // sp110,    spE4
    640     s32 nSamplesToProcess;  // sp10c/a0, spE0
    641 #endif
    642 
    643     s32 leftRight;
    644     s32 s3;
    645     s32 s5; //s4
    646 
    647     u32 samplesLenFixedPoint;    // v1_1
    648     s32 nSamplesInThisIteration; // v1_2
    649     u32 a3;
    650 #ifndef VERSION_EU
    651     s32 t9;
    652 #endif
    653     u8 *v0_2;
    654     s32 nParts;                 // spE8, spBC
    655     s32 curPart;                // spE4, spB8
    656 
    657 #ifndef VERSION_EU
    658     f32 resamplingRate; // f12
    659 #endif
    660     s32 temp;
    661 
    662 #ifdef VERSION_EU
    663     s32 s5Aligned;
    664 #endif
    665     s32 resampledTempLen;                    // spD8, spAC
    666     u16 noteSamplesDmemAddrBeforeResampling; // spD6, spAA
    667 
    668 
    669 #ifndef VERSION_EU
    670     for (noteIndex = 0; noteIndex < gMaxSimultaneousNotes; noteIndex++) {
    671         note = &gNotes[noteIndex];
    672 #ifdef VERSION_US
    673         //! This function requires note->enabled to be volatile, but it breaks other functions like note_enable.
    674         //! Casting to a struct with just the volatile bitfield works, but there may be a better way to match.
    675         if (((struct vNote *)note)->enabled && IS_BANK_LOAD_COMPLETE(note->bankId) == FALSE) {
    676 #else
    677         if (IS_BANK_LOAD_COMPLETE(note->bankId) == FALSE) {
    678 #endif
    679             gAudioErrorFlags = (note->bankId << 8) + noteIndex + 0x1000000;
    680         } else if (((struct vNote *)note)->enabled) {
    681 #else
    682         if (note->noteSubEu.enabled == FALSE) {
    683             return cmd;
    684         } else {
    685 #endif
    686             flags = 0;
    687 #ifdef VERSION_EU
    688             tempBufLen = bufLen;
    689 #endif
    690 
    691 #ifdef VERSION_EU
    692             if (noteSubEu->needsInit == TRUE) {
    693 #else
    694             if (note->needsInit == TRUE) {
    695 #endif
    696                 flags = A_INIT;
    697 #ifndef VERSION_EU
    698                 note->samplePosInt = 0;
    699                 note->samplePosFrac = 0;
    700 #else
    701                 synthesisState->restart = FALSE;
    702                 synthesisState->samplePosInt = 0;
    703                 synthesisState->samplePosFrac = 0;
    704                 synthesisState->curVolLeft = 1;
    705                 synthesisState->curVolRight = 1;
    706                 synthesisState->prevHeadsetPanRight = 0;
    707                 synthesisState->prevHeadsetPanLeft = 0;
    708 #endif
    709             }
    710 
    711 #ifndef VERSION_EU
    712             if (note->frequency < US_FLOAT(2.0)) {
    713                 nParts = 1;
    714                 if (note->frequency > US_FLOAT(1.99996)) {
    715                     note->frequency = US_FLOAT(1.99996);
    716                 }
    717                 resamplingRate = note->frequency;
    718             } else {
    719                 // If frequency is > 2.0, the processing must be split into two parts
    720                 nParts = 2;
    721                 if (note->frequency >= US_FLOAT(3.99993)) {
    722                     note->frequency = US_FLOAT(3.99993);
    723                 }
    724                 resamplingRate = note->frequency * US_FLOAT(.5);
    725             }
    726 
    727             resamplingRateFixedPoint = (u16)(s32)(resamplingRate * 32768.0f);
    728             samplesLenFixedPoint = note->samplePosFrac + (resamplingRateFixedPoint * bufLen) * 2;
    729             note->samplePosFrac = samplesLenFixedPoint & 0xFFFF; // 16-bit store, can't reuse
    730 #else
    731             resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint;
    732             nParts = noteSubEu->hasTwoAdpcmParts + 1;
    733             samplesLenFixedPoint = (resamplingRateFixedPoint * tempBufLen * 2) + synthesisState->samplePosFrac;
    734             synthesisState->samplePosFrac = samplesLenFixedPoint & 0xFFFF;
    735 #endif
    736 
    737 #ifdef VERSION_EU
    738             if (noteSubEu->isSyntheticWave) {
    739                 cmd = load_wave_samples(cmd, noteSubEu, synthesisState, samplesLenFixedPoint >> 0x10);
    740                 noteSamplesDmemAddrBeforeResampling = (synthesisState->samplePosInt * 2) + DMEM_ADDR_UNCOMPRESSED_NOTE;
    741                 synthesisState->samplePosInt += samplesLenFixedPoint >> 0x10;
    742             }
    743 #else
    744             if (note->sound == NULL) {
    745                 // A wave synthesis note (not ADPCM)
    746 
    747                 cmd = load_wave_samples(cmd, note, samplesLenFixedPoint >> 0x10);
    748                 noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + note->samplePosInt * 2;
    749                 note->samplePosInt += (samplesLenFixedPoint >> 0x10);
    750                 flags = 0;
    751             }
    752 #endif
    753             else {
    754                 // ADPCM note
    755 
    756 #ifdef VERSION_EU
    757                 audioBookSample = noteSubEu->sound.audioBankSound->sample;
    758 #else
    759                 audioBookSample = note->sound->sample;
    760 #endif
    761 
    762                 loopInfo = audioBookSample->loop;
    763                 endPos = loopInfo->end;
    764                 sampleAddr = audioBookSample->sampleAddr;
    765                 resampledTempLen = 0;
    766                 for (curPart = 0; curPart < nParts; curPart++) {
    767                     nAdpcmSamplesProcessed = 0; // s8
    768                     s5 = 0;                     // s4
    769 
    770                     if (nParts == 1) {
    771                         samplesLenAdjusted = samplesLenFixedPoint >> 0x10;
    772                     } else if ((samplesLenFixedPoint >> 0x10) & 1) {
    773                         samplesLenAdjusted = ((samplesLenFixedPoint >> 0x10) & ~1) + (curPart * 2);
    774                     }
    775                     else {
    776                         samplesLenAdjusted = (samplesLenFixedPoint >> 0x10);
    777                     }
    778 
    779                     if (curLoadedBook != audioBookSample->book->book) {
    780                         u32 nEntries; // v1
    781                         curLoadedBook = audioBookSample->book->book;
    782 #ifdef VERSION_EU
    783                         nEntries = 16 * audioBookSample->book->order * audioBookSample->book->npredictors;
    784                         aLoadADPCM(cmd++, nEntries, VIRTUAL_TO_PHYSICAL2(curLoadedBook + noteSubEu->bookOffset));
    785 #else
    786                         nEntries = audioBookSample->book->order * audioBookSample->book->npredictors;
    787                         aLoadADPCM(cmd++, nEntries * 16, VIRTUAL_TO_PHYSICAL2(curLoadedBook));
    788 #endif
    789                     }
    790 
    791 #ifdef VERSION_EU
    792                     if (noteSubEu->bookOffset) {
    793                         curLoadedBook = euUnknownData_80301950; // what's this? never read
    794                     }
    795 #endif
    796 
    797                     while (nAdpcmSamplesProcessed != samplesLenAdjusted) {
    798                         s32 samplesRemaining; // v1
    799                         s32 s0;
    800 
    801                         noteFinished = FALSE;
    802                         restart = FALSE;
    803                         nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed;
    804 #ifdef VERSION_EU
    805                         s2 = synthesisState->samplePosInt & 0xf;
    806                         samplesRemaining = endPos - synthesisState->samplePosInt;
    807 #else
    808                         s2 = note->samplePosInt & 0xf;
    809                         samplesRemaining = endPos - note->samplePosInt;
    810 #endif
    811 
    812 #ifdef VERSION_EU
    813                         if (s2 == 0 && synthesisState->restart == FALSE) {
    814                             s2 = 16;
    815                         }
    816 #else
    817                         if (s2 == 0 && note->restart == FALSE) {
    818                             s2 = 16;
    819                         }
    820 #endif
    821                         s6 = 16 - s2; // a1
    822 
    823                         if (nSamplesToProcess < samplesRemaining) {
    824                             t0 = (nSamplesToProcess - s6 + 0xf) / 16;
    825                             s0 = t0 * 16;
    826                             s3 = s6 + s0 - nSamplesToProcess;
    827                         } else {
    828 #ifndef VERSION_EU
    829                             s0 = samplesRemaining + s2 - 0x10;
    830 #else
    831                             s0 = samplesRemaining - s6;
    832 #endif
    833                             s3 = 0;
    834                             if (s0 <= 0) {
    835                                 s0 = 0;
    836                                 s6 = samplesRemaining;
    837                             }
    838                             t0 = (s0 + 0xf) / 16;
    839                             if (loopInfo->count != 0) {
    840                                 // Loop around and restart
    841                                 restart = 1;
    842                             } else {
    843                                 noteFinished = 1;
    844                             }
    845                         }
    846 
    847                         if (t0 != 0) {
    848 #ifdef VERSION_EU
    849                             temp = (synthesisState->samplePosInt - s2 + 0x10) / 16;
    850                             if (audioBookSample->loaded == 0x81) {
    851                                 v0_2 = sampleAddr + temp * 9;
    852                             } else {
    853                                 v0_2 = dma_sample_data(
    854                                     (uintptr_t) (sampleAddr + temp * 9),
    855                                     t0 * 9, flags, &synthesisState->sampleDmaIndex);
    856                             }
    857 #else
    858                             temp = (note->samplePosInt - s2 + 0x10) / 16;
    859                             v0_2 = dma_sample_data(
    860                                 (uintptr_t) (sampleAddr + temp * 9),
    861                                 t0 * 9, flags, &note->sampleDmaIndex);
    862 #endif
    863                             a3 = (u32)((uintptr_t) v0_2 & 0xf);
    864                             aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA, 0, t0 * 9 + a3);
    865                             aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(v0_2 - a3));
    866                         } else {
    867                             s0 = 0;
    868                             a3 = 0;
    869                         }
    870 
    871 #ifdef VERSION_EU
    872                         if (synthesisState->restart != FALSE) {
    873                             aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state));
    874                             flags = A_LOOP; // = 2
    875                             synthesisState->restart = FALSE;
    876                         }
    877 #else
    878                         if (note->restart != FALSE) {
    879                             aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state));
    880                             flags = A_LOOP; // = 2
    881                             note->restart = FALSE;
    882                         }
    883 #endif
    884 
    885                         nSamplesInThisIteration = s0 + s6 - s3;
    886 #ifdef VERSION_EU
    887                         if (nAdpcmSamplesProcessed == 0) {
    888                             aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3,
    889                                        DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
    890                             aADPCMdec(cmd++, flags,
    891                                       VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
    892                             sp130 = s2 * 2;
    893                         } else {
    894                             s5Aligned = ALIGN(s5, 5);
    895                             aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3,
    896                                        DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2);
    897                             aADPCMdec(cmd++, flags,
    898                                       VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
    899                             aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned + (s2 * 2),
    900                                       DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2);
    901                         }
    902 #else
    903                         if (nAdpcmSamplesProcessed == 0) {
    904                             aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
    905                             aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->adpcmdecState));
    906                             sp130 = s2 * 2;
    907                         } else {
    908                             aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN(s5, 5), s0 * 2);
    909                             aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->adpcmdecState));
    910                             aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN(s5, 5) + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2);
    911                         }
    912 #endif
    913 
    914                         nAdpcmSamplesProcessed += nSamplesInThisIteration;
    915 
    916                         switch (flags) {
    917                             case A_INIT: // = 1
    918                                 sp130 = 0;
    919                                 s5 = s0 * 2 + s5;
    920                                 break;
    921 
    922                             case A_LOOP: // = 2
    923                                 s5 = nSamplesInThisIteration * 2 + s5;
    924                                 break;
    925 
    926                             default:
    927                                 if (s5 != 0) {
    928                                     s5 = nSamplesInThisIteration * 2 + s5;
    929                                 } else {
    930                                     s5 = (s2 + nSamplesInThisIteration) * 2;
    931                                 }
    932                                 break;
    933                         }
    934                         flags = 0;
    935 
    936                         if (noteFinished) {
    937                             aClearBuffer(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5,
    938                                          (samplesLenAdjusted - nAdpcmSamplesProcessed) * 2);
    939 #ifdef VERSION_EU
    940                             noteSubEu->finished = 1;
    941                             note->noteSubEu.finished = 1;
    942                             note->noteSubEu.enabled = 0;
    943 #else
    944                             note->samplePosInt = 0;
    945                             note->finished = 1;
    946                             ((struct vNote *)note)->enabled = 0;
    947 #endif
    948                             break;
    949                         }
    950 #ifdef VERSION_EU
    951                         if (restart) {
    952                             synthesisState->restart = TRUE;
    953                             synthesisState->samplePosInt = loopInfo->start;
    954                         } else {
    955                             synthesisState->samplePosInt += nSamplesToProcess;
    956                         }
    957 #else
    958                         if (restart) {
    959                             note->restart = TRUE;
    960                             note->samplePosInt = loopInfo->start;
    961                         } else {
    962                             note->samplePosInt += nSamplesToProcess;
    963                         }
    964 #endif
    965                     }
    966 
    967                     switch (nParts) {
    968                         case 1:
    969                             noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + sp130;
    970                             break;
    971 
    972                         case 2:
    973                             switch (curPart) {
    974                                 case 0:
    975                                     aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED, samplesLenAdjusted + 4);
    976 #ifdef VERSION_EU
    977                                     aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->dummyResampleState));
    978 #else
    979                                     aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->dummyResampleState));
    980 #endif
    981                                     resampledTempLen = samplesLenAdjusted + 4;
    982                                     noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED + 4;
    983 #ifdef VERSION_EU
    984                                     if (noteSubEu->finished != FALSE) {
    985 #else
    986                                     if (note->finished != FALSE) {
    987 #endif
    988                                         aClearBuffer(cmd++, DMEM_ADDR_RESAMPLED + resampledTempLen, samplesLenAdjusted + 0x10);
    989                                     }
    990                                     break;
    991 
    992                                 case 1:
    993                                     aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130,
    994                                                DMEM_ADDR_RESAMPLED2,
    995                                                samplesLenAdjusted + 8);
    996 #ifdef VERSION_EU
    997                                     aResample(cmd++, A_INIT, 0xff60,
    998                                               VIRTUAL_TO_PHYSICAL2(
    999                                                   synthesisState->synthesisBuffers->dummyResampleState));
   1000 #else
   1001                                     aResample(cmd++, A_INIT, 0xff60,
   1002                                               VIRTUAL_TO_PHYSICAL2(
   1003                                                   note->synthesisBuffers->dummyResampleState));
   1004 #endif
   1005                                     aDMEMMove(cmd++, DMEM_ADDR_RESAMPLED2 + 4,
   1006                                               DMEM_ADDR_RESAMPLED + resampledTempLen,
   1007                                               samplesLenAdjusted + 4);
   1008                                     break;
   1009                             }
   1010                     }
   1011 
   1012 #ifdef VERSION_EU
   1013                     if (noteSubEu->finished != FALSE) {
   1014 #else
   1015                     if (note->finished != FALSE) {
   1016 #endif
   1017                         break;
   1018                     }
   1019                 }
   1020             }
   1021 
   1022             flags = 0;
   1023 
   1024 #ifdef VERSION_EU
   1025             if (noteSubEu->needsInit == TRUE) {
   1026                 flags = A_INIT;
   1027                 noteSubEu->needsInit = FALSE;
   1028             }
   1029 
   1030             cmd = final_resample(cmd, synthesisState, bufLen * 2, resamplingRateFixedPoint,
   1031                                  noteSamplesDmemAddrBeforeResampling, flags);
   1032 #else
   1033             if (note->needsInit == TRUE) {
   1034                 flags = A_INIT;
   1035                 note->needsInit = FALSE;
   1036             }
   1037 
   1038             cmd = final_resample(cmd, note, bufLen * 2, resamplingRateFixedPoint,
   1039                                  noteSamplesDmemAddrBeforeResampling, flags);
   1040 #endif
   1041 
   1042 #ifdef VERSION_EU
   1043             if (noteSubEu->headsetPanRight != 0 || synthesisState->prevHeadsetPanRight != 0) {
   1044                 leftRight = 1;
   1045             } else if (noteSubEu->headsetPanLeft != 0 || synthesisState->prevHeadsetPanLeft != 0) {
   1046                 leftRight = 2;
   1047 #else
   1048             if (note->headsetPanRight != 0 || note->prevHeadsetPanRight != 0) {
   1049                 leftRight = 1;
   1050             } else if (note->headsetPanLeft != 0 || note->prevHeadsetPanLeft != 0) {
   1051                 leftRight = 2;
   1052 #endif
   1053             } else {
   1054                 leftRight = 0;
   1055             }
   1056 
   1057 #ifdef VERSION_EU
   1058             cmd = process_envelope(cmd, noteSubEu, synthesisState, bufLen, 0, leftRight, flags);
   1059 #else
   1060             cmd = process_envelope(cmd, note, bufLen, 0, leftRight, flags);
   1061 #endif
   1062 
   1063 #ifdef VERSION_EU
   1064             if (noteSubEu->usesHeadsetPanEffects) {
   1065                 cmd = note_apply_headset_pan_effects(cmd, noteSubEu, synthesisState, bufLen * 2, flags, leftRight);
   1066             }
   1067 #else
   1068             if (note->usesHeadsetPanEffects) {
   1069                 cmd = note_apply_headset_pan_effects(cmd, note, bufLen * 2, flags, leftRight);
   1070             }
   1071 #endif
   1072         }
   1073 #ifndef VERSION_EU
   1074     }
   1075 
   1076     t9 = bufLen * 2;
   1077     aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, t9);
   1078     aInterleave(cmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH);
   1079     t9 *= 2;
   1080     aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, t9);
   1081     aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(aiBuf));
   1082 #endif
   1083 
   1084     return cmd;
   1085 }
   1086 
   1087 #ifdef VERSION_EU
   1088 u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad) {
   1089     s32 a3;
   1090     s32 repeats;
   1091     s32 i;
   1092     aSetBuffer(cmd++, /*flags*/ 0, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ 0, /*count*/ 128);
   1093     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples));
   1094 
   1095     synthesisState->samplePosInt &= 0x3f;
   1096     a3 = 64 - synthesisState->samplePosInt;
   1097     if (a3 < nSamplesToLoad) {
   1098         repeats = (nSamplesToLoad - a3 + 63) / 64;
   1099         for (i = 0; i < repeats; i++) {
   1100             aDMEMMove(cmd++,
   1101                       /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE,
   1102                       /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + (1 + i) * 128,
   1103                       /*count*/ 128);
   1104         }
   1105     }
   1106     return cmd;
   1107 }
   1108 #else
   1109 u64 *load_wave_samples(u64 *cmd, struct Note *note, s32 nSamplesToLoad) {
   1110     s32 a3;
   1111     s32 i;
   1112     aSetBuffer(cmd++, /*flags*/ 0, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ 0,
   1113                /*count*/ sizeof(note->synthesisBuffers->samples));
   1114     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->samples));
   1115     note->samplePosInt &= (note->sampleCount - 1);
   1116     a3 = 64 - note->samplePosInt;
   1117     if (a3 < nSamplesToLoad) {
   1118         for (i = 0; i <= (nSamplesToLoad - a3 + 63) / 64 - 1; i++) {
   1119             aDMEMMove(cmd++, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + (1 + i) * sizeof(note->synthesisBuffers->samples), /*count*/ sizeof(note->synthesisBuffers->samples));
   1120         }
   1121     }
   1122     return cmd;
   1123 }
   1124 #endif
   1125 
   1126 #ifdef VERSION_EU
   1127 u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags) {
   1128     aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count);
   1129     aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->finalResampleState));
   1130     return cmd;
   1131 }
   1132 #else
   1133 u64 *final_resample(u64 *cmd, struct Note *note, s32 count, u16 pitch, u16 dmemIn, u32 flags) {
   1134     aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count);
   1135     aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->finalResampleState));
   1136     return cmd;
   1137 }
   1138 #endif
   1139 
   1140 #ifndef VERSION_EU
   1141 u64 *process_envelope(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf, s32 headsetPanSettings,
   1142                       UNUSED u32 flags) {
   1143     UNUSED u8 pad[16];
   1144     struct VolumeChange vol;
   1145     vol.sourceLeft = note->curVolLeft;
   1146     vol.sourceRight = note->curVolRight;
   1147     vol.targetLeft = note->targetVolLeft;
   1148     vol.targetRight = note->targetVolRight;
   1149     note->curVolLeft = vol.targetLeft;
   1150     note->curVolRight = vol.targetRight;
   1151     return process_envelope_inner(cmd, note, nSamples, inBuf, headsetPanSettings, &vol);
   1152 }
   1153 
   1154 u64 *process_envelope_inner(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf,
   1155                             s32 headsetPanSettings, struct VolumeChange *vol) {
   1156     UNUSED u8 pad[3];
   1157     u8 mixerFlags;
   1158     UNUSED u8 pad2[8];
   1159     s32 rampLeft, rampRight;
   1160 #elif defined(VERSION_EU)
   1161 u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, UNUSED u32 flags) {
   1162     UNUSED u8 pad1[20];
   1163     u16 sourceRight;
   1164     u16 sourceLeft;
   1165     UNUSED u8 pad2[4];
   1166     u16 targetLeft;
   1167     u16 targetRight;
   1168     s32 mixerFlags;
   1169     s32 rampLeft;
   1170     s32 rampRight;
   1171 
   1172     sourceLeft = synthesisState->curVolLeft;
   1173     sourceRight = synthesisState->curVolRight;
   1174     targetLeft = (note->targetVolLeft << 5);
   1175     targetRight = (note->targetVolRight << 5);
   1176     if (targetLeft == 0) {
   1177         targetLeft++;
   1178     }
   1179     if (targetRight == 0) {
   1180         targetRight++;
   1181     }
   1182     synthesisState->curVolLeft = targetLeft;
   1183     synthesisState->curVolRight = targetRight;
   1184 #endif
   1185 
   1186     // For aEnvMixer, five buffers and count are set using aSetBuffer.
   1187     // in, dry left, count without A_AUX flag.
   1188     // dry right, wet left, wet right with A_AUX flag.
   1189 
   1190     if (note->usesHeadsetPanEffects) {
   1191         aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DEFAULT_LEN_1CH);
   1192 
   1193         switch (headsetPanSettings) {
   1194             case 1:
   1195                 aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_NOTE_PAN_TEMP, nSamples * 2);
   1196                 aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH,
   1197                            DMEM_ADDR_WET_RIGHT_CH);
   1198                 break;
   1199             case 2:
   1200                 aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
   1201                 aSetBuffer(cmd++, A_AUX, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_WET_LEFT_CH,
   1202                            DMEM_ADDR_WET_RIGHT_CH);
   1203                 break;
   1204             default:
   1205                 aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
   1206                 aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH,
   1207                            DMEM_ADDR_WET_RIGHT_CH);
   1208                 break;
   1209         }
   1210     } else {
   1211         // It's a bit unclear what the "stereo strong" concept does.
   1212         // Instead of mixing the opposite channel to the normal buffers, the sound is first
   1213         // mixed into a temporary buffer and then subtracted from the normal buffer.
   1214         if (note->stereoStrongRight) {
   1215             aClearBuffer(cmd++, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, DEFAULT_LEN_2CH);
   1216             aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, nSamples * 2);
   1217             aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_STEREO_STRONG_TEMP_WET,
   1218                        DMEM_ADDR_WET_RIGHT_CH);
   1219         } else if (note->stereoStrongLeft) {
   1220             aClearBuffer(cmd++, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, DEFAULT_LEN_2CH);
   1221             aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
   1222             aSetBuffer(cmd++, A_AUX, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, DMEM_ADDR_WET_LEFT_CH,
   1223                        DMEM_ADDR_STEREO_STRONG_TEMP_WET);
   1224         } else {
   1225             aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
   1226             aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_RIGHT_CH);
   1227         }
   1228     }
   1229 
   1230 #ifdef VERSION_EU
   1231     if (targetLeft == sourceLeft && targetRight == sourceRight && !note->envMixerNeedsInit) {
   1232 #else
   1233     if (vol->targetLeft == vol->sourceLeft && vol->targetRight == vol->sourceRight
   1234         && !note->envMixerNeedsInit) {
   1235 #endif
   1236         mixerFlags = A_CONTINUE;
   1237     } else {
   1238         mixerFlags = A_INIT;
   1239 
   1240 #ifdef VERSION_EU
   1241         rampLeft = gCurrentLeftVolRamping[targetLeft >> 5] * gCurrentRightVolRamping[sourceLeft >> 5];
   1242         rampRight = gCurrentLeftVolRamping[targetRight >> 5] * gCurrentRightVolRamping[sourceRight >> 5];
   1243 #else
   1244         rampLeft = get_volume_ramping(vol->sourceLeft, vol->targetLeft, nSamples);
   1245         rampRight = get_volume_ramping(vol->sourceRight, vol->targetRight, nSamples);
   1246 #endif
   1247 
   1248         // The operation's parameters change meanings depending on flags
   1249 #ifdef VERSION_EU
   1250         aSetVolume(cmd++, A_VOL | A_LEFT, sourceLeft, 0, 0);
   1251         aSetVolume(cmd++, A_VOL | A_RIGHT, sourceRight, 0, 0);
   1252         aSetVolume32(cmd++, A_RATE | A_LEFT, targetLeft, rampLeft);
   1253         aSetVolume32(cmd++, A_RATE | A_RIGHT, targetRight, rampRight);
   1254         aSetVolume(cmd++, A_AUX, gVolume, 0, note->reverbVol << 8);
   1255 #else
   1256         aSetVolume(cmd++, A_VOL | A_LEFT, vol->sourceLeft, 0, 0);
   1257         aSetVolume(cmd++, A_VOL | A_RIGHT, vol->sourceRight, 0, 0);
   1258         aSetVolume32(cmd++, A_RATE | A_LEFT, vol->targetLeft, rampLeft);
   1259         aSetVolume32(cmd++, A_RATE | A_RIGHT, vol->targetRight, rampRight);
   1260         aSetVolume(cmd++, A_AUX, gVolume, 0, note->reverbVolShifted);
   1261 #endif
   1262     }
   1263 
   1264 #ifdef VERSION_EU
   1265     if (gUseReverb && note->reverbVol != 0) {
   1266         aEnvMixer(cmd++, mixerFlags | A_AUX,
   1267                   VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->mixEnvelopeState));
   1268 #else
   1269     if (gSynthesisReverb.useReverb && note->reverbVol != 0) {
   1270         aEnvMixer(cmd++, mixerFlags | A_AUX,
   1271                   VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->mixEnvelopeState));
   1272 #endif
   1273         if (note->stereoStrongRight) {
   1274             aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
   1275             // 0x8000 is -100%, so subtract sound instead of adding...
   1276             aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
   1277                  /*out*/ DMEM_ADDR_LEFT_CH);
   1278             aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET,
   1279                  /*out*/ DMEM_ADDR_WET_LEFT_CH);
   1280         } else if (note->stereoStrongLeft) {
   1281             aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
   1282             aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
   1283                  /*out*/ DMEM_ADDR_RIGHT_CH);
   1284             aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET,
   1285                  /*out*/ DMEM_ADDR_WET_RIGHT_CH);
   1286         }
   1287     } else {
   1288 #ifdef VERSION_EU
   1289         aEnvMixer(cmd++, mixerFlags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->mixEnvelopeState));
   1290 #else
   1291         aEnvMixer(cmd++, mixerFlags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->mixEnvelopeState));
   1292 #endif
   1293         if (note->stereoStrongRight) {
   1294             aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
   1295             aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
   1296                  /*out*/ DMEM_ADDR_LEFT_CH);
   1297         } else if (note->stereoStrongLeft) {
   1298             aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
   1299             aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
   1300                  /*out*/ DMEM_ADDR_RIGHT_CH);
   1301         }
   1302     }
   1303     return cmd;
   1304 }
   1305 
   1306 #ifdef VERSION_EU
   1307 u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight) {
   1308 #else
   1309 u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 flags, s32 leftRight) {
   1310 #endif
   1311     u16 dest;
   1312     u16 pitch;
   1313 #ifdef VERSION_EU
   1314     u8 prevPanShift;
   1315     u8 panShift;
   1316     UNUSED u8 unkDebug;
   1317 #else
   1318     u16 prevPanShift;
   1319     u16 panShift;
   1320 #endif
   1321 
   1322     switch (leftRight) {
   1323         case 1:
   1324             dest = DMEM_ADDR_LEFT_CH;
   1325 #ifdef VERSION_EU
   1326             panShift = noteSubEu->headsetPanRight;
   1327 #else
   1328             panShift = note->headsetPanRight;
   1329 #endif
   1330             note->prevHeadsetPanLeft = 0;
   1331             prevPanShift = note->prevHeadsetPanRight;
   1332             note->prevHeadsetPanRight = panShift;
   1333             break;
   1334         case 2:
   1335             dest = DMEM_ADDR_RIGHT_CH;
   1336 #ifdef VERSION_EU
   1337             panShift = noteSubEu->headsetPanLeft;
   1338 #else
   1339             panShift = note->headsetPanLeft;
   1340 #endif
   1341             note->prevHeadsetPanRight = 0;
   1342 
   1343             prevPanShift = note->prevHeadsetPanLeft;
   1344             note->prevHeadsetPanLeft = panShift;
   1345             break;
   1346         default:
   1347             return cmd;
   1348     }
   1349 
   1350     if (flags != 1) { // A_INIT?
   1351         // Slightly adjust the sample rate in order to fit a change in pan shift
   1352         if (prevPanShift == 0) {
   1353             // Kind of a hack that moves the first samples into the resample state
   1354             aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, 8);
   1355             aClearBuffer(cmd++, 8, 8); // Set pitch accumulator to 0 in the resample state
   1356             aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP + 0x10,
   1357                       0x10); // No idea, result seems to be overwritten later
   1358 
   1359             aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, 32);
   1360             aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panResampleState));
   1361 
   1362 #ifdef VERSION_EU
   1363             pitch = (bufLen << 0xf) / (bufLen + panShift - prevPanShift + 8);
   1364             if (pitch) {
   1365             }
   1366 #else
   1367             pitch = (bufLen << 0xf) / (panShift + bufLen - prevPanShift + 8);
   1368 #endif
   1369             aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP + 8, DMEM_ADDR_TEMP, panShift + bufLen - prevPanShift);
   1370             aResample(cmd++, 0, pitch, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panResampleState));
   1371         } else {
   1372             if (panShift == 0) {
   1373                 pitch = (bufLen << 0xf) / (bufLen - prevPanShift - 4);
   1374             } else {
   1375                 pitch = (bufLen << 0xf) / (bufLen + panShift - prevPanShift);
   1376             }
   1377 
   1378 #if defined(VERSION_EU) && !defined(AVOID_UB)
   1379             if (unkDebug) { // UB
   1380             }
   1381 #endif
   1382             aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, panShift + bufLen - prevPanShift);
   1383             aResample(cmd++, 0, pitch, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panResampleState));
   1384         }
   1385 
   1386         if (prevPanShift != 0) {
   1387             aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, 0, prevPanShift);
   1388             aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer));
   1389             aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift, panShift + bufLen - prevPanShift);
   1390         } else {
   1391             aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP, panShift + bufLen - prevPanShift);
   1392         }
   1393     } else {
   1394         // Just shift right
   1395         aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen);
   1396         aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + panShift, bufLen);
   1397         aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, panShift);
   1398     }
   1399 
   1400     if (panShift) {
   1401         // Save excessive samples for next iteration
   1402         aSetBuffer(cmd++, 0, 0, DMEM_ADDR_NOTE_PAN_TEMP + bufLen, panShift);
   1403         aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer));
   1404     }
   1405 
   1406     aSetBuffer(cmd++, 0, 0, 0, bufLen);
   1407     aMix(cmd++, 0, /*gain*/ 0x7fff, /*in*/ DMEM_ADDR_NOTE_PAN_TEMP, /*out*/ dest);
   1408 
   1409     return cmd;
   1410 }
   1411 
   1412 #ifndef VERSION_EU
   1413 // Moved to playback.c in EU
   1414 
   1415 void note_init_volume(struct Note *note) {
   1416     note->targetVolLeft = 0;
   1417     note->targetVolRight = 0;
   1418     note->reverbVol = 0;
   1419     note->reverbVolShifted = 0;
   1420     note->unused2 = 0;
   1421     note->curVolLeft = 1;
   1422     note->curVolRight = 1;
   1423     note->frequency = 0.0f;
   1424 }
   1425 
   1426 void note_set_vel_pan_reverb(struct Note *note, f32 velocity, f32 pan, u8 reverbVol) {
   1427     s32 panIndex;
   1428     f32 volLeft;
   1429     f32 volRight;
   1430     // Anding with 127 avoids out-of-bounds reads when pan is outside of [0, 1].
   1431     // This can occur during PU movement -- see the bug comment in get_sound_pan
   1432     // in external.c. An out-of-bounds read by itself doesn't crash, but if the
   1433     // resulting value is a nan or denormal, performing arithmetic on it crashes
   1434     // on console.
   1435 #ifdef VERSION_JP
   1436     panIndex = MIN((s32)(pan * 127.5), 127);
   1437 #else
   1438     panIndex = (s32)(pan * 127.5f) & 127;
   1439 #endif
   1440     if (note->stereoHeadsetEffects && gSoundMode == SOUND_MODE_HEADSET) {
   1441         s8 smallPanIndex;
   1442         s8 temp = (s8)(pan * 10.0f);
   1443         if (temp < 9) {
   1444             smallPanIndex = temp;
   1445         } else {
   1446             smallPanIndex = 9;
   1447         }
   1448         note->headsetPanLeft = gHeadsetPanQuantization[smallPanIndex];
   1449         note->headsetPanRight = gHeadsetPanQuantization[9 - smallPanIndex];
   1450         note->stereoStrongRight = FALSE;
   1451         note->stereoStrongLeft = FALSE;
   1452         note->usesHeadsetPanEffects = TRUE;
   1453         volLeft = gHeadsetPanVolume[panIndex];
   1454         volRight = gHeadsetPanVolume[127 - panIndex];
   1455     } else if (note->stereoHeadsetEffects && gSoundMode == SOUND_MODE_STEREO) {
   1456         u8 strongLeft;
   1457         u8 strongRight;
   1458         strongLeft = FALSE;
   1459         strongRight = FALSE;
   1460         note->headsetPanLeft = 0;
   1461         note->headsetPanRight = 0;
   1462         note->usesHeadsetPanEffects = FALSE;
   1463         volLeft = gStereoPanVolume[panIndex];
   1464         volRight = gStereoPanVolume[127 - panIndex];
   1465         if (panIndex < 0x20) {
   1466             strongLeft = TRUE;
   1467         } else if (panIndex > 0x60) {
   1468             strongRight = TRUE;
   1469         }
   1470         note->stereoStrongRight = strongRight;
   1471         note->stereoStrongLeft = strongLeft;
   1472     } else if (gSoundMode == SOUND_MODE_MONO) {
   1473         volLeft = .707f;
   1474         volRight = .707f;
   1475     } else {
   1476         volLeft = gDefaultPanVolume[panIndex];
   1477         volRight = gDefaultPanVolume[127 - panIndex];
   1478     }
   1479 
   1480     if (velocity < 0) {
   1481         velocity = 0;
   1482     }
   1483 #ifdef VERSION_JP
   1484     note->targetVolLeft = (u16)(velocity * volLeft) & ~0x80FF; // 0x7F00, but that doesn't match
   1485     note->targetVolRight = (u16)(velocity * volRight) & ~0x80FF;
   1486 #else
   1487     note->targetVolLeft = (u16)(s32)(velocity * volLeft) & ~0x80FF;
   1488     note->targetVolRight = (u16)(s32)(velocity * volRight) & ~0x80FF;
   1489 #endif
   1490     if (note->targetVolLeft == 0) {
   1491         note->targetVolLeft++;
   1492     }
   1493     if (note->targetVolRight == 0) {
   1494         note->targetVolRight++;
   1495     }
   1496     if (note->reverbVol != reverbVol) {
   1497         note->reverbVol = reverbVol;
   1498         note->reverbVolShifted = reverbVol << 8;
   1499         note->envMixerNeedsInit = TRUE;
   1500         return;
   1501     }
   1502 
   1503     if (note->needsInit) {
   1504         note->envMixerNeedsInit = TRUE;
   1505     } else {
   1506         note->envMixerNeedsInit = FALSE;
   1507     }
   1508 }
   1509 
   1510 void note_set_frequency(struct Note *note, f32 frequency) {
   1511     note->frequency = frequency;
   1512 }
   1513 
   1514 void note_enable(struct Note *note) {
   1515     note->enabled = TRUE;
   1516     note->needsInit = TRUE;
   1517     note->restart = FALSE;
   1518     note->finished = FALSE;
   1519     note->stereoStrongRight = FALSE;
   1520     note->stereoStrongLeft = FALSE;
   1521     note->usesHeadsetPanEffects = FALSE;
   1522     note->headsetPanLeft = 0;
   1523     note->headsetPanRight = 0;
   1524     note->prevHeadsetPanRight = 0;
   1525     note->prevHeadsetPanLeft = 0;
   1526 }
   1527 
   1528 void note_disable(struct Note *note) {
   1529     if (note->needsInit == TRUE) {
   1530         note->needsInit = FALSE;
   1531     } else {
   1532         note_set_vel_pan_reverb(note, 0, .5, 0);
   1533     }
   1534     note->priority = NOTE_PRIORITY_DISABLED;
   1535     note->enabled = FALSE;
   1536     note->finished = FALSE;
   1537     note->parentLayer = NO_LAYER;
   1538     note->prevParentLayer = NO_LAYER;
   1539 }
   1540 #endif
   1541 #endif