summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/audio/svision.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/audio/svision.c')
-rw-r--r--src/mess/audio/svision.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/mess/audio/svision.c b/src/mess/audio/svision.c
new file mode 100644
index 00000000000..3cb3715c768
--- /dev/null
+++ b/src/mess/audio/svision.c
@@ -0,0 +1,318 @@
+/***************************************************************************
+ supervision sound hardware
+
+ PeT mess@utanet.at
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/svision.h"
+
+typedef enum
+{
+ SVISION_NOISE_Type7Bit,
+ SVISION_NOISE_Type14Bit
+} SVISION_NOISE_Type;
+
+typedef struct
+{
+ UINT8 reg[3];
+ int on, right, left, play;
+ SVISION_NOISE_Type type;
+ int state;
+ int volume;
+ int count;
+ double step, pos;
+ int value; // currently simple random function
+} SVISION_NOISE;
+
+typedef struct
+{
+ UINT8 reg[5];
+ int on, right, left;
+ int ca14to16;
+ int start,size;
+ double pos, step;
+ int finished;
+} SVISION_DMA;
+
+typedef struct
+{
+ UINT8 reg[4];
+ int on;
+ int waveform, volume;
+ int pos;
+ int size;
+ int count;
+} SVISION_CHANNEL;
+
+typedef struct _svision_sound_state svision_sound_state;
+struct _svision_sound_state
+{
+ sound_stream *mixer_channel;
+ SVISION_DMA dma;
+ SVISION_NOISE noise;
+ SVISION_CHANNEL channel[2];
+};
+
+
+INLINE svision_sound_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == SVISION);
+ return (svision_sound_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+int *svision_dma_finished(device_t *device)
+{
+ svision_sound_state *state = get_safe_token(device);
+ return &state->dma.finished;
+}
+
+void svision_sound_decrement(device_t *device)
+{
+ svision_sound_state *state = get_safe_token(device);
+
+ if (state->channel[0].count > 0)
+ state->channel[0].count--;
+ if (state->channel[1].count > 0)
+ state->channel[1].count--;
+ if (state->noise.count > 0)
+ state->noise.count--;
+}
+
+WRITE8_DEVICE_HANDLER( svision_sounddma_w )
+{
+ svision_sound_state *state = get_safe_token(device);
+ logerror("%.6f svision snddma write %04x %02x\n", device->machine().time().as_double(),offset+0x18,data);
+ state->dma.reg[offset] = data;
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ state->dma.start = (state->dma.reg[0] | (state->dma.reg[1] << 8));
+ break;
+ case 2:
+ state->dma.size = (data ? data : 0x100) * 32;
+ break;
+ case 3:
+ state->dma.step = device->machine().device("maincpu")->unscaled_clock() / (256.0 * device->machine().sample_rate() * (1 + (data & 3)));
+ state->dma.right = data & 4;
+ state->dma.left = data & 8;
+ state->dma.ca14to16 = ((data & 0x70) >> 4) << 14;
+ break;
+ case 4:
+ state->dma.on = data & 0x80;
+ if (state->dma.on)
+ {
+ state->dma.pos = 0.0;
+ }
+ break;
+ }
+}
+
+WRITE8_DEVICE_HANDLER( svision_noise_w )
+{
+ svision_sound_state *state = get_safe_token(device);
+ // logerror("%.6f svision noise write %04x %02x\n",machine.time(),offset+0x28,data);
+ state->noise.reg[offset]=data;
+ switch (offset)
+ {
+ case 0:
+ state->noise.volume=data&0xf;
+ state->noise.step= device->machine().device("maincpu")->unscaled_clock() / (256.0*device->machine().sample_rate()*(1+(data>>4)));
+ break;
+ case 1:
+ state->noise.count = data + 1;
+ break;
+ case 2:
+ state->noise.type = (SVISION_NOISE_Type) (data & 1);
+ state->noise.play = data & 2;
+ state->noise.right = data & 4;
+ state->noise.left = data & 8;
+ state->noise.on = data & 0x10; /* honey bee start */
+ state->noise.state = 1;
+ break;
+ }
+ state->noise.pos=0.0;
+}
+
+void svision_soundport_w(device_t *device, int which, int offset, int data)
+{
+ svision_sound_state *state = get_safe_token(device);
+ SVISION_CHANNEL *channel = &state->channel[which];
+ UINT16 size;
+
+ state->mixer_channel->update();
+ channel->reg[offset] = data;
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ size = channel->reg[0] | ((channel->reg[1] & 7) << 8);
+ if (size)
+ {
+ // channel->size=(int)(device->machine().sample_rate()*(size<<5)/4e6);
+ channel->size= (int) (device->machine().sample_rate() * (size << 5) / device->machine().device("maincpu")->unscaled_clock());
+ }
+ else
+ {
+ channel->size = 0;
+ }
+ channel->pos = 0;
+ break;
+ case 2:
+ channel->on = data & 0x40;
+ channel->waveform = (data & 0x30) >> 4;
+ channel->volume = data & 0xf;
+ break;
+ case 3:
+ channel->count = data + 1;
+ break;
+ }
+}
+
+/************************************/
+/* Sound handler update */
+/************************************/
+static STREAM_UPDATE( svision_update )
+{
+ svision_sound_state *state = get_safe_token(device);
+ stream_sample_t *left=outputs[0], *right=outputs[1];
+ int i, j;
+ SVISION_CHANNEL *channel;
+
+ for (i = 0; i < samples; i++, left++, right++)
+ {
+ *left = 0;
+ *right = 0;
+ for (channel=state->channel, j=0; j<ARRAY_LENGTH(state->channel); j++, channel++)
+ {
+ if (channel->size != 0)
+ {
+ if (channel->on||channel->count)
+ {
+ int on = FALSE;
+ switch (channel->waveform)
+ {
+ case 0:
+ on = channel->pos <= (28 * channel->size) >> 5;
+ break;
+ case 1:
+ on = channel->pos <= (24 * channel->size) >> 5;
+ break;
+ default:
+ case 2:
+ on = channel->pos <= channel->size / 2;
+ break;
+ case 3:
+ on = channel->pos <= (9 * channel->size) >> 5;
+ break;
+ }
+ {
+ INT16 s = on ? channel->volume << 8 : 0;
+ if (j == 0)
+ *right += s;
+ else
+ *left += s;
+ }
+ }
+ channel->pos++;
+ if (channel->pos >= channel->size)
+ channel->pos = 0;
+ }
+ }
+ if (state->noise.on && (state->noise.play || state->noise.count))
+ {
+ INT16 s = (state->noise.value ? 1 << 8: 0) * state->noise.volume;
+ int b1, b2;
+ if (state->noise.left)
+ *left += s;
+ if (state->noise.right)
+ *right += s;
+ state->noise.pos += state->noise.step;
+ if (state->noise.pos >= 1.0)
+ {
+ switch (state->noise.type)
+ {
+ case SVISION_NOISE_Type7Bit:
+ state->noise.value = state->noise.state & 0x40 ? 1 : 0;
+ b1 = (state->noise.state & 0x40) != 0;
+ b2 = (state->noise.state & 0x20) != 0;
+ state->noise.state=(state->noise.state<<1)+(b1!=b2?1:0);
+ break;
+ case SVISION_NOISE_Type14Bit:
+ default:
+ state->noise.value = state->noise.state & 0x2000 ? 1 : 0;
+ b1 = (state->noise.state & 0x2000) != 0;
+ b2 = (state->noise.state & 0x1000) != 0;
+ state->noise.state = (state->noise.state << 1) + (b1 != b2 ? 1 : 0);
+ }
+ state->noise.pos -= 1;
+ }
+ }
+ if (state->dma.on)
+ {
+ UINT8 sample;
+ INT16 s;
+ UINT16 addr = state->dma.start + (unsigned) state->dma.pos / 2;
+ if (addr >= 0x8000 && addr < 0xc000)
+ {
+ sample = device->machine().root_device().memregion("user1")->base()[(addr & 0x3fff) | state->dma.ca14to16];
+ }
+ else
+ {
+ sample = device->machine().device("maincpu")->memory().space(AS_PROGRAM)->read_byte(addr);
+ }
+ if (((unsigned)state->dma.pos) & 1)
+ s = (sample & 0xf);
+ else
+ s = (sample & 0xf0) >> 4;
+ s <<= 8;
+ if (state->dma.left)
+ *left += s;
+ if (state->dma.right)
+ *right += s;
+ state->dma.pos += state->dma.step;
+ if (state->dma.pos >= state->dma.size)
+ {
+ state->dma.finished = TRUE;
+ state->dma.on = FALSE;
+ svision_irq(device->machine());
+ }
+ }
+ }
+}
+
+/************************************/
+/* Sound handler start */
+/************************************/
+
+static DEVICE_START( svision_sound )
+{
+ svision_sound_state *state = get_safe_token(device);
+ memset(&state->dma, 0, sizeof(state->dma));
+ memset(&state->noise, 0, sizeof(state->noise));
+ memset(state->channel, 0, sizeof(state->channel));
+
+ state->mixer_channel = device->machine().sound().stream_alloc(*device, 0, 2, device->machine().sample_rate(), 0, svision_update);
+}
+
+
+DEVICE_GET_INFO( svision_sound )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(svision_sound_state); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(svision_sound); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Super Vision Custom"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ }
+}
+
+DEFINE_LEGACY_SOUND_DEVICE(SVISION, svision_sound);