/*
 * Emulation code rewritten by viznut. Still needs some cleanups etc.
 *
 * This file is part of VICE, the Versatile Commodore Emulator.
 * See README for copyright notice.
 *
 *  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.
 *
 */

unsigned char noiseloop[1024] = {
  7, 30, 30, 28, 28, 62, 60, 56,120,248,124, 30, 31,143,  7,  7,193,192,224,
241,224,240,227,225,192,224,120,126, 60, 56,224,225,195,195,135,199,  7, 30,
 28, 31, 14, 14, 30, 14, 15, 15,195,195,241,225,227,193,227,195,195,252, 60,
 30, 15,131,195,193,193,195,195,199,135,135,199, 15, 14, 60,124,120, 60, 60,
 60, 56, 62, 28,124, 30, 60, 15, 14, 62,120,240,240,224,225,241,193,195,199,
195,225,241,224,225,240,241,227,192,240,224,248,112,227,135,135,192,240,224,
241,225,225,199,131,135,131,143,135,135,199,131,195,131,195,241,225,195,199,
129,207,135,  3,135,199,199,135,131,225,195,  7,195,135,135,  7,135,195,135,
131,225,195,199,195,135,135,143, 15,135,135, 15,207, 31,135,142, 14,  7,129,
195,227,193,224,240,224,227,131,135,  7,135,142, 30, 15,  7,135,143, 31,  7,
135,193,240,225,225,227,199, 15,  3,143,135, 14, 30, 30, 15,135,135, 15,135,
 31, 15,195,195,240,248,240,112,241,240,240,225,240,224,120,124,120,124,112,
113,225,225,195,195,199,135, 28, 60, 60, 28, 60,124, 30, 30, 30, 28, 60,120,
248,248,225,195,135, 30, 30, 60, 62, 15, 15,135, 31,142, 15, 15,142, 30, 30,
 30, 30, 15, 15,143,135,135,195,131,193,225,195,193,195,199,143, 15, 15, 15,
 15,131,199,195,193,225,224,248, 62, 60, 60, 60, 60, 60,120, 62, 30, 30, 30,
 15, 15, 15, 30, 14, 30, 30, 15, 15,135, 31,135,135, 28, 62, 31, 15, 15,142,
 62, 14, 62, 30, 28, 60,124,252, 56,120,120, 56,120,112,248,124, 30, 60, 60,
 48,241,240,112,112,224,248,240,248,120,120,113,225,240,227,193,240,113,227,
199,135,142, 62, 14, 30, 62, 15,  7,135, 12, 62, 15,135, 15, 30, 60, 60, 56,
120,241,231,195,195,199,142, 60, 56,240,224,126, 30, 62, 14, 15, 15, 15,  3,
195,195,199,135, 31, 14, 30, 28, 60, 60, 15,  7,  7,199,199,135,135,143, 15,
192,240,248, 96,240,240,225,227,227,195,195,195,135, 15,135,142, 30, 30, 63,
 30, 14, 28, 60,126, 30, 60, 56,120,120,120, 56,120, 60,225,227,143, 31, 28,
120,112,126, 15,135,  7,195,199, 15, 30, 60, 14, 15, 14, 30,  3,240,240,241,
227,193,199,192,225,225,225,225,224,112,225,240,120,112,227,199, 15,193,225,
227,195,192,240,252, 28, 60,112,248,112,248,120, 60,112,240,120,112,124,124,
 60, 56, 30, 62, 60,126,  7,131,199,193,193,225,195,195,195,225,225,240,120,
124, 62, 15, 31,  7,143, 15,131,135,193,227,227,195,195,225,240,248,240, 60,
124, 60, 15,142, 14, 31, 31, 14, 60, 56,120,112,112,240,240,248,112,112,120,
 56, 60,112,224,240,120,241,240,120, 62, 60, 15,  7, 14, 62, 30, 63, 30, 14,
 15,135,135,  7, 15,  7,199,143, 15,135, 30, 30, 31, 30, 30, 60, 30, 28, 62,
 15,  3,195,129,224,240,252, 56, 60, 62, 14, 30, 28,124, 30, 31, 14, 62, 28,
120,120,124, 30, 62, 30, 60, 31, 15, 31, 15, 15,143, 28, 60,120,248,240,248,
112,240,120,120, 60, 60,120, 60, 31, 15,  7,134, 28, 30, 28, 30, 30, 31,  3,
195,199,142, 60, 60, 28, 24,240,225,195,225,193,225,227,195,195,227,195,131,
135,131,135, 15,  7,  7,225,225,224,124,120, 56,120,120, 60, 31, 15,143, 14,
  7, 15,  7,131,195,195,129,240,248,241,224,227,199, 28, 62, 30, 15, 15,195,
240,240,227,131,195,199,  7, 15, 15, 15, 15, 15,  7,135, 15, 15, 14, 15, 15,
 30, 15, 15,135,135,135,143,199,199,131,131,195,199,143,135,  7,195,142, 30,
 56, 62, 60, 56,124, 31, 28, 56, 60,120,124, 30, 28, 60, 63, 30, 14, 62, 28,
 60, 31, 15,  7,195,227,131,135,129,193,227,207, 14, 15, 30, 62, 30, 31, 15,
143,195,135, 14,  3,240,240,112,224,225,225,199,142, 15, 15, 30, 14, 30, 31,
 28,120,240,241,241,224,241,225,225,224,224,241,193,240,113,225,195,131,199,
131,225,225,248,112,240,240,240,240,240,112,248,112,112, 97,224,240,225,224,
120,113,224,240,248, 56, 30, 28, 56,112,248, 96,120, 56, 60, 63, 31, 15, 31,
 15, 31,135,135,131,135,131,225,225,240,120,241,240,112, 56, 56,112,224,227,
192,224,248,120,120,248, 56,241,225,225,195,135,135, 14, 30, 31, 14, 14, 15,
 15,135,195,135,  7,131,192,240, 56, 60, 60, 56,240,252, 62, 30, 28, 28, 56,
112,240,241,224,240,224,224,241,227,224,225,240,240,120,124,120, 60,120,120,
 56,120,120,120,120,112,227,131,131,224,195,193,225,193,193,193,227,195,199,
 30, 14, 31, 30, 30, 15, 15, 14, 14, 14,  7,131,135,135, 14,  7,143, 15, 15,
 15, 14, 28,112,225,224,113,193,131,131,135, 15, 30, 24,120,120,124, 62, 28,
 56,240,225,224,120,112, 56, 60, 62, 30, 60, 30, 28,112, 60, 56, 63
};

static float voltagefunction[] =
{
0.0000, 0.0045, 0.0090, 0.0225, 0.0279, 0.0344, 0.0403, 0.0459, 0.0489,
0.0537, 0.0584, 0.0632, 0.0678, 0.0715, 0.0759, 0.0973, 0.1003, 0.1032,
0.1062, 0.1091, 0.1121, 0.1150, 0.1180, 0.1209, 0.1239, 0.1296, 0.1354,
0.1411, 0.1469, 0.1526, 0.1583, 0.1585, 0.1586, 0.1629, 0.1672, 0.1716,
0.1759, 0.1802, 0.1845, 0.1888, 0.1931, 0.2017, 0.2102, 0.2188, 0.2273,
0.2359, 0.2383, 0.2407, 0.2432, 0.2456, 0.2480, 0.2504, 0.2529, 0.2553,
0.2577, 0.2601, 0.2626, 0.2718, 0.2810, 0.2903, 0.2995, 0.3001, 0.3006,
0.3012, 0.3018, 0.3024, 0.3029, 0.3035, 0.3041, 0.3047, 0.3053, 0.3058,
0.3064, 0.3292, 0.3520, 0.3748, 0.3749, 0.3750, 0.3751, 0.3752, 0.3753,
0.3754, 0.3756, 0.3757, 0.3758, 0.3759, 0.3760, 0.3761, 0.3762, 0.4002,
0.4242, 0.4245, 0.4249, 0.4252, 0.4256, 0.4260, 0.4263, 0.4267, 0.4270,
0.4274, 0.4278, 0.4281, 0.4285, 0.4288, 0.4292, 0.5165, 0.5184, 0.5203,
0.5221, 0.5240, 0.5258, 0.5277, 0.5295, 0.5314, 0.5332, 0.5351, 0.5369,
0.5388, 0.5406, 0.5425, 0.5444, 0.5506, 0.5568, 0.5631, 0.5693, 0.5755,
0.5817, 0.5880, 0.5942, 0.6004, 0.6067, 0.6129, 0.6191, 0.6231, 0.6270,
0.6310, 0.6340, 0.6370, 0.6399, 0.6429, 0.6459, 0.6489, 0.6519, 0.6548,
0.6578, 0.6608, 0.6638, 0.6668, 0.6697, 0.6727, 0.6757, 0.6779, 0.6800,
0.6822, 0.6844, 0.6865, 0.6887, 0.6909, 0.6930, 0.6952, 0.6974, 0.6995,
0.7017, 0.7039, 0.7060, 0.7082, 0.7097, 0.7112, 0.7127, 0.7142, 0.7157,
0.7172, 0.7187, 0.7202, 0.7217, 0.7254, 0.7290, 0.7327, 0.7364, 0.7400,
0.7437, 0.7462, 0.7487, 0.7512, 0.7538, 0.7563, 0.7588, 0.7613, 0.7638,
0.7663, 0.7688, 0.7713, 0.7739, 0.7764, 0.7789, 0.7814, 0.7830, 0.7847,
0.7863, 0.7880, 0.7896, 0.7913, 0.7929, 0.7946, 0.7962, 0.7979, 0.7995,
0.8012, 0.8028, 0.8045, 0.8061, 0.8088, 0.8114, 0.8141, 0.8167, 0.8194,
0.8220, 0.8247, 0.8273, 0.8300, 0.8326, 0.8353, 0.8379, 0.8406, 0.8432,
0.8459, 0.8462, 0.8464, 0.8467, 0.8469, 0.8472, 0.8474, 0.8477, 0.8480,
0.8482, 0.8485, 0.8487, 0.8490, 0.8492, 0.8495, 0.8498, 0.8500, 0.8503,
0.8505, 0.8508, 0.8511, 0.8513, 0.8516, 0.8518, 0.8521, 0.8523, 0.8526,
0.8529, 0.8531, 0.8534, 0.8536, 0.8539, 0.8541, 0.8544, 0.8547, 0.8549,
0.8552, 0.8554, 0.8557, 0.8559, 0.8562, 0.8565, 0.8567, 0.8570, 0.8572,
0.8575, 0.8578, 0.8580, 0.8583, 0.8585, 0.8588, 0.8590, 0.8593, 0.8596,
0.8598, 0.8601, 0.8603, 0.8606, 0.8608, 0.8611, 0.8614, 0.8616, 0.8619,
0.8621, 0.8624, 0.8626, 0.8629, 0.8632, 0.8634, 0.8637, 0.8639, 0.8642,
0.8644, 0.8647, 0.8650, 0.8652, 0.8655, 0.8657, 0.8660, 0.8663, 0.8665,
0.8668, 0.8670, 0.8673, 0.8675, 0.8678, 0.8681, 0.8683, 0.8686, 0.8688,
0.8691, 0.8693, 0.8696, 0.8699, 0.8701, 0.8704, 0.8706, 0.8709, 0.8711,
0.8714, 0.8717, 0.8719, 0.8722, 0.8724, 0.8727, 0.8730, 0.8732, 0.8735,
0.8737, 0.8740, 0.8742, 0.8745, 0.8748, 0.8750, 0.8753, 0.8755, 0.8758,
0.8760, 0.8763, 0.8766, 0.8768, 0.8771, 0.8773, 0.8776, 0.8778, 0.8781,
0.8784, 0.8786, 0.8789, 0.8791, 0.8794, 0.8796, 0.8799, 0.8802, 0.8804,
0.8807, 0.8809, 0.8812, 0.8815, 0.8817, 0.8820, 0.8822, 0.8825, 0.8827,
0.8830, 0.8833, 0.8835, 0.8838, 0.8840, 0.8843, 0.8845, 0.8848, 0.8851,
0.8853, 0.8856, 0.8858, 0.8861, 0.8863, 0.8866, 0.8869, 0.8871, 0.8874,
0.8876, 0.8879, 0.8881, 0.8884, 0.8887, 0.8889, 0.8892, 0.8894, 0.8897,
0.8900, 0.8902, 0.8905, 0.8907, 0.8910, 0.8912, 0.8915, 0.8918, 0.8920,
0.8923, 0.8925, 0.8928, 0.8930, 0.8933, 0.8936, 0.8938, 0.8941, 0.8943,
0.8946, 0.8948, 0.8951, 0.8954, 0.8956, 0.8959, 0.8961, 0.8964, 0.8967,
0.8969, 0.8972, 0.8974, 0.8977, 0.8979, 0.8982, 0.8985, 0.8987, 0.8990,
0.8992, 0.8995, 0.8997, 0.9000
};

#include "vice.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "lib.h"
#include "maincpu.h"
#include "sid.h"
#include "sid-resources.h"
#include "sound.h"
#include "types.h"
#include "vic20sound.h"
#include "vic20.h"

static BYTE vic20_sound_data[16];

/* dummy function for now */
int machine_sid2_check_range(unsigned int sid2_adr)
{
    return 0;
}

struct sound_vic20_s
{
  unsigned char div;
  struct
  {
    unsigned char out;
    unsigned char reg;
    unsigned char shift;
    signed short ctr;
  } ch[4];
  unsigned short noisectr;
  unsigned char volume;
  int cyclecount;

  int accum;
  int accum_cycles;
  
  int cycles_per_sample;
  int leftover_cycles;
  int speed;
  
  float highpassbuf;
  float highpassbeta;
  float lowpassbuf;
  float lowpassbeta;
};
typedef struct sound_vic20_s sound_vic20_t;

static struct sound_vic20_s snd;

void vic_sound_clock(int cycles);

static int vic_sound_machine_calculate_samples(sound_t *psid, SWORD *pbuf, int nr,
                                    int interleave, int *delta_t)
{
    int s=0;
    
    while (s < nr && *delta_t >= snd.cycles_per_sample - snd.leftover_cycles)
    {
        float o;
        SWORD vicbuf;
        int z;

        vic_sound_clock(snd.cycles_per_sample - snd.leftover_cycles);

        o = voltagefunction[(((snd.accum*7)/snd.accum_cycles) + 1) * snd.volume];
        o = snd.lowpassbuf*snd.lowpassbeta + o*(1.0-snd.lowpassbeta); // 0.75 + o*0.25;
        snd.lowpassbuf=o;
        o -= snd.highpassbuf;
        snd.highpassbuf += o * snd.highpassbeta;
        o *= 0x80*256; // todo precalc into tab
        if(o<-32768) vicbuf = -32768; else
        if(o >32767) vicbuf = 32767; else
                     vicbuf = o;

        pbuf[s*interleave] = vicbuf;
        s++;
        snd.accum = 0;
        snd.accum_cycles = 0;
        *delta_t -= snd.cycles_per_sample - snd.leftover_cycles;
        snd.leftover_cycles = 0;
    }
    if(*delta_t > 0)
    {
        snd.leftover_cycles += *delta_t;
        vic_sound_clock(*delta_t);
        *delta_t = 0;
    }
    return s;
}

void vic_sound_reset(void)
{
    WORD i;

    sound_reset();
    for (i = 10; i < 15; i++)
        vic_sound_store(i, 0);
}

void vic_sound_store(WORD addr, BYTE value)
{
    addr &= 0x0f;
    vic20_sound_data[addr] = value;
    sound_store((WORD)(addr+0x20), value, 0);
}


void vic_sound_clock(int cycles)
{
  int i,j;
  if(cycles<=0) return;
  for(j=0;j<3;j++)
  {
    int chspeed="\4\3\2"[j];
    if(snd.ch[j].ctr > cycles)
    {
       snd.accum += snd.ch[j].out * cycles;
       snd.ch[j].ctr -= cycles;
    }
    else
    for(i=cycles;i;i--)
    {
      snd.ch[j].ctr--;
      if(snd.ch[j].ctr<=0)
      {
        int a = (~snd.ch[j].reg)&127;
        a=a?a:128;
        snd.ch[j].ctr += a << chspeed;
        if(snd.ch[j].reg&128)
        {
          unsigned char shift = snd.ch[j].shift;
          shift = ((shift<<1) | ((shift&128)>>7))^1;
          snd.ch[j].shift = shift;
          snd.ch[j].out = shift&1;
        } else
        {
          snd.ch[j].shift <<= 1;
          snd.ch[j].out = 0;
        }
      }
      snd.accum += snd.ch[j].out;
    }
  }

  if(snd.ch[3].ctr > cycles)
  {
    snd.accum += snd.ch[3].out * cycles;
    snd.ch[3].ctr -= cycles;
  }
  else
  for(i=cycles;i;i--)
  {
    snd.ch[3].ctr--;
    if(snd.ch[3].ctr<=0)
    {
        int a = (~snd.ch[3].reg)&127;
        a=a?a:128;
        snd.ch[j].ctr += a << 4;
        if(snd.ch[3].reg&128)
        {
          snd.ch[3].out = (noiseloop[(snd.noisectr>>3)&1023]>>(snd.noisectr&7))&1;
        } else
        {
          snd.ch[3].out = 0;
        }
        snd.noisectr++;
    }
    snd.accum += snd.ch[3].out;
  }
  
  snd.accum_cycles += cycles;
}

static void vic_sound_machine_store(sound_t *psid, WORD addr, BYTE value)
{
    switch (addr) {
      case 0xA:
        snd.ch[0].reg = value;
        break;
      case 0xB:
        snd.ch[1].reg = value;
        break;
      case 0xC:
        snd.ch[2].reg = value;
        break;
      case 0xD:
        snd.ch[3].reg = value;
        break;
      case 0xE:
        snd.volume = value & 0x0f;
        break;
    }
}

static int vic_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec)
{
    DWORD i;

    memset((unsigned char*)&snd, 0, sizeof(snd));

    snd.cycles_per_sample = cycles_per_sec / speed;

    snd.speed = speed;

    snd.lowpassbeta =  1.0 - snd.cycles_per_sample / ( snd.cycles_per_sample + 62.0 );
    snd.highpassbeta = 1.0 - snd.cycles_per_sample / ( snd.cycles_per_sample + 0.04 );

    for (i = 0; i < 16; i++)
        vic_sound_machine_store(psid, (WORD)i, vic20_sound_data[i]);

    return 1;
}

static BYTE vic_sound_machine_read(sound_t *psid, WORD addr)
{
  return 0;
}

sound_t *sound_machine_open(int chipno)
{
    return sid_sound_machine_open(chipno);
}

int sound_machine_init(sound_t *psid, int speed, int cycles_per_sec)
{
    vic_sound_machine_init(psid, speed, cycles_per_sec);

    if (!sidcart_clock && cycles_per_sec==VIC20_PAL_CYCLES_PER_SEC)
    {
        return sid_sound_machine_init(psid, (int)(speed*1.125), cycles_per_sec);
    }
    else
    {
        return sid_sound_machine_init(psid, speed, cycles_per_sec);
    }
}

void sound_machine_close(sound_t *psid)
{
    sid_sound_machine_close(psid);
}

/* for read/store 0x00 <= addr <= 0x1f is the sid
 *                0x20 <= addr <= 0x3f is the vic
 *
 * future sound devices will be able to use 0x40 and up
 */

BYTE sound_machine_read(sound_t *psid, WORD addr)
{
    if (addr>=0x20 && addr<=0x3f)
        return vic_sound_machine_read(psid, (WORD)(addr-0x20));
    else
        return sid_sound_machine_read(psid, addr);
}

void sound_machine_store(sound_t *psid, WORD addr, BYTE byte)
{
    if (addr>=0x20 && addr<=0x3f)
        vic_sound_machine_store(psid, (WORD)(addr-0x20), byte);
    else
        sid_sound_machine_store(psid, addr, byte);
}

void sound_machine_reset(sound_t *psid, CLOCK cpu_clk)
{
    sid_sound_machine_reset(psid, cpu_clk);
}

int sound_machine_calculate_samples(sound_t *psid, SWORD *pbuf, int nr,
                                    int interleave, int *delta_t)
{
    int temp;

/* TODO reinclude sidcart support */
/* sid_sound_machine_calculate_samples(psid, pbuf, nr, interleave, delta_t); */
    temp=vic_sound_machine_calculate_samples(psid, pbuf, nr, interleave, delta_t);
    return temp;
}

void sound_machine_prevent_clk_overflow(sound_t *psid, CLOCK sub)
{
    sid_sound_machine_prevent_clk_overflow(psid, sub);
}

char *sound_machine_dump_state(sound_t *psid)
{
    return sid_sound_machine_dump_state(psid);
}

int sound_machine_cycle_based(void)
{
    return 1;
}

int sound_machine_channels(void)
{
    return sid_sound_machine_channels();
}

void sound_machine_enable(int enable)
{
    sid_sound_machine_enable(enable);
}

