Fix compile, Add SM8521 to list

This commit is contained in:
cam900 2023-02-11 21:37:11 +09:00
parent 0cb36206c4
commit 07a1c57a5a
10 changed files with 286 additions and 199 deletions

View File

@ -455,6 +455,8 @@ src/engine/platform/sound/snes/SPC_DSP.cpp
src/engine/platform/sound/ga20/iremga20.cpp
src/engine/platform/sound/sm8521.c
src/engine/platform/oplAInterface.cpp
src/engine/platform/ym2608Interface.cpp
src/engine/platform/ym2610Interface.cpp
@ -539,6 +541,7 @@ src/engine/platform/rf5c68.cpp
src/engine/platform/snes.cpp
src/engine/platform/k007232.cpp
src/engine/platform/ga20.cpp
src/engine/platform/sm8521.cpp
src/engine/platform/pcmdac.cpp
src/engine/platform/dummy.cpp
)

View File

@ -75,6 +75,7 @@
#include "platform/vb.h"
#include "platform/k007232.h"
#include "platform/ga20.h"
#include "platform/sm8521.h"
#include "platform/pcmdac.h"
#include "platform/dummy.h"
#include "../ta-log.h"
@ -489,6 +490,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
case DIV_SYSTEM_GA20:
dispatch=new DivPlatformGA20;
break;
case DIV_SYSTEM_SM8521:
dispatch=new DivPlatformSM8521;
break;
case DIV_SYSTEM_PCM_DAC:
dispatch=new DivPlatformPCMDAC;
break;

View File

@ -144,10 +144,8 @@ void DivPlatformSM8521::tick(bool sysTick) {
rWrite(freqMap[i][1],chan[i].freq&0xff);
const unsigned char temp=regPool[0x40];
if (chan[i].keyOn) {
rWrite(0x40,temp|(1<<i));
}
if (chan[i].keyOff) {
rWrite(0x40,temp&~(1<<i));
}
if (chan[i].keyOn) chan[i].keyOn=false;
if (chan[i].keyOff) chan[i].keyOff=false;
@ -171,6 +169,9 @@ int DivPlatformSM8521::dispatch(DivCommand c) {
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (!isMuted[c.chan]) {
rWrite(0x40,regPool[0x40]|0x80|(1<<c.chan));
}
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
@ -186,6 +187,7 @@ int DivPlatformSM8521::dispatch(DivCommand c) {
chan[c.chan].active=false;
chan[c.chan].keyOff=true;
chan[c.chan].macroInit(NULL);
rWrite(0x40,regPool[0x40]&~(1<<c.chan));
break;
case DIV_CMD_NOTE_OFF_ENV:
case DIV_CMD_ENV_RELEASE:
@ -279,6 +281,11 @@ int DivPlatformSM8521::dispatch(DivCommand c) {
void DivPlatformSM8521::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
chan[ch].volumeChanged=true;
if (mute) {
rWrite(0x40,regPool[0x40]&~(1<<ch));
} else if (chan[ch].active) {
rWrite(0x40,regPool[0x40]|0x80|(1<<ch));
}
}
void DivPlatformSM8521::forceIns() {
@ -322,7 +329,7 @@ void DivPlatformSM8521::reset() {
addWrite(0xffffffff,0);
}
sm8521_reset(&sm8521);
sm8521_write(&sm8521,0x40,0x80); // initialize SGC
rWrite(0x40,0x80); // initialize SGC
}
int DivPlatformSM8521::getOutputCount() {

View File

@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _NAMCOWSG_H
#define _NAMCOWSG_H
#ifndef _SM8521_H
#define _SM8521_H
#include "../dispatch.h"
#include <queue>
@ -26,8 +26,8 @@
#include "sound/sm8521.h"
class DivPlatformSM8521: public DivDispatch {
const unsigned char volMap[3]={0x42,0x44,0x4a};
const unsigned char freqMap[3][2]={{0x46,0x47},{0x48,0x49},{0x4c,0x4d}};
struct Channel: public SharedChannel<signed char> {
@ -36,7 +36,7 @@ class DivPlatformSM8521: public DivDispatch {
bool volumeChanged;
DivWaveSynth ws;
Channel():
SharedChannel<signed char>(15),
SharedChannel<signed char>(31),
antiClickPeriodCount(0),
antiClickWavePos(0),
wave(-1),

View File

@ -0,0 +1,235 @@
/*
============================================================================
SM8521 sound emulator
by cam900
This file is licensed under zlib license.
============================================================================
zlib License
(C) 2022-present cam900 and contributors
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
============================================================================
TODO:
- needs hardware test
*/
#include "sm8521.h"
#include <stdlib.h>
enum sm8521_sgc
{
SM8521_SGC_SONDOUT = (1 << 7),
SM8521_SGC_DIROUT = (1 << 3),
SM8521_SGC_SG2OUT = (1 << 2),
SM8521_SGC_SG1OUT = (1 << 1),
SM8521_SGC_SG0OUT = (1 << 0)
};
void sm8521_sg_wave_tick(struct sm8521_wave_t *sg, const int cycle)
{
sg->base.counter += cycle;
while (sg->base.counter >= (sg->base.t + 1))
{
sg->addr++;
sg->base.counter -= (sg->base.t + 1);
}
int wave = (sg->wave[(sg->addr >> 1) & 0xf] >> ((sg->addr & 1) << 2)) & 0xf;
if (wave & 0x8)
{
wave = -(0x8 - (wave & 0x7));
}
sg->base.out = (wave * sg->base.level) >> 1; // scale out to 8bit
}
void sm8521_noise_tick(struct sm8521_noise_t *noise, const int cycle)
{
noise->base.counter += cycle;
while (noise->base.counter >= (noise->base.t + 1))
{
noise->lfsr = rand() & 0x1; // unknown algorithm
noise->base.counter -= (noise->base.t + 1);
}
noise->base.out = (((noise->lfsr & 0x1) ? 7 : -8) * noise->base.level) >> 1; // scale out to 8bit
}
void sm8521_sound_tick(struct sm8521_t *sm8521, const int cycle)
{
int out = 0;
if (sm8521->sgc & SM8521_SGC_SONDOUT)
{
if (sm8521->sgc & SM8521_SGC_DIROUT)
{
out = sm8521->sgda - 0x80;
}
else
{
if (sm8521->sgc & SM8521_SGC_SG0OUT)
{
sm8521_sg_wave_tick(&sm8521->sg[0], cycle);
out += sm8521->sg[0].base.out;
}
if (sm8521->sgc & SM8521_SGC_SG1OUT)
{
sm8521_sg_wave_tick(&sm8521->sg[1], cycle);
out += sm8521->sg[1].base.out;
}
if (sm8521->sgc & SM8521_SGC_SG2OUT)
{
sm8521_noise_tick(&sm8521->noise, cycle);
out += sm8521->noise.base.out;
}
out = (out < -0x80) ? -0x80 : ((out > 0x7f) ? 0x7f : out); // clamp
}
}
sm8521->out = out;
}
void sm8521_reset(struct sm8521_t *sm8521)
{
for (int i = 0; i < 2; i++)
{
sm8521->sg[i].base.t = 0;
sm8521->sg[i].base.level = 0;
sm8521->sg[i].base.out = 0;
sm8521->sg[i].base.counter = 0;
sm8521->sg[i].addr = 0;
for (int j = 0; j < 16; j++)
{
sm8521->sg[i].wave[j] = 0;
}
}
sm8521->noise.base.t = 0;
sm8521->noise.base.level = 0;
sm8521->noise.base.out = 0;
sm8521->noise.base.counter = 0;
sm8521->noise.lfsr = 0;
sm8521->out = 0;
sm8521->sgda = 0;
sm8521->sgc = 0;
}
unsigned char sm8521_read(struct sm8521_t *sm8521, const unsigned char a)
{
if ((a & 0xe0) == 0x60)
{
if ((a & 0x10) && (!(sm8521->sgc & SM8521_SGC_SG1OUT))) // 0x70-0x7f SG1W0-15
{
return sm8521->sg[1].wave[a & 0xf];
}
else if ((!(a & 0x10)) && (!(sm8521->sgc & SM8521_SGC_SG0OUT))) // 0x60-0x6f SG0W0-15
{
return sm8521->sg[0].wave[a & 0xf];
}
return 0;
}
switch (a)
{
case 0x40: // SGC
return sm8521->sgc;
break;
case 0x42: // SG0L
return sm8521->sg[0].base.level & 0x1f;
break;
case 0x44: // SG1L
return sm8521->sg[1].base.level & 0x1f;
break;
case 0x46: // SG0TH
return (sm8521->sg[0].base.t >> 8) & 0xf;
break;
case 0x47: // SG0TL
return sm8521->sg[0].base.t & 0xff;
break;
case 0x48: // SG1TH
return (sm8521->sg[1].base.t >> 8) & 0xf;
break;
case 0x49: // SG1TL
return sm8521->sg[1].base.t & 0x0ff;
break;
case 0x4a: // SG2L
return sm8521->noise.base.level & 0x1f;
break;
case 0x4c: // SG2TH
return (sm8521->noise.base.t >> 8) & 0xf;
break;
case 0x4d: // SG2TL
return sm8521->noise.base.t & 0xff;
break;
default:
return 0;
break;
}
}
void sm8521_write(struct sm8521_t *sm8521, const unsigned char a, const unsigned char d)
{
if ((a & 0xe0) == 0x60)
{
if ((a & 0x10) && (!(sm8521->sgc & SM8521_SGC_SG1OUT))) // 0x70-0x7f SG1W0-15
{
sm8521->sg[1].wave[a & 0xf] = d;
}
else if ((!(a & 0x10)) && (!(sm8521->sgc & SM8521_SGC_SG0OUT))) // 0x60-0x6f SG0W0-15
{
sm8521->sg[0].wave[a & 0xf] = d;
}
return;
}
switch (a)
{
case 0x40: // SGC
sm8521->sgc = d;
break;
case 0x42: // SG0L
sm8521->sg[0].base.level = d & 0x1f;
break;
case 0x44: // SG1L
sm8521->sg[1].base.level = d & 0x1f;
break;
case 0x46: // SG0TH
sm8521->sg[0].base.t = (sm8521->sg[0].base.t & 0x0ff) | ((d << 8) & 0xf00);
break;
case 0x47: // SG0TL
sm8521->sg[0].base.t = (sm8521->sg[0].base.t & 0xf00) | (d & 0x0ff);
break;
case 0x48: // SG1TH
sm8521->sg[1].base.t = (sm8521->sg[1].base.t & 0x0ff) | ((d << 8) & 0xf00);
break;
case 0x49: // SG1TL
sm8521->sg[1].base.t = (sm8521->sg[1].base.t & 0xf00) | (d & 0x0ff);
break;
case 0x4a: // SG2L
sm8521->noise.base.level = d & 0x1f;
break;
case 0x4c: // SG2TH
sm8521->noise.base.t = (sm8521->noise.base.t & 0x0ff) | ((d << 8) & 0xf00);
break;
case 0x4d: // SG2TL
sm8521->noise.base.t = (sm8521->noise.base.t & 0xf00) | (d & 0x0ff);
break;
case 0x4e: // SGDA
sm8521->sgda = d;
break;
}
}

View File

@ -36,22 +36,14 @@ TODO:
*/
#include <stdlib.h>
#ifndef _SM8521_EMU_H
#define _SM8521_EMU_H
#ifdef __cplusplus
extern "C"
{
#endif
enum sm8521_sgc
{
SM8521_SGC_SONDOUT = (1 << 7),
SM8521_SGC_DIROUT = (1 << 3),
SM8521_SGC_SG2OUT = (1 << 2),
SM8521_SGC_SG1OUT = (1 << 1),
SM8521_SGC_SG0OUT = (1 << 0)
};
struct sm8521_sg_t
{
unsigned short t; // Time constant register
@ -82,192 +74,19 @@ struct sm8521_t
unsigned char sgc; // Control register
};
void sm8521_sg_wave_tick(struct sm8521_wave_t *sg, const int cycle)
{
sg->base.counter += cycle;
while (sg->base.counter >= (sg->base.t + 1))
{
sg->addr++;
sg->base.counter -= (sg->base.t + 1);
}
int wave = (sg->wave[(sg->addr >> 1) & 0xf] >> ((sg->addr & 1) << 2)) & 0xf;
if (wave & 0x8)
{
wave = -(0x8 - (wave & 0x7));
}
sg->base.out = (wave * sg->base.level) >> 1; // scale out to 8bit
}
void sm8521_sg_wave_tick(struct sm8521_wave_t *sg, const int cycle);
void sm8521_noise_tick(struct sm8521_noise_t *noise, const int cycle)
{
noise->base.counter += cycle;
while (noise->base.counter >= (noise->base.t + 1))
{
noise->lfsr = rand() & 0x1; // unknown algorithm
noise->base.counter -= (noise->base.t + 1);
}
noise->base.out = (((noise->lfsr & 0x1) ? 7 : -8) * noise->base.level) >> 1; // scale out to 8bit
}
void sm8521_noise_tick(struct sm8521_noise_t *noise, const int cycle);
void sm8521_sound_tick(struct sm8521_t *sm8521, const int cycle)
{
int out = 0;
if (sm8521->sgc & SM8521_SGC_SONDOUT)
{
if (sm8521->sgc & SM8521_SGC_DIROUT)
{
out = sm8521->sgda - 0x80;
}
else
{
if (sm8521->sgc & SM8521_SGC_SG0OUT)
{
sm8521_sg_wave_tick(&sm8521->sg[0], cycle);
out += sm8521->sg[0].base.out;
}
if (sm8521->sgc & SM8521_SGC_SG1OUT)
{
sm8521_sg_wave_tick(&sm8521->sg[1], cycle);
out += sm8521->sg[1].base.out;
}
if (sm8521->sgc & SM8521_SGC_SG2OUT)
{
sm8521_noise_tick(&sm8521->noise, cycle);
out += sm8521->noise.base.out;
}
out = (out < -0x80) ? -0x80 : ((out > 0x7f) ? 0x7f : out); // clamp
}
}
sm8521->out = out;
}
void sm8521_sound_tick(struct sm8521_t *sm8521, const int cycle);
void sm8521_reset(struct sm8521_t *sm8521)
{
for (int i = 0; i < 2; i++)
{
sm8521->sg[i].base.t = 0;
sm8521->sg[i].base.level = 0;
sm8521->sg[i].base.out = 0;
sm8521->sg[i].base.counter = 0;
sm8521->sg[i].addr = 0;
for (int j = 0; j < 16; j++)
{
sm8521->sg[i].wave[j] = 0;
}
}
sm8521->noise.base.t = 0;
sm8521->noise.base.level = 0;
sm8521->noise.base.out = 0;
sm8521->noise.base.counter = 0;
sm8521->noise.lfsr = 0;
sm8521->out = 0;
sm8521->sgda = 0;
sm8521->sgc = 0;
}
void sm8521_reset(struct sm8521_t *sm8521);
unsigned char sm8521_read(struct sm8521_t *sm8521, const unsigned char a)
{
if ((a & 0xe0) == 0x60)
{
if ((a & 0x10) && (!(sm8521->sgc & SM8521_SGC_SG1OUT))) // 0x70-0x7f SG1W0-15
{
return sm8521->sg[1].wave[a & 0xf];
}
else if ((!(a & 0x10)) && (!(sm8521->sgc & SM8521_SGC_SG0OUT))) // 0x60-0x6f SG0W0-15
{
return sm8521->sg[0].wave[a & 0xf];
}
return 0;
}
switch (a)
{
case 0x40: // SGC
return sm8521->sgc;
break;
case 0x42: // SG0L
return sm8521->sg[0].base.level & 0x1f;
break;
case 0x44: // SG1L
return sm8521->sg[1].base.level & 0x1f;
break;
case 0x46: // SG0TH
return (sm8521->sg[0].base.t >> 8) & 0xf;
break;
case 0x47: // SG0TL
return sm8521->sg[0].base.t & 0xff;
break;
case 0x48: // SG1TH
return (sm8521->sg[1].base.t >> 8) & 0xf;
break;
case 0x49: // SG1TL
return sm8521->sg[1].base.t & 0x0ff;
break;
case 0x4a: // SG2L
return sm8521->noise.base.level & 0x1f;
break;
case 0x4c: // SG2TH
return (sm8521->noise.base.t >> 8) & 0xf;
break;
case 0x4d: // SG2TL
return sm8521->noise.base.t & 0xff;
break;
default:
return 0;
break;
}
}
void sm8521_write(struct sm8521_t *sm8521, const unsigned char a, const unsigned char d)
{
if ((a & 0xe0) == 0x60)
{
if ((a & 0x10) && (!(sm8521->sgc & SM8521_SGC_SG1OUT))) // 0x70-0x7f SG1W0-15
{
sm8521->sg[1].wave[a & 0xf] = d;
}
else if ((!(a & 0x10)) && (!(sm8521->sgc & SM8521_SGC_SG0OUT))) // 0x60-0x6f SG0W0-15
{
sm8521->sg[0].wave[a & 0xf] = d;
}
return;
}
switch (a)
{
case 0x40: // SGC
sm8521->sgc = d;
break;
case 0x42: // SG0L
sm8521->sg[0].base.level = d & 0x1f;
break;
case 0x44: // SG1L
sm8521->sg[1].base.level = d & 0x1f;
break;
case 0x46: // SG0TH
sm8521->sg[0].base.t = (sm8521->sg[0].base.t & 0x0ff) | ((d << 8) & 0xf00);
break;
case 0x47: // SG0TL
sm8521->sg[0].base.t = (sm8521->sg[0].base.t & 0xf00) | (d & 0x0ff);
break;
case 0x48: // SG1TH
sm8521->sg[1].base.t = (sm8521->sg[1].base.t & 0x0ff) | ((d << 8) & 0xf00);
break;
case 0x49: // SG1TL
sm8521->sg[1].base.t = (sm8521->sg[1].base.t & 0xf00) | (d & 0x0ff);
break;
case 0x4a: // SG2L
sm8521->noise.base.level = d & 0x1f;
break;
case 0x4c: // SG2TH
sm8521->noise.base.t = (sm8521->noise.base.t & 0x0ff) | ((d << 8) & 0xf00);
break;
case 0x4d: // SG2TL
sm8521->noise.base.t = (sm8521->noise.base.t & 0xf00) | (d & 0x0ff);
break;
case 0x4e: // SGDA
sm8521->sgda = d;
break;
}
}
unsigned char sm8521_read(struct sm8521_t *sm8521, const unsigned char a);
void sm8521_write(struct sm8521_t *sm8521, const unsigned char a, const unsigned char d);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _SM8521_EMU_H

View File

@ -124,7 +124,8 @@ enum DivSystem {
DIV_SYSTEM_YM2610_CSM,
DIV_SYSTEM_YM2610B_CSM,
DIV_SYSTEM_YM2203_CSM,
DIV_SYSTEM_YM2608_CSM
DIV_SYSTEM_YM2608_CSM,
DIV_SYSTEM_SM8521
};
struct DivGroovePattern {

View File

@ -1822,6 +1822,17 @@ void DivEngine::registerSystems() {
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}
);
sysDefs[DIV_SYSTEM_SM8521]=new DivSysDef(
"Sharp SM8521", NULL, 0xc8, 0, 3, false, true, 0, false, 0,
"a SoC with wavetable sound hardware",
{"Channel 1", "Channel 2", "Noise"},
{"CH1", "CH2", "NOI"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_NOISE},
{DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO},
{},
namcoEffectHandlerMap
);
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false, 0,
"this is a system designed for testing purposes.",

View File

@ -998,6 +998,7 @@ const int availableSystems[]={
DIV_SYSTEM_MSM5232,
DIV_SYSTEM_K007232,
DIV_SYSTEM_GA20,
DIV_SYSTEM_SM8521,
DIV_SYSTEM_PCM_DAC,
DIV_SYSTEM_PONG,
0 // don't remove this last one!
@ -1084,6 +1085,7 @@ const int chipsSpecial[]={
DIV_SYSTEM_PET,
DIV_SYSTEM_VRC6,
DIV_SYSTEM_MMC5,
DIV_SYSTEM_SM8521,
0 // don't remove this last one!
};

View File

@ -2575,6 +2575,11 @@ void FurnaceGUI::initSystemPresets() {
CH(DIV_SYSTEM_SFX_BEEPER, 1.0f, 0, "")
}
);
ENTRY(
"Sharp SM8521", {
CH(DIV_SYSTEM_SM8521, 1.0f, 0, "")
}
);
if (settings.hiddenSystems) {
ENTRY(
"Dummy System", {