// File: ipatix[P]wav2agb/converter.cpp
// Function: dpcm_lookahead(int&, unsigned long&, double const*, unsigned long, int)
static void dpcm_lookahead(
        int& minimumError, size_t& minimumErrorIndex,
        const double *sampleBuf, const size_t lookahead, const int prevLevel)
{
    if (lookahead == 0) {
        minimumError = 0;
        return;
    }

    minimumError = std::numeric_limits<int>::max();
    minimumErrorIndex = dpcmLookupTable.size();

    for (size_t i = 0; i < dpcmLookupTable.size(); i++) {
        int newLevel = prevLevel + dpcmLookupTable[i];

        int recMinimumError;
        size_t recMinimumErrorIndex;

        // TODO apply dither noise
        int s = clamp(static_cast<int>(floor(sampleBuf[0] * 128.0)), -128, 127);
        int errorEstimation = squared(s - newLevel);
        if (errorEstimation >= minimumError)
            continue;

        dpcm_lookahead(recMinimumError, recMinimumErrorIndex,
                sampleBuf + 1, lookahead - 1, newLevel);

        // TODO weigh the error squared
        int error = squared(s - newLevel) + recMinimumError;
        if (error < minimumError) {
            if (newLevel <= 127 && newLevel >= -128) {
                minimumError = error;
                minimumErrorIndex = i;
            }
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movl %r8d, -0x24(%rbp)
cmpq $0x0, -0x20(%rbp)
jne 0x4332
movq -0x8(%rbp), %rax
movl $0x0, (%rax)
jmp 0x4472
callq 0x4710
movl %eax, %ecx
movq -0x8(%rbp), %rax
movl %ecx, (%rax)
leaq 0xcfaa(%rip), %rdi      # 0x112f0
callq 0x4720
movq %rax, %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
movq $0x0, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x60(%rbp)
leaq 0xcf84(%rip), %rdi      # 0x112f0
callq 0x4720
movq %rax, %rcx
movq -0x60(%rbp), %rax
cmpq %rcx, %rax
jae 0x4472
movl -0x24(%rbp), %eax
movl %eax, -0x64(%rbp)
movq -0x30(%rbp), %rsi
leaq 0xcf5e(%rip), %rdi      # 0x112f0
callq 0x46f0
movq %rax, %rcx
movl -0x64(%rbp), %eax
movsbl (%rcx), %ecx
addl %ecx, %eax
movl %eax, -0x34(%rbp)
movq -0x18(%rbp), %rax
movsd 0x7c7f(%rip), %xmm0     # 0xc030
mulsd (%rax), %xmm0
callq 0x3480
cvttsd2si %xmm0, %eax
movl %eax, -0x48(%rbp)
movl $0xffffff80, -0x4c(%rbp) # imm = 0xFFFFFF80
movl $0x7f, -0x50(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x4c(%rbp), %rsi
leaq -0x50(%rbp), %rdx
callq 0x4650
movl (%rax), %eax
movl %eax, -0x44(%rbp)
movl -0x44(%rbp), %edi
subl -0x34(%rbp), %edi
callq 0x4480
movl %eax, -0x54(%rbp)
movl -0x54(%rbp), %eax
movq -0x8(%rbp), %rcx
cmpl (%rcx), %eax
jl 0x4400
jmp 0x4461
movq -0x18(%rbp), %rdx
addq $0x8, %rdx
movq -0x20(%rbp), %rcx
subq $0x1, %rcx
movl -0x34(%rbp), %r8d
leaq -0x38(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x4300
movl -0x44(%rbp), %edi
subl -0x34(%rbp), %edi
callq 0x4480
addl -0x38(%rbp), %eax
movl %eax, -0x58(%rbp)
movl -0x58(%rbp), %eax
movq -0x8(%rbp), %rcx
cmpl (%rcx), %eax
jge 0x445f
cmpl $0x7f, -0x34(%rbp)
jg 0x445d
cmpl $-0x80, -0x34(%rbp)
jl 0x445d
movl -0x58(%rbp), %ecx
movq -0x8(%rbp), %rax
movl %ecx, (%rax)
movq -0x30(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
jmp 0x445f
jmp 0x4461
movq -0x30(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x30(%rbp)
jmp 0x435d
addq $0x70, %rsp
popq %rbp
retq
nopl (%rax,%rax)