diff --git a/Core/SSGAudio.h b/Core/SSGAudio.h index b7fc3d87..dd0d1fd7 100644 --- a/Core/SSGAudio.h +++ b/Core/SSGAudio.h @@ -4,8 +4,89 @@ #include "APU.h" #include "BaseExpansionAudio.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 +class SSGAudio : public BaseExpansionAudio +{ +private: + std::unique_ptr _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.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) : 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 class SSGAudio : public BaseExpansionAudio { @@ -142,4 +223,5 @@ public: break; } } -}; \ No newline at end of file +}; +#endif \ No newline at end of file diff --git a/Core/emu2149.cpp b/Core/emu2149.cpp index 41641c79..6660ea10 100644 --- a/Core/emu2149.cpp +++ b/Core/emu2149.cpp @@ -8,18 +8,18 @@ 2002 03-02 : Version 1.12 -- Removed PSG_init & PSG_close. 2002 10-13 : Version 1.14 -- Fixed the envelope unit. 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 - frequency register is written before key-on. + 2004 01-11 : Version 1.16 -- Fixed the envelope problem where the envelope + frequency register is written before key-on. 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. References: - psg.vhd -- 2000 written by Kazuhiro Tsujikawa. - s_fme7.c -- 1999,2000 written by Mamiya (NEZplug). - ay8910.c -- 1998-2001 Author unknown (MAME). - MSX-Datapack -- 1991 ASCII Corp. - AY-3-8910 data sheet - + psg.vhd -- 2000 written by Kazuhiro Tsujikawa. + s_fme7.c -- 1999,2000 written by Mamiya (NEZplug). + ay8910.c -- 1998-2001 Author unknown (MAME). + MSX-Datapack -- 1991 ASCII Corp. + AY-3-8910 data sheet + *****************************************************************************/ #include "stdafx.h" #include @@ -29,347 +29,354 @@ static uint32_t voltbl[2][32] = { {0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, - 0x0B, 0x0D, 0x0F, 0x12, - 0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C, 0x5A, 0x6A, 0x7F, 0x97, - 0xB4, 0xD6, 0xFF, 0xFF}, - {0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x05, 0x05, 0x07, 0x07, - 0x0B, 0x0B, 0x0F, 0x0F, - 0x16, 0x16, 0x1F, 0x1F, 0x2D, 0x2D, 0x3F, 0x3F, 0x5A, 0x5A, 0x7F, 0x7F, - 0xB4, 0xB4, 0xFF, 0xFF} + 0x0B, 0x0D, 0x0F, 0x12, + 0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C, 0x5A, 0x6A, 0x7F, 0x97, + 0xB4, 0xD6, 0xFF, 0xFF}, + {0x00, 0x00, 0x03, 0x03, 0x04, 0x04, 0x06, 0x06, 0x09, 0x09, 0x0D, 0x0D, + 0x12, 0x12, 0x1D, 0x1D, + 0x22, 0x22, 0x37, 0x37, 0x4D, 0x4D, 0x62, 0x62, 0x82, 0x82, 0xA6, 0xA6, + 0xD0, 0xD0, 0xFF, 0xFF} }; static uint8_t regmsk[16] = { - 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f, - 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff + 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f, + 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff }; #define GETA_BITS 24 static void -internal_refresh (PSG * psg) +internal_refresh(PSG* psg) { - if (psg->quality) - { - psg->base_incr = 1 << GETA_BITS; - psg->realstep = (uint32_t) ((1 << 31) / psg->rate); - psg->psgstep = (uint32_t) ((1 << 31) / (psg->clk / 16)); - psg->psgtime = 0; - } - else - { - psg->base_incr = - (uint32_t) ((double) psg->clk * (1 << GETA_BITS) / (16 * psg->rate)); - } + if (psg->quality) + { + psg->base_incr = 1 << GETA_BITS; + psg->realstep = (uint32_t)((1 << 31) / psg->rate); + psg->psgstep = (uint32_t)((1 << 31) / (psg->clk / 8)); + psg->psgtime = 0; + } + else + { + psg->base_incr = + (uint32_t)((double)psg->clk * (1 << GETA_BITS) / (8 * psg->rate)); + } } void -PSG_set_rate (PSG * psg, uint32_t r) +PSG_set_clock(PSG* psg, uint32_t c) { - psg->rate = r ? r : 44100; - internal_refresh (psg); + psg->clk = c; + internal_refresh(psg); } void -PSG_set_quality (PSG * psg, uint32_t q) +PSG_set_rate(PSG* psg, uint32_t r) { - psg->quality = q; - 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; + psg->rate = r ? r : 44100; + internal_refresh(psg); } void -PSG_setVolumeMode (PSG * psg, int type) +PSG_set_quality(PSG* psg, uint32_t q) { - 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; - } + psg->quality = q; + 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 +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 -PSG_setMask (PSG *psg, uint32_t mask) +PSG_setMask(PSG* psg, uint32_t mask) { - uint32_t ret = 0; - if(psg) - { - ret = psg->mask; - psg->mask = mask; - } - return ret; + uint32_t ret = 0; + if (psg) + { + ret = psg->mask; + psg->mask = mask; + } + return ret; } uint32_t -PSG_toggleMask (PSG *psg, uint32_t mask) +PSG_toggleMask(PSG* psg, uint32_t mask) { - uint32_t ret = 0; - if(psg) - { - ret = psg->mask; - psg->mask ^= mask; - } - return ret; + uint32_t ret = 0; + if (psg) + { + ret = psg->mask; + psg->mask ^= mask; + } + return ret; } 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++) - { - psg->count[i] = 0x1000; - psg->freq[i] = 0; - psg->edge[i] = 0; - psg->volume[i] = 0; - psg->ch_out[i] = 0; - } + for (i = 0; i < 3; i++) + { + psg->count[i] = 0x1000; + psg->freq[i] = 0; + psg->edge[i] = 0; + psg->volume[i] = 0; + psg->ch_out[i] = 0; + } - psg->mask = 0; + psg->mask = 0; - for (i = 0; i < 16; i++) - psg->reg[i] = 0; - psg->adr = 0; + for (i = 0; i < 16; i++) + psg->reg[i] = 0; + psg->adr = 0; - psg->noise_seed = 0xffff; - psg->noise_count = 0x40; - psg->noise_freq = 0; + psg->noise_seed = 0xffff; + psg->noise_count = 0x40; + psg->noise_freq = 0; - psg->env_volume = 0; - psg->env_ptr = 0; - psg->env_freq = 0; - psg->env_count = 0; - psg->env_pause = 1; + psg->env_volume = 0; + psg->env_ptr = 0; + psg->env_freq = 0; + psg->env_count = 0; + psg->env_pause = 1; - psg->out = 0; + psg->out = 0; } void -PSG_delete (PSG * psg) +PSG_delete(PSG* psg) { - free (psg); + free(psg); } 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 -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 -PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val) +PSG_writeIO(PSG* psg, uint32_t adr, uint32_t val) { - if (adr & 1) - PSG_writeReg (psg, psg->adr, val); - else - psg->adr = val & 0x1f; + if (adr & 1) + PSG_writeReg(psg, psg->adr, val); + else + psg->adr = val & 0x1f; } static inline void -update_output (PSG * psg) +update_output(PSG* psg) { - int i, noise; - uint32_t incr; + int i, noise; + uint32_t incr; - psg->base_count += psg->base_incr; - incr = (psg->base_count >> GETA_BITS); - psg->base_count &= (1 << GETA_BITS) - 1; + psg->base_count += psg->base_incr; + incr = (psg->base_count >> GETA_BITS); + psg->base_count &= (1 << GETA_BITS) - 1; - /* Envelope */ - psg->env_count += incr; - while (psg->env_count>=0x10000 && psg->env_freq!=0) - { - if (!psg->env_pause) - { - if(psg->env_face) - psg->env_ptr = (psg->env_ptr + 1) & 0x3f ; - else - psg->env_ptr = (psg->env_ptr + 0x3f) & 0x3f; - } + /* Envelope */ + psg->env_count += incr; + while (psg->env_count >= 0x10000 && psg->env_freq != 0) + { + if (!psg->env_pause) + { + if (psg->env_face) + psg->env_ptr = (psg->env_ptr + 1) & 0x3f; + else + psg->env_ptr = (psg->env_ptr + 0x3f) & 0x3f; + } - if (psg->env_ptr & 0x20) /* if carry or borrow */ - { - if (psg->env_continue) - { - if (psg->env_alternate^psg->env_hold) psg->env_face ^= 1; - if (psg->env_hold) psg->env_pause = 1; - psg->env_ptr = psg->env_face?0:0x1f; - } - else - { - psg->env_pause = 1; - psg->env_ptr = 0; - } - } + if (psg->env_ptr & 0x20) /* if carry or borrow */ + { + if (psg->env_continue) + { + if (psg->env_alternate ^ psg->env_hold) psg->env_face ^= 1; + if (psg->env_hold) psg->env_pause = 1; + psg->env_ptr = psg->env_face ? 0 : 0x1f; + } + else + { + psg->env_pause = 1; + psg->env_ptr = 0; + } + } - psg->env_count -= psg->env_freq; - } + psg->env_count -= psg->env_freq; + } - /* Noise */ - psg->noise_count += incr; - if (psg->noise_count & 0x40) - { - if (psg->noise_seed & 1) - psg->noise_seed ^= 0x24000; - psg->noise_seed >>= 1; - psg->noise_count -= psg->noise_freq?psg->noise_freq:(1<<1); - } - noise = psg->noise_seed & 1; + /* Noise */ + psg->noise_count += incr; + if (psg->noise_count & 0x40) + { + if (psg->noise_seed & 1) + psg->noise_seed ^= 0x24000; + psg->noise_seed >>= 1; + psg->noise_count -= psg->noise_freq ? psg->noise_freq : (1 << 1); + } + noise = psg->noise_seed & 1; - /* Tone */ - for (i = 0; i < 3; i++) - { - psg->count[i] += incr; - if (psg->count[i] & 0x1000) - { - if (psg->freq[i] > 1) - { - psg->edge[i] = !psg->edge[i]; - psg->count[i] -= psg->freq[i]; - } - else - { - psg->edge[i] = 1; - } - } + /* Tone */ + for (i = 0; i < 3; i++) + { + psg->count[i] += incr; + if (psg->count[i] & 0x1000) + { + if (psg->freq[i] > 1) + { + psg->edge[i] = !psg->edge[i]; + psg->count[i] -= psg->freq[i]; + } + else + { + psg->edge[i] = 1; + } + } - if (psg->mask&PSG_MASK_CH(i)) - continue; + if (psg->mask & PSG_MASK_CH(i)) + continue; - if ((psg->tmask[i]||psg->edge[i]) && (psg->nmask[i]||noise)) - { - if (!(psg->volume[i] & 32)) - psg->ch_out[i] += (psg->voltbl[psg->volume[i] & 31] << 4); - else - psg->ch_out[i] += (psg->voltbl[psg->env_ptr] << 4); - } + if ((psg->tmask[i] || psg->edge[i]) && (psg->nmask[i] || noise)) + { + if (!(psg->volume[i] & 32)) + psg->ch_out[i] += (psg->voltbl[psg->volume[i] & 31] << 4); + else + psg->ch_out[i] += (psg->voltbl[psg->env_ptr] << 4); + } - psg->ch_out[i] >>= 1; + psg->ch_out[i] >>= 1; - } + } } -static inline int16_t -mix_output(PSG *psg) { - return (int16_t)(psg->out = psg->ch_out[0] + psg->ch_out[1] + psg->ch_out[2]); +static inline int16_t +mix_output(PSG* psg) { + return (int16_t)(psg->out = psg->ch_out[0] + psg->ch_out[1] + psg->ch_out[2]); } int16_t -PSG_calc (PSG * psg) +PSG_calc(PSG* psg) { - if (!psg->quality) { - update_output(psg); - return mix_output(psg); - } + if (!psg->quality) { + update_output(psg); + return mix_output(psg); + } - /* Simple rate converter */ - while (psg->realstep > psg->psgtime) - { - psg->psgtime += psg->psgstep; - update_output(psg); - } - psg->psgtime = psg->psgtime - psg->realstep; + /* Simple rate converter */ + while (psg->realstep > psg->psgtime) + { + psg->psgtime += psg->psgstep; + update_output(psg); + } + psg->psgtime = psg->psgtime - psg->realstep; - return mix_output(psg); + return mix_output(psg); } 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); - switch (reg) - { - case 0: - case 2: - case 4: - case 1: - case 3: - case 5: - c = reg >> 1; - psg->freq[c] = ((psg->reg[c * 2 + 1] & 15) << 8) + psg->reg[c * 2]; - break; + psg->reg[reg] = (uint8_t)(val & 0xff); + switch (reg) + { + case 0: + case 2: + case 4: + case 1: + case 3: + case 5: + c = reg >> 1; + psg->freq[c] = ((psg->reg[c * 2 + 1] & 15) << 8) + psg->reg[c * 2]; + break; - case 6: - psg->noise_freq = (val & 31) << 1; - break; + case 6: + psg->noise_freq = (val & 31) << 1; + break; - case 7: - psg->tmask[0] = (val & 1); - psg->tmask[1] = (val & 2); - psg->tmask[2] = (val & 4); - psg->nmask[0] = (val & 8); - psg->nmask[1] = (val & 16); - psg->nmask[2] = (val & 32); - break; + case 7: + psg->tmask[0] = (val & 1); + psg->tmask[1] = (val & 2); + psg->tmask[2] = (val & 4); + psg->nmask[0] = (val & 8); + psg->nmask[1] = (val & 16); + psg->nmask[2] = (val & 32); + break; - case 8: - case 9: - case 10: - psg->volume[reg - 8] = val << 1; - break; - - case 11: - case 12: - psg->env_freq = (psg->reg[12] << 8) + psg->reg[11]; - break; + case 8: + case 9: + case 10: + psg->volume[reg - 8] = val << 1; + break; - case 13: - psg->env_continue = (val >> 3) & 1; - psg->env_attack = (val >> 2) & 1; - 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; + case 11: + case 12: + psg->env_freq = (psg->reg[12] << 8) + psg->reg[11]; + break; - case 14: - case 15: - default: - break; - } + case 13: + psg->env_continue = (val >> 3) & 1; + psg->env_attack = (val >> 2) & 1; + 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; } \ No newline at end of file diff --git a/Core/emu2149.h b/Core/emu2149.h index 538edf75..338e0ad5 100644 --- a/Core/emu2149.h +++ b/Core/emu2149.h @@ -15,74 +15,75 @@ extern "C" { #endif - typedef struct __PSG - { + typedef struct __PSG + { - /* Volume Table */ - uint32_t *voltbl; + /* Volume Table */ + uint32_t* voltbl; - uint8_t reg[0x20]; - int32_t out; + uint8_t reg[0x20]; + int32_t out; - uint32_t clk, rate, base_incr, quality; + uint32_t clk, rate, base_incr, quality; - uint32_t count[3]; - uint32_t volume[3]; - uint32_t freq[3]; - uint32_t edge[3]; - uint32_t tmask[3]; - uint32_t nmask[3]; - uint32_t mask; + uint32_t count[3]; + uint32_t volume[3]; + uint32_t freq[3]; + uint32_t edge[3]; + uint32_t tmask[3]; + uint32_t nmask[3]; + uint32_t mask; - uint32_t base_count; + uint32_t base_count; - uint32_t env_volume; - uint32_t env_ptr; - uint32_t env_face; + uint32_t env_volume; + uint32_t env_ptr; + uint32_t env_face; - uint32_t env_continue; - uint32_t env_attack; - uint32_t env_alternate; - uint32_t env_hold; - uint32_t env_pause; - uint32_t env_reset; + uint32_t env_continue; + uint32_t env_attack; + uint32_t env_alternate; + uint32_t env_hold; + uint32_t env_pause; + uint32_t env_reset; - uint32_t env_freq; - uint32_t env_count; + uint32_t env_freq; + uint32_t env_count; - uint32_t noise_seed; - uint32_t noise_count; - uint32_t noise_freq; + uint32_t noise_seed; + uint32_t noise_count; + uint32_t noise_freq; - /* rate converter */ - uint32_t realstep; - uint32_t psgtime; - uint32_t psgstep; + /* rate converter */ + uint32_t realstep; + uint32_t psgtime; + uint32_t psgstep; - /* I/O Ctrl */ - uint32_t adr; + /* I/O Ctrl */ + uint32_t adr; - /* output of channels */ - int16_t ch_out[3]; + /* output of channels */ + 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 } #endif -#endif +#endif \ No newline at end of file