// File: /workspace/github_cpp_makefile_star2_O3/khedoros[P]khednes/apu.cpp
// Function: apu::gen_audio(unsigned short)
void apu::gen_audio(uint16_t to_gen) { //To be run once per frame, to generate audio
    //cout<<"Gen_audio"<<endl;
    write_pos = !write_pos;
    //assert(to_gen == SAMPLES_PER_FRAME);
    //std::cout<<"apu::gen_audio("<<to_gen<<")"<<std::endl;
    uint16_t reg_audio_sample = SAMPLES_PER_FRAME + 20;
    int write_cycle = 0;
    int write_frame = 0;
    if(writes.size() > 0) { //If there are reg writes left on the queue, find the frame where the next one should apply
        //cout<<writes.size()<<" reg writes in queue"<<endl;
        write_frame = writes.front().first.first;
        //frame = write_frame;
        write_cycle = writes.front().first.second; //Write cycle is in terms of PPU cycle
        reg_audio_sample = uint16_t(double(write_cycle) * double(SAMPLES_PER_FRAME) / double(CLK_PER_FRAME)); //Convert it to which sample the change applies to
        //if(writes.size() > 50) {
            //cout<<"writes.size() = "<<writes.size()<<" next reg at sample: "<<reg_audio_sample<<endl;
        //}
    }

    for(int i = 0; i < SAMPLES_PER_FRAME; ++i) {
        //cout<<"Sample "<<i<<endl;
        //clock the 60Hz, 120Hz, and 240Hz things
        if(i == SAMPLES_PER_FRAME / 4) {
            clock_quarter();
        }
        else if(i == SAMPLES_PER_FRAME / 2) {
            clock_quarter();
            clock_half();
        }
        else if(i == (SAMPLES_PER_FRAME * 3) / 4) {
            clock_quarter();
        }
        else if(i == (SAMPLES_PER_FRAME - 1)) {
            clock_quarter();
            clock_half();
        }

        //Clock the things that need updated *every* cycle (but we've got to emulate that, since this loop only covers every sample)
        clock_every();

        while(writes.size() > 0 && ((write_frame == frame && reg_audio_sample <= i) || write_frame < frame)) { //Apply Register writes that go here
            //cout<<"Woot, applying a reg write with "<<writes.size()<<"writes remaining"<<endl;
            reg_dequeue();
            if(writes.size() > 0) {
                write_frame = writes.front().first.first;
                write_cycle = writes.front().first.second;
                reg_audio_sample = uint16_t(double(write_cycle) * double(SAMPLES_PER_FRAME) / double(CLK_PER_FRAME));
            }
            else {
                reg_audio_sample = SAMPLES_PER_FRAME + 20; //i.e. don't trigger a dequeue again
            }
        }
        char accum = 0;
        for(int voice = 0; voice < 4; ++voice) {
            //cout<<"Doing voice "<<voice<<endl;
            //Get sample value for each voice, put into appropriate buffer location
            if(enabled[voice] && length[voice] != 0 && (voice != TRI || !enable_linear_cntr || linear_cntr != 0)) {
                //cout<<"getting sample =)"<<endl;
                accum += get_sample(voice);
            }
            //else
            //    cout<<"Not getting sample for voice "<<voice<<endl;
        }
        //if(int(accum) + pcm_data > 255) cout<<"Too big: accum="<<int(accum)<<", pcm="<<pcm_data<<endl;
        //if(pcm_data != 0) cout<<"pcm="<<pcm_data<<endl;
        //cout<<"first: "<<dat.first<<"loc: "<<dat.first*SAMPLES_PER_FRAME<<endl;
        dat.buffer[i+(buffer_write_pos * SAMPLES_PER_FRAME)] = accum + dmc_pcm_data/4;

    }
    //cout<<hex<<val.first<<": 0x"<<val.second.first<<" val: 0x"<<val.second.second<<endl;
    //frame++;
    //if(write_pos) write_pos = 0;
    //else write_pos = 1;
    //cout<<"End of gen_audio"<<endl;
    dat.buffered+=SAMPLES_PER_FRAME;
    buffer_write_pos++;
    buffer_write_pos %= obtained.samples;
    //cout<<"Generate 735"<<endl;
    //cout<<"Write: Frame: "<<frame<<" buffer index: "<<buffer_write_pos<<" samples: "<<buffer_write_pos*SAMPLES_PER_FRAME<<" -> "<<(buffer_write_pos+1)*SAMPLES_PER_FRAME<<endl;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
xorb $0x1, (%rdi)
cmpq $0x0, 0x60(%rdi)
je 0x111f9
movq 0x50(%rbx), %rax
movl 0x10(%rax), %ebp
cvtsi2sdl 0x14(%rax), %xmm0
mulsd 0x4b0e(%rip), %xmm0     # 0x15cf8
divsd 0x4b0e(%rip), %xmm0     # 0x15d00
cvttsd2si %xmm0, %r12d
jmp 0x11200
xorl %ebp, %ebp
movw $0x2f3, %r12w           # imm = 0x2F3
xorl %r15d, %r15d
cmpl $0x226, %r15d           # imm = 0x226
jg 0x11220
cmpl $0xb7, %r15d
je 0x11244
cmpl $0x16f, %r15d           # imm = 0x16F
je 0x11232
jmp 0x1124c
cmpl $0x227, %r15d           # imm = 0x227
je 0x11244
cmpl $0x2de, %r15d           # imm = 0x2DE
jne 0x1124c
movq %rbx, %rdi
callq 0x10eea
movq %rbx, %rdi
callq 0x10f92
jmp 0x1124c
movq %rbx, %rdi
callq 0x10eea
movq %rbx, %rdi
callq 0x1106c
cmpq $0x0, 0x60(%rbx)
je 0x112b2
movl 0x244(%rbx), %edx
cmpl %edx, %ebp
sete %al
movzwl %r12w, %ecx
cmpq %rcx, %r15
setae %cl
cmpl %edx, %ebp
jl 0x11278
andb %cl, %al
je 0x112b2
movq %rbx, %rdi
callq 0x1135e
cmpq $0x0, 0x60(%rbx)
je 0x112ad
movq 0x50(%rbx), %rax
xorps %xmm0, %xmm0
cvtsi2sdl 0x14(%rax), %xmm0
mulsd 0x4a5d(%rip), %xmm0     # 0x15cf8
divsd 0x4a5d(%rip), %xmm0     # 0x15d00
cvttsd2si %xmm0, %r12d
movl 0x10(%rax), %ebp
jmp 0x1125b
movw $0x2f3, %r12w           # imm = 0x2F3
xorl %r14d, %r14d
xorl %r13d, %r13d
cmpb $0x1, 0xb4(%rbx,%r14)
jne 0x112f4
cmpl $0x0, 0x174(%rbx,%r14,4)
je 0x112f4
cmpq $0x2, %r14
jne 0x112e6
cmpb $0x1, 0x11c(%rbx)
jne 0x112e6
cmpl $0x0, 0x118(%rbx)
je 0x112f4
movq %rbx, %rdi
movl %r14d, %esi
callq 0x11832
addb %al, %r13b
incq %r14
cmpq $0x4, %r14
jne 0x112b8
movl 0x220(%rbx), %eax
leal 0x3(%rax), %ecx
testl %eax, %eax
cmovnsl %eax, %ecx
shrl $0x2, %ecx
imulq $0x2df, 0x8(%rbx), %rax # imm = 0x2DF
addq 0x18(%rbx), %rax
addb %cl, %r13b
movb %r13b, (%r15,%rax)
incq %r15
cmpq $0x2df, %r15            # imm = 0x2DF
jne 0x11203
addl $0x2df, 0x2c(%rbx)      # imm = 0x2DF
movq 0x8(%rbx), %rax
incq %rax
movzwl 0x98(%rbx), %ecx
xorl %edx, %edx
divq %rcx
movq %rdx, 0x8(%rbx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq