prepare for the last chips for 0.6pre1

YMZ280B is counted. don't worry.
This commit is contained in:
tildearrow 2022-05-20 02:43:39 -05:00
parent 0ef0296b7d
commit 251734bd04
13 changed files with 1011 additions and 4 deletions

View file

@ -256,6 +256,7 @@ extern/opl/opl3.c
src/engine/platform/sound/sn76496.cpp src/engine/platform/sound/sn76496.cpp
src/engine/platform/sound/ay8910.cpp src/engine/platform/sound/ay8910.cpp
src/engine/platform/sound/saa1099.cpp src/engine/platform/sound/saa1099.cpp
src/engine/platform/sound/namco.cpp
src/engine/platform/sound/gb/apu.c src/engine/platform/sound/gb/apu.c
src/engine/platform/sound/gb/timing.c src/engine/platform/sound/gb/timing.c
src/engine/platform/sound/pce_psg.cpp src/engine/platform/sound/pce_psg.cpp

View file

@ -223,6 +223,8 @@ size | description
| - 0xb7: PC-98 extended - 19 channels | - 0xb7: PC-98 extended - 19 channels
| - 0xb8: YMZ280B - 8 channels | - 0xb8: YMZ280B - 8 channels
| - 0xb9: Namco WSG - 3 channels | - 0xb9: Namco WSG - 3 channels
| - 0xba: Namco 15xx - 8 channels
| - 0xbb: Namco CUS30 - 8 channels
| - 0xde: YM2610B extended - 19 channels | - 0xde: YM2610B extended - 19 channels
| - 0xe0: QSound - 19 channels | - 0xe0: QSound - 19 channels
| - 0xfd: Dummy System - 8 channels | - 0xfd: Dummy System - 8 channels
@ -407,6 +409,7 @@ size | description
| - 28: MultiPCM | - 28: MultiPCM
| - 29: SNES | - 29: SNES
| - 30: Sound Unit | - 30: Sound Unit
| - 31: Namco WSG
1 | reserved 1 | reserved
STR | instrument name STR | instrument name
--- | **FM instrument data** --- | **FM instrument data**

View file

@ -58,6 +58,7 @@ enum DivInstrumentType: unsigned short {
DIV_INS_MULTIPCM=28, DIV_INS_MULTIPCM=28,
DIV_INS_SNES=29, DIV_INS_SNES=29,
DIV_INS_SU=30, DIV_INS_SU=30,
DIV_INS_NAMCO=31,
DIV_INS_MAX, DIV_INS_MAX,
DIV_INS_NULL DIV_INS_NULL
}; };

View file

@ -581,7 +581,7 @@ YM2203 English datasheet: http://www.appleii-box.de/APPLE2/JonasCard/YM2203%20da
YM2203 Japanese datasheet contents, translated: http://www.larwe.com/technical/chip_ym2203.html YM2203 Japanese datasheet contents, translated: http://www.larwe.com/technical/chip_ym2203.html
*/ */
// additional modifications by tildearrow and Eulous for furnace (particularly AY8930 emulation) // additional modifications by tildearrow, Eulous, cam900 and Grauw for furnace (particularly AY8930 emulation)
#include "ay8910.h" #include "ay8910.h"
#include <stdio.h> #include <stdio.h>

View file

@ -0,0 +1,804 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria,Aaron Giles
/***************************************************************************
NAMCO sound driver.
This driver handles the four known types of NAMCO wavetable sounds:
- 3-voice mono (PROM-based design: Pac-Man, Pengo, Dig Dug, etc)
- 8-voice quadrophonic (Pole Position 1, Pole Position 2)
- 8-voice mono (custom 15XX: Mappy, Dig Dug 2, etc)
- 8-voice stereo (System 1)
The 15XX custom does not have a DAC of its own; instead, it streams
the 4-bit PROM data directly into the 99XX custom DAC. Most pre-99XX
(and pre-15XX) Namco games use a LS273 latch (cleared when sound is
disabled), a 4.7K/2.2K/1K/470 resistor-weighted DAC, and a 4066 and
second group of resistors (10K/22K/47K/100K) for volume control.
Pole Position does more complicated sound mixing: a 4051 multiplexes
wavetable sound with four signals derived from the 52XX and 54XX, the
selected signal is distributed to four volume control sections, and
finally the engine noise is mixed into all four channels. The later
CUS30 also uses the 99XX DAC, or two 99XX in the optional 16-channel
stereo configuration, but it uses no PROM and delivers its own samples.
The CUS30 has been decapped and verified to be a ULA.
***************************************************************************/
// additional modifications by tildearrow for furnace
#include "namco.h"
#include <string.h>
/* quality parameter: internal sample rate is 192 KHz, output is 48 KHz */
#define INTERNAL_RATE 192000
/* 16 bits: sample bits of the stream buffer */
/* 4 bits: volume */
/* 4 bits: prom sample bits */
#define MIXLEVEL (1 << (16 - 4 - 4))
/* stream output level */
#define OUTPUT_LEVEL(n) ((n) * MIXLEVEL / m_voices)
/* a position of waveform sample */
#define WAVEFORM_POSITION(n) (((n) >> m_f_fracbits) & 0x1f)
namco_audio_device::namco_audio_device(uint32_t clock)
: m_wave_ptr(NULL)
, m_last_channel(nullptr)
, m_wavedata(nullptr)
, m_wave_size(0)
, m_sound_enable(false)
, m_namco_clock(0)
, m_sample_rate(0)
, m_f_fracbits(0)
, m_voices(0)
, m_stereo(false)
{
}
namco_device::namco_device(uint32_t clock)
: namco_audio_device(clock)
{
}
namco_15xx_device::namco_15xx_device(uint32_t clock)
:namco_audio_device(clock)
{
}
namco_cus30_device::namco_cus30_device(uint32_t clock)
: namco_audio_device(clock)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void namco_audio_device::device_start()
{
/* extract globals from the interface */
m_last_channel = m_channel_list + m_voices;
/* build the waveform table */
build_decoded_waveform(m_wave_ptr);
/* start with sound enabled, many games don't have a sound enable register */
m_sound_enable = true;
/* reset all the voices */
for (sound_channel *voice = m_channel_list; voice < m_last_channel; voice++)
{
voice->frequency = 0;
voice->volume[0] = voice->volume[1] = 0;
voice->waveform_select = 0;
voice->counter = 0;
voice->noise_sw = 0;
voice->noise_state = 0;
voice->noise_seed = 1;
voice->noise_counter = 0;
voice->noise_hold = 0;
}
}
void namco_device::device_start()
{
namco_audio_device::device_start();
}
void namco_15xx_device::device_start()
{
namco_audio_device::device_start();
}
void namco_audio_device::device_clock_changed()
{
int clock_multiple;
/* adjust internal clock */
m_namco_clock = clock();
for (clock_multiple = 0; m_namco_clock < INTERNAL_RATE; clock_multiple++)
m_namco_clock *= 2;
m_f_fracbits = clock_multiple + 15;
/* adjust output clock */
m_sample_rate = m_namco_clock;
//logerror("Namco: freq fractional bits = %d: internal freq = %d, output freq = %d\n", m_f_fracbits, m_namco_clock, m_sample_rate);
}
/* update the decoded waveform data */
void namco_audio_device::update_namco_waveform(int offset, uint8_t data)
{
if (m_wave_size == 1)
{
int16_t wdata;
int v;
/* use full byte, first 4 high bits, then low 4 bits */
for (v = 0; v < (int)MAX_VOLUME; v++)
{
wdata = ((data >> 4) & 0x0f) - 8;
m_waveform[v][offset * 2] = OUTPUT_LEVEL(wdata * v);
wdata = (data & 0x0f) - 8;
m_waveform[v][offset * 2 + 1] = OUTPUT_LEVEL(wdata * v);
}
}
else
{
int v;
/* use only low 4 bits */
for (v = 0; v < (int)MAX_VOLUME; v++)
m_waveform[v][offset] = OUTPUT_LEVEL(((data & 0x0f) - 8) * v);
}
}
/* build the decoded waveform table */
void namco_audio_device::build_decoded_waveform(uint8_t *rgnbase)
{
if (rgnbase != nullptr)
m_wavedata = rgnbase;
else
{
m_wavedata = m_waveram_alloc;
}
for (int offset = 0; offset < 256; offset++)
update_namco_waveform(offset, m_wavedata[offset]);
}
/* generate sound by oversampling */
uint32_t namco_audio_device::namco_update_one(short* buffer, int size, const int16_t *wave, uint32_t counter, uint32_t freq)
{
for (int sampindex = 0; sampindex < size; sampindex++)
{
buffer[sampindex]=wave[WAVEFORM_POSITION(counter)];
counter += freq;
}
return counter;
}
void namco_audio_device::sound_enable_w(int state)
{
m_sound_enable = state;
}
/********************************************************************************/
/* pacman register map
0x05: ch 0 waveform select
0x0a: ch 1 waveform select
0x0f: ch 2 waveform select
0x10: ch 0 the first voice has extra frequency bits
0x11-0x14: ch 0 frequency
0x15: ch 0 volume
0x16-0x19: ch 1 frequency
0x1a: ch 1 volume
0x1b-0x1e: ch 2 frequency
0x1f: ch 2 volume
*/
void namco_device::pacman_sound_w(int offset, uint8_t data)
{
sound_channel *voice;
int ch;
data &= 0x0f;
if (m_soundregs[offset] == data)
return;
/* set the register */
m_soundregs[offset] = data;
if (offset < 0x10)
ch = (offset - 5) / 5;
else if (offset == 0x10)
ch = 0;
else
ch = (offset - 0x11) / 5;
if (ch >= m_voices)
return;
/* recompute the voice parameters */
voice = m_channel_list + ch;
switch (offset - ch * 5)
{
case 0x05:
voice->waveform_select = data & 7;
break;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
/* the frequency has 20 bits */
/* the first voice has extra frequency bits */
voice->frequency = (ch == 0) ? m_soundregs[0x10] : 0;
voice->frequency += (m_soundregs[ch * 5 + 0x11] << 4);
voice->frequency += (m_soundregs[ch * 5 + 0x12] << 8);
voice->frequency += (m_soundregs[ch * 5 + 0x13] << 12);
voice->frequency += (m_soundregs[ch * 5 + 0x14] << 16); /* always 0 */
break;
case 0x15:
voice->volume[0] = data;
break;
}
}
void namco_cus30_device::pacman_sound_w(int offset, uint8_t data)
{
sound_channel *voice;
int ch;
uint8_t *soundregs = &m_wavedata[0x100];
data &= 0x0f;
if (soundregs[offset] == data)
return;
/* set the register */
soundregs[offset] = data;
if (offset < 0x10)
ch = (offset - 5) / 5;
else if (offset == 0x10)
ch = 0;
else
ch = (offset - 0x11) / 5;
if (ch >= m_voices)
return;
/* recompute the voice parameters */
voice = m_channel_list + ch;
switch (offset - ch * 5)
{
case 0x05:
voice->waveform_select = data & 7;
break;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
/* the frequency has 20 bits */
/* the first voice has extra frequency bits */
voice->frequency = (ch == 0) ? soundregs[0x10] : 0;
voice->frequency += (soundregs[ch * 5 + 0x11] << 4);
voice->frequency += (soundregs[ch * 5 + 0x12] << 8);
voice->frequency += (soundregs[ch * 5 + 0x13] << 12);
voice->frequency += (soundregs[ch * 5 + 0x14] << 16); /* always 0 */
break;
case 0x15:
voice->volume[0] = data;
break;
}
}
/********************************************************************************/
/* polepos register map
Note: even if there are 8 voices, the game doesn't use the first 2 because
it select the 54XX/52XX outputs on those channels
0x00-0x01 ch 0 frequency
0x02 ch 0 xxxx---- GAIN 2 volume
0x03 ch 0 xxxx---- GAIN 3 volume
----xxxx GAIN 4 volume
0x04-0x07 ch 1
.
.
.
0x1c-0x1f ch 7
0x23 ch 0 xxxx---- GAIN 1 volume
-----xxx waveform select
----x-xx channel output select
0-7 (all the same, shared with waveform select) = wave
8 = CHANL1 (54XX pins 17-20)
9 = CHANL2 (54XX pins 8-11)
A = CHANL3 (54XX pins 4-7)
B = CHANL4 (52XX)
0x27 ch 1
0x2b ch 2
0x2f ch 3
0x33 ch 4
0x37 ch 5
0x3b ch 6
0x3f ch 7
*/
uint8_t namco_device::polepos_sound_r(int offset)
{
return m_soundregs[offset];
}
void namco_device::polepos_sound_w(int offset, uint8_t data)
{
sound_channel *voice;
int ch;
if (m_soundregs[offset] == data)
return;
/* set the register */
m_soundregs[offset] = data;
ch = (offset & 0x1f) / 4;
/* recompute the voice parameters */
voice = m_channel_list + ch;
switch (offset & 0x23)
{
case 0x00:
case 0x01:
/* the frequency has 16 bits */
voice->frequency = m_soundregs[ch * 4 + 0x00];
voice->frequency += m_soundregs[ch * 4 + 0x01] << 8;
break;
case 0x23:
voice->waveform_select = data & 7;
[[fallthrough]];
case 0x02:
case 0x03:
voice->volume[0] = voice->volume[1] = 0;
// front speakers ?
voice->volume[0] += m_soundregs[ch * 4 + 0x03] >> 4;
voice->volume[1] += m_soundregs[ch * 4 + 0x03] & 0x0f;
// rear speakers ?
voice->volume[0] += m_soundregs[ch * 4 + 0x23] >> 4;
voice->volume[1] += m_soundregs[ch * 4 + 0x02] >> 4;
voice->volume[0] /= 2;
voice->volume[1] /= 2;
/* if 54XX or 52XX selected, silence this voice */
if (m_soundregs[ch * 4 + 0x23] & 8)
voice->volume[0] = voice->volume[1] = 0;
break;
}
}
/********************************************************************************/
/* 15XX register map
0x03 ch 0 volume
0x04-0x05 ch 0 frequency
0x06 ch 0 waveform select & frequency
0x0b ch 1 volume
0x0c-0x0d ch 1 frequency
0x0e ch 1 waveform select & frequency
.
.
.
0x3b ch 7 volume
0x3c-0x3d ch 7 frequency
0x3e ch 7 waveform select & frequency
Grobda also stuffs values into register offset 0x02 with a frequency of zero
to make 15XX channels act like a 4-bit DAC instead of waveform voices. This
has been emulated by allowing writes to set the upper counter bits directly.
Possibly offsets 0x00 and 0x01 can be used to set the fractional bits.
*/
template <typename T, typename U> constexpr T make_bitmask(U n)
{
return T((n < (int)(8 * sizeof(T)) ? (std::make_unsigned_t<T>(1) << n) : std::make_unsigned_t<T>(0)) - 1);
}
void namco_15xx_device::namco_15xx_w(int offset, uint8_t data)
{
sound_channel *voice;
int ch;
if (m_soundregs[offset] == data)
return;
/* set the register */
m_soundregs[offset] = data;
ch = offset / 8;
if (ch >= m_voices)
return;
/* recompute the voice parameters */
voice = m_channel_list + ch;
switch (offset - ch * 8)
{
case 0x02:
voice->counter &= make_bitmask<uint32_t>(m_f_fracbits);
voice->counter |= uint32_t(data & 0x1f) << m_f_fracbits;
break;
case 0x03:
voice->volume[0] = data & 0x0f;
break;
case 0x06:
voice->waveform_select = (data >> 4) & 7;
[[fallthrough]];
case 0x04:
case 0x05:
/* the frequency has 20 bits */
voice->frequency = m_soundregs[ch * 8 + 0x04];
voice->frequency += m_soundregs[ch * 8 + 0x05] << 8;
voice->frequency += (m_soundregs[ch * 8 + 0x06] & 15) << 16; /* high bits are from here */
break;
}
}
/********************************************************************************/
/* namcos1 register map
0x00 ch 0 left volume
0x01 ch 0 waveform select & frequency
0x02-0x03 ch 0 frequency
0x04 ch 0 right volume AND
0x04 ch 1 noise sw
0x08 ch 1 left volume
0x09 ch 1 waveform select & frequency
0x0a-0x0b ch 1 frequency
0x0c ch 1 right volume AND
0x0c ch 2 noise sw
.
.
.
0x38 ch 7 left volume
0x39 ch 7 waveform select & frequency
0x3a-0x3b ch 7 frequency
0x3c ch 7 right volume AND
0x3c ch 0 noise sw
*/
void namco_cus30_device::namcos1_sound_w(int offset, uint8_t data)
{
sound_channel *voice;
int ch;
int nssw;
/* verify the offset */
if (offset > 63)
{
//logerror("NAMCOS1 sound: Attempting to write past the 64 registers segment\n");
return;
}
uint8_t *soundregs = &m_wavedata[0x100];
if (soundregs[offset] == data)
return;
/* set the register */
soundregs[offset] = data;
ch = offset / 8;
if (ch >= m_voices)
return;
/* recompute the voice parameters */
voice = m_channel_list + ch;
switch (offset - ch * 8)
{
case 0x00:
voice->volume[0] = data & 0x0f;
break;
case 0x01:
voice->waveform_select = (data >> 4) & 15;
[[fallthrough]];
case 0x02:
case 0x03:
/* the frequency has 20 bits */
voice->frequency = (soundregs[ch * 8 + 0x01] & 15) << 16; /* high bits are from here */
voice->frequency += soundregs[ch * 8 + 0x02] << 8;
voice->frequency += soundregs[ch * 8 + 0x03];
break;
case 0x04:
voice->volume[1] = data & 0x0f;
nssw = ((data & 0x80) >> 7);
if (++voice == m_last_channel)
voice = m_channel_list;
voice->noise_sw = nssw;
break;
}
}
void namco_cus30_device::namcos1_cus30_w(int offset, uint8_t data)
{
if (offset < 0x100)
{
if (m_wavedata[offset] != data)
{
m_wavedata[offset] = data;
/* update the decoded waveform table */
update_namco_waveform(offset, data);
}
}
else if (offset < 0x140)
namcos1_sound_w(offset - 0x100,data);
else
m_wavedata[offset] = data;
}
uint8_t namco_cus30_device::namcos1_cus30_r(int offset)
{
return m_wavedata[offset];
}
uint8_t namco_15xx_device::sharedram_r(int offset)
{
return m_soundregs[offset];
}
void namco_15xx_device::sharedram_w(int offset, uint8_t data)
{
if (offset < 0x40)
namco_15xx_w(offset, data);
else
{
m_soundregs[offset] = data;
}
}
//-------------------------------------------------
// sound_stream_update - handle a stream update
//-------------------------------------------------
void namco_audio_device::sound_stream_update(short** outputs, int len)
{
if (m_stereo)
{
/* zap the contents of the buffers */
memset(outputs[0],0,len*sizeof(short));
memset(outputs[1],0,len*sizeof(short));
/* if no sound, we're done */
if (!m_sound_enable)
return;
/* loop over each voice and add its contribution */
for (sound_channel *voice = m_channel_list; voice < m_last_channel; voice++)
{
short* lmix = outputs[0];
short* rmix = outputs[1];
int lv = voice->volume[0];
int rv = voice->volume[1];
if (voice->noise_sw)
{
int f = voice->frequency & 0xff;
/* only update if we have non-zero volume */
if (lv || rv)
{
int hold_time = 1 << (m_f_fracbits - 16);
int hold = voice->noise_hold;
uint32_t delta = f << 4;
uint32_t c = voice->noise_counter;
int16_t l_noise_data = OUTPUT_LEVEL(0x07 * (lv >> 1));
int16_t r_noise_data = OUTPUT_LEVEL(0x07 * (rv >> 1));
int i;
/* add our contribution */
for (i = 0; i < len; i++)
{
int cnt;
if (voice->noise_state)
{
lmix[i]=l_noise_data;
rmix[i]=r_noise_data;
}
else
{
lmix[i]=-l_noise_data;
rmix[i]=-r_noise_data;
}
if (hold)
{
hold--;
continue;
}
hold = hold_time;
c += delta;
cnt = (c >> 12);
c &= (1 << 12) - 1;
for( ;cnt > 0; cnt--)
{
if ((voice->noise_seed + 1) & 2) voice->noise_state ^= 1;
if (voice->noise_seed & 1) voice->noise_seed ^= 0x28000;
voice->noise_seed >>= 1;
}
}
/* update the counter and hold time for this voice */
voice->noise_counter = c;
voice->noise_hold = hold;
}
}
else
{
/* save the counter for this voice */
uint32_t c = voice->counter;
/* only update if we have non-zero left volume */
if (lv)
{
const int16_t *lw = &m_waveform[lv][voice->waveform_select * 32];
/* generate sound into the buffer */
c = namco_update_one(lmix, len, lw, voice->counter, voice->frequency);
}
/* only update if we have non-zero right volume */
if (rv)
{
const int16_t *rw = &m_waveform[rv][voice->waveform_select * 32];
/* generate sound into the buffer */
c = namco_update_one(rmix, len, rw, voice->counter, voice->frequency);
}
/* update the counter for this voice */
voice->counter = c;
}
}
}
else
{
sound_channel *voice;
short* buffer = outputs[0];
/* zap the contents of the buffer */
memset(buffer,0,len*sizeof(short));
/* if no sound, we're done */
if (!m_sound_enable)
return;
/* loop over each voice and add its contribution */
for (voice = m_channel_list; voice < m_last_channel; voice++)
{
int v = voice->volume[0];
if (voice->noise_sw)
{
int f = voice->frequency & 0xff;
/* only update if we have non-zero volume */
if (v)
{
int hold_time = 1 << (m_f_fracbits - 16);
int hold = voice->noise_hold;
uint32_t delta = f << 4;
uint32_t c = voice->noise_counter;
int16_t noise_data = OUTPUT_LEVEL(0x07 * (v >> 1));
int i;
/* add our contribution */
for (i = 0; i < len; i++)
{
int cnt;
if (voice->noise_state)
buffer[i]=noise_data;
else
buffer[i]=-noise_data;
if (hold)
{
hold--;
continue;
}
hold = hold_time;
c += delta;
cnt = (c >> 12);
c &= (1 << 12) - 1;
for( ;cnt > 0; cnt--)
{
if ((voice->noise_seed + 1) & 2) voice->noise_state ^= 1;
if (voice->noise_seed & 1) voice->noise_seed ^= 0x28000;
voice->noise_seed >>= 1;
}
}
/* update the counter and hold time for this voice */
voice->noise_counter = c;
voice->noise_hold = hold;
}
}
else
{
/* only update if we have non-zero volume */
if (v)
{
const int16_t *w = &m_waveform[v][voice->waveform_select * 32];
/* generate sound into buffer and update the counter for this voice */
voice->counter = namco_update_one(buffer, len, w, voice->counter, voice->frequency);
}
}
}
}
}
void namco_device::sound_stream_update(short** outputs, int len)
{
namco_audio_device::sound_stream_update(outputs,len);
}
void namco_15xx_device::sound_stream_update(short** outputs, int len)
{
namco_audio_device::sound_stream_update(outputs,len);
}
void namco_cus30_device::sound_stream_update(short** outputs, int len)
{
namco_audio_device::sound_stream_update(outputs,len);
}

View file

@ -0,0 +1,130 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria,Aaron Giles
#ifndef MAME_SOUND_NAMCO_H
#define MAME_SOUND_NAMCO_H
#include <stdint.h>
#include <memory>
class namco_audio_device
{
public:
// configuration
void set_voices(int voices) { m_voices = voices; }
void set_stereo(bool stereo) { m_stereo = stereo; }
void sound_enable_w(int state);
protected:
static constexpr unsigned MAX_VOICES = 8;
static constexpr unsigned MAX_VOLUME = 16;
/* this structure defines the parameters for a channel */
struct sound_channel
{
uint32_t frequency;
uint32_t counter;
int32_t volume[2];
int32_t noise_sw;
int32_t noise_state;
int32_t noise_seed;
uint32_t noise_counter;
int32_t noise_hold;
int32_t waveform_select;
};
namco_audio_device(uint32_t clock);
// device-level overrides
void device_start();
void device_clock_changed();
// internal state
void build_decoded_waveform( uint8_t *rgnbase );
void update_namco_waveform(int offset, uint8_t data);
uint32_t namco_update_one(short* buffer, int size, const int16_t *wave, uint32_t counter, uint32_t freq);
/* waveform region */
uint8_t* m_wave_ptr;
/* data about the sound system */
sound_channel m_channel_list[MAX_VOICES];
sound_channel *m_last_channel;
uint8_t *m_wavedata;
/* global sound parameters */
int m_wave_size;
bool m_sound_enable;
int m_namco_clock;
int m_sample_rate;
int m_f_fracbits;
int m_voices; /* number of voices */
bool m_stereo; /* set to indicate stereo (e.g., System 1) */
uint8_t m_waveram_alloc[0x400];
/* decoded waveform table */
int16_t m_waveform[MAX_VOLUME][512];
virtual void sound_stream_update(short** outputs, int len);
};
class namco_device : public namco_audio_device
{
public:
namco_device(uint32_t clock);
void pacman_sound_w(int offset, uint8_t data);
uint8_t polepos_sound_r(int offset);
void polepos_sound_w(int offset, uint8_t data);
protected:
// device-level overrides
virtual void device_start();
virtual void sound_stream_update(short** outputs, int len);
private:
uint8_t m_soundregs[0x400];
};
class namco_15xx_device : public namco_audio_device
{
public:
namco_15xx_device(uint32_t clock);
void namco_15xx_w(int offset, uint8_t data);
uint8_t sharedram_r(int offset);
void sharedram_w(int offset, uint8_t data);
protected:
// device-level overrides
virtual void device_start();
virtual void sound_stream_update(short** outputs, int len);
private:
uint8_t m_soundregs[0x400];
};
class namco_cus30_device : public namco_audio_device
{
public:
namco_cus30_device(uint32_t clock);
void namcos1_cus30_w(int offset, uint8_t data); /* wavedata + sound registers + RAM */
uint8_t namcos1_cus30_r(int offset);
void namcos1_sound_w(int offset, uint8_t data);
void pacman_sound_w(int offset, uint8_t data);
protected:
virtual void sound_stream_update(short** outputs, int len);
};
#endif // MAME_SOUND_NAMCO_H

View file

@ -107,6 +107,9 @@ enum DivSystem {
DIV_SYSTEM_SOUND_UNIT, DIV_SYSTEM_SOUND_UNIT,
DIV_SYSTEM_MSM6295, DIV_SYSTEM_MSM6295,
DIV_SYSTEM_MSM6258, DIV_SYSTEM_MSM6258,
DIV_SYSTEM_NAMCO,
DIV_SYSTEM_NAMCO_15XX,
DIV_SYSTEM_NAMCO_CUS30,
DIV_SYSTEM_DUMMY DIV_SYSTEM_DUMMY
}; };

View file

@ -1966,9 +1966,42 @@ void DivEngine::registerSystems() {
{DIV_INS_AMIGA} {DIV_INS_AMIGA}
); );
sysDefs[DIV_SYSTEM_NAMCO]=new DivSysDef(
"Namco WSG", NULL, 0xb9, 0, 3, false, true, 0, false,
"a wavetable sound chip used in Pac-Man, among other early Namco arcade games.",
{"Channel 1", "Channel 2", "Channel 3"},
{"CH1", "CH2", "CH3"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
{DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO},
{},
waveOnlyEffectHandler
);
sysDefs[DIV_SYSTEM_NAMCO_15XX]=new DivSysDef(
"Namco 15XX WSG", NULL, 0xba, 0, 8, false, true, 0, false,
"successor of the original Namco WSG chip, used in later Namco arcade games.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
{DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO},
{},
waveOnlyEffectHandler
);
sysDefs[DIV_SYSTEM_NAMCO_CUS30]=new DivSysDef(
"Namco CUS30 WSG", NULL, 0xbb, 0, 8, false, true, 0, false,
"like Namco 15XX but with stereo sound.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
{DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO},
{},
waveOnlyEffectHandler
);
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef( sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false, "Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false,
"this is a system designed for testing purposes..", "this is a system designed for testing purposes.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"}, {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},

View file

@ -228,6 +228,10 @@ void FurnaceGUI::drawInsList() {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SU]); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SU]);
name=fmt::sprintf(ICON_FA_MICROCHIP " %.2X: %s##_INS%d",i,ins->name,i); name=fmt::sprintf(ICON_FA_MICROCHIP " %.2X: %s##_INS%d",i,ins->name,i);
break; break;
case DIV_INS_NAMCO:
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_NAMCO]);
name=fmt::sprintf(ICON_FA_PIE_CHART " %.2X: %s##_INS%d",i,ins->name,i);
break;
default: default:
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]);
name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i); name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i);

View file

@ -149,6 +149,7 @@ enum FurnaceGUIColors {
GUI_COLOR_INSTR_MULTIPCM, GUI_COLOR_INSTR_MULTIPCM,
GUI_COLOR_INSTR_SNES, GUI_COLOR_INSTR_SNES,
GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_SU,
GUI_COLOR_INSTR_NAMCO,
GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_INSTR_UNKNOWN,
GUI_COLOR_CHANNEL_FM, GUI_COLOR_CHANNEL_FM,
@ -937,6 +938,7 @@ class FurnaceGUI {
int horizontalDataView; int horizontalDataView;
int noMultiSystem; int noMultiSystem;
int oldMacroVSlider; int oldMacroVSlider;
int displayAllInsTypes;
unsigned int maxUndoSteps; unsigned int maxUndoSteps;
String mainFontPath; String mainFontPath;
String patFontPath; String patFontPath;
@ -1026,6 +1028,7 @@ class FurnaceGUI {
horizontalDataView(0), horizontalDataView(0),
noMultiSystem(0), noMultiSystem(0),
oldMacroVSlider(0), oldMacroVSlider(0),
displayAllInsTypes(0),
maxUndoSteps(100), maxUndoSteps(100),
mainFontPath(""), mainFontPath(""),
patFontPath(""), patFontPath(""),

View file

@ -79,7 +79,7 @@ const int vgmVersions[6]={
0x171 0x171
}; };
const char* insTypes[DIV_INS_MAX]={ const char* insTypes[DIV_INS_MAX+1]={
"Standard (SMS/NES)", "Standard (SMS/NES)",
"FM (4-operator)", "FM (4-operator)",
"Game Boy", "Game Boy",
@ -111,6 +111,8 @@ const char* insTypes[DIV_INS_MAX]={
"MultiPCM", "MultiPCM",
"SNES", "SNES",
"Sound Unit", "Sound Unit",
"Namco WSG",
NULL
}; };
const char* sampleDepths[17]={ const char* sampleDepths[17]={
@ -754,6 +756,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
D(GUI_COLOR_INSTR_MULTIPCM,"",ImVec4(1.0f,0.8f,0.1f,1.0f)), D(GUI_COLOR_INSTR_MULTIPCM,"",ImVec4(1.0f,0.8f,0.1f,1.0f)),
D(GUI_COLOR_INSTR_SNES,"",ImVec4(0.8f,0.7f,1.0f,1.0f)), D(GUI_COLOR_INSTR_SNES,"",ImVec4(0.8f,0.7f,1.0f,1.0f)),
D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)), D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)),
D(GUI_COLOR_INSTR_NAMCO,"",ImVec4(1.0f,1.0f,0.0f,1.0f)),
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)), D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)),
@ -877,6 +880,11 @@ const int availableSystems[]={
DIV_SYSTEM_MMC5, DIV_SYSTEM_MMC5,
DIV_SYSTEM_SCC, DIV_SYSTEM_SCC,
DIV_SYSTEM_SCC_PLUS, DIV_SYSTEM_SCC_PLUS,
DIV_SYSTEM_MSM6258,
DIV_SYSTEM_MSM6295,
DIV_SYSTEM_NAMCO,
DIV_SYSTEM_NAMCO_15XX,
DIV_SYSTEM_NAMCO_CUS30,
0 // don't remove this last one! 0 // don't remove this last one!
}; };

View file

@ -1404,7 +1404,15 @@ void FurnaceGUI::drawInsEdit() {
} }
*/ */
if (ImGui::BeginCombo("##Type",insTypes[insType])) { if (ImGui::BeginCombo("##Type",insTypes[insType])) {
for (DivInstrumentType i: e->getPossibleInsTypes()) { std::vector<DivInstrumentType> insTypeList;
if (settings.displayAllInsTypes) {
for (int i=0; insTypes[i]; i++) {
insTypeList.push_back((DivInstrumentType)i);
}
} else {
insTypeList=e->getPossibleInsTypes();
}
for (DivInstrumentType i: insTypeList) {
if (ImGui::Selectable(insTypes[i],insType==i)) { if (ImGui::Selectable(insTypes[i],insType==i)) {
ins->type=i; ins->type=i;

View file

@ -1368,6 +1368,7 @@ void FurnaceGUI::drawSettings() {
UI_COLOR_CONFIG(GUI_COLOR_INSTR_MULTIPCM,"MultiPCM"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_MULTIPCM,"MultiPCM");
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SNES,"SNES"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_SNES,"SNES");
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit");
UI_COLOR_CONFIG(GUI_COLOR_INSTR_NAMCO,"Namco WSG");
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown");
ImGui::TreePop(); ImGui::TreePop();
} }
@ -1797,6 +1798,7 @@ void FurnaceGUI::drawSettings() {
// these are the cheat codes: // these are the cheat codes:
// "Debug" - toggles mobile UI // "Debug" - toggles mobile UI
// "Nice Amiga cover of the song!" - enables hidden systems (YMU759/SoundUnit/Dummy) // "Nice Amiga cover of the song!" - enables hidden systems (YMU759/SoundUnit/Dummy)
// "42 63" - enables all instrument types
if (ImGui::BeginTabItem("Cheat Codes")) { if (ImGui::BeginTabItem("Cheat Codes")) {
ImVec2 settingsViewSize=ImGui::GetContentRegionAvail(); ImVec2 settingsViewSize=ImGui::GetContentRegionAvail();
settingsViewSize.y-=ImGui::GetFrameHeight()+ImGui::GetStyle().WindowPadding.y; settingsViewSize.y-=ImGui::GetFrameHeight()+ImGui::GetStyle().WindowPadding.y;
@ -1824,6 +1826,10 @@ void FurnaceGUI::drawSettings() {
mmlString[30]=":smile: :star_struck: :sunglasses: :ok_hand:"; mmlString[30]=":smile: :star_struck: :sunglasses: :ok_hand:";
settings.hiddenSystems=!settings.hiddenSystems; settings.hiddenSystems=!settings.hiddenSystems;
} }
if (checker==0xe888896b && checker1==0xbde) {
mmlString[30]="enabled all instrument types";
settings.displayAllInsTypes=!settings.displayAllInsTypes;
}
mmlString[31]=""; mmlString[31]="";
} }
@ -1944,6 +1950,7 @@ void FurnaceGUI::syncSettings() {
settings.horizontalDataView=e->getConfInt("horizontalDataView",0); settings.horizontalDataView=e->getConfInt("horizontalDataView",0);
settings.noMultiSystem=e->getConfInt("noMultiSystem",0); settings.noMultiSystem=e->getConfInt("noMultiSystem",0);
settings.oldMacroVSlider=e->getConfInt("oldMacroVSlider",0); settings.oldMacroVSlider=e->getConfInt("oldMacroVSlider",0);
settings.displayAllInsTypes=e->getConfInt("displayAllInsTypes",0);
clampSetting(settings.mainFontSize,2,96); clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96); clampSetting(settings.patFontSize,2,96);
@ -2018,6 +2025,7 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.horizontalDataView,0,1); clampSetting(settings.horizontalDataView,0,1);
clampSetting(settings.noMultiSystem,0,1); clampSetting(settings.noMultiSystem,0,1);
clampSetting(settings.oldMacroVSlider,0,1); clampSetting(settings.oldMacroVSlider,0,1);
clampSetting(settings.displayAllInsTypes,0,1);
settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys",""));
if (settings.initialSys.size()<4) { if (settings.initialSys.size()<4) {
@ -2140,6 +2148,7 @@ void FurnaceGUI::commitSettings() {
e->setConf("horizontalDataView",settings.horizontalDataView); e->setConf("horizontalDataView",settings.horizontalDataView);
e->setConf("noMultiSystem",settings.noMultiSystem); e->setConf("noMultiSystem",settings.noMultiSystem);
e->setConf("oldMacroVSlider",settings.oldMacroVSlider); e->setConf("oldMacroVSlider",settings.oldMacroVSlider);
e->setConf("displayAllInsTypes",settings.displayAllInsTypes);
// colors // colors
for (int i=0; i<GUI_COLOR_MAX; i++) { for (int i=0; i<GUI_COLOR_MAX; i++) {