diff options
Diffstat (limited to 'src/mame/audio/attckufo.c')
-rw-r--r-- | src/mame/audio/attckufo.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/mame/audio/attckufo.c b/src/mame/audio/attckufo.c new file mode 100644 index 00000000000..b7ac3a33044 --- /dev/null +++ b/src/mame/audio/attckufo.c @@ -0,0 +1,262 @@ +/*************************************************************************** + + Attack ufo sound emulation + based on MOS 6560 emulator by + PeT mess@utanet.at + +***************************************************************************/ +#include <math.h> +#include "driver.h" +#include "streams.h" +#include "sound/custom.h" +#include "includes/attckufo.h" + +/* + * assumed model: + * each write to a ton/noise generated starts it new + * each generator behaves like an timer + * when it reaches 0, the next samplevalue is given out + */ + +/* + * noise channel + * based on a document by diku0748@diku.dk (Asger Alstrup Nielsen) + * + * 23 bit shift register + * initial value (0x7ffff8) + * after shift bit 0 is set to bit 22 xor bit 17 + * dac sample bit22 bit20 bit16 bit13 bit11 bit7 bit4 bit2(lsb) + * + * emulation: + * allocate buffer for 5 sec sampledata (fastest played frequency) + * and fill this buffer in init with the required sample + * fast turning off channel, immediate change of frequency + */ + +#define NOISE_BUFFER_SIZE_SEC 5 + + +#define TONE1_ON (attckufo_regs[0xa]&0x80) +#define TONE2_ON (attckufo_regs[0xb]&0x80) +#define TONE3_ON (attckufo_regs[0xc]&0x80) +#define NOISE_ON (attckufo_regs[0xd]&0x80) +#define VOLUME (attckufo_regs[0xe]&0x0f) + +#define OUTPUT_RATE (14318181/14/32) + +#define TONE_FREQUENCY_MIN ((14318181/14)/256/128) +#define TONE1_VALUE (8*(128-((attckufo_regs[0xa]+1)&0x7f))) +#define TONE1_FREQUENCY ((14318181/14)/32/TONE1_VALUE) +#define TONE2_VALUE (4*(128-((attckufo_regs[0xb]+1)&0x7f))) +#define TONE2_FREQUENCY ((14318181/14)/32/TONE2_VALUE) +#define TONE3_VALUE (2*(128-((attckufo_regs[0xc]+1)&0x7f))) +#define TONE3_FREQUENCY ((14318181/14)/32/TONE3_VALUE) +#define NOISE_VALUE (32*(128-((attckufo_regs[0xd]+1)&0x7f))) +#define NOISE_FREQUENCY ((14318181/14)/NOISE_VALUE) +#define NOISE_FREQUENCY_MAX ((14318181/14)/32/1) + +static int tone1pos = 0, tone2pos = 0, tone3pos = 0, + tonesize, tone1samples = 1, tone2samples = 1, tone3samples = 1, + noisesize, /* number of samples */ + noisepos = 0, /* pos of tone */ + noisesamples = 1; /* count of samples to give out per tone */ + +static sound_stream *channel; +static INT16 *tone; + +static INT8 *noise; + +void attckufo_soundport_w (int offset, int data) +{ + int old = attckufo_regs[offset]; + stream_update(channel); + switch (offset) + { + case 0xa: + attckufo_regs[offset] = data; + if (!(old & 0x80) && TONE1_ON) + { + tone1pos = 0; + tone1samples = OUTPUT_RATE / TONE1_FREQUENCY; + if (tone1samples == 0) + tone1samples = 1; + } + + break; + case 0xb: + attckufo_regs[offset] = data; + if (!(old & 0x80) && TONE2_ON) + { + tone2pos = 0; + tone2samples = OUTPUT_RATE / TONE2_FREQUENCY; + if (tone2samples == 0) + tone2samples = 1; + } + + break; + case 0xc: + attckufo_regs[offset] = data; + if (!(old & 0x80) && TONE3_ON) + { + tone3pos = 0; + tone3samples = OUTPUT_RATE / TONE3_FREQUENCY; + if (tone2samples == 0) + tone2samples = 1; + } + + break; + case 0xd: + attckufo_regs[offset] = data; + if (NOISE_ON) + { + noisesamples = (int) ((double) NOISE_FREQUENCY_MAX * OUTPUT_RATE + * NOISE_BUFFER_SIZE_SEC / NOISE_FREQUENCY); + + if ((double) noisepos / noisesamples >= 1.0) + { + noisepos = 0; + } + } + else + { + noisepos = 0; + } + break; + case 0xe: + attckufo_regs[offset] = (old & ~0xf) | (data & 0xf); + + break; + } +} + +/************************************/ +/* Sound handler update */ +/************************************/ +static void attckufo_update (void *param,stream_sample_t **inputs, stream_sample_t **_buffer,int length) +{ + int i, v; + stream_sample_t *buffer = _buffer[0]; + + for (i = 0; i < length; i++) + { + v = 0; + if (TONE1_ON /*||(tone1pos!=0) */ ) + { + v += tone[tone1pos * tonesize / tone1samples]; + tone1pos++; + + if (tone1pos >= tone1samples) + { + tone1pos = 0; + tone1samples = OUTPUT_RATE / TONE1_FREQUENCY; + if (tone1samples == 0) + tone1samples = 1; + } + + } + if (TONE2_ON ) + { + v += tone[tone2pos * tonesize / tone2samples]; + tone2pos++; + if (tone2pos >= tone2samples) + { + tone2pos = 0; + tone2samples = OUTPUT_RATE / TONE2_FREQUENCY; + if (tone2samples == 0) + tone2samples = 1; + } + + } + if (TONE3_ON ) + { + v += tone[tone3pos * tonesize / tone3samples]; + tone3pos++; + + if (tone3pos >= tone3samples) + { + tone3pos = 0; + tone3samples = OUTPUT_RATE / TONE3_FREQUENCY; + if (tone3samples == 0) + tone3samples = 1; + } + + } + if (NOISE_ON) + { + v += noise[(int) ((double) noisepos * noisesize / noisesamples)]; + noisepos++; + if ((double) noisepos / noisesamples >= 1.0) + { + noisepos = 0; + } + } + v = (v * VOLUME) << 2; + if (v > 32767) + buffer[i] = 32767; + else if (v < -32767) + buffer[i] = -32767; + else + buffer[i] = v; + + + + } +} + +/************************************/ +/* Sound handler start */ +/************************************/ + + +void *attckufo_custom_start(int clock, const struct CustomSound_interface *config) +{ + int i; + + channel = stream_create(0, 1, OUTPUT_RATE, 0, attckufo_update); + + + /* buffer for fastest played sample for 5 second + * so we have enough data for min 5 second */ + noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC; + noise = (INT8*) auto_malloc (noisesize * sizeof (noise[0])); + { + int noiseshift = 0x7ffff8; + char data; + + for (i = 0; i < noisesize; i++) + { + data = 0; + if (noiseshift & 0x400000) + data |= 0x80; + if (noiseshift & 0x100000) + data |= 0x40; + if (noiseshift & 0x010000) + data |= 0x20; + if (noiseshift & 0x002000) + data |= 0x10; + if (noiseshift & 0x000800) + data |= 0x08; + if (noiseshift & 0x000080) + data |= 0x04; + if (noiseshift & 0x000010) + data |= 0x02; + if (noiseshift & 0x000004) + data |= 0x01; + noise[i] = data; + if (((noiseshift & 0x400000) == 0) != ((noiseshift & 0x002000) == 0)) + noiseshift = (noiseshift << 1) | 1; + else + noiseshift <<= 1; + } + } + tonesize = OUTPUT_RATE / TONE_FREQUENCY_MIN; + + tone = (INT16*) auto_malloc (tonesize * sizeof (tone[0])); + + for (i = 0; i < tonesize; i++) + { + tone[i] = (INT16)(sin (2 * M_PI * i / tonesize) * 127 + 0.5); + } + return (void *) ~0; +} + |