mirror of
https://github.com/holub/mame
synced 2025-04-24 17:30:55 +03:00
Free to good home if you can make it not sound like ass (nw)
This commit is contained in:
parent
bb2dee47ba
commit
7555ca37d8
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -5865,6 +5865,8 @@ src/mess/audio/upd1771.h svneol=native#text/plain
|
||||
src/mess/audio/vboy.c svneol=native#text/plain
|
||||
src/mess/audio/vboy.h svneol=native#text/plain
|
||||
src/mess/audio/vc4000.c svneol=native#text/plain
|
||||
src/mess/audio/vrc6.c svneol=native#text/plain
|
||||
src/mess/audio/vrc6.h svneol=native#text/plain
|
||||
src/mess/audio/wswan.c svneol=native#text/plain
|
||||
src/mess/drivers/4004clk.c svneol=native#text/plain
|
||||
src/mess/drivers/68ksbc.c svneol=native#text/plain
|
||||
|
320
src/mess/audio/vrc6.c
Normal file
320
src/mess/audio/vrc6.c
Normal file
@ -0,0 +1,320 @@
|
||||
/***************************************************************************
|
||||
|
||||
vrc6.c
|
||||
Konami VRC6 additional sound channels
|
||||
|
||||
Emulation by R. Belmont
|
||||
|
||||
References:
|
||||
http://wiki.nesdev.com/w/index.php/VRC6_audio
|
||||
http://nesdev.com/vrcvi.txt
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "vrc6.h"
|
||||
|
||||
#define DISABLE_VRC6_SOUND // not ready yet
|
||||
|
||||
// device type definition
|
||||
const device_type VRC6 = &device_creator<vrc6snd_device>;
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// vrc6snd_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
vrc6snd_device::vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, VRC6, "VRC6 sound", tag, owner, clock),
|
||||
device_sound_interface(mconfig, *this)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void vrc6snd_device::device_start()
|
||||
{
|
||||
m_stream = machine().sound().stream_alloc(*this, 0, 1, clock(), this);
|
||||
|
||||
m_freqctrl = m_pulsectrl[0] = m_pulsectrl[1] = 0;
|
||||
m_pulsefrql[0] = m_pulsefrql[1] = m_pulsefrqh[0] = m_pulsefrqh[1] = 0;
|
||||
m_sawaccum = m_sawfrql = m_sawfrqh = m_sawclock = m_sawrate = 0;
|
||||
m_ticks[0] = m_ticks[1] = m_ticks[2] = 0;
|
||||
m_output[0] = m_output[1] = m_output[2] = 0;
|
||||
m_pulseduty[0] = m_pulseduty[1] = 15;
|
||||
|
||||
save_item(NAME(m_freqctrl));
|
||||
save_item(NAME(m_pulsectrl));
|
||||
save_item(NAME(m_sawrate));
|
||||
save_item(NAME(m_sawaccum));
|
||||
save_item(NAME(m_pulsefrql));
|
||||
save_item(NAME(m_pulsefrqh));
|
||||
save_item(NAME(m_sawfrql));
|
||||
save_item(NAME(m_sawfrqh));
|
||||
save_item(NAME(m_ticks));
|
||||
save_item(NAME(m_output));
|
||||
save_item(NAME(m_pulseduty));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void vrc6snd_device::device_reset()
|
||||
{
|
||||
m_stream->update();
|
||||
|
||||
m_freqctrl = m_pulsectrl[0] = m_pulsectrl[1] = 0;
|
||||
m_pulsefrql[0] = m_pulsefrql[1] = 0;
|
||||
m_sawaccum = m_sawfrql = m_sawclock = m_sawrate = 0;
|
||||
m_ticks[0] = m_ticks[1] = m_ticks[2] = 0;
|
||||
m_output[0] = m_output[1] = m_output[2] = 0;
|
||||
m_pulseduty[0] = m_pulseduty[1] = 15;
|
||||
m_pulsefrqh[0] = m_pulsefrqh[1] = m_sawfrqh = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// sound_stream_update - handle update requests for
|
||||
// our sound stream
|
||||
//-------------------------------------------------
|
||||
|
||||
void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
||||
{
|
||||
stream_sample_t *out = outputs[0];
|
||||
INT16 tmp;
|
||||
int i;
|
||||
|
||||
// check global halt bit
|
||||
if (m_freqctrl & 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
// update pulse1
|
||||
if (m_pulsefrqh[0] & 0x80)
|
||||
{
|
||||
m_ticks[0]--;
|
||||
if (m_ticks[0] == 0)
|
||||
{
|
||||
m_ticks[0] = m_pulsefrql[0] | (m_pulsefrqh[0] & 0xf)<<4;
|
||||
|
||||
m_pulseduty[0]--;
|
||||
if (m_pulsectrl[0] & 0x80)
|
||||
{
|
||||
m_output[0] = m_pulsectrl[0] & 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pulseduty[0] <= ((m_pulsectrl[0]>>4) & 0x7))
|
||||
{
|
||||
m_output[0] = m_pulsectrl[0] & 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pulseduty[0] == 0)
|
||||
{
|
||||
m_pulseduty[0] = 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output[0] = 0;
|
||||
}
|
||||
|
||||
// update pulse2
|
||||
if (m_pulsefrqh[1] & 0x80)
|
||||
{
|
||||
m_ticks[1]--;
|
||||
if (m_ticks[1] == 0)
|
||||
{
|
||||
m_ticks[1] = m_pulsefrql[1] | (m_pulsefrqh[1] & 0xf)<<4;
|
||||
|
||||
m_pulseduty[1]--;
|
||||
if (m_pulsectrl[1] & 0x80)
|
||||
{
|
||||
m_output[1] = m_pulsectrl[1] & 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pulseduty[1] <= ((m_pulsectrl[1]>>4) & 0x7))
|
||||
{
|
||||
m_output[1] = m_pulsectrl[1] & 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pulseduty[1] == 0)
|
||||
{
|
||||
m_pulseduty[1] = 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output[1] = 0;
|
||||
}
|
||||
|
||||
// update saw
|
||||
if (m_sawfrqh & 0x80)
|
||||
{
|
||||
m_ticks[2]--;
|
||||
if (m_ticks[2] == 0)
|
||||
{
|
||||
m_ticks[2] = m_sawfrql | (m_sawfrqh & 0xf)<<4;
|
||||
|
||||
// only update on even steps
|
||||
if ((m_sawclock > 0) && (!(m_sawclock & 1)))
|
||||
{
|
||||
m_sawaccum += (m_sawrate & 0x3f);
|
||||
m_output[2] = (m_sawaccum>>3);
|
||||
}
|
||||
m_sawclock++;
|
||||
|
||||
if (m_sawclock >= 14)
|
||||
{
|
||||
m_sawclock = m_sawaccum = 0;
|
||||
m_output[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output[2] = 0;
|
||||
}
|
||||
|
||||
// sum 2 4-bit pulses, 1 5-bit saw = unsigned 6 bit output
|
||||
tmp = (INT16)(UINT8)(m_output[0] + m_output[1] + m_output[2]);
|
||||
tmp <<= 8;
|
||||
|
||||
out[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// write - write to the chip's registers
|
||||
//---------------------------------------
|
||||
|
||||
WRITE8_MEMBER( vrc6snd_device::write )
|
||||
{
|
||||
switch (offset >> 8)
|
||||
{
|
||||
case 0:
|
||||
m_stream->update();
|
||||
switch (offset & 3)
|
||||
{
|
||||
case 0:
|
||||
m_pulsectrl[0] = data;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_pulsefrql[0] = data;
|
||||
if (!(m_pulsefrqh[1] & 0x80))
|
||||
{
|
||||
m_ticks[0] &= ~0xff;
|
||||
m_ticks[0] |= m_pulsefrql[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
#ifndef DISABLE_VRC6_SOUND
|
||||
m_pulsefrqh[0] = data;
|
||||
// if disabling channel, reset phase
|
||||
if (!(data & 0x80))
|
||||
{
|
||||
m_pulseduty[0] = 15;
|
||||
m_ticks[0] &= 0xff;
|
||||
m_ticks[0] |= (m_pulsefrqh[0] & 0xf)<<4;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_freqctrl = data;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_stream->update();
|
||||
switch (offset & 3)
|
||||
{
|
||||
case 0:
|
||||
m_pulsectrl[1] = data;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_pulsefrql[1] = data;
|
||||
if (!(m_pulsefrqh[1] & 0x80))
|
||||
{
|
||||
m_ticks[1] &= ~0xff;
|
||||
m_ticks[1] |= m_pulsefrql[1];
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
#ifndef DISABLE_VRC6_SOUND
|
||||
m_pulsefrqh[1] = data;
|
||||
// if disabling channel, reset phase
|
||||
if (!(data & 0x80))
|
||||
{
|
||||
m_pulseduty[1] = 15;
|
||||
m_ticks[1] &= 0xff;
|
||||
m_ticks[1] |= (m_pulsefrqh[1] & 0xf)<<4;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_stream->update();
|
||||
switch (offset & 3)
|
||||
{
|
||||
case 0:
|
||||
m_sawrate = data;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_sawfrql = data;
|
||||
if (!(m_sawfrqh & 0x80))
|
||||
{
|
||||
m_ticks[2] &= ~0xff;
|
||||
m_ticks[2] |= m_sawfrql;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
#ifndef DISABLE_VRC6_SOUND
|
||||
m_sawfrqh = data;
|
||||
// if disabling channel, reset phase
|
||||
if (!(data & 0x80))
|
||||
{
|
||||
m_sawaccum = 0;
|
||||
m_ticks[2] &= 0xff;
|
||||
m_ticks[2] |= (m_sawfrqh & 0xf)<<4;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
61
src/mess/audio/vrc6.h
Normal file
61
src/mess/audio/vrc6.h
Normal file
@ -0,0 +1,61 @@
|
||||
/***************************************************************************
|
||||
|
||||
vrc6.h
|
||||
Konami VRC6 add-on sound
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __VRC6_H__
|
||||
#define __VRC6_H__
|
||||
|
||||
//**************************************************************************
|
||||
// INTERFACE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define MCFG_VRC6_ADD(_tag, _clock) \
|
||||
MCFG_DEVICE_ADD(_tag, VRC6, _clock)
|
||||
|
||||
#define MCFG_VRC6_REPLACE(_tag, _clock) \
|
||||
MCFG_DEVICE_REPLACE(_tag, VRC6, _clock)
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> vrc6snd_device
|
||||
|
||||
class vrc6snd_device : public device_t, public device_sound_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
DECLARE_WRITE8_MEMBER(write);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
|
||||
|
||||
private:
|
||||
UINT8 m_freqctrl, m_pulsectrl[2], m_sawrate;
|
||||
UINT8 m_pulsefrql[2], m_pulsefrqh[2], m_pulseduty[2];
|
||||
UINT8 m_sawfrql, m_sawfrqh, m_sawclock, m_sawaccum;
|
||||
UINT16 m_ticks[3];
|
||||
UINT8 m_output[3];
|
||||
|
||||
sound_stream *m_stream;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type VRC6;
|
||||
|
||||
|
||||
#endif /* __VRC6_H__ */
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
|
||||
|
||||
#define N2A03_DEFAULTCLOCK (21477272.724 / 12)
|
||||
|
||||
//-------------------------------------------------
|
||||
// constructor
|
||||
@ -78,7 +79,8 @@ nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, co
|
||||
}
|
||||
|
||||
nes_konami_vrc6_device::nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: nes_konami_vrc4_device(mconfig, NES_VRC6, "NES Cart Konami VRC-6 PCB", tag, owner, clock, "nes_vrc6", __FILE__)
|
||||
: nes_konami_vrc4_device(mconfig, NES_VRC6, "NES Cart Konami VRC-6 PCB", tag, owner, clock, "nes_vrc6", __FILE__),
|
||||
m_vrc6snd(*this, "vrc6snd")
|
||||
{
|
||||
}
|
||||
|
||||
@ -187,6 +189,11 @@ void nes_konami_vrc4_device::pcb_reset()
|
||||
memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
|
||||
}
|
||||
|
||||
void nes_konami_vrc6_device::device_start()
|
||||
{
|
||||
nes_konami_vrc4_device::device_start();
|
||||
}
|
||||
|
||||
void nes_konami_vrc7_device::device_start()
|
||||
{
|
||||
m_ym2413 = device().subdevice("ym");
|
||||
@ -573,9 +580,11 @@ WRITE8_MEMBER(nes_konami_vrc6_device::write_h)
|
||||
case 0x4000:
|
||||
prg8_cd(data);
|
||||
break;
|
||||
case 0x1000:
|
||||
case 0x2000:
|
||||
LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", (offset & 0x7000) | add_lines, data));
|
||||
case 0x1000: // pulse 1 & global control
|
||||
m_vrc6snd->write(space, add_lines>>8, data);
|
||||
break;
|
||||
case 0x2000: // pulse 2
|
||||
m_vrc6snd->write(space, (add_lines>>8) | 0x100, data);
|
||||
break;
|
||||
case 0x3000:
|
||||
if (add_lines == 0x300)
|
||||
@ -588,8 +597,10 @@ WRITE8_MEMBER(nes_konami_vrc6_device::write_h)
|
||||
case 0x0c: set_nt_mirroring(PPU_MIRROR_HIGH); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", (offset & 0x7000) | add_lines, data));
|
||||
else // saw
|
||||
{
|
||||
m_vrc6snd->write(space, (add_lines>>8) | 0x200, data);
|
||||
}
|
||||
break;
|
||||
case 0x5000:
|
||||
case 0x6000:
|
||||
@ -623,6 +634,25 @@ WRITE8_MEMBER(nes_konami_vrc6_device::write_h)
|
||||
}
|
||||
}
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( vrc6 )
|
||||
|
||||
// additional sound hardware
|
||||
MCFG_SPEAKER_STANDARD_MONO("addon")
|
||||
|
||||
MCFG_SOUND_ADD("vrc6snd", VRC6, N2A03_DEFAULTCLOCK)
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
//-------------------------------------------------
|
||||
// machine_config_additions - device-specific
|
||||
// machine configurations
|
||||
//-------------------------------------------------
|
||||
|
||||
machine_config_constructor nes_konami_vrc6_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( vrc6 );
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
|
||||
Konami VRC7
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define __NES_KONAMI_H
|
||||
|
||||
#include "machine/nes_nxrom.h"
|
||||
#include "audio/vrc6.h"
|
||||
|
||||
|
||||
// ======================> nes_konami_vrc1_device
|
||||
@ -111,9 +112,11 @@ public:
|
||||
nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual machine_config_constructor device_mconfig_additions() const;
|
||||
virtual DECLARE_WRITE8_MEMBER(write_h);
|
||||
|
||||
// TODO: emulate sound capabilities!
|
||||
required_device<vrc6snd_device> m_vrc6snd;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1425,6 +1425,7 @@ $(MESSOBJ)/nintendo.a: \
|
||||
$(MESS_MACHINE)/nes_jy.o \
|
||||
$(MESS_MACHINE)/nes_kaiser.o \
|
||||
$(MESS_MACHINE)/nes_konami.o \
|
||||
$(MESS_AUDIO)/vrc6.o \
|
||||
$(MESS_MACHINE)/nes_legacy.o \
|
||||
$(MESS_MACHINE)/nes_multigame.o \
|
||||
$(MESS_MACHINE)/nes_namcot.o \
|
||||
|
Loading…
Reference in New Issue
Block a user