// File: khedoros[P]khednes/apu.cpp
// Function: apu::init(bool)
void apu::init(bool headless/*=false*/) {

    //dat.buffer = &(buffer[0]); Set this after the number of samples has been determined
    dat.apui = this;
    dat.first = 1;
    dat.buffered = 0;

    desired.freq = SAMPLE_RATE;
    desired.format = AUDIO_U8;
    desired.channels = 1;

    //#ifndef _WIN32
    //desired.samples = SAMPLES_PER_FRAME * 2; //Works for PulseAudio
    //#else
    desired.samples = 1024;                  //Works for DirectSound
    //#endif
    desired.callback = my_callback;
    desired.userdata = &dat;

    int init_success = 0;

    #ifdef _WIN32
    const char * desired_driver = "directsound";
    #else
    const char * desired_driver = "pulseaudio";
    #endif

    if(headless) {
        printf("In headless mode; going to init dummy audio driver.\n");
        init_success = SDL_AudioInit("dummy");
    }
    else {
        for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
            const char* driver_name = SDL_GetAudioDriver(i);
            printf("Audio driver #%d: %s\n", i, driver_name);
            if(strcmp(driver_name, desired_driver) == 0) {
                cout<<"Going to init "<<desired_driver<<" driver."<<endl;
                init_success = SDL_AudioInit(desired_driver);
            }
        }
    }
    
    const char * device_name = "";
    if(init_success == 0) {
        cout<<"I think I successfully init'd the driver. Here are the "<<SDL_GetNumAudioDevices(0)<<" audio devices it provides: "<<endl;
        for(int i=0;i<SDL_GetNumAudioDevices(0);++i) {
            device_name = SDL_GetAudioDeviceName(i,0);
            #ifdef _WIN32
            if(i == 0 && device_name) id = SDL_OpenAudioDevice(device_name, 0, &desired, &obtained, 0);
            #endif
            
            if(device_name) {
                printf("Audio device #%d: %s\n", i, device_name);
            }
            else
                printf("Audio device #%d: NULL!?!\n", i);
        }
    }

    #ifndef _WIN32
    id = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
    #endif    

    if(id <= 0) {
        cerr<<"Couldn't open the audio device: "<<SDL_GetError()<<endl;
        //return 1;
    }
    else {
        if(SDL_GetCurrentAudioDriver()) {
            cout<<"Opened audio device with driver: "<<SDL_GetCurrentAudioDriver()<<endl;
        }
        else {
            cout<<"Doesn't seem like a driver was successfully init'd!"<<endl;

        }
    }

    if(id > 0) {
    //if(desired.freq != obtained.freq || desired.format != obtained.format || desired.channels != obtained.channels || desired.samples != obtained.samples) {
        //cout<<"Desired:\n\tFreq: "<<desired.freq<<"\n\tFormat: "<<desired.format<<"\n\tChannels: "<<int(desired.channels)<<"\n\tSamples: "<<desired.samples<<endl<<endl;
        cout<<"Obtained:\n\tFreq: "<<obtained.freq<<"\n\tFormat: "<<obtained.format<<"\n\tChannels: "<<int(obtained.channels)<<"\n\tSamples: "<<obtained.samples<<endl;
            //cout<<"Bufsize: "<<bufsize<<endl;
        size_t bufsize = SAMPLES_PER_FRAME * obtained.samples;
        buffer.resize(bufsize,0);
        dat.buffer = &(buffer[0]);
    //}
    //cout<<"byte size: "<<obtained.size<<endl;

    //if(obtained.freq != SAMPLE_RATE) {
    //    cout<<"Didn't get the frequency I wanted. Should be interesting."<<endl;
    //}
    }
}

// Assembly:
subq $0x78, %rsp
movb %sil, %al
movq %rdi, 0x70(%rsp)
andb $0x1, %al
movb %al, 0x6f(%rsp)
movq 0x70(%rsp), %rax
movq %rax, 0x28(%rsp)
movq %rax, 0x20(%rax)
movb $0x1, 0x28(%rax)
movl $0x0, 0x2c(%rax)
movl $0xac44, 0x70(%rax)     # imm = 0xAC44
movw $0x8, 0x74(%rax)
movb $0x1, 0x76(%rax)
movw $0x400, 0x78(%rax)      # imm = 0x400
leaq -0x189(%rip), %rcx      # 0x22200
movq %rcx, 0x80(%rax)
movq %rax, %rcx
addq $0x18, %rcx
movq %rcx, 0x88(%rax)
movl $0x0, 0x68(%rsp)
leaq 0xaad5(%rip), %rax      # 0x2ce82
movq %rax, 0x60(%rsp)
testb $0x1, 0x6f(%rsp)
je 0x223dc
leaq 0xaacd(%rip), %rdi      # 0x2ce8d
movb $0x0, %al
callq 0x4050
leaq 0xaaf4(%rip), %rdi      # 0x2cec2
callq 0x4590
movl %eax, 0x68(%rsp)
jmp 0x22498
movl $0x0, 0x5c(%rsp)
movl 0x5c(%rsp), %eax
movl %eax, 0x24(%rsp)
callq 0x4110
movl %eax, %ecx
movl 0x24(%rsp), %eax
cmpl %ecx, %eax
jge 0x22496
movl 0x5c(%rsp), %edi
callq 0x46b0
movq %rax, 0x50(%rsp)
movl 0x5c(%rsp), %esi
movq 0x50(%rsp), %rdx
leaq 0xaaab(%rip), %rdi      # 0x2cec8
movb $0x0, %al
callq 0x4050
movq 0x50(%rsp), %rdi
movq 0x60(%rsp), %rsi
callq 0x4530
cmpl $0x0, %eax
jne 0x22484
movq 0x14b71(%rip), %rdi     # 0x36fb0
leaq 0xaa98(%rip), %rsi      # 0x2cede
callq 0x43c0
movq %rax, %rdi
movq 0x60(%rsp), %rsi
callq 0x43c0
movq %rax, %rdi
leaq 0xaa8b(%rip), %rsi      # 0x2ceed
callq 0x43c0
movq %rax, %rdi
movq 0x14b1f(%rip), %rsi     # 0x36f90
callq 0x4400
movq 0x60(%rsp), %rdi
callq 0x4590
movl %eax, 0x68(%rsp)
jmp 0x22486
movl 0x5c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x5c(%rsp)
jmp 0x223e4
jmp 0x22498
leaq 0x8cce(%rip), %rax      # 0x2b16d
movq %rax, 0x48(%rsp)
cmpl $0x0, 0x68(%rsp)
jne 0x2256d
movq 0x14afa(%rip), %rdi     # 0x36fb0
leaq 0xaa39(%rip), %rsi      # 0x2cef6
callq 0x43c0
movq %rax, 0x18(%rsp)
xorl %edi, %edi
callq 0x4300
movq 0x18(%rsp), %rdi
movl %eax, %esi
callq 0x4660
movq %rax, %rdi
leaq 0xaa4a(%rip), %rsi      # 0x2cf2e
callq 0x43c0
movq %rax, %rdi
movq 0x14a9d(%rip), %rsi     # 0x36f90
callq 0x4400
movl $0x0, 0x44(%rsp)
movl 0x44(%rsp), %eax
movl %eax, 0x14(%rsp)
xorl %edi, %edi
callq 0x4300
movl %eax, %ecx
movl 0x14(%rsp), %eax
cmpl %ecx, %eax
jge 0x2256b
movl 0x44(%rsp), %edi
xorl %esi, %esi
callq 0x4140
movq %rax, 0x48(%rsp)
cmpq $0x0, 0x48(%rsp)
je 0x2254a
movl 0x44(%rsp), %esi
movq 0x48(%rsp), %rdx
leaq 0xaa0a(%rip), %rdi      # 0x2cf4b
movb $0x0, %al
callq 0x4050
jmp 0x2255c
movl 0x44(%rsp), %esi
leaq 0xaa0c(%rip), %rdi      # 0x2cf61
movb $0x0, %al
callq 0x4050
jmp 0x2255e
movl 0x44(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x44(%rsp)
jmp 0x22500
jmp 0x2256d
movq 0x28(%rsp), %rcx
movq %rcx, %rdx
addq $0x70, %rdx
addq $0x90, %rcx
xorl %eax, %eax
movl %eax, %edi
xorl %r8d, %r8d
movl %r8d, %esi
callq 0x4460
movl %eax, %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x68(%rax)
cmpl $0x0, 0x68(%rax)
ja 0x225da
movq 0x14a4a(%rip), %rdi     # 0x36ff0
leaq 0xa9cf(%rip), %rsi      # 0x2cf7c
callq 0x43c0
movq %rax, 0x8(%rsp)
callq 0x42e0
movq 0x8(%rsp), %rdi
movq %rax, %rsi
callq 0x43c0
movq %rax, %rdi
movq 0x149bd(%rip), %rsi     # 0x36f90
callq 0x4400
jmp 0x22642
callq 0x40c0
cmpq $0x0, %rax
je 0x2261e
movq 0x149c4(%rip), %rdi     # 0x36fb0
leaq 0xa9aa(%rip), %rsi      # 0x2cf9d
callq 0x43c0
movq %rax, (%rsp)
callq 0x40c0
movq (%rsp), %rdi
movq %rax, %rsi
callq 0x43c0
movq %rax, %rdi
movq 0x14979(%rip), %rsi     # 0x36f90
callq 0x4400
jmp 0x22640
movq 0x1498b(%rip), %rdi     # 0x36fb0
leaq 0xa993(%rip), %rsi      # 0x2cfbf
callq 0x43c0
movq %rax, %rdi
movq 0x14955(%rip), %rsi     # 0x36f90
callq 0x4400
jmp 0x22642
movq 0x28(%rsp), %rax
cmpl $0x0, 0x68(%rax)
jbe 0x2273e
movq 0x14958(%rip), %rdi     # 0x36fb0
leaq 0xa994(%rip), %rsi      # 0x2cff3
callq 0x43c0
movq %rax, %rdi
movq 0x28(%rsp), %rax
movl 0x90(%rax), %esi
callq 0x4660
movq %rax, %rdi
leaq 0xa984(%rip), %rsi      # 0x2d005
callq 0x43c0
movq %rax, %rdi
movq 0x28(%rsp), %rax
movzwl 0x94(%rax), %esi
callq 0x4630
movq %rax, %rdi
leaq 0xa96c(%rip), %rsi      # 0x2d010
callq 0x43c0
movq %rax, %rdi
movq 0x28(%rsp), %rax
movzbl 0x96(%rax), %esi
callq 0x4660
movq %rax, %rdi
leaq 0xa956(%rip), %rsi      # 0x2d01d
callq 0x43c0
movq %rax, %rdi
movq 0x28(%rsp), %rax
movzwl 0x98(%rax), %esi
callq 0x4630
movq %rax, %rdi
movq 0x148a6(%rip), %rsi     # 0x36f90
callq 0x4400
movq 0x28(%rsp), %rdi
movzwl 0x98(%rdi), %eax
imull $0x2df, %eax, %eax      # imm = 0x2DF
cltq
movq %rax, 0x38(%rsp)
addq $0x38, %rdi
movq 0x38(%rsp), %rsi
movb $0x0, 0x37(%rsp)
leaq 0x37(%rsp), %rdx
callq 0x113e0
movq 0x28(%rsp), %rdi
addq $0x38, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x114a0
movq %rax, %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x18(%rax)
addq $0x78, %rsp
retq
nopw %cs:(%rax,%rax)