/*
 * Sound.c
 * By: Odis
 */
#include "main.h"

#include <string.h>

/* globals...*/
int volume;
bool stopped;
bool loop;

LPDIRECTSOUND ds = NULL;
LPDIRECTSOUNDBUFFER song = NULL;

/* un alloc a buffer */
void delete_wave( LPDIRECTSOUNDBUFFER buf )
{
   if ( buf == NULL )
    return;
    
   buf->lpVtbl->Release(buf);
}

/* intialize the buffer that the sound will reside in */
LPDIRECTSOUNDBUFFER init_buffer( DWORD bytes )
{
   HRESULT hr;
   WAVEFORMATEX wfx;
   ZeroMemory( &wfx, sizeof(WAVEFORMATEX));
   
   wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM;
   wfx.nChannels  = 1;
   wfx.nSamplesPerSec = 22050;
   wfx.wBitsPerSample = 8;
   wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
   wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);
   
   DSBUFFERDESC dsbd;
   ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
   
   dsbd.dwSize = sizeof(DSBUFFERDESC);
   dsbd.dwFlags = DSBCAPS_CTRLVOLUME;
   dsbd.dwBufferBytes = bytes;
/*       dsbd.guid3DAlgorithm = GUID_NULL;*/
   dsbd.lpwfxFormat = &wfx;
   
   LPDIRECTSOUNDBUFFER buffer = NULL;

   hr = ds->lpVtbl->CreateSoundBuffer(ds, &dsbd, &buffer, NULL );
   
   buffer->lpVtbl->SetFormat(buffer, &wfx);
   
   if FAILED(hr)
    return NULL;
    
   return buffer;
}

/* load an entire wave file */
LPDIRECTSOUNDBUFFER load_wave_from_file( LPSTR file, DWORD bytes )
{
   if ( !file || file[0] == '\0' )
     return NULL;

   HMMIO wve = NULL;
   
   wve = mmioOpen( file, NULL, MMIO_READ );
   
   if ( wve == NULL )
   {
    mmioClose( wve, 0 );
    return NULL;
   }
   
   VOID* locked = NULL; /* pointer to locked buffer memory */
   DWORD lsize  = 0;    /* size of the locked buffer */
   LPDIRECTSOUNDBUFFER buf = init_buffer(bytes);
   
   if ( buf == NULL )
   {
    mmioClose( wve, 0);
    return NULL;
   }
   
   HRESULT hr;
   hr = buf->lpVtbl->Lock(buf, 0, bytes, &locked, &lsize, NULL, NULL, DSBLOCK_ENTIREBUFFER);
   
   if FAILED(hr)
   {
    delete_wave(buf);
    mmioClose( wve, 0 );
    return NULL;
   }
    
   /* start from the beginning */
   mmioSeek( wve, 0, SEEK_SET);
   
   int rt;
   rt = mmioRead( wve, (HPSTR)locked, (LONG)bytes );
   
   if ( rt == 0 )
    lsize = bytes;
   else if ( rt == -1 )
   {
    delete_wave(buf);
    mmioClose( wve, 0 );
    return NULL;
   }
   
   buf->lpVtbl->Unlock(buf, locked, lsize, NULL, 0 );
   
   /* unalloc this, we don't need it anymore */
   mmioClose( wve, 0 );
   
   return buf;
}

/* play the buffer */
void play_wave( LPDIRECTSOUNDBUFFER buf, bool loop )
{
  if ( buf == NULL )
   return;
   

  if ( loop == TRUE )
    buf->lpVtbl->Play(buf,0,0,DSBPLAY_LOOPING);
  else
    buf->lpVtbl->Play(buf,0,0,0);
    
  stopped = FALSE;
}

/* stop the said audio */
void stop_wave( LPDIRECTSOUNDBUFFER buf )
{
   if ( buf == NULL )
    return;
    
   buf->lpVtbl->Stop(buf);
   
   stopped = TRUE;
}

/* set the volume */
void set_volume( LPDIRECTSOUNDBUFFER buf, LONG amount )
{
  if ( buf == NULL )
    return;
  
  if ( amount > DSBVOLUME_MAX )
   amount = DSBVOLUME_MAX;
  else if ( amount < DSBVOLUME_MIN )
   amount = DSBVOLUME_MIN;
  
  volume = amount;
    
  buf->lpVtbl->SetVolume(buf,amount);
}

/* initialize directsound stuff */
bool init_dx( void )
{
 bool ok = FALSE;
 HWND hwnd = (HWND)GetForegroundWindow();

  if ( DirectSoundCreate( 0, &ds, 0 ) == DS_OK )
   if ( ds->lpVtbl->SetCooperativeLevel(ds,hwnd,DSSCL_PRIORITY) == DS_OK )
     ok = TRUE;
    
  if ( ok == TRUE )
  {
//    song = load_wave_from_file( (LPSTR)SONG_FILE, (DWORD)SONG_BYTES );

    loop = FALSE;
    stopped = FALSE;
    volume = -200;

    wave = mmioOpen( SONG_FILE, NULL, MMIO_READ ); /* open */
    handle_dx(TRUE); /* get the song some data */
    return TRUE;

   /*song = load_wave_from_resource( songmem, (DWORD)SONG_BYTES );*/
  }


  return FALSE;
}

/* load a wave file from resource - the whole thing*/
LPDIRECTSOUNDBUFFER load_wave_from_resource( HGLOBAL mem, DWORD bytes )
{
   if ( mem == NULL )
     return NULL;

   VOID* locked = NULL; /* pointer to locked buffer memory */
   DWORD lsize  = 0;    /* size of the locked buffer */
   LPDIRECTSOUNDBUFFER buf = init_buffer(bytes);

   if ( buf == NULL )
    return NULL;

   HRESULT hr;
   hr = buf->lpVtbl->Lock(buf, 0, bytes, &locked, &lsize, NULL, NULL, DSBLOCK_ENTIREBUFFER);

   if FAILED(hr)
   {
    delete_wave(buf);
    return NULL;
   }

   BYTE *ptr;
   ptr = mem;
   
   memcpy(locked,&ptr[44],lsize);

   buf->lpVtbl->Unlock(buf, locked, lsize, NULL, 0 );

   return buf;
}

/* update anything that needs it, specifically streaming audio */
void handle_dx( bool restart )
{
   if ( stopped == TRUE )
    return;

   static unsigned int seek_spot = 0;
   LPDIRECTSOUNDBUFFER old = song; /* keep track of the old for disposal */
   DWORD bytes = BUFFER_SIZE;

   if ( restart == TRUE )
    seek_spot = 0;

   /* check seek for looping */
   if ( seek_spot+bytes > SONG_BYTES )
    bytes = SONG_BYTES-seek_spot; /* set bytes to the remaining few that are left */

   /* create the new one using bytes so we dont alloc more then we need */
   LPDIRECTSOUNDBUFFER d = init_buffer(bytes); /* new buf, about 2 seconds */
   
   

   if ( wave == NULL )
   {
     mmioClose( wave, 0 );
     return;
   }

   VOID* locked = NULL; /* pointer to locked buffer memory */
   DWORD lsize  = 0;    /* size of the locked buffer */

   if ( d == NULL )
   {
    mmioClose( wave, 0);
    return;
   }

   HRESULT hr;
   hr = d->lpVtbl->Lock(d, 0, bytes, &locked, &lsize, NULL, NULL, DSBLOCK_ENTIREBUFFER);

   if FAILED(hr)
   {
    delete_wave(d);
    mmioClose( wave, 0 );
    return;
   }

   /* start read in relation to the beginning */
   mmioSeek( wave, seek_spot, SEEK_SET);

   int rt = mmioRead( wave, (HPSTR)locked, (LONG)bytes );

   if ( rt == 0 )
    lsize = bytes;
   else if ( rt == -1 )
   {
    delete_wave(d);
    mmioClose( wave, 0 );
    return;
   }

   d->lpVtbl->Unlock(d, locked, lsize, NULL, 0 );

   seek_spot += bytes;

   song = d; /* song pointer is now pointing to the new bufer */

   set_volume( song, volume );
   play_wave(song,FALSE);
   
   delete_wave(old); /* get rid of the old buffer */
   
   ///////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\
   
   if ( (bytes != BUFFER_SIZE) && (loop == TRUE)) /* we hit the end, loop bitch */
    seek_spot = 0;
   else if ( (bytes != BUFFER_SIZE) )
   {
    stopped = TRUE;
    printf( "\n\nDone playing, restart to hear again. Looping is off...\n\n" );
   }
}