ftp.nice.ch/pub/next/tools/emulators/vice.0.15.0.NeXT.sd.tgz#/vice-0.15.0/src/vic20/vic20sound.c

This is vic20sound.c in view mode; [Download] [Up]

/*
 * vic20sound.c - implementation of VIC20 sound code
 *
 * Written by
 *  Teemu Rantanen (tvr@cs.hut.fi)
 *
 * 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.
 *
 */

#include <stdio.h>

#include "vice.h"
#include "sound.h"
#include "maincpu.h"
#include "utils.h"

#include "vic20sound.h"

/* warnings */
static warn_t *pwarn;

/* argh */
static BYTE siddata[16];

/* noise magic */
#define NSHIFT(v, n) (((v)<<(n))|((((v)>>(23-(n)))^(v>>(18-(n))))&((1<<(n))-1)))
#define NVALUE(v) (noiseLSB[v&0xff]|noiseMID[(v>>8)&0xff]|noiseMSB[(v>>16)&0xff])
#define NSEED 0x7ffff8

/* Noise tables */
#define NOISETABLESIZE 256
static BYTE noiseMSB[NOISETABLESIZE];
static BYTE noiseMID[NOISETABLESIZE];
static BYTE noiseLSB[NOISETABLESIZE];

/* needed data for one voice */
typedef struct voice_s
{
    /* counter value */
    DWORD		 f;
    /* counter step / sample */
    DWORD		 fs;

    /* noise shift register. Note! rv may be 0 to 15 shifts 'behind' the
       real noise shift register value. Remaining shifts are done when
       it is referenced */
    DWORD		 rv;
} voice_t;

/* needed data for SID */
struct sound_s
{
    /* number of voices */
    voice_t		 v[4];
    /* 4-bit volume value */
    BYTE		 vol;

    /* internal constant used for sample rate dependent calculations */
    DWORD		 speed1;
};

int sound_machine_calculate_samples(sound_t *psid, SWORD *pbuf, int nr)
{
    int			i;
    DWORD		o0, o1, o2, o3;

    for (i = 0; i < nr; i++)
    {
	/* addfptrs */
	psid->v[0].f += psid->v[0].fs;
	psid->v[1].f += psid->v[1].fs;
	psid->v[2].f += psid->v[2].fs;
	psid->v[3].f += psid->v[3].fs;
	/* noise */
	if (psid->v[3].f < psid->v[3].fs)
	    psid->v[3].rv = NSHIFT(psid->v[3].rv, 16);
	/* voices */
	o0 = (psid->v[0].f & 0x80000000) >> 2;
	o1 = (psid->v[1].f & 0x80000000) >> 2;
	o2 = (psid->v[2].f & 0x80000000) >> 2;
	o3 = (DWORD)NVALUE(NSHIFT(psid->v[3].rv, psid->v[3].f >> 28)) << 22;
	/* sample */
	pbuf[i] = ((SDWORD)((o0+o1+o2+o3)>>20)-0x800)*psid->vol;
    }
    return 0;
}


/* SID initialization routine */
sound_t *sound_machine_open(int speed, int cycles_per_sec)
{
    DWORD		 i;
    sound_t		*psid;

    psid = xmalloc(sizeof(*psid));
    memset(psid, 0, sizeof(psid));
    psid->speed1 = (cycles_per_sec << 8) / speed;
    psid->v[3].rv = NSEED;
    for (i = 0; i < NOISETABLESIZE; i++)
    {
	noiseLSB[i] = (((i>>(7-2))&0x04)|((i>>(4-1))&0x02)|((i>>(2-0))&0x01));
	noiseMID[i] = (((i>>(13-8-4))&0x10)|((i<<(3-(11-8)))&0x08));
	noiseMSB[i] = (((i<<(7-(22-16)))&0x80)|((i<<(6-(20-16)))&0x40)
 		       |((i<<(5-(16-16)))&0x20));
    }
    for (i = 0; i < 16; i++)
	sound_machine_store(psid, i, siddata[i]);
    return psid;
}

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

void sound_reset(void)
{
    int				i;
    for (i = 10; i < 15; i++)
	store_sound(i, 0);
    warn_reset(pwarn);
    sound_prevent_clk_overflow(clk);
}

void sound_machine_init(void)
{
    pwarn = warn_init("SOUNDVIC20", 128);
}


/*
 * XXX: This is _really_ experimental
 */
#define VIC20FREQBASE    65535

void store_sound(ADDRESS addr, BYTE value)
{
    addr &= 0x0f;
    siddata[addr] = value;
    sound_store(addr, value);
}

void sound_machine_store(sound_t *psid, ADDRESS addr, BYTE value)
{
    DWORD			freq;
    int				sbase, shift, div;

#if 0
    {
        char			*t = "                ";
        warn(pwarn, 8,
             "Sound support for VIC20 is at _very_ experimental stage.\n"
             "%sIf you think this doesn't sound right, please wait\n"
             "%sfor the next snapshot or help me get this right.\n"
             "%s                          // tvr", t, t, t);
    }
#endif

    switch (addr)
    {
    case 10:
    case 11:
    case 12:
    case 13:
	sbase = (addr - 10)*4;
	shift = addr - 10;
	if (addr == 13)
	    shift = 0;
	div = 255 - value;
	/* XXX: ? */
	if (!div)
	    div = 127;
	if (!(value & 0x80))
	    freq = 0;
	else
	    freq = VIC20FREQBASE*(1 << shift)/div;
	psid->v[addr - 10].fs = psid->speed1 * freq;
	break;
    case 14:
	/* volume */
	psid->vol = value & 0x0f;
	break;
    }
}

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

BYTE sound_machine_read(sound_t *psid, ADDRESS addr)
{
    abort();
    return 0;
}

char *sound_machine_dump_state(sound_t *psid)
{
    char				buf[1024];

    sprintf(buf, "#SID: clk=%d v=%d\n", clk, psid->vol);
    return stralloc(buf);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.