// Emacs style mode select   -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id
//
//  Copyright (C) 2004 Carlos Guariglia
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 2
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
//  02111-1307, USA.
//
//
// DESCRIPTION:  Platform-independent sound code
//
//-----------------------------------------------------------------------------

#include "doomstat.h"
#include "sounds.h"
#include "r_main.h"
#include "m_random.h"
#include "w_wad.h"
//#include "mus180\muslib.h"

#define S_CLIPPING_DIST (1200<<FRACBITS)
#define S_CLOSE_DIST (200<<FRACBITS)
#define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)

boolean nosfxparm, nomusicparm;

typedef struct
{
  sfxinfo_t *sfxinfo;
  const mobj_t *origin;
  int handle;
} channel_t;

static channel_t *channels;

int snd_SfxVolume = 15;
int snd_MusicVolume = 15;
static boolean mus_paused;
static musicinfo_t *mus_playing;

static void S_StopChannel(int cnum)
{
  if (channels[cnum].sfxinfo)
    {
      I_StopSound(channels[cnum].handle);
      channels[cnum].sfxinfo = 0;
    }
}

static int
S_AdjustSoundParams(const mobj_t *listener,const mobj_t *source,int *vol)
{
  fixed_t adx, ady, dist;

  adx = abs((listener->x >> FRACBITS) - (source->x >> FRACBITS));
  ady = abs((listener->y >> FRACBITS) - (source->y >> FRACBITS));

  if (ady > adx)
    dist = adx, adx = ady, ady = dist;

  dist = adx ? FixedDiv(adx, finesine[(tantoangle[FixedDiv(ady,adx) >> DBITS]
				       + ANG90) >> ANGLETOFINESHIFT]) : 0;

  if (!dist)
    {
      *vol = snd_SfxVolume;
      return *vol > 0;
    }

  if (dist > S_CLIPPING_DIST >> FRACBITS)
    return 0;

  *vol = dist < S_CLOSE_DIST >> FRACBITS ? snd_SfxVolume :
    snd_SfxVolume * ((S_CLIPPING_DIST>>FRACBITS)-dist) /
    S_ATTENUATOR;

  return *vol > 0;
}

static int S_getChannel(const void *origin, sfxinfo_t *sfxinfo)
{
  int cnum;
  channel_t *c;

  for (cnum=0; cnum<8 && channels[cnum].sfxinfo; cnum++)
    if (origin && channels[cnum].origin == origin &&
        channels[cnum].sfxinfo->singularity == sfxinfo->singularity)
      {
        S_StopChannel(cnum);
        break;
      }

  if (cnum == 8)
    {
      for (cnum=0 ; cnum<8 ; cnum++)
        if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
          break;
      if (cnum == 8)
        return -1;
      else
        S_StopChannel(cnum);
    }

  c = &channels[cnum];
  c->sfxinfo = sfxinfo;
  c->origin = origin;
  return cnum;
}

void S_StartSound(const mobj_t *origin, int sfx_id)
{
  int priority=64, cnum;
  int volume = snd_SfxVolume;
  sfxinfo_t *sfx;

  if (nosfxparm)
    return;

  sfx = &S_sfx[sfx_id];

  if (sfx->link)
    {
      priority = sfx->priority;
      volume += sfx->volume;

      if (volume < 1)
        return;

      if (volume >= snd_SfxVolume)
        volume = snd_SfxVolume;
    }
  if (origin && origin != players[displayplayer].mo)
  if (!S_AdjustSoundParams(players[displayplayer].mo, origin, &volume))
  return;

  for (cnum=0 ; cnum<8 ; cnum++)
    if (channels[cnum].sfxinfo &&
        channels[cnum].sfxinfo->singularity == sfx->singularity &&
	channels[cnum].origin == origin)
      {
        S_StopChannel(cnum);
        break;
      }

  cnum = S_getChannel(origin, sfx);

  if (cnum<0)
    return;

  channels[cnum].handle = I_StartSound(sfx_id, volume, 128, 128, priority);
}

void S_StopSound(const mobj_t *origin)
{
  int cnum;

  if (nosfxparm)
    return;

  for (cnum=0 ; cnum<8 ; cnum++)
    if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
      {
        S_StopChannel(cnum);
        break;
      }
}

void S_PauseSound(void)
{
  if (mus_playing && !mus_paused)
    { mus_paused = true;
      //MLpause(handlemus);
    }
}

void S_ResumeSound(void)
{
  if (mus_playing && mus_paused)
    { mus_paused = false;
      //MLunpause(handlemus);
    }
}

void S_UpdateSounds(const mobj_t *listener)
{
  int cnum;

  if (nosfxparm)
    return;

  for (cnum=0 ; cnum<8 ; cnum++)
    {
      channel_t *c = &channels[cnum];
      sfxinfo_t *sfx = c->sfxinfo;
      if (sfx)
        {
         int volume = snd_SfxVolume;

              if (sfx->link)
                {
                  volume += sfx->volume;
                  if (volume < 1)
                    {
                      S_StopChannel(cnum);
                      continue;
                    }
                  else
                    if (volume > snd_SfxVolume)
                      volume = snd_SfxVolume;
                }

              if (c->origin && listener != c->origin)
                if (!S_AdjustSoundParams(listener, c->origin, &volume))
                  S_StopChannel(cnum);
        }
    }
}

void S_SetMusicVolume(int volume)
{
  if (nomusicparm)
    return;
  //MLsetVolume(handlemus, volume*34);
  snd_MusicVolume = volume;
}

void S_SetSfxVolume(int volume)
{
  if (nosfxparm)
    return;

  snd_SfxVolume = volume;
}

void S_StopMusic(void)
{
  if (!mus_playing)
    return;
  //MLstop(handlemus);
  //MLfreeHandle(handlemus);
  mus_playing = 0;
}

void S_ChangeMusic(int musicnum, int looping)
{
  musicinfo_t *music;
  //int banknum;

  if (nomusicparm)
    return;

  if (musicnum <= mus_None || musicnum >= NUMMUSIC)
    I_Error("Bad music number %d", musicnum);

  music = &S_music[musicnum];

  if (mus_playing == music)
    return;

  S_StopMusic();

  if (!music->lumpnum)
    {
      char namebuf[9];
      sprintf(namebuf, "d_%s", music->name);
      music->lumpnum = W_GetNumForName(namebuf);
    }
  //banknum = W_GetNumForName("GENMIDI");
  //musposition = lumpinfo[music->lumpnum].position;
  //fdmus = lumpinfo[music->lumpnum].handle;
  //bankposition = lumpinfo[banknum].position;
  //fdbank = lumpinfo[banknum].handle;
  //I_PlayMus(looping);
  //MLsetVolume(handlemus, snd_MusicVolume*34);
  mus_playing = music;
}

void S_StartMusic(int m_id)
{
  S_ChangeMusic(m_id, false);
}

void S_Start(void)
{
  int cnum,mnum;

  if (!nosfxparm)
    for (cnum=0 ; cnum<8 ; cnum++)
      if (channels[cnum].sfxinfo)
        S_StopChannel(cnum);

  if (nomusicparm)
    return;

  mus_paused = 0;

    if (gamemode == commercial)
      mnum = mus_runnin + gamemap - 1;
    else
      {
        static const int spmus[] =
        {
          mus_e3m4,
          mus_e3m2,
          mus_e3m3,
          mus_e1m5,
          mus_e2m7,
          mus_e2m4,
          mus_e2m6,
          mus_e2m5,
          mus_e1m9
        };

        if (gameepisode < 4)
          mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
        else
          mnum = spmus[gamemap-1];
      }
  S_ChangeMusic(mnum, true);
}

void S_Init(int sfxVolume, int musicVolume)
{
  if (!nosfxparm)
    {
      printf("S_Init: default sfx volume %d\n", sfxVolume);
      S_SetSfxVolume(sfxVolume);
      channels = (channel_t*)calloc(8, sizeof(channel_t));
    }
  S_SetMusicVolume(musicVolume);
  mus_paused = 0;
  //install_int_ex(MLplayerInterrupt,8523);
}
