sm64

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

synthesis_sh.c (38727B)


      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 0x450
     14 #define DMEM_ADDR_RESAMPLED 0x470
     15 #define DMEM_ADDR_RESAMPLED2 0x5f0
     16 #define DMEM_ADDR_UNCOMPRESSED_NOTE 0x5f0
     17 #define DMEM_ADDR_NOTE_PAN_TEMP 0x650
     18 #define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x990
     19 #define DMEM_ADDR_LEFT_CH 0x990
     20 #define DMEM_ADDR_RIGHT_CH 0xb10
     21 #define DMEM_ADDR_WET_LEFT_CH 0xc90
     22 #define DMEM_ADDR_WET_RIGHT_CH 0xe10
     23 
     24 #define aSetLoadBufferPair(pkt, c, off)                                                                \
     25     aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_LEFT_CH, 0, DEFAULT_LEN_1CH - c);                             \
     26     aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off)));                  \
     27     aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_RIGHT_CH, 0, DEFAULT_LEN_1CH - c);                            \
     28     aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)))
     29 
     30 #define aSetSaveBufferPair(pkt, c, d, off)                                                             \
     31     aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_LEFT_CH, d);                                               \
     32     aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left +  (off)));                 \
     33     aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_RIGHT_CH, d);                                              \
     34     aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)));
     35 
     36 #define ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1))
     37 
     38 struct VolumeChange {
     39     u16 sourceLeft;
     40     u16 sourceRight;
     41     u16 targetLeft;
     42     u16 targetRight;
     43 };
     44 
     45 u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex);
     46 u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex);
     47 u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad);
     48 u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags);
     49 u64 *process_envelope(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, u32 flags);
     50 u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight);
     51 
     52 struct SynthesisReverb gSynthesisReverbs[4];
     53 u8 sAudioSynthesisPad[0x10];
     54 
     55 s16 gVolume;
     56 s8 gUseReverb;
     57 s8 gNumSynthesisReverbs;
     58 s16 D_SH_803479B4; // contains 4096
     59 struct NoteSubEu *gNoteSubsEu;
     60 
     61 // Equivalent functionality as the US/JP version,
     62 // just that the reverb structure is chosen from an array with index
     63 // Identical in EU.
     64 void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex) {
     65     struct ReverbRingBufferItem *item;
     66     struct SynthesisReverb *reverb = &gSynthesisReverbs[reverbIndex];
     67     s32 srcPos;
     68     s32 dstPos;
     69     s32 nSamples;
     70     s32 excessiveSamples;
     71     s32 UNUSED pad[3];
     72     if (reverb->downsampleRate != 1) {
     73         if (reverb->framesLeftToIgnore == 0) {
     74             // Now that the RSP has finished, downsample the samples produced two frames ago by skipping
     75             // samples.
     76             item = &reverb->items[reverb->curFrame][updateIndex];
     77 
     78             // Touches both left and right since they are adjacent in memory
     79             osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
     80 
     81             for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
     82                  srcPos += reverb->downsampleRate, dstPos++) {
     83                 reverb->ringBuffer.left[item->startPos + dstPos] =
     84                     item->toDownsampleLeft[srcPos];
     85                 reverb->ringBuffer.right[item->startPos + dstPos] =
     86                     item->toDownsampleRight[srcPos];
     87             }
     88             for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += reverb->downsampleRate, dstPos++) {
     89                 reverb->ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
     90                 reverb->ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
     91             }
     92         }
     93     }
     94 
     95     item = &reverb->items[reverb->curFrame][updateIndex];
     96     nSamples = chunkLen / reverb->downsampleRate;
     97     excessiveSamples = (nSamples + reverb->nextRingBufferPos) - reverb->bufSizePerChannel;
     98     if (excessiveSamples < 0) {
     99         // There is space in the ring buffer before it wraps around
    100         item->lengthA = nSamples * 2;
    101         item->lengthB = 0;
    102         item->startPos = (s32) reverb->nextRingBufferPos;
    103         reverb->nextRingBufferPos += nSamples;
    104     } else {
    105         // Ring buffer wrapped around
    106         item->lengthA = (nSamples - excessiveSamples) * 2;
    107         item->lengthB = excessiveSamples * 2;
    108         item->startPos = reverb->nextRingBufferPos;
    109         reverb->nextRingBufferPos = excessiveSamples;
    110     }
    111     // These fields are never read later
    112     item->numSamplesAfterDownsampling = nSamples;
    113     item->chunkLen = chunkLen;
    114 }
    115 
    116 u64 *synthesis_load_reverb_ring_buffer(u64 *cmd, u16 addr, u16 srcOffset, s32 len, s32 reverbIndex) {
    117     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[srcOffset]),
    118                 addr, len);
    119     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[srcOffset]),
    120                 addr + DEFAULT_LEN_1CH, len);
    121     return cmd;
    122 }
    123 
    124 u64 *synthesis_save_reverb_ring_buffer(u64 *cmd, u16 addr, u16 destOffset, s32 len, s32 reverbIndex) {
    125     aSaveBuffer(cmd++, addr,
    126                 VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[destOffset]), len);
    127     aSaveBuffer(cmd++, addr + DEFAULT_LEN_1CH,
    128                 VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[destOffset]), len);
    129     return cmd;
    130 }
    131 
    132 void func_sh_802ed644(s32 updateIndexStart, s32 noteIndex) {
    133     s32 i;
    134 
    135     for (i = updateIndexStart + 1; i < gAudioBufferParameters.updatesPerFrame; i++) {
    136         if (!gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].needsInit) {
    137             gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].enabled = FALSE;
    138         } else {
    139             break;
    140         }
    141     }
    142 }
    143 
    144 void synthesis_load_note_subs_eu(s32 updateIndex) {
    145     struct NoteSubEu *src;
    146     struct NoteSubEu *dest;
    147     s32 i;
    148 
    149     for (i = 0; i < gMaxSimultaneousNotes; i++) {
    150         src = &gNotes[i].noteSubEu;
    151         dest = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
    152         if (src->enabled) {
    153             *dest = *src;
    154             src->needsInit = FALSE;
    155         } else {
    156             dest->enabled = FALSE;
    157         }
    158     }
    159 }
    160 
    161 // TODO: (Scrub C) pointless mask and whitespace
    162 u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
    163     s32 i, j;
    164     u32 *aiBufPtr;
    165     u64 *cmd = cmdBuf;
    166     s32 chunkLen;
    167 
    168     for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
    169         process_sequences(i - 1);
    170         synthesis_load_note_subs_eu(gAudioBufferParameters.updatesPerFrame - i);
    171     }
    172     aiBufPtr = (u32 *) aiBuf;
    173     for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
    174         if (i == 1) {
    175             chunkLen = bufLen;
    176         } else {
    177             if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) {
    178                 chunkLen = gAudioBufferParameters.samplesPerUpdateMax;
    179             } else if (bufLen / i <= gAudioBufferParameters.samplesPerUpdateMin) {
    180                 chunkLen = gAudioBufferParameters.samplesPerUpdateMin;
    181             } else {
    182                 chunkLen = gAudioBufferParameters.samplesPerUpdate;
    183             }
    184         }
    185         for (j = 0; j < gNumSynthesisReverbs; j++) {
    186             if (gSynthesisReverbs[j].useReverb != 0) {
    187                 prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j);
    188             }
    189         }
    190         cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioBufferParameters.updatesPerFrame - i);
    191         bufLen -= chunkLen;
    192         aiBufPtr += chunkLen;
    193     }
    194 
    195     for (j = 0; j < gNumSynthesisReverbs; j++) {
    196         if (gSynthesisReverbs[j].framesLeftToIgnore != 0) {
    197             gSynthesisReverbs[j].framesLeftToIgnore--;
    198         }
    199         gSynthesisReverbs[j].curFrame ^= 1;
    200     }
    201     *writtenCmds = cmd - cmdBuf;
    202     return cmd;
    203 }
    204 
    205 u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s16 updateIndex) {
    206     struct ReverbRingBufferItem *item;
    207     s16 startPad;
    208     s16 paddedLengthA;
    209 
    210     item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
    211 
    212     if (gSynthesisReverbs[reverbIndex].downsampleRate == 1) {
    213         cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
    214         if (item->lengthB != 0) {
    215             cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
    216         }
    217         aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
    218         aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
    219     } else {
    220         startPad = (item->startPos % 8u) * 2;
    221         paddedLengthA = ALIGN(startPad + item->lengthA, 4);
    222 
    223         cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, (item->startPos - startPad / 2), DEFAULT_LEN_1CH, reverbIndex);
    224         if (item->lengthB != 0) {
    225             cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + paddedLengthA, 0, DEFAULT_LEN_1CH - paddedLengthA, reverbIndex);
    226         }
    227 
    228         aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED + startPad, DMEM_ADDR_WET_LEFT_CH, bufLen * 2);
    229         aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateLeft));
    230 
    231         aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED2 + startPad, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2);
    232         aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateRight));
    233 
    234         aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
    235         aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
    236     }
    237     if (gSynthesisReverbs[reverbIndex].panRight != 0 || gSynthesisReverbs[reverbIndex].panLeft != 0) {
    238         // Leak some audio from the left reverb channel into the right reverb channel and vice versa (pan)
    239         aDMEMMove(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_1CH);
    240         aMix(cmd++, gSynthesisReverbs[reverbIndex].panRight, DMEM_ADDR_WET_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_1CH);
    241         aMix(cmd++, gSynthesisReverbs[reverbIndex].panLeft, DMEM_ADDR_RESAMPLED, DMEM_ADDR_WET_RIGHT_CH, DEFAULT_LEN_1CH);
    242     }
    243     return cmd;
    244 }
    245 
    246 u64 *synthesis_load_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
    247     struct ReverbRingBufferItem *item;
    248     struct SynthesisReverb *reverb;
    249 
    250     reverb = &gSynthesisReverbs[reverbIndex];
    251     item = &reverb->items[reverb->curFrame][updateIndex];
    252     // Get the oldest samples in the ring buffer into the wet channels
    253     cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex);
    254     if (item->lengthB != 0) {
    255         // Ring buffer wrapped
    256         cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex);
    257     }
    258     return cmd;
    259 }
    260 
    261 u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
    262     struct ReverbRingBufferItem *item;
    263 
    264     item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
    265     switch (gSynthesisReverbs[reverbIndex].downsampleRate) {
    266         case 1:
    267             // Put the oldest samples in the ring buffer into the wet channels
    268             cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
    269             if (item->lengthB != 0) {
    270                 // Ring buffer wrapped
    271                 cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
    272             }
    273             break;
    274 
    275         default:
    276             // Downsampling is done later by CPU when RSP is done, therefore we need to have double
    277             // buffering. Left and right buffers are adjacent in memory.
    278             aSaveBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH,
    279                     VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex].toDownsampleLeft), DEFAULT_LEN_2CH);
    280             break;
    281     }
    282     gSynthesisReverbs[reverbIndex].resampleFlags = 0;
    283     return cmd;
    284 }
    285 
    286 u64 *func_sh_802EDF24(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
    287     struct ReverbRingBufferItem *item;
    288     struct SynthesisReverb *reverb;
    289 
    290     reverb = &gSynthesisReverbs[reverbIndex];
    291     item = &reverb->items[reverb->curFrame][updateIndex];
    292     // Put the oldest samples in the ring buffer into the wet channels
    293     cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex);
    294     if (item->lengthB != 0) {
    295         // Ring buffer wrapped
    296         cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex);
    297     }
    298     return cmd;
    299 }
    300 
    301 u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
    302     struct NoteSubEu *noteSubEu;
    303     u8 noteIndices[56];
    304     s32 temp;
    305     s32 i;
    306     s16 j;
    307     s16 notePos = 0;
    308 
    309     if (gNumSynthesisReverbs == 0) {
    310         for (i = 0; i < gMaxSimultaneousNotes; i++) {
    311             if (gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i].enabled) {
    312                 noteIndices[notePos++] = i;
    313             }
    314         }
    315     } else {
    316         for (j = 0; j < gNumSynthesisReverbs; j++) {
    317             for (i = 0; i < gMaxSimultaneousNotes; i++) {
    318                 noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
    319                 if (noteSubEu->enabled && j == noteSubEu->reverbIndex) {
    320                     noteIndices[notePos++] = i;
    321                 }
    322             }
    323         }
    324 
    325         for (i = 0; i < gMaxSimultaneousNotes; i++) {
    326             noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
    327             if (noteSubEu->enabled && noteSubEu->reverbIndex >= gNumSynthesisReverbs) {
    328                 noteIndices[notePos++] = i;
    329             }
    330         }
    331     }
    332     aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
    333     i = 0;
    334     for (j = 0; j < gNumSynthesisReverbs; j++) {
    335         gUseReverb = gSynthesisReverbs[j].useReverb;
    336         if (gUseReverb != 0) {
    337             cmd = synthesis_resample_and_mix_reverb(cmd, bufLen, j, updateIndex);
    338         }
    339         for (; i < notePos; i++) {
    340             temp = updateIndex * gMaxSimultaneousNotes;
    341             if (j == gNoteSubsEu[temp + noteIndices[i]].reverbIndex) {
    342                 cmd = synthesis_process_note(noteIndices[i],
    343                                              &gNoteSubsEu[temp + noteIndices[i]],
    344                                              &gNotes[noteIndices[i]].synthesisState,
    345                                              aiBuf, bufLen, cmd, updateIndex);
    346                 continue;
    347             } else {
    348                 break;
    349             }
    350         }
    351         if (gSynthesisReverbs[j].useReverb != 0) {
    352             if (gSynthesisReverbs[j].unk100 != NULL) {
    353                 aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk100);
    354                 aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_LEFT_CH, gSynthesisReverbs[j].unk108);
    355             }
    356             if (gSynthesisReverbs[j].unk104 != NULL) {
    357                 aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk104);
    358                 aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_RIGHT_CH, gSynthesisReverbs[j].unk10C);
    359             }
    360             cmd = synthesis_save_reverb_samples(cmd, j, updateIndex);
    361             if (gSynthesisReverbs[j].unk5 != -1) {
    362                 if (gSynthesisReverbs[gSynthesisReverbs[j].unk5].downsampleRate == 1) {
    363                     cmd = synthesis_load_reverb_samples(cmd, gSynthesisReverbs[j].unk5, updateIndex);
    364                     aMix(cmd++, gSynthesisReverbs[j].unk08, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_2CH);
    365                     cmd = func_sh_802EDF24(cmd++, gSynthesisReverbs[j].unk5, updateIndex);
    366                 }
    367             }
    368         }
    369     }
    370     for (; i < notePos; i++) {
    371         struct NoteSubEu *noteSubEu2 = &gNoteSubsEu[updateIndex * gMaxSimultaneousNotes + noteIndices[i]];
    372         cmd = synthesis_process_note(noteIndices[i],
    373                                      noteSubEu2,
    374                                      &gNotes[noteIndices[i]].synthesisState,
    375                                      aiBuf, bufLen, cmd, updateIndex);
    376     }
    377 
    378     temp = bufLen * 2;
    379     aInterleave(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH, temp);
    380     aSaveBuffer(cmd++, DMEM_ADDR_TEMP, VIRTUAL_TO_PHYSICAL2(aiBuf), temp * 2);
    381     return cmd;
    382 }
    383 
    384 u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, UNUSED s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
    385     UNUSED s32 pad0[3];
    386     struct AudioBankSample *audioBookSample; // sp164, sp138
    387     struct AdpcmLoop *loopInfo; // sp160, sp134
    388     s16 *curLoadedBook; // sp154, sp130
    389     UNUSED u8 padEU[0x04];
    390     UNUSED u8 pad8[0x04];
    391     s32 noteFinished; // 150 t2, sp124
    392     s32 restart; // 14c t3, sp120
    393     s32 flags; // sp148, sp11C, t8
    394     u16 resamplingRateFixedPoint; // sp5c, sp11A
    395     s32 nSamplesToLoad; //s0, Ec
    396     UNUSED u8 pad7[0x0c]; // sp100
    397     s32 sp130; //sp128, sp104
    398     UNUSED s32 tempBufLen;
    399     UNUSED u32 pad9;
    400     s32 t0;
    401     u8 *sampleAddr; // sp120, spF4
    402     s32 s6;
    403     s32 samplesLenAdjusted; // 108,      spEC
    404     s32 nAdpcmSamplesProcessed; // signed required for US // spc0
    405     s32 endPos; // sp110,    spE4
    406     s32 nSamplesToProcess; // sp10c/a0, spE0
    407     // Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
    408     // behavior with the break near the end of the loop, causing US and JP to need a goto instead
    409     UNUSED s32 samplesLenInt;
    410     s32 s2;
    411     s32 leftRight; //s0
    412     s32 s5; //s4
    413     u32 samplesLenFixedPoint; // v1_1
    414     s32 s3;     // spA0
    415     s32 nSamplesInThisIteration; // v1_2
    416     u32 a3;
    417     u8 *v0_2;
    418     s32 unk_s6; // sp90
    419     s32 s5Aligned;
    420     s32 sp88;
    421     s32 sp84;
    422     u32 temp;
    423     s32 nParts; // spE8, spBC
    424     s32 curPart; // spE4, spB8
    425     s32 aligned;
    426     UNUSED u32 padSH1;
    427     s32 resampledTempLen; // spD8, spAC, sp6c
    428     u16 noteSamplesDmemAddrBeforeResampling; // spD6, spAA, sp6a -- 6C
    429     UNUSED u32 padSH2;
    430     UNUSED u32 padSH3;
    431     UNUSED u32 padSH4;
    432     struct Note *note;  // sp58
    433     u16 sp56;           // sp56
    434     u16 addr;
    435     u8 synthesisVolume;
    436 
    437     curLoadedBook = NULL;
    438     note = &gNotes[noteIndex];
    439     flags = 0;
    440     if (noteSubEu->needsInit == TRUE) {
    441         flags = A_INIT;
    442         synthesisState->restart = 0;
    443         synthesisState->samplePosInt = 0;
    444         synthesisState->samplePosFrac = 0;
    445         synthesisState->curVolLeft = 0;
    446         synthesisState->curVolRight = 0;
    447         synthesisState->prevHeadsetPanRight = 0;
    448         synthesisState->prevHeadsetPanLeft = 0;
    449         synthesisState->reverbVol = noteSubEu->reverbVol;
    450         synthesisState->unk5 = 0;
    451         note->noteSubEu.finished = 0;
    452     }
    453 
    454     resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint;
    455     nParts = noteSubEu->hasTwoAdpcmParts + 1;
    456     samplesLenFixedPoint = (resamplingRateFixedPoint * bufLen * 2) + synthesisState->samplePosFrac;
    457     nSamplesToLoad = (samplesLenFixedPoint >> 0x10);
    458     synthesisState->samplePosFrac = samplesLenFixedPoint & 0xFFFF;
    459 
    460     if ((synthesisState->unk5 == 1) && (nParts == 2)) {
    461         nSamplesToLoad += 2;
    462         sp56 = 2;
    463     } else if ((synthesisState->unk5 == 2) && (nParts == 1)) {
    464         nSamplesToLoad -= 4;
    465         sp56 = 4;
    466     } else {
    467         sp56 = 0;
    468     }
    469 
    470 
    471     synthesisState->unk5 = nParts;
    472 
    473     if (noteSubEu->isSyntheticWave) {
    474         cmd = load_wave_samples(cmd, noteSubEu, synthesisState, nSamplesToLoad);
    475         noteSamplesDmemAddrBeforeResampling = (synthesisState->samplePosInt * 2) + DMEM_ADDR_UNCOMPRESSED_NOTE;
    476         synthesisState->samplePosInt += nSamplesToLoad;
    477     } else {
    478         // ADPCM note
    479         audioBookSample = noteSubEu->sound.audioBankSound->sample;
    480         loopInfo = audioBookSample->loop;
    481         endPos = loopInfo->end;
    482         sampleAddr = audioBookSample->sampleAddr;
    483         resampledTempLen = 0;
    484         for (curPart = 0; curPart < nParts; curPart++) {
    485             nAdpcmSamplesProcessed = 0; // s8
    486             s5 = 0; // s4
    487 
    488             if (nParts == 1) {
    489                 samplesLenAdjusted = nSamplesToLoad;
    490             } else if (nSamplesToLoad & 1) {
    491                 samplesLenAdjusted = (nSamplesToLoad & ~1) + (curPart * 2);
    492             } else {
    493                 samplesLenAdjusted = nSamplesToLoad;
    494             }
    495 
    496             if (audioBookSample->codec == CODEC_ADPCM) {
    497                 if (curLoadedBook != (*audioBookSample->book).book) {
    498                     u32 nEntries;
    499                     switch (noteSubEu->bookOffset) {
    500                         case 1:
    501                             curLoadedBook = euUnknownData_80301950 + 1;
    502                             break;
    503                         case 2:
    504                             curLoadedBook = euUnknownData_80301950 + 2;
    505                             break;
    506                         case 3:
    507                         default:
    508                             curLoadedBook = audioBookSample->book->book;
    509                             break;
    510                     }
    511                     nEntries = 16 * audioBookSample->book->order * audioBookSample->book->npredictors;
    512                     aLoadADPCM(cmd++, nEntries, VIRTUAL_TO_PHYSICAL2(curLoadedBook));
    513                 }
    514             }
    515 
    516             while (nAdpcmSamplesProcessed != samplesLenAdjusted) {
    517                 s32 samplesRemaining; // v1
    518                 s32 s0;
    519 
    520                 noteFinished = FALSE;
    521                 restart = FALSE;
    522                 s2 = synthesisState->samplePosInt & 0xf;
    523                 samplesRemaining = endPos - synthesisState->samplePosInt;
    524                 nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed;
    525 
    526                 if (s2 == 0 && synthesisState->restart == FALSE) {
    527                     s2 = 16;
    528                 }
    529                 s6 = 16 - s2; // a1
    530                 if (nSamplesToProcess < samplesRemaining) {
    531                     t0 = (nSamplesToProcess - s6 + 0xf) / 16;
    532                     s0 = t0 * 16;
    533                     s3 = s6 + s0 - nSamplesToProcess;
    534                 } else {
    535                     s0 = samplesRemaining - s6;
    536                     s3 = 0;
    537                     if (s0 <= 0) {
    538                         s0 = 0;
    539                         s6 = samplesRemaining;
    540                     }
    541                     t0 = (s0 + 0xf) / 16;
    542                     if (loopInfo->count != 0) {
    543                         // Loop around and restart
    544                         restart = 1;
    545                     } else {
    546                         noteFinished = 1;
    547                     }
    548                 }
    549                 switch (audioBookSample->codec) {
    550                     case CODEC_ADPCM:
    551                         unk_s6 = 9;
    552                         sp88 = 0x10;
    553                         sp84 = 0;
    554                         break;
    555                     case CODEC_S8:
    556                         unk_s6 = 0x10;
    557                         sp88 = 0x10;
    558                         sp84 = 0;
    559                         break;
    560                     case CODEC_SKIP: goto skip;
    561                 }
    562                 if (t0 != 0) {
    563                     temp = (synthesisState->samplePosInt + sp88 - s2) / 16;
    564                     if (audioBookSample->medium == 0) {
    565                         v0_2 = sp84 + (temp * unk_s6) + sampleAddr;
    566                     } else {
    567                         v0_2 = dma_sample_data((uintptr_t)(sp84 + (temp * unk_s6) + sampleAddr),
    568                                 ALIGN(t0 * unk_s6 + 16, 4), flags, &synthesisState->sampleDmaIndex, audioBookSample->medium);
    569                     }
    570 
    571                     a3 = ((uintptr_t)v0_2 & 0xf);
    572                     aligned = ALIGN(t0 * unk_s6 + 16, 4);
    573                     addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
    574                     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(v0_2 - a3), addr, ALIGN(t0 * unk_s6 + 16, 4));
    575                 } else {
    576                     s0 = 0;
    577                     a3 = 0;
    578                 }
    579                 if (synthesisState->restart != FALSE) {
    580                     aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state));
    581                     flags = A_LOOP; // = 2
    582                     synthesisState->restart = FALSE;
    583                 }
    584                 nSamplesInThisIteration = s0 + s6 - s3;
    585                 if (nAdpcmSamplesProcessed == 0) {
    586                     switch (audioBookSample->codec) {
    587                         case CODEC_ADPCM:
    588                             aligned = ALIGN(t0 * unk_s6 + 16, 4);
    589                             addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
    590                             aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
    591                             aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
    592                             break;
    593                         case CODEC_S8:
    594                             aligned = ALIGN(t0 * unk_s6 + 16, 4);
    595                             addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
    596                             aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
    597                             aS8Dec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
    598                             break;
    599                     }
    600                     sp130 = s2 * 2;
    601                 } else {
    602                     s5Aligned = ALIGN(s5 + 16, 4);
    603                     switch (audioBookSample->codec) {
    604                         case CODEC_ADPCM:
    605                             aligned = ALIGN(t0 * unk_s6 + 16, 4);
    606                             addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
    607                             aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2);
    608                             aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
    609                             break;
    610                         case CODEC_S8:
    611                             aligned = ALIGN(t0 * unk_s6 + 16, 4);
    612                             addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
    613                             aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2);
    614                             aS8Dec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
    615                             break;
    616                     }
    617                     aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2);
    618                 }
    619                 nAdpcmSamplesProcessed += nSamplesInThisIteration;
    620                 switch (flags) {
    621                     case A_INIT: // = 1
    622                         sp130 = 0x20;
    623                         s5 = (s0 + 0x10) * 2;
    624                         break;
    625                     case A_LOOP: // = 2
    626                         s5 = (nSamplesInThisIteration) * 2 + s5;
    627                         break;
    628                     default:
    629                         if (s5 != 0) {
    630                             s5 = (nSamplesInThisIteration) * 2 + s5;
    631                         } else {
    632                             s5 = (s2 + (nSamplesInThisIteration)) * 2;
    633                         }
    634                         break;
    635                 }
    636                 flags = 0;
    637 skip:
    638                 if (noteFinished) {
    639                     aClearBuffer(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5,
    640                             (samplesLenAdjusted - nAdpcmSamplesProcessed) * 2);
    641                     noteSubEu->finished = 1;
    642                     note->noteSubEu.finished = 1;
    643                     func_sh_802ed644(updateIndex, noteIndex);
    644                     break;
    645                 }
    646                 if (restart != 0) {
    647                     synthesisState->restart = TRUE;
    648                     synthesisState->samplePosInt = loopInfo->start;
    649                 } else {
    650                     synthesisState->samplePosInt += nSamplesToProcess;
    651                 }
    652             }
    653 
    654             switch (nParts) {
    655                 case 1:
    656                     noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + sp130;
    657                     break;
    658                 case 2:
    659                     switch (curPart) {
    660                         case 0:
    661                             aDownsampleHalf(cmd++, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED);
    662                             resampledTempLen = samplesLenAdjusted;
    663                             noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED;
    664                             if (noteSubEu->finished != FALSE) {
    665                                 aClearBuffer(cmd++, noteSamplesDmemAddrBeforeResampling + resampledTempLen, samplesLenAdjusted + 0x10);
    666                             }
    667                             break;
    668                         case 1:
    669                             aDownsampleHalf(cmd++, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, resampledTempLen + DMEM_ADDR_RESAMPLED);
    670                             break;
    671                     }
    672             }
    673             if (noteSubEu->finished != FALSE) {
    674                 break;
    675             }
    676         }
    677     }
    678     flags = 0;
    679     if (noteSubEu->needsInit == TRUE) {
    680         flags = A_INIT;
    681         noteSubEu->needsInit = FALSE;
    682     }
    683     flags = flags | sp56;
    684     cmd = final_resample(cmd, synthesisState, bufLen * 2, resamplingRateFixedPoint,
    685             noteSamplesDmemAddrBeforeResampling, flags);
    686     if ((flags & 1) != 0) {
    687         flags = 1;
    688     }
    689 
    690     if (noteSubEu->filter) {
    691         aFilter(cmd++, 0x02, bufLen * 2, noteSubEu->filter);
    692         aFilter(cmd++, flags, DMEM_ADDR_TEMP, synthesisState->synthesisBuffers->filterBuffer);
    693 
    694     }
    695 
    696     if (noteSubEu->bookOffset == 3) {
    697         aUnknown25(cmd++, 0, bufLen * 2, DMEM_ADDR_TEMP, DMEM_ADDR_TEMP);
    698     }
    699 
    700     synthesisVolume = noteSubEu->synthesisVolume;
    701     if (synthesisVolume != 0) {
    702         if (synthesisVolume < 0x10) {
    703             synthesisVolume = 0x10;
    704         }
    705 
    706         aHiLoGain(cmd++, synthesisVolume, (bufLen + 0x10) * 2, DMEM_ADDR_TEMP);
    707     }
    708 
    709     if (noteSubEu->headsetPanRight != 0 || synthesisState->prevHeadsetPanRight != 0) {
    710         leftRight = 1;
    711     } else if (noteSubEu->headsetPanLeft != 0 || synthesisState->prevHeadsetPanLeft != 0) {
    712         leftRight = 2;
    713     } else {
    714         leftRight = 0;
    715     }
    716     cmd = process_envelope(cmd, noteSubEu, synthesisState, bufLen, DMEM_ADDR_TEMP, leftRight, flags);
    717     if (noteSubEu->usesHeadsetPanEffects) {
    718         if ((flags & 1) == 0) {
    719             flags = 0;
    720         }
    721         cmd = note_apply_headset_pan_effects(cmd, noteSubEu, synthesisState, bufLen * 2, flags, leftRight);
    722     }
    723 
    724     return cmd;
    725 }
    726 
    727 u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad) {
    728     s32 a3;
    729     s32 repeats;
    730     aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples),
    731                 DMEM_ADDR_UNCOMPRESSED_NOTE, 128);
    732 
    733     synthesisState->samplePosInt &= 0x3f;
    734     a3 = 64 - synthesisState->samplePosInt;
    735     if (a3 < nSamplesToLoad) {
    736         repeats = (nSamplesToLoad - a3 + 63) / 64;
    737         if (repeats != 0) {
    738             aDuplicate(cmd++,
    739                     /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE,
    740                     /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + 128,
    741                     /*copies*/ repeats);
    742         }
    743     }
    744     return cmd;
    745 }
    746 
    747 u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags) {
    748     if (pitch == 0) {
    749         aClearBuffer(cmd++, DMEM_ADDR_TEMP, count);
    750     } else {
    751         aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count);
    752         aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->finalResampleState));
    753     }
    754     return cmd;
    755 }
    756 
    757 u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, UNUSED u32 flags) {
    758     u16 sourceRight;
    759     u16 sourceLeft;
    760     u16 targetLeft;
    761     u16 targetRight;
    762     s16 rampLeft;
    763     s16 rampRight;
    764     s32 sourceReverbVol;
    765     s16 rampReverb;
    766     s32 reverbVolDiff = 0;
    767 
    768     sourceLeft = synthesisState->curVolLeft;
    769     sourceRight = synthesisState->curVolRight;
    770     targetLeft = note->targetVolLeft;
    771     targetRight = note->targetVolRight;
    772     targetLeft <<= 4;
    773     targetRight <<= 4;
    774 
    775     if (targetLeft != sourceLeft) {
    776         rampLeft = (targetLeft - sourceLeft) / (nSamples >> 3);
    777     } else {
    778         rampLeft = 0;
    779     }
    780     if (targetRight != sourceRight) {
    781         rampRight = (targetRight - sourceRight) / (nSamples >> 3);
    782     } else {
    783         rampRight = 0;
    784     }
    785 
    786     sourceReverbVol = synthesisState->reverbVol;
    787     if (note->reverbVol != sourceReverbVol) {
    788         reverbVolDiff = ((note->reverbVol & 0x7f) - (sourceReverbVol & 0x7f)) << 9;
    789         rampReverb = reverbVolDiff / (nSamples >> 3);
    790         synthesisState->reverbVol = note->reverbVol;
    791     } else {
    792         rampReverb = 0;
    793     }
    794     synthesisState->curVolLeft = sourceLeft + rampLeft * (nSamples >> 3);
    795     synthesisState->curVolRight = sourceRight + rampRight * (nSamples >> 3);
    796 
    797     if (note->usesHeadsetPanEffects) {
    798         aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DEFAULT_LEN_1CH);
    799         aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, rampReverb, rampLeft, rampRight);
    800         aEnvSetup2(cmd++, sourceLeft, sourceRight);
    801 
    802         switch (headsetPanSettings) {
    803             case 1:
    804                 aEnvMixer(cmd++,
    805                     inBuf, nSamples,
    806                     (sourceReverbVol & 0x80) >> 7,
    807                     note->stereoStrongRight, note->stereoStrongLeft,
    808                     DMEM_ADDR_NOTE_PAN_TEMP,
    809                     DMEM_ADDR_RIGHT_CH,
    810                     DMEM_ADDR_WET_LEFT_CH,
    811                     DMEM_ADDR_WET_RIGHT_CH);
    812                 break;
    813             case 2:
    814                 aEnvMixer(cmd++,
    815                     inBuf, nSamples,
    816                     (sourceReverbVol & 0x80) >> 7,
    817                     note->stereoStrongRight, note->stereoStrongLeft,
    818                     DMEM_ADDR_LEFT_CH,
    819                     DMEM_ADDR_NOTE_PAN_TEMP,
    820                     DMEM_ADDR_WET_LEFT_CH,
    821                     DMEM_ADDR_WET_RIGHT_CH);
    822                 break;
    823             default:
    824                 aEnvMixer(cmd++,
    825                     inBuf, nSamples,
    826                     (sourceReverbVol & 0x80) >> 7,
    827                     note->stereoStrongRight, note->stereoStrongLeft,
    828                     DMEM_ADDR_LEFT_CH,
    829                     DMEM_ADDR_RIGHT_CH,
    830                     DMEM_ADDR_WET_LEFT_CH,
    831                     DMEM_ADDR_WET_RIGHT_CH);
    832                 break;
    833         }
    834     } else {
    835         aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, rampReverb, rampLeft, rampRight);
    836         aEnvSetup2(cmd++, sourceLeft, sourceRight);
    837         aEnvMixer(cmd++,
    838                 inBuf, nSamples,
    839                 (sourceReverbVol & 0x80) >> 7,
    840                 note->stereoStrongRight, note->stereoStrongLeft,
    841                 DMEM_ADDR_LEFT_CH,
    842                 DMEM_ADDR_RIGHT_CH,
    843                 DMEM_ADDR_WET_LEFT_CH,
    844                 DMEM_ADDR_WET_RIGHT_CH);
    845     }
    846     return cmd;
    847 }
    848 
    849 u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight) {
    850     u16 dest;
    851     u16 pitch;
    852     u8 prevPanShift;
    853     u8 panShift;
    854     UNUSED u8 unkDebug;
    855 
    856     switch (leftRight) {
    857         case 1:
    858             dest = DMEM_ADDR_LEFT_CH;
    859             panShift = noteSubEu->headsetPanRight;
    860             note->prevHeadsetPanLeft = 0;
    861             prevPanShift = note->prevHeadsetPanRight;
    862             note->prevHeadsetPanRight = panShift;
    863             break;
    864         case 2:
    865             dest = DMEM_ADDR_RIGHT_CH;
    866             panShift = noteSubEu->headsetPanLeft;
    867             note->prevHeadsetPanRight = 0;
    868 
    869             prevPanShift = note->prevHeadsetPanLeft;
    870             note->prevHeadsetPanLeft = panShift;
    871             break;
    872         default:
    873             return cmd;
    874     }
    875 
    876     if (flags != 1) { // A_INIT?
    877         // Slightly adjust the sample rate in order to fit a change in pan shift
    878         if (panShift != prevPanShift) {
    879             pitch = (((bufLen << 0xf) / 2) - 1) / ((bufLen + panShift - prevPanShift - 2) / 2);
    880             aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, (bufLen + panShift) - prevPanShift);
    881             aResampleZoh(cmd++, pitch, 0);
    882         } else {
    883             aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen);
    884         }
    885 
    886         if (prevPanShift != 0) {
    887             aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer),
    888                         DMEM_ADDR_NOTE_PAN_TEMP, ALIGN(prevPanShift, 4));
    889             aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift, bufLen + panShift - prevPanShift);
    890         } else {
    891             aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP, bufLen + panShift);
    892         }
    893     } else {
    894         // Just shift right
    895         aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen);
    896         aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, panShift);
    897         aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + panShift, bufLen);
    898     }
    899 
    900     if (panShift) {
    901         // Save excessive samples for next iteration
    902         aSaveBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP + bufLen,
    903                     VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer), ALIGN(panShift, 4));
    904     }
    905 
    906     aAddMixer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, dest, (bufLen + 0x3f) & 0xffc0);
    907 
    908     return cmd;
    909 }
    910 #endif