add AY-3-8910 platform!

this paves the way for eventual AY-3-8930 platform...
This commit is contained in:
tildearrow 2022-01-13 02:52:19 -05:00
parent 2fcb474544
commit 0b352ecd9a
9 changed files with 2372 additions and 3 deletions

View file

@ -65,6 +65,7 @@ src/log.cpp
extern/Nuked-OPN2/ym3438.c
extern/opm/opm.c
src/engine/platform/sound/sn76496.cpp
src/engine/platform/sound/ay8910.cpp
src/engine/platform/sound/gb/apu.c
src/engine/platform/sound/gb/timing.c
src/engine/platform/sound/pce_psg.cpp
@ -116,6 +117,7 @@ src/engine/platform/c64.cpp
src/engine/platform/arcade.cpp
src/engine/platform/ym2610.cpp
src/engine/platform/ym2610ext.cpp
src/engine/platform/ay.cpp
src/engine/platform/dummy.cpp)
set(GUI_SOURCES

View file

@ -9,6 +9,7 @@
#include "platform/arcade.h"
#include "platform/ym2610.h"
#include "platform/ym2610ext.h"
#include "platform/ay.h"
#include "platform/dummy.h"
#include "../ta-log.h"
@ -112,6 +113,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
case DIV_SYSTEM_YM2610_EXT:
dispatch=new DivPlatformYM2610Ext;
break;
case DIV_SYSTEM_AY8910:
dispatch=new DivPlatformAY8910;
break;
default:
logW("this system is not supported yet! using dummy platform.\n");
dispatch=new DivPlatformDummy;

357
src/engine/platform/ay.cpp Normal file
View file

@ -0,0 +1,357 @@
#include "ay.h"
#include "../engine.h"
#include "sound/ay8910.h"
#include <string.h>
#include <math.h>
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v);}
#define PSG_FREQ_BASE 7640.0f
void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) {
if (ayBufLen<len) {
ayBufLen=len;
for (int i=0; i<3; i++) {
delete[] ayBuf[i];
ayBuf[i]=new short[ayBufLen];
}
}
while (!writes.empty()) {
QueuedWrite w=writes.front();
ay->address_w(w.addr);
ay->data_w(w.val);
writes.pop();
}
ay->sound_stream_update(ayBuf,len);
for (size_t i=0; i<len; i++) {
bufL[i+start]=ayBuf[0][i]+ayBuf[1][i]+ayBuf[2][i];
bufR[i+start]=ayBuf[0][i]+ayBuf[1][i]+ayBuf[2][i];
}
//static int os[2];
/*for (size_t h=start; h<start+len; h++) {
os[0]=0; os[1]=0;
if (!writes.empty()) {
if (--delay<1) {
QueuedWrite& w=writes.front();
fm->write(0x0+((w.addr>>8)<<1),w.addr);
fm->write(0x1+((w.addr>>8)<<1),w.val);
writes.pop();
delay=4;
}
}
fm->generate(&fmout);
os[0]=fmout.data[0]+(fmout.data[2]>>1);
if (os[0]<-32768) os[0]=-32768;
if (os[0]>32767) os[0]=32767;
os[1]=fmout.data[1]+(fmout.data[2]>>1);
if (os[1]<-32768) os[1]=-32768;
if (os[1]>32767) os[1]=32767;
bufL[h]=os[0];
bufR[h]=os[1];
}*/
}
void DivPlatformAY8910::tick() {
// PSG
for (int i=0; i<3; i++) {
chan[i].std.next();
if (chan[i].std.hadVol) {
chan[i].outVol=chan[i].std.vol-(15-chan[i].vol);
if (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) {
rWrite(0x08+i,0);
} else {
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
}
}
if (chan[i].std.hadArp) {
if (!chan[i].inPorta) {
if (chan[i].std.arpMode) {
chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].std.arp)/12.0f)));
} else {
chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].note+chan[i].std.arp-12)/12.0f)));
}
}
chan[i].freqChanged=true;
} else {
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].note)/12.0f)));
chan[i].freqChanged=true;
}
}
if (chan[i].std.hadDuty) {
rWrite(0x06,31-chan[i].std.duty);
}
if (chan[i].std.hadWave) {
chan[i].psgMode&=4;
chan[i].psgMode|=(chan[i].std.wave+1)&3;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
if (chan[i].freq>4095) chan[i].freq=4095;
if (chan[i].keyOn) {
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
//rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
}
if (chan[i].keyOff) {
rWrite(0x08+i,0);
}
rWrite((i)<<1,chan[i].freq&0xff);
rWrite(1+((i)<<1),chan[i].freq>>8);
if (chan[i].keyOn) chan[i].keyOn=false;
if (chan[i].keyOff) chan[i].keyOff=false;
chan[i].freqChanged=false;
}
}
rWrite(0x07,
~((chan[0].psgMode&1)|
((chan[1].psgMode&1)<<1)|
((chan[2].psgMode&1)<<2)|
((chan[0].psgMode&2)<<2)|
((chan[1].psgMode&2)<<3)|
((chan[2].psgMode&2)<<4)));
if (ayEnvSlide!=0) {
ayEnvSlideLow+=ayEnvSlide;
while (ayEnvSlideLow>7) {
ayEnvSlideLow-=8;
if (ayEnvPeriod<0xffff) {
ayEnvPeriod++;
immWrite(0x0b,ayEnvPeriod);
immWrite(0x0c,ayEnvPeriod>>8);
}
}
while (ayEnvSlideLow<-7) {
ayEnvSlideLow+=8;
if (ayEnvPeriod>0) {
ayEnvPeriod--;
immWrite(0x0b,ayEnvPeriod);
immWrite(0x0c,ayEnvPeriod>>8);
}
}
}
for (int i=0; i<16; i++) {
if (pendingWrites[i]!=oldWrites[i]) {
immWrite(i,pendingWrites[i]&0xff);
oldWrites[i]=pendingWrites[i];
}
}
}
int DivPlatformAY8910::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].std.init(ins);
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
} else {
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
}
break;
}
case DIV_CMD_NOTE_OFF:
chan[c.chan].keyOff=true;
chan[c.chan].active=false;
chan[c.chan].std.init(NULL);
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.hasVol) {
chan[c.chan].outVol=c.value;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
} else {
if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
}
break;
break;
}
case DIV_CMD_GET_VOLUME: {
return chan[c.chan].vol;
break;
}
case DIV_CMD_INSTRUMENT:
if (chan[c.chan].ins!=c.value) {
chan[c.chan].insChanged=true;
}
chan[c.chan].ins=c.value;
break;
case DIV_CMD_PITCH: {
chan[c.chan].pitch=c.value;
chan[c.chan].freqChanged=true;
break;
}
case DIV_CMD_NOTE_PORTA: {
int destFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value2/12.0f)));
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value;
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value;
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
}
chan[c.chan].freqChanged=true;
if (return2) {
chan[c.chan].inPorta=false;
return 2;
}
break;
}
case DIV_CMD_LEGATO: {
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].freqChanged=true;
break;
}
case DIV_CMD_STD_NOISE_FREQ:
rWrite(0x06,31-c.value);
break;
case DIV_CMD_AY_ENVELOPE_SET:
ayEnvMode=c.value>>4;
rWrite(0x0d,ayEnvMode);
if (c.value&15) {
chan[c.chan].psgMode|=4;
} else {
chan[c.chan].psgMode&=~4;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
} else {
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
}
break;
case DIV_CMD_AY_ENVELOPE_LOW:
ayEnvPeriod&=0xff00;
ayEnvPeriod|=c.value;
immWrite(0x0b,ayEnvPeriod);
immWrite(0x0c,ayEnvPeriod>>8);
break;
case DIV_CMD_AY_ENVELOPE_HIGH:
ayEnvPeriod&=0xff;
ayEnvPeriod|=c.value<<8;
immWrite(0x0b,ayEnvPeriod);
immWrite(0x0c,ayEnvPeriod>>8);
break;
case DIV_CMD_AY_ENVELOPE_SLIDE:
ayEnvSlide=c.value;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;
case DIV_CMD_GET_VOLMAX:
return 15;
break;
case DIV_CMD_PRE_PORTA:
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:
break;
default:
//printf("WARNING: unimplemented command %d\n",c.cmd);
break;
}
return 1;
}
void DivPlatformAY8910::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
if (isMuted[ch]) {
rWrite(0x08+ch,0);
} else {
rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode&4)<<2));
}
}
void DivPlatformAY8910::forceIns() {
for (int i=0; i<3; i++) {
chan[i].insChanged=true;
}
immWrite(0x0b,ayEnvPeriod);
immWrite(0x0c,ayEnvPeriod>>8);
immWrite(0x0d,ayEnvMode);
}
void DivPlatformAY8910::reset() {
while (!writes.empty()) writes.pop();
ay->device_reset();
for (int i=0; i<3; i++) {
chan[i]=DivPlatformAY8910::Channel();
chan[i].vol=0x0f;
}
for (int i=0; i<16; i++) {
oldWrites[i]=-1;
pendingWrites[i]=-1;
}
lastBusy=60;
dacMode=0;
dacPeriod=0;
dacPos=0;
dacRate=0;
dacSample=-1;
sampleBank=0;
ayEnvPeriod=0;
ayEnvMode=0;
ayEnvSlide=0;
ayEnvSlideLow=0;
delay=0;
extMode=false;
}
bool DivPlatformAY8910::isStereo() {
return false;
}
bool DivPlatformAY8910::keyOffAffectsArp(int ch) {
return true;
}
int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, bool pal) {
parent=p;
skipRegisterWrites=false;
for (int i=0; i<3; i++) {
isMuted[i]=false;
}
if (pal) {
rate=250000;
} else {
rate=250000;
}
ay=new ay8910_device(rate);
ay->set_psg_type(ay8910_device::PSG_TYPE_AY);
ay->device_start();
ayBufLen=65536;
for (int i=0; i<3; i++) ayBuf[i]=new short[ayBufLen];
reset();
return 3;
}
void DivPlatformAY8910::quit() {
for (int i=0; i<3; i++) delete[] ayBuf[i];
delete ay;
}

65
src/engine/platform/ay.h Normal file
View file

@ -0,0 +1,65 @@
#ifndef _AY_H
#define _AY_H
#include "../dispatch.h"
#include "../macroInt.h"
#include <queue>
#include "sound/ay8910.h"
class DivPlatformAY8910: public DivDispatch {
protected:
struct Channel {
unsigned char freqH, freqL;
int freq, baseFreq, pitch;
unsigned char ins, note, psgMode;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
int vol, outVol;
unsigned char pan;
DivMacroInt std;
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
};
Channel chan[3];
bool isMuted[3];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
ay8910_device* ay;
unsigned char lastBusy;
bool dacMode;
int dacPeriod;
int dacRate;
int dacPos;
int dacSample;
unsigned char sampleBank;
int delay;
bool extMode;
short oldWrites[16];
short pendingWrites[16];
unsigned char ayEnvMode;
unsigned short ayEnvPeriod;
short ayEnvSlideLow;
short ayEnvSlide;
short* ayBuf[3];
size_t ayBufLen;
public:
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void reset();
void forceIns();
void tick();
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void quit();
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,371 @@
// license:BSD-3-Clause
// copyright-holders:Couriersud
#ifndef MAME_SOUND_AY8910_H
#define MAME_SOUND_AY8910_H
#define ALL_8910_CHANNELS -1
/* Internal resistance at Volume level 7. */
#define AY8910_INTERNAL_RESISTANCE (356)
#define YM2149_INTERNAL_RESISTANCE (353)
/*
* The following is used by all drivers not reviewed yet.
* This will like the old behavior, output between
* 0 and 7FFF
*/
#define AY8910_LEGACY_OUTPUT (0x01)
/*
* Specifying the next define will simulate the special
* cross channel mixing if outputs are tied together.
* The driver will only provide one stream in this case.
*/
#define AY8910_SINGLE_OUTPUT (0x02)
/*
* The following define is the default behavior.
* Output level 0 is 0V and 7ffff corresponds to 5V.
* Use this to specify that a discrete mixing stage
* follows.
*/
#define AY8910_DISCRETE_OUTPUT (0x04)
/*
* The following define causes the driver to output
* resistor values. Intended to be used for
* netlist interfacing.
*/
#define AY8910_RESISTOR_OUTPUT (0x08)
/*
* This define specifies the initial state of
* YM2149, YM3439, AY8930 pin 26 (SEL pin).
* By default it is set to high,
* compatible with AY8910.
*/
/* TODO: make it controllable while it's running (used by any hw???) */
#define YM2149_PIN26_HIGH (0x00) /* or N/C */
#define YM2149_PIN26_LOW (0x10)
#define BIT(x,n) (((x)>>(n))&1)
enum device_type {
AY8910,
AY8912,
AY8913,
AY8914,
AY8930,
YM2149,
YM3439,
YMZ284,
YMZ294,
SUNSOFT_5B_SOUND
};
class ay8910_device
{
public:
enum psg_type_t
{
PSG_TYPE_AY,
PSG_TYPE_YM
};
enum config_t
{
PSG_DEFAULT = 0x0,
PSG_PIN26_IS_CLKSEL = 0x1,
PSG_HAS_INTERNAL_DIVIDER = 0x2,
PSG_EXTENDED_ENVELOPE = 0x4,
PSG_HAS_EXPANDED_MODE = 0x8
};
// construction/destruction
ay8910_device(unsigned int clock);
// configuration helpers
void set_flags(int flags) { m_flags = flags; }
void set_psg_type(psg_type_t psg_type) { set_type(psg_type); }
void set_resistors_load(int res_load0, int res_load1, int res_load2) { m_res_load[0] = res_load0; m_res_load[1] = res_load1; m_res_load[2] = res_load2; }
unsigned char data_r() { return ay8910_read_ym(); }
void address_w(unsigned char data);
void data_w(unsigned char data);
// /RES
void reset_w(unsigned char data = 0) { ay8910_reset_ym(); }
// use this when BC1 == A0; here, BC1=0 selects 'data' and BC1=1 selects 'latch address'
void data_address_w(int offset, unsigned char data) { ay8910_write_ym(~offset & 1, data); } // note that directly connecting BC1 to A0 puts data on 0 and address on 1
// use this when BC1 == !A0; here, BC1=0 selects 'latch address' and BC1=1 selects 'data'
void address_data_w(int offset, unsigned char data) { ay8910_write_ym(offset & 1, data); }
// bc1=a0, bc2=a1
void write_bc1_bc2(int offset, unsigned char data);
struct ay_ym_param
{
double r_up;
double r_down;
int res_count;
double res[32];
};
struct mosfet_param
{
double m_Vth;
double m_Vg;
int m_count;
double m_Kn[32];
};
// internal interface for PSG component of YM device
// FIXME: these should be private, but vector06 accesses them directly
ay8910_device(device_type type, unsigned int clock, psg_type_t psg_type, int streams, int ioports, int feature = PSG_DEFAULT);
// device-level overrides
void device_start();
void device_reset();
// sound stream update overrides
void sound_stream_update(short** outputs, int outLen);
void ay8910_write_ym(int addr, unsigned char data);
unsigned char ay8910_read_ym();
void ay8910_reset_ym();
private:
static constexpr int NUM_CHANNELS = 3;
device_type chip_type;
/* register id's */
enum
{
AY_AFINE = 0x00,
AY_ACOARSE = 0x01,
AY_BFINE = 0x02,
AY_BCOARSE = 0x03,
AY_CFINE = 0x04,
AY_CCOARSE = 0x05,
AY_NOISEPER = 0x06,
AY_ENABLE = 0x07,
AY_AVOL = 0x08,
AY_BVOL = 0x09,
AY_CVOL = 0x0a,
AY_EAFINE = 0x0b,
AY_EACOARSE = 0x0c,
AY_EASHAPE = 0x0d,
AY_PORTA = 0x0e,
AY_PORTB = 0x0f,
AY_EBFINE = 0x10,
AY_EBCOARSE = 0x11,
AY_ECFINE = 0x12,
AY_ECCOARSE = 0x13,
AY_EBSHAPE = 0x14,
AY_ECSHAPE = 0x15,
AY_ADUTY = 0x16,
AY_BDUTY = 0x17,
AY_CDUTY = 0x18,
AY_NOISEAND = 0x19,
AY_NOISEOR = 0x1a,
AY_TEST = 0x1f
};
// structs
struct tone_t
{
unsigned int period;
unsigned char volume;
unsigned char duty;
int count;
unsigned char duty_cycle;
unsigned char output;
void reset()
{
period = 0;
volume = 0;
duty = 0;
count = 0;
duty_cycle = 0;
output = 0;
}
void set_period(unsigned char fine, unsigned char coarse)
{
period = fine | (coarse << 8);
}
void set_volume(unsigned char val)
{
volume = val;
}
void set_duty(unsigned char val)
{
duty = val;
}
};
struct envelope_t
{
unsigned int period;
int count;
signed char step;
unsigned int volume;
unsigned char hold, alternate, attack, holding;
void reset()
{
period = 0;
count = 0;
step = 0;
volume = 0;
hold = 0;
alternate = 0;
attack = 0;
holding = 0;
}
void set_period(unsigned char fine, unsigned char coarse)
{
period = fine | (coarse << 8);
}
void set_shape(unsigned char shape, unsigned char mask)
{
attack = (shape & 0x04) ? mask : 0x00;
if ((shape & 0x08) == 0)
{
/* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */
hold = 1;
alternate = attack;
}
else
{
hold = shape & 0x01;
alternate = shape & 0x02;
}
step = mask;
holding = 0;
volume = (step ^ attack);
}
};
// inlines
inline bool tone_enable(int chan) { return BIT(m_regs[AY_ENABLE], chan); }
inline unsigned char tone_volume(tone_t *tone) { return tone->volume & (is_expanded_mode() ? 0x1f : 0x0f); }
inline unsigned char tone_envelope(tone_t *tone) { return (tone->volume >> (is_expanded_mode() ? 5 : 4)) & ((m_feature & PSG_EXTENDED_ENVELOPE) ? 3 : 1); }
inline unsigned char tone_duty(tone_t *tone) { return is_expanded_mode() ? (tone->duty & 0x8 ? 0x8 : (tone->duty & 0xf)) : 0x4; }
inline unsigned char get_envelope_chan(int chan) { return is_expanded_mode() ? chan : 0; }
inline bool noise_enable(int chan) { return BIT(m_regs[AY_ENABLE], 3 + chan); }
inline unsigned char noise_period() { return is_expanded_mode() ? m_regs[AY_NOISEPER] & 0xff : m_regs[AY_NOISEPER] & 0x1f; }
inline unsigned char noise_output() { return m_rng & 1; }
inline bool is_expanded_mode() { return ((m_feature & PSG_HAS_EXPANDED_MODE) && ((m_mode & 0xe) == 0xa)); }
inline unsigned char get_register_bank() { return is_expanded_mode() ? (m_mode & 0x1) << 4 : 0; }
// internal helpers
void set_type(psg_type_t psg_type);
inline float mix_3D();
void ay8910_write_reg(int r, int v);
void build_mixer_table();
// internal state
psg_type_t m_type;
int m_streams;
int m_ioports;
int m_ready;
//sound_stream *m_channel;
bool m_active;
int m_register_latch;
unsigned char m_regs[16 * 2];
int m_last_enable;
tone_t m_tone[NUM_CHANNELS];
envelope_t m_envelope[NUM_CHANNELS];
unsigned char m_prescale_noise;
int m_count_noise;
int m_rng;
unsigned char m_mode;
unsigned char m_env_step_mask;
/* init parameters ... */
int m_step;
int m_zero_is_off;
unsigned char m_vol_enabled[NUM_CHANNELS];
const ay_ym_param *m_par;
const ay_ym_param *m_par_env;
short m_vol_table[NUM_CHANNELS][16];
short m_env_table[NUM_CHANNELS][32];
short m_vol3d_table[32*32*32*8];
int m_flags; /* Flags */
int m_feature; /* Chip specific features */
int m_res_load[3]; /* Load on channel in ohms */
};
class ay8912_device : public ay8910_device
{
public:
ay8912_device(unsigned int clock);
};
class ay8913_device : public ay8910_device
{
public:
ay8913_device(unsigned int clock);
};
class ay8914_device : public ay8910_device
{
public:
ay8914_device(unsigned int clock);
/* AY8914 handlers needed due to different register map */
unsigned char read(int offset);
void write(int offset, unsigned char data);
};
class ay8930_device : public ay8910_device
{
public:
ay8930_device(unsigned int clock);
};
class ym2149_device : public ay8910_device
{
public:
ym2149_device(unsigned int clock);
};
class ym3439_device : public ay8910_device
{
public:
ym3439_device(unsigned int clock);
};
class ymz284_device : public ay8910_device
{
public:
ymz284_device(unsigned int clock);
};
class ymz294_device : public ay8910_device
{
public:
ymz294_device(unsigned int clock);
};
class sunsoft_5b_sound_device : public ay8910_device
{
public:
sunsoft_5b_sound_device(unsigned int clock);
};
#endif // MAME_DEVICES_SOUND_AY8910_H

View file

@ -327,6 +327,31 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
return false;
}
break;
case DIV_SYSTEM_AY8910:
switch (effect) {
case 0x20: // mode
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
break;
case 0x21: // noise freq
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal));
break;
case 0x22: // envelope enable
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal));
break;
case 0x23: // envelope period low
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal));
break;
case 0x24: // envelope period high
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal));
break;
case 0x25: // envelope slide up
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,-effectVal));
break;
case 0x26: // envelope slide down
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal));
break;
}
break;
default:
return false;
}

View file

@ -1532,7 +1532,7 @@ void FurnaceGUI::drawPattern() {
ImGui::End();
}
const char* aboutLine[53]={
const char* aboutLine[54]={
"tildearrow",
"is proud to present",
"",
@ -1555,6 +1555,7 @@ const char* aboutLine[53]={
"Nuked-OPM & Nuked-OPN2 by Nuke.YKT",
"ymfm by Aaron Giles",
"MAME SN76496 by Nicola Salmoria",
"MAME AY-3-8910 by Couriersud",
"SameBoy by Lior Halphon",
"Mednafen PCE",
"puNES by FHorse",
@ -1637,7 +1638,7 @@ void FurnaceGUI::drawAbout() {
}
}
for (int i=0; i<53; i++) {
for (int i=0; i<54; i++) {
double posX=(scrW*dpiScale/2.0)+(sin(double(i)*0.5+double(aboutScroll)/90.0)*120*dpiScale)-(ImGui::CalcTextSize(aboutLine[i]).x*0.5);
double posY=(scrH-aboutScroll+42*i)*dpiScale;
if (posY<-80*dpiScale || posY>scrH*dpiScale) continue;
@ -1660,7 +1661,7 @@ void FurnaceGUI::drawAbout() {
ImGui::PopFont();
aboutScroll+=2;
if (++aboutSin>=2400) aboutSin=0;
if (aboutScroll>(42*53+scrH)) aboutScroll=-20;
if (aboutScroll>(42*54+scrH)) aboutScroll=-20;
}
ImGui::End();
}

View file

@ -110,6 +110,7 @@ bool pVersion(String) {
printf("- Nuked-OPN2 by Nuke.YKT (LGPLv2.1)\n");
printf("- ymfm by Aaron Giles (BSD 3-clause)\n");
printf("- MAME SN76496 emulation core by Nicola Salmoria (BSD 3-clause)\n");
printf("- MAME AY-3-8910 emulation core by Couriersud (BSD 3-clause)\n");
printf("- SameBoy by Lior Halphon (MIT)\n");
printf("- Mednafen PCE by Mednafen Team (GPLv2)\n");
printf("- puNES by FHorse (GPLv2)\n");