Go Back   The PokéCommunity Forums > ROM Hacking > Research & Development
Reload this Page Development: ipatix' HQ Sound Mixer

Notices
For all updates, view the main page.

Research & Development Got a well-founded knack with ROM hacking? Love reverse-engineering the Pokémon games? Or perhaps you love your assembly language. This is the spot for polling and gathering your ideas, and then implementing them! Share your hypothesis, get ideas from others, and collaborate to create!
Research & Development programs in this forum are subject to moderator approval before they are displayed.



Reply
 
Thread Tools
  #1    
Old April 24th, 2014 (04:29 AM). Edited January 20th, 2015 by ipatix.
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
ipatix' High Quality Sound Mixer

Introduction:
If you are not interested in technical stuff skip to assembly and insertion. This is a pretty easy to do mod which could be used by any hack regardless of the use of music hacks. It also improves the vanilla music quality at no cost.

Hello and welcome do a new development thread of mine.
As you might already know from the thread's name I developed a new Sound Mixing Routine for GBA Pokemon games.
But what is the Sound Mixer? To understand what it does you need to know how digital sound is produced and what hardware ability the AGB has.
To explain it very basic: The AGB only has 2 hardware channels for sound playback (usually one for the left and one for the right speaker). With these 2 channels we could only play 1 stereo sound at one of the 12 samplingrates the AGB hardware supports. This is where the mixer and a resampler comes in handy. The mixer "mixes" together a few sounds and produces one output sound. Using this we can play back more sound at the same time and if we use this in combination with a resampler we can playback any sound at any given samplingrate (--> variable pitch) at the same time.
All of this is done by Nintendo's (with some mods done by Game Freak) Sound Engine which comes with their SDK. Sounds cool, doesn't it?

There has been done one major flaw with the design of the Mixer though:
The Sound Mixer produces a short period of sound each frame (~ 1/60 s) which gets placed in a buffer in memory. This data is then transferred by hardware timers and DMAs to the sound circuit for playback. Since the AGB only supports 8 bit resoultion of the audio samples this buffer must have an 8 bit depth. Because Nintendo wanted to make their code use less System ressources and RAM they also use this output buffer as work area for the actual mixing. This might not sound very problematic but the issues we are getting is that a Sound that has an 8 bit resolution has hearable quantization noise. This quantization noise is pretty low, however, each time the mixer adds another sound from a virtual channel (these are also called Direct Sound channels although they have nothing to do with Microsoft's DirectSound) it adds quantization noise to the buffer due to the volume scaling that is always done (we can't play all channels at a fixed volume). Because the quantization noise is applied once per channel it get's really loud and is really annoying (even in some commercial titles, not Pokemon though). In Pokemon games this is mostly not noticeable due to an untrained ear and the limited virtual Direct Sound channels of 5. 5 Direct Sound channels aren't much though (if you have ever done Music Hacking) and I personally do the 12 channel hack already for quite a long time. This makes the noise worse though and it did make the music sound really bad sometimes.


Then I came up with a solution for this:
Let's use a work area with a higher bit depth (e.g. commonly used 16 bits, or 14 bits in my Routine) to eliminate quantization noise during the mixing process and only add the noise once for the final downscaling to the main output buffer. The only problem we're getting is that we need an additional "work buffer" in IRAM. We need to use IRAM and not regular WRAM due to the execution performance we need. This also why the mixing routine is really complicated and very annoying to read to get the best performance possible (although there still would some improvments possible). The other thing that is necessary to run things as fast is possible is that the mixing routine is placed in IRAM aswell for faster code loading and the ability to use the ARM instruction set with no performance cost but with the ability to reduce the overall amount of instructions.
I took my time and disassembled the code during the last two weeks and tried to understand how it works. I didn't completley understand everything but I understood the most important parts that we're required to realize my project.

The Routine:
I'll share the modified routine with you here but I won't explain how it works because it is so complicated for someone who isn't into sound programming. However, during the disassembly process I documented nearly every instruction and wrote down what it does. But you probably won't understand it anway
Every line that is marked with 3x "#" has been added or modified from the original routine.
So here it is:

Code:
@ created by ~ipatix~

    .equ    GAME_BPED, 0
    .equ    GAME_BPEE, 1
    .equ    GAME_BPRE, 2
    .equ    GAME_KWJ6, 3


    .equ    USED_GAME, GAME_BPED                @ CHOOSE YOUR GAME

    .equ    FRAME_LENGTH_5734, 0x60
    .equ    FRAME_LENGTH_7884, 0x84
    .equ    FRAME_LENGTH_10512, 0xB0
    .equ    FRAME_LENGTH_13379, 0xE0            @ DEFAULT
    .equ    FRAME_LENGTH_15768, 0x108
    .equ    FRAME_LENGTH_18157, 0x130
    .equ    FRAME_LENGTH_21024, 0x160
    .equ    FRAME_LENGTH_26758, 0x1C0
    .equ    FRAME_LENGTH_31536, 0x210
    .equ    FRAME_LENGTH_36314, 0x260
    .equ    FRAME_LENGTH_40137, 0x2A0
    .equ    FRAME_LENGTH_42048, 0x2C0

    .equ    BPED_DELTA_TABLE, 0x08686C5C
    .equ    BPEE_DELTA_TABLE, 0x08675A70
    .equ    BPRE_DELTA_TABLE, 0x084899F8
    .equ    KWJ6_DELTA_TABLE, 0x0807CC0C

    .equ    DECODER_BUFFER_BPE, 0x03001300
    .equ    DECODER_BUFFER_BPR, 0x03002088
    .equ    DECODER_BUFFER_KWJ, 0x03005800

    .equ    FREE_IRAM_BPE, 0x03005100
    .equ    FREE_IRAM_BPR, 0x03004200
    .equ    FREE_IRAM_KWJ, 0x03005840

@*********** IF BPED
.if USED_GAME==GAME_BPED

    .equ    hq_buffer, FREE_IRAM_BPE
    .equ    buffer_spacing, FRAME_LENGTH_13379*2
    .equ    delta_table, BPED_DELTA_TABLE
    .equ    decoder_buffer_target, DECODER_BUFFER_BPE
    .equ    ALLOW_PAUSE, 1

.endif
@*********** IF BPEE
.if USED_GAME==GAME_BPED

    .equ    hq_buffer, FREE_IRAM_BPE
    .equ    buffer_spacing, FRAME_LENGTH_13379*2
    .equ    delta_table, BPEE_DELTA_TABLE
    .equ    decoder_buffer_target, DECODER_BUFFER_BPE
    .equ    ALLOW_PAUSE, 1

.endif
@*********** IF BPRE
.if USED_GAME==GAME_BPRE

    .equ    hq_buffer, FREE_IRAM_BPR
    .equ    buffer_spacing, FRAME_LENGTH_13379*2
    .equ    delta_table, BPRE_DELTA_TABLE
    .equ    decoder_buffer_target, DECODER_BUFFER_BPR
    .equ    ALLOW_PAUSE, 1

.endif
@*********** IF KWJ6
.if USED_GAME==GAME_KWJ6

    .equ    hq_buffer, FREE_IRAM_KWJ
    .equ    buffer_spacing, FRAME_LENGTH_13379*2
    .equ    delta_table, KWJ6_DELTA_TABLE
    .equ    decoder_buffer_target, DECODER_BUFFER_KWJ
    .equ    ALLOW_PAUSE, 0

.endif
@***********

    .equ    CHN_STATUS, 0x0
    .equ    CHN_MODE, 0x1
    .equ    CHN_VOL_1, 0x2
    .equ    CHN_VOL_2, 0x3
    .equ    CHN_ATTACK, 0x4
    .equ    CHN_DECAY, 0x5
    .equ    CHN_SUSTAIN, 0x6
    .equ    CHN_RELEASE, 0x7
    .equ    CHN_ADSR_LEVEL, 0x9
    .equ    CHN_FINAL_VOL_1, 0xA
    .equ    CHN_FINAL_VOL_2, 0xB
    .equ    CHN_ECHO_VOL, 0xC
    .equ    CHN_ECHO_REMAIN, 0xD
    .equ    CHN_POSITION_REL, 0x18                @ RELATIVE FOR COMPRESSED SAMPLES (decrementing)
    .equ    CHN_FINE_POSITION, 0x1C
    .equ    CHN_FREQUENCY, 0x20
    .equ    CHN_WAVE_OFFSET, 0x24
    .equ    CHN_POSITION_ABS, 0x28                @ RELATIVE FOR COMPRESSED SAMPLES (incrementing)
    .equ    CHN_BLOCK_COUNT, 0x3C

    .equ    WAVE_LOOP_FLAG, 0x3
    .equ    WAVE_FREQ, 0x4
    .equ    WAVE_LOOP_START, 0x8
    .equ    WAVE_LENGTH, 0xC

    .equ    ARG_FRAME_LENGTH, 0x0
    .equ    ARG_CHN_LEFT, 0x4
    .equ    ARG_BUFFER_POS, 0x8
    .equ    ARG_ABS_LOOP_OFFSET, 0xC
    .equ    ARG_LOOP_MODE, 0x10
    .equ    ARG_SCAN_LIMIT, 0x14
    .equ    ARG_VAR_AREA, 0x18

    .equ    VAR_REVERB, 0x5
    .equ    VAR_MAX_CHN, 0x6
    .equ    VAR_MASTER_VOL, 0x7
    .equ    VAR_DEF_PITCH_FAC, 0x18
    .equ    VAR_FIRST_CHN, 0x50

    .equ    FLAG_CHN_INIT, 0x80
    .equ    FLAG_CHN_RELEASE, 0x40
    .equ    FLAG_CHN_COMP, 0x20
    .equ    FLAG_CHN_LOOP, 0x10
    .equ    FLAG_CHN_ECHO, 0x4
    .equ    FLAG_CHN_ATTACK, 0x3
    .equ    FLAG_CHN_DECAY, 0x2
    .equ    FLAG_CHN_SUSTAIN, 0x1

    .equ    MODE_COMPRESSED, 0x30
    .equ    MODE_FIXED_FREQ, 0x8
    .equ    MODE_REVERSE, 0x10

    .global    mixer_entry
    .thumb
    .align 2

@********************* ENTRY ************************@
mixer_entry:

LDRB    R3, [R0, #VAR_REVERB]            @ Load Reverb Value from byte #5 given by var area to R3
CMP    R3, #0                    @ 
BEQ    clear_buffer                @ if Reverb == 0 --> just clear the buffer and don't do any reverb

ADR    R1, do_reverb                @ Reverb is enabled --> load reverb handler label to R1
BX    R1                    @ switch to ARM and execute Reverb Handler
@******************* ENTRY END **********************@

    .align 2
    .arm

@******************* DO REVERB **********************@
do_reverb:

CMP    R4, #2                    @ load 2nd reverb source from frame before
ADDEQ    R7, R0, #0x350                @ this resets the position to read data from the frame before the actual work frame
ADDNE    R7, R5, R8                @
MOV    R4, R8                    @ R4 shall be a countdown variable

LDR    R10, hq_buffer_1            @ ### load alternate buffer location
LDR    R11, buffer_spacing_1            @ ### do the same for the buffer spacing


reverb_loop:
LDRSB    R0, [R5, R6]                @ load 2nd buffer sample to R0
LDRSB    R1, [R5], #1                @ ### load 1st buffer sample to R1 --- modified the sample pointer extension
ADD    R0, R0, R1                @ mix samples together
LDRSB    R1, [R7, R6]                @ load 2nd buffer sample from previous frame to R1
ADD    R0, R0, R1                @ mix samples together
LDRSB    R1, [R7], #1                @ load 1st buffer sample from previous frame to R1 and increment sample counter
ADD    R0, R0, R1                @ mix samples together
MUL    R1, R0, R3                @ apply reverb level by multiplication
MOV    R0, R1, ASR#3                @ ### shift down sample from s8 to s16 (changed from ASR#9 to ASR#3) - modified -
TST    R0, #0x3000                @ check if sample is negative
ADDNE    R0, R0, #0x20                @ add #1 to sample if negative - this improves the ASR division for the negative area because the lowest possible negative division result is -1 and not 0
STRH    R0, [R10, R11]                @ write calculated reverb sample to HQ buffer 2
STRH    R0, [R10], #2                @ write calculated reverb sample to HQ buffer 1 and increment buffer counter by two (16 bit samples each)
SUBS    R4, R4, #1                @ decrease buffer counter by 1
BGT    reverb_loop                @ if the counter is > 0 repeat the procedure

ADR    R0, loop_setup+1            @ load next step label to R0
BX    R0                    @ jump and switch back to THUMB
@******************* REVERB END *********************@

    .thumb
    
@******************* BUFF CLEAR *********************@
clear_buffer:

MOV    R0, #0                    @ Copy 0 to R0 to be able to use this register to clear memory
MOV    R1, R8                    @ Copy Buffer length to R1 for calculation
LDR    R5, hq_buffer_1                @ ### override the buffer position with the HQ one
LDR    R6, buffer_spacing_1            @ ### do the same for the buffer spacing
ADD    R6, R6, R5                @ Buffer position + stereo spacing = buffer #2 position
LSR    R1, #2                    @ check for bad buffer alignment and clear the buffer depending on that
                        @ ### changed shift from 3 to 2 (buffer twice as long)

BCC    clear_buffer_align_8

clear_buffer_align_4:                @ if buffer is 4 aligned

STMIA    R5!, {R0}
STMIA    R6!, {R0}

clear_buffer_align_8:                @ if buffer is 8 aligned

LSR    R1, #1
BCC    clear_buffer_align_16

STMIA    R5!, {R0}
STMIA    R6!, {R0}
STMIA    R5!, {R0}
STMIA    R6!, {R0}

clear_buffer_align_16:                @ if buffer is 16 aligned (usual case)

STMIA    R5!, {R0}
STMIA    R6!, {R0}
STMIA    R5!, {R0}
STMIA    R6!, {R0}
STMIA    R5!, {R0}
STMIA    R6!, {R0}
STMIA    R5!, {R0}
STMIA    R6!, {R0}
SUB    R1, #1
BGT    clear_buffer_align_16            @ repeat procedure until buffer is cleared
B    loop_setup
@***************** BUFF CLEAR END *******************@


    .align 2
hq_buffer_1:
    .word    hq_buffer
buffer_spacing_1:
    .word    buffer_spacing

@********************* SETUP ************************@
loop_setup:

LDR    R4, [SP, #ARG_VAR_AREA]            @ load ARG_0x18 (main var area) to R4
LDR    R0, [R4, #VAR_DEF_PITCH_FAC]        @ load samplingrate pitch factor value to R0
MOV    R12, R0                    @ copy factor to R12
LDRB    R0, [R4, #VAR_MAX_CHN]            @ load MAX channels to R0
ADD    R4, #VAR_FIRST_CHN            @ R4 == Base channel Offset (Channel 0)
@******************* END SETUP **********************@

@***************** MAIN CHANNELS ********************@
channel_main_loop:

STR    R0, [SP, #ARG_CHN_LEFT]            @ store Max Channel value to create a count variable
LDR    R3, [R4, #CHN_WAVE_OFFSET]        @ load Wave Data offset to R3
LDR    R0, [SP, #ARG_SCAN_LIMIT]        @ load Scanline limit to R0 (0 = disabled)
CMP    R0, #0                    @ Scanline limit disabled?
BEQ    channel_begin                @ if limit is disabled skip the processing time limiter

LDR    R1, vcount_reg                @ load scanline register offset into R1
LDRB    R1, [R1]                @ load current scanline into R1
CMP    R1, #0xA0                @ is current scanline out of visivle area?
BCS    scanline_vblank

ADD    R1, #0xE4                @ add total amount of lines to R1

scanline_vblank:

CMP    R1, R0                    @ do the scanlines exceed the limit
BCC    channel_begin                @ if it doesn't continue with channel loop
B    mixer_end                @ if it does, end the loop

    .align 2
vcount_reg:
    .word    0x04000006            @ register address to vcount

channel_begin:

LDRB    R6, [R4]                @ load channel byte #0x0 to R6
MOVS    R0, #0xC7                @ load comparison byte into R0
TST    R0, R6                    @ is any of the bytes set?
BNE    channel_status_check            @ if any of 0xC7 bits is set then jump to channel_status_check
B    channel_check_processed_channels    @ if no bit is set go to the channel processing check

channel_status_check:

MOVS    R0, #FLAG_CHN_INIT            @ load "start channel" comparison value into R0
TST    R0, R6                    @ is the associated bit set?
BEQ    channel_envelope_handler        @ if it isn't set go over to TEMP_LABEL

MOVS    R0, #FLAG_CHN_RELEASE            @ load "channel on release" comparison value into R0
TST    R0, R6                    @ is the associated bit set?
BNE    channel_stop_func            @ if it IS set jump to label

                        @ The Routine will continue when the "channel started flag" is set and release is off

MOVS    R6, #FLAG_CHN_ATTACK            @ load channel status ATTACK to R6                - R3 = Wave Data Header Position - R4 = Channel Offset
STRB    R6, [R4]                @ write status to status byte in channel data array
MOVS    R0, R3                    @ load sample pointer to R0
ADD    R0, #0x10                @ extend wave data pointer so it points to the actual beginning of the wave data

@*************** Pokemon Games *****************@
.if ALLOW_PAUSE==1
LDR    R1, [R4, #CHN_POSITION_REL]        @ load sample position into R1
ADD    R0, R0, R1                @ add it to the base offset
STR    R0, [R4, #CHN_POSITION_ABS]        @ write the current sample position to 0x28 of channel in array
LDR    R0, [R3, #WAVE_LENGTH]            @ load sample length into R0
SUB    R0, R0, R1                @ R0 = Samples left (if it's 0 the end of sample is reached)
STR    R0, [R4, #CHN_POSITION_REL]        @ Write samples left into Relative Channel Position Variable in Channel
.endif
@************* End Pokemon Games ***************@

@**************** Other Games ******************@
.if ALLOW_PAUSE==0
STR    R0, [R4, #CHN_POSITION_ABS]
LDR    R0, [R3, #WAVE_LENGTH]
STR    R0, [R4, #CHN_POSITION_REL]
.endif
@************** End Other Games ****************@

MOVS    R5, #0                    @ Set R5 = 0
STRB    R5, [R4, #CHN_ADSR_LEVEL]        @ Reset Envelope level to #0
STR    R5, [R4, #CHN_FINE_POSITION]        @ Reset Fine Sample Position (UNCONFIRMED!!!)
LDRB    R2, [R3, #WAVE_LOOP_FLAG]        @ Load Loop Flag into R2
MOVS    R0, #0xC0                @ Load Loop Flag comparison value into R0    0x40 PROBABLY POSSIBLE ASWELL???
TST    R0, R2                    @ Loop off --> Equal; Loop on --> Not Equal
BEQ    channel_adsr_attack_handler        @ if the loop is off skip the loop handler

MOV    R0, #0x10                @
ORR    R6, R0                    @ Turn on Bit of channel status 0x10 / B.0001.0000
STRB    R6, [R4]                @ Info: Loop Flag in Channel Status
B    channel_adsr_attack_handler

channel_envelope_handler:
LDRB    R5, [R4, #CHN_ADSR_LEVEL]        @ load channel ADSR LEVEL to R5
MOVS    R0, #FLAG_CHN_ECHO            @ load Echo Flag to R0
TST    R0, R6                    @ is the Echo Flag Set?
BEQ    channel_adsr_no_echo            @ if Echo Flag is clear jump to regular ADSR handler

LDRB    R0, [R4, #CHN_ECHO_REMAIN]        @ load remainung Echo length to R0
SUB    R0, #1                    @ subtract by one
STRB    R0, [R4, #CHN_ECHO_REMAIN]        @ store remainung Echo length
BHI    channel_vol_calc            @ if Echo remain > 1 jump to main MATH --- Else go over to channel_stop

channel_stop_func:

MOVS    R0, #0                    @ load 0 into R0
STRB    R0, [R4]                @ write channel status 0 (STOP COMPLETLEY)
B    channel_check_processed_channels

channel_adsr_no_echo:

MOVS    R0, #FLAG_CHN_RELEASE            @ load Release Flag into R0 for comparison
TST    R0, R6                    @ is Release Flag clear?
BEQ    channel_adsr_no_release            @ Release clear --> goto no_release ; Release set --> continue func

LDRB    R0, [R4, #CHN_RELEASE]            @ load release value into R0 | INFO: R5 = ADSR LEVEL
MUL    R5, R0                    @ Multiplay ADSR Level with Release
LSR    R5, R5, #8                @ Divide ADSR Level by 256 -> new ADSR Level
LDRB    R0, [R4, #CHN_ECHO_VOL]            @ load Echo Volume to R0
CMP    R5, R0                    @ Is ADSR value higher than Echo vol?
BHI    channel_vol_calc            @ go on with main MATH

channel_adsr_check_echo_disabled:

LDRB    R5, [R4, #CHN_ECHO_VOL]            @ load up once again the Echo Vol to R5
CMP    R5, #0                    @ make sure that the Echo Vol is not 0 (to disable echo)
BEQ    channel_stop_func            @ channel got released and no Echo is enabled -> disable channel

MOVS    R0, #FLAG_CHN_ECHO            @ load the Echo Flag to R0
ORR    R6, R0                    @ Set the bit for the Echo flag in the channel status
STRB    R6, [R4]                @ write the Channel Status to memory
B    channel_vol_calc            @ go on with the main math

channel_adsr_no_release:

MOVS    R2, #3                    @ load B11 to R2 (to remove any other bits from the channel status)
AND    R2, R6                    @ cut away other buts from the channel status to R2
CMP    R2, #FLAG_CHN_DECAY            @ Check if the Decay bit is set
BNE    channel_adsr_no_decay

LDRB    R0, [R4, #CHN_DECAY]            @ load Channel Decay to R0
MUL    R5, R0                    @ multiplay ADSR level with decay value
LSR    R5, R5, #8                @ divide by 256 to scale back to 8 bit value
LDRB    R0, [R4, #CHN_SUSTAIN]            @ load Sustain level for comparison to R0
CMP    R5, R0                    @ check if the decayed ADSR level is above Sustain
BHI    channel_vol_calc            @ if Sustain level not reached yet go to main MATH

MOVS    R5, R0                    @ if sustain level is reached copy sustain level to R5
BEQ    channel_adsr_check_echo_disabled    @ if sustain level is 0 check echo first before disabling the channel

SUB    R6, #1                    @ change channel status to Sustain from Decay
STRB    R6, [R4]                @ write status to memory
B    channel_vol_calc            @ head over to the main MATH

channel_adsr_no_decay:

CMP    R2, #FLAG_CHN_ATTACK            @ compare if the channel status is ATTACK
BNE    channel_vol_calc

channel_adsr_attack_handler:
LDRB    R0, [R4, #CHN_ATTACK]            @ load Attack value to R0
ADD    R5, R5, R0                @ add attack value to adsr level
CMP    R5, #0xFF                @ check if adsr reached/overflowed highest value
BCC    channel_vol_calc

MOVS    R5, #0xFF                @ if overflow --> adsr = 0xFF
SUB    R6, #1                    @ change from attack to decay mode
STRB    R6, [R4]                @ save the channel status

channel_vol_calc:

STRB    R5, [R4, #CHN_ADSR_LEVEL]        @ write the current adsr level back to the channel var area
LDR    R0, [SP, #ARG_VAR_AREA]            @ load the main var area to R0
LDRB    R0, [R0, #VAR_MASTER_VOL]        @ load the Master Volume into R0
ADD    R0, #1                    @ Add #1 to master volume, so the range goes from 0-15 to 1-16
MUL    R0, R5                    @ multiply master volume with channel adsr level to calc next vol level
LSR    R5, R0, #4                @ divide the new volume level by 16 to scale doesn the value to 8 bits

LDRB    R0, [R4, #CHN_VOL_1]            @ load Volume 1 (right) into R0
MUL    R0, R5                    @ multiply with previous vol level to R0
LSR    R0, R0, #8                @ scale down back to 8 bits
STRB    R0, [R4, #CHN_FINAL_VOL_1]        @ write final volume 1 to channel vars

LDRB    R0, [R4, #CHN_VOL_2]            @ load Volume 2 (left) into R0
MUL    R0, R5                    @ do the same procedure
LSR    R0, R0, #8                @ shift back to 8 bits
STRB    R0, [R4, #CHN_FINAL_VOL_2]        @ write final volume 2 to channel vars

MOVS    R0, #FLAG_CHN_LOOP            @ write Loop Flag comparison value to R0
AND    R0, R6                    @ seperate the flag bit from the status (R6) -> R0
STR    R0, [SP, #ARG_LOOP_MODE]        @ store the loop flag to Stack ARG
BEQ    channel_setup_mixing            @ skip loop setup procedure

MOVS    R0, R3                    @ copy wave header pointer to R0
ADD    R0, #0x10                @ add 0x10 so it matches the beginning of the actual wave data
LDR    R1, [R3, #WAVE_LOOP_START]        @ load the loop start position into R1 --- R1 = LoopStart (relative)
ADD    R0, R0, R1                @ R0 = absolute pointer of loop start
STR    R0, [SP, #ARG_ABS_LOOP_OFFSET]        @ Write the Result to the Stack
LDR    R0, [R3, #WAVE_LENGTH]            @ load the sample length into R0 --- R0 = Length/End (relative)
SUB    R0, R0, R1                @ calculate the difference from Loop End to Loop Start and store it in R0
STR    R0, [SP, #ARG_LOOP_MODE]        @ store the difference in the WAVE_LOOP_MODE Argument

channel_setup_mixing:

LDR    R5, hq_buffer_2                @ load buffer position to R5
LDR    R2, [R4, #CHN_POSITION_REL]        @ load relative sample position into R2 (samples left)
LDR    R3, [R4, #CHN_POSITION_ABS]        @ load the current position from the samples in ROM to R3
ADR    R0, channel_mixing            @ prepare switch to ARM Mode for mixing
BX    R0                    @ switch to ARM Mode

    .align 2
    
hq_buffer_2:
    .word    hq_buffer
    .arm

channel_mixing:                    @ ---------------------- MIXING STARTS HERE ------------------

STR    R8, [SP, #ARG_FRAME_LENGTH]        @ load some (slower) WRAM work area into R8
LDR    R9, [R4, #CHN_FINE_POSITION]        @ load the fine channel position into R9
LDRB    R10, [R4, #CHN_FINAL_VOL_1]        @ load the renderer volume 1, to R10
LDRB    R11, [R4, #CHN_FINAL_VOL_2]        @ do the same for volume 2 to R11
LDRB    R0, [R4, #CHN_MODE]            @ load the compression Mode Byte into R0
TST    R0, #MODE_COMPRESSED            @ check if the sample is uncompressed (0x20 & 0x30 usually indicate compressed samples and will cause the Z flag to be false)
BEQ    channel_uncompressed_mixing

BL    channel_compressed_mixing        @ load the compression decoder mixer instead of the regular one
B    channel_var_freq_mixing_store_fine_pos    @ end compressed channel mixing and go over to the normal fine position storing

channel_uncompressed_mixing:            @ uncompressed mixing init function

MOV    R10, R10, LSL#8                @ ### expand the volume levels to 24 bits from 8 bits --- changed to 16 bits
MOV    R11, R11, LSL#8
LDRB    R0, [R4, #CHN_MODE]            @ load the channel mode to R0
TST    R0, #MODE_FIXED_FREQ            @ check if the channel mode is not fixed frequency
BEQ    channel_var_freq_mixing            @ jump over to the variable frequency routine --- There is two different routines for fixed (non resampled) rates because Drums usually play with only one pitch and can speed up code execution time if no resampling is enabled

channel_fixed_freq_mixing_loop:

CMP    R2, #2                    @ check if the left sample amount is smaller or equal to 4
BLE    channel_fixed_freq_mixing_fetch_last    @ go down and process last samples if it's 4 or less --- continue if it's more

SUBS    R2, R2, R8                @ subtract the frame length from R2 (left samples)
MOVGT    R9, #0                    @ if there is enough samples to fill the frame, copy 0 to R9
BGT    channel_fixed_freq_mixing_fetch_samples    @ 

MOV    R9, R8                    @ copy frame length to R9
ADD    R2, R2, R8                @ R2 = samples left (subtraced and added R8 (frame length)?)
SUB    R8, R2, #4                @ ################ UNKNOWN; MAYBE SOMETHING BROKEN ??? ################ subtract the left samples by 4 and place the result in R8 --- Edit: Apperantly nothing broken
SUB    R9, R9, R8                @ RESULTS --> R2 = left samples --> R8 = left samples-4 --> R9 = FrameLength-(samplesLeft - 4)
ANDS    R2, R2, #3
MOVEQ    R2, #4

channel_fixed_freq_mixing_fetch_samples:    @ fetch current  4 samples from buffer #1 and #2

LDR    R6, [R5]                @ load the 4 samples from first buffer to R6
LDR    R7, [R5, #buffer_spacing]            @ do the same for buffer #2 and R7

channel_fixed_load_new_samples:

LDRSB    R0, [R3], #1                @ load sample from current position into R0 and increment the abs sample position by #1
MOV    R0, R0, LSL#6
MUL    R1, R10, R0                @ calc the samples level with volume amplification (remember. VOL << 16)
BIC    R1, R1, #0xFF00                @ ### clear the lower unimportant bits --- the level is now something like this: 0x??000000
ADD    R6, R1, R6, ROR#16            @ ### Now add this to the previous level and rotate the bits of the result --> next commands can edit the next sample like the previous one
MUL    R1, R11, R0                @ calculate the next level (vol #2)
BIC    R1, R1, #0xFF00                @ ### clear the bits like before
ADD    R7, R1, R7, ROR#16            @ ### do the same like before for the second buffer
ADDS    R5, R5, #0x80000000            @ ### ABUSE R5 as counting variable. this will cause the loop to repeat until the pointer of the sample buffer overflows to it's original position (i.e. 4 / 3 times) --- changed to 0x80000000 from 0x40000000
BCC    channel_fixed_load_new_samples        @ if the carry bit is not set (no overflow)

STR    R7, [R5, #buffer_spacing]            @ store the new samples to buffer #2
STR    R6, [R5], #4                @ store new samples to buffer #1 and increment buffer pointer
SUBS    R8, R8, #2                @ sample counter of one frame by 4 and check if it's bigger than #0
BGT    channel_fixed_freq_mixing_fetch_samples    @ repeat until the buffer got filled

ADDS    R8, R8, R9                @ R8 = samples left after frame -4
BEQ    channel_mixing_store_pos        @ check if the END/LOOP is reached 

channel_fixed_freq_mixing_fetch_last:

LDR    R6, [R5]                @ fetch the next samples #1 and #2
LDR    R7, [R5, #buffer_spacing]

channel_fixed_load_last_samples:

LDRSB    R0, [R3], #1                @ load next sample from memory with pointer increment
MOV    R0, R0, LSL#6
MUL    R1, R10, R0                @ multiply sample with volume factor #1
BIC    R1, R1, #0xFF00                @ ### cut away unimportant bits#
ADD    R6, R1, R6, ROR#16            @ ### add it to the buffer
MUL    R1, R11, R0                @ do the same thing for volume #2
BIC    R1, R1, #0xFF00                @ ### ...
ADD    R7, R1, R7, ROR#16            @ ### ...
SUBS    R2, R2, #1                @ left samples (1-4)
BEQ    channel_fixed_freq_loop_handler

channel_fixed_freq_count_sample:

ADDS    R5, R5, #0x80000000            @ ### abuse buffer pointer as counter variable --- changed from 0x40000000 to 0x80000000
BCC    channel_fixed_load_last_samples        @ repeat the procedure until the last samples are loaded

STR    R7, [R5, #buffer_spacing]            @ write the samples to the buffer
STR    R6, [R5], #4                @ increment the buffer counter
SUBS    R8, R8, #2                @ ### check if there is still samples to put into the current frame --- reduce the sample countdown to #2 instead of #4
BGT    channel_fixed_freq_mixing_loop        @ go back to the main loop
B    channel_mixing_store_pos        @ go to some end function

channel_var_freq_mixing_loop_handler:

LDR    R0, [SP, #0x18]                @ IMPORTANT: --> =ARG_LOOP_MODE (0x10) due to the moved Stack Pointer from the STMFD command
CMP    R0, #0                    @ is the loop disabled?
BEQ    channel_var_freq_mixing_stop_channel    @ if the loop is disabled, stop the channel

LDR    R3, [SP, #0x14]                @ IMPORTANT: --> =ARG_ABS_LOOP_OFFSET (0xC) due to the moved Stack pointer from the STMFD command
RSB    LR, R2, #0                @ LR = 0 - remaining samples

channel_var_freq_mixing_set_loop:

ADDS    R2, R0, R2                @ R2 = 0x10 + remaining samples
BGT    channel_var_freq_mixing_fetch_next    @ go on with mixing if there is a few left samples (?, not fully understood yet)

SUB    LR, LR, R0                @ - remaining samples - 0x10
B    channel_var_freq_mixing_set_loop

channel_var_freq_mixing_stop_channel:

LDMFD    SP!, {R4, R12}                @ pop registers from stack
MOV    R2, #0                    @ set the remaining samples to #0
B    channel_fixed_freq_stop_mixing        @ use the same handler as the fixed mixing to stop the channel

channel_fixed_freq_loop_handler:

LDR    R2, [SP, #ARG_LOOP_MODE]        @ load the loop flag of the current channel
CMP    R2, #0                    @ check if the loop flag is not set
LDRNE    R3, [SP, #ARG_ABS_LOOP_OFFSET]        @ if it is set, load the loop pointer into R3
BNE    channel_fixed_freq_count_sample        @ go back to the main loop

channel_fixed_freq_stop_mixing:

STRB    R2, [R4]                @ write 0 to the channel status to stop the channel
MOV    R0, R5, LSR#30                @ shoft the two LS Bits to the two MS Bits
BIC    R5, R5, #0xC0000000            @ clear the "counting" bits of the buffer pointer
RSB    R0, R0, #3                @ Subtract the "MS Bits value" from 3 and place the result in R0
MOV    R0, R0, LSL#4                @ ### Multiply R0 by 8 and cut away high bits --- changed from 3 to 4
MOV    R6, R6, ROR R0                @ rotate the last volume level to the final position
MOV    R7, R7, ROR R0                @ as well for volume #2
STR    R7, [R5, #buffer_spacing]        @ write the last samples to the buffer
STR    R6, [R5], #4                @ ...
B    channel_mixing_exit_func        @ go to the exit func to switch back to thumb mode and restart the channel loop

channel_var_freq_mixing:

STMFD    SP!, {R4, R12}                @ push R4 and R12 onto Stack (opposite direction of arguments)
LDR    R1, [R4, #CHN_FREQUENCY]        @ load the channels frequency value into R1
MUL    R4, R12, R1                @ multiply samplingrate pitch factor with the frequency
LDRSB    R0, [R3]                @ load first sample to memory
LDRSB    R1, [R3, #1]!                @ load the following sample into memory and increment sample counter by 1
SUB    R1, R1, R0                @ store sample DELTA to R1 and discard the following sample
MOV    R0, R0, LSL#6                @ ### added

channel_var_freq_mixing_loop:

LDR    R6, [R5]                @ load current samples from buffer to R6 (#1)
LDR    R7, [R5, #buffer_spacing]                @ do the same for buffer #2 with R7

channel_var_freq_mixing_resampling:

MUL    LR, R9, R1                @ multiply Fine Channel position with the delta (linear interpolation)
ADD    LR, R0, LR, ASR#17            @ ### add it to the base sample level to calculate the final level --- ASR#23 to ASR#17
MUL    R12, R10, LR                @ apply the final volume level #1 to R12
BIC    R12, R12, #0xFF00            @ clear garbage bits
ADD    R6, R12, R6, ROR#16            @ add it to the output sample word
MUL    R12, R11, LR                @ do the same for vol #2
BIC    R12, R12, #0xFF00            @ ...
ADD    R7, R12, R7, ROR#16            @ ...
ADD    R9, R9, R4                @ add samplingrate conversion factor to the fine channel position
MOVS    LR, R9, LSR#23                @ check if the fine channel position overflowed a certain range or how much it overflowed the range
BEQ    channel_var_freq_mixing_count

BIC    R9, R9, #0x3F800000            @ clear all "overflow" bits from R9 --> i.e. seperation from the overflow count (LR) and the actual left value (R9)
SUBS    R2, R2, LR                @ remove the overflow count from the left samples
BLE    channel_var_freq_mixing_loop_handler    @ handle the loop end / sample end

SUBS    LR, LR, #1                @ decrease overflow count by one and check if the overflow was fixed
ADDEQ    R0, R1, R0, ASR#6            @ ### if there is no more overflow after decreasing the overflow count calculate the next sample my simply adding the previous DELTA to the actual sample --- added shift

channel_var_freq_mixing_fetch_next:

LDRNESB    R0, [R3, LR]!                @ if the overflow was higher than 1 (skipped more than one sample) load the next ine depending on overflow
LDRSB    R1, [R3, #1]!                @ @ load the following sample to R1 for interpolation
SUB    R1, R1, R0                @ calculate the DELTA to R1
MOV    R0, R0, LSL#6                @ ### added left shift

channel_var_freq_mixing_count:

ADDS    R5, R5, #0x80000000            @ ### abuse sample pointer as counter variable --- changed from 0x40000000 to 0x80000000
BCC    channel_var_freq_mixing_resampling    @ repeat the resampling/mixing process until 4 bytes of samples are filled

STR    R7, [R5, #buffer_spacing]        @ store sample #2
STR    R6, [R5], #4                @ store sample #1  and increment sample counter
SUBS    R8, R8, #2                @ ### decrease samples left from current frame by 4 - changed to #2 samples per loop
BGT    channel_var_freq_mixing_loop        @ if there is still samples to fill repeat the loop for mixing and resampling

SUB    R3, R3, #1                @ decrease current absolute sample position by one (it has been increased by one due to the interpolation)
LDMFD    SP!, {R4, R12}                @ pop 2 registers from the stack

channel_var_freq_mixing_store_fine_pos:        @ store the fine position for non-fixed freq modes (i.e. compressed and/or pitched sounds)

STR    R9, [R4, #CHN_FINE_POSITION]        @ store the fine channel position

channel_mixing_store_pos:

STR    R2, [R4, #CHN_POSITION_REL]        @ store absolute and relative sample position
STR    R3, [R4, #CHN_POSITION_ABS]        @

channel_mixing_exit_func:

LDR    R8, [SP, #ARG_FRAME_LENGTH]        @ reset the frame length
ADR    R0, channel_check_processed_channels+1    @ load the thumb adress | 1 to change to thumb mode
BX    R0

    .thumb

channel_check_processed_channels:
LDR    R0, [SP, #ARG_CHN_LEFT]            @ load Channel counter variable to R0
SUB    R0, #1                    @ decrease channel count by 1
BLE    mixer_end                @ if channel count <= 0 go to end func

ADD    R4, #0x40                @ add 0x40 to channel offset register so the Routine will process the next channel
B    channel_main_loop

mixer_end:                    @ MAIN END HANDLER

ADR    R0, downsampler
BX    R0

downsampler_return:

LDR    R0, [SP, #ARG_VAR_AREA]            @ load the main var area to R0
LDR    R3, mixer_finished_status        @ load some status indication value to R3
STR    R3, [R0]                @ store this value to the main var area
ADD    SP, SP, #0x1C                @ discard the argument variables
POP    {R0-R7}                    @ reload previous registers
MOV    R8, R0                    @ backup some registers into the HIGH registers
MOV    R9, R1                    @ ...
MOV    R10, R2                    @ ...
MOV    R11, R3                    @ ...
POP    {R3}                    @ get the return address from the stack
BX    R3                    @ -------------------------- END THE MIXER AND RETURN TO "m4aMain()" --------------------------------

    .align    2

mixer_finished_status:
    .word    0x68736D53

@*************** MAIN CHANNELS END ******************@

    .arm

@****************** DOWNSAMPLER *********************@

@ ### the complete Downsampler section has been added

downsampler:

LDR    R7, buffer_spacing_2
MOV    R6, R8
LDR    R5, [SP, #ARG_BUFFER_POS]
LDR    R4, hq_buffer_3

downsampler_loop:

LDRSH    R1, [R4, R7]
LDRSH    R0, [R4], #2
LDRSH    R3, [R4, R7]
LDRSH    R2, [R4], #2

MOV    R0, R0, ASR#6
MOV    R1, R1, ASR#6
MOV    R2, R2, ASR#6
MOV    R3, R3, ASR#6

STRB    R1, [R5, #0x630]
STRB    R0, [R5], #1
STRB    R3, [R5, #0x630]
STRB    R2, [R5], #1

SUBS    R6, R6, #2
BGT    downsampler_loop

ADR    R0, downsampler_return+1
BX    R0

@ ###

@**************** DOWNSAMPLER END *******************@

hq_buffer_3:
    .word    hq_buffer
buffer_spacing_2:
    .word    buffer_spacing


@************ DECOMPRESSOR + RESAMPLER **************@

channel_compressed_mixing:

LDR    R6, [R4, #CHN_WAVE_OFFSET]        @ load the wave header offset to R6
LDRB    R0, [R4]                @ load the compression flag into R0
TST    R0, #FLAG_CHN_COMP            @ check if the compression flag is set
BNE    setup_compressed_mixing_frequency    @ if it is set go over to ???

ORR    R0, R0, #0x20                @ set the compression flag
STRB    R0, [R4]                @ write the updated status byte to Channelo
LDRB    R0, [R4, #CHN_MODE]            @ load the channel mode to R0
TST    R0, #MODE_REVERSE            @ check if reverse playback is enabled
BEQ    determine_compression_type

special_compression_setup:

LDR    R1, [R6, #WAVE_LENGTH]            @ R1 = sample length/end
ADD    R1, R1, R6, LSL#1            @ get the absolute end position of the waveform and multiply it by 2 due to the compressed samples only being 4 bits long
ADD    R1, R1, #0x20                @ add 0x20 to match the real *2 beginning of the wave data (header length 0x10 * 2)
SUB    R3, R1, R3                @ subtract the orgignal wave data offset from the calculated value to get the actual beginning of the wave data
STR    R3, [R4, #CHN_POSITION_ABS]

determine_compression_type:

LDRH    R0, [R6]                @ load the wave data type to R6 (0x1 = compressed; 0x0 = pcm)
CMP    R0, #0                    @ check if the sample is uncompressed
BEQ    setup_compressed_mixing_frequency

SUB    R3, R3, R6                @ do some unkown asolute position calculating ??????
SUB    R3, R3, #0x10                @ same here ??????????
STR    R3, [R4, #CHN_POSITION_ABS]

setup_compressed_mixing_frequency:

STMFD    SP!, {R8, R12, LR}            @ save the registers for frame lengthcounter and the actual length in R12--> (SP - 0xC) --- 
MOV    R10, R10, LSL#8                @ ### shift the volume #1 to the 2nd MSB --- changed to 8 from 16
MOV    R11, R11, LSL#8                @ ### shoft the volume #2 to the 2nd MSB --- same here
LDR    R1, [R4, #CHN_FREQUENCY]        @ load the channel frequency to R1
LDRB    R0, [R4, #CHN_MODE]            @ load the channel mode to R0
TST    R0, #MODE_FIXED_FREQ            @ check if fixed frequency mode is enabled
MOVNE    R8, #0x800000                @ load the default pitch factor to R8
MULEQ    R8, R12, R1                @ if pitch is not fixed, mulitply the frequency with the default rate pitch factor
LDRH    R0, [R6]                @ load the sample format from header to R0
CMP    R0, #0                    @ check if the sample is uncompressed
BEQ    uncomressed_mixing_reverse_check    @ if sample is uncompressed check if reverse playback is enabled

MOV    R0, #0xFF000000                @ load some kind of flag to R0 ????????
STR    R0, [R4, #0x3C]                @ store it in the last channel VAR slot
LDRB    R0, [R4, #CHN_MODE]            @ load AGAIN the channel mode to R0
TST    R0, #0x10                @ check the reverse playback flag
BNE    compressed_mixing_reverse_init        @ if the flag is set go to reverse playback init + compressed handler

BL    bdpcm_decoder                @ call the FetchSample() function to return the next sample (new samples are decompressed if necessary)
MOV    R0, R1                    @ copy the result to R0
ADD    R3, R3, #1                @ increment the sample counter by one
BL    bdpcm_decoder                @ fetch next sample for interpolation
SUB    R1, R1, R0                @ write the DELTA to R1
MOV    R0, R0, LSL#6                @ ### added

compressed_mixing_load_samples:

LDR    R6, [R5]                @ load 4 samples from mixing buffer #1
LDR    R7, [R5, #buffer_spacing]            @ load 4 samples from mixing buffer #2

compressed_mixing_loop:

MUL    LR, R9, R1                @ multiply the DELTA with the fine position value
ADD    LR, R0, LR, ASR#17            @ ### add the actual sample but divide after to scale down the value back to and 8 bit sample --- changed from 23 to 17
MUL    R12, R10, LR                @ apply vol #1
BIC    R12, R12, #0xFF00            @ ### clear the lower bits - changed from 0xFF0000 to 0xFF00
ADD    R6, R12, R6, ROR#16            @ ### put the sample into the buffer #1 and rotate
MUL    R12, R11, LR                @ apply vol #2
BIC    R12, R12, #0xFF00            @ ### clear the lower bits - changed from 0xFF0000 to 0xFF00
ADD    R7, R12, R7, ROR#16            @ ### put the sample into buffer #2 and rotate the bytes
ADD    R9, R9, R8                @ add the pitch factor to fine position
MOVS    LR, R9, LSR#23                @ cut of the lower bits to seperate fine and relative stream position
BEQ    compressed_mixing_count_current_sample    @ if the overflow amount is 0 don't care about increasing the integer stream position

BIC    R9, R9, #0x3F800000            @ cut of the lower bits if there is overflow (position increasment)
SUBS    R2, R2, LR                @ remove the coatse sample overflow count from the samples remaining
BLE    compressed_mixing_end_handler        @ if the end is reached call the END/LOOP handler

SUBS    LR, LR, #1                @ remove one from the overflow and check if it's done with that (i.e. = 0)
BNE    compressed_mixing_fetch_next        @ if there is more samples to remove fetch a new sample

ADD    R0, R1, R0, ASR#6            @ ### calculate next sample (if the overflow was only 1 we can directly calculate the next base sample for interpolation because we already read it from ROM before and made the DELTA value --> add previous base sample with DELTA = new base sample) --- added shoft
B    compressed_mixing_fetch_delta        @

compressed_mixing_fetch_next:        

ADD    R3, R3, LR                @ add the (probably negative) rewind position to R3 to calculate new position
BL    bdpcm_decoder                @ fetch new sample
MOV    R0, R1                    @ move the base sample to R0

compressed_mixing_fetch_delta:

ADD    R3, R3, #1                @ increment sample position by #1
BL    bdpcm_decoder                @ fetch sample
SUB    R1, R1, R0                @ calc DELTA
MOV    R0, R0, LSL#6                @ ### added

compressed_mixing_count_current_sample:

ADDS    R5, R5, #0x80000000            @ abuse the buffer pointer as counter var at the higher bits
BCC    compressed_mixing_loop            @ go back to mixing loop #1

STR    R7, [R5, #buffer_spacing]            @ write 4 samples to each of the two buffers
STR    R6, [R5], #4                @ after that increment buffer pointer
LDR    R6, [SP]                @ load frame sample countdown
SUBS    R6, R6, #2                @ ### subtract 4 from sample amount --- changed from #4 to #2
STR    R6, [SP]                @ store the variable again
BGT    compressed_mixing_load_samples        @ redo the mixing loop if there is still samples left

SUB    R3, R3, #1                @ remove #1 from sample count (???)
B    special_mixing_return            @ go to return handler

compressed_mixing_end_handler:

LDR    R0, [SP, #0xC+ARG_LOOP_MODE]        @ add 0xC due to the moved stack pointer
CMP    R0, #0                    @ check if loop is disabled
BEQ    compressed_mixing_stop_and_return    @ if loop is disabled go to STOP sample handler

LDR    R3, [R4, #CHN_WAVE_OFFSET]        @ load the wave data offset to R3
LDR    R3, [R3, #WAVE_LOOP_START]        @ load the loop start position to R3
RSB    LR, R2, #0                @ calc the amount of sample that need to get rewinded for looping

compressed_mixing_loop_handler:

ADDS    R2, R2, R0                @ add loopflag to left samples (???)
BGT    compressed_mixing_fetch_next

SUB    LR, LR, R0                @ do some loop stuff (???)
B    compressed_mixing_loop_handler        @ repeat procedure (???)

compressed_mixing_reverse_init:

SUB    R3, R3, #1                @ remove one from the sample position (reverse, so di not add #1)
BL    bdpcm_decoder                @ fetch the base sample
MOV    R0, R1                    @ move the base sample (returned from R1)
SUB    R3, R3, #1                @ remove one from the sample position
BL    bdpcm_decoder                @ fetch the next sample for DELTA calc
SUB    R1, R1, R0                @ calc delta to R1
MOV    R0, R0, LSL#6                @ ### added

compressed_mixing_reverse_load_samples:

LDR    R6, [R5]                @ load samples from buffer #1
LDR    R7, [R5, #buffer_spacing]            @ load samples from buffer #2

compressed_mixing_reverse_loop:

MUL    LR, R9, R1                @ multiply DELTA with fine position
ADD    LR, R0, LR, ASR#17            @ ### add the downshifted delta to the base sample to calc the interpolated sample
MUL    R12, R10, LR                @ apply the volume factor #1 to the sample
BIC    R12, R12, #0xFF00            @ ### clear bad bits
ADD    R6, R12, R6, ROR#16            @ ### rotate the sample bits by 8 and add the current sample
MUL    R12, R11, LR                @ apply volume factor #2 to the sample
BIC    R12, R12, #0xFF00            @ ### clear bad bits
ADD    R7, R12, R7, ROR#16            @ ### do the same for samples #2
ADD    R9, R9, R8                @ add the pitch factor to the fine position
MOVS    LR, R9, LSR#23                @ cut off the fine position bits and move them to LR
BEQ    compressed_mixing_reverse_count_sample    @ check if there is no new samples (we can use the samples again for interpolation, no overflow)

BIC    R9, R9, #0x3F800000            @ seperate the fine position bits
SUBS    R2, R2, LR                @ subtract the sample overflow from the remaing samples
BLE    compressed_mixing_stop_and_return    @ if end of samples is reached

SUBS    LR, LR, #1                @ remove one from the sample overflow and check if the result is Zero
BNE    compressed_mixing_reverse_fetch_next    @ if it is more samples to reload

ADD    R0, R1, R0, ASR#6            @ ### set the base sample to the delta sample (we can skip reloading a sample here) --- added shift
B    compressed_mixing_reverse_seekback

compressed_mixing_reverse_fetch_next:

SUB    R3, R3, LR                @ seek back as many samples as written in the sample overflow
BL    bdpcm_decoder                @ fetch the next sample
MOV    R0, R1                    @ move to base sample Register (R0)

compressed_mixing_reverse_seekback:

SUB    R3, R3, #1                @ decrease the sample position even further
BL    bdpcm_decoder                @ fetch next DELTA sample
SUB    R1, R1, R0                @ calc delta to base sample
MOV    R0, R0, LSL#6                @ ### added shift

compressed_mixing_reverse_count_sample:

ADDS    R5, R5, #0x80000000            @ abuse sample pointer as counter variable on the higher bits
BCC    compressed_mixing_reverse_loop        @ repeat the mixing loop

STR    R7, [R5, #buffer_spacing]            @ write the 4 samples to buffer #2
STR    R6, [R5], #4                @ do the same for buffer #1 but increase the buffer pointer by 4
LDR    R6, [SP]                @ load the frame sample countdown to R6
SUBS    R6, R6, #2                @ ### remove 4 from the frame counter --- changed from #4 to #2
STR    R6, [SP]                @ store the counter
BGT    compressed_mixing_reverse_load_samples    @ if there is samples left to do, continue with the loop

ADD    R3, R3, #2                @ extend sample position by #2 (???)
B    special_mixing_return            @ go to return function

uncomressed_mixing_reverse_check:

LDRB    R0, [R4, #1]                @ load channel mode to R0
TST    R0, #MODE_REVERSE            @ check if the reverse mode is enabled
BEQ    special_mixing_return                @ if reverse mode is not enabled skip this channel because this routine is not made to do regular mixing

LDRSB    R0, [R3, #-1]!                @ reduce the sample counter by #1 and load is as base offset
LDRSB    R1, [R3, #-1]                @ load the DELTA sample
SUB    R1, R1, R0                @ calculate the DELTA value
MOV    R0, R0, LSL#6                @ added shift

uncompressed_mixing_reverse_load_samples:

LDR    R6, [R5]                @ load samples from buffer #1
LDR    R7, [R5, #buffer_spacing]        @ load samples from buffer #2

uncompressed_mixing_reverse_loop:

MUL    LR, R9, R1                @ do the same mixing procedure as usual
ADD    LR, R0, LR, ASR#17            @ ###
MUL    R12, R10, LR
BIC    R12, R12, #0xFF00            @ ###
ADD    R6, R12, R6, ROR#16            @ ###
MUL    R12, R11, LR
BIC    R12, R12, #0xFF00            @ ###
ADD    R7, R12, R7, ROR#16            @ ###
ADD    R9, R9, R8
MOVS    LR, R9, LSR#23
BEQ    uncompressed_mixing_reverse_count

BIC    R9, R9, #0x3F800000            @ seperate fine position bits
SUBS    R2, R2, LR                @ remove the overflow bits from the position count
BLE    compressed_mixing_stop_and_return    @ stop the channel after finishing

LDRSB    R0, [R3, -LR]!                @ load new base sample
LDRSB    R1, [R3, #-1]                @ load the new DELTA sample
SUB    R1, R1, R0                @ calc DELTA
MOV    R0, R0, LSL#6                @ ###

uncompressed_mixing_reverse_count:

ADDS    R5, R5, #0x80000000            @ ### count sample (abuse as count var)
BCC    uncompressed_mixing_reverse_loop    @ if there is still samples in this block to process, repeat loop

STR    R7, [R5, #buffer_spacing]        @ store samples to buffer #2
STR    R6, [R5], #4                @ do the same for buffer #2 + increment the sample pointer
LDR    R6, [SP]                @ load the frame counter to R6
SUBS    R6, R6, #2                @ ### decrease sample count by 4 (4 per sample block) --- changed from #4 to #2
STR    R6, [SP]                @ store it again
BGT    uncompressed_mixing_reverse_load_samples    @

ADD    R3, R3, #1                @ sample position +1 (???)

special_mixing_return:

LDMFD    SP!, {R8, R12, PC}

compressed_mixing_stop_and_return:

MOV    R2, #0                    @ set channel status indicator to stop in R2
STRB    R2, [R4]                @ store it in the channel variables
MOV    R0, R5, LSR#30                @ get the last samples' index
BIC    R5, R5, #0xC0000000            @ remove the bad bits from the channel pointer
RSB    R0, R0, #3                @ negate the index for correct rotation
MOV    R0, R0, LSL#4                @ ### multiply the bit rotation amount by 8 (so we get byte units)
MOV    R6, R6, ROR R0                @ rotate the last sample in position for buffer #1
MOV    R7, R7, ROR R0                @ do the same for buffer #2
STR    R7, [R5, #buffer_spacing]            @ store buffer #2 samples
STR    R6, [R5], #4                @ do the same for buffer #1 and increment buffer pointer
LDMFD    SP!, {R8, R12, PC}            @ pop registers and return to main channel loop

@*********** END COMPRESSOR + RESAMPLER *************@

@****************** BDPCM DEOCODER ******************@

bdpcm_decoder:

STMFD    SP!, {R0, R2, R5-R7, LR}            @ push registers to make them free to use: R0, R2, R5, R6, R7, LR
MOV    R0, R3, LSR#6                @ shift the relative position over to clip of every but the block offset
LDR    R1, [R4, #CHN_BLOCK_COUNT]        @ check if the current sample position is at the beginning of the current block
CMP    R0, R1
BEQ    bdpcm_decoder_return

STR    R0, [R4, #CHN_BLOCK_COUNT]        @ store the block position to Channel Vars
MOV    R1, #0x21                @ load decoding byte count to R1 (1 Block = 0x21 Bytes)
MUL    R2, R1, R0                @ multiply the block count with the block length to calc actual byte position of current block
LDR    R1, [R4, #CHN_WAVE_OFFSET]        @ load the wave data offset to R1
ADD    R2, R2, R1                @ add the wave data offset and 0x10 to get the actual position in ROM
ADD    R2, R2, #0x10                @ 
LDR    R5, decoder_buffer            @ load the decoder buffer pointer to R5
LDR    R6, delta_lookup_table            @ load the lookup table pointer to R6
MOV    R7, #0x40                @ load the block sample count (0x40) to R7
LDRB    LR, [R2], #1                @ load the first byte & sample from the wave data to LR (each block starts with a signed 8 bit pcm sample) LDRSB not necessary due to the 24 high bits being cut off anyway
STRB    LR, [R5], #1                @ write the sample to the decoder buffer
LDRB    R1, [R2], #1                @ load the next 2 samples to R1 (to get decoded) --- LSBits is decoded first and MSBits last
B    bdpcm_decoder_lsb

bdpcm_decoder_msb:

LDRB    R1, [R2], #1                @ load the next 2 samples to get decoded
MOV    R0, R1, LSR#4                @ seperate the current samples' bits
LDRSB    R0, [R6, R0]                @ load the differential value from the lookup table
ADD    LR, LR, R0                @ add the decoded value to the previous sample value to calc the current samples' level
STRB    LR, [R5], #1                @ write the output sample to the decoder buffer and increment buffer pointer

bdpcm_decoder_lsb:

AND    R0, R1, #0xF                @ seperate the 4 LSBits
LDRSB    R0, [R6, R0]                @ but the 4 bit value into the lookup table and save the result to R0
ADD    LR, LR, R0                @ add the value from the lookup table to the previous value to calc the new one
STRB    LR, [R5], #1                @ store the decoded sample to the decoding buffer
SUBS    R7, R7, #2                @ decrease the block sample counter by 2 (2 samples each byte) and check if it is still above 0
BGT    bdpcm_decoder_msb            @ if there is still samples to decode jump to the MSBits

bdpcm_decoder_return:

LDR    R5, decoder_buffer            @ reload the decompressor buffer offset to R5
AND    R0, R3, #0x3F                @ cut off the main position bits to read data from short buffer
LDRSB    R1, [R5, R0]                @ read the decoded sample from buffer
LDMFD    SP!, {R0, R2, R5-R7, PC}        @ pop registers and return to the compressed sample mixer

@**************** END BDPCM DECODER *****************@

decoder_buffer:
    .word    decoder_buffer_target
delta_lookup_table:
    .word    delta_table

    .end


If you actually managed to understand "something":
I changed all pointers in the main loops from the output buffer to the HQ work area and changed the calculated samples from 8 bits to 14 bits. You might wonder here why I used a 14 bit resolution instead of a something more even like 16 bits.
The reason for this is that I thought it might be useful to have some kind of room for overflowed samples. Because the 14 bit samples are stored in 16 bit values there is 2 bits for overflow.
I thought this might be useful to implement like that because if I might actually add an overflow protection and clip the samples (it's very unlikely the output level will get higher than 4x max range). This would be very easy to do when doing the downsampling when cmocing the samples from the HQ to the main output buffer. Clipping the samples will remove "clicks" when the output level will get to high.
However, I didn't do the overflow protection yet because I still have (or tell me if you got an idea) to come up with some fast and efficient ASM code that checks each time if the sample overflowed (it needs to be as fast as possible). So you still might get some clicks in your output if you're going a little crazy with volume.

Assembly and insertion:
Before insertion you of course have to assemble the file first. Before assembly, though, you need to do some editing depending on which version and language you are using.
So I made a
few changes here recently: You'll just have to set the line ".equ USED_GAME, GAME_BPED" depended on your game.
The presets for BPEE and BPED should be compatible now with the DNS, BPRE is still broken I think. KWJ6 should bother you, it was just some testing I did with Kawa's Jukebox and my Soundroutine.

If you managed to get it over to this section of text you are ready to assemble the code. It should result a binary file with the length of 0x7A0 bytes.

Put this somewhere in your ROM. It doesn't really matter where it is since this routine is loaded to IRAM before execution automatically anyway.

Write down the offset and copy the pointer (don't forget to add 0x08000000) to the version and language specified locations:
  • BPED: 0x2F5E30
  • BPEE: 0x2E00F0
  • BPRE: 0x1DD0B4
Apperantly the pointers usually have +1 added (Thumb entrypoint) although don't doing that doesn't seem to make a difference because the code isn't executed from ROM directly anyway.


Next step: Play the game and have fun with low noise audio ^.^
REMEBER: If you are using emulator quick saves, you have to save the game in the game itself and reload the ingame save because the new code is only loaded once during ROM startup and will need a restart of the ROM. (quicksaves will contain the old mixer in the IRAM).

Comparison (old vs. new):
Here is a video comparing the default mixer (1st) and my mixer (2nd):



Conclusion:
Yeah, so this was actually my really first ASM project and I hope you enjoy using it. Please don't forget to give Credits when making your hack public.
Feedback appreciated!

__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #2    
Old April 24th, 2014 (10:46 AM).
Chaos_Darkrai's Avatar
Chaos_Darkrai Chaos_Darkrai is offline
 
Join Date: Apr 2012
Gender: Male
Posts: 284
Do I take the whole routine, straight from the first line, then change the values? Or do I start at a specific line?
__________________
░░░░░███████ ]▄▄▄▄▄▄▄▄
▂▄▅█████████▅▄▃▂
Il███████████████████].
◥⊙▲⊙▲⊙▲⊙▲⊙▲⊙▲⊙◤..

If you're looking for a good time, or just want to chat, come over to Weloxux and I's channel at:
http://mibbit.com/?server=irc.mibbit.net&channel=%23Dragons_Den

Reply With Quote
  #3    
Old April 24th, 2014 (10:56 AM).
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
No, you have to start from the top line (the complete routine). You just have to modify the lines I mentioned above.
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #4    
Old April 24th, 2014 (11:09 AM).
Chaos_Darkrai's Avatar
Chaos_Darkrai Chaos_Darkrai is offline
 
Join Date: Apr 2012
Gender: Male
Posts: 284
So if I am using BPRE, I wouldn't change the routine at all? Or would I put the offset where the words are?
__________________
░░░░░███████ ]▄▄▄▄▄▄▄▄
▂▄▅█████████▅▄▃▂
Il███████████████████].
◥⊙▲⊙▲⊙▲⊙▲⊙▲⊙▲⊙◤..

If you're looking for a good time, or just want to chat, come over to Weloxux and I's channel at:
http://mibbit.com/?server=irc.mibbit.net&channel=%23Dragons_Den

Reply With Quote
  #5    
Old April 24th, 2014 (11:52 AM). Edited April 24th, 2014 by ipatix.
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
If you use you wouldn't need to change anything, right. And, no, you wouldn't need to change the words because the words are defined by the .equ-s and should change all according to the adjustments you do in the first lines.
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #6    
Old April 24th, 2014 (12:27 PM).
Chaos_Darkrai's Avatar
Chaos_Darkrai Chaos_Darkrai is offline
 
Join Date: Apr 2012
Gender: Male
Posts: 284
Quote originally posted by ipatix:
If you use you wouldn't need to change anything, right. And, no, you wouldn't need to change the worse because the worse are defined by the .equ-s and should change all according to the adjustments you do in the first lines.
OK. Thanks a bunch ipatix! Wonderful job on this!
__________________
░░░░░███████ ]▄▄▄▄▄▄▄▄
▂▄▅█████████▅▄▃▂
Il███████████████████].
◥⊙▲⊙▲⊙▲⊙▲⊙▲⊙▲⊙◤..

If you're looking for a good time, or just want to chat, come over to Weloxux and I's channel at:
http://mibbit.com/?server=irc.mibbit.net&channel=%23Dragons_Den

Reply With Quote
  #7    
Old April 26th, 2014 (10:24 PM).
Wobbu's Avatar
Wobbu Wobbu is offline
ffet
Moderator
 
Join Date: Mar 2012
Location: Humilau City
Gender: Male
Nature: Relaxed
Posts: 2,349
I just tested this on BPEE and all my custom music sounds so much better now! Newer generation music that I ported to my hack doesn't produce nearly as much unnecessary noises as they used to, especially ones that have a heavy use of high-pitched instruments. Thank you a lot for researching this! The difference is very noticeable.
__________________
Sprite courtesy of Fairy
Reply With Quote
  #8    
Old April 27th, 2014 (02:19 AM).
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
Thanks for the feedback
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #9    
Old April 27th, 2014 (02:39 AM).
Sniper's Avatar
Sniper Sniper is offline
ふゆかい
 
Join Date: Nov 2013
Location: Philippines
Gender: Male
Nature: Quiet
Posts: 1,401
So I tried same as Wobbu did. It's so much better right now! Another research that helped a lot!
__________________
Reply With Quote
  #10    
Old April 27th, 2014 (03:30 PM).
designmadman designmadman is offline
 
Join Date: Dec 2012
Location: canada
Gender: Male
Nature: Adamant
Posts: 12
Mmmph so i changed the start of your routine so i could use it for fire red and inserted it at 0x800660 then i entered this pointer: (60 06 80 08) at 0x1DD0B4 and the game freezes everytime it tries to play sound i also tried (61 06 80 08) the plus 1 thumb pointer and still no good so i'm sure i screwed up somewhere...
Reply With Quote
  #11    
Old April 28th, 2014 (03:16 AM).
PokeBunny's Avatar
PokeBunny PokeBunny is offline
Pokemon Game Maker
 
Join Date: Aug 2012
Location: South Africa
Age: 15
Gender: Male
Nature: Serious
Posts: 34
Not bad. Turns out you are smart. But the AGB music player sounds bad. But they use it because you only have to use swi functions. Gamefreak is lazy!
__________________
special POKeBUNNY

The Pokemon Game Developer
If you are wondering why I'm taking long to make Pokemon Hot Red and Cold Blue... It's because I barely get computer time. Be patient (I'm not!.

My SoundCloud!!!!!!!!!
Reply With Quote
  #12    
Old April 28th, 2014 (06:49 AM).
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
@PokeBunny:
Actually Gamefreak is not "that" lazy. To clarify things:
The AGB music player is part of the Nintendo SDK. And they did a pretty decent job on doing a very efficient music player although there is some flaws here and there (like the noisy sound). This music player was implemented into the BIOS when the AGB came out to have a fast music player that doesn't need IWRAM for Code which is stored in the BIOS (remember, BIOS memory is as fast as IWRAM). This however turned out to be a problem: There was some bugs with the old versions of the music player and because Nintendo let the Developer to choose BIOS or IWRAM (updateable) code almost all developers used the IWRAM solution.
So "you only have to use swi functions" is not 100% correctly. Anyway, there is not much Nintendo could have done a lot better. With my code and (enough free CPU load which Pokegames don't have) you could reach very good quality. So it's not "all bad".

Some other developers like Camelot (--> developed Golden Sun) however completley rewrote the code of some parts of the music which provide much higher quality and lower CPU load. This is how they could make the game provide one of the best GBA soundtracks in my opinion:

https://www.youtube.com/watch?v=NrcG9lgGGNg

I might actually try to port their engine to Pokemon in the future but I don't promise that. The code they use is even 10 times as complicated as it already was with Nintendos one. The other thing that'll be tough to do is to add the support for compressed samples and reverse playback to this engine (which no other game than Pokemon is able to; default sound driver modded by Gamefreak).

@designmadman:
I don't know why it won't work. I tried it once on my own on Firered US and it worked.
Usually "bad settings" that are language depended shouldn't crash the game (although the sound myight turn really buggy).

Check again if you did the assembly process correctly (correct settings) and if you did all the pointers correctly.
Other than that I don't know what could have gone wrong...
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #13    
Old April 28th, 2014 (09:03 PM).
designmadman designmadman is offline
 
Join Date: Dec 2012
Location: canada
Gender: Male
Nature: Adamant
Posts: 12
Yeah i tried it on a clean new fire red rom and it works fine i guess something on my current modified rom is preventing the routine from working properly. Nice job on this sounds really good when i import songs to the clean rom.
Reply With Quote
  #14    
Old April 29th, 2014 (04:31 AM).
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
It should work on any ROM that doesn't use the free IWRAM areas I use in the code.
For Emerald 0x03005200 (4*0xE0 Bytes)
For Fire Red 0x03004200 (4*0xE0 Bytes)
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #15    
Old April 29th, 2014 (03:39 PM).
Merak's Avatar
Merak Merak is offline
Because reasons.
 
Join Date: Jul 2013
Location: Deep in my thoughts.
Age: 19
Nature: Relaxed
Posts: 250
Huh. I've got a pretty well-trained ear. I didn't really notice much of a difference in your example, just that the second set of audio played was a bit clearer I guess but not much.
lol Is the change easier to hear in the game itself, or am I the only one who doesn't notice a big difference? Just wondering.


But yeah anyway even if I can't tell the difference or if it isn't that big or whatever, still great job on this ASM! Keep up the good work. ^^
Reply With Quote
  #16    
Old April 30th, 2014 (01:52 AM). Edited May 9th, 2014 by ipatix.
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
Listen carefully to the parts that are more quiet. Specially at these parts it should be pretty noticeable.

EDIT:
@ anyone who is having problem with issues:
This routine is not compatible with ASM hacks that access the IWRAM at the areas specified in the code. I recently found out that I had to move the area for Emerald to 0x03005100 because prime's DNS uses some areas around there aswell and my routine would cause glitchy pallette changes all the time.

EDIT 2:
I now changed the assembly code to a preset system. The only thing you'll do before assembly is set the right "USED_GAME" and run the assembly.
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #17    
Old May 17th, 2014 (01:05 AM). Edited May 17th, 2014 by angelXwind.
angelXwind's Avatar
angelXwind angelXwind is offline
SHSL Programmer Pineapple Girl
 
Join Date: May 2010
Gender: Female
Posts: 2
There's a typo on line 48 of your code. See here: https://github.com/angelXwind/pokemon-gen3-hq-sound-mixer/commit/be377b7540ed89a7588941348ed12fd129440669

Also, I wrote a Makefile around your code that executes the following after asssembly (BPEE target):

Code:
dd if=main.bin of="out.gba" conv=notrunc seek=3014896 bs=1
(3014896 is 0x2E00F0 in dec, here's how that Makefile works: https://github.com/angelXwind/pokemon-gen3-hq-sound-mixer/blob/master/Makefile)

However, the resulting ROM only causes the emulator to loop at the BIOS forever.

The assembled binary is 0x7A0 bytes long as it should be, so I'm (most likely) assembling it correctly.

Am I injecting the binary into the wrong area? Or...
Reply With Quote
  #18    
Old May 17th, 2014 (01:06 AM).
PokeBunny's Avatar
PokeBunny PokeBunny is offline
Pokemon Game Maker
 
Join Date: Aug 2012
Location: South Africa
Age: 15
Gender: Male
Nature: Serious
Posts: 34
SO there is a music player in the BIOS. I didn't know that. You know the reason: in GBATEK, some of the swi functions are undocumented as SoundWhatever #.
__________________
special POKeBUNNY

The Pokemon Game Developer
If you are wondering why I'm taking long to make Pokemon Hot Red and Cold Blue... It's because I barely get computer time. Be patient (I'm not!.

My SoundCloud!!!!!!!!!
Reply With Quote
  #19    
Old May 17th, 2014 (02:09 AM).
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
Quote originally posted by angelXwind:
There's a typo on line 48 of your code. See here: https://github.com/angelXwind/pokemon-gen3-hq-sound-mixer/commit/019a667a4612c4bbfa0438c59ed9a3fbdbc983f9

Also, I wrote a Makefile around your code that executes the following after asssembly (BPEE target):

Code:
dd if=main.bin of="out.gba" conv=notrunc seek=3014896 bs=1
(3014896 is 0x2E00F0 in dec, here's how that Makefile works: https://github.com/angelXwind/pokemon-gen3-hq-sound-mixer/blob/master/Makefile)

However, the resulting ROM only causes the emulator to loop at the BIOS forever.

The assembled binary is 0x7A0 bytes long as it should be, so I'm (most likely) assembling it correctly.

Am I injecting the binary into the wrong area? Or...
You can't just overwrite the old code. My new one is slightly bigger so you'll overwrite other stuff. Perhaps this could be the problem.

@all: I just want to announce that version 2.0 of the mixer is already very far in development state. The biggest changes are that the code is completley rewritten, executes almost twice as fast and supports a basic Synth engine without the use of samples in ROM. It'll probably still be incompatible with interdepth's RTC (and/or DNS) for now due to overlapping RAM areas but I'll tell you later more about that.
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #20    
Old May 17th, 2014 (07:59 AM). Edited May 17th, 2014 by angelXwind.
angelXwind's Avatar
angelXwind angelXwind is offline
SHSL Programmer Pineapple Girl
 
Join Date: May 2010
Gender: Female
Posts: 2
Quote originally posted by ipatix:
You can't just overwrite the old code. My new one is slightly bigger so you'll overwrite other stuff. Perhaps this could be the problem.
Ah, thanks for the information. Injecting the binary into some free space in the ROM then modifying the pointer seems to work.

Also, I created a GitHub repository with a Makefile that completely automates the process of assembling and injecting the binary into a ROM. https://github.com/angelXwind/pokemon-gen3-hq-sound-mixer
Reply With Quote
  #21    
Old May 17th, 2014 (09:05 AM).
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
Emerald itself without modifications only uses a max of 5 sounds at the same time which doesn't produce that much noise (the more channels, the more noisy it gets) and you only hear it if you listen very carefully.
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #22    
Old June 7th, 2014 (08:17 PM).
PmHacks PmHacks is offline
 
Join Date: Feb 2004
Gender:
Posts: 27
I don't suppose you have a disassembly of the original sound engine or the bios one do you?
Reply With Quote
  #23    
Old June 8th, 2014 (03:01 PM). Edited June 10th, 2014 by ipatix.
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
I can provide one tomorrow. I won't write another documentation though.

Edit: Sry, didn't get enough time today, I'll so it as soon as possible.

Edit 2: There we go:

Code:
ROM:082F4E20 ; =============== S U B R O U T I N E =======================================
ROM:082F4E20
ROM:082F4E20
ROM:082F4E20 entry
ROM:082F4E20
ROM:082F4E20 ARG_FRAME_LENGTH=  0
ROM:082F4E20 ARG_CHN_LEFT    =  4
ROM:082F4E20 ARG_BUFFER_POS  =  8
ROM:082F4E20 ARG_ABS_LOOP_OFFSET=  0xC
ROM:082F4E20 ARG_LOOP_MODE   =  0x10
ROM:082F4E20 ARG_SCAN_LIMIT  =  0x14
ROM:082F4E20 ARG_VAR_AREA    =  0x18
ROM:082F4E20
ROM:082F4E20                 LDRB    R3, [R0,#5]
ROM:082F4E22                 CMP     R3, #0
ROM:082F4E24                 BEQ     clear_buffer
ROM:082F4E26                 ADR     R1, do_reverb
ROM:082F4E28                 BX      R1 ; do_reverb
ROM:082F4E28 ; ---------------------------------------------------------------------------
ROM:082F4E2A                 DCB    0
ROM:082F4E2B                 DCB    0
ROM:082F4E2C ; ---------------------------------------------------------------------------
ROM:082F4E2C                 CODE32
ROM:082F4E2C
ROM:082F4E2C do_reverb                               ; CODE XREF: entry+8j
ROM:082F4E2C                                         ; DATA XREF: entry+6o
ROM:082F4E2C                 CMP     R4, #2
ROM:082F4E30                 ADDEQ   R7, R0, #0x350
ROM:082F4E34                 ADDNE   R7, R5, R8
ROM:082F4E38                 MOV     R4, R8
ROM:082F4E3C
ROM:082F4E3C reverb_loop                             ; CODE XREF: entry+54j
ROM:082F4E3C                 LDRSB   R0, [R5,R6]
ROM:082F4E40                 LDRSB   R1, [R5]
ROM:082F4E44                 ADD     R0, R0, R1
ROM:082F4E48                 LDRSB   R1, [R7,R6]
ROM:082F4E4C                 ADD     R0, R0, R1
ROM:082F4E50                 LDRSB   R1, [R7],#1
ROM:082F4E54                 ADD     R0, R0, R1
ROM:082F4E58                 MUL     R1, R0, R3
ROM:082F4E5C                 MOV     R0, R1,ASR#9
ROM:082F4E60                 TST     R0, #0x80
ROM:082F4E64                 ADDNE   R0, R0, #1
ROM:082F4E68                 STRB    R0, [R5,R6]
ROM:082F4E6C                 STRB    R0, [R5],#1
ROM:082F4E70                 SUBS    R4, R4, #1
ROM:082F4E74                 BGT     reverb_loop
ROM:082F4E78                 ADR     R0, (loop_setup+1)
ROM:082F4E7C                 BX      R0 ; loop_setup
ROM:082F4E80 ; ---------------------------------------------------------------------------
ROM:082F4E80                 CODE16
ROM:082F4E80
ROM:082F4E80 clear_buffer                            ; CODE XREF: entry+4j
ROM:082F4E80                 MOVS    R0, #0
ROM:082F4E82                 MOV     R1, R8
ROM:082F4E84                 ADDS    R6, R6, R5
ROM:082F4E86                 LSRS    R1, R1, #3
ROM:082F4E88                 BCC     clear_buffer_align_8
ROM:082F4E8A                 STMIA   R5!, {R0}
ROM:082F4E8C                 STMIA   R6!, {R0}
ROM:082F4E8E
ROM:082F4E8E clear_buffer_align_8                    ; CODE XREF: entry+68j
ROM:082F4E8E                 LSRS    R1, R1, #1
ROM:082F4E90                 BCC     clear_buffer_align_16
ROM:082F4E92                 STMIA   R5!, {R0}
ROM:082F4E94                 STMIA   R6!, {R0}
ROM:082F4E96                 STMIA   R5!, {R0}
ROM:082F4E98                 STMIA   R6!, {R0}
ROM:082F4E9A
ROM:082F4E9A clear_buffer_align_16                   ; CODE XREF: entry+70j
ROM:082F4E9A                                         ; entry+8Cj
ROM:082F4E9A                 STMIA   R5!, {R0}
ROM:082F4E9C                 STMIA   R6!, {R0}
ROM:082F4E9E                 STMIA   R5!, {R0}
ROM:082F4EA0                 STMIA   R6!, {R0}
ROM:082F4EA2                 STMIA   R5!, {R0}
ROM:082F4EA4                 STMIA   R6!, {R0}
ROM:082F4EA6                 STMIA   R5!, {R0}
ROM:082F4EA8                 STMIA   R6!, {R0}
ROM:082F4EAA                 SUBS    R1, #1
ROM:082F4EAC                 BGT     clear_buffer_align_16
ROM:082F4EAE
ROM:082F4EAE loop_setup                              ; CODE XREF: entry+5Cj
ROM:082F4EAE                                         ; DATA XREF: entry+58o
ROM:082F4EAE                 LDR     R4, [SP,#ARG_VAR_AREA]
ROM:082F4EB0                 LDR     R0, [R4,#0x18]
ROM:082F4EB2                 MOV     R12, R0
ROM:082F4EB4                 LDRB    R0, [R4,#6]
ROM:082F4EB6                 ADDS    R4, #0x50
ROM:082F4EB8
ROM:082F4EB8 channel_main_loop                       ; CODE XREF: entry+3A0j
ROM:082F4EB8                 STR     R0, [SP,#ARG_CHN_LEFT]
ROM:082F4EBA                 LDR     R3, [R4,#0x24]
ROM:082F4EBC                 LDR     R0, [SP,#ARG_SCAN_LIMIT]
ROM:082F4EBE                 CMP     R0, #0
ROM:082F4EC0                 BEQ     channel_begin
ROM:082F4EC2                 LDR     R1, =0x4000006
ROM:082F4EC4                 LDRB    R1, [R1]
ROM:082F4EC6                 CMP     R1, #0xA0
ROM:082F4EC8                 BCS     scanline_vblank
ROM:082F4ECA                 ADDS    R1, #0xE4
ROM:082F4ECC
ROM:082F4ECC scanline_vblank                         ; CODE XREF: entry+A8j
ROM:082F4ECC                 CMP     R1, R0
ROM:082F4ECE                 BCC     channel_begin
ROM:082F4ED0                 B       mixer_end
ROM:082F4ED0 ; ---------------------------------------------------------------------------
ROM:082F4ED2                 DCB    0
ROM:082F4ED3                 DCB    0
ROM:082F4ED4 vcount_reg                              ; DATA XREF: entry+A2r
ROM:082F4ED4                 DCD 0x4000006
ROM:082F4ED8 ; ---------------------------------------------------------------------------
ROM:082F4ED8
ROM:082F4ED8 channel_begin                           ; CODE XREF: entry+A0j
ROM:082F4ED8                                         ; entry+AEj
ROM:082F4ED8                 LDRB    R6, [R4]
ROM:082F4EDA                 MOVS    R0, #0xC7
ROM:082F4EDC                 TST     R0, R6
ROM:082F4EDE                 BNE     channel_status_check
ROM:082F4EE0                 B       channel_check_processed_channels
ROM:082F4EE2 ; ---------------------------------------------------------------------------
ROM:082F4EE2
ROM:082F4EE2 channel_status_check                    ; CODE XREF: entry+BEj
ROM:082F4EE2                 MOVS    R0, #0x80
ROM:082F4EE4                 TST     R0, R6
ROM:082F4EE6                 BEQ     channel_envelope_handler
ROM:082F4EE8                 MOVS    R0, #0x40
ROM:082F4EEA                 TST     R0, R6
ROM:082F4EEC                 BNE     channel_stop_func
ROM:082F4EEE                 MOVS    R6, #3
ROM:082F4EF0                 STRB    R6, [R4]
ROM:082F4EF2                 MOVS    R0, R3
ROM:082F4EF4                 ADDS    R0, #0x10
ROM:082F4EF6                 LDR     R1, [R4,#0x18]
ROM:082F4EF8                 ADDS    R0, R0, R1
ROM:082F4EFA                 STR     R0, [R4,#0x28]
ROM:082F4EFC                 LDR     R0, [R3,#0xC]
ROM:082F4EFE                 SUBS    R0, R0, R1
ROM:082F4F00                 STR     R0, [R4,#0x18]
ROM:082F4F02                 MOVS    R5, #0
ROM:082F4F04                 STRB    R5, [R4,#9]
ROM:082F4F06                 STR     R5, [R4,#0x1C]
ROM:082F4F08                 LDRB    R2, [R3,#3]
ROM:082F4F0A                 MOVS    R0, #0xC0
ROM:082F4F0C                 TST     R0, R2
ROM:082F4F0E                 BEQ     channel_adsr_attack_handler
ROM:082F4F10                 MOVS    R0, #0x10
ROM:082F4F12                 ORRS    R6, R0
ROM:082F4F14                 STRB    R6, [R4]
ROM:082F4F16                 B       channel_adsr_attack_handler
ROM:082F4F18 ; ---------------------------------------------------------------------------
ROM:082F4F18
ROM:082F4F18 channel_envelope_handler                ; CODE XREF: entry+C6j
ROM:082F4F18                 LDRB    R5, [R4,#9]
ROM:082F4F1A                 MOVS    R0, #4
ROM:082F4F1C                 TST     R0, R6
ROM:082F4F1E                 BEQ     channel_adsr_no_echo
ROM:082F4F20                 LDRB    R0, [R4,#0xD]
ROM:082F4F22                 SUBS    R0, #1
ROM:082F4F24                 STRB    R0, [R4,#0xD]
ROM:082F4F26                 BHI     channel_vol_calc
ROM:082F4F28
ROM:082F4F28 channel_stop_func                       ; CODE XREF: entry+CCj
ROM:082F4F28                                         ; entry+124j
ROM:082F4F28                 MOVS    R0, #0
ROM:082F4F2A                 STRB    R0, [R4]
ROM:082F4F2C                 B       channel_check_processed_channels
ROM:082F4F2E ; ---------------------------------------------------------------------------
ROM:082F4F2E
ROM:082F4F2E channel_adsr_no_echo                    ; CODE XREF: entry+FEj
ROM:082F4F2E                 MOVS    R0, #0x40
ROM:082F4F30                 TST     R0, R6
ROM:082F4F32                 BEQ     channel_adsr_no_release
ROM:082F4F34                 LDRB    R0, [R4,#7]
ROM:082F4F36                 MULS    R5, R0
ROM:082F4F38                 LSRS    R5, R5, #8
ROM:082F4F3A                 LDRB    R0, [R4,#0xC]
ROM:082F4F3C                 CMP     R5, R0
ROM:082F4F3E                 BHI     channel_vol_calc
ROM:082F4F40
ROM:082F4F40 channel_adsr_check_echo_disabled        ; CODE XREF: entry+144j
ROM:082F4F40                 LDRB    R5, [R4,#0xC]
ROM:082F4F42                 CMP     R5, #0
ROM:082F4F44                 BEQ     channel_stop_func
ROM:082F4F46                 MOVS    R0, #4
ROM:082F4F48                 ORRS    R6, R0
ROM:082F4F4A                 STRB    R6, [R4]
ROM:082F4F4C                 B       channel_vol_calc
ROM:082F4F4E ; ---------------------------------------------------------------------------
ROM:082F4F4E
ROM:082F4F4E channel_adsr_no_release                 ; CODE XREF: entry+112j
ROM:082F4F4E                 MOVS    R2, #3
ROM:082F4F50                 ANDS    R2, R6
ROM:082F4F52                 CMP     R2, #2
ROM:082F4F54                 BNE     channel_adsr_no_decay
ROM:082F4F56                 LDRB    R0, [R4,#5]
ROM:082F4F58                 MULS    R5, R0
ROM:082F4F5A                 LSRS    R5, R5, #8
ROM:082F4F5C                 LDRB    R0, [R4,#6]
ROM:082F4F5E                 CMP     R5, R0
ROM:082F4F60                 BHI     channel_vol_calc
ROM:082F4F62                 MOVS    R5, R0
ROM:082F4F64                 BEQ     channel_adsr_check_echo_disabled
ROM:082F4F66                 SUBS    R6, #1
ROM:082F4F68                 STRB    R6, [R4]
ROM:082F4F6A                 B       channel_vol_calc
ROM:082F4F6C ; ---------------------------------------------------------------------------
ROM:082F4F6C
ROM:082F4F6C channel_adsr_no_decay                   ; CODE XREF: entry+134j
ROM:082F4F6C                 CMP     R2, #3
ROM:082F4F6E                 BNE     channel_vol_calc
ROM:082F4F70
ROM:082F4F70 channel_adsr_attack_handler             ; CODE XREF: entry+EEj
ROM:082F4F70                                         ; entry+F6j
ROM:082F4F70                 LDRB    R0, [R4,#4]
ROM:082F4F72                 ADDS    R5, R5, R0
ROM:082F4F74                 CMP     R5, #0xFF
ROM:082F4F76                 BCC     channel_vol_calc
ROM:082F4F78                 MOVS    R5, #0xFF
ROM:082F4F7A                 SUBS    R6, #1
ROM:082F4F7C                 STRB    R6, [R4]
ROM:082F4F7E
ROM:082F4F7E channel_vol_calc                        ; CODE XREF: entry+106j
ROM:082F4F7E                                         ; entry+11Ej ...
ROM:082F4F7E                 STRB    R5, [R4,#9]
ROM:082F4F80                 LDR     R0, [SP,#ARG_VAR_AREA]
ROM:082F4F82                 LDRB    R0, [R0,#7]
ROM:082F4F84                 ADDS    R0, #1
ROM:082F4F86                 MULS    R0, R5
ROM:082F4F88                 LSRS    R5, R0, #4
ROM:082F4F8A                 LDRB    R0, [R4,#2]
ROM:082F4F8C                 MULS    R0, R5
ROM:082F4F8E                 LSRS    R0, R0, #8
ROM:082F4F90                 STRB    R0, [R4,#0xA]
ROM:082F4F92                 LDRB    R0, [R4,#3]
ROM:082F4F94                 MULS    R0, R5
ROM:082F4F96                 LSRS    R0, R0, #8
ROM:082F4F98                 STRB    R0, [R4,#0xB]
ROM:082F4F9A                 MOVS    R0, #0x10
ROM:082F4F9C                 ANDS    R0, R6
ROM:082F4F9E                 STR     R0, [SP,#ARG_LOOP_MODE]
ROM:082F4FA0                 BEQ     channel_setup_mixing
ROM:082F4FA2                 MOVS    R0, R3
ROM:082F4FA4                 ADDS    R0, #0x10
ROM:082F4FA6                 LDR     R1, [R3,#8]
ROM:082F4FA8                 ADDS    R0, R0, R1
ROM:082F4FAA                 STR     R0, [SP,#ARG_ABS_LOOP_OFFSET]
ROM:082F4FAC                 LDR     R0, [R3,#0xC]
ROM:082F4FAE                 SUBS    R0, R0, R1
ROM:082F4FB0                 STR     R0, [SP,#ARG_LOOP_MODE]
ROM:082F4FB2
ROM:082F4FB2 channel_setup_mixing                    ; CODE XREF: entry+180j
ROM:082F4FB2                 LDR     R5, [SP,#ARG_BUFFER_POS]
ROM:082F4FB4                 LDR     R2, [R4,#0x18]
ROM:082F4FB6                 LDR     R3, [R4,#0x28]
ROM:082F4FB8                 ADR     R0, channel_mixing
ROM:082F4FBA                 BX      R0 ; channel_mixing
ROM:082F4FBC                 CODE32
ROM:082F4FBC
ROM:082F4FBC channel_mixing                          ; DATA XREF: entry+198o
ROM:082F4FBC                 STR     R8, [SP,#ARG_FRAME_LENGTH]
ROM:082F4FC0                 LDR     R9, [R4,#0x1C]
ROM:082F4FC4                 LDRB    R10, [R4,#0xA]
ROM:082F4FC8                 LDRB    R11, [R4,#0xB]
ROM:082F4FCC                 LDRB    R0, [R4,#1]
ROM:082F4FD0                 TST     R0, #0x30
ROM:082F4FD4                 BEQ     channel_uncompressed_mixing
ROM:082F4FD8                 BL      channel_compressed_mixing
ROM:082F4FDC                 B       channel_var_freq_mixing_store_fine_pos
ROM:082F4FE0 ; ---------------------------------------------------------------------------
ROM:082F4FE0
ROM:082F4FE0 channel_uncompressed_mixing             ; CODE XREF: entry+1B4j
ROM:082F4FE0                 MOV     R10, R10,LSL#16
ROM:082F4FE4                 MOV     R11, R11,LSL#16
ROM:082F4FE8                 LDRB    R0, [R4,#1]
ROM:082F4FEC                 TST     R0, #8
ROM:082F4FF0                 BEQ     channel_var_freq_mixing
ROM:082F4FF4
ROM:082F4FF4 channel_fixed_freq_mixing_loop          ; CODE XREF: entry+284j
ROM:082F4FF4                 CMP     R2, #4
ROM:082F4FF8                 BLE     channel_fixed_freq_mixing_fetch_last
ROM:082F4FFC                 SUBS    R2, R2, R8
ROM:082F5000                 MOVGT   R9, #0
ROM:082F5004                 BGT     channel_fixed_freq_mixing_fetch_samples
ROM:082F5008                 MOV     R9, R8
ROM:082F500C                 ADD     R2, R2, R8
ROM:082F5010                 SUB     R8, R2, #4
ROM:082F5014                 SUB     R9, R9, R8
ROM:082F5018                 ANDS    R2, R2, #3
ROM:082F501C                 MOVEQ   R2, #4
ROM:082F5020
ROM:082F5020 channel_fixed_freq_mixing_fetch_samples ; CODE XREF: entry+1E4j
ROM:082F5020                                         ; entry+238j
ROM:082F5020                 LDR     R6, [R5]
ROM:082F5024                 LDR     R7, [R5,#0x630]
ROM:082F5028
ROM:082F5028 channel_fixed_load_new_samples          ; CODE XREF: entry+228j
ROM:082F5028                 LDRSB   R0, [R3],#1
ROM:082F502C                 MUL     R1, R10, R0
ROM:082F5030                 BIC     R1, R1, #0xFF0000
ROM:082F5034                 ADD     R6, R1, R6,ROR#8
ROM:082F5038                 MUL     R1, R11, R0
ROM:082F503C                 BIC     R1, R1, #0xFF0000
ROM:082F5040                 ADD     R7, R1, R7,ROR#8
ROM:082F5044                 ADDS    R5, R5, #0x40000000
ROM:082F5048                 BCC     channel_fixed_load_new_samples
ROM:082F504C                 STR     R7, [R5,#0x630]
ROM:082F5050                 STR     R6, [R5],#4
ROM:082F5054                 SUBS    R8, R8, #4
ROM:082F5058                 BGT     channel_fixed_freq_mixing_fetch_samples
ROM:082F505C                 ADDS    R8, R8, R9
ROM:082F5060                 BEQ     channel_mixing_store_pos
ROM:082F5064
ROM:082F5064 channel_fixed_freq_mixing_fetch_last    ; CODE XREF: entry+1D8j
ROM:082F5064                 LDR     R6, [R5]
ROM:082F5068                 LDR     R7, [R5,#0x630]
ROM:082F506C
ROM:082F506C channel_fixed_load_last_samples         ; CODE XREF: entry+274j
ROM:082F506C                 LDRSB   R0, [R3],#1
ROM:082F5070                 MUL     R1, R10, R0
ROM:082F5074                 BIC     R1, R1, #0xFF0000
ROM:082F5078                 ADD     R6, R1, R6,ROR#8
ROM:082F507C                 MUL     R1, R11, R0
ROM:082F5080                 BIC     R1, R1, #0xFF0000
ROM:082F5084                 ADD     R7, R1, R7,ROR#8
ROM:082F5088                 SUBS    R2, R2, #1
ROM:082F508C                 BEQ     channel_fixed_freq_loop_handler
ROM:082F5090
ROM:082F5090 channel_fixed_freq_count_sample         ; CODE XREF: entry+2C8j
ROM:082F5090                 ADDS    R5, R5, #0x40000000
ROM:082F5094                 BCC     channel_fixed_load_last_samples
ROM:082F5098                 STR     R7, [R5,#0x630]
ROM:082F509C                 STR     R6, [R5],#4
ROM:082F50A0                 SUBS    R8, R8, #4
ROM:082F50A4                 BGT     channel_fixed_freq_mixing_loop
ROM:082F50A8                 B       channel_mixing_store_pos
ROM:082F50AC ; ---------------------------------------------------------------------------
ROM:082F50AC
ROM:082F50AC channel_var_freq_mixing_loop_handler    ; CODE XREF: entry+348j
ROM:082F50AC                 LDR     R0, [SP,#ARG_VAR_AREA]
ROM:082F50B0                 CMP     R0, #0
ROM:082F50B4                 BEQ     channel_var_freq_mixing_stop_channel
ROM:082F50B8                 LDR     R3, [SP,#ARG_SCAN_LIMIT]
ROM:082F50BC                 RSB     LR, R2, #0
ROM:082F50C0
ROM:082F50C0 channel_var_freq_mixing_set_loop        ; CODE XREF: entry+2ACj
ROM:082F50C0                 ADDS    R2, R0, R2
ROM:082F50C4                 BGT     channel_var_freq_mixing_fetch_next
ROM:082F50C8                 SUB     LR, LR, R0
ROM:082F50CC                 B       channel_var_freq_mixing_set_loop
ROM:082F50D0 ; ---------------------------------------------------------------------------
ROM:082F50D0
ROM:082F50D0 channel_var_freq_mixing_stop_channel    ; CODE XREF: entry+294j
ROM:082F50D0                 LDMFD   SP!, {R4,R12}
ROM:082F50D4                 MOV     R2, #0
ROM:082F50D8                 B       channel_fixed_freq_stop_mixing
ROM:082F50DC ; ---------------------------------------------------------------------------
ROM:082F50DC
ROM:082F50DC channel_fixed_freq_loop_handler         ; CODE XREF: entry+26Cj
ROM:082F50DC                 LDR     R2, [SP,#ARG_LOOP_MODE]
ROM:082F50E0                 CMP     R2, #0
ROM:082F50E4                 LDRNE   R3, [SP,#ARG_ABS_LOOP_OFFSET]
ROM:082F50E8                 BNE     channel_fixed_freq_count_sample
ROM:082F50EC
ROM:082F50EC channel_fixed_freq_stop_mixing          ; CODE XREF: entry+2B8j
ROM:082F50EC                 STRB    R2, [R4]
ROM:082F50F0                 MOV     R0, R5,LSR#30
ROM:082F50F4                 BIC     R5, R5, #0xC0000000
ROM:082F50F8                 RSB     R0, R0, #3
ROM:082F50FC                 MOV     R0, R0,LSL#3
ROM:082F5100                 MOV     R6, R6,ROR R0
ROM:082F5104                 MOV     R7, R7,ROR R0
ROM:082F5108                 STR     R7, [R5,#0x630]
ROM:082F510C                 STR     R6, [R5],#4
ROM:082F5110                 B       channel_mixing_exit_func
ROM:082F5114 ; ---------------------------------------------------------------------------
ROM:082F5114
ROM:082F5114 channel_var_freq_mixing                 ; CODE XREF: entry+1D0j
ROM:082F5114                 STMFD   SP!, {R4,R12}
ROM:082F5118                 LDR     R1, [R4,#0x20]
ROM:082F511C                 MUL     R4, R12, R1
ROM:082F5120                 LDRSB   R0, [R3]
ROM:082F5124                 LDRSB   R1, [R3,#1]!
ROM:082F5128                 SUB     R1, R1, R0
ROM:082F512C
ROM:082F512C channel_var_freq_mixing_loop            ; CODE XREF: entry+374j
ROM:082F512C                 LDR     R6, [R5]
ROM:082F5130                 LDR     R7, [R5,#0x630]
ROM:082F5134
ROM:082F5134 channel_var_freq_mixing_resampling      ; CODE XREF: entry+364j
ROM:082F5134                 MUL     LR, R9, R1
ROM:082F5138                 ADD     LR, R0, LR,ASR#23
ROM:082F513C                 MUL     R12, R10, LR
ROM:082F5140                 BIC     R12, R12, #0xFF0000
ROM:082F5144                 ADD     R6, R12, R6,ROR#8
ROM:082F5148                 MUL     R12, R11, LR
ROM:082F514C                 BIC     R12, R12, #0xFF0000
ROM:082F5150                 ADD     R7, R12, R7,ROR#8
ROM:082F5154                 ADD     R9, R9, R4
ROM:082F5158                 MOVS    LR, R9,LSR#23
ROM:082F515C                 BEQ     channel_var_freq_mixing_count
ROM:082F5160                 BIC     R9, R9, #0x3F800000
ROM:082F5164                 SUBS    R2, R2, LR
ROM:082F5168                 BLE     channel_var_freq_mixing_loop_handler
ROM:082F516C                 SUBS    LR, LR, #1
ROM:082F5170                 ADDEQ   R0, R0, R1
ROM:082F5174
ROM:082F5174 channel_var_freq_mixing_fetch_next      ; CODE XREF: entry+2A4j
ROM:082F5174                 LDRNESB R0, [R3,LR]!
ROM:082F5178                 LDRSB   R1, [R3,#1]!
ROM:082F517C                 SUB     R1, R1, R0
ROM:082F5180
ROM:082F5180 channel_var_freq_mixing_count           ; CODE XREF: entry+33Cj
ROM:082F5180                 ADDS    R5, R5, #0x40000000
ROM:082F5184                 BCC     channel_var_freq_mixing_resampling
ROM:082F5188                 STR     R7, [R5,#0x630]
ROM:082F518C                 STR     R6, [R5],#4
ROM:082F5190                 SUBS    R8, R8, #4
ROM:082F5194                 BGT     channel_var_freq_mixing_loop
ROM:082F5198                 SUB     R3, R3, #1
ROM:082F519C                 LDMFD   SP!, {R4,R12}
ROM:082F51A0
ROM:082F51A0 channel_var_freq_mixing_store_fine_pos  ; CODE XREF: entry+1BCj
ROM:082F51A0                 STR     R9, [R4,#0x1C]
ROM:082F51A4
ROM:082F51A4 channel_mixing_store_pos                ; CODE XREF: entry+240j
ROM:082F51A4                                         ; entry+288j
ROM:082F51A4                 STR     R2, [R4,#0x18]
ROM:082F51A8                 STR     R3, [R4,#0x28]
ROM:082F51AC
ROM:082F51AC channel_mixing_exit_func                ; CODE XREF: entry+2F0j
ROM:082F51AC                 LDR     R8, [SP,#ARG_FRAME_LENGTH]
ROM:082F51B0                 ADR     R0, (channel_check_processed_channels+1)
ROM:082F51B4                 BX      R0 ; channel_check_processed_channels
ROM:082F51B8                 CODE16
ROM:082F51B8
ROM:082F51B8 channel_check_processed_channels        ; CODE XREF: entry+C0j
ROM:082F51B8                                         ; entry+10Cj
ROM:082F51B8                                         ; DATA XREF: ...
ROM:082F51B8                 LDR     R0, [SP,#ARG_CHN_LEFT]
ROM:082F51BA                 SUBS    R0, #1
ROM:082F51BC                 BLE     mixer_end
ROM:082F51BE                 ADDS    R4, #0x40
ROM:082F51C0                 B       channel_main_loop
ROM:082F51C2 ; ---------------------------------------------------------------------------
ROM:082F51C2
ROM:082F51C2 mixer_end                               ; CODE XREF: entry+B0j
ROM:082F51C2                                         ; entry+39Cj
ROM:082F51C2                 LDR     R0, [SP,#ARG_VAR_AREA]
ROM:082F51C4                 LDR     R3, =0x68736D53
ROM:082F51C6                 STR     R3, [R0]
ROM:082F51C8                 ADD     SP, SP, #0x1C
ROM:082F51CA                 POP     {R0-R7}
ROM:082F51CC                 MOV     R8, R0
ROM:082F51CE                 MOV     R9, R1
ROM:082F51D0                 MOV     R10, R2
ROM:082F51D2                 MOV     R11, R3
ROM:082F51D4                 POP     {R3}
ROM:082F51D6                 BX      R3
ROM:082F51D6 ; End of function entry
ROM:082F51D6
ROM:082F51D6 ; ---------------------------------------------------------------------------
ROM:082F51D8 dword_82F51D8   DCD 0x68736D53          ; DATA XREF: entry+3A4r
ROM:082F51DC                 CODE32
ROM:082F51DC
ROM:082F51DC ; =============== S U B R O U T I N E =======================================
ROM:082F51DC
ROM:082F51DC
ROM:082F51DC channel_compressed_mixing               ; CODE XREF: entry+1B8p
ROM:082F51DC
ROM:082F51DC ARG_FRAME_COUNT = -0xC
ROM:082F51DC ARG_LOOP_MODE   =  0x10
ROM:082F51DC
ROM:082F51DC                 LDR     R6, [R4,#0x24]  ; load wave offset to R6
ROM:082F51E0                 LDRB    R0, [R4]
ROM:082F51E4                 TST     R0, #0x20
ROM:082F51E8                 BNE     setup_compressed_mixing_frequency
ROM:082F51EC                 ORR     R0, R0, #0x20   ; if compresson or
ROM:082F51EC                                         ; reverse playback
ROM:082F51EC                                         ; not enabled yet,
ROM:082F51EC                                         ; set it up here
ROM:082F51F0                 STRB    R0, [R4]
ROM:082F51F4                 LDRB    R0, [R4,#1]
ROM:082F51F8                 TST     R0, #0x10
ROM:082F51FC                 BEQ     determine_compression
ROM:082F5200                 LDR     R1, [R6,#0xC]   ; R1 = sample amount
ROM:082F5204                 ADD     R1, R1, R6,LSL#1
ROM:082F5208                 ADD     R1, R1, #0x20
ROM:082F520C                 SUB     R3, R1, R3
ROM:082F5210                 STR     R3, [R4,#0x28]  ; reverse playback sample location
ROM:082F5214
ROM:082F5214 determine_compression                   ; CODE XREF: channel_compressed_mixing+20j
ROM:082F5214                 LDRH    R0, [R6]
ROM:082F5218                 CMP     R0, #0
ROM:082F521C                 BEQ     setup_compressed_mixing_frequency
ROM:082F5220                 SUB     R3, R3, R6
ROM:082F5224                 SUB     R3, R3, #0x10
ROM:082F5228                 STR     R3, [R4,#0x28]
ROM:082F522C
ROM:082F522C setup_compressed_mixing_frequency       ; CODE XREF: channel_compressed_mixing+Cj
ROM:082F522C                                         ; channel_compressed_mixing+40j
ROM:082F522C                 STMFD   SP!, {R8,R12,LR}
ROM:082F5230                 MOV     R10, R10,LSL#16
ROM:082F5234                 MOV     R11, R11,LSL#16
ROM:082F5238                 LDR     R1, [R4,#0x20]
ROM:082F523C                 LDRB    R0, [R4,#1]
ROM:082F5240                 TST     R0, #8
ROM:082F5244                 MOVNE   R8, #0x800000
ROM:082F5248                 MULEQ   R8, R12, R1
ROM:082F524C                 LDRH    R0, [R6]
ROM:082F5250                 CMP     R0, #0
ROM:082F5254                 BEQ     uncomressed_mixing_reverse_check
ROM:082F5258                 MOV     R0, #0xFF000000
ROM:082F525C                 STR     R0, [R4,#0x3C]
ROM:082F5260                 LDRB    R0, [R4,#1]
ROM:082F5264                 TST     R0, #0x10
ROM:082F5268                 BNE     compressed_mixing_reverse_init
ROM:082F526C                 BL      bdpcm_decoder
ROM:082F5270                 MOV     R0, R1
ROM:082F5274                 ADD     R3, R3, #1
ROM:082F5278                 BL      bdpcm_decoder
ROM:082F527C                 SUB     R1, R1, R0
ROM:082F5280
ROM:082F5280 compressed_mixing_load_samples          ; CODE XREF: channel_compressed_mixing+128j
ROM:082F5280                 LDR     R6, [R5]
ROM:082F5284                 LDR     R7, [R5,#0x630]
ROM:082F5288
ROM:082F5288 compressed_mixing_loop                  ; CODE XREF: channel_compressed_mixing+110j
ROM:082F5288                 MUL     LR, R9, R1
ROM:082F528C                 ADD     LR, R0, LR,ASR#23
ROM:082F5290                 MUL     R12, R10, LR
ROM:082F5294                 BIC     R12, R12, #0xFF0000
ROM:082F5298                 ADD     R6, R12, R6,ROR#8
ROM:082F529C                 MUL     R12, R11, LR
ROM:082F52A0                 BIC     R12, R12, #0xFF0000
ROM:082F52A4                 ADD     R7, R12, R7,ROR#8
ROM:082F52A8                 ADD     R9, R9, R8
ROM:082F52AC                 MOVS    LR, R9,LSR#23
ROM:082F52B0                 BEQ     compressed_mixing_count_current_sample
ROM:082F52B4                 BIC     R9, R9, #0x3F800000
ROM:082F52B8                 SUBS    R2, R2, LR
ROM:082F52BC                 BLE     compressed_mixing_end_handler
ROM:082F52C0                 SUBS    LR, LR, #1
ROM:082F52C4                 BNE     compressed_mixing_fetch_next
ROM:082F52C8                 ADD     R0, R0, R1
ROM:082F52CC                 B       compressed_mixing_fetch_delta
ROM:082F52D0 ; ---------------------------------------------------------------------------
ROM:082F52D0
ROM:082F52D0 compressed_mixing_fetch_next            ; CODE XREF: channel_compressed_mixing+E8j
ROM:082F52D0                                         ; channel_compressed_mixing+150j
ROM:082F52D0                 ADD     R3, R3, LR
ROM:082F52D4                 BL      bdpcm_decoder
ROM:082F52D8                 MOV     R0, R1
ROM:082F52DC
ROM:082F52DC compressed_mixing_fetch_delta           ; CODE XREF: channel_compressed_mixing+F0j
ROM:082F52DC                 ADD     R3, R3, #1
ROM:082F52E0                 BL      bdpcm_decoder
ROM:082F52E4                 SUB     R1, R1, R0
ROM:082F52E8
ROM:082F52E8 compressed_mixing_count_current_sample  ; CODE XREF: channel_compressed_mixing+D4j
ROM:082F52E8                 ADDS    R5, R5, #0x40000000
ROM:082F52EC                 BCC     compressed_mixing_loop
ROM:082F52F0                 STR     R7, [R5,#0x630]
ROM:082F52F4                 STR     R6, [R5],#4
ROM:082F52F8                 LDR     R6, [SP,#0xC+ARG_FRAME_COUNT]
ROM:082F52FC                 SUBS    R6, R6, #4
ROM:082F5300                 STR     R6, [SP,#0xC+ARG_FRAME_COUNT]
ROM:082F5304                 BGT     compressed_mixing_load_samples
ROM:082F5308                 SUB     R3, R3, #1
ROM:082F530C                 B       special_mixing_return
ROM:082F5310 ; ---------------------------------------------------------------------------
ROM:082F5310
ROM:082F5310 compressed_mixing_end_handler           ; CODE XREF: channel_compressed_mixing+E0j
ROM:082F5310                 LDR     R0, [SP,#0xC+ARG_LOOP_MODE]
ROM:082F5314                 CMP     R0, #0
ROM:082F5318                 BEQ     compressed_mixing_stop_and_return
ROM:082F531C                 LDR     R3, [R4,#0x24]
ROM:082F5320                 LDR     R3, [R3,#8]
ROM:082F5324                 RSB     LR, R2, #0
ROM:082F5328
ROM:082F5328 compressed_mixing_loop_handler          ; CODE XREF: channel_compressed_mixing+158j
ROM:082F5328                 ADDS    R2, R2, R0
ROM:082F532C                 BGT     compressed_mixing_fetch_next
ROM:082F5330                 SUB     LR, LR, R0
ROM:082F5334                 B       compressed_mixing_loop_handler
ROM:082F5338 ; ---------------------------------------------------------------------------
ROM:082F5338
ROM:082F5338 compressed_mixing_reverse_init          ; CODE XREF: channel_compressed_mixing+8Cj
ROM:082F5338                 SUB     R3, R3, #1
ROM:082F533C                 BL      bdpcm_decoder
ROM:082F5340                 MOV     R0, R1
ROM:082F5344                 SUB     R3, R3, #1
ROM:082F5348                 BL      bdpcm_decoder
ROM:082F534C                 SUB     R1, R1, R0
ROM:082F5350
ROM:082F5350 compressed_mixing_reverse_load_samples  ; CODE XREF: channel_compressed_mixing+1F8j
ROM:082F5350                 LDR     R6, [R5]
ROM:082F5354                 LDR     R7, [R5,#0x630]
ROM:082F5358
ROM:082F5358 compressed_mixing_reverse_loop          ; CODE XREF: channel_compressed_mixing+1E0j
ROM:082F5358                 MUL     LR, R9, R1
ROM:082F535C                 ADD     LR, R0, LR,ASR#23
ROM:082F5360                 MUL     R12, R10, LR
ROM:082F5364                 BIC     R12, R12, #0xFF0000
ROM:082F5368                 ADD     R6, R12, R6,ROR#8
ROM:082F536C                 MUL     R12, R11, LR
ROM:082F5370                 BIC     R12, R12, #0xFF0000
ROM:082F5374                 ADD     R7, R12, R7,ROR#8
ROM:082F5378                 ADD     R9, R9, R8
ROM:082F537C                 MOVS    LR, R9,LSR#23
ROM:082F5380                 BEQ     compressed_mixing_reverse_count_sample
ROM:082F5384                 BIC     R9, R9, #0x3F800000
ROM:082F5388                 SUBS    R2, R2, LR
ROM:082F538C                 BLE     compressed_mixing_stop_and_return
ROM:082F5390                 SUBS    LR, LR, #1
ROM:082F5394                 BNE     compressed_mixing_reverse_fetch_next
ROM:082F5398                 ADD     R0, R0, R1
ROM:082F539C                 B       compressed_mixing_reverse_seekback
ROM:082F53A0 ; ---------------------------------------------------------------------------
ROM:082F53A0
ROM:082F53A0 compressed_mixing_reverse_fetch_next    ; CODE XREF: channel_compressed_mixing+1B8j
ROM:082F53A0                 SUB     R3, R3, LR
ROM:082F53A4                 BL      bdpcm_decoder
ROM:082F53A8                 MOV     R0, R1
ROM:082F53AC
ROM:082F53AC compressed_mixing_reverse_seekback      ; CODE XREF: channel_compressed_mixing+1C0j
ROM:082F53AC                 SUB     R3, R3, #1
ROM:082F53B0                 BL      bdpcm_decoder
ROM:082F53B4                 SUB     R1, R1, R0
ROM:082F53B8
ROM:082F53B8 compressed_mixing_reverse_count_sample  ; CODE XREF: channel_compressed_mixing+1A4j
ROM:082F53B8                 ADDS    R5, R5, #0x40000000
ROM:082F53BC                 BCC     compressed_mixing_reverse_loop
ROM:082F53C0                 STR     R7, [R5,#0x630]
ROM:082F53C4                 STR     R6, [R5],#4
ROM:082F53C8                 LDR     R6, [SP,#0xC+ARG_FRAME_COUNT]
ROM:082F53CC                 SUBS    R6, R6, #4
ROM:082F53D0                 STR     R6, [SP,#0xC+ARG_FRAME_COUNT]
ROM:082F53D4                 BGT     compressed_mixing_reverse_load_samples
ROM:082F53D8                 ADD     R3, R3, #2
ROM:082F53DC                 B       special_mixing_return
ROM:082F53E0 ; ---------------------------------------------------------------------------
ROM:082F53E0
ROM:082F53E0 uncomressed_mixing_reverse_check        ; CODE XREF: channel_compressed_mixing+78j
ROM:082F53E0                 LDRB    R0, [R4,#1]
ROM:082F53E4                 TST     R0, #0x10
ROM:082F53E8                 BEQ     special_mixing_return
ROM:082F53EC                 LDRSB   R0, [R3,#-1]!
ROM:082F53F0                 LDRSB   R1, [R3,#-1]
ROM:082F53F4                 SUB     R1, R1, R0
ROM:082F53F8
ROM:082F53F8 uncompressed_mixing_reverse_load_samples
ROM:082F53F8                                         ; CODE XREF: channel_compressed_mixing+284j
ROM:082F53F8                 LDR     R6, [R5]
ROM:082F53FC                 LDR     R7, [R5,#0x630]
ROM:082F5400
ROM:082F5400 uncompressed_mixing_reverse_loop        ; CODE XREF: channel_compressed_mixing+26Cj
ROM:082F5400                 MUL     LR, R9, R1
ROM:082F5404                 ADD     LR, R0, LR,ASR#23
ROM:082F5408                 MUL     R12, R10, LR
ROM:082F540C                 BIC     R12, R12, #0xFF0000
ROM:082F5410                 ADD     R6, R12, R6,ROR#8
ROM:082F5414                 MUL     R12, R11, LR
ROM:082F5418                 BIC     R12, R12, #0xFF0000
ROM:082F541C                 ADD     R7, R12, R7,ROR#8
ROM:082F5420                 ADD     R9, R9, R8
ROM:082F5424                 MOVS    LR, R9,LSR#23
ROM:082F5428                 BEQ     uncompressed_mixing_reverse_count
ROM:082F542C                 BIC     R9, R9, #0x3F800000
ROM:082F5430                 SUBS    R2, R2, LR
ROM:082F5434                 BLE     compressed_mixing_stop_and_return
ROM:082F5438                 LDRSB   R0, [R3,-LR]!
ROM:082F543C                 LDRSB   R1, [R3,#-1]
ROM:082F5440                 SUB     R1, R1, R0
ROM:082F5444
ROM:082F5444 uncompressed_mixing_reverse_count       ; CODE XREF: channel_compressed_mixing+24Cj
ROM:082F5444                 ADDS    R5, R5, #0x40000000
ROM:082F5448                 BCC     uncompressed_mixing_reverse_loop
ROM:082F544C                 STR     R7, [R5,#0x630]
ROM:082F5450                 STR     R6, [R5],#4
ROM:082F5454                 LDR     R6, [SP,#0xC+ARG_FRAME_COUNT]
ROM:082F5458                 SUBS    R6, R6, #4
ROM:082F545C                 STR     R6, [SP,#0xC+ARG_FRAME_COUNT]
ROM:082F5460                 BGT     uncompressed_mixing_reverse_load_samples
ROM:082F5464                 ADD     R3, R3, #1
ROM:082F5468
ROM:082F5468 special_mixing_return                   ; CODE XREF: channel_compressed_mixing+130j
ROM:082F5468                                         ; channel_compressed_mixing+200j ...
ROM:082F5468                 LDMFD   SP!, {R8,R12,PC}
ROM:082F546C ; ---------------------------------------------------------------------------
ROM:082F546C
ROM:082F546C compressed_mixing_stop_and_return       ; CODE XREF: channel_compressed_mixing+13Cj
ROM:082F546C                                         ; channel_compressed_mixing+1B0j ...
ROM:082F546C                 MOV     R2, #0
ROM:082F5470                 STRB    R2, [R4]
ROM:082F5474                 MOV     R0, R5,LSR#30
ROM:082F5478                 BIC     R5, R5, #0xC0000000
ROM:082F547C                 RSB     R0, R0, #3
ROM:082F5480                 MOV     R0, R0,LSL#3
ROM:082F5484                 MOV     R6, R6,ROR R0
ROM:082F5488                 MOV     R7, R7,ROR R0
ROM:082F548C                 STR     R7, [R5,#0x630]
ROM:082F5490                 STR     R6, [R5],#4
ROM:082F5494                 LDMFD   SP!, {R8,R12,PC}
ROM:082F5494 ; End of function channel_compressed_mixing
ROM:082F5494
ROM:082F5498
ROM:082F5498 ; =============== S U B R O U T I N E =======================================
ROM:082F5498
ROM:082F5498
ROM:082F5498 bdpcm_decoder                           ; CODE XREF: channel_compressed_mixing+90p
ROM:082F5498                                         ; channel_compressed_mixing+9Cp ...
ROM:082F5498                 STMFD   SP!, {R0,R2,R5-R7,LR}
ROM:082F549C                 MOV     R0, R3,LSR#6
ROM:082F54A0                 LDR     R1, [R4,#0x3C]
ROM:082F54A4                 CMP     R0, R1
ROM:082F54A8                 BEQ     bdpcm_decoder_return
ROM:082F54AC                 STR     R0, [R4,#0x3C]
ROM:082F54B0                 MOV     R1, #0x21
ROM:082F54B4                 MUL     R2, R1, R0
ROM:082F54B8                 LDR     R1, [R4,#0x24]
ROM:082F54BC                 ADD     R2, R2, R1
ROM:082F54C0                 ADD     R2, R2, #0x10
ROM:082F54C4                 LDR     R5, =0x3001300
ROM:082F54C8                 LDR     R6, =delta_table_686C5C
ROM:082F54CC                 MOV     R7, #0x40
ROM:082F54D0                 LDRB    LR, [R2],#1
ROM:082F54D4                 STRB    LR, [R5],#1
ROM:082F54D8                 LDRB    R1, [R2],#1
ROM:082F54DC                 B       bdpcm_decoder_lsb
ROM:082F54E0 ; ---------------------------------------------------------------------------
ROM:082F54E0
ROM:082F54E0 bdpcm_decoder_msb                       ; CODE XREF: bdpcm_decoder+70j
ROM:082F54E0                 LDRB    R1, [R2],#1
ROM:082F54E4                 MOV     R0, R1,LSR#4
ROM:082F54E8                 LDRSB   R0, [R6,R0]
ROM:082F54EC                 ADD     LR, LR, R0
ROM:082F54F0                 STRB    LR, [R5],#1
ROM:082F54F4
ROM:082F54F4 bdpcm_decoder_lsb                       ; CODE XREF: bdpcm_decoder+44j
ROM:082F54F4                 AND     R0, R1, #0xF
ROM:082F54F8                 LDRSB   R0, [R6,R0]
ROM:082F54FC                 ADD     LR, LR, R0
ROM:082F5500                 STRB    LR, [R5],#1
ROM:082F5504                 SUBS    R7, R7, #2
ROM:082F5508                 BGT     bdpcm_decoder_msb
ROM:082F550C
ROM:082F550C bdpcm_decoder_return                    ; CODE XREF: bdpcm_decoder+10j
ROM:082F550C                 LDR     R5, =0x3001300
ROM:082F5510                 AND     R0, R3, #0x3F
ROM:082F5514                 LDRSB   R1, [R5,R0]
ROM:082F5518                 LDMFD   SP!, {R0,R2,R5-R7,PC}
ROM:082F5518 ; End of function bdpcm_decoder
ROM:082F5518
ROM:082F5518 ; ---------------------------------------------------------------------------
ROM:082F551C decoder_buffer  DCD 0x3001300           ; DATA XREF: bdpcm_decoder+2Cr
ROM:082F551C                                         ; bdpcm_decoder:bdpcm_decoder_returnr
ROM:082F5520 delta_lookup_table DCD delta_table_686C5C ; DATA XREF: bdpcm_decoder+30r
I didn't dump the BIOS code because I don't see a reason in doing it. Iirc it uses a less optimized code and is slower and doesn't support certain features like the cry playback and the reverse playback.
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
  #24    
Old September 28th, 2014 (06:07 AM).
PokeBunny's Avatar
PokeBunny PokeBunny is offline
Pokemon Game Maker
 
Join Date: Aug 2012
Location: South Africa
Age: 15
Gender: Male
Nature: Serious
Posts: 34
Do you have code for the music player?
__________________
special POKeBUNNY

The Pokemon Game Developer
If you are wondering why I'm taking long to make Pokemon Hot Red and Cold Blue... It's because I barely get computer time. Be patient (I'm not!.

My SoundCloud!!!!!!!!!
Reply With Quote
  #25    
Old October 1st, 2014 (04:19 AM).
ipatix's Avatar
ipatix ipatix is offline
Sound Expert
 
Join Date: May 2008
Location: Germany
Gender: Male
Nature: Relaxed
Posts: 137
What do you mean by "music player"?

Do you mean the whole sound engine?
Do you mean the song data decoder?
__________________
Visit my YouTube channel (music hacking and other stuff): http://www.youtube.com/user/theipatix
Reply With Quote
Reply
Quick Reply

Sponsored Links
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are UTC -8. The time now is 10:35 PM.