summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/canyon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/canyon.c')
-rw-r--r--src/mame/drivers/canyon.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/src/mame/drivers/canyon.c b/src/mame/drivers/canyon.c
index b3faad13a3b..89d53c197cd 100644
--- a/src/mame/drivers/canyon.c
+++ b/src/mame/drivers/canyon.c
@@ -37,6 +37,7 @@
***************************************************************************/
#include "driver.h"
+#include "cpu/m6502/m6502.h"
#include "canyon.h"
#include "sound/discrete.h"
d='n89' href='#n89'>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 159pre { line-height: 125%; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight .c { color: #8f5902; font-style: italic } /* Comment */ .highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ .highlight .g { color: #000000 } /* Generic */ .highlight .k { color: #204a87; font-weight: bold } /* Keyword */ .highlight .l { color: #000000 } /* Literal */ .highlight .n { color: #000000 } /* Name */ .highlight .o { color: #ce5c00; font-weight: bold } /* Operator */ .highlight .x { color: #000000 } /* Other */ .highlight .p { color: #000000; font-weight: bold } /* Punctuation */ .highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ .highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ .highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */ .highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ .highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ .highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ .highlight .gd { color: #a40000 } /* Generic.Deleted */ .highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ .highlight .gr { color: #ef2929 } /* Generic.Error */ .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .highlight .gi { color: #00A000 } /* Generic.Inserted */ .highlight .go { color: #000000; font-style: italic } /* Generic.Output */ .highlight .gp { color: #8f5902 } /* Generic.Prompt */ .highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ .highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ .highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ .highlight .ld { color: #000000 } /* Literal.Date */ .highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ .highlight .s { color: #4e9a06 } /* Literal.String */ .highlight .na { color: #c4a000 } /* Name.Attribute */ .highlight .nb { color: #204a87 } /* Name.Builtin */ .highlight .nc { color: #000000 } /* Name.Class */ .highlight .no { color: #000000 } /* Name.Constant */ .highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ .highlight .ni { color: #ce5c00 } /* Name.Entity */ .highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #000000 } /* Name.Function */ .highlight .nl { color: #f57900 } /* Name.Label */ .highlight .nn { color: #000000 } /* Name.Namespace */ .highlight .nx { color: #000000 } /* Name.Other */ .highlight .py { color: #000000 } /* Name.Property */ .highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #000000 } /* Name.Variable */ .highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ .highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ .highlight .w { color: #f8f8f8 } /* Text.Whitespace */ .highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ .highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ .highlight .sc { color: #4e9a06 } /* Literal.String.Char */ .highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ .highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ .highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ .highlight .se { color: #4e9a06 } /* Literal.String.Escape */ .highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ .highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ .highlight .sx { color: #4e9a06 } /* Literal.String.Other */ .highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ .highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ .highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ .highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #000000 } /* Name.Function.Ma
// license:BSD-3-Clause
// copyright-holders:Manuel Abadia
/***************************************************************************
                    Gaelco Sound Hardware

                By Manuel Abadia <emumanu+mame@gmail.com>

CG-1V/GAE1 (Gaelco custom GFX & Sound chip):
    The CG-1V/GAE1 can handle up to 7 stereo channels.
    The chip output is connected to a TDA1543 (16 bit DAC).

Registers per channel:
======================
    Word | Bit(s)            | Description
    -----+-FEDCBA98-76543210-+--------------------------
      0  | xxxxxxxx xxxxxxxx | not used?
      1  | xxxx---- -------- | left channel volume (0x00..0x0f)
      1  | ----xxxx -------- | right channel volume (0x00..0x0f)
      1  | -------- xxxx---- | sample type (0x0c = PCM 8 bits mono, 0x08 = PCM 8 bits stereo)
      1  | -------- ----xxxx | ROM Bank
      2  | xxxxxxxx xxxxxxxx | sample end position
      3  | xxxxxxxx xxxxxxxx | remaining bytes to play

      the following are used only when looping (usually used for music)

      4  | xxxxxxxx xxxxxxxx | not used?
      5  | xxxx---- -------- | left channel volume (0x00..0x0f)
      5  | ----xxxx -------- | right channel volume (0x00..0x0f)
      5  | -------- xxxx---- | sample type (0x0c = PCM 8 bits mono, 0x08 = PCM 8 bits stereo)
      5  | -------- ----xxxx | ROM Bank
      6  | xxxxxxxx xxxxxxxx | sample end position
      7  | xxxxxxxx xxxxxxxx | remaining bytes to play

    The samples are played from (end position + length) to (end position)!

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

#include "emu.h"
#include "gaelco.h"
#include "wavwrite.h"

#define VERBOSE_SOUND 0
#define VERBOSE_READ_WRITES 0
#define LOG_SOUND(x) do { if (VERBOSE_SOUND) logerror x; } while (0)
#define LOG_READ_WRITES(x) do { if (VERBOSE_READ_WRITES) logerror x; } while (0)

//#define ALT_MIX

#define LOG_WAVE  0
static wav_file* wavraw; // Raw waveform


/*============================================================================
                        Gaelco GAE1 sound device
  ============================================================================*/

DEFINE_DEVICE_TYPE(GAELCO_GAE1, gaelco_gae1_device, "gaelco_gae1", "Gaelco GAE1")

gaelco_gae1_device::gaelco_gae1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gaelco_gae1_device(mconfig, GAELCO_GAE1, tag, owner, clock)
{
}

gaelco_gae1_device::gaelco_gae1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock)
	, device_sound_interface(mconfig, *this)
	, device_rom_interface(mconfig, *this)
	, m_stream(nullptr)
{
}


/*============================================================================
                        CG-1V/GAE1 Sound Update

            Writes length bytes to the sound buffer
  ============================================================================*/

void gaelco_gae1_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
	/* fill all data needed */
	for (int j = 0; j < outputs[0].samples(); j++)
	{
		int output_l = 0, output_r = 0;

		/* for each channel */
		for (int ch = 0; ch < NUM_CHANNELS; ch++)
		{
			int ch_data_l = 0, ch_data_r = 0;
			sound_channel *channel = &m_channel[ch];

			/* if the channel is playing */
			if (channel->active == 1)
			{
				int data, chunkNum = 0;
				int base_offset, type, bank, vol_r, vol_l, end_pos;

				/* if the channel is looping, get current chunk to play */
				if (channel->loop == 1)
					chunkNum = channel->chunkNum;

				base_offset = ch*8 + chunkNum*4;

				/* get channel parameters */
				type = ((m_sndregs[base_offset + 1] >> 4) & 0x0f);
				bank = m_banks[((m_sndregs[base_offset + 1] >> 0) & 0x03)];
				vol_l = ((m_sndregs[base_offset + 1] >> 12) & 0x0f);
				vol_r = ((m_sndregs[base_offset + 1] >> 8) & 0x0f);
				end_pos = (m_sndregs[base_offset + 2] << 8) - 1;

				/* generates output data (range 0x00000..0xffff) */
				if (type == 0x08) /* PCM, 8 bits mono */
				{
					data = read_byte(bank + end_pos + m_sndregs[base_offset + 3]);
					ch_data_l = m_volume_table[vol_l][data];
					ch_data_r = m_volume_table[vol_r][data];

					m_sndregs[base_offset + 3]--;
				}
				else if (type == 0x0c) /* PCM, 8 bits stereo */
				{
					data = read_byte(bank + end_pos + m_sndregs[base_offset + 3]);
					ch_data_l = m_volume_table[vol_l][data];

					m_sndregs[base_offset + 3]--;

					if (m_sndregs[base_offset + 3] > 0)
					{
						data = read_byte(bank + end_pos + m_sndregs[base_offset + 3]);
						ch_data_r = m_volume_table[vol_r][data];

						m_sndregs[base_offset + 3]--;
					}
				}
				else
				{
					LOG_SOUND(("(GAE1) Playing unknown sample format in channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", ch, type, bank, end_pos, m_sndregs[base_offset + 3]));
					//channel->active = 0;
					// play2000 expects these to expire, are they valid? this is unrelated to the missing sounds in touchgo which never hits here
					m_sndregs[base_offset + 3]--;
				}

				/* check if the current sample has finished playing */
				if (m_sndregs[base_offset + 3] == 0)
				{
					if (channel->loop == 0)    /* if no looping, we're done */
					{
						channel->active = 0;
					}
					else                    /* if we're looping, swap chunks */
					{
						channel->chunkNum = (channel->chunkNum + 1) & 0x01;

						/* if the length of the next chunk is 0, we're done */
						if (m_sndregs[ch*8 + channel->chunkNum*4 + 3] == 0)
							channel->active = 0;

					}
				}
			}

			/* add the contribution of this channel to the current data output */
			output_l += ch_data_l;
			output_r += ch_data_r;
		}

#ifndef ALT_MIX
		/* clip to max or min value */
		if (output_l > 32767) output_l = 32767;
		if (output_r > 32767) output_r = 32767;
		if (output_l < -32768) output_l = -32768;
		if (output_r < -32768) output_r = -32768;
#else
		/* ponderate channels */
		output_l /= NUM_CHANNELS;
		output_r /= NUM_CHANNELS;
#endif

		/* now that we have computed all channels, save current data to the output buffer */
		outputs[0].put_int(j, output_l, 32768);
		outputs[1].put_int(j, output_r, 32768);
	}

//  if (wavraw)
//      wav_add_data_buffer(wavraw, outputs[0], outputs[1]);
}

/*============================================================================
                        CG-1V/GAE1 Read Handler
  ============================================================================*/

uint16_t gaelco_gae1_device::gaelcosnd_r(offs_t offset)
{
	LOG_READ_WRITES(("%s: (GAE1): read from %04x\n", machine().describe_context(), offset));

	/* first update the stream to this point in time */
	m_stream->update();

	return m_sndregs[offset];
}

/*============================================================================
                        CG-1V/GAE1 Write Handler
  ============================================================================*/

void gaelco_gae1_device::gaelcosnd_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
	sound_channel *channel = &m_channel[offset >> 3];

	LOG_READ_WRITES(("%s: (GAE1): write %04x to %04x\n", machine().describe_context(), data, offset));

	/* first update the stream to this point in time */
	m_stream->update();

	COMBINE_DATA(&m_sndregs[offset]);

	switch(offset & 0x07)
	{
		case 0x03:
			/* trigger sound */
			if ((m_sndregs[offset - 1] != 0) && (data != 0))
			{
				if (!channel->active)
				{
					channel->active = 1;
					channel->chunkNum = 0;
					channel->loop = 0;
					LOG_SOUND(("(GAE1) Playing sample channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", offset >> 3, (m_sndregs[offset - 2] >> 4) & 0x0f, m_sndregs[offset - 2] & 0x03, m_sndregs[offset - 1] << 8, data));
				}
			}
			else
				channel->active = 0;

			break;

		case 0x07: /* enable/disable looping */
			if ((m_sndregs[offset - 1] != 0) && (data != 0))
			{
				LOG_SOUND(("(GAE1) Looping in channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", offset >> 3, (m_sndregs[offset - 2] >> 4) & 0x0f, m_sndregs[offset - 2] & 0x03, m_sndregs[offset - 1] << 8, data));
				channel->loop = 1;
			}
			else
				channel->loop = 0;

			break;
	}
}

/*============================================================================
                        CG-1V/GAE1 Init / Close
  ============================================================================*/

void gaelco_gae1_device::device_start()
{
	u32 rate = clock() / 128;
	m_stream = stream_alloc(0, 2, rate);

	/* init volume table */
	for (int vol = 0; vol < VOLUME_LEVELS; vol++)
		for (int j = -128; j <= 127; j++)
			m_volume_table[vol][(j ^ 0x80) & 0xff] = (vol*j*256)/(VOLUME_LEVELS - 1);

	if (LOG_WAVE)
		wavraw = wav_open("gae1_snd.wav", rate, 2);
}


void gaelco_gae1_device::device_stop()
{
	if (wavraw)
		wav_close(wavraw);
	wavraw = nullptr;
}


void gaelco_gae1_device::device_post_load()
{
	device_clock_changed();
}


void gaelco_gae1_device::device_clock_changed()
{
	u32 rate = clock() / 128;
	m_stream->set_sample_rate(rate);
	if (wavraw)
		wav_close(wavraw);

	if (LOG_WAVE)
		wavraw = wav_open("gae1_snd.wav", rate, 2);
}


void gaelco_gae1_device::rom_bank_updated()
{
	m_stream->update();
}


/*============================================================================
                        Gaelco CG-1V sound device
  ============================================================================*/

DEFINE_DEVICE_TYPE(GAELCO_CG1V, gaelco_cg1v_device, "gaelco_cg1v", "Gaelco CG1V")

gaelco_cg1v_device::gaelco_cg1v_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gaelco_gae1_device(mconfig, GAELCO_CG1V, tag, owner, clock)
{
}