|
|
|
@@ -61,9 +61,9 @@
|
|
|
|
|
| |
|
|
|
|
|
GND GND
|
|
|
|
|
|
|
|
|
|
Each Volume level x will select a different resistor Rx. Measurements from fpgaarcade.com
|
|
|
|
|
where used to calibrate channel mixing for the YM2149. This was done using
|
|
|
|
|
a least square approach using a fixed RL of 1K Ohm.
|
|
|
|
|
Each Volume level x will select a different resistor Rx. Measurements from
|
|
|
|
|
fpgaarcade.com were used to calibrate channel mixing for the YM2149. This was
|
|
|
|
|
done using a least square approach using a fixed RL of 1K Ohm.
|
|
|
|
|
|
|
|
|
|
For the AY measurements cited in e.g. openmsx as "Hacker Kay" for a single
|
|
|
|
|
channel were taken. These were normalized to 0 ... 65535 and consequently
|
|
|
|
@@ -73,14 +73,13 @@ line e.g. with the formula used by pcmenc for the volume: vol(i) = exp(i/2-7.5).
|
|
|
|
|
The following is documentation from the code moved here and amended to reflect
|
|
|
|
|
the changes done:
|
|
|
|
|
|
|
|
|
|
Careful studies of the chip output prove that the chip counts up from 0
|
|
|
|
|
until the counter becomes greater or equal to the period. This is an
|
|
|
|
|
important difference when the program is rapidly changing the period to
|
|
|
|
|
modulate the sound. This is worthwhile noting, since the datasheets
|
|
|
|
|
say, that the chip counts down.
|
|
|
|
|
Also, note that period = 0 is the same as period = 1. This is mentioned
|
|
|
|
|
in the YM2203 data sheets. However, this does NOT apply to the Envelope
|
|
|
|
|
period. In that case, period = 0 is half as period = 1.
|
|
|
|
|
Careful studies of the chip output prove that the chip counts up from 0 until
|
|
|
|
|
the counter becomes greater or equal to the period. This is an important
|
|
|
|
|
difference when the program is rapidly changing the period to modulate the
|
|
|
|
|
sound. This is worthwhile noting, since the datasheets say, that the chip
|
|
|
|
|
counts down. Also, note that period = 0 is the same as period = 1. This is
|
|
|
|
|
mentioned in the YM2203 data sheets. However, this does NOT apply to the
|
|
|
|
|
Envelope period. In that case, period = 0 is half as period = 1.
|
|
|
|
|
|
|
|
|
|
Envelope shapes:
|
|
|
|
|
C AtAlH
|
|
|
|
@@ -99,20 +98,35 @@ The envelope counter on the AY-3-8910 has 16 steps. On the YM2149 it
|
|
|
|
|
has twice the steps, happening twice as fast.
|
|
|
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
#include <SDL/SDL.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
// MAME headers
|
|
|
|
|
/*
|
|
|
|
|
#include "osdcomm.h"
|
|
|
|
|
#include "mamecore.h"
|
|
|
|
|
#include "deprecat.h"
|
|
|
|
|
|
|
|
|
|
#include "sndintrf.h"
|
|
|
|
|
#include "deprecat.h"
|
|
|
|
|
//#include "deprecat.h"
|
|
|
|
|
#include "streams.h"
|
|
|
|
|
//#include "cpuintrf.h"
|
|
|
|
|
#include "cpuintrf.h"
|
|
|
|
|
*/
|
|
|
|
|
#include "sndint.h"
|
|
|
|
|
#include "ay8910.h"
|
|
|
|
|
|
|
|
|
|
// lazyness
|
|
|
|
|
#define logerror printf
|
|
|
|
|
|
|
|
|
|
/* pen_t is used to represent pixel values in bitmaps */
|
|
|
|
|
typedef UINT32 pen_t;
|
|
|
|
|
|
|
|
|
|
/* stream_sample_t is used to represent a single sample in a sound stream */
|
|
|
|
|
typedef INT32 stream_sample_t;
|
|
|
|
|
|
|
|
|
|
/*************************************
|
|
|
|
|
*
|
|
|
|
|
* Defines
|
|
|
|
|
*
|
|
|
|
|
*************************************/
|
|
|
|
|
|
|
|
|
|
#define MAX_OUTPUT 0x7fff
|
|
|
|
@@ -145,8 +159,19 @@ has twice the steps, happening twice as fast.
|
|
|
|
|
#define TONE_ENVELOPE(_psg, _chan) (((_psg)->regs[AY_AVOL + (_chan)] >> 4) & 1)
|
|
|
|
|
#define ENVELOPE_PERIOD(_psg) (((_psg)->regs[AY_EFINE] | ((_psg)->regs[AY_ECOARSE]<<8)))
|
|
|
|
|
|
|
|
|
|
/*************************************
|
|
|
|
|
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// prototypes
|
|
|
|
|
extern int sdl_init(int samplerate);
|
|
|
|
|
extern int sdlaudio_init(int samplerate);
|
|
|
|
|
extern void sdl_kill();
|
|
|
|
|
extern int sdl_create_buffers(void);
|
|
|
|
|
extern void sdl_destroy_buffers(void);
|
|
|
|
|
extern void sdl_cleanup_audio(int samplerate);
|
|
|
|
|
extern void sdl_callback(void *userdata, Uint8 *stream, int len);
|
|
|
|
|
extern void osd_update_audio_stream(int samplerate, INT16 *b, int s);
|
|
|
|
|
|
|
|
|
|
/**************************************
|
|
|
|
|
* Type definitions
|
|
|
|
|
*
|
|
|
|
|
*************************************/
|
|
|
|
@@ -166,7 +191,7 @@ struct _ay8910_context
|
|
|
|
|
int index;
|
|
|
|
|
int streams;
|
|
|
|
|
int ready;
|
|
|
|
|
sound_stream *channel;
|
|
|
|
|
//sound_stream *channel;
|
|
|
|
|
const ay8910_interface *intf;
|
|
|
|
|
INT32 register_latch;
|
|
|
|
|
UINT8 regs[16];
|
|
|
|
@@ -216,7 +241,7 @@ static const ay_ym_param ym2149_param_env =
|
|
|
|
|
1397, 1123, 925, 762, 578, 438, 332, 251 },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
#if 1
|
|
|
|
|
/* RL = 1000, Hacker Kay normalized, 2.1V to 3.2V */
|
|
|
|
|
static const ay_ym_param ay8910_param =
|
|
|
|
|
{
|
|
|
|
@@ -270,6 +295,7 @@ static const ay_ym_param ay8910_param =
|
|
|
|
|
*
|
|
|
|
|
*************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INLINE void build_3D_table(double rl, const ay_ym_param *par, const ay_ym_param *par_env, int normalize, double factor, int zero_is_off, INT32 *tab)
|
|
|
|
|
{
|
|
|
|
|
int j, j1, j2, j3, e, indx;
|
|
|
|
@@ -393,8 +419,7 @@ static void ay8910_write_reg(ay8910_context *psg, int r, int v)
|
|
|
|
|
//if (r >= 11 && r <= 13 ) printf("%d %x %02x\n", PSG->index, r, v);
|
|
|
|
|
psg->regs[r] = v;
|
|
|
|
|
|
|
|
|
|
switch( r )
|
|
|
|
|
{
|
|
|
|
|
switch ( r ) {
|
|
|
|
|
case AY_AFINE:
|
|
|
|
|
case AY_ACOARSE:
|
|
|
|
|
case AY_BFINE:
|
|
|
|
@@ -608,8 +633,8 @@ static void ay8910_update(void *param,stream_sample_t **inputs, stream_sample_t
|
|
|
|
|
|
|
|
|
|
static void build_mixer_table(ay8910_context *psg)
|
|
|
|
|
{
|
|
|
|
|
int normalize = 0;
|
|
|
|
|
int chan;
|
|
|
|
|
int normalize = 0;
|
|
|
|
|
int chan;
|
|
|
|
|
|
|
|
|
|
if ((psg->intf->flags & AY8910_LEGACY_OUTPUT) != 0)
|
|
|
|
|
{
|
|
|
|
@@ -628,7 +653,7 @@ static void build_mixer_table(ay8910_context *psg)
|
|
|
|
|
*/
|
|
|
|
|
build_3D_table(psg->intf->res_load[0], psg->par, psg->par_env, normalize, 3, psg->zero_is_off, psg->vol3d_table);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
static void ay8910_statesave(ay8910_context *psg, int sndindex)
|
|
|
|
|
{
|
|
|
|
|
state_save_register_item("AY8910", sndindex, psg->register_latch);
|
|
|
|
@@ -651,7 +676,7 @@ static void ay8910_statesave(ay8910_context *psg, int sndindex)
|
|
|
|
|
state_save_register_item("AY8910", sndindex, psg->holding);
|
|
|
|
|
state_save_register_item("AY8910", sndindex, psg->rng);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
/*************************************
|
|
|
|
|
*
|
|
|
|
|
* Public functions
|
|
|
|
@@ -664,8 +689,8 @@ void *ay8910_start_ym(sound_type chip_type, int sndindex, int clock, const ay891
|
|
|
|
|
{
|
|
|
|
|
ay8910_context *info;
|
|
|
|
|
|
|
|
|
|
info = (ay8910_context*) auto_malloc(sizeof(*info));
|
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
|
info = malloc(sizeof(ay8910_context));
|
|
|
|
|
memset(info, 0, sizeof(ay8910_context));
|
|
|
|
|
info->index = sndindex;
|
|
|
|
|
info->intf = intf;
|
|
|
|
|
if ((info->intf->flags & AY8910_SINGLE_OUTPUT) != 0)
|
|
|
|
@@ -710,7 +735,7 @@ void *ay8910_start_ym(sound_type chip_type, int sndindex, int clock, const ay891
|
|
|
|
|
info->channel = stream_create(0,info->streams,clock / 8 ,info,ay8910_update);
|
|
|
|
|
|
|
|
|
|
ay8910_set_clock_ym(info,clock);
|
|
|
|
|
ay8910_statesave(info, sndindex);
|
|
|
|
|
//ay8910_statesave(info, sndindex);
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
@@ -754,7 +779,7 @@ void ay8910_set_volume(int chip,int channel,int volume)
|
|
|
|
|
void ay8910_set_clock_ym(void *chip, int clock)
|
|
|
|
|
{
|
|
|
|
|
ay8910_context *psg = chip;
|
|
|
|
|
stream_set_sample_rate(psg->channel, clock / 8 );
|
|
|
|
|
//stream_set_sample_rate(psg->channel, clock / 8 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ay8910_write_ym(void *chip, int addr, int data)
|
|
|
|
@@ -769,7 +794,7 @@ void ay8910_write_ym(void *chip, int addr, int data)
|
|
|
|
|
if (r == AY_ESHAPE || psg->regs[r] != data)
|
|
|
|
|
{
|
|
|
|
|
/* update the output buffer before changing the register */
|
|
|
|
|
stream_update(psg->channel);
|
|
|
|
|
//stream_update(psg->channel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ay8910_write_reg(psg,r,data);
|
|
|
|
@@ -798,16 +823,16 @@ int ay8910_read_ym(void *chip)
|
|
|
|
|
*/
|
|
|
|
|
if (psg->intf->portAread)
|
|
|
|
|
psg->regs[AY_PORTA] = (*psg->intf->portAread)(Machine, 0);
|
|
|
|
|
else
|
|
|
|
|
logerror("PC %04x: warning - read 8910 #%d Port A\n",activecpu_get_pc(),psg->index);
|
|
|
|
|
//else
|
|
|
|
|
//logerror("PC %04x: warning - read 8910 #%d Port A\n",activecpu_get_pc(),psg->index);
|
|
|
|
|
break;
|
|
|
|
|
case AY_PORTB:
|
|
|
|
|
if ((psg->regs[AY_ENABLE] & 0x80) != 0)
|
|
|
|
|
logerror("warning: read from 8910 #%d Port B set as output\n",psg->index);
|
|
|
|
|
if (psg->intf->portBread)
|
|
|
|
|
psg->regs[AY_PORTB] = (*psg->intf->portBread)(Machine, 0);
|
|
|
|
|
else
|
|
|
|
|
logerror("PC %04x: warning - read 8910 #%d Port B\n",activecpu_get_pc(),psg->index);
|
|
|
|
|
//else
|
|
|
|
|
// logerror("PC %04x: warning - read 8910 #%d Port B\n",activecpu_get_pc(),psg->index);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return psg->regs[r];
|
|
|
|
@@ -819,7 +844,7 @@ int ay8910_read_ym(void *chip)
|
|
|
|
|
*
|
|
|
|
|
*************************************/
|
|
|
|
|
|
|
|
|
|
static void *ay8910_start(const char *tag, int sndindex, int clock, const void *config)
|
|
|
|
|
void *ay8910_start(const char *tag, int sndindex, int clock, const void *config)
|
|
|
|
|
{
|
|
|
|
|
static const ay8910_interface generic_ay8910 =
|
|
|
|
|
{
|
|
|
|
@@ -831,7 +856,8 @@ static void *ay8910_start(const char *tag, int sndindex, int clock, const void *
|
|
|
|
|
return ay8910_start_ym(SOUND_AY8910, sndindex+16, clock, intf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *ym2149_start(const char *tag, int sndindex, int clock, const void *config)
|
|
|
|
|
/*static void
|
|
|
|
|
*ym2149_start(const char *tag, int sndindex, int clock, const void *config)
|
|
|
|
|
{
|
|
|
|
|
static const ay8910_interface generic_ay8910 =
|
|
|
|
|
{
|
|
|
|
@@ -841,7 +867,7 @@ static void *ym2149_start(const char *tag, int sndindex, int clock, const void *
|
|
|
|
|
};
|
|
|
|
|
const ay8910_interface *intf = (config ? config : &generic_ay8910);
|
|
|
|
|
return ay8910_start_ym(SOUND_YM2149, sndindex+16, clock, intf);
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
static void ay8910_stop(void *chip)
|
|
|
|
|
{
|
|
|
|
@@ -902,19 +928,34 @@ void ay8912_get_info(void *token, UINT32 state, sndinfo *info)
|
|
|
|
|
{
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case SNDINFO_PTR_START: info->start = ay8910_start; break;
|
|
|
|
|
case SNDINFO_STR_NAME: info->s = "AY-3-8912A"; break;
|
|
|
|
|
default: ay8910_get_info(token, state, info); break;
|
|
|
|
|
case SNDINFO_PTR_START:
|
|
|
|
|
info->start = ay8910_start;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SNDINFO_STR_NAME:
|
|
|
|
|
info->s = "AY-3-8912A";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ay8910_get_info(token, state, info);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ay8913_get_info(void *token, UINT32 state, sndinfo *info)
|
|
|
|
|
{
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case SNDINFO_PTR_START: info->start = ay8910_start; break;
|
|
|
|
|
case SNDINFO_STR_NAME: info->s = "AY-3-8913A"; break;
|
|
|
|
|
default: ay8910_get_info(token, state, info); break;
|
|
|
|
|
switch (state) {
|
|
|
|
|
case SNDINFO_PTR_START:
|
|
|
|
|
info->start = ay8910_start;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SNDINFO_STR_NAME:
|
|
|
|
|
info->s = "AY-3-8913A";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ay8910_get_info(token, state, info);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
@@ -954,26 +995,29 @@ void ymz284_get_info(void *token, UINT32 state, sndinfo *info)
|
|
|
|
|
{
|
|
|
|
|
case SNDINFO_PTR_START: info->start = ym2149_start; break;
|
|
|
|
|
case SNDINFO_STR_NAME: info->s = "YMZ284"; break;
|
|
|
|
|
default: ay8910_get_info(token, state, info); break;
|
|
|
|
|
default:
|
|
|
|
|
ay8910_get_info(token, state, info);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ymz294_get_info(void *token, UINT32 state, sndinfo *info)
|
|
|
|
|
{
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case SNDINFO_PTR_START: info->start = ym2149_start; break;
|
|
|
|
|
case SNDINFO_STR_NAME: info->s = "YMZ294"; break;
|
|
|
|
|
default: ay8910_get_info(token, state, info); break;
|
|
|
|
|
switch (state) {
|
|
|
|
|
case SNDINFO_PTR_START:
|
|
|
|
|
info->start = ym2149_start;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SNDINFO_STR_NAME:
|
|
|
|
|
info->s = "YMZ294";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ay8910_get_info(token, state, info);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
main(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
printf("ay8910test.\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************
|
|
|
|
|
*
|
|
|
|
@@ -1002,9 +1046,25 @@ WRITE8_HANDLER( ay8910_control_port_1_w ) { ay8910_write_ym(sndti_token(SOUND_AY
|
|
|
|
|
WRITE8_HANDLER( ay8910_control_port_2_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data); }
|
|
|
|
|
WRITE8_HANDLER( ay8910_control_port_3_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 3),0,data); }
|
|
|
|
|
WRITE8_HANDLER( ay8910_control_port_4_w ) { ay8910_write_ym(sndti_token(SOUND_AY8910, 4),0,data); }
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_0_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data & 0xff); }
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_1_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 1),0,data & 0xff); }
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_2_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data & 0xff); }
|
|
|
|
|
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_0_lsb_w )
|
|
|
|
|
{
|
|
|
|
|
if (ACCESSING_BITS_0_7)
|
|
|
|
|
ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_1_lsb_w )
|
|
|
|
|
{
|
|
|
|
|
if (ACCESSING_BITS_0_7)
|
|
|
|
|
ay8910_write_ym(sndti_token(SOUND_AY8910, 1),0,data & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_2_lsb_w )
|
|
|
|
|
{
|
|
|
|
|
if (ACCESSING_BITS_0_7)
|
|
|
|
|
ay8910_write_ym(sndti_token(SOUND_AY8910, 2),0,data & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_3_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),0,data & 0xff); }
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_4_lsb_w ) { if (ACCESSING_BITS_0_7) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),0,data & 0xff); }
|
|
|
|
|
WRITE16_HANDLER( ay8910_control_port_0_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 0),0,data >> 8); }
|
|
|
|
@@ -1028,3 +1088,29 @@ WRITE16_HANDLER( ay8910_write_port_1_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_w
|
|
|
|
|
WRITE16_HANDLER( ay8910_write_port_2_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 2),1,data >> 8); }
|
|
|
|
|
WRITE16_HANDLER( ay8910_write_port_3_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 3),1,data >> 8); }
|
|
|
|
|
WRITE16_HANDLER( ay8910_write_port_4_msb_w ) { if (ACCESSING_BITS_8_15) ay8910_write_ym(sndti_token(SOUND_AY8910, 4),1,data >> 8); }
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
//running_machine *machine;
|
|
|
|
|
INT16 sounddata[100];
|
|
|
|
|
int i=0, sndindex=1, clock=500000;
|
|
|
|
|
ay8910_context *info;
|
|
|
|
|
const ay8910_interface ay8910_inf;
|
|
|
|
|
int sample_rate = 11025;
|
|
|
|
|
|
|
|
|
|
printf("ay8910test.\n");
|
|
|
|
|
for (i=0; i<100; ++i)
|
|
|
|
|
sounddata[i] = 32000 + 100 * i;
|
|
|
|
|
|
|
|
|
|
//machine = malloc(sizeof(running_machine));
|
|
|
|
|
sdlaudio_init(sample_rate);
|
|
|
|
|
info = ay8910_start(NULL, sndindex, clock, &ay8910_inf);
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
osd_update_audio_stream(sample_rate,sounddata,100);
|
|
|
|
|
sdl_kill();
|
|
|
|
|
//free(machine);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|