Replaced S5b emu with emu2149 for better accuracy
including missing features like envelope and noise
This commit is contained in:
parent
d06a647428
commit
fdee47855a
3 changed files with 400 additions and 310 deletions
|
@ -4,8 +4,89 @@
|
||||||
#include "APU.h"
|
#include "APU.h"
|
||||||
#include "BaseExpansionAudio.h"
|
#include "BaseExpansionAudio.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
#include "emu2149.h"
|
||||||
|
|
||||||
|
//#define SSG_USE_OLD_EMU
|
||||||
|
#ifndef SSG_USE_OLD_EMU
|
||||||
|
#define SSG_USE_EMU2149
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SSG_USE_EMU2149
|
||||||
|
template<AudioChannel...channels>
|
||||||
|
class SSGAudio : public BaseExpansionAudio
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::unique_ptr<PSG, void(*)(PSG*)> _psg;
|
||||||
|
uint8_t _currentRegister;
|
||||||
|
int16_t _lastOutput;
|
||||||
|
int16_t _currentOutput;
|
||||||
|
double _clock;
|
||||||
|
bool _processTick;
|
||||||
|
static constexpr uint8_t cycleCount = 1;
|
||||||
|
|
||||||
|
void UpdateOutputLevel()
|
||||||
|
{
|
||||||
|
(_console->GetApu()->AddExpansionAudioDelta(channels, _currentOutput - _lastOutput), ...);
|
||||||
|
_lastOutput = _currentOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void StreamState(bool saving) override
|
||||||
|
{
|
||||||
|
BaseExpansionAudio::StreamState(saving);
|
||||||
|
ValueInfo<PSG> psg{ _psg.get() };
|
||||||
|
Stream( _currentRegister, _lastOutput, _clock, psg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClockAudio() override
|
||||||
|
{
|
||||||
|
_clock += GetSSGClockFrequency() / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
|
||||||
|
|
||||||
|
while (_clock >= cycleCount)
|
||||||
|
{
|
||||||
|
_currentOutput = 0;
|
||||||
|
|
||||||
|
for (uint8_t cycle = 0; cycle < cycleCount; cycle++)
|
||||||
|
{
|
||||||
|
_clock--;
|
||||||
|
_currentOutput = PSG_calc(_psg.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentOutput /= 26;
|
||||||
|
|
||||||
|
UpdateOutputLevel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t GetSSGClockFrequency()
|
||||||
|
{
|
||||||
|
return _console->GetCpu()->GetClockRate(_console->GetModel()) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
SSGAudio(shared_ptr<Console> console) : BaseExpansionAudio(console), _psg{ PSG_new(1 , 1), &PSG_delete }
|
||||||
|
{
|
||||||
|
_currentRegister = 0;
|
||||||
|
_lastOutput = 0;
|
||||||
|
_clock = 0;
|
||||||
|
PSG_reset(_psg.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteRegister(uint16_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
switch (addr) {
|
||||||
|
case 0xC000:
|
||||||
|
_currentRegister = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE000:
|
||||||
|
if (_currentRegister <= 0xF)
|
||||||
|
PSG_writeReg(_psg.get(), _currentRegister, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
template<AudioChannel...channels>
|
template<AudioChannel...channels>
|
||||||
class SSGAudio : public BaseExpansionAudio
|
class SSGAudio : public BaseExpansionAudio
|
||||||
{
|
{
|
||||||
|
@ -142,4 +223,5 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
519
Core/emu2149.cpp
519
Core/emu2149.cpp
|
@ -8,18 +8,18 @@
|
||||||
2002 03-02 : Version 1.12 -- Removed PSG_init & PSG_close.
|
2002 03-02 : Version 1.12 -- Removed PSG_init & PSG_close.
|
||||||
2002 10-13 : Version 1.14 -- Fixed the envelope unit.
|
2002 10-13 : Version 1.14 -- Fixed the envelope unit.
|
||||||
2003 09-19 : Version 1.15 -- Added PSG_setMask and PSG_toggleMask
|
2003 09-19 : Version 1.15 -- Added PSG_setMask and PSG_toggleMask
|
||||||
2004 01-11 : Version 1.16 -- Fixed the envelope problem where the envelope
|
2004 01-11 : Version 1.16 -- Fixed the envelope problem where the envelope
|
||||||
frequency register is written before key-on.
|
frequency register is written before key-on.
|
||||||
2015 12-13 : Version 1.17 -- Changed own integer types to C99 stdint.h types.
|
2015 12-13 : Version 1.17 -- Changed own integer types to C99 stdint.h types.
|
||||||
2016 09-06 : Version 1.20 -- Support per-channel output.
|
2016 09-06 : Version 1.20 -- Support per-channel output.
|
||||||
|
|
||||||
References:
|
References:
|
||||||
psg.vhd -- 2000 written by Kazuhiro Tsujikawa.
|
psg.vhd -- 2000 written by Kazuhiro Tsujikawa.
|
||||||
s_fme7.c -- 1999,2000 written by Mamiya (NEZplug).
|
s_fme7.c -- 1999,2000 written by Mamiya (NEZplug).
|
||||||
ay8910.c -- 1998-2001 Author unknown (MAME).
|
ay8910.c -- 1998-2001 Author unknown (MAME).
|
||||||
MSX-Datapack -- 1991 ASCII Corp.
|
MSX-Datapack -- 1991 ASCII Corp.
|
||||||
AY-3-8910 data sheet
|
AY-3-8910 data sheet
|
||||||
|
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -29,347 +29,354 @@
|
||||||
|
|
||||||
static uint32_t voltbl[2][32] = {
|
static uint32_t voltbl[2][32] = {
|
||||||
{0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09,
|
{0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09,
|
||||||
0x0B, 0x0D, 0x0F, 0x12,
|
0x0B, 0x0D, 0x0F, 0x12,
|
||||||
0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C, 0x5A, 0x6A, 0x7F, 0x97,
|
0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C, 0x5A, 0x6A, 0x7F, 0x97,
|
||||||
0xB4, 0xD6, 0xFF, 0xFF},
|
0xB4, 0xD6, 0xFF, 0xFF},
|
||||||
{0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x05, 0x05, 0x07, 0x07,
|
{0x00, 0x00, 0x03, 0x03, 0x04, 0x04, 0x06, 0x06, 0x09, 0x09, 0x0D, 0x0D,
|
||||||
0x0B, 0x0B, 0x0F, 0x0F,
|
0x12, 0x12, 0x1D, 0x1D,
|
||||||
0x16, 0x16, 0x1F, 0x1F, 0x2D, 0x2D, 0x3F, 0x3F, 0x5A, 0x5A, 0x7F, 0x7F,
|
0x22, 0x22, 0x37, 0x37, 0x4D, 0x4D, 0x62, 0x62, 0x82, 0x82, 0xA6, 0xA6,
|
||||||
0xB4, 0xB4, 0xFF, 0xFF}
|
0xD0, 0xD0, 0xFF, 0xFF}
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t regmsk[16] = {
|
static uint8_t regmsk[16] = {
|
||||||
0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f,
|
0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f,
|
||||||
0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff
|
0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GETA_BITS 24
|
#define GETA_BITS 24
|
||||||
|
|
||||||
static void
|
static void
|
||||||
internal_refresh (PSG * psg)
|
internal_refresh(PSG* psg)
|
||||||
{
|
{
|
||||||
if (psg->quality)
|
if (psg->quality)
|
||||||
{
|
{
|
||||||
psg->base_incr = 1 << GETA_BITS;
|
psg->base_incr = 1 << GETA_BITS;
|
||||||
psg->realstep = (uint32_t) ((1 << 31) / psg->rate);
|
psg->realstep = (uint32_t)((1 << 31) / psg->rate);
|
||||||
psg->psgstep = (uint32_t) ((1 << 31) / (psg->clk / 16));
|
psg->psgstep = (uint32_t)((1 << 31) / (psg->clk / 8));
|
||||||
psg->psgtime = 0;
|
psg->psgtime = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
psg->base_incr =
|
psg->base_incr =
|
||||||
(uint32_t) ((double) psg->clk * (1 << GETA_BITS) / (16 * psg->rate));
|
(uint32_t)((double)psg->clk * (1 << GETA_BITS) / (8 * psg->rate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PSG_set_rate (PSG * psg, uint32_t r)
|
PSG_set_clock(PSG* psg, uint32_t c)
|
||||||
{
|
{
|
||||||
psg->rate = r ? r : 44100;
|
psg->clk = c;
|
||||||
internal_refresh (psg);
|
internal_refresh(psg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PSG_set_quality (PSG * psg, uint32_t q)
|
PSG_set_rate(PSG* psg, uint32_t r)
|
||||||
{
|
{
|
||||||
psg->quality = q;
|
psg->rate = r ? r : 44100;
|
||||||
internal_refresh (psg);
|
internal_refresh(psg);
|
||||||
}
|
|
||||||
|
|
||||||
PSG *
|
|
||||||
PSG_new (uint32_t c, uint32_t r)
|
|
||||||
{
|
|
||||||
PSG *psg;
|
|
||||||
|
|
||||||
psg = (PSG *) malloc (sizeof (PSG));
|
|
||||||
if (psg == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PSG_setVolumeMode (psg, EMU2149_VOL_DEFAULT);
|
|
||||||
psg->clk = c;
|
|
||||||
psg->rate = r ? r : 44100;
|
|
||||||
PSG_set_quality (psg, 0);
|
|
||||||
|
|
||||||
return psg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PSG_setVolumeMode (PSG * psg, int type)
|
PSG_set_quality(PSG* psg, uint32_t q)
|
||||||
{
|
{
|
||||||
switch (type)
|
psg->quality = q;
|
||||||
{
|
internal_refresh(psg);
|
||||||
case 1:
|
}
|
||||||
psg->voltbl = voltbl[EMU2149_VOL_YM2149];
|
|
||||||
break;
|
PSG*
|
||||||
case 2:
|
PSG_new(uint32_t c, uint32_t r)
|
||||||
psg->voltbl = voltbl[EMU2149_VOL_AY_3_8910];
|
{
|
||||||
break;
|
PSG* psg;
|
||||||
default:
|
|
||||||
psg->voltbl = voltbl[EMU2149_VOL_DEFAULT];
|
psg = (PSG*)malloc(sizeof(PSG));
|
||||||
break;
|
if (psg == NULL)
|
||||||
}
|
return NULL;
|
||||||
|
|
||||||
|
PSG_setVolumeMode(psg, EMU2149_VOL_DEFAULT);
|
||||||
|
psg->clk = c;
|
||||||
|
psg->rate = r ? r : 44100;
|
||||||
|
PSG_set_quality(psg, 0);
|
||||||
|
|
||||||
|
return psg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_setVolumeMode(PSG* psg, int type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
psg->voltbl = voltbl[EMU2149_VOL_YM2149];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
psg->voltbl = voltbl[EMU2149_VOL_AY_3_8910];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
psg->voltbl = voltbl[EMU2149_VOL_DEFAULT];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
PSG_setMask (PSG *psg, uint32_t mask)
|
PSG_setMask(PSG* psg, uint32_t mask)
|
||||||
{
|
{
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
if(psg)
|
if (psg)
|
||||||
{
|
{
|
||||||
ret = psg->mask;
|
ret = psg->mask;
|
||||||
psg->mask = mask;
|
psg->mask = mask;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
PSG_toggleMask (PSG *psg, uint32_t mask)
|
PSG_toggleMask(PSG* psg, uint32_t mask)
|
||||||
{
|
{
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
if(psg)
|
if (psg)
|
||||||
{
|
{
|
||||||
ret = psg->mask;
|
ret = psg->mask;
|
||||||
psg->mask ^= mask;
|
psg->mask ^= mask;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PSG_reset (PSG * psg)
|
PSG_reset(PSG* psg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
psg->base_count = 0;
|
psg->base_count = 0;
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
psg->count[i] = 0x1000;
|
psg->count[i] = 0x1000;
|
||||||
psg->freq[i] = 0;
|
psg->freq[i] = 0;
|
||||||
psg->edge[i] = 0;
|
psg->edge[i] = 0;
|
||||||
psg->volume[i] = 0;
|
psg->volume[i] = 0;
|
||||||
psg->ch_out[i] = 0;
|
psg->ch_out[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
psg->mask = 0;
|
psg->mask = 0;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
psg->reg[i] = 0;
|
psg->reg[i] = 0;
|
||||||
psg->adr = 0;
|
psg->adr = 0;
|
||||||
|
|
||||||
psg->noise_seed = 0xffff;
|
psg->noise_seed = 0xffff;
|
||||||
psg->noise_count = 0x40;
|
psg->noise_count = 0x40;
|
||||||
psg->noise_freq = 0;
|
psg->noise_freq = 0;
|
||||||
|
|
||||||
psg->env_volume = 0;
|
psg->env_volume = 0;
|
||||||
psg->env_ptr = 0;
|
psg->env_ptr = 0;
|
||||||
psg->env_freq = 0;
|
psg->env_freq = 0;
|
||||||
psg->env_count = 0;
|
psg->env_count = 0;
|
||||||
psg->env_pause = 1;
|
psg->env_pause = 1;
|
||||||
|
|
||||||
psg->out = 0;
|
psg->out = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PSG_delete (PSG * psg)
|
PSG_delete(PSG* psg)
|
||||||
{
|
{
|
||||||
free (psg);
|
free(psg);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
PSG_readIO (PSG * psg)
|
PSG_readIO(PSG* psg)
|
||||||
{
|
{
|
||||||
return (uint8_t) (psg->reg[psg->adr]);
|
return (uint8_t)(psg->reg[psg->adr]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
PSG_readReg (PSG * psg, uint32_t reg)
|
PSG_readReg(PSG* psg, uint32_t reg)
|
||||||
{
|
{
|
||||||
return (uint8_t) (psg->reg[reg & 0x1f]);
|
return (uint8_t)(psg->reg[reg & 0x1f]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val)
|
PSG_writeIO(PSG* psg, uint32_t adr, uint32_t val)
|
||||||
{
|
{
|
||||||
if (adr & 1)
|
if (adr & 1)
|
||||||
PSG_writeReg (psg, psg->adr, val);
|
PSG_writeReg(psg, psg->adr, val);
|
||||||
else
|
else
|
||||||
psg->adr = val & 0x1f;
|
psg->adr = val & 0x1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
update_output (PSG * psg)
|
update_output(PSG* psg)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i, noise;
|
int i, noise;
|
||||||
uint32_t incr;
|
uint32_t incr;
|
||||||
|
|
||||||
psg->base_count += psg->base_incr;
|
psg->base_count += psg->base_incr;
|
||||||
incr = (psg->base_count >> GETA_BITS);
|
incr = (psg->base_count >> GETA_BITS);
|
||||||
psg->base_count &= (1 << GETA_BITS) - 1;
|
psg->base_count &= (1 << GETA_BITS) - 1;
|
||||||
|
|
||||||
/* Envelope */
|
/* Envelope */
|
||||||
psg->env_count += incr;
|
psg->env_count += incr;
|
||||||
while (psg->env_count>=0x10000 && psg->env_freq!=0)
|
while (psg->env_count >= 0x10000 && psg->env_freq != 0)
|
||||||
{
|
{
|
||||||
if (!psg->env_pause)
|
if (!psg->env_pause)
|
||||||
{
|
{
|
||||||
if(psg->env_face)
|
if (psg->env_face)
|
||||||
psg->env_ptr = (psg->env_ptr + 1) & 0x3f ;
|
psg->env_ptr = (psg->env_ptr + 1) & 0x3f;
|
||||||
else
|
else
|
||||||
psg->env_ptr = (psg->env_ptr + 0x3f) & 0x3f;
|
psg->env_ptr = (psg->env_ptr + 0x3f) & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (psg->env_ptr & 0x20) /* if carry or borrow */
|
if (psg->env_ptr & 0x20) /* if carry or borrow */
|
||||||
{
|
{
|
||||||
if (psg->env_continue)
|
if (psg->env_continue)
|
||||||
{
|
{
|
||||||
if (psg->env_alternate^psg->env_hold) psg->env_face ^= 1;
|
if (psg->env_alternate ^ psg->env_hold) psg->env_face ^= 1;
|
||||||
if (psg->env_hold) psg->env_pause = 1;
|
if (psg->env_hold) psg->env_pause = 1;
|
||||||
psg->env_ptr = psg->env_face?0:0x1f;
|
psg->env_ptr = psg->env_face ? 0 : 0x1f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
psg->env_pause = 1;
|
psg->env_pause = 1;
|
||||||
psg->env_ptr = 0;
|
psg->env_ptr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
psg->env_count -= psg->env_freq;
|
psg->env_count -= psg->env_freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Noise */
|
/* Noise */
|
||||||
psg->noise_count += incr;
|
psg->noise_count += incr;
|
||||||
if (psg->noise_count & 0x40)
|
if (psg->noise_count & 0x40)
|
||||||
{
|
{
|
||||||
if (psg->noise_seed & 1)
|
if (psg->noise_seed & 1)
|
||||||
psg->noise_seed ^= 0x24000;
|
psg->noise_seed ^= 0x24000;
|
||||||
psg->noise_seed >>= 1;
|
psg->noise_seed >>= 1;
|
||||||
psg->noise_count -= psg->noise_freq?psg->noise_freq:(1<<1);
|
psg->noise_count -= psg->noise_freq ? psg->noise_freq : (1 << 1);
|
||||||
}
|
}
|
||||||
noise = psg->noise_seed & 1;
|
noise = psg->noise_seed & 1;
|
||||||
|
|
||||||
/* Tone */
|
/* Tone */
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
psg->count[i] += incr;
|
psg->count[i] += incr;
|
||||||
if (psg->count[i] & 0x1000)
|
if (psg->count[i] & 0x1000)
|
||||||
{
|
{
|
||||||
if (psg->freq[i] > 1)
|
if (psg->freq[i] > 1)
|
||||||
{
|
{
|
||||||
psg->edge[i] = !psg->edge[i];
|
psg->edge[i] = !psg->edge[i];
|
||||||
psg->count[i] -= psg->freq[i];
|
psg->count[i] -= psg->freq[i];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
psg->edge[i] = 1;
|
psg->edge[i] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (psg->mask&PSG_MASK_CH(i))
|
if (psg->mask & PSG_MASK_CH(i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((psg->tmask[i]||psg->edge[i]) && (psg->nmask[i]||noise))
|
if ((psg->tmask[i] || psg->edge[i]) && (psg->nmask[i] || noise))
|
||||||
{
|
{
|
||||||
if (!(psg->volume[i] & 32))
|
if (!(psg->volume[i] & 32))
|
||||||
psg->ch_out[i] += (psg->voltbl[psg->volume[i] & 31] << 4);
|
psg->ch_out[i] += (psg->voltbl[psg->volume[i] & 31] << 4);
|
||||||
else
|
else
|
||||||
psg->ch_out[i] += (psg->voltbl[psg->env_ptr] << 4);
|
psg->ch_out[i] += (psg->voltbl[psg->env_ptr] << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
psg->ch_out[i] >>= 1;
|
psg->ch_out[i] >>= 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int16_t
|
static inline int16_t
|
||||||
mix_output(PSG *psg) {
|
mix_output(PSG* psg) {
|
||||||
return (int16_t)(psg->out = psg->ch_out[0] + psg->ch_out[1] + psg->ch_out[2]);
|
return (int16_t)(psg->out = psg->ch_out[0] + psg->ch_out[1] + psg->ch_out[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t
|
int16_t
|
||||||
PSG_calc (PSG * psg)
|
PSG_calc(PSG* psg)
|
||||||
{
|
{
|
||||||
if (!psg->quality) {
|
if (!psg->quality) {
|
||||||
update_output(psg);
|
update_output(psg);
|
||||||
return mix_output(psg);
|
return mix_output(psg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simple rate converter */
|
/* Simple rate converter */
|
||||||
while (psg->realstep > psg->psgtime)
|
while (psg->realstep > psg->psgtime)
|
||||||
{
|
{
|
||||||
psg->psgtime += psg->psgstep;
|
psg->psgtime += psg->psgstep;
|
||||||
update_output(psg);
|
update_output(psg);
|
||||||
}
|
}
|
||||||
psg->psgtime = psg->psgtime - psg->realstep;
|
psg->psgtime = psg->psgtime - psg->realstep;
|
||||||
|
|
||||||
return mix_output(psg);
|
return mix_output(psg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PSG_writeReg (PSG * psg, uint32_t reg, uint32_t val)
|
PSG_writeReg(PSG* psg, uint32_t reg, uint32_t val)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if (reg > 15) return;
|
if (reg > 15) return;
|
||||||
|
|
||||||
val &= regmsk[reg];
|
val &= regmsk[reg];
|
||||||
|
|
||||||
psg->reg[reg] = (uint8_t) (val & 0xff);
|
psg->reg[reg] = (uint8_t)(val & 0xff);
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 1:
|
case 1:
|
||||||
case 3:
|
case 3:
|
||||||
case 5:
|
case 5:
|
||||||
c = reg >> 1;
|
c = reg >> 1;
|
||||||
psg->freq[c] = ((psg->reg[c * 2 + 1] & 15) << 8) + psg->reg[c * 2];
|
psg->freq[c] = ((psg->reg[c * 2 + 1] & 15) << 8) + psg->reg[c * 2];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
psg->noise_freq = (val & 31) << 1;
|
psg->noise_freq = (val & 31) << 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
psg->tmask[0] = (val & 1);
|
psg->tmask[0] = (val & 1);
|
||||||
psg->tmask[1] = (val & 2);
|
psg->tmask[1] = (val & 2);
|
||||||
psg->tmask[2] = (val & 4);
|
psg->tmask[2] = (val & 4);
|
||||||
psg->nmask[0] = (val & 8);
|
psg->nmask[0] = (val & 8);
|
||||||
psg->nmask[1] = (val & 16);
|
psg->nmask[1] = (val & 16);
|
||||||
psg->nmask[2] = (val & 32);
|
psg->nmask[2] = (val & 32);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
case 9:
|
case 9:
|
||||||
case 10:
|
case 10:
|
||||||
psg->volume[reg - 8] = val << 1;
|
psg->volume[reg - 8] = val << 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 11:
|
|
||||||
case 12:
|
|
||||||
psg->env_freq = (psg->reg[12] << 8) + psg->reg[11];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 13:
|
case 11:
|
||||||
psg->env_continue = (val >> 3) & 1;
|
case 12:
|
||||||
psg->env_attack = (val >> 2) & 1;
|
psg->env_freq = (psg->reg[12] << 8) + psg->reg[11];
|
||||||
psg->env_alternate = (val >> 1) & 1;
|
break;
|
||||||
psg->env_hold = val & 1;
|
|
||||||
psg->env_face = psg->env_attack;
|
|
||||||
psg->env_pause = 0;
|
|
||||||
psg->env_count = 0x10000 - psg->env_freq;
|
|
||||||
psg->env_ptr = psg->env_face?0:0x1f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 14:
|
case 13:
|
||||||
case 15:
|
psg->env_continue = (val >> 3) & 1;
|
||||||
default:
|
psg->env_attack = (val >> 2) & 1;
|
||||||
break;
|
psg->env_alternate = (val >> 1) & 1;
|
||||||
}
|
psg->env_hold = val & 1;
|
||||||
|
psg->env_face = psg->env_attack;
|
||||||
|
psg->env_pause = 0;
|
||||||
|
psg->env_count = 0x10000 - psg->env_freq;
|
||||||
|
psg->env_ptr = psg->env_face ? 0 : 0x1f;
|
||||||
|
break;
|
||||||
|
|
||||||
return;
|
case 14:
|
||||||
|
case 15:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
107
Core/emu2149.h
107
Core/emu2149.h
|
@ -15,74 +15,75 @@ extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct __PSG
|
typedef struct __PSG
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Volume Table */
|
/* Volume Table */
|
||||||
uint32_t *voltbl;
|
uint32_t* voltbl;
|
||||||
|
|
||||||
uint8_t reg[0x20];
|
uint8_t reg[0x20];
|
||||||
int32_t out;
|
int32_t out;
|
||||||
|
|
||||||
uint32_t clk, rate, base_incr, quality;
|
uint32_t clk, rate, base_incr, quality;
|
||||||
|
|
||||||
uint32_t count[3];
|
uint32_t count[3];
|
||||||
uint32_t volume[3];
|
uint32_t volume[3];
|
||||||
uint32_t freq[3];
|
uint32_t freq[3];
|
||||||
uint32_t edge[3];
|
uint32_t edge[3];
|
||||||
uint32_t tmask[3];
|
uint32_t tmask[3];
|
||||||
uint32_t nmask[3];
|
uint32_t nmask[3];
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
|
|
||||||
uint32_t base_count;
|
uint32_t base_count;
|
||||||
|
|
||||||
uint32_t env_volume;
|
uint32_t env_volume;
|
||||||
uint32_t env_ptr;
|
uint32_t env_ptr;
|
||||||
uint32_t env_face;
|
uint32_t env_face;
|
||||||
|
|
||||||
uint32_t env_continue;
|
uint32_t env_continue;
|
||||||
uint32_t env_attack;
|
uint32_t env_attack;
|
||||||
uint32_t env_alternate;
|
uint32_t env_alternate;
|
||||||
uint32_t env_hold;
|
uint32_t env_hold;
|
||||||
uint32_t env_pause;
|
uint32_t env_pause;
|
||||||
uint32_t env_reset;
|
uint32_t env_reset;
|
||||||
|
|
||||||
uint32_t env_freq;
|
uint32_t env_freq;
|
||||||
uint32_t env_count;
|
uint32_t env_count;
|
||||||
|
|
||||||
uint32_t noise_seed;
|
uint32_t noise_seed;
|
||||||
uint32_t noise_count;
|
uint32_t noise_count;
|
||||||
uint32_t noise_freq;
|
uint32_t noise_freq;
|
||||||
|
|
||||||
/* rate converter */
|
/* rate converter */
|
||||||
uint32_t realstep;
|
uint32_t realstep;
|
||||||
uint32_t psgtime;
|
uint32_t psgtime;
|
||||||
uint32_t psgstep;
|
uint32_t psgstep;
|
||||||
|
|
||||||
/* I/O Ctrl */
|
/* I/O Ctrl */
|
||||||
uint32_t adr;
|
uint32_t adr;
|
||||||
|
|
||||||
/* output of channels */
|
/* output of channels */
|
||||||
int16_t ch_out[3];
|
int16_t ch_out[3];
|
||||||
|
|
||||||
} PSG;
|
} PSG;
|
||||||
|
|
||||||
|
void PSG_set_quality(PSG* psg, uint32_t q);
|
||||||
|
void PSG_set_clock(PSG* psg, uint32_t c);
|
||||||
|
void PSG_set_rate(PSG* psg, uint32_t r);
|
||||||
|
PSG* PSG_new(uint32_t clk, uint32_t rate);
|
||||||
|
void PSG_reset(PSG*);
|
||||||
|
void PSG_delete(PSG*);
|
||||||
|
void PSG_writeReg(PSG*, uint32_t reg, uint32_t val);
|
||||||
|
void PSG_writeIO(PSG* psg, uint32_t adr, uint32_t val);
|
||||||
|
uint8_t PSG_readReg(PSG* psg, uint32_t reg);
|
||||||
|
uint8_t PSG_readIO(PSG* psg);
|
||||||
|
int16_t PSG_calc(PSG*);
|
||||||
|
void PSG_setVolumeMode(PSG* psg, int type);
|
||||||
|
uint32_t PSG_setMask(PSG*, uint32_t mask);
|
||||||
|
uint32_t PSG_toggleMask(PSG*, uint32_t mask);
|
||||||
|
|
||||||
void PSG_set_quality (PSG * psg, uint32_t q);
|
|
||||||
void PSG_set_rate (PSG * psg, uint32_t r);
|
|
||||||
PSG *PSG_new (uint32_t clk, uint32_t rate);
|
|
||||||
void PSG_reset (PSG *);
|
|
||||||
void PSG_delete (PSG *);
|
|
||||||
void PSG_writeReg (PSG *, uint32_t reg, uint32_t val);
|
|
||||||
void PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val);
|
|
||||||
uint8_t PSG_readReg (PSG * psg, uint32_t reg);
|
|
||||||
uint8_t PSG_readIO (PSG * psg);
|
|
||||||
int16_t PSG_calc (PSG *);
|
|
||||||
void PSG_setVolumeMode (PSG * psg, int type);
|
|
||||||
uint32_t PSG_setMask (PSG *, uint32_t mask);
|
|
||||||
uint32_t PSG_toggleMask (PSG *, uint32_t mask);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Add table
Reference in a new issue