summaryrefslogtreecommitdiffstats
path: root/src/mame/video/funkybee.cpp
diff options
context:
space:
mode:
author Robbbert <Robbbert@users.noreply.github.com>2025-04-26 10:48:07 +1000
committer Robbbert <Robbbert@users.noreply.github.com>2025-04-26 10:48:07 +1000
commitf870617117d2fa20bf955e247b092d7e8081145a (patch)
tree9698efea07b8c15aff28c74aa7bd27cc5827aee3 /src/mame/video/funkybee.cpp
parent89e1fe2e818b4ed38e678123439c1a4abdd50ddd (diff)
Added sf2prime 0.50HEADmaster
Diffstat (limited to 'src/mame/video/funkybee.cpp')
0 files changed, 0 insertions, 0 deletions
> 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
/***********************************************************

    Astrocade custom 'IO' chip sound chip driver
    Aaron Giles
    based on original work by Frank Palazzolo

************************************************************

    Register Map
    ============

    Register 0:
        D7..D0: Master oscillator frequency

    Register 1:
        D7..D0: Tone generator A frequency

    Register 2:
        D7..D0: Tone generator B frequency

    Register 3:
        D7..D0: Tone generator C frequency

    Register 4:
        D7..D6: Vibrato speed
        D5..D0: Vibrato depth

    Register 5:
            D5: Noise AM enable
            D4: Mux source (0=vibrato, 1=noise)
        D3..D0: Tone generator C volume

    Register 6:
        D7..D4: Tone generator B volume
        D3..D0: Tone generator A volume

    Register 7:
        D7..D0: Noise volume

***********************************************************/

#include "emu.h"
#include "streams.h"
#include "astrocde.h"


typedef struct _astrocade_state astrocade_state;
struct _astrocade_state
{
	sound_stream *stream;		/* sound stream */

	UINT8		reg[8];			/* 8 control registers */

	UINT8		master_count;	/* current master oscillator count */
	UINT16		vibrato_clock;	/* current vibrato clock */

	UINT8		noise_clock;	/* current noise generator clock */
	UINT16		noise_state;	/* current noise LFSR state */

	UINT8		a_count;		/* current tone generator A count */
	UINT8		a_state;		/* current tone generator A state */

	UINT8		b_count;		/* current tone generator B count */
	UINT8		b_state;		/* current tone generator B state */

	UINT8		c_count;		/* current tone generator C count */
	UINT8		c_state;		/* current tone generator C state */

	UINT8		bitswap[256];	/* bitswap table */
};


INLINE astrocade_state *get_safe_token(const device_config *device)
{
	assert(device != NULL);
	assert(device->token != NULL);
	assert(device->type == SOUND);
	assert(sound_get_type(device) == SOUND_ASTROCADE);
	return (astrocade_state *)device->token;
}



/*************************************
 *
 *  Core sound update
 *
 *************************************/

static STREAM_UPDATE( astrocade_update )
{
	astrocade_state *chip = (astrocade_state *)param;
	stream_sample_t *dest = outputs[0];
	UINT16 noise_state;
	UINT8 master_count;
	UINT8 noise_clock;

	/* load some locals */
	master_count = chip->master_count;
	noise_clock = chip->noise_clock;
	noise_state = chip->noise_state;

	/* loop over samples */
	while (samples > 0)
	{
		stream_sample_t cursample = 0;
		int samples_this_time;
		int samp;

		/* compute the number of cycles until the next master oscillator reset */
		/* or until the next noise boundary */
		samples_this_time = MIN(samples, 256 - master_count);
		samples_this_time = MIN(samples_this_time, 64 - noise_clock);
		samples -= samples_this_time;

		/* sum the output of the tone generators */
		if (chip->a_state)
			cursample += chip->reg[6] & 0x0f;
		if (chip->b_state)
			cursample += chip->reg[6] >> 4;
		if (chip->c_state)
			cursample += chip->reg[5] & 0x0f;

		/* add in the noise if it is enabled, based on the top bit of the LFSR */
		if ((chip->reg[5] & 0x20) && (noise_state & 0x4000))
			cursample += chip->reg[7] >> 4;

		/* scale to max and output */
		cursample = cursample * 32767 / 60;
		for (samp = 0; samp < samples_this_time; samp++)
			*dest++ = cursample;

		/* clock the noise; a 2-bit counter clocks a 4-bit counter which clocks the LFSR */
		noise_clock += samples_this_time;
		if (noise_clock >= 64)
		{
			/* update the noise state; this is a 15-bit LFSR with feedback from */
			/* the XOR of the top two bits */
			noise_state = (noise_state << 1) | (~((noise_state >> 14) ^ (noise_state >> 13)) & 1);
			noise_clock -= 64;

			/* the same clock also controls the vibrato clock, which is a 13-bit counter */
			chip->vibrato_clock++;
		}

		/* clock the master oscillator; this is an 8-bit up counter */
		master_count += samples_this_time;
		if (master_count == 0)
		{
			/* reload based on mux value -- the value from the register is negative logic */
			master_count = ~chip->reg[0];

			/* mux value 0 means reload based on the vibrato control */
			if ((chip->reg[5] & 0x10) == 0)
			{
				/* vibrato speed (register 4 bits 6-7) selects one of the top 4 bits */
				/* of the 13-bit vibrato clock to use (0=highest freq, 3=lowest) */
				if (!((chip->vibrato_clock >> (chip->reg[4] >> 6)) & 0x0200))
				{
					/* if the bit is clear, we add the vibrato volume to the counter */
					master_count += chip->reg[4] & 0x3f;
				}
			}

			/* mux value 1 means reload based on the noise control */
			else
			{
				/* the top 8 bits of the noise LFSR are ANDed with the noise volume */
				/* register and added to the count */
				master_count += chip->bitswap[(noise_state >> 7) & 0xff] & chip->reg[7];
			}

			/* clock tone A */
			if (++chip->a_count == 0)
			{
				chip->a_state ^= 1;
				chip->a_count = ~chip->reg[1];
			}

			/* clock tone B */
			if (++chip->b_count == 0)
			{
				chip->b_state ^= 1;
				chip->b_count = ~chip->reg[2];
			}

			/* clock tone C */
			if (++chip->c_count == 0)
			{
				chip->c_state ^= 1;
				chip->c_count = ~chip->reg[3];
			}
		}
	}

	/* put back the locals */
	chip->master_count = master_count;
	chip->noise_clock = noise_clock;
	chip->noise_state = noise_state;
}



/*************************************
 *
 *  Chip reset
 *
 *************************************/

static DEVICE_RESET( astrocade )
{
	astrocade_state *chip = get_safe_token(device);

	memset(chip->reg, 0, sizeof(chip->reg));

	chip->master_count = 0;
	chip->vibrato_clock = 0;

	chip->noise_clock = 0;
	chip->noise_state = 0;

	chip->a_count = 0;
	chip->a_state = 0;

	chip->b_count = 0;
	chip->b_state = 0;

	chip->c_count = 0;
	chip->c_state = 0;
}


/*************************************
 *
 *  Save state registration
 *
 *************************************/

static void astrocade_state_save_register(astrocade_state *chip, const device_config *device)
{
	state_save_register_device_item_array(device, 0, chip->reg);

	state_save_register_device_item(device, 0, chip->master_count);
	state_save_register_device_item(device, 0, chip->vibrato_clock);

	state_save_register_device_item(device, 0, chip->noise_clock);
	state_save_register_device_item(device, 0, chip->noise_state);

	state_save_register_device_item(device, 0, chip->a_count);
	state_save_register_device_item(device, 0, chip->a_state);

	state_save_register_device_item(device, 0, chip->b_count);
	state_save_register_device_item(device, 0, chip->b_state);

	state_save_register_device_item(device, 0, chip->c_count);
	state_save_register_device_item(device, 0, chip->c_state);
}



/*************************************
 *
 *  Chip initialization
 *
 *************************************/

static DEVICE_START( astrocade )
{
	astrocade_state *chip = get_safe_token(device);
	int i;

	/* generate a bitswap table for the noise */
	for (i = 0; i < 256; i++)
		chip->bitswap[i] = BITSWAP8(i, 0,1,2,3,4,5,6,7);

	/* allocate a stream for output */
	chip->stream = stream_create(device, 0, 1, device->clock, chip, astrocade_update);

	/* reset state */
	DEVICE_RESET_CALL(astrocade);
	astrocade_state_save_register(chip, device);
}



/*************************************
 *
 *  Sound write accessors
 *
 *************************************/

WRITE8_DEVICE_HANDLER( astrocade_sound_w )
{
	astrocade_state *chip = get_safe_token(device);

	if ((offset & 8) != 0)
		offset = (offset >> 8) & 7;
	else
		offset &= 7;

	/* update */
	stream_update(chip->stream);

	/* stash the new register value */
	chip->reg[offset & 7] = data;
}



/*************************************
 *
 *  Get/set info callbacks
 *
 *************************************/

DEVICE_GET_INFO( astrocade )
{
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case DEVINFO_INT_TOKEN_BYTES:					info->i = sizeof(astrocade_state);					break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case DEVINFO_FCT_START:							info->start = DEVICE_START_NAME( astrocade );		break;
		case DEVINFO_FCT_RESET:							info->reset = DEVICE_RESET_NAME( astrocade );		break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:							strcpy(info->s, "Astrocade");						break;
		case DEVINFO_STR_FAMILY:					strcpy(info->s, "Bally");							break;
		case DEVINFO_STR_VERSION:					strcpy(info->s, "2.0");								break;
		case DEVINFO_STR_SOURCE_FILE:						strcpy(info->s, __FILE__);							break;
		case DEVINFO_STR_CREDITS:					strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
	}
}