#include <stdlib.h>
#include "ibm.h"
#include "device.h"
#include "io.h"
#include "sound.h"

#include "sound_resid.h"
#include "sound_ssi2001.h"

typedef struct ssi2001_t {
        void *psid;
        int16_t buffer[MAXSOUNDBUFLEN * 2];
        int pos;
} ssi2001_t;

static void ssi2001_update(ssi2001_t *ssi2001) {
        if (ssi2001->pos >= sound_pos_global)
                return;

        sid_fillbuf(&ssi2001->buffer[ssi2001->pos], sound_pos_global - ssi2001->pos, ssi2001->psid);
        ssi2001->pos = sound_pos_global;
}

static void ssi2001_get_buffer(int32_t *buffer, int len, void *p) {
        ssi2001_t *ssi2001 = (ssi2001_t *)p;
        int c;

        ssi2001_update(ssi2001);

        for (c = 0; c < len * 2; c++)
                buffer[c] += ssi2001->buffer[c >> 1] / 2;

        ssi2001->pos = 0;
}

static uint8_t ssi2001_read(uint16_t addr, void *p) {
        ssi2001_t *ssi2001 = (ssi2001_t *)p;

        ssi2001_update(ssi2001);

        return sid_read(addr, p);
}

static void ssi2001_write(uint16_t addr, uint8_t val, void *p) {
        ssi2001_t *ssi2001 = (ssi2001_t *)p;

        ssi2001_update(ssi2001);
        sid_write(addr, val, p);
}

void *ssi2001_init() {
        ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t));
        memset(ssi2001, 0, sizeof(ssi2001_t));

        pclog("ssi2001_init\n");
        ssi2001->psid = sid_init();
        sid_reset(ssi2001->psid);
        io_sethandler(0x0280, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001);
        sound_add_handler(ssi2001_get_buffer, ssi2001);
        return ssi2001;
}

void ssi2001_close(void *p) {
        ssi2001_t *ssi2001 = (ssi2001_t *)p;

        sid_close(ssi2001->psid);

        free(ssi2001);
}

device_t ssi2001_device = {"Innovation SSI-2001", 0, ssi2001_init, ssi2001_close, NULL, NULL, NULL, NULL};
