mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-29 02:51:24 +00:00
AY8930: implement noise and/or mask
cannot confirm whether this behavior is accurate to hardware though... thanks Eulous for details on this!
This commit is contained in:
parent
488bd45907
commit
5a7cf57aa2
6 changed files with 68 additions and 24 deletions
|
@ -64,6 +64,8 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_AY_ENVELOPE_LOW,
|
DIV_CMD_AY_ENVELOPE_LOW,
|
||||||
DIV_CMD_AY_ENVELOPE_HIGH,
|
DIV_CMD_AY_ENVELOPE_HIGH,
|
||||||
DIV_CMD_AY_ENVELOPE_SLIDE,
|
DIV_CMD_AY_ENVELOPE_SLIDE,
|
||||||
|
DIV_CMD_AY_NOISE_MASK_AND,
|
||||||
|
DIV_CMD_AY_NOISE_MASK_OR,
|
||||||
|
|
||||||
DIV_CMD_SAA_ENVELOPE,
|
DIV_CMD_SAA_ENVELOPE,
|
||||||
|
|
||||||
|
|
|
@ -271,6 +271,14 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_AY_ENVELOPE_SLIDE:
|
case DIV_CMD_AY_ENVELOPE_SLIDE:
|
||||||
ayEnvSlide[c.chan]=c.value;
|
ayEnvSlide[c.chan]=c.value;
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_AY_NOISE_MASK_AND:
|
||||||
|
ayNoiseAnd=c.value;
|
||||||
|
immWrite(0x19,ayNoiseAnd);
|
||||||
|
break;
|
||||||
|
case DIV_CMD_AY_NOISE_MASK_OR:
|
||||||
|
ayNoiseOr=c.value;
|
||||||
|
immWrite(0x1a,ayNoiseOr);
|
||||||
|
break;
|
||||||
case DIV_ALWAYS_SET_VOLUME:
|
case DIV_ALWAYS_SET_VOLUME:
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
@ -325,14 +333,8 @@ void DivPlatformAY8930::reset() {
|
||||||
pendingWrites[i]=-1;
|
pendingWrites[i]=-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBusy=60;
|
ayNoiseAnd=0;
|
||||||
dacMode=0;
|
ayNoiseOr=0;
|
||||||
dacPeriod=0;
|
|
||||||
dacPos=0;
|
|
||||||
dacRate=0;
|
|
||||||
dacSample=-1;
|
|
||||||
sampleBank=0;
|
|
||||||
|
|
||||||
delay=0;
|
delay=0;
|
||||||
|
|
||||||
extMode=false;
|
extMode=false;
|
||||||
|
|
|
@ -28,14 +28,7 @@ class DivPlatformAY8930: public DivDispatch {
|
||||||
};
|
};
|
||||||
std::queue<QueuedWrite> writes;
|
std::queue<QueuedWrite> writes;
|
||||||
ay8930_device* ay;
|
ay8930_device* ay;
|
||||||
unsigned char lastBusy;
|
unsigned char ayNoiseAnd, ayNoiseOr;
|
||||||
|
|
||||||
bool dacMode;
|
|
||||||
int dacPeriod;
|
|
||||||
int dacRate;
|
|
||||||
int dacPos;
|
|
||||||
int dacSample;
|
|
||||||
unsigned char sampleBank;
|
|
||||||
bool bank;
|
bool bank;
|
||||||
|
|
||||||
int delay;
|
int delay;
|
||||||
|
|
|
@ -581,6 +581,8 @@ 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)
|
||||||
|
|
||||||
#include "ay8910.h"
|
#include "ay8910.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -1019,8 +1021,10 @@ void ay8910_device::ay8910_write_reg(int r, int v)
|
||||||
m_tone[2].set_duty(m_regs[AY_CDUTY]);
|
m_tone[2].set_duty(m_regs[AY_CDUTY]);
|
||||||
break;
|
break;
|
||||||
case AY_NOISEAND:
|
case AY_NOISEAND:
|
||||||
|
m_noise_and=m_regs[AY_NOISEAND];
|
||||||
|
break;
|
||||||
case AY_NOISEOR:
|
case AY_NOISEOR:
|
||||||
// not implemented
|
m_noise_or=m_regs[AY_NOISEOR];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
m_regs[r] = 0; // reserved, set as 0
|
m_regs[r] = 0; // reserved, set as 0
|
||||||
|
@ -1080,13 +1084,36 @@ void ay8910_device::sound_stream_update(short** outputs, int outLen)
|
||||||
|
|
||||||
if (!m_prescale_noise || is_expanded_mode()) // AY8930 noise generator rate is twice compares as compatibility mode
|
if (!m_prescale_noise || is_expanded_mode()) // AY8930 noise generator rate is twice compares as compatibility mode
|
||||||
{
|
{
|
||||||
/* The Random Number Generator of the 8910 is a 17-bit shift */
|
if (is_expanded_mode()) {
|
||||||
/* register. The input to the shift register is bit0 XOR bit3 */
|
// This is called "Noise value" on the docs, but is a counter whose period is determined by the LFSR.
|
||||||
/* (bit0 is the output). This was verified on AY-3-8910 and YM2149 chips. */
|
// Using AND/OR gates, specific periods can be "filtered" out.
|
||||||
|
// A square wave can be generated through this behavior, which can be used for crude AM pulse width modulation.
|
||||||
// TODO : get actually algorithm for AY8930
|
|
||||||
m_rng ^= (((m_rng & 1) ^ ((m_rng >> 3) & 1)) << 17);
|
// The period of the noise is determined by this value.
|
||||||
m_rng >>= 1;
|
// The least significant byte of the LFSR is bitwise ANDed with the AND mask, and then bitwise ORed with the OR mask.
|
||||||
|
unsigned int noiseValuePeriod = ((m_rng & 0xFF & m_noise_and) | m_noise_or);
|
||||||
|
|
||||||
|
// Clock the noise value.
|
||||||
|
if (m_noise_value >= noiseValuePeriod) {
|
||||||
|
m_noise_value = 0;
|
||||||
|
|
||||||
|
// When everything is finally said and done, a 1bit latch is flipped.
|
||||||
|
// This is the final output of the noise, to be multiplied by the tone and envelope generators of the channel.
|
||||||
|
m_noise_latch ^= 1;
|
||||||
|
|
||||||
|
// The 17-bit LFSR is updated, using an XOR across bits 0 and 2.
|
||||||
|
unsigned int feedback = (m_rng & 1) ^ ((m_rng >> 2) & 1);
|
||||||
|
m_rng >>= 1;
|
||||||
|
m_rng |= (feedback << 16);
|
||||||
|
}
|
||||||
|
m_noise_value++;
|
||||||
|
} else {
|
||||||
|
/* The Random Number Generator of the 8910 is a 17-bit shift */
|
||||||
|
/* register. The input to the shift register is bit0 XOR bit3 */
|
||||||
|
/* (bit0 is the output). This was verified on AY-3-8910 and YM2149 chips. */
|
||||||
|
m_rng ^= (((m_rng & 1) ^ ((m_rng >> 3) & 1)) << 17);
|
||||||
|
m_rng >>= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1242,6 +1269,10 @@ void ay8910_device::ay8910_reset_ym()
|
||||||
m_register_latch = 0;
|
m_register_latch = 0;
|
||||||
m_rng = 1;
|
m_rng = 1;
|
||||||
m_mode = 0; // ay-3-8910 compatible mode
|
m_mode = 0; // ay-3-8910 compatible mode
|
||||||
|
m_noise_and = 0;
|
||||||
|
m_noise_or = 0;
|
||||||
|
m_noise_value = 0;
|
||||||
|
m_noise_latch = 0;
|
||||||
for (int chan = 0; chan < NUM_CHANNELS; chan++)
|
for (int chan = 0; chan < NUM_CHANNELS; chan++)
|
||||||
{
|
{
|
||||||
m_tone[chan].reset();
|
m_tone[chan].reset();
|
||||||
|
@ -1428,6 +1459,10 @@ ay8910_device::ay8910_device(device_type type, unsigned int clock,
|
||||||
m_prescale_noise(0),
|
m_prescale_noise(0),
|
||||||
m_count_noise(0),
|
m_count_noise(0),
|
||||||
m_rng(0),
|
m_rng(0),
|
||||||
|
m_noise_and(0),
|
||||||
|
m_noise_or(0),
|
||||||
|
m_noise_value(0),
|
||||||
|
m_noise_latch(0),
|
||||||
m_mode(0),
|
m_mode(0),
|
||||||
m_env_step_mask((!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? 0x0f : 0x1f),
|
m_env_step_mask((!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? 0x0f : 0x1f),
|
||||||
m_step( (!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? 2 : 1),
|
m_step( (!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? 2 : 1),
|
||||||
|
|
|
@ -292,6 +292,10 @@ private:
|
||||||
unsigned char m_prescale_noise;
|
unsigned char m_prescale_noise;
|
||||||
int m_count_noise;
|
int m_count_noise;
|
||||||
int m_rng;
|
int m_rng;
|
||||||
|
unsigned int m_noise_and;
|
||||||
|
unsigned int m_noise_or;
|
||||||
|
unsigned int m_noise_value;
|
||||||
|
unsigned int m_noise_latch;
|
||||||
unsigned char m_mode;
|
unsigned char m_mode;
|
||||||
unsigned char m_env_step_mask;
|
unsigned char m_env_step_mask;
|
||||||
/* init parameters ... */
|
/* init parameters ... */
|
||||||
|
|
|
@ -76,6 +76,8 @@ const char* cmdName[DIV_CMD_MAX]={
|
||||||
"AY_ENVELOPE_LOW",
|
"AY_ENVELOPE_LOW",
|
||||||
"AY_ENVELOPE_HIGH",
|
"AY_ENVELOPE_HIGH",
|
||||||
"AY_ENVELOPE_SLIDE",
|
"AY_ENVELOPE_SLIDE",
|
||||||
|
"AY_NOISE_MASK_AND",
|
||||||
|
"AY_NOISE_MASK_OR",
|
||||||
|
|
||||||
"SAA_ENVELOPE",
|
"SAA_ENVELOPE",
|
||||||
|
|
||||||
|
@ -359,6 +361,12 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
||||||
case 0x26: // envelope slide down
|
case 0x26: // envelope slide down
|
||||||
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal));
|
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal));
|
||||||
break;
|
break;
|
||||||
|
case 0x27: // noise and mask
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_AND,ch,effectVal));
|
||||||
|
break;
|
||||||
|
case 0x28: // noise or mask
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_OR,ch,effectVal));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_SAA1099:
|
case DIV_SYSTEM_SAA1099:
|
||||||
|
|
Loading…
Reference in a new issue