// File: ipatix[P]wav2agb/converter.cpp
// Function: convert_dpcm(wav_file&, std::basic_ofstream<char, std::char_traits<char>>&)
static void convert_dpcm(wav_file& wf, std::ofstream& ofs)
{
    int loop_sample = 0;

    uint32_t block_pos = 0;

    int minimumError;
    size_t minimumErrorIndex;

    for (size_t i = 0; i <= wf.loopEnd; i += DPCM_BLK_SIZE) {
        double ds[DPCM_BLK_SIZE];
        wf.readData(i, ds, DPCM_BLK_SIZE);
        // check if loop end is inside this block
        if (i + DPCM_BLK_SIZE > wf.loopEnd) {
            assert(wf.loopEnd - i < DPCM_BLK_SIZE);
            ds[wf.loopEnd - i] = loop_sample;
        }
        // TODO apply dither noise
        int s = clamp(static_cast<int>(floor(ds[0] * 128.0)), -128, 127);

        if (wf.loopEnabled && i == wf.loopStart)
            loop_sample = s;

        data_write(ofs, block_pos, s, false);

        size_t innerLoopCount = 1;
        uint8_t outData = 0;
        size_t sampleBufReadLen;

        goto initial_loop_enter;

        do {
            sampleBufReadLen = std::min(dpcm_enc_lookahead, DPCM_BLK_SIZE - innerLoopCount);
            dpcm_lookahead(
                    minimumError, minimumErrorIndex,
                    &ds[innerLoopCount], sampleBufReadLen, s);
            outData = static_cast<uint8_t>((minimumErrorIndex & 0xF) << 4);
            s += dpcmLookupTable[minimumErrorIndex];
            innerLoopCount += 1;
initial_loop_enter:
            sampleBufReadLen = std::min(dpcm_enc_lookahead, DPCM_BLK_SIZE - innerLoopCount);
            dpcm_lookahead(
                    minimumError, minimumErrorIndex,
                    &ds[innerLoopCount], sampleBufReadLen, s);
            outData |= static_cast<uint8_t>(minimumErrorIndex & 0xF);
            s += dpcmLookupTable[minimumErrorIndex];
            innerLoopCount += 1;
            data_write(ofs, block_pos, outData, true);
        } while (innerLoopCount < DPCM_BLK_SIZE);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x270, %rsp            # imm = 0x270
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x0, -0x14(%rbp)
movl $0x0, -0x18(%rbp)
movq $0x0, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq -0x8(%rbp), %rcx
movl 0x258(%rcx), %ecx
cmpq %rcx, %rax
ja 0x4243
movq -0x8(%rbp), %rdi
movq -0x30(%rbp), %rsi
leaq -0x230(%rbp), %rdx
movl $0x40, %ecx
callq 0x84d0
movq -0x30(%rbp), %rax
addq $0x40, %rax
movq -0x8(%rbp), %rcx
movl 0x258(%rcx), %ecx
cmpq %rcx, %rax
jbe 0x4011
movq -0x8(%rbp), %rax
movl 0x258(%rax), %eax
subq -0x30(%rbp), %rax
cmpq $0x40, %rax
jae 0x3fd6
jmp 0x3ff5
leaq 0x8173(%rip), %rdi      # 0xc150
leaq 0x818b(%rip), %rsi      # 0xc16f
movl $0x87, %edx
leaq 0x818d(%rip), %rcx      # 0xc17d
callq 0x31d0
cvtsi2sdl -0x14(%rbp), %xmm0
movq -0x8(%rbp), %rax
movl 0x258(%rax), %eax
subq -0x30(%rbp), %rax
movsd %xmm0, -0x230(%rbp,%rax,8)
movsd 0x8017(%rip), %xmm0     # 0xc030
mulsd -0x230(%rbp), %xmm0
callq 0x3480
cvttsd2si %xmm0, %eax
movl %eax, -0x238(%rbp)
movl $0xffffff80, -0x23c(%rbp) # imm = 0xFFFFFF80
movl $0x7f, -0x240(%rbp)
leaq -0x238(%rbp), %rdi
leaq -0x23c(%rbp), %rsi
leaq -0x240(%rbp), %rdx
callq 0x4650
movl (%rax), %eax
movl %eax, -0x234(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x25c(%rax)
je 0x408f
movq -0x30(%rbp), %rax
movq -0x8(%rbp), %rcx
movl 0x254(%rcx), %ecx
cmpq %rcx, %rax
jne 0x408f
movl -0x234(%rbp), %eax
movl %eax, -0x14(%rbp)
movq -0x10(%rbp), %rdi
movl -0x234(%rbp), %edx
leaq -0x18(%rbp), %rsi
xorl %ecx, %ecx
callq 0x4250
movq $0x1, -0x248(%rbp)
movb $0x0, -0x249(%rbp)
jmp 0x415e
movl $0x40, %eax
subq -0x248(%rbp), %rax
movq %rax, -0x260(%rbp)
leaq 0xd1f3(%rip), %rdi      # 0x112c8
leaq -0x260(%rbp), %rsi
callq 0x46b0
movq (%rax), %rax
movq %rax, -0x258(%rbp)
movq -0x248(%rbp), %rax
leaq -0x230(%rbp), %rdx
shlq $0x3, %rax
addq %rax, %rdx
movq -0x258(%rbp), %rcx
movl -0x234(%rbp), %r8d
leaq -0x1c(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0x4300
movq -0x28(%rbp), %rax
andq $0xf, %rax
shlq $0x4, %rax
movb %al, -0x249(%rbp)
movq -0x28(%rbp), %rsi
leaq 0xd1b8(%rip), %rdi      # 0x112f0
callq 0x46f0
movsbl (%rax), %eax
addl -0x234(%rbp), %eax
movl %eax, -0x234(%rbp)
movq -0x248(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x248(%rbp)
movl $0x40, %eax
subq -0x248(%rbp), %rax
movq %rax, -0x268(%rbp)
leaq 0xd150(%rip), %rdi      # 0x112c8
leaq -0x268(%rbp), %rsi
callq 0x46b0
movq (%rax), %rax
movq %rax, -0x258(%rbp)
movq -0x248(%rbp), %rax
leaq -0x230(%rbp), %rdx
shlq $0x3, %rax
addq %rax, %rdx
movq -0x258(%rbp), %rcx
movl -0x234(%rbp), %r8d
leaq -0x1c(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0x4300
movq -0x28(%rbp), %rax
andq $0xf, %rax
movzbl %al, %ecx
movzbl -0x249(%rbp), %eax
orl %ecx, %eax
movb %al, -0x249(%rbp)
movq -0x28(%rbp), %rsi
leaq 0xd10d(%rip), %rdi      # 0x112f0
callq 0x46f0
movsbl (%rax), %eax
addl -0x234(%rbp), %eax
movl %eax, -0x234(%rbp)
movq -0x248(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x248(%rbp)
movq -0x10(%rbp), %rdi
movzbl -0x249(%rbp), %edx
leaq -0x18(%rbp), %rsi
movl $0x1, %ecx
callq 0x4250
cmpq $0x40, -0x248(%rbp)
jb 0x40bb
jmp 0x4232
movq -0x30(%rbp), %rax
addq $0x40, %rax
movq %rax, -0x30(%rbp)
jmp 0x3f79
addq $0x270, %rsp            # imm = 0x270
popq %rbp
retq
nopl (%rax)