Begin re-porting FM code from NP2

This commit is contained in:
Jonathan Campbell 2018-02-17 01:42:28 -08:00
parent 6e879a8562
commit d3732007e3
58 changed files with 9072 additions and 3989 deletions

View File

@ -4,6 +4,7 @@
#include <math.h>
#include "inout.h"
#include "mixer.h"
// GLUE TYPEDEFS
@ -22,7 +23,6 @@ typedef uint8_t BOOL;
#endif
typedef char OEMCHAR;
typedef void* NEVENTITEM;
typedef void* NP2CFG;
#define OEMTEXT(x) (x)
#define SOUNDCALL
@ -42,6 +42,11 @@ typedef void* NP2CFG;
#define M_PI 3.14159265358979323846
#endif
enum {
PCBASECLOCK25 = 2457600,
PCBASECLOCK20 = 1996800
};
#ifndef WIN32
static inline void ZeroMemory(void *p,size_t l) {
memset(p,0,l);
@ -62,3 +67,53 @@ static inline void sound_sync(void) {
if (pc98_mixer) pc98_mixer->FillUp();
}
#ifndef IOOUTCALL
#define IOOUTCALL
#endif
#ifndef IOINPCALL
#define IOINPCALL
#endif
#ifndef BRESULT
#define BRESULT UINT
#endif
enum {
SUCCESS = 0,
FAILURE = 1
};
// HACK: Map the Neko Project II I/O handlers to DOSBox-X I/O handlers
//typedef Bitu IO_ReadHandler(Bitu port,Bitu iolen);
//typedef void IO_WriteHandler(Bitu port,Bitu val,Bitu iolen);
typedef IO_ReadHandler *IOINP;
typedef IO_WriteHandler *IOOUT;
//typedef void (IOOUTCALL *IOOUT)(UINT port, REG8 val);
//typedef REG8 (IOINPCALL *IOINP)(UINT port);
void cbuscore_attachsndex(UINT port, const IOOUT *out, const IOINP *inp);
// ƒTƒEƒ“ƒhI/O - 12bit decode
BRESULT iocore_attachsndout(UINT port, IOOUT func);
BRESULT iocore_attachsndinp(UINT port, IOINP func);
typedef struct {
UINT baseclock;
UINT multiple;
UINT16 samplingrate;
UINT8 snd86opt;
UINT8 vol14[6];
UINT8 vol_fm;
UINT8 vol_ssg;
UINT8 vol_adpcm;
UINT8 vol_pcm;
UINT8 vol_rhythm;
} NP2CFG;
extern NP2CFG np2_cfg;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "board118.h"
#include "cs4231io.h"
#include "sound.h"
#include "fmboard.h"
#include "s98.h"
static void IOOUTCALL ymf_o188(UINT port, REG8 dat) {
opn.addr = dat;
opn.data = dat;
(void)port;
}
static void IOOUTCALL ymf_o18a(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr;
if (addr >= 0x100) {
return;
}
S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg1, addr, dat);
}
}
else {
if (addr < 0x20) {
rhythm_setreg(&rhythm, addr, dat);
}
else if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon(dat & 0x0f, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x07) - 1, dat);
}
}
else {
fmtimer_setreg(addr, dat);
}
}
else if (addr < 0xc0) {
opngen_setreg(0, addr, dat);
}
opn.reg[addr] = dat;
}
(void)port;
}
static void IOOUTCALL ymf_o18c(UINT port, REG8 dat) {
if (opn.extend) {
opn.addr = dat + 0x100;
opn.data = dat;
}
(void)port;
}
static void IOOUTCALL ymf_o18e(UINT port, REG8 dat) {
UINT addr;
if (!opn.extend) {
return;
}
opn.data = dat;
addr = opn.addr - 0x100;
if (addr >= 0x100) {
return;
}
S98_put(EXTEND2608, addr, dat);
opn.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(3, addr, dat);
}
else {
if (addr == 0x10) {
if (!(dat & 0x80)) {
opn.adpcmmask = ~(dat & 0x1c);
}
}
}
(void)port;
}
static REG8 IOINPCALL ymf_i188(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL ymf_i18a(UINT port) {
UINT addr;
addr = opn.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg1));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg1, addr));
}
else if (addr == 0xff) {
return(1);
}
else {
(void)port;
return(opn.data);
}
}
static REG8 IOINPCALL ymf_i18c(UINT port) {
if (opn.extend) {
return(fmtimer.status & 3);
}
(void)port;
return(0xff);
}
static void extendchannel(REG8 enable) {
opn.extend = enable;
if (enable) {
opn.channels = 6;
opngen_setcfg(6, OPN_STEREO | 0x007);
}
else {
opn.channels = 3;
opngen_setcfg(3, OPN_MONORAL | 0x007);
rhythm_setreg(&rhythm, 0x10, 0xff);
}
}
static void IOOUTCALL ymf_oa460(UINT port, REG8 dat) {
cs4231.extfunc = dat;
extendchannel((REG8)(dat & 1));
(void)port;
}
static REG8 IOINPCALL ymf_ia460(UINT port) {
(void)port;
return(0x80 | (cs4231.extfunc & 1));
}
// ----
static const IOOUT ymf_o[4] = {
ymf_o188, ymf_o18a, ymf_o18c, ymf_o18e};
static const IOINP ymf_i[4] = {
ymf_i188, ymf_i18a, ymf_i18c, NULL};
void board118_reset(const NP2CFG *pConfig) {
fmtimer_reset(0xc0);
opngen_setcfg(3, OPN_STEREO | 0x038);
cs4231io_reset();
soundrom_load(0xcc000, OEMTEXT("118"));
fmboard_extreg(extendchannel);
(void)pConfig;
}
void board118_bind(void) {
fmboard_fmrestore(0, 0);
fmboard_fmrestore(3, 1);
psggen_restore(&psg1);
fmboard_rhyrestore(&rhythm, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcm);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
cs4231io_bind();
cbuscore_attachsndex(0x188, ymf_o, ymf_i);
iocore_attachout(0xa460, ymf_oa460);
iocore_attachinp(0xa460, ymf_ia460);
}

View File

@ -0,0 +1,12 @@
#ifdef __cplusplus
extern "C" {
#endif
void board118_reset(const NP2CFG *pConfig);
void board118_bind(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,212 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "board14.h"
#include "sound.h"
#include "fmboard.h"
// どうも 8253C-2は 4MHz/16らすい
// とりあえず 1996800/8を入力してみる... (ver0.71)
// ---- 8253C-2
UINT board14_pitcount(void) {
SINT32 clk;
clk = nevent_getremain(NEVENT_MUSICGEN);
if (clk >= 0) {
clk /= pccore.multiple;
clk /= 8;
if (!(pccore.cpumode & CPUMODE_8MHZ)) {
clk = clk * 13 / 16;
}
return(clk);
}
return(0);
}
// ---- intr
static void setmusicgenevent(UINT32 cnt, BOOL absolute) {
if (cnt > 4) { // 根拠なし
cnt *= pccore.multiple;
}
else {
cnt = pccore.multiple << 16;
}
if (!(pccore.cpumode & CPUMODE_8MHZ)) {
cnt = cnt * 16 / 13; // cnt * 2457600 / 1996800
}
cnt *= 8;
nevent_set(NEVENT_MUSICGEN, cnt, musicgenint, absolute);
}
void musicgenint(NEVENTITEM item) {
PITCH pitch;
if (item->flag & NEVENT_SETEVENT) {
pitch = pit.ch + 3;
if ((pitch->ctrl & 0x0c) == 0x04) {
// レートジェネレータ
setmusicgenevent(pitch->value, NEVENT_RELATIVE);
}
}
pic_setirq(0x0c);
(void)item;
}
// ---- I/O
static void IOOUTCALL musicgen_o088(UINT port, REG8 dat) {
musicgen.porta = dat;
(void)port;
}
static void IOOUTCALL musicgen_o08a(UINT port, REG8 dat) {
musicgen.portb = dat;
(void)port;
}
static void IOOUTCALL musicgen_o08c(UINT port, REG8 dat) {
if (dat & 0x80) {
if (!(musicgen.portc & 0x80)) {
musicgen.sync = 1;
musicgen.ch = 0;
}
else if (musicgen.sync) {
musicgen.sync = 0;
sound_sync();
musicgen.key[musicgen.ch] = dat;
tms3631_setkey(&tms3631, (REG8)musicgen.ch, dat);
}
else if ((!(dat & 0x40)) && (musicgen.portc & 0x40)) {
musicgen.sync = 1;
musicgen.ch = (musicgen.ch + 1) & 7;
}
}
musicgen.portc = dat;
(void)port;
}
static void IOOUTCALL musicgen_o188(UINT port, REG8 dat) {
sound_sync();
musicgen.mask = dat;
tms3631_setenable(&tms3631, dat);
(void)port;
}
static void IOOUTCALL musicgen_o18c(UINT port, REG8 dat) {
PITCH pitch;
pitch = pit.ch + 3;
if (!pit_setcount(pitch, dat)) {
setmusicgenevent(pitch->value, NEVENT_ABSOLUTE);
}
(void)port;
}
static void IOOUTCALL musicgen_o18e(UINT port, REG8 dat) {
pit_setflag(pit.ch + 3, dat);
(void)port;
}
static REG8 IOINPCALL musicgen_i088(UINT port) {
(void)port;
return(musicgen.porta);
}
static REG8 IOINPCALL musicgen_i08a(UINT port) {
(void)port;
return(musicgen.portb);
}
static REG8 IOINPCALL musicgen_i08c(UINT port) {
(void)port;
return(musicgen.portc);
}
static REG8 IOINPCALL musicgen_i08e(UINT port) {
(void)port;
return(0x08);
}
static REG8 IOINPCALL musicgen_i188(UINT port) {
(void)port;
return(musicgen.mask);
}
static REG8 IOINPCALL musicgen_i18c(UINT port) {
(void)port;
return(pit_getstat(pit.ch + 3));
}
static REG8 IOINPCALL musicgen_i18e(UINT port) {
(void)port;
#if 1
return(0x80); // INT-5
#else
return(0x40); // INT-5
#endif
}
// ----
static const IOOUT musicgen_o0[4] = {
musicgen_o088, musicgen_o08a, musicgen_o08c, NULL};
static const IOOUT musicgen_o1[4] = {
musicgen_o188, musicgen_o188, musicgen_o18c, musicgen_o18e};
static const IOINP musicgen_i0[4] = {
musicgen_i088, musicgen_i08a, musicgen_i08c, musicgen_i08e};
static const IOINP musicgen_i1[4] = {
musicgen_i188, musicgen_i188, musicgen_i18c, musicgen_i18e};
void board14_reset(const NP2CFG *pConfig) {
ZeroMemory(&musicgen, sizeof(musicgen));
soundrom_load(0xcc000, OEMTEXT("14"));
(void)pConfig;
}
void board14_bind(void) {
sound_streamregist(&tms3631, (SOUNDCB)tms3631_getpcm);
cbuscore_attachsndex(0x088, musicgen_o0, musicgen_i0);
cbuscore_attachsndex(0x188, musicgen_o1, musicgen_i1);
}
void board14_allkeymake(void) {
REG8 i;
for (i=0; i<8; i++) {
tms3631_setkey(&tms3631, i, musicgen.key[i]);
}
}

View File

@ -0,0 +1,17 @@
#ifdef __cplusplus
extern "C" {
#endif
void musicgenint(NEVENTITEM item);
UINT board14_pitcount(void);
void board14_allkeymake(void);
void board14_reset(const NP2CFG *pConfig);
void board14_bind(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,99 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "board26k.h"
#include "sound.h"
#include "fmboard.h"
#include "s98.h"
static void IOOUTCALL opn_o188(UINT port, REG8 dat) {
opn.addr = dat;
opn.data = dat;
(void)port;
}
static void IOOUTCALL opn_o18a(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr;
S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg1, addr, dat);
}
}
else if (addr < 0x100) {
if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon(dat & 0x0f, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[2].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(0, addr, dat);
}
opn.reg[addr] = dat;
}
(void)port;
}
static REG8 IOINPCALL opn_i188(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL opn_i18a(UINT port) {
UINT addr;
addr = opn.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg1));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg1, addr));
}
(void)port;
return(opn.data);
}
// ----
static const IOOUT opn_o[4] = {
opn_o188, opn_o18a, NULL, NULL};
static const IOINP opn_i[4] = {
opn_i188, opn_i18a, NULL, NULL};
void board26k_reset(const NP2CFG *pConfig) {
opngen_setcfg(3, 0);
fmtimer_reset(pConfig->snd26opt & 0xc0);
soundrom_loadex(pConfig->snd26opt & 7, OEMTEXT("26"));
opn.base = (pConfig->snd26opt & 0x10)?0x000:0x100;
}
void board26k_bind(void) {
fmboard_fmrestore(0, 0);
psggen_restore(&psg1);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcm);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
cbuscore_attachsndex(0x188 - opn.base, opn_o, opn_i);
}

View File

@ -0,0 +1,12 @@
#ifdef __cplusplus
extern "C" {
#endif
void board26k_reset(const NP2CFG *pConfig);
void board26k_bind(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,271 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "board86.h"
#include "pcm86io.h"
#include "sound.h"
#include "fmboard.h"
#include "s98.h"
static void IOOUTCALL opna_o188(UINT port, REG8 dat) {
opn.addr = dat;
opn.data = dat;
(void)port;
}
static void IOOUTCALL opna_o18a(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr;
if (addr >= 0x100) {
return;
}
S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg1, addr, dat);
}
}
else {
if (addr < 0x20) {
if (opn.extend) {
rhythm_setreg(&rhythm, addr, dat);
}
}
else if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon(dat & 0x0f, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x07) - 1, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[2].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(0, addr, dat);
}
opn.reg[addr] = dat;
}
(void)port;
}
static void IOOUTCALL opna_o18c(UINT port, REG8 dat) {
if (opn.extend) {
opn.addr = dat + 0x100;
opn.data = dat;
}
(void)port;
}
static void IOOUTCALL opna_o18e(UINT port, REG8 dat) {
UINT addr;
if (!opn.extend) {
return;
}
opn.data = dat;
addr = opn.addr - 0x100;
if (addr >= 0x100) {
return;
}
S98_put(EXTEND2608, addr, dat);
opn.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(3, addr, dat);
}
else {
if (addr == 0x10) {
if (!(dat & 0x80)) {
opn.adpcmmask = ~(dat & 0x1c);
}
}
}
(void)port;
}
static REG8 IOINPCALL opna_i188(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL opna_i18a(UINT port) {
UINT addr;
addr = opn.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg1));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg1, addr));
}
else if (addr == 0xff) {
return(1);
}
(void)port;
return(opn.data);
}
static REG8 IOINPCALL opna_i18c(UINT port) {
if (opn.extend) {
return((fmtimer.status & 3) | (opn.adpcmmask & 8));
}
(void)port;
return(0xff);
}
static REG8 IOINPCALL opna_i18e(UINT port) {
if (opn.extend) {
UINT addr = opn.addr - 0x100;
if ((addr == 0x08) || (addr == 0x0f)) {
return(opn.reg[addr + 0x100]);
}
return(opn.data);
}
(void)port;
return(0xff);
}
static void extendchannel(REG8 enable) {
opn.extend = enable;
if (enable) {
opn.channels = 6;
opngen_setcfg(6, OPN_STEREO | 0x007);
}
else {
opn.channels = 3;
opngen_setcfg(3, OPN_MONORAL | 0x007);
rhythm_setreg(&rhythm, 0x10, 0xff);
}
}
// ----
static const IOOUT opna_o[4] = {
opna_o188, opna_o18a, opna_o18c, opna_o18e};
static const IOINP opna_i[4] = {
opna_i188, opna_i18a, opna_i18c, opna_i18e};
void board86_reset(const NP2CFG *pConfig) {
fmtimer_reset((pConfig->snd86opt & 0x10) |
((pConfig->snd86opt & 0x4) << 5) |
((pConfig->snd86opt & 0x8) << 3));
opngen_setcfg(3, OPN_STEREO | 0x038);
if (pConfig->snd86opt & 2) {
soundrom_load(0xcc000, OEMTEXT("86"));
}
opn.base = (pConfig->snd86opt & 0x01)?0x000:0x100;
fmboard_extreg(extendchannel);
}
void board86_bind(void) {
fmboard_fmrestore(0, 0);
fmboard_fmrestore(3, 1);
psggen_restore(&psg1);
fmboard_rhyrestore(&rhythm, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcm);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
pcm86io_bind();
cbuscore_attachsndex(0x188 + opn.base, opna_o, opna_i);
}
// ---- + chibioto
static void IOOUTCALL opnac_o18e(UINT port, REG8 dat) {
UINT addr;
if (!opn.extend) {
return;
}
opn.data = dat;
addr = opn.addr - 0x100;
if (addr >= 0x100) {
return;
}
S98_put(EXTEND2608, addr, dat);
opn.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(3, addr, dat);
}
else {
if (addr < 0x12) {
adpcm_setreg(&adpcm, addr, dat);
}
}
(void)port;
}
static REG8 IOINPCALL opnac_i18c(UINT port) {
if (opn.extend) {
return((fmtimer.status & 3) | adpcm_status(&adpcm));
// return((fmtimer.status & 3) | (opn.adpcmmask & 8));
}
(void)port;
return(0xff);
}
static REG8 IOINPCALL opnac_i18e(UINT port) {
if (opn.extend) {
UINT addr = opn.addr - 0x100;
if (addr == 0x08) {
return(adpcm_readsample(&adpcm));
}
else if (addr == 0x0f) {
return(opn.reg[addr + 0x100]);
}
return(opn.data);
}
(void)port;
return(0xff);
}
static const IOOUT opnac_o[4] = {
opna_o188, opna_o18a, opna_o18c, opnac_o18e};
static const IOINP opnac_i[4] = {
opna_i188, opna_i18a, opnac_i18c, opnac_i18e};
void board86c_bind(void) {
fmboard_fmrestore(0, 0);
fmboard_fmrestore(3, 1);
psggen_restore(&psg1);
fmboard_rhyrestore(&rhythm, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcm);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
sound_streamregist(&adpcm, (SOUNDCB)adpcm_getpcm);
pcm86io_bind();
cbuscore_attachsndex(0x188 + opn.base, opnac_o, opnac_i);
}

View File

@ -0,0 +1,14 @@
#ifdef __cplusplus
extern "C" {
#endif
void board86_reset(const NP2CFG *pConfig);
void board86_bind(void);
void board86c_bind(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,741 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "boardpx.h"
#include "sound.h"
#include "fmboard.h"
#include "s98.h"
#include "pcm86io.h"
#if defined(SUPPORT_PX)
static void IOOUTCALL spb_o188(UINT port, REG8 dat) {
opn.addr = dat;
opn.data = dat;
(void)port;
}
static void IOOUTCALL spb_o18a(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr;
if (addr >= 0x100) {
return;
}
// S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg1, addr, dat);
}
}
else {
if (addr < 0x20) {
rhythm_setreg(&rhythm, addr, dat);
}
else if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon(dat & 0x0f, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) - 1, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[2].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(0, addr, dat);
}
opn.reg[addr] = dat;
}
(void)port;
}
static void IOOUTCALL spb_o18c(UINT port, REG8 dat) {
opn.addr = dat + 0x100;
opn.data = dat;
(void)port;
}
static void IOOUTCALL spb_o18e(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr - 0x100;
if (addr >= 0x100) {
return;
}
// S98_put(EXTEND2608, addr, dat);
opn.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(3, addr, dat);
}
else if (addr < 0x12) {
adpcm_setreg(&adpcm, addr, dat);
}
(void)port;
}
static REG8 IOINPCALL spb_i188(UINT port) {
(void)port;
return((fmtimer.status & 3) | adpcm_status(&adpcm));
}
static REG8 IOINPCALL spb_i18a(UINT port) {
UINT addr;
addr = opn.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg1));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg1, addr));
}
else if (addr == 0xff) {
return(1);
}
else {
(void)port;
return(opn.data);
}
}
static REG8 IOINPCALL spb_i18e(UINT port) {
UINT addr;
addr = opn.addr - 0x100;
if (addr == 0x08) {
return(adpcm_readsample(&adpcm));
}
else if (addr == 0x0f) {
return(opn.reg[addr + 0x100]);
}
else {
(void)port;
return(opn.data);
}
}
static void IOOUTCALL spb_o088(UINT port, REG8 dat) {
opn2.addr = dat;
opn2.data = dat;
(void)port;
}
static void IOOUTCALL spb_o08a(UINT port, REG8 dat) {
UINT addr;
opn2.data = dat;
addr = opn2.addr;
if (addr >= 0x100) {
return;
}
// S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg2, addr, dat);
}
}
else {
if (addr < 0x20) {
rhythm_setreg(&rhythm2, addr, dat);
}
else if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon((dat & 0x0f) + 12, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) + 11, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[14].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(12, addr, dat);
}
opn2.reg[addr] = dat;
}
(void)port;
}
static void IOOUTCALL spb_o08c(UINT port, REG8 dat) {
opn2.addr = dat + 0x100;
opn2.data = dat;
(void)port;
}
static void IOOUTCALL spb_o08e(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn2.addr - 0x100;
if (addr >= 0x100) {
return;
}
// S98_put(EXTEND2608, addr, dat);
opn2.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(15, addr, dat);
}
else if (addr < 0x12) {
adpcm_setreg(&adpcm2, addr, dat);
}
(void)port;
}
static REG8 IOINPCALL spb_i088(UINT port) {
(void)port;
return((fmtimer.status & 3) | adpcm_status(&adpcm2));
}
static REG8 IOINPCALL spb_i08a(UINT port) {
UINT addr;
addr = opn2.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg2));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg2, addr));
}
else if (addr == 0xff) {
return(1);
}
else {
(void)port;
return(opn2.data);
}
}
static REG8 IOINPCALL spb_i08e(UINT port) {
UINT addr;
addr = opn2.addr - 0x100;
if (addr == 0x08) {
return(adpcm_readsample(&adpcm2));
}
else if (addr == 0x0f) {
return(opn2.reg[addr + 0x100]);
}
else
{
(void)port;
return(opn2.data);
}
}
static void IOOUTCALL p86_o288(UINT port, REG8 dat) {
opn3.addr = dat;
opn3.data = dat;
(void)port;
}
static void IOOUTCALL p86_o28a(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr;
if (addr >= 0x100) {
return;
}
// S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg3, addr, dat);
}
}
else {
if (addr < 0x20) {
rhythm_setreg(&rhythm3, addr, dat);
}
else if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon((dat & 0x0f) + 24, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) + 23, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[26].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(24, addr, dat);
}
opn3.reg[addr] = dat;
}
(void)port;
}
static void IOOUTCALL p86_o28c(UINT port, REG8 dat) {
opn3.addr = dat + 0x100;
opn3.data = dat;
(void)port;
}
static void IOOUTCALL p86_o28e(UINT port, REG8 dat) {
UINT addr;
opn3.data = dat;
addr = opn3.addr - 0x100;
if (addr >= 0x100) {
return;
}
// S98_put(EXTEND2608, addr, dat);
opn3.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(27, addr, dat);
}
else if (addr < 0x12) {
adpcm_setreg(&adpcm3, addr, dat);
}
(void)port;
}
static REG8 IOINPCALL p86_i288(UINT port) {
(void)port;
return((fmtimer.status & 3) | adpcm_status(&adpcm3));
}
static REG8 IOINPCALL p86_i28a(UINT port) {
UINT addr;
addr = opn.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg3));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg3, addr));
}
else if (addr == 0xff) {
return(1);
}
else {
(void)port;
return(opn3.data);
}
}
static REG8 IOINPCALL p86_i28e(UINT port) {
UINT addr;
addr = opn3.addr - 0x100;
if (addr == 0x08) {
return(adpcm_readsample(&adpcm3));
}
else if (addr == 0x0f) {
return(opn3.reg[addr + 0x100]);
}
else {
(void)port;
return(opn3.data);
}
}
// ---- spark board
static void IOOUTCALL spr_o588(UINT port, REG8 dat) {
opn.addr2 = dat;
// opn.data2 = dat;
(void)port;
}
static void IOOUTCALL spr_o58a(UINT port, REG8 dat) {
UINT addr;
// opn.data2 = dat;
addr = opn.addr2;
if (addr >= 0x100) {
return;
}
if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon((dat & 0x0f) + 6, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) + 5, dat);
}
}
else {
if (addr == 0x27) {
opnch[8].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(6, addr, dat);
}
opn.reg[addr + 0x200] = dat;
(void)port;
}
static void IOOUTCALL spr_o58c(UINT port, REG8 dat) {
opn.addr2 = dat + 0x100;
// opn.data2 = dat;
(void)port;
}
static void IOOUTCALL spr_o58e(UINT port, REG8 dat) {
UINT addr;
// opn.data2 = dat;
addr = opn.addr2 - 0x100;
if (addr >= 0x100) {
return;
}
opn.reg[addr + 0x300] = dat;
if (addr >= 0x30) {
opngen_setreg(9, addr, dat);
}
(void)port;
}
static REG8 IOINPCALL spr_i588(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL spr_i58a(UINT port) {
UINT addr;
addr = opn.addr2;
if ((addr >= 0x20) && (addr < 0xff)) {
return(opn.reg[addr + 0x200]);
}
else if (addr == 0xff) {
return(0);
}
else {
(void)port;
// return(opn.data2);
return(0xff);
}
}
static REG8 IOINPCALL spr_i58c(UINT port) {
(void)port;
return(fmtimer.status & 3);
}
static REG8 IOINPCALL spr_i58e(UINT port) {
UINT addr;
addr = opn.addr2;
if (addr < 0x100) {
return(opn.reg[addr + 0x200]);
}
else {
(void)port;
// return(opn.data2);
return(0xff);
}
}
static void IOOUTCALL spr_o488(UINT port, REG8 dat) {
opn2.addr2 = dat;
// opn2.data2 = dat;
(void)port;
}
static void IOOUTCALL spr_o48a(UINT port, REG8 dat) {
UINT addr;
// opn2.data2 = dat;
addr = opn2.addr2;
if (addr >= 0x100) {
return;
}
if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon((dat & 0x0f) + 18, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) + 17, dat);
}
}
else {
if (addr == 0x27) {
opnch[20].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(18, addr, dat);
}
opn2.reg[addr + 0x200] = dat;
(void)port;
}
static void IOOUTCALL spr_o48c(UINT port, REG8 dat) {
opn2.addr2 = dat + 0x100;
// opn2.data2 = dat;
(void)port;
}
static void IOOUTCALL spr_o48e(UINT port, REG8 dat) {
UINT addr;
// opn.data2 = dat;
addr = opn2.addr2 - 0x100;
if (addr >= 0x100) {
return;
}
opn2.reg[addr + 0x300] = dat;
if (addr >= 0x30) {
opngen_setreg(21, addr, dat);
}
(void)port;
}
static REG8 IOINPCALL spr_i488(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL spr_i48a(UINT port) {
UINT addr;
addr = opn2.addr2;
if ((addr >= 0x20) && (addr < 0xff)) {
return(opn2.reg[addr + 0x200]);
}
else if (addr == 0xff) {
return(0);
}
else {
(void)port;
// return(opn2.data2);
return(0xff);
}
}
static REG8 IOINPCALL spr_i48c(UINT port) {
(void)port;
return(fmtimer.status & 3);
}
static REG8 IOINPCALL spr_i48e(UINT port) {
UINT addr;
addr = opn2.addr2;
if (addr < 0x100) {
return(opn2.reg[addr + 0x200]);
}
else {
(void)port;
// return(opn2.data2);
return(0xff);
}
}
// ----
static const IOOUT spb_o[4] = {
spb_o188, spb_o18a, spb_o18c, spb_o18e};
static const IOINP spb_i[4] = {
spb_i188, spb_i18a, spb_i188, spb_i18e};
static const IOOUT spb_o2[4] = {
spb_o088, spb_o08a, spb_o08c, spb_o08e};
static const IOINP spb_i2[4] = {
spb_i088, spb_i08a, spb_i088, spb_i08e};
static const IOOUT p86_o3[4] = {
p86_o288, p86_o28a, p86_o28c, p86_o28e};
static const IOINP p86_i3[4] = {
p86_i288, p86_i28a, p86_i288, p86_i28e};
// ----
static const IOOUT spr_o[4] = {
spr_o588, spr_o58a, spr_o58c, spr_o58e};
static const IOINP spr_i[4] = {
spr_i588, spr_i58a, spr_i58c, spr_i58e};
static const IOOUT spr_o2[4] = {
spr_o488, spr_o48a, spr_o48c, spr_o48e};
static const IOINP spr_i2[4] = {
spr_i488, spr_i48a, spr_i48c, spr_i48e};
void boardpx1_reset(const NP2CFG *pConfig) {
fmtimer_reset(pConfig->spbopt & 0xc0);
opn.reg[0x2ff] = 0;
opn.channels = 12;
opn2.reg[0x2ff] = 0;
opn2.channels = 12;
opngen_setcfg(24, OPN_STEREO | 0x00ffffff);
soundrom_loadex(pConfig->spbopt & 7, OEMTEXT("SPB"));
opn.base = (pConfig->spbopt & 0x10)?0x000:0x100;
}
void boardpx1_bind(void) {
fmboard_fmrestore(0, 0);
fmboard_fmrestore(3, 1);
fmboard_fmrestore(6, 2);
fmboard_fmrestore(9, 3);
fmboard_fmrestore2(&opn2, 12, 0);
fmboard_fmrestore2(&opn2, 15, 1);
fmboard_fmrestore2(&opn2, 18, 2);
fmboard_fmrestore2(&opn2, 21, 3);
psggen_restore(&psg1);
psggen_restore(&psg2);
fmboard_rhyrestore(&rhythm, 0);
fmboard_rhyrestore2(&opn2, &rhythm2, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcmvr);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
sound_streamregist(&psg2, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
rhythm_bind(&rhythm2);
sound_streamregist(&adpcm, (SOUNDCB)adpcm_getpcm);
sound_streamregist(&adpcm2, (SOUNDCB)adpcm_getpcm);
cbuscore_attachsndex(0x188, spb_o, spb_i);
cbuscore_attachsndex(0x588, spr_o, spr_i);
cbuscore_attachsndex(0x088, spb_o2, spb_i2);
cbuscore_attachsndex(0x488, spr_o2, spr_i2);
}
static void extendchannelx2(REG8 enable) {
opn3.extend = enable;
if (enable) {
opn3.channels = 6;
opngen_setcfg(30, OPN_STEREO | 0x07000000);
}
else {
opn3.channels = 3;
opngen_setcfg(27, OPN_MONORAL | 0x07000000);
rhythm_setreg(&rhythm2, 0x10, 0xff);
}
}
void boardpx2_reset(const NP2CFG *pConfig) {
fmtimer_reset(pConfig->spbopt & 0xc0);
opn.reg[0x2ff] = 0;
opn.channels = 12;
opn2.reg[0x2ff] = 0;
opn2.channels = 12;
opn3.channels = 3;
opngen_setcfg(27, OPN_STEREO | 0x38ffffff);
soundrom_loadex(pConfig->spbopt & 7, OEMTEXT("SPB"));
opn.base = (pConfig->spbopt & 0x10)?0x000:0x100;
fmboard_extreg(extendchannelx2);
}
void boardpx2_bind(void) {
fmboard_fmrestore(0, 0);
fmboard_fmrestore(3, 1);
fmboard_fmrestore(6, 2);
fmboard_fmrestore(9, 3);
fmboard_fmrestore2(&opn2, 12, 0);
fmboard_fmrestore2(&opn2, 15, 1);
fmboard_fmrestore2(&opn2, 18, 2);
fmboard_fmrestore2(&opn2, 21, 3);
fmboard_fmrestore2(&opn3, 24, 0);
fmboard_fmrestore2(&opn3, 27, 1);
psggen_restore(&psg1);
psggen_restore(&psg2);
psggen_restore(&psg3);
fmboard_rhyrestore(&rhythm, 0);
fmboard_rhyrestore2(&opn2, &rhythm2, 0);
fmboard_rhyrestore2(&opn3, &rhythm3, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcmvr);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
sound_streamregist(&psg2, (SOUNDCB)psggen_getpcm);
sound_streamregist(&psg3, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
rhythm_bind(&rhythm2);
rhythm_bind(&rhythm3);
sound_streamregist(&adpcm, (SOUNDCB)adpcm_getpcm);
sound_streamregist(&adpcm2, (SOUNDCB)adpcm_getpcm);
sound_streamregist(&adpcm3, (SOUNDCB)adpcm_getpcm);
pcm86io_bind();
cbuscore_attachsndex(0x188, spb_o, spb_i);
cbuscore_attachsndex(0x588, spr_o, spr_i);
cbuscore_attachsndex(0x088, spb_o2, spb_i2);
cbuscore_attachsndex(0x488, spr_o2, spr_i2);
cbuscore_attachsndex(0x288, p86_o3, p86_i3);
}
#endif // defined(SUPPORT_PX)

View File

@ -0,0 +1,19 @@
#if defined(SUPPORT_PX)
#ifdef __cplusplus
extern "C" {
#endif
void boardpx1_reset(const NP2CFG *pConfig);
void boardpx1_bind(void);
void boardpx2_reset(const NP2CFG *pConfig);
void boardpx2_bind(void);
#ifdef __cplusplus
}
#endif
#endif // defined(SUPPORT_PX)

View File

@ -0,0 +1,309 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "boardspb.h"
#include "sound.h"
#include "fmboard.h"
#include "s98.h"
static void IOOUTCALL spb_o188(UINT port, REG8 dat) {
opn.addr = dat;
opn.data = dat;
(void)port;
}
static void IOOUTCALL spb_o18a(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr;
if (addr >= 0x100) {
return;
}
S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg1, addr, dat);
}
}
else {
if (addr < 0x20) {
rhythm_setreg(&rhythm, addr, dat);
}
else if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon(dat & 0x0f, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) - 1, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[2].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(0, addr, dat);
}
opn.reg[addr] = dat;
}
(void)port;
}
static void IOOUTCALL spb_o18c(UINT port, REG8 dat) {
opn.addr = dat + 0x100;
opn.data = dat;
(void)port;
}
static void IOOUTCALL spb_o18e(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr - 0x100;
if (addr >= 0x100) {
return;
}
S98_put(EXTEND2608, addr, dat);
opn.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(3, addr, dat);
}
else if (addr < 0x12) {
adpcm_setreg(&adpcm, addr, dat);
}
(void)port;
}
static REG8 IOINPCALL spb_i188(UINT port) {
(void)port;
return((fmtimer.status & 3) | adpcm_status(&adpcm));
}
static REG8 IOINPCALL spb_i18a(UINT port) {
UINT addr;
addr = opn.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg1));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg1, addr));
}
else if (addr == 0xff) {
return(1);
}
else {
(void)port;
return(opn.data);
}
}
static REG8 IOINPCALL spb_i18e(UINT port) {
UINT addr;
addr = opn.addr - 0x100;
if (addr == 0x08) {
return(adpcm_readsample(&adpcm));
}
else if (addr == 0x0f) {
return(opn.reg[addr + 0x100]);
}
else {
(void)port;
return(opn.data);
}
}
// ---- spark board
static void IOOUTCALL spr_o588(UINT port, REG8 dat) {
opn.addr2 = dat;
// opn.data2 = dat;
(void)port;
}
static void IOOUTCALL spr_o58a(UINT port, REG8 dat) {
UINT addr;
// opn.data2 = dat;
addr = opn.addr2;
if (addr >= 0x100) {
return;
}
if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon((dat & 0x0f) + 6, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) + 5, dat);
}
}
else {
if (addr == 0x27) {
opnch[8].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(6, addr, dat);
}
opn.reg[addr + 0x200] = dat;
(void)port;
}
static void IOOUTCALL spr_o58c(UINT port, REG8 dat) {
opn.addr2 = dat + 0x100;
// opn.data2 = dat;
(void)port;
}
static void IOOUTCALL spr_o58e(UINT port, REG8 dat) {
UINT addr;
// opn.data2 = dat;
addr = opn.addr2 - 0x100;
if (addr >= 0x100) {
return;
}
opn.reg[addr + 0x300] = dat;
if (addr >= 0x30) {
opngen_setreg(9, addr, dat);
}
(void)port;
}
static REG8 IOINPCALL spr_i588(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL spr_i58a(UINT port) {
UINT addr;
addr = opn.addr2;
if ((addr >= 0x20) && (addr < 0xff)) {
return(opn.reg[addr + 0x200]);
}
else if (addr == 0xff) {
return(0);
}
else {
(void)port;
// return(opn.data2);
return(0xff);
}
}
static REG8 IOINPCALL spr_i58c(UINT port) {
(void)port;
return(fmtimer.status & 3);
}
static REG8 IOINPCALL spr_i58e(UINT port) {
UINT addr;
addr = opn.addr2;
if (addr < 0x100) {
return(opn.reg[addr + 0x200]);
}
else {
(void)port;
// return(opn.data2);
return(0xff);
}
}
// ----
static const IOOUT spb_o[4] = {
spb_o188, spb_o18a, spb_o18c, spb_o18e};
static const IOINP spb_i[4] = {
spb_i188, spb_i18a, spb_i188, spb_i18e};
void boardspb_reset(const NP2CFG *pConfig) {
fmtimer_reset(pConfig->spbopt & 0xc0);
opn.channels = 6;
opngen_setcfg(6, OPN_STEREO | 0x03f);
soundrom_loadex(pConfig->spbopt & 7, OEMTEXT("SPB"));
opn.base = ((pConfig->spbopt & 0x10)?0x000:0x100);
}
void boardspb_bind(void) {
fmboard_fmrestore(0, 0);
fmboard_fmrestore(3, 1);
psggen_restore(&psg1);
fmboard_rhyrestore(&rhythm, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcmvr);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
sound_streamregist(&adpcm, (SOUNDCB)adpcm_getpcm);
cbuscore_attachsndex(0x188 - opn.base, spb_o, spb_i);
}
// ----
static const IOOUT spr_o[4] = {
spr_o588, spr_o58a, spr_o58c, spr_o58e};
static const IOINP spr_i[4] = {
spr_i588, spr_i58a, spr_i58c, spr_i58e};
void boardspr_reset(const NP2CFG *pConfig) {
fmtimer_reset(pConfig->spbopt & 0xc0);
opn.reg[0x2ff] = 0;
opn.channels = 12;
opngen_setcfg(12, OPN_STEREO | 0x03f);
soundrom_loadex(pConfig->spbopt & 7, OEMTEXT("SPB"));
opn.base = (pConfig->spbopt & 0x10)?0x000:0x100;
}
void boardspr_bind(void) {
fmboard_fmrestore(0, 0);
fmboard_fmrestore(3, 1);
fmboard_fmrestore(6, 2);
fmboard_fmrestore(9, 3);
psggen_restore(&psg1);
fmboard_rhyrestore(&rhythm, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcmvr);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
sound_streamregist(&adpcm, (SOUNDCB)adpcm_getpcm);
cbuscore_attachsndex(0x188 - opn.base, spb_o, spb_i);
cbuscore_attachsndex(0x588 - opn.base, spr_o, spr_i);
}

View File

@ -0,0 +1,15 @@
#ifdef __cplusplus
extern "C" {
#endif
void boardspb_reset(const NP2CFG *pConfig);
void boardspb_bind(void);
void boardspr_reset(const NP2CFG *pConfig);
void boardspr_bind(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,271 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "boardx2.h"
#include "pcm86io.h"
#include "sound.h"
#include "fmboard.h"
#include "s98.h"
static void IOOUTCALL opn_o088(UINT port, REG8 dat) {
opn.addr2 = dat;
opn.data2 = dat;
(void)port;
}
static void IOOUTCALL opn_o08a(UINT port, REG8 dat) {
UINT addr;
opn.data2 = dat;
addr = opn.addr2;
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg1, addr, dat);
}
}
else {
if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon(dat & 0x0f, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[2].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(0, addr, dat);
}
opn.reg[addr + 0x200] = dat;
}
(void)port;
}
static REG8 IOINPCALL opn_i088(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL opn_i08a(UINT port) {
UINT addr;
addr = opn.addr2;
if (addr == 0x0e) {
return(0xff);
}
if (addr < 0x10) {
return(psggen_getreg(&psg1, addr));
}
else {
(void)port;
return(opn.data2);
}
}
// ----
static void IOOUTCALL opna_o188(UINT port, REG8 dat) {
opn.addr = dat;
opn.data = dat;
(void)port;
}
static void IOOUTCALL opna_o18a(UINT port, REG8 dat) {
UINT addr;
opn.data = dat;
addr = opn.addr;
if (addr >= 0x100) {
return;
}
S98_put(NORMAL2608, addr, dat);
if (addr < 0x10) {
if (addr != 0x0e) {
psggen_setreg(&psg2, addr, dat);
}
}
else {
if (addr < 0x20) {
if (opn.extend) {
rhythm_setreg(&rhythm, addr, dat);
}
}
else if (addr < 0x30) {
if (addr == 0x28) {
if ((dat & 0x0f) < 3) {
opngen_keyon((dat & 0x0f) + 3, dat);
}
else if (((dat & 0x0f) != 3) &&
((dat & 0x0f) < 7)) {
opngen_keyon((dat & 0x0f) + 2, dat);
}
}
else {
fmtimer_setreg(addr, dat);
if (addr == 0x27) {
opnch[2].extop = dat & 0xc0;
}
}
}
else if (addr < 0xc0) {
opngen_setreg(3, addr, dat);
}
opn.reg[addr] = dat;
}
(void)port;
}
static void IOOUTCALL opna_o18c(UINT port, REG8 dat) {
if (opn.extend) {
opn.addr = dat + 0x100;
opn.data = dat;
}
(void)port;
}
static void IOOUTCALL opna_o18e(UINT port, REG8 dat) {
UINT addr;
if (!opn.extend) {
return;
}
addr = opn.addr - 0x100;
if (addr >= 0x100) {
return;
}
S98_put(EXTEND2608, addr, dat);
opn.reg[addr + 0x100] = dat;
if (addr >= 0x30) {
opngen_setreg(6, addr, dat);
}
else {
if (addr == 0x10) {
if (!(dat & 0x80)) {
opn.adpcmmask = ~(dat & 0x1c);
}
}
}
(void)port;
}
static REG8 IOINPCALL opna_i188(UINT port) {
(void)port;
return(fmtimer.status);
}
static REG8 IOINPCALL opna_i18a(UINT port) {
UINT addr;
addr = opn.addr;
if (addr == 0x0e) {
return(fmboard_getjoy(&psg2));
}
else if (addr < 0x10) {
return(psggen_getreg(&psg2, addr));
}
else if (addr == 0xff) {
return(1);
}
else {
(void)port;
return(opn.data);
}
}
static REG8 IOINPCALL opna_i18c(UINT port) {
if (opn.extend) {
return((fmtimer.status & 3) | (opn.adpcmmask & 8));
}
(void)port;
return(0xff);
}
static REG8 IOINPCALL opna_i18e(UINT port) {
if (opn.extend) {
UINT addr = opn.addr - 0x100;
if ((addr == 0x08) || (addr == 0x0f)) {
return(opn.reg[addr + 0x100]);
}
return(opn.data);
}
(void)port;
return(0xff);
}
static void extendchannel(REG8 enable) {
opn.extend = enable;
if (enable) {
opn.channels = 9;
opngen_setcfg(9, OPN_STEREO | 0x038);
}
else {
opn.channels = 6;
opngen_setcfg(6, OPN_MONORAL | 0x038);
rhythm_setreg(&rhythm, 0x10, 0xff);
}
}
// ----
static const IOOUT opn_o[4] = {
opn_o088, opn_o08a, NULL, NULL};
static const IOINP opn_i[4] = {
opn_i088, opn_i08a, NULL, NULL};
static const IOOUT opna_o[4] = {
opna_o188, opna_o18a, opna_o18c, opna_o18e};
static const IOINP opna_i[4] = {
opna_i188, opna_i18a, opna_i18c, opna_i18e};
void boardx2_reset(const NP2CFG *pConfig) {
fmtimer_reset(0xc0);
opn.channels = 6;
opngen_setcfg(6, OPN_STEREO | 0x1c0);
soundrom_load(0xcc000, OEMTEXT("86"));
fmboard_extreg(extendchannel);
(void)pConfig;
}
void boardx2_bind(void) {
fmboard_fmrestore(0, 2);
fmboard_fmrestore(3, 0);
fmboard_fmrestore(6, 1);
psggen_restore(&psg1);
psggen_restore(&psg2);
fmboard_rhyrestore(&rhythm, 0);
sound_streamregist(&opngen, (SOUNDCB)opngen_getpcm);
sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
sound_streamregist(&psg2, (SOUNDCB)psggen_getpcm);
rhythm_bind(&rhythm);
pcm86io_bind();
cbuscore_attachsndex(0x088, opn_o, opn_i);
cbuscore_attachsndex(0x188, opna_o, opna_i);
}

View File

@ -0,0 +1,12 @@
#ifdef __cplusplus
extern "C" {
#endif
void boardx2_reset(const NP2CFG *pConfig);
void boardx2_bind(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,256 @@
#include "compiler.h"
#include "cpucore.h"
#include "pccore.h"
#include "iocore.h"
#include "pcm86io.h"
#include "sound.h"
#include "fmboard.h"
extern PCM86CFG pcm86cfg;
static const UINT8 pcm86bits[] = {1, 1, 1, 2, 0, 0, 0, 1};
static const SINT32 pcm86rescue[] = {PCM86_RESCUE * 32, PCM86_RESCUE * 24,
PCM86_RESCUE * 16, PCM86_RESCUE * 12,
PCM86_RESCUE * 8, PCM86_RESCUE * 6,
PCM86_RESCUE * 4, PCM86_RESCUE * 3};
static void IOOUTCALL pcm86_oa460(UINT port, REG8 val) {
// TRACEOUT(("86pcm out %.4x %.2x", port, val));
pcm86.extfunc = val;
fmboard_extenable((REG8)(val & 1));
(void)port;
}
static void IOOUTCALL pcm86_oa466(UINT port, REG8 val) {
// TRACEOUT(("86pcm out %.4x %.2x", port, val));
if ((val & 0xe0) == 0xa0) {
sound_sync();
pcm86.vol5 = (~val) & 15;
pcm86.volume = pcm86cfg.vol * pcm86.vol5;
}
(void)port;
}
static void IOOUTCALL pcm86_oa468(UINT port, REG8 val) {
REG8 xchgbit;
// TRACEOUT(("86pcm out %.4x %.2x", port, val));
sound_sync();
xchgbit = pcm86.fifo ^ val;
// バッファリセット判定
if ((xchgbit & 8) && (val & 8)) {
pcm86.readpos = 0; // バッファリセット
pcm86.wrtpos = 0;
pcm86.realbuf = 0;
pcm86.virbuf = 0;
pcm86.lastclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
pcm86.lastclock <<= 6;
}
if ((xchgbit & 0x10) && (!(val & 0x10))) {
pcm86.irqflag = 0;
// pcm86.write = 0;
// pcm86.reqirq = 0;
}
// サンプリングレート変更
if (xchgbit & 7) {
pcm86.rescue = pcm86rescue[val & 7] << pcm86.stepbit;
pcm86_setpcmrate(val);
}
#if 1 // これ重大なバグ....
pcm86.fifo = val;
#else
pcm86.fifo = val & (~0x10);
#endif
if ((xchgbit & 0x80) && (val & 0x80)) {
pcm86.lastclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
pcm86.lastclock <<= 6;
}
pcm86_setnextintr();
(void)port;
}
static void IOOUTCALL pcm86_oa46a(UINT port, REG8 val) {
// TRACEOUT(("86pcm out %.4x %.2x", port, val));
sound_sync();
if (pcm86.fifo & 0x20) {
#if 1
if (val != 0xff) {
pcm86.fifosize = (UINT16)((val + 1) << 7);
}
else {
pcm86.fifosize = 0x7ffc;
}
#else
if (!val) {
val++;
}
pcm86.fifosize = (WORD)(val) << 7;
#endif
}
else {
pcm86.dactrl = val;
pcm86.stepbit = pcm86bits[(val >> 4) & 7];
pcm86.stepmask = (1 << pcm86.stepbit) - 1;
pcm86.rescue = pcm86rescue[pcm86.fifo & 7] << pcm86.stepbit;
}
pcm86_setnextintr();
(void)port;
}
static void IOOUTCALL pcm86_oa46c(UINT port, REG8 val) {
// TRACEOUT(("86pcm out %.4x %.2x", port, val));
#if 1
if (pcm86.virbuf < PCM86_LOGICALBUF) {
pcm86.virbuf++;
}
pcm86.buffer[pcm86.wrtpos] = val;
pcm86.wrtpos = (pcm86.wrtpos + 1) & PCM86_BUFMSK;
pcm86.realbuf++;
// バッファオーバーフローの監視
if (pcm86.realbuf >= PCM86_REALBUFSIZE) {
#if 1
pcm86.realbuf -= 4;
pcm86.readpos = (pcm86.readpos + 4) & PCM86_BUFMSK;
#else
pcm86.realbuf &= 3; // align4決めウチ
pcm86.realbuf += PCM86_REALBUFSIZE - 4;
#endif
}
// pcm86.write = 1;
pcm86.reqirq = 1;
#else
if (pcm86.virbuf < PCM86_LOGICALBUF) {
pcm86.virbuf++;
pcm86.buffer[pcm86.wrtpos] = val;
pcm86.wrtpos = (pcm86.wrtpos + 1) & PCM86_BUFMSK;
pcm86.realbuf++;
// バッファオーバーフローの監視
if (pcm86.realbuf >= PCM86_REALBUFSIZE) {
pcm86.realbuf &= 3; // align4決めウチ
pcm86.realbuf += PCM86_REALBUFSIZE - 4;
}
// pcm86.write = 1;
pcm86.reqirq = 1;
}
#endif
(void)port;
}
static REG8 IOINPCALL pcm86_ia460(UINT port) {
(void)port;
return(0x40 | (pcm86.extfunc & 1));
}
static REG8 IOINPCALL pcm86_ia466(UINT port) {
UINT32 past;
UINT32 cnt;
UINT32 stepclock;
REG8 ret;
past = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
past <<= 6;
past -= pcm86.lastclock;
stepclock = pcm86.stepclock;
if (past >= stepclock) {
cnt = past / stepclock;
pcm86.lastclock += (cnt * stepclock);
past -= cnt * stepclock;
if (pcm86.fifo & 0x80) {
sound_sync();
RECALC_NOWCLKWAIT(cnt);
}
}
ret = ((past << 1) >= stepclock)?1:0;
if (pcm86.virbuf >= PCM86_LOGICALBUF) { // バッファフル
ret |= 0x80;
}
else if (!pcm86.virbuf) { // バッファ0
ret |= 0x40; // ちと変…
}
(void)port;
// TRACEOUT(("86pcm in %.4x %.2x", port, ret));
return(ret);
}
static REG8 IOINPCALL pcm86_ia468(UINT port) {
REG8 ret;
ret = pcm86.fifo & (~0x10);
#if 1
if (pcm86gen_intrq()) {
ret |= 0x10;
}
#elif 1 // むしろこう?
if (pcm86.fifo & 0x20) {
sound_sync();
if (pcm86.virbuf <= pcm86.fifosize) {
if (pcm86.write) {
pcm86.write = 0;
}
else {
ret |= 0x10;
}
}
}
#else
if ((pcm86.write) && (pcm86.fifo & 0x20)) {
// pcm86.write = 0;
sound_sync();
if (pcm86.virbuf <= pcm86.fifosize) {
pcm86.write = 0;
ret |= 0x10;
}
}
#endif
(void)port;
// TRACEOUT(("86pcm in %.4x %.2x", port, ret));
return(ret);
}
static REG8 IOINPCALL pcm86_ia46a(UINT port) {
(void)port;
// TRACEOUT(("86pcm in %.4x %.2x", port, pcm86.dactrl));
return(pcm86.dactrl);
}
static REG8 IOINPCALL pcm86_inpdummy(UINT port) {
(void)port;
return(0);
}
// ----
void pcm86io_bind(void) {
sound_streamregist(&pcm86, (SOUNDCB)pcm86gen_getpcm);
iocore_attachout(0xa460, pcm86_oa460);
iocore_attachout(0xa466, pcm86_oa466);
iocore_attachout(0xa468, pcm86_oa468);
iocore_attachout(0xa46a, pcm86_oa46a);
iocore_attachout(0xa46c, pcm86_oa46c);
iocore_attachinp(0xa460, pcm86_ia460);
iocore_attachinp(0xa462, pcm86_inpdummy);
iocore_attachinp(0xa464, pcm86_inpdummy);
iocore_attachinp(0xa466, pcm86_ia466);
iocore_attachinp(0xa468, pcm86_ia468);
iocore_attachinp(0xa46a, pcm86_ia46a);
iocore_attachinp(0xa46c, pcm86_inpdummy);
iocore_attachinp(0xa46e, pcm86_inpdummy);
}

View File

@ -0,0 +1,12 @@
#ifdef __cplusplus
extern "C" {
#endif
void pcm86io_bind(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,77 @@
enum {
ADTIMING_BIT = 11,
ADTIMING = (1 << ADTIMING_BIT),
ADPCM_SHIFT = 3
};
typedef struct {
UINT8 ctrl1; // 00
UINT8 ctrl2; // 01
UINT8 start[2]; // 02
UINT8 stop[2]; // 04
UINT8 reg06;
UINT8 reg07;
UINT8 data; // 08
UINT8 delta[2]; // 09
UINT8 level; // 0b
UINT8 limit[2]; // 0c
UINT8 reg0e;
UINT8 reg0f;
UINT8 flag; // 10
UINT8 reg11;
UINT8 reg12;
UINT8 reg13;
} ADPCMREG;
typedef struct {
ADPCMREG reg;
UINT32 pos;
UINT32 start;
UINT32 stop;
UINT32 limit;
SINT32 level;
UINT32 base;
SINT32 samp;
SINT32 delta;
SINT32 remain;
SINT32 step;
SINT32 out0;
SINT32 out1;
SINT32 fb;
SINT32 pertim;
UINT8 status;
UINT8 play;
UINT8 mask;
UINT8 fifopos;
UINT8 fifo[2];
UINT8 padding[2];
UINT8 buf[0x40000];
} _ADPCM, *ADPCM;
typedef struct {
UINT rate;
UINT vol;
} ADPCMCFG;
#ifdef __cplusplus
extern "C" {
#endif
void adpcm_initialize(UINT rate);
void adpcm_setvol(UINT vol);
void adpcm_reset(ADPCM ad);
void adpcm_update(ADPCM ad);
void adpcm_setreg(ADPCM ad, UINT reg, REG8 value);
REG8 adpcm_status(ADPCM ad);
REG8 SOUNDCALL adpcm_readsample(ADPCM ad);
void SOUNDCALL adpcm_datawrite(ADPCM ad, REG8 data);
void SOUNDCALL adpcm_getpcm(ADPCM ad, SINT32 *buf, UINT count);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,122 @@
#include "compiler.h"
#include "sound.h"
#include "opngen.h"
#include "adpcm.h"
ADPCMCFG adpcmcfg;
void adpcm_initialize(UINT rate) {
adpcmcfg.rate = rate;
}
void adpcm_setvol(UINT vol) {
adpcmcfg.vol = vol;
}
void adpcm_reset(ADPCM ad) {
ZeroMemory(ad, sizeof(_ADPCM));
ad->mask = 0; // (UINT8)~0x1c;
ad->delta = 127;
STOREINTELWORD(ad->reg.stop, 0x0002);
STOREINTELWORD(ad->reg.limit, 0xffff);
ad->stop = 0x000060;
ad->limit = 0x200000;
adpcm_update(ad);
}
void adpcm_update(ADPCM ad) {
UINT32 addr;
if (adpcmcfg.rate) {
ad->base = ADTIMING * (OPNA_CLOCK / 72) / adpcmcfg.rate;
}
addr = LOADINTELWORD(ad->reg.delta);
addr = (addr * ad->base) >> 16;
if (addr < 0x80) {
addr = 0x80;
}
ad->step = addr;
ad->pertim = (1 << (ADTIMING_BIT * 2)) / addr;
ad->level = (ad->reg.level * adpcmcfg.vol) >> 4;
}
void adpcm_setreg(ADPCM ad, UINT reg, REG8 value) {
UINT32 addr;
sound_sync();
((UINT8 *)(&ad->reg))[reg] = value;
switch(reg) {
case 0x00: // control1
if ((value & 0x80) && (!ad->play)) {
ad->play = 0x20;
ad->pos = ad->start;
ad->samp = 0;
ad->delta = 127;
ad->remain = 0;
}
if (value & 1) {
ad->play = 0;
}
break;
case 0x01: // control2
break;
case 0x02: case 0x03: // start address
addr = (LOADINTELWORD(ad->reg.start)) << 5;
ad->pos = addr;
ad->start = addr;
break;
case 0x04: case 0x05: // stop address
addr = (LOADINTELWORD(ad->reg.stop) + 1) << 5;
ad->stop = addr;
break;
case 0x08: // data
if ((ad->reg.ctrl1 & 0x60) == 0x60) {
adpcm_datawrite(ad, value);
}
break;
case 0x09: case 0x0a: // delta
addr = LOADINTELWORD(ad->reg.delta);
addr = (addr * ad->base) >> 16;
if (addr < 0x80) {
addr = 0x80;
}
ad->step = addr;
ad->pertim = (1 << (ADTIMING_BIT * 2)) / addr;
break;
case 0x0b: // level
ad->level = (value * adpcmcfg.vol) >> 4;
break;
case 0x0c: case 0x0d: // limit address
addr = (LOADINTELWORD(ad->reg.limit) + 1) << 5;
ad->limit = addr;
break;
case 0x10: // flag
if (value & 0x80) {
ad->status = 0;
}
else {
ad->mask = ~(value & 0x1f);
}
break;
}
}
REG8 adpcm_status(ADPCM ad) {
return(((ad->status | 8) & ad->mask) | ad->play);
}

View File

@ -0,0 +1,292 @@
#include "compiler.h"
#include "sound.h"
#include "adpcm.h"
#define ADPCM_NBR 0x80000000
static const UINT adpcmdeltatable[8] = {
// 0.89, 0.89, 0.89, 0.89, 1.2, 1.6, 2.0, 2.4
228, 228, 228, 228, 308, 408, 512, 612};
REG8 SOUNDCALL adpcm_readsample(ADPCM ad) {
UINT32 pos;
REG8 data;
REG8 ret;
if ((ad->reg.ctrl1 & 0x60) == 0x20) {
pos = ad->pos & 0x1fffff;
if (!(ad->reg.ctrl2 & 2)) {
data = ad->buf[pos >> 3];
pos += 8;
}
else {
const UINT8 *ptr;
REG8 bit;
UINT tmp;
ptr = ad->buf + ((pos >> 3) & 0x7fff);
bit = 1 << (pos & 7);
tmp = (ptr[0x00000] & bit);
tmp += (ptr[0x08000] & bit) << 1;
tmp += (ptr[0x10000] & bit) << 2;
tmp += (ptr[0x18000] & bit) << 3;
tmp += (ptr[0x20000] & bit) << 4;
tmp += (ptr[0x28000] & bit) << 5;
tmp += (ptr[0x30000] & bit) << 6;
tmp += (ptr[0x38000] & bit) << 7;
data = (REG8)(tmp >> (pos & 7));
pos++;
}
if (pos != ad->stop) {
pos &= 0x1fffff;
ad->status |= 4;
}
if (pos >= ad->limit) {
pos = 0;
}
ad->pos = pos;
}
else {
data = 0;
}
pos = ad->fifopos;
ret = ad->fifo[ad->fifopos];
ad->fifo[ad->fifopos] = data;
ad->fifopos ^= 1;
return(ret);
}
void SOUNDCALL adpcm_datawrite(ADPCM ad, REG8 data) {
UINT32 pos;
pos = ad->pos & 0x1fffff;
if (!(ad->reg.ctrl2 & 2)) {
ad->buf[pos >> 3] = data;
pos += 8;
}
else {
UINT8 *ptr;
UINT8 bit;
UINT8 mask;
ptr = ad->buf + ((pos >> 3) & 0x7fff);
bit = 1 << (pos & 7);
mask = ~bit;
ptr[0x00000] &= mask;
if (data & 0x01) {
ptr[0x00000] |= bit;
}
ptr[0x08000] &= mask;
if (data & 0x02) {
ptr[0x08000] |= bit;
}
ptr[0x10000] &= mask;
if (data & 0x04) {
ptr[0x10000] |= bit;
}
ptr[0x18000] &= mask;
if (data & 0x08) {
ptr[0x18000] |= bit;
}
ptr[0x20000] &= mask;
if (data & 0x10) {
ptr[0x20000] |= bit;
}
ptr[0x28000] &= mask;
if (data & 0x20) {
ptr[0x28000] |= bit;
}
ptr[0x30000] &= mask;
if (data & 0x40) {
ptr[0x30000] |= bit;
}
ptr[0x38000] &= mask;
if (data & 0x80) {
ptr[0x38000] |= bit;
}
pos++;
}
if (pos == ad->stop) {
pos &= 0x1fffff;
ad->status |= 4;
}
if (pos >= ad->limit) {
pos = 0;
}
ad->pos = pos;
}
static void SOUNDCALL getadpcmdata(ADPCM ad) {
UINT32 pos;
UINT data;
UINT dir;
SINT32 dlt;
SINT32 samp;
pos = ad->pos;
if (!(ad->reg.ctrl2 & 2)) {
data = ad->buf[(pos >> 3) & 0x3ffff];
if (!(pos & ADPCM_NBR)) {
data >>= 4;
}
pos += ADPCM_NBR + 4;
}
else {
const UINT8 *ptr;
REG8 bit;
UINT tmp;
ptr = ad->buf + ((pos >> 3) & 0x7fff);
bit = 1 << (pos & 7);
if (!(pos & ADPCM_NBR)) {
tmp = (ptr[0x20000] & bit);
tmp += (ptr[0x28000] & bit) << 1;
tmp += (ptr[0x30000] & bit) << 2;
tmp += (ptr[0x38000] & bit) << 3;
data = tmp >> (pos & 7);
pos += ADPCM_NBR;
}
else {
tmp = (ptr[0x00000] & bit);
tmp += (ptr[0x08000] & bit) << 1;
tmp += (ptr[0x10000] & bit) << 2;
tmp += (ptr[0x18000] & bit) << 3;
data = tmp >> (pos & 7);
pos += ADPCM_NBR + 1;
}
}
dir = data & 8;
data &= 7;
dlt = adpcmdeltatable[data] * ad->delta;
dlt >>= 8;
if (dlt < 127) {
dlt = 127;
}
else if (dlt > 24000) {
dlt = 24000;
}
samp = ad->delta;
ad->delta = dlt;
samp *= ((data * 2) + 1);
samp >>= ADPCM_SHIFT;
if (!dir) {
samp += ad->samp;
if (samp > 32767) {
samp = 32767;
}
}
else {
samp = ad->samp - samp;
if (samp < -32767) {
samp = -32767;
}
}
ad->samp = samp;
if (!(pos & ADPCM_NBR)) {
if (pos == ad->stop) {
if (ad->reg.ctrl1 & 0x10) {
pos = ad->start;
ad->samp = 0;
ad->delta = 127;
}
else {
pos &= 0x1fffff;
ad->status |= 4;
ad->play = 0;
}
}
else if (pos >= ad->limit) {
pos = 0;
}
}
ad->pos = pos;
samp *= ad->level;
samp >>= (10 + 1);
ad->out0 = ad->out1;
ad->out1 = samp + ad->fb;
ad->fb = samp >> 1;
}
void SOUNDCALL adpcm_getpcm(ADPCM ad, SINT32 *pcm, UINT count) {
SINT32 remain;
SINT32 samp;
if ((count == 0) || (ad->play == 0)) {
return;
}
remain = ad->remain;
if (ad->step <= ADTIMING) {
do {
if (remain < 0) {
remain += ADTIMING;
getadpcmdata(ad);
if (ad->play == 0) {
if (remain > 0) {
do {
samp = (ad->out0 * remain) >> ADTIMING_BIT;
if (ad->reg.ctrl2 & 0x80) {
pcm[0] += samp;
}
if (ad->reg.ctrl2 & 0x40) {
pcm[1] += samp;
}
pcm += 2;
remain -= ad->step;
} while((remain > 0) && (--count));
}
goto adpcmstop;
}
}
samp = (ad->out0 * remain) + (ad->out1 * (ADTIMING - remain));
samp >>= ADTIMING_BIT;
if (ad->reg.ctrl2 & 0x80) {
pcm[0] += samp;
}
if (ad->reg.ctrl2 & 0x40) {
pcm[1] += samp;
}
pcm += 2;
remain -= ad->step;
} while(--count);
}
else {
do {
if (remain > 0) {
samp = ad->out0 * (ADTIMING - remain);
do {
getadpcmdata(ad);
if (ad->play == 0) {
goto adpcmstop;
}
samp += ad->out0 * min(remain, ad->pertim);
remain -= ad->pertim;
} while(remain > 0);
}
else {
samp = ad->out0 * ADTIMING;
}
remain += ADTIMING;
samp >>= ADTIMING_BIT;
if (ad->reg.ctrl2 & 0x80) {
pcm[0] += samp;
}
if (ad->reg.ctrl2 & 0x40) {
pcm[1] += samp;
}
pcm += 2;
} while(--count);
}
ad->remain = remain;
return;
adpcmstop:
ad->out0 = 0;
ad->out1 = 0;
ad->fb = 0;
ad->remain = 0;
}

View File

@ -0,0 +1,74 @@
#if !defined(DISABLE_SOUND)
enum {
BEEPEVENT_MAXBIT = 8,
BEEPEVENT_MAX = (1 << BEEPEVENT_MAXBIT)
};
typedef struct {
SINT32 clock;
int enable;
} BPEVENT;
typedef struct {
UINT16 cnt;
UINT16 hz;
int buz;
int __puchi;
UINT8 mode;
UINT8 padding[3];
int low;
int enable;
int lastenable;
SINT32 clock;
UINT events;
BPEVENT event[BEEPEVENT_MAX];
} _BEEP, *BEEP;
typedef struct {
UINT rate;
UINT vol;
UINT __puchibase;
UINT samplebase;
} BEEPCFG;
#ifdef __cplusplus
extern "C" {
#endif
extern _BEEP beep;
void beep_initialize(UINT rate);
void beep_deinitialize(void);
void beep_setvol(UINT vol);
void beep_changeclock(void);
void beep_reset(void);
void beep_hzset(UINT16 cnt);
void beep_modeset(void);
void beep_eventinit(void);
void beep_eventreset(void);
void beep_lheventset(int beep_low);
void beep_oneventset(void);
void SOUNDCALL beep_getpcm(BEEP bp, SINT32 *pcm, UINT count);
#ifdef __cplusplus
}
#endif
#else
#define beep_setvol(v)
#define beep_changeclock()
#define beep_hzset(c)
#define beep_modeset()
#define beep_eventreset()
#define beep_lheventset(b)
#define beep_oneventset()
#endif

View File

@ -0,0 +1,175 @@
#include "compiler.h"
#include "dosio.h"
#include "cpucore.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
#include "beep.h"
_BEEP beep;
BEEPCFG beepcfg;
// #define BEEPLOG
#if defined(BEEPLOG)
static struct {
FILEH fh;
UINT events;
UINT32 event[0x10000];
} bplog;
static void beeplogflash(void) {
if ((bplog.fh != FILEH_INVALID) && (bplog.events)) {
file_write(bplog.fh, bplog.event, bplog.events * sizeof(UINT32));
bplog.events = 0;
}
}
#endif
void beep_initialize(UINT rate) {
beepcfg.rate = rate;
beepcfg.vol = 2;
#if defined(BEEPLOG)
bplog.fh = file_create("beeplog");
bplog.events = 0;
#endif
}
void beep_deinitialize(void) {
#if defined(BEEPLOG)
beeplogflash();
if (bplog.fh != FILEH_INVALID) {
file_close(bplog.fh);
bplog.fh = FILEH_INVALID;
}
#endif
}
void beep_setvol(UINT vol) {
beepcfg.vol = vol & 3;
}
void beep_changeclock(void) {
UINT32 hz;
UINT rate;
hz = pccore.realclock / 25;
rate = beepcfg.rate / 25;
beepcfg.samplebase = (1 << 16) * rate / hz;
}
void beep_reset(void) {
beep_changeclock();
ZeroMemory(&beep, sizeof(beep));
beep.mode = 1;
}
void beep_hzset(UINT16 cnt) {
double hz;
sound_sync();
beep.hz = 0;
if ((cnt & 0xff80) && (beepcfg.rate)) {
hz = 65536.0 / 4.0 * pccore.baseclock / beepcfg.rate / cnt;
if (hz < 0x8000) {
beep.hz = (UINT16)hz;
return;
}
}
}
void beep_modeset(void) {
UINT8 newmode;
newmode = (pit.ch[1].ctrl >> 2) & 3;
if (beep.mode != newmode) {
sound_sync();
beep.mode = newmode;
beep_eventinit();
}
}
static void beep_eventset(void) {
BPEVENT *evt;
int enable;
SINT32 clk;
enable = beep.low & beep.buz;
if (beep.enable != enable) {
#if defined(BEEPLOG)
UINT32 tmp;
tmp = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
if (enable) {
tmp |= 0x80000000;
}
else {
tmp &= ~0x80000000;
}
bplog.event[bplog.events++] = tmp;
if (bplog.events >= NELEMENTS(bplog.event)) {
beeplogflash();
}
#endif
if (beep.events >= (BEEPEVENT_MAX / 2)) {
sound_sync();
}
beep.enable = enable;
if (beep.events < BEEPEVENT_MAX) {
clk = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
evt = beep.event + beep.events;
beep.events++;
evt->clock = (clk - beep.clock) * beepcfg.samplebase;
evt->enable = enable;
beep.clock = clk;
}
}
}
void beep_eventinit(void) {
beep.low = 0;
beep.enable = 0;
beep.lastenable = 0;
beep.clock = soundcfg.lastclock;
beep.events = 0;
}
void beep_eventreset(void) {
beep.lastenable = beep.enable;
beep.clock = soundcfg.lastclock;
beep.events = 0;
}
void beep_lheventset(int low) {
if (beep.low != low) {
beep.low = low;
beep_eventset();
}
}
void beep_oneventset(void) {
int buz;
buz = (sysport.c & 8)?0:1;
if (beep.buz != buz) {
beep.buz = buz;
beep_eventset();
}
}

View File

@ -0,0 +1,160 @@
#include "compiler.h"
#include "sound.h"
#include "beep.h"
extern BEEPCFG beepcfg;
static void oneshot(BEEP bp, SINT32 *pcm, UINT count) {
SINT32 vol;
const BPEVENT *bev;
SINT32 clk;
int event;
SINT32 remain;
SINT32 samp;
vol = beepcfg.vol;
bev = bp->event;
if (bp->events) {
bp->events--;
clk = bev->clock;
event = bev->enable;
bev++;
}
else {
clk = 0x40000000;
event = bp->lastenable;
}
do {
remain = (1 << 16);
samp = 0;
while(remain >= clk) {
remain -= clk;
if (bp->lastenable) {
samp += clk;
}
bp->lastenable = event;
if (bp->events) {
bp->events--;
clk = bev->clock;
event = bev->enable;
bev++;
}
else {
clk = 0x40000000;
}
}
clk -= remain;
if (bp->lastenable) {
samp += remain;
}
samp *= vol;
samp >>= (16 - 10);
pcm[0] += samp;
pcm[1] += samp;
pcm += 2;
} while(--count);
bp->lastenable = event;
bp->events = 0;
}
static void rategenerator(BEEP bp, SINT32 *pcm, UINT count) {
SINT32 vol;
const BPEVENT *bev;
SINT32 samp;
SINT32 remain;
SINT32 clk;
int event;
UINT r;
vol = beepcfg.vol;
bev = bp->event;
if (bp->events) {
bp->events--;
clk = bev->clock;
event = bev->enable;
bev++;
}
else {
clk = 0x40000000;
event = bp->lastenable;
}
do {
if (clk >= (1 << 16)) {
r = clk >> 16;
r = min(r, count);
clk -= r << 16;
count -= r;
if (bp->lastenable) {
do {
samp = (bp->cnt & 0x8000)?1:-1;
bp->cnt += bp->hz;
samp += (bp->cnt & 0x8000)?1:-1;
bp->cnt += bp->hz;
samp += (bp->cnt & 0x8000)?1:-1;
bp->cnt += bp->hz;
samp += (bp->cnt & 0x8000)?1:-1;
bp->cnt += bp->hz;
samp *= vol;
samp <<= (10 - 2);
pcm[0] += samp;
pcm[1] += samp;
pcm += 2;
} while(--r);
}
else {
pcm += 2 * r;
}
}
else {
remain = (1 << 16);
samp = 0;
while(remain >= clk) {
remain -= clk;
if (bp->lastenable) {
samp += clk;
}
bp->lastenable = event;
bp->cnt = 0;
if (bp->events) {
bp->events--;
clk = bev->clock;
event = bev->enable;
bev++;
}
else {
clk = 0x40000000;
}
}
clk -= remain;
if (bp->lastenable) {
samp += remain;
}
samp *= vol;
samp >>= (16 - 10);
pcm[0] += samp;
pcm[1] += samp;
pcm += 2;
count--;
}
} while(count);
bp->lastenable = event;
bp->events = 0;
}
void SOUNDCALL beep_getpcm(BEEP bp, SINT32 *pcm, UINT count) {
if ((count) && (beepcfg.vol)) {
if (bp->mode == 0) {
if (bp->events) {
oneshot(bp, pcm, count);
}
}
else if (bp->mode == 1) {
rategenerator(bp, pcm, count);
}
}
}

View File

@ -0,0 +1,358 @@
#include "compiler.h"
#include "joymng.h"
#include "soundmng.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "board14.h"
#include "board26k.h"
#include "board86.h"
#include "boardx2.h"
#include "board118.h"
#include "boardspb.h"
#if defined(SUPPORT_PX)
#include "boardpx.h"
#endif // defined(SUPPORT_PX)
#include "amd98.h"
#include "pcm86io.h"
#include "cs4231io.h"
#include "sound.h"
#include "fmboard.h"
#include "beep.h"
#include "keydisp.h"
#include "keystat.h"
UINT32 usesound;
OPN_T opn;
AMD98 amd98;
MUSICGEN musicgen;
_TMS3631 tms3631;
_FMTIMER fmtimer;
_OPNGEN opngen;
OPNCH opnch[OPNCH_MAX];
_PSGGEN __psg[3];
_RHYTHM rhythm;
_ADPCM adpcm;
_PCM86 pcm86;
_CS4231 cs4231;
#if defined(SUPPORT_PX)
OPN_T opn2;
OPN_T opn3;
_RHYTHM rhythm2;
_RHYTHM rhythm3;
_ADPCM adpcm2;
_ADPCM adpcm3;
#endif // defined(SUPPORT_PX)
static void (*extfn)(REG8 enable);
// ----
static REG8 rapids = 0;
REG8 fmboard_getjoy(PSGGEN psg) {
REG8 ret;
rapids ^= 0xf0; // ver0.28
ret = 0xff;
if (!(psg->reg.io2 & 0x40)) {
ret &= (joymng_getstat() | (rapids & 0x30));
if (np2cfg.KEY_MODE == 1) {
ret &= keystat_getjoy();
}
}
else {
if (np2cfg.KEY_MODE == 2) {
ret &= keystat_getjoy();
}
}
if (np2cfg.BTN_RAPID) {
ret |= rapids;
}
// rapidと非rapidを合成 // ver0.28
ret &= ((ret >> 2) | (~0x30));
if (np2cfg.BTN_MODE) {
UINT8 bit1 = (ret & 0x20) >> 1; // ver0.28
UINT8 bit2 = (ret & 0x10) << 1;
ret = (ret & (~0x30)) | bit1 | bit2;
}
// intr 反映して終わり // ver0.28
ret &= 0x3f;
ret |= fmtimer.intr;
return(ret);
}
// ----
void fmboard_extreg(void (*ext)(REG8 enable)) {
extfn = ext;
}
void fmboard_extenable(REG8 enable) {
if (extfn) {
(*extfn)(enable);
}
}
// ----
static void setfmregs(UINT8 *reg) {
FillMemory(reg + 0x30, 0x60, 0xff);
FillMemory(reg + 0x90, 0x20, 0x00);
FillMemory(reg + 0xb0, 0x04, 0x00);
FillMemory(reg + 0xb4, 0x04, 0xc0);
}
void fmboard_reset(const NP2CFG *pConfig, UINT32 type) {
UINT8 cross;
soundrom_reset();
beep_reset(); // ver0.27a
cross = np2cfg.snd_x; // ver0.30
extfn = NULL;
ZeroMemory(&opn, sizeof(opn));
setfmregs(opn.reg + 0x000);
setfmregs(opn.reg + 0x100);
setfmregs(opn.reg + 0x200);
setfmregs(opn.reg + 0x300);
opn.reg[0xff] = 0x01;
opn.channels = 3;
opn.adpcmmask = (UINT8)~(0x1c);
#if defined(SUPPORT_PX)
ZeroMemory(&opn2, sizeof(opn2));
setfmregs(opn2.reg + 0x000);
setfmregs(opn2.reg + 0x100);
setfmregs(opn2.reg + 0x200);
setfmregs(opn2.reg + 0x300);
opn2.reg[0xff] = 0x01;
opn2.channels = 3;
opn2.adpcmmask = (UINT8)~(0x1c);
ZeroMemory(&opn3, sizeof(opn3));
setfmregs(opn3.reg + 0x000);
setfmregs(opn3.reg + 0x100);
setfmregs(opn3.reg + 0x200);
setfmregs(opn3.reg + 0x300);
opn3.reg[0xff] = 0x01;
opn3.channels = 3;
opn3.adpcmmask = (UINT8)~(0x1c);
#endif // defined(SUPPORT_PX)
ZeroMemory(&musicgen, sizeof(musicgen));
ZeroMemory(&amd98, sizeof(amd98));
tms3631_reset(&tms3631);
opngen_reset();
psggen_reset(&psg1);
psggen_reset(&psg2);
psggen_reset(&psg3);
rhythm_reset(&rhythm);
#if defined(SUPPORT_PX)
rhythm_reset(&rhythm2);
rhythm_reset(&rhythm3);
#endif // defined(SUPPORT_PX)
adpcm_reset(&adpcm);
#if defined(SUPPORT_PX)
adpcm_reset(&adpcm2);
adpcm_reset(&adpcm3);
#endif // defined(SUPPORT_PX)
pcm86_reset();
cs4231_reset();
switch(type) {
case 0x01:
board14_reset(pConfig);
break;
case 0x02:
board26k_reset(pConfig);
break;
case 0x04:
board86_reset(pConfig);
break;
case 0x06:
boardx2_reset(pConfig);
break;
case 0x08:
board118_reset(pConfig);
break;
case 0x14:
board86_reset(pConfig);
break;
case 0x20:
boardspb_reset(pConfig);
cross ^= pConfig->spb_x;
break;
case 0x40:
boardspr_reset(pConfig);
cross ^= pConfig->spb_x;
break;
case 0x80:
// amd98_reset(pConfig);
break;
#if defined(SUPPORT_PX)
case 0x30:
boardpx1_reset(pConfig);
break;
case 0x50:
boardpx2_reset(pConfig);
break;
#endif // defined(SUPPORT_PX)
default:
type = 0;
break;
}
usesound = type;
soundmng_setreverse(cross);
keydisp_setfmboard(type);
opngen_setVR(pConfig->spb_vrc, pConfig->spb_vrl);
}
void fmboard_bind(void) {
switch(usesound) {
case 0x01:
board14_bind();
break;
case 0x02:
board26k_bind();
break;
case 0x04:
board86_bind();
break;
case 0x06:
boardx2_bind();
break;
case 0x08:
board118_bind();
break;
case 0x14:
board86c_bind();
break;
case 0x20:
boardspb_bind();
break;
case 0x40:
boardspr_bind();
break;
case 0x80:
amd98_bind();
break;
#if defined(SUPPORT_PX)
case 0x30:
boardpx1_bind();
break;
case 0x50:
boardpx2_bind();
break;
#endif // defined(SUPPORT_PX)
}
sound_streamregist(&beep, (SOUNDCB)beep_getpcm);
}
// ----
void fmboard_fmrestore(REG8 chbase, UINT bank) {
REG8 i;
const UINT8 *reg;
reg = opn.reg + (bank * 0x100);
for (i=0x30; i<0xa0; i++) {
opngen_setreg(chbase, i, reg[i]);
}
for (i=0xb7; i>=0xa0; i--) {
opngen_setreg(chbase, i, reg[i]);
}
for (i=0; i<3; i++) {
opngen_keyon(chbase + i, opngen.keyreg[chbase + i]);
}
}
void fmboard_rhyrestore(RHYTHM rhy, UINT bank) {
const UINT8 *reg;
reg = opn.reg + (bank * 0x100);
rhythm_setreg(rhy, 0x11, reg[0x11]);
rhythm_setreg(rhy, 0x18, reg[0x18]);
rhythm_setreg(rhy, 0x19, reg[0x19]);
rhythm_setreg(rhy, 0x1a, reg[0x1a]);
rhythm_setreg(rhy, 0x1b, reg[0x1b]);
rhythm_setreg(rhy, 0x1c, reg[0x1c]);
rhythm_setreg(rhy, 0x1d, reg[0x1d]);
}
#if defined(SUPPORT_PX)
void fmboard_fmrestore2(OPN_T* pOpn, REG8 chbase, UINT bank) {
REG8 i;
const UINT8 *reg;
reg = pOpn->reg + (bank * 0x100);
for (i=0x30; i<0xa0; i++) {
opngen_setreg(chbase, i, reg[i]);
}
for (i=0xb7; i>=0xa0; i--) {
opngen_setreg(chbase, i, reg[i]);
}
for (i=0; i<3; i++) {
opngen_keyon(chbase + i, opngen.keyreg[chbase + i]);
}
}
void fmboard_rhyrestore2(OPN_T* pOpn, RHYTHM rhy, UINT bank) {
const UINT8 *reg;
reg = pOpn->reg + (bank * 0x100);
rhythm_setreg(rhy, 0x11, reg[0x11]);
rhythm_setreg(rhy, 0x18, reg[0x18]);
rhythm_setreg(rhy, 0x19, reg[0x19]);
rhythm_setreg(rhy, 0x1a, reg[0x1a]);
rhythm_setreg(rhy, 0x1b, reg[0x1b]);
rhythm_setreg(rhy, 0x1c, reg[0x1c]);
rhythm_setreg(rhy, 0x1d, reg[0x1d]);
}
#endif // defined(SUPPORT_PX)

View File

@ -0,0 +1,103 @@
#if !defined(DISABLE_SOUND)
#include "soundrom.h"
#include "tms3631.h"
#include "fmtimer.h"
#include "opngen.h"
#include "psggen.h"
#include "rhythm.h"
#include "adpcm.h"
#include "pcm86.h"
#include "cs4231.h"
typedef struct {
UINT addr;
UINT addr2;
UINT8 data;
UINT8 data2;
UINT16 base;
UINT8 adpcmmask;
UINT8 channels;
UINT8 extend;
UINT8 _padding;
UINT8 reg[0x400];
} OPN_T;
typedef struct {
UINT16 port;
UINT8 psg3reg;
UINT8 rhythm;
} AMD98;
typedef struct {
UINT8 porta;
UINT8 portb;
UINT8 portc;
UINT8 mask;
UINT8 key[8];
int sync;
int ch;
} MUSICGEN;
#ifdef __cplusplus
extern "C" {
#endif
extern UINT32 usesound;
extern OPN_T opn;
extern AMD98 amd98;
extern MUSICGEN musicgen;
extern _TMS3631 tms3631;
extern _FMTIMER fmtimer;
extern _OPNGEN opngen;
extern OPNCH opnch[OPNCH_MAX];
extern _PSGGEN __psg[3];
extern _RHYTHM rhythm;
extern _ADPCM adpcm;
extern _PCM86 pcm86;
extern _CS4231 cs4231;
#define psg1 __psg[0]
#define psg2 __psg[1]
#define psg3 __psg[2]
#if defined(SUPPORT_PX)
extern OPN_T opn2;
extern OPN_T opn3;
extern _RHYTHM rhythm2;
extern _RHYTHM rhythm3;
extern _ADPCM adpcm2;
extern _ADPCM adpcm3;
#endif // defined(SUPPORT_PX)
REG8 fmboard_getjoy(PSGGEN psg);
void fmboard_extreg(void (*ext)(REG8 enable));
void fmboard_extenable(REG8 enable);
void fmboard_reset(const NP2CFG *pConfig, UINT32 type);
void fmboard_bind(void);
void fmboard_fmrestore(REG8 chbase, UINT bank);
void fmboard_rhyrestore(RHYTHM rhy, UINT bank);
#if defined(SUPPORT_PX)
void fmboard_fmrestore2(OPN_T* pOpn, REG8 chbase, UINT bank);
void fmboard_rhyrestore2(OPN_T* pOpn, RHYTHM rhy, UINT bank);
#endif // defined(SUPPORT_PX)
#ifdef __cplusplus
}
#endif
#else
#define fmboard_reset(t)
#define fmboard_bind()
#endif

View File

@ -0,0 +1,134 @@
#include "compiler.h"
#include "cpucore.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
static const UINT8 irqtable[4] = {0x03, 0x0d, 0x0a, 0x0c};
static void set_fmtimeraevent(BOOL absolute) {
SINT32 l;
l = 18 * (1024 - fmtimer.timera);
if (pccore.cpumode & CPUMODE_8MHZ) { // 4MHz
l = (l * 1248 / 625) * pccore.multiple;
}
else { // 5MHz
l = (l * 1536 / 625) * pccore.multiple;
}
// TRACEOUT(("FMTIMER-A: %08x-%d", l, absolute));
nevent_set(NEVENT_FMTIMERA, l, fmport_a, absolute);
}
static void set_fmtimerbevent(BOOL absolute) {
SINT32 l;
l = 288 * (256 - fmtimer.timerb);
if (pccore.cpumode & CPUMODE_8MHZ) { // 4MHz
l = (l * 1248 / 625) * pccore.multiple;
}
else { // 5MHz
l = (l * 1536 / 625) * pccore.multiple;
}
// TRACEOUT(("FMTIMER-B: %08x-%d", l, absolute));
nevent_set(NEVENT_FMTIMERB, l, fmport_b, absolute);
}
void fmport_a(NEVENTITEM item) {
BOOL intreq = FALSE;
if (item->flag & NEVENT_SETEVENT) {
intreq = pcm86gen_intrq();
if (fmtimer.reg & 0x04) {
fmtimer.status |= 0x01;
intreq = TRUE;
}
if (intreq) {
pic_setirq(fmtimer.irq);
// TRACEOUT(("fm int-A"));
}
set_fmtimeraevent(FALSE);
}
}
void fmport_b(NEVENTITEM item) {
BOOL intreq = FALSE;
if (item->flag & NEVENT_SETEVENT) {
intreq = pcm86gen_intrq();
if (fmtimer.reg & 0x08) {
fmtimer.status |= 0x02;
intreq = TRUE;
}
if (intreq) {
pic_setirq(fmtimer.irq);
// TRACEOUT(("fm int-B"));
}
set_fmtimerbevent(FALSE);
}
}
void fmtimer_reset(UINT irq) {
ZeroMemory(&fmtimer, sizeof(fmtimer));
fmtimer.intr = irq & 0xc0;
fmtimer.intdisabel = irq & 0x10;
fmtimer.irq = irqtable[irq >> 6];
// pic_registext(fmtimer.irq);
}
void fmtimer_setreg(UINT reg, REG8 value) {
// TRACEOUT(("fm %x %x [%.4x:%.4x]", reg, value, CPU_CS, CPU_IP));
switch(reg) {
case 0x24:
fmtimer.timera = (value << 2) + (fmtimer.timera & 3);
break;
case 0x25:
fmtimer.timera = (fmtimer.timera & 0x3fc) + (value & 3);
break;
case 0x26:
fmtimer.timerb = value;
break;
case 0x27:
fmtimer.reg = value;
fmtimer.status &= ~((value & 0x30) >> 4);
if (value & 0x01) {
if (!nevent_iswork(NEVENT_FMTIMERA)) {
set_fmtimeraevent(NEVENT_ABSOLUTE);
}
}
else {
nevent_reset(NEVENT_FMTIMERA);
}
if (value & 0x02) {
if (!nevent_iswork(NEVENT_FMTIMERB)) {
set_fmtimerbevent(NEVENT_ABSOLUTE);
}
}
else {
nevent_reset(NEVENT_FMTIMERB);
}
if (!(value & 0x03)) {
pic_resetirq(fmtimer.irq);
}
break;
}
}

View File

@ -0,0 +1,26 @@
typedef struct {
UINT16 timera;
UINT8 timerb;
UINT8 status;
UINT8 reg;
UINT8 intr;
UINT8 irq;
UINT8 intdisabel;
} _FMTIMER, *FMTIMER;
#ifdef __cplusplus
extern "C" {
#endif
void fmport_a(NEVENTITEM item);
void fmport_b(NEVENTITEM item);
void fmtimer_reset(UINT irq);
void fmtimer_setreg(UINT reg, REG8 value);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,113 @@
#include "compiler.h"
#include "getsnd.h"
#if defined(SUPPORT_MP3)
#include "amethyst.h"
#define mp3_getdecver __mp3_getdecver
#define mp3_create __mp3_create
#define mp3_destroy __mp3_destroy
#define mp3_predecode __mp3_predecode
#define mp3_decode __mp3_decode
#define mp3_adjustgain __mp3_adjustgain
static UINT mp3_dec(GETSND snd, short *dst) {
UINT8 *src;
MPEGL3 *mp3;
int r;
src = snd->datptr;
mp3 = (MPEGL3 *)snd->snd;
if (snd->datsize < 4) {
goto mp3dec_err;
}
r = mp3_predecode(mp3, src);
if (r) {
if ((r != MPEGHEAD_RENEWAL) ||
(snd->samplingrate != mp3->c.samplingrate) ||
(snd->channels != mp3->c.channels)) {
TRACEOUT(("mp3 decord err"));
goto mp3dec_err;
}
}
if (snd->datsize < mp3->c.insize) {
goto mp3dec_err;
}
snd->datptr += mp3->c.insize;
snd->datsize -= mp3->c.insize;
mp3_decode(mp3, dst, src, mp3->c.insize);
return(mp3->c.outsamples);
mp3dec_err:
return(0);
}
static void mp3_decend(GETSND snd) {
mp3_destroy((MPEGL3 *)snd->snd);
}
BOOL __mp3_open(GETSND snd, UINT8 *ptr, UINT size) {
MPEGL3 *mp3;
if (size < 4) {
goto mp3opn_err;
}
mp3 = mp3_create(ptr);
if (mp3 == NULL) {
goto mp3opn_err;
}
snd->datptr = ptr;
snd->datsize = size;
snd->snd = mp3;
snd->dec = (GSDEC)mp3_dec;
snd->decend = mp3_decend;
snd->samplingrate = mp3->c.samplingrate;
snd->channels = mp3->c.channels;
snd->blocksize = 1728;
snd->blocksamples = mp3->c.outsamples;
snd->bit = 16;
TRACEOUT(("mp3: %dHz %dkbps", mp3->c.samplingrate, mp3->c.kbitrate));
return(SUCCESS);
mp3opn_err:
return(FAILURE);
}
BOOL getmp3_open(GETSND snd, UINT8 *ptr, UINT size) {
UINT pos;
if ((size < 10) && (!memcmp(ptr, "ID3", 3))) {
pos = (ptr[6] & 0x7f);
pos <<= 7;
pos |= (ptr[7] & 0x7f);
pos <<= 7;
pos |= (ptr[8] & 0x7f);
pos <<= 7;
pos |= (ptr[9] & 0x7f);
pos += 10;
TRACEOUT(("ID3 Tag - size:%dbyte(s)", pos));
if (size < pos) {
goto mp3opn_err;
}
ptr += pos;
size -= pos;
}
if (__mp3_open(snd, ptr, size) != SUCCESS) {
goto mp3opn_err;
}
return(SUCCESS);
mp3opn_err:
return(FAILURE);
}
#endif

View File

@ -0,0 +1,264 @@
#include "compiler.h"
#include "getsnd.h"
#if defined(SUPPORT_OGG)
#include <math.h>
#include "vorbis/codec.h"
typedef struct {
int phase;
ogg_sync_state oy;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
vorbis_info vi;
vorbis_comment vc;
vorbis_dsp_state vd;
vorbis_block vb;
} __OV;
// ----
static int snd_read(GETSND snd, void *buffer, int size) {
UINT rsize;
if (size <= 0) {
goto sndrd_err;
}
rsize = (UINT)size;
if (rsize >= snd->datsize) {
rsize = snd->datsize;
}
CopyMemory(buffer, snd->datptr, rsize);
snd->datptr += rsize;
snd->datsize -= rsize;
return((int)rsize);
sndrd_err:
return(0);
}
enum {
OVPHASE_HEAD = 0,
OVPHASE_STREAMIN,
OVPHASE_GETPCM,
OVPHASE_NEXT,
OVPHASE_CLOSE
};
static UINT ogg_dec(GETSND snd, short *dst) {
__OV *ov;
int result;
char *buffer;
int bytes;
float **pcm;
int samples;
int i;
int j;
float *mono;
short *ptr;
long val;
ov = (__OV *)snd->snd;
do {
switch(ov->phase) {
case OVPHASE_HEAD:
result = ogg_sync_pageout(&ov->oy, &ov->og);
if (result > 0) {
ogg_stream_pagein(&ov->os, &ov->og);
ov->phase = OVPHASE_STREAMIN;
}
else if (result == 0) {
ov->phase = OVPHASE_NEXT;
}
else {
TRACEOUT(("Corrupt or missing data in bitstream"));
}
break;
case OVPHASE_STREAMIN:
result = ogg_stream_packetout(&ov->os, &ov->op);
if (result > 0) {
if (vorbis_synthesis(&ov->vb, &ov->op) == 0) {
vorbis_synthesis_blockin(&ov->vd, &ov->vb);
}
ov->phase = OVPHASE_GETPCM;
}
else if (result == 0) {
if (!ogg_page_eos(&ov->og)) {
ov->phase = OVPHASE_NEXT;
}
else {
ov->phase = OVPHASE_CLOSE;
}
}
break;
case OVPHASE_GETPCM:
samples = vorbis_synthesis_pcmout(&ov->vd, &pcm);
if (samples > 0) {
if (samples > (int)snd->blocksamples) {
samples = (int)snd->blocksamples;
}
for (i=0; i<ov->vi.channels; i++) {
ptr = dst + i;
mono = pcm[i];
for (j=0; j<samples; j++) {
val = (long)(mono[j] * 32767.f);
if (val > 32767) {
val = 32767;
}
if (val < -32768) {
val = -32768;
}
*ptr = (short)val;
ptr += ov->vi.channels;
}
}
vorbis_synthesis_read(&ov->vd, samples);
return((UINT)samples);
}
ov->phase = OVPHASE_STREAMIN;
break;
case OVPHASE_NEXT:
buffer = ogg_sync_buffer(&ov->oy, 4096);
bytes = snd_read(snd, buffer, 4096);
ogg_sync_wrote(&ov->oy, bytes);
#if 1
ov->phase = OVPHASE_HEAD;
#else
if (bytes) {
ov->phase = OVPHASE_HEAD;
}
else {
ov->phase = OVPHASE_CLOSE;
}
#endif
break;
case OVPHASE_CLOSE:
return(0);
}
} while(1);
}
static void ogg_decend(GETSND snd) {
__OV *ov;
ov = (__OV *)snd->snd;
ogg_stream_clear(&ov->os);
vorbis_block_clear(&ov->vb);
vorbis_dsp_clear(&ov->vd);
vorbis_comment_clear(&ov->vc);
vorbis_info_clear(&ov->vi);
ogg_sync_clear(&ov->oy);
_MFREE(ov);
}
BOOL getogg_open(GETSND snd, UINT8 *ptr, UINT size) {
__OV *ov;
char *buffer;
int bytes;
int i;
int result;
snd->datptr = ptr;
snd->datsize = size;
ov = (__OV *)_MALLOC(sizeof(__OV), "__OV");
if (ov == NULL) {
goto ovopn_err0;
}
ZeroMemory(ov, sizeof(__OV));
buffer = ogg_sync_buffer(&ov->oy, 4096);
bytes = snd_read(snd, buffer, 4096);
ogg_sync_wrote(&ov->oy, bytes);
if (ogg_sync_pageout(&ov->oy, &ov->og) != 1) {
TRACEOUT(("Input does not appear to be an Ogg bitstream."));
goto ovopn_err1;
}
ogg_stream_init(&ov->os, ogg_page_serialno(&ov->og));
vorbis_info_init(&ov->vi);
vorbis_comment_init(&ov->vc);
if (ogg_stream_pagein(&ov->os, &ov->og) < 0) {
TRACEOUT(("Error reading first page of Ogg bitstream data."));
goto ovopn_err1;
}
if (ogg_stream_packetout(&ov->os, &ov->op) != 1) {
TRACEOUT(("Error reading initial header packet."));
goto ovopn_err1;
}
if (vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op) < 0) {
TRACEOUT(("This Ogg bitstream does not contain Vorbis audio data."));
goto ovopn_err1;
}
i = 0;
while(i < 2) {
while(i < 2) {
result = ogg_sync_pageout(&ov->oy, &ov->og);
if (result == 0) {
break;
}
if (result == 1) {
ogg_stream_pagein(&ov->os, &ov->og);
while(i < 2) {
result = ogg_stream_packetout(&ov->os, &ov->op);
if (result == 0) {
break;
}
if (result < 0) {
TRACEOUT(("Corrupt secondary header. Exiting."));
goto ovopn_err1;
}
vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op);
i++;
}
}
}
buffer = ogg_sync_buffer(&ov->oy, 4096);
bytes = snd_read(snd, buffer, 4096);
if ((bytes == 0) && (i < 2)) {
TRACEOUT(("End of file before finding all Vorbis headers!"));
return(-1);
}
ogg_sync_wrote(&ov->oy, bytes);
}
snd->snd = ov;
snd->dec = (GSDEC)ogg_dec;
snd->decend = ogg_decend;
snd->samplingrate = ov->vi.rate;
snd->channels = ov->vi.channels;
snd->blocksize = 4096 * 2;
snd->blocksamples = 4096 / ov->vi.channels;
snd->bit = 16;
vorbis_synthesis_init(&ov->vd, &ov->vi);
vorbis_block_init(&ov->vd, &ov->vb);
return(SUCCESS);
ovopn_err1:
ogg_sync_clear(&ov->oy);
_MFREE(ov);
ovopn_err0:
return(FAILURE);
}
#endif

View File

@ -0,0 +1,153 @@
#include "compiler.h"
#include "getsnd.h"
#define DNBASEBITS 12
#define DNMIXBASE (1 << DNBASEBITS)
#define UPBASEBITS 12
#define UPMIXBASE (1 << UPBASEBITS)
// 偽物てんぷれーと
// マイクロソフトはマクロ展開下手だから動作チェキするように。
// ---- モノラル出力
#define MIX_INPUTBIT 8
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 1
#define FUNC_NOR m8m16nr
#define FUNC_DOWN m8m16dn
#define FUNC_UP m8m16up
#include "getsndmn.mcr"
#define MIX_INPUTBIT 8
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 2
#define FUNC_NOR s8m16nr
#define FUNC_DOWN s8m16dn
#define FUNC_UP s8m16up
#include "getsndmn.mcr"
#define MIX_INPUTBIT 16
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 1
#define FUNC_NOR m16m16nr
#define FUNC_DOWN m16m16dn
#define FUNC_UP m16m16up
#include "getsndmn.mcr"
#define MIX_INPUTBIT 16
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 2
#define FUNC_NOR s16m16nr
#define FUNC_DOWN s16m16dn
#define FUNC_UP s16m16up
#include "getsndmn.mcr"
// ---- ステレオ出力
#define MIX_INPUTBIT 8
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 1
#define FUNC_NOR m8s16nr
#define FUNC_DOWN m8s16dn
#define FUNC_UP m8s16up
#include "getsndst.mcr"
#define MIX_INPUTBIT 8
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 2
#define FUNC_NOR s8s16nr
#define FUNC_DOWN s8s16dn
#define FUNC_UP s8s16up
#include "getsndst.mcr"
#define MIX_INPUTBIT 16
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 1
#define FUNC_NOR m16s16nr
#define FUNC_DOWN m16s16dn
#define FUNC_UP m16s16up
#include "getsndst.mcr"
#define MIX_INPUTBIT 16
#define MIX_OUTPUTBIT 16
#define MIX_CHANNELS 2
#define FUNC_NOR s16s16nr
#define FUNC_DOWN s16s16dn
#define FUNC_UP s16s16up
#include "getsndst.mcr"
static const GSCNV cnvfunc[] = {
(GSCNV)m8m16nr, (GSCNV)m8m16dn, (GSCNV)m8m16up,
(GSCNV)s8m16nr, (GSCNV)s8m16dn, (GSCNV)s8m16up,
(GSCNV)m16m16nr, (GSCNV)m16m16dn, (GSCNV)m16m16up,
(GSCNV)s16m16nr, (GSCNV)s16m16dn, (GSCNV)s16m16up,
(GSCNV)m8s16nr, (GSCNV)m8s16dn, (GSCNV)m8s16up,
(GSCNV)s8s16nr, (GSCNV)s8s16dn, (GSCNV)s8s16up,
(GSCNV)m16s16nr, (GSCNV)m16s16dn, (GSCNV)m16s16up,
(GSCNV)s16s16nr, (GSCNV)s16s16dn, (GSCNV)s16s16up};
BOOL getsnd_setmixproc(GETSND snd, UINT samprate, UINT channles) {
int funcnum;
if ((snd->samplingrate < 8000) || (snd->samplingrate > 96000)) {
goto gssmp_err;
}
if ((samprate < 8000) || (samprate > 96000)) {
goto gssmp_err;
}
funcnum = 0;
if (snd->channels == 1) {
}
else if (snd->channels == 2) {
funcnum |= 1;
}
else {
goto gssmp_err;
}
if (snd->bit == 8) {
}
else if (snd->bit == 16) {
funcnum |= 2;
}
else {
goto gssmp_err;
}
if (channles == 1) {
}
else if (channles == 2) {
funcnum |= 4;
}
else {
goto gssmp_err;
}
funcnum *= 3;
if (snd->samplingrate > samprate) {
snd->mrate = (DNMIXBASE * samprate) / snd->samplingrate;
snd->rem = DNMIXBASE;
funcnum += 1;
}
else if (snd->samplingrate < samprate) {
snd->mrate = (UPMIXBASE * samprate) / snd->samplingrate;
funcnum += 2;
}
snd->cnv = cnvfunc[funcnum];
return(SUCCESS);
gssmp_err:
return(FAILURE);
}

View File

@ -0,0 +1,102 @@
#include "compiler.h"
#include "getsnd.h"
GETSND getsnd_create(void *datptr, UINT datsize) {
_GETSND snd;
BOOL r;
UINT size;
UINT blkwork;
GETSND ret;
ZeroMemory(&snd, sizeof(snd));
r = getwave_open(&snd, (UINT8 *)datptr, datsize);
#if defined(SUPPORT_MP3)
if (r == FAILURE) {
r = getmp3_open(&snd, (UINT8 *)datptr, datsize);
}
#endif
#if defined(SUPPORT_OGG)
if (r == FAILURE) {
r = getogg_open(&snd, (UINT8 *)datptr, datsize);
}
#endif
if (r == FAILURE) {
goto gscre_err0;
}
blkwork = (snd.bit + 7) >> 3;
blkwork *= snd.channels;
blkwork *= snd.blocksamples;
size = blkwork + snd.blocksize;
ret = (GETSND)_MALLOC(sizeof(_GETSND) + size, "GETSND");
if (ret == NULL) {
goto gscre_err1;
}
ZeroMemory(ret + 1, size);
// ƒ<><C692>[ƒNÆ©<E2809A>Ýè<E28099>B
snd.buffer = (UINT8 *)(ret + 1);
snd.work = snd.buffer + blkwork;
*ret = snd;
if (getsnd_setmixproc(ret, snd.samplingrate, snd.channels) != SUCCESS) {
TRACEOUT(("err"));
goto gscre_err1;
}
return(ret);
gscre_err1:
if (snd.decend) {
(*snd.decend)(&snd);
}
gscre_err0:
return(NULL);
}
void getsnd_destroy(GETSND snd) {
if (snd == NULL) {
goto gsdes_end;
}
if (snd->decend) {
(*snd->decend)(snd);
}
_MFREE(snd);
gsdes_end:
return;
}
UINT getsnd_getpcmbyleng(GETSND snd, void *pcm, UINT leng) {
UINT8 *pcmp;
UINT8 *pcmterm;
if (snd == NULL) {
goto gsgpl_err;
}
pcmp = (UINT8 *)pcm;
pcmterm = pcmp + leng;
while(pcmp < pcmterm) {
if (snd->remain != 0) {
pcmp = (UINT8 *)(*snd->cnv)(snd, pcmp, pcmterm);
}
if (snd->remain == 0) {
snd->buf = snd->buffer;
snd->remain = (*snd->dec)(snd, snd->buffer);
if (snd->remain == 0) {
break;
}
}
}
return((UINT)(pcmp - (UINT8 *)pcm));
gsgpl_err:
return(0);
}

View File

@ -0,0 +1,57 @@
// #define SUPPORT_MP3
// #define SUPPORT_OGG
#ifdef __cplusplus
extern "C" {
#endif
struct _getsnd;
typedef struct _getsnd _GETSND;
typedef struct _getsnd *GETSND;
typedef UINT (*GSDEC)(GETSND self, void *buf);
typedef void (*GSDECEND)(GETSND self);
typedef void *(*GSCNV)(GETSND self, void *buf, void *bufterm);
BOOL getwave_open(GETSND snd, UINT8 *ptr, UINT size);
BOOL getmp3_open(GETSND snd, UINT8 *ptr, UINT size);
BOOL getogg_open(GETSND snd, UINT8 *ptr, UINT size);
BOOL getsnd_setmixproc(GETSND snd, UINT samprate, UINT channles);
struct _getsnd {
UINT8 *work; // data load用バッファ
UINT8 *buffer; // デコード済みバッファ
void *buf;
UINT remain;
long mrate;
long rem;
long pcml;
long pcmr;
UINT8 *datptr;
UINT datsize;
void *snd; // optional
GSDEC dec;
GSDECEND decend; // optional
GSCNV cnv;
UINT samplingrate;
UINT channels;
UINT bit;
UINT blocksamples; // ブロックサンプル数
UINT blocksize; // 1ブロックのワークサイズ
};
GETSND getsnd_create(void *datptr, UINT datsize);
void getsnd_destroy(GETSND hdl);
UINT getsnd_getpcmbyleng(GETSND hdl, void *pcm, UINT leng);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,160 @@
#if (MIX_INPUTBIT == 8)
#define _SMP_IN unsigned char
#define _SAMP(s) (((long)(s) - 0x80) << 8)
#elif (MIX_INPUTBIT == 16)
#define _SMP_IN short
#define _SAMP(s) (long)(s)
#endif
#if (MIX_OUTPUTBIT == 8)
#define _SMP_OUT unsigned char
#define _SAMPLIMIT(s) if ((s) > 32767) { \
(s) = 32767; \
} \
else if ((s) < -32768) { \
(s) = -32768; \
}
#define _OUTSAMP(d, s) (d) = (_SMP_OUT)(((s) >> 8) + 0x80)
#elif (MIX_OUTPUTBIT == 16)
#define _SMP_OUT short
#define _SAMPLIMIT(s) if ((s) > 32767) { \
(s) = 32767; \
} \
else if ((s) < -32768) { \
(s) = -32768; \
}
#define _OUTSAMP(d, s) (d) = (_SMP_OUT)(s)
#endif
static _SMP_OUT *FUNC_NOR(GETSND trk, _SMP_OUT *pcm, _SMP_OUT *pcmterm) {
_SMP_IN *samp;
UINT size;
size = min(trk->remain, (UINT)(pcmterm - pcm));
trk->remain -= size;
samp = (_SMP_IN *)trk->buf;
do {
long out;
out = _SAMP(*samp++);
#if (MIX_CHANNELS == 2)
out += _SAMP(*samp++);
out >>= 1;
#endif
_SAMPLIMIT(out);
_OUTSAMP(pcm[0], out);
pcm += 1;
} while(--size);
trk->buf = samp;
return(pcm);
}
static _SMP_OUT *FUNC_DOWN(GETSND trk, _SMP_OUT *pcm, _SMP_OUT *pcmterm) {
long mrate;
_SMP_IN *samp;
long smp;
samp = (_SMP_IN *)trk->buf;
mrate = trk->mrate;
do {
if (trk->rem > mrate) {
trk->rem -= mrate;
smp = _SAMP(*samp++);
#if (MIX_CHANNELS == 2)
smp += _SAMP(*samp++);
smp >>= 1;
#endif
trk->pcml += smp * mrate;
}
else {
long out;
long tmp;
out = trk->pcml;
out += _SAMP(samp[0]) * trk->rem;
out >>= DNBASEBITS;
_SAMPLIMIT(out);
_OUTSAMP(pcm[0], out);
tmp = mrate - trk->rem;
smp = _SAMP(*samp++);
#if (MIX_CHANNELS == 2)
smp += _SAMP(*samp++);
smp >>= 1;
#endif
trk->pcml = smp * tmp;
trk->rem = DNMIXBASE - tmp;
pcm += 1;
if (pcm >= pcmterm) {
trk->remain--;
break;
}
}
} while(--trk->remain);
trk->buf = samp;
return(pcm);
}
static _SMP_OUT *FUNC_UP(GETSND trk, _SMP_OUT *pcm, _SMP_OUT *pcmterm) {
_SMP_IN *samp;
long mrate;
samp = (_SMP_IN *)trk->buf;
mrate = trk->mrate;
do {
long tmp;
tmp = UPMIXBASE - trk->rem;
if (tmp >= 0) {
long dat;
long next;
dat = (trk->pcml * trk->rem);
next = _SAMP(*samp++);
#if (MIX_CHANNELS == 2)
next += _SAMP(*samp++);
next >>= 1;
#endif
dat += (next * tmp);
dat >>= UPBASEBITS;
_SAMPLIMIT(dat);
trk->pcml = next;
_OUTSAMP(pcm[0], dat);
trk->remain--;
trk->rem = trk->mrate - tmp;
pcm += 1;
if (pcm >= pcmterm) {
goto upsampterm;
}
}
while(trk->rem >= UPMIXBASE) {
long out;
trk->rem -= UPMIXBASE;
out = trk->pcml;
_SAMPLIMIT(out);
_OUTSAMP(pcm[0], out);
pcm += 1;
if (pcm >= pcmterm) {
goto upsampterm;
}
}
} while(trk->remain);
upsampterm:
trk->buf = samp;
return(pcm);
}
#undef _SAMP
#undef _SMP_IN
#undef _SMP_OUT
#undef _SAMPLIMIT
#undef _OUTSAMP
#undef MIX_INPUTBIT
#undef MIX_OUTPUTBIT
#undef MIX_CHANNELS
#undef FUNC_NOR
#undef FUNC_DOWN
#undef FUNC_UP

View File

@ -0,0 +1,173 @@
#if (MIX_INPUTBIT == 8)
#define _SMP_IN unsigned char
#define _SAMP(s) (((long)(s) - 0x80) << 8)
#elif (MIX_INPUTBIT == 16)
#define _SMP_IN short
#define _SAMP(s) (long)(s)
#endif
#if (MIX_OUTPUTBIT == 8)
#define _SMP_OUT unsigned char
#define _SAMPLIMIT(s) if ((s) > 32767) { \
(s) = 32767; \
} \
else if ((s) < -32768) { \
(s) = -32768; \
}
#define _OUTSAMP(d, s) (d) = (_SMP_OUT)(((s) >> 8) + 0x80)
#elif (MIX_OUTPUTBIT == 16)
#define _SMP_OUT short
#define _SAMPLIMIT(s) if ((s) > 32767) { \
(s) = 32767; \
} \
else if ((s) < -32768) { \
(s) = -32768; \
}
#define _OUTSAMP(d, s) (d) = (_SMP_OUT)(s)
#endif
static _SMP_OUT *FUNC_NOR(GETSND trk, _SMP_OUT *pcm, _SMP_OUT *pcmterm) {
_SMP_IN *samp;
UINT size;
size = min(trk->remain, (UINT)((pcmterm - pcm) / 2));
trk->remain -= size;
samp = (_SMP_IN *)trk->buf;
do {
long out;
out = _SAMP(*samp++);
_SAMPLIMIT(out);
_OUTSAMP(pcm[0], out);
#if (MIX_CHANNELS == 2)
out = _SAMP(*samp++);
_SAMPLIMIT(out);
#endif
_OUTSAMP(pcm[1], out);
pcm += 2;
} while(--size);
trk->buf = samp;
return(pcm);
}
static _SMP_OUT *FUNC_DOWN(GETSND trk, _SMP_OUT *pcm, _SMP_OUT *pcmterm) {
long mrate;
_SMP_IN *samp;
samp = (_SMP_IN *)trk->buf;
mrate = trk->mrate;
do {
if (trk->rem > mrate) {
trk->rem -= mrate;
trk->pcml += _SAMP(*samp++) * mrate;
#if (MIX_CHANNELS == 2)
trk->pcmr += _SAMP(*samp++) * mrate;
#endif
}
else {
long out;
long tmp;
out = trk->pcml;
out += _SAMP(samp[0]) * trk->rem;
out >>= DNBASEBITS;
_SAMPLIMIT(out);
_OUTSAMP(pcm[0], out);
#if (MIX_CHANNELS == 2)
out = trk->pcmr;
out += _SAMP(samp[1]) * trk->rem;
out >>= DNBASEBITS;
_SAMPLIMIT(out);
#endif
_OUTSAMP(pcm[1], out);
tmp = mrate - trk->rem;
trk->pcml = _SAMP(*samp++) * tmp;
#if (MIX_CHANNELS == 2)
trk->pcmr = _SAMP(*samp++) * tmp;
#endif
trk->rem = DNMIXBASE - tmp;
pcm += 2;
if (pcm >= pcmterm) {
trk->remain--;
break;
}
}
} while(--trk->remain);
trk->buf = samp;
return(pcm);
}
static _SMP_OUT *FUNC_UP(GETSND trk, _SMP_OUT *pcm, _SMP_OUT *pcmterm) {
_SMP_IN *samp;
long mrate;
samp = (_SMP_IN *)trk->buf;
mrate = trk->mrate;
do {
long tmp;
tmp = UPMIXBASE - trk->rem;
if (tmp >= 0) {
long dat;
long next;
dat = (trk->pcml * trk->rem);
next = _SAMP(*samp++);
dat += (next * tmp);
dat >>= UPBASEBITS;
_SAMPLIMIT(dat);
trk->pcml = next;
_OUTSAMP(pcm[0], dat);
#if (MIX_CHANNELS == 2)
dat = (trk->pcmr * trk->rem);
next = _SAMP(*samp++);
dat += (next * tmp);
dat >>= UPBASEBITS;
_SAMPLIMIT(dat);
trk->pcmr = next;
#endif
_OUTSAMP(pcm[1], dat);
trk->remain--;
trk->rem = trk->mrate - tmp;
pcm += 2;
if (pcm >= pcmterm) {
goto upsampterm;
}
}
while(trk->rem >= UPMIXBASE) {
long out;
trk->rem -= UPMIXBASE;
out = trk->pcml;
_SAMPLIMIT(out);
_OUTSAMP(pcm[0], out);
#if (MIX_CHANNELS == 2)
out = trk->pcmr;
_SAMPLIMIT(out);
#endif
_OUTSAMP(pcm[1], out);
pcm += 2;
if (pcm >= pcmterm) {
goto upsampterm;
}
}
} while(trk->remain);
upsampterm:
trk->buf = samp;
return(pcm);
}
#undef _SAMP
#undef _SMP_IN
#undef _SMP_OUT
#undef _SAMPLIMIT
#undef _OUTSAMP
#undef MIX_INPUTBIT
#undef MIX_OUTPUTBIT
#undef MIX_CHANNELS
#undef FUNC_NOR
#undef FUNC_DOWN
#undef FUNC_UP

View File

@ -0,0 +1,576 @@
#include "compiler.h"
#include "getsnd.h"
#if defined(__GNUC__)
typedef struct {
char head[4];
UINT8 size[4];
char fmt[4];
} __attribute__ ((packed)) RIFF_HEADER;
typedef struct {
char head[4];
UINT8 size[4];
} __attribute__ ((packed)) WAVE_HEADER;
typedef struct {
UINT8 format[2];
UINT8 channel[2];
UINT8 rate[4];
UINT8 rps[4];
UINT8 block[2];
UINT8 bit[2];
} __attribute__ ((packed)) WAVE_INFOS;
typedef struct {
UINT8 exsize[2];
UINT8 spb[2];
UINT8 numcoef[2];
} __attribute__ ((packed)) WAVE_MSA_INFO;
#else /* __GNUC__ */
#pragma pack(push, 1)
typedef struct {
char head[4];
UINT8 size[4];
char fmt[4];
} RIFF_HEADER;
typedef struct {
char head[4];
UINT8 size[4];
} WAVE_HEADER;
typedef struct {
UINT8 format[2];
UINT8 channel[2];
UINT8 rate[4];
UINT8 rps[4];
UINT8 block[2];
UINT8 bit[2];
} WAVE_INFOS;
typedef struct {
UINT8 exsize[2];
UINT8 spb[2];
UINT8 numcoef[2];
} WAVE_MSA_INFO;
#pragma pack(pop)
#endif /* __GNUC__ */
static const char fmt_riff[] = "RIFF";
static const char fmt_wave[] = "WAVE";
static const char fmt_rmp3[] = "RMP3";
static const char chunk_fmt[] = "fmt ";
static const char chunk_data[] = "data";
// ---- PCM
#if defined(BYTESEX_LITTLE)
static UINT pcm_dec(GETSND snd, void *dst) {
UINT size;
size = min(snd->blocksize, snd->datsize);
if (size) {
CopyMemory(dst, snd->datptr, size);
snd->datptr += size;
snd->datsize -= size;
size >>= (int)(long)snd->snd;
}
return(size);
}
#elif defined(BYTESEX_BIG)
static UINT pcm_dec(GETSND snd, UINT8 *dst) {
UINT size;
UINT cnt;
UINT8 *src;
size = min(snd->blocksize, snd->datsize);
if (size) {
if (snd->bit == 16) {
cnt = size >> 1;
src = snd->datptr;
while(cnt) {
cnt--;
dst[0] = src[1];
dst[1] = src[0];
src += 2;
dst += 2;
}
}
else {
CopyMemory(dst, snd->datptr, size);
}
snd->datptr += size;
snd->datsize -= size;
size >>= (int)(long)snd->snd;
}
return(size);
}
#endif
static const UINT8 abits[4] = {0, 1, 0, 2};
static BOOL pcm_open(GETSND snd) {
UINT align;
if ((snd->bit != 8) && (snd->bit != 16)) {
goto pcmopn_err;
}
align = snd->channels * (snd->bit >> 3);
if (snd->blocksize != align) {
goto pcmopn_err;
}
snd->blocksamples = 0x800; // 適当に。
snd->blocksize *= snd->blocksamples;
snd->snd = (void *)(long)abits[align - 1];
snd->dec = (GSDEC)pcm_dec;
return(SUCCESS);
pcmopn_err:
return(FAILURE);
}
// ---- MS-ADPCM
typedef struct {
SINT16 Coef1;
SINT16 Coef2;
} __COEFPAIR;
static const int MSADPCMTable[16] = {
230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230
};
static UINT msa_dec(GETSND snd, SINT16 *dst) {
UINT8 *buf;
UINT size;
UINT outsamples;
int pred[2], delta[2], nibble;
UINT i;
UINT8 indata;
__COEFPAIR *coef;
UINT ch;
SINT32 outdata;
buf = snd->datptr; // ワーク使ってません。
size = min(snd->datsize, snd->blocksize);
snd->datptr += size;
snd->datsize -= size;
outsamples = 0;
if (snd->channels == 1) {
if (size >= 7) {
pred[0] = buf[0];
pred[1] = 0;
delta[0] = LOADINTELWORD(buf+1);
delta[1] = 0;
*dst++ = (SINT16)LOADINTELWORD(buf+5);
*dst++ = (SINT16)LOADINTELWORD(buf+3);
buf += 7;
outsamples = 2 + ((size - 7) * 2);
}
}
else {
if (size >= 14) {
pred[0] = buf[0];
pred[1] = buf[1];
delta[0] = LOADINTELWORD(buf+2);
delta[1] = LOADINTELWORD(buf+4);
*dst++ = (SINT16)LOADINTELWORD(buf+10);
*dst++ = (SINT16)LOADINTELWORD(buf+12);
*dst++ = (SINT16)LOADINTELWORD(buf+6);
*dst++ = (SINT16)LOADINTELWORD(buf+8);
buf += 14;
outsamples = 2 + (size - 14);
}
}
coef = (__COEFPAIR *)snd->snd;
nibble = 0;
indata = 0; // for gcc
for (i=2; i<outsamples; i++) {
for (ch=0; ch<snd->channels; ch++) {
int d = delta[ch], p, data;
if (!nibble) {
indata = *buf++;
data = indata >> 4;
}
else {
data = indata & 15;
}
nibble ^= 1;
delta[ch] = (MSADPCMTable[data] * d) >> 8;
if (delta[ch] < 16) {
delta[ch] = 16;
}
p = (((*(dst - snd->channels )) * coef[pred[ch]].Coef1)
+((*(dst - snd->channels*2)) * coef[pred[ch]].Coef2));
p >>= 8;
outdata = (((data>=8)?(data-16):data) * d) + p;
if (outdata > 32767) {
outdata = 32767;
}
else if (outdata < -32768) {
outdata = -32768;
}
*dst++ = (SINT16)outdata;
}
}
return(outsamples);
}
static void msa_decend(GETSND snd) {
_MFREE(snd->snd);
}
static BOOL msa_open(GETSND snd, WAVE_INFOS *wavehead, UINT headsize) {
WAVE_MSA_INFO *info;
UINT exsize;
UINT numcoef;
UINT spb;
UINT blk;
__COEFPAIR *coef;
UINT8 *p;
if ((snd->bit != 4) ||
(headsize < (sizeof(WAVE_INFOS) + sizeof(WAVE_MSA_INFO)))) {
goto msaopn_err;
}
info = (WAVE_MSA_INFO *)(wavehead + 1);
headsize -= sizeof(WAVE_INFOS);
headsize -= sizeof(WAVE_MSA_INFO);
exsize = LOADINTELWORD(info->exsize);
spb = LOADINTELWORD(info->spb);
numcoef = LOADINTELWORD(info->numcoef);
blk = snd->blocksize;
blk /= snd->channels;
blk -= 6;
blk *= 2;
TRACEOUT(("wav: msa: ExtraSize %d / SPB=%d NumOfCoefs=%d",
exsize, spb, numcoef));
if (blk != spb) {
TRACEOUT(("wav: msa: block size error"));
goto msaopn_err;
}
if (exsize < (numcoef * 4 + 4)) {
TRACEOUT(("wav: msa: extra info size error"));
goto msaopn_err;
}
if (numcoef == 0) {
TRACEOUT(("wav: msa: coef == 0"));
goto msaopn_err;
}
coef = (__COEFPAIR*)_MALLOC(numcoef * sizeof(__COEFPAIR), "adpcm coefs");
if (coef == NULL) {
goto msaopn_err;
}
snd->blocksamples = spb;
snd->bit = 16;
snd->dec = (GSDEC)msa_dec;
snd->decend = msa_decend;
snd->snd = (void *)coef;
p = (UINT8 *)(info + 1);
do {
coef->Coef1 = LOADINTELWORD(p + 0);
coef->Coef2 = LOADINTELWORD(p + 2);
coef++;
p += 4;
} while(--numcoef);
return(SUCCESS);
msaopn_err:
return(FAILURE);
}
// ---- IMA
#define IMA_MAXSTEP 89
static BOOL ima_init = FALSE;
static UINT8 ima_statetbl[IMA_MAXSTEP][8];
static const int ima_stateadj[8] = {-1, -1, -1, -1, 2, 4, 6, 8};
static const int ima_steptable[IMA_MAXSTEP] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19,
21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157,
173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660,
4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,
11487,12635,13899,15289,16818,18500,20350,22385,24623,27086,29794,32767};
static void ima_inittable(void) {
int i, j, k;
for (i=0; i<IMA_MAXSTEP; i++) {
for (j=0; j<8; j++) {
k = i + ima_stateadj[j];
if (k < 0) {
k = 0;
}
else if (k >= IMA_MAXSTEP) {
k = IMA_MAXSTEP - 1;
}
ima_statetbl[i][j] = (UINT8)k;
}
}
}
static UINT ima_dec(GETSND snd, SINT16 *dst) {
UINT c;
SINT32 val[2];
int state[2];
UINT8 *src;
UINT blk;
if (snd->blocksize > snd->datsize) {
goto imadec_err;
}
src = snd->datptr; // ワーク使ってません。
snd->datptr += snd->blocksize;
snd->datsize -= snd->blocksize;
blk = snd->blocksamples;
for (c=0; c<snd->channels; c++) {
SINT16 tmp;
tmp = LOADINTELWORD(src);
val[c] = tmp;
*dst++ = (SINT16)val[c];
state[c] = src[2];
if (state[c] >= IMA_MAXSTEP) {
state[c] = 0;
}
src += 4;
}
blk--;
while(blk >= 8) {
blk -= 8;
for (c=0; c<snd->channels; c++) {
UINT samp, r;
samp = 0; // for gcc
r = 8;
do {
int step, dp;
if (!(r & 1)) {
samp = *src++;
}
else {
samp >>= 4;
}
step = ima_steptable[state[c]];
state[c] = ima_statetbl[state[c]][samp & 7];
dp = ((((samp & 7) << 1) + 1) * step) >> 3;
if (!(samp & 8)) {
val[c] += dp;
if (val[c] > 32767) {
val[c] = 32767;
}
}
else {
val[c] -= dp;
if (val[c] < -32768) {
val[c] = -32768;
}
}
*dst = (SINT16)val[c];
dst += snd->channels;
} while(--r);
dst -= (8 * snd->channels);
dst++;
}
dst += (7 * snd->channels);
}
return(snd->blocksamples);
imadec_err:
return(0);
}
static BOOL ima_open(GETSND snd) {
int blk;
if (snd->bit != 4) {
goto imaopn_err;
}
blk = snd->blocksize;
blk /= snd->channels;
if (blk & 3) {
goto imaopn_err;
}
blk -= 4; // first block;
blk *= 2;
blk += 1;
snd->blocksamples = blk;
snd->bit = 16;
snd->dec = (GSDEC)ima_dec;
if (!ima_init) {
ima_init = TRUE;
ima_inittable();
}
return(SUCCESS);
imaopn_err:
return(FAILURE);
}
// ---- MP3
#if defined(SUPPORT_MP3)
extern BOOL __mp3_open(GETSND snd, UINT8 *ptr, UINT size);
#endif
// ----
BOOL getwave_open(GETSND snd, UINT8 *ptr, UINT size) {
RIFF_HEADER *riff;
WAVE_HEADER *head;
WAVE_INFOS *info;
UINT pos;
UINT format;
BOOL r;
UINT headsize = 0;
UINT datasize;
info = NULL; // for gcc
// RIFFのチェック
riff = (RIFF_HEADER *)ptr;
pos = sizeof(RIFF_HEADER);
if (size < pos) {
TRACEOUT(("wav: error RIFF header"));
goto gwopn_err;
}
if (memcmp(riff->head, fmt_riff, 4)) {
TRACEOUT(("wav: error RIFF header"));
goto gwopn_err;
}
if (!memcmp(riff->fmt, fmt_wave, 4)) {
// フォーマットヘッダチェック
head = (WAVE_HEADER *)(ptr + pos);
pos += sizeof(WAVE_HEADER);
if (size < pos) {
TRACEOUT(("wav: error fmt header"));
goto gwopn_err;
}
if (memcmp(head->head, chunk_fmt, 4)) {
TRACEOUT(("wav: error fmt header"));
goto gwopn_err;
}
headsize = LOADINTELDWORD(head->size);
if (headsize < sizeof(WAVE_INFOS)) {
TRACEOUT(("wav: error fmt length"));
goto gwopn_err;
}
// フォーマットチェック
info = (WAVE_INFOS *)(ptr + pos);
pos += headsize;
if (size < pos) {
TRACEOUT(("wav: error fmt data"));
goto gwopn_err;
}
format = LOADINTELWORD(info->format);
snd->channels = LOADINTELWORD(info->channel);
snd->samplingrate = LOADINTELDWORD(info->rate);
snd->blocksize = LOADINTELWORD(info->block);
snd->bit = LOADINTELWORD(info->bit);
TRACEOUT(("wav: fmt: %x / %dch %dHz %dbit",
format, snd->channels, snd->samplingrate, snd->bit));
if ((UINT)(snd->channels - 1) >= 2) {
TRACEOUT(("wav: channels err"));
goto gwopn_err;
}
}
else if (!memcmp(riff->fmt, fmt_rmp3, 4)) {
format = 0x55;
}
else {
TRACEOUT(("wav: error WAVE header"));
goto gwopn_err;
}
// dataまで移動。
while(1) {
head = (WAVE_HEADER *)(ptr + pos);
pos += sizeof(WAVE_HEADER);
if (size < pos) {
TRACEOUT(("wav: error data header"));
goto gwopn_err;
}
if (!memcmp(head->head, chunk_data, 4)) {
break;
}
pos += LOADINTELDWORD(head->size);
}
ptr += pos;
size -= pos;
datasize = LOADINTELDWORD(head->size);
size = min(size, datasize);
switch(format) {
case 0x01: // PCM
r = pcm_open(snd);
break;
case 0x02:
r = msa_open(snd, info, headsize);
break;
case 0x11:
r = ima_open(snd);
break;
#if defined(SUPPORT_MP3)
case 0x55:
return(__mp3_open(snd, ptr, size));
#endif
#if defined(SUPPORT_OGG)
case 0x6751:
return(getogg_open(snd, ptr, size));
#endif
default:
r = FAILURE;
break;
}
if (r != SUCCESS) {
TRACEOUT(("wav: decord open error"));
goto gwopn_err;
}
// 登録~
snd->datptr = ptr;
snd->datsize = size;
return(SUCCESS);
gwopn_err:
return(FAILURE);
}

View File

@ -0,0 +1,184 @@
enum {
#if defined(SUPPORT_PX)
OPNCH_MAX = 30,
#else // defined(SUPPORT_PX)
OPNCH_MAX = 12,
#endif // defined(SUPPORT_PX)
OPNA_CLOCK = 55466 * 72,
OPN_CHMASK = 0x80000000,
OPN_STEREO = 0x80000000,
OPN_MONORAL = 0x00000000
};
#if defined(OPNGENX86)
enum {
FMDIV_BITS = 8,
FMDIV_ENT = (1 << FMDIV_BITS),
FMVOL_SFTBIT = 4
};
#define SIN_BITS 11
#define EVC_BITS 10
#define ENV_BITS 16
#define KF_BITS 6
#define FREQ_BITS 21
#define ENVTBL_BIT 14
#define SINTBL_BIT 14
#elif defined(OPNGENARM)
enum {
FMDIV_BITS = 8,
FMDIV_ENT = (1 << FMDIV_BITS),
FMVOL_SFTBIT = 4
};
#define SIN_BITS 8
#define EVC_BITS 7
#define ENV_BITS 16
#define KF_BITS 6
#define FREQ_BITS 20
#define ENVTBL_BIT 14
#define SINTBL_BIT 14 // env+sin 30bit max
#else
enum {
FMDIV_BITS = 8,
FMDIV_ENT = (1 << FMDIV_BITS),
FMVOL_SFTBIT = 4
};
#define SIN_BITS 10
#define EVC_BITS 10
#define ENV_BITS 16
#define KF_BITS 6
#define FREQ_BITS 21
#define ENVTBL_BIT 14
#define SINTBL_BIT 15
#endif
#define TL_BITS (FREQ_BITS+2)
#define OPM_OUTSB (TL_BITS + 2 - 16) // OPM output 16bit
#define SIN_ENT (1L << SIN_BITS)
#define EVC_ENT (1L << EVC_BITS)
#define EC_ATTACK 0 // ATTACK start
#define EC_DECAY (EVC_ENT << ENV_BITS) // DECAY start
#define EC_OFF ((2 * EVC_ENT) << ENV_BITS) // OFF
#define TL_MAX (EVC_ENT * 2)
enum {
OPNSLOT1 = 0, // slot number
OPNSLOT2 = 2,
OPNSLOT3 = 1,
OPNSLOT4 = 3,
EM_ATTACK = 4,
EM_DECAY1 = 3,
EM_DECAY2 = 2,
EM_RELEASE = 1,
EM_OFF = 0
};
typedef struct {
SINT32 *detune1; // detune1
SINT32 totallevel; // total level
SINT32 decaylevel; // decay level
const SINT32 *attack; // attack ratio
const SINT32 *decay1; // decay1 ratio
const SINT32 *decay2; // decay2 ratio
const SINT32 *release; // release ratio
SINT32 freq_cnt; // frequency count
SINT32 freq_inc; // frequency step
SINT32 multiple; // multiple
UINT8 keyscale; // key scale
UINT8 env_mode; // envelope mode
UINT8 envratio; // envelope ratio
UINT8 ssgeg1; // SSG-EG
SINT32 env_cnt; // envelope count
SINT32 env_end; // envelope end count
SINT32 env_inc; // envelope step
SINT32 env_inc_attack; // envelope attack step
SINT32 env_inc_decay1; // envelope decay1 step
SINT32 env_inc_decay2; // envelope decay2 step
SINT32 env_inc_release; // envelope release step
} OPNSLOT;
typedef struct {
OPNSLOT slot[4];
UINT8 algorithm; // algorithm
UINT8 feedback; // self feedback
UINT8 playing;
UINT8 outslot;
SINT32 op1fb; // operator1 feedback
SINT32 *connect1; // operator1 connect
SINT32 *connect3; // operator3 connect
SINT32 *connect2; // operator2 connect
SINT32 *connect4; // operator4 connect
UINT32 keynote[4]; // key note // ver0.27
UINT8 keyfunc[4]; // key function
UINT8 kcode[4]; // key code
UINT8 pan; // pan
UINT8 extop; // extendopelator-enable
UINT8 stereo; // stereo-enable
UINT8 padding2;
} OPNCH;
typedef struct {
UINT playchannels;
UINT playing;
SINT32 feedback2;
SINT32 feedback3;
SINT32 feedback4;
SINT32 outdl;
SINT32 outdc;
SINT32 outdr;
SINT32 calcremain;
UINT8 keyreg[OPNCH_MAX];
} _OPNGEN, *OPNGEN;
typedef struct {
SINT32 calc1024;
SINT32 fmvol;
UINT ratebit;
UINT vr_en;
SINT32 vr_l;
SINT32 vr_r;
SINT32 sintable[SIN_ENT];
SINT32 envtable[EVC_ENT];
SINT32 envcurve[EVC_ENT*2 + 1];
} OPNCFG;
#ifdef __cplusplus
extern "C" {
#endif
void opngen_initialize(UINT rate);
void opngen_setvol(UINT vol);
void opngen_setVR(REG8 channel, REG8 value);
void opngen_reset(void);
void opngen_setcfg(REG8 maxch, UINT32 flag);
void opngen_setextch(UINT chnum, REG8 data);
void opngen_setreg(REG8 chbase, UINT reg, REG8 value);
void opngen_keyon(UINT chnum, REG8 value);
void SOUNDCALL opngen_getpcm(void *hdl, SINT32 *buf, UINT count);
void SOUNDCALL opngen_getpcmvr(void *hdl, SINT32 *buf, UINT count);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,626 @@
#include "compiler.h"
#include <math.h>
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
#include "keydisp.h"
#define OPM_ARRATE 399128L
#define OPM_DRRATE 5514396L
#define EG_STEP (96.0 / EVC_ENT) // dB step
#define SC(db) (SINT32)((db) * ((3.0 / EG_STEP) * (1 << ENV_BITS))) + EC_DECAY
#define D2(v) (((double)(6 << KF_BITS) * log((double)(v)) / log(2.0)) + 0.5)
#define FMASMSHIFT (32 - 6 - (OPM_OUTSB + 1 + FMDIV_BITS) + FMVOL_SFTBIT)
#define FREQBASE4096 ((double)OPNA_CLOCK / calcrate / 64)
OPNCFG opncfg;
#ifdef OPNGENX86
char envshift[EVC_ENT];
char sinshift[SIN_ENT];
#endif
static SINT32 detunetable[8][32];
static SINT32 attacktable[94];
static SINT32 decaytable[94];
static const SINT32 decayleveltable[16] = {
SC( 0),SC( 1),SC( 2),SC( 3),SC( 4),SC( 5),SC( 6),SC( 7),
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)};
static const UINT8 multipletable[] = {
1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
static const SINT32 nulltable[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static const UINT8 kftable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3};
static const UINT8 dttable[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,
2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22};
static const int extendslot[4] = {2, 3, 1, 0};
static const int fmslot[4] = {0, 2, 1, 3};
void opngen_initialize(UINT rate) {
UINT ratebit;
int i;
char sft;
int j;
double pom;
long detune;
double freq;
UINT32 calcrate;
if (rate == 44100) {
ratebit = 0;
}
else if (rate == 22050) {
ratebit = 1;
}
else {
ratebit = 2;
}
calcrate = (OPNA_CLOCK / 72) >> ratebit;
opncfg.calc1024 = FMDIV_ENT * 44100 / (OPNA_CLOCK / 72);
for (i=0; i<EVC_ENT; i++) {
#ifdef OPNGENX86
sft = ENVTBL_BIT;
while(sft < (ENVTBL_BIT + 8)) {
pom = (double)(1 << sft) / pow(10.0, EG_STEP*(EVC_ENT-i)/20.0);
opncfg.envtable[i] = (long)pom;
envshift[i] = sft - TL_BITS;
if (opncfg.envtable[i] >= (1 << (ENVTBL_BIT - 1))) {
break;
}
sft++;
}
#else
pom = (double)(1 << ENVTBL_BIT) / pow(10.0, EG_STEP*(EVC_ENT-i)/20.0);
opncfg.envtable[i] = (long)pom;
#endif
}
for (i=0; i<SIN_ENT; i++) {
#ifdef OPNGENX86
char sft;
sft = SINTBL_BIT;
while(sft < (SINTBL_BIT + 8)) {
pom = (double)(1 << sft) * sin(2*PI*i/SIN_ENT);
opncfg.sintable[i] = (long)pom;
sinshift[i] = sft;
if (opncfg.sintable[i] >= (1 << (SINTBL_BIT - 1))) {
break;
}
if (opncfg.sintable[i] <= -1 * (1 << (SINTBL_BIT - 1))) {
break;
}
sft++;
}
#else
pom = (double)((1 << SINTBL_BIT) - 1) * sin(2*PI*i/SIN_ENT);
opncfg.sintable[i] = (long)pom;
#endif
}
for (i=0; i<EVC_ENT; i++) {
pom = pow(((double)(EVC_ENT-1-i)/EVC_ENT), 8) * EVC_ENT;
opncfg.envcurve[i] = (long)pom;
opncfg.envcurve[EVC_ENT + i] = i;
}
opncfg.envcurve[EVC_ENT*2] = EVC_ENT;
// opmbaserate = (1L << FREQ_BITS) / (rate * x / 44100) * 55466;
// でも今は x == 55466だから…
// ここで FREQ_BITS >= 16が条件
if (rate == 44100) {
opncfg.ratebit = 0 + (FREQ_BITS - 16);
}
else if (rate == 22050) {
opncfg.ratebit = 1 + (FREQ_BITS - 16);
}
else {
opncfg.ratebit = 2 + (FREQ_BITS - 16);
}
for (i=0; i<4; i++) {
for (j=0; j<32; j++) {
detune = dttable[i*32 + j];
sft = ratebit + (FREQ_BITS - 21);
if (sft >= 0) {
detune <<= sft;
}
else {
detune >>= (0 - sft);
}
detunetable[i][j] = detune;
detunetable[i+4][j] = -detune;
}
}
for (i=0; i<4; i++) {
attacktable[i] = decaytable[i] = 0;
}
for (i=4; i<64; i++) {
freq = (double)(EVC_ENT << ENV_BITS) * FREQBASE4096;
if (i < 8) { // 忘れてます。
freq *= 1.0 + (i & 2) * 0.25;
}
else if (i < 60) {
freq *= 1.0 + (i & 3) * 0.25;
}
freq *= (double)(1 << ((i >> 2) - 1));
#if 0
attacktable[i] = (long)((freq + OPM_ARRATE - 1) / OPM_ARRATE);
decaytable[i] = (long)((freq + OPM_DRRATE - 1) / OPM_DRRATE);
#else
attacktable[i] = (long)(freq / OPM_ARRATE);
decaytable[i] = (long)(freq / OPM_DRRATE);
#endif
if (attacktable[i] >= EC_DECAY) {
TRACEOUT(("attacktable %d %d %ld", i, attacktable[i], EC_DECAY));
}
if (decaytable[i] >= EC_DECAY) {
TRACEOUT(("decaytable %d %d %ld", i, decaytable[i], EC_DECAY));
}
}
attacktable[62] = EC_DECAY - 1;
attacktable[63] = EC_DECAY - 1;
for (i=64; i<94; i++) {
attacktable[i] = attacktable[63];
decaytable[i] = decaytable[63];
}
}
void opngen_setvol(UINT vol) {
opncfg.fmvol = vol * 5 / 4;
#if defined(OPNGENX86)
opncfg.fmvol <<= FMASMSHIFT;
#endif
}
void opngen_setVR(REG8 channel, REG8 value) {
if ((channel & 3) && (value)) {
opncfg.vr_en = TRUE;
opncfg.vr_l = (channel & 1)?value:0;
opncfg.vr_r = (channel & 2)?value:0;
}
else {
opncfg.vr_en = FALSE;
}
}
// ----
static void set_algorithm(OPNCH *ch) {
SINT32 *outd;
UINT8 outslot;
outd = &opngen.outdc;
if (ch->stereo) {
switch(ch->pan & 0xc0) {
case 0x80:
outd = &opngen.outdl;
break;
case 0x40:
outd = &opngen.outdr;
break;
}
}
switch(ch->algorithm) {
case 0:
ch->connect1 = &opngen.feedback2;
ch->connect2 = &opngen.feedback3;
ch->connect3 = &opngen.feedback4;
outslot = 0x08;
break;
case 1:
ch->connect1 = &opngen.feedback3;
ch->connect2 = &opngen.feedback3;
ch->connect3 = &opngen.feedback4;
outslot = 0x08;
break;
case 2:
ch->connect1 = &opngen.feedback4;
ch->connect2 = &opngen.feedback3;
ch->connect3 = &opngen.feedback4;
outslot = 0x08;
break;
case 3:
ch->connect1 = &opngen.feedback2;
ch->connect2 = &opngen.feedback4;
ch->connect3 = &opngen.feedback4;
outslot = 0x08;
break;
case 4:
ch->connect1 = &opngen.feedback2;
ch->connect2 = outd;
ch->connect3 = &opngen.feedback4;
outslot = 0x0a;
break;
case 5:
ch->connect1 = 0;
ch->connect2 = outd;
ch->connect3 = outd;
outslot = 0x0e;
break;
case 6:
ch->connect1 = &opngen.feedback2;
ch->connect2 = outd;
ch->connect3 = outd;
outslot = 0x0e;
break;
case 7:
default:
ch->connect1 = outd;
ch->connect2 = outd;
ch->connect3 = outd;
outslot = 0x0f;
}
ch->connect4 = outd;
ch->outslot = outslot;
}
static void set_dt1_mul(OPNSLOT *slot, REG8 value) {
slot->multiple = (SINT32)multipletable[value & 0x0f];
slot->detune1 = detunetable[(value >> 4) & 7];
}
static void set_tl(OPNSLOT *slot, REG8 value) {
#if (EVC_BITS >= 7)
slot->totallevel = ((~value) & 0x007f) << (EVC_BITS - 7);
#else
slot->totallevel = ((~value) & 0x007f) >> (7 - EVC_BITS);
#endif
}
static void set_ks_ar(OPNSLOT *slot, REG8 value) {
slot->keyscale = ((~value) >> 6) & 3;
value &= 0x1f;
slot->attack = (value)?(attacktable + (value << 1)):nulltable;
slot->env_inc_attack = slot->attack[slot->envratio];
if (slot->env_mode == EM_ATTACK) {
slot->env_inc = slot->env_inc_attack;
}
}
static void set_d1r(OPNSLOT *slot, REG8 value) {
value &= 0x1f;
slot->decay1 = (value)?(decaytable + (value << 1)):nulltable;
slot->env_inc_decay1 = slot->decay1[slot->envratio];
if (slot->env_mode == EM_DECAY1) {
slot->env_inc = slot->env_inc_decay1;
}
}
static void set_dt2_d2r(OPNSLOT *slot, REG8 value) {
value &= 0x1f;
slot->decay2 = (value)?(decaytable + (value << 1)):nulltable;
if (slot->ssgeg1) {
slot->env_inc_decay2 = 0;
}
else {
slot->env_inc_decay2 = slot->decay2[slot->envratio];
}
if (slot->env_mode == EM_DECAY2) {
slot->env_inc = slot->env_inc_decay2;
}
}
static void set_d1l_rr(OPNSLOT *slot, REG8 value) {
slot->decaylevel = decayleveltable[(value >> 4)];
slot->release = decaytable + ((value & 0x0f) << 2) + 2;
slot->env_inc_release = slot->release[slot->envratio];
if (slot->env_mode == EM_RELEASE) {
slot->env_inc = slot->env_inc_release;
if (value == 0xff) {
slot->env_mode = EM_OFF;
slot->env_cnt = EC_OFF;
slot->env_end = EC_OFF + 1;
slot->env_inc = 0;
}
}
}
static void set_ssgeg(OPNSLOT *slot, REG8 value) {
value &= 0xf;
if ((value == 0xb) || (value == 0xd)) {
slot->ssgeg1 = 1;
slot->env_inc_decay2 = 0;
}
else {
slot->ssgeg1 = 0;
slot->env_inc_decay2 = slot->decay2[slot->envratio];
}
if (slot->env_mode == EM_DECAY2) {
slot->env_inc = slot->env_inc_decay2;
}
}
static void channleupdate(OPNCH *ch) {
int i;
UINT32 fc = ch->keynote[0]; // ver0.27
UINT8 kc = ch->kcode[0];
UINT evr;
OPNSLOT *slot;
int s;
slot = ch->slot;
if (!(ch->extop)) {
for (i=0; i<4; i++, slot++) {
slot->freq_inc = (fc + slot->detune1[kc]) * slot->multiple;
evr = kc >> slot->keyscale;
if (slot->envratio != evr) {
slot->envratio = evr;
slot->env_inc_attack = slot->attack[evr];
slot->env_inc_decay1 = slot->decay1[evr];
slot->env_inc_decay2 = slot->decay2[evr];
slot->env_inc_release = slot->release[evr];
}
}
}
else {
for (i=0; i<4; i++, slot++) {
s = extendslot[i];
slot->freq_inc = (ch->keynote[s] + slot->detune1[ch->kcode[s]])
* slot->multiple;
evr = ch->kcode[s] >> slot->keyscale;
if (slot->envratio != evr) {
slot->envratio = evr;
slot->env_inc_attack = slot->attack[evr];
slot->env_inc_decay1 = slot->decay1[evr];
slot->env_inc_decay2 = slot->decay2[evr];
slot->env_inc_release = slot->release[evr];
}
}
}
}
// ----
void opngen_reset(void) {
OPNCH *ch;
UINT i;
OPNSLOT *slot;
UINT j;
ZeroMemory(&opngen, sizeof(opngen));
ZeroMemory(opnch, sizeof(opnch));
opngen.playchannels = 3;
ch = opnch;
for (i=0; i<OPNCH_MAX; i++) {
ch->keynote[0] = 0;
slot = ch->slot;
for (j=0; j<4; j++) {
slot->env_mode = EM_OFF;
slot->env_cnt = EC_OFF;
slot->env_end = EC_OFF + 1;
slot->env_inc = 0;
slot->detune1 = detunetable[0];
slot->attack = nulltable;
slot->decay1 = nulltable;
slot->decay2 = nulltable;
slot->release = decaytable;
slot++;
}
ch++;
}
for (i=0x30; i<0xc0; i++) {
opngen_setreg(0, i, 0xff);
opngen_setreg(3, i, 0xff);
opngen_setreg(6, i, 0xff);
opngen_setreg(9, i, 0xff);
}
}
void opngen_setcfg(REG8 maxch, UINT32 flag) {
OPNCH *ch;
UINT i;
opngen.playchannels = maxch;
ch = opnch;
if ((flag & OPN_CHMASK) == OPN_STEREO) {
for (i=0; i<OPNCH_MAX; i++) {
if (flag & (1 << i)) {
ch->stereo = TRUE;
set_algorithm(ch);
}
ch++;
}
}
else {
for (i=0; i<OPNCH_MAX; i++) {
if (flag & (1 << i)) {
ch->stereo = FALSE;
set_algorithm(ch);
}
ch++;
}
}
}
void opngen_setextch(UINT chnum, REG8 data) {
OPNCH *ch;
ch = opnch;
ch[chnum].extop = data;
}
void opngen_setreg(REG8 chbase, UINT reg, REG8 value) {
UINT chpos;
OPNCH *ch;
OPNSLOT *slot;
UINT fn;
UINT8 blk;
chpos = reg & 3;
if (chpos == 3) {
return;
}
sound_sync();
ch = opnch + chbase + chpos;
if (reg < 0xa0) {
slot = ch->slot + fmslot[(reg >> 2) & 3];
switch(reg & 0xf0) {
case 0x30: // DT1 MUL
set_dt1_mul(slot, value);
channleupdate(ch);
break;
case 0x40: // TL
set_tl(slot, value);
break;
case 0x50: // KS AR
set_ks_ar(slot, value);
channleupdate(ch);
break;
case 0x60: // D1R
set_d1r(slot, value);
break;
case 0x70: // DT2 D2R
set_dt2_d2r(slot, value);
channleupdate(ch);
break;
case 0x80: // D1L RR
set_d1l_rr(slot, value);
break;
case 0x90:
set_ssgeg(slot, value);
channleupdate(ch);
break;
}
}
else {
switch(reg & 0xfc) {
case 0xa0:
blk = ch->keyfunc[0] >> 3;
fn = ((ch->keyfunc[0] & 7) << 8) + value;
ch->kcode[0] = (blk << 2) | kftable[fn >> 7];
// ch->keynote[0] = fn * opmbaserate / (1L << (22-blk));
ch->keynote[0] = (fn << (opncfg.ratebit + blk)) >> 6;
channleupdate(ch);
break;
case 0xa4:
ch->keyfunc[0] = value & 0x3f;
break;
case 0xa8:
ch = opnch + chbase + 2;
blk = ch->keyfunc[chpos+1] >> 3;
fn = ((ch->keyfunc[chpos+1] & 7) << 8) + value;
ch->kcode[chpos+1] = (blk << 2) | kftable[fn >> 7];
// ch->keynote[chpos+1] = fn * opmbaserate / (1L << (22-blk));
ch->keynote[chpos+1] = (fn << (opncfg.ratebit + blk)) >> 6;
channleupdate(ch);
break;
case 0xac:
ch = opnch + chbase + 2;
ch->keyfunc[chpos+1] = value & 0x3f;
break;
case 0xb0:
ch->algorithm = (UINT8)(value & 7);
value = (value >> 3) & 7;
if (value) {
ch->feedback = 8 - value;
}
else {
ch->feedback = 0;
}
set_algorithm(ch);
break;
case 0xb4:
ch->pan = (UINT8)(value & 0xc0);
set_algorithm(ch);
break;
}
}
}
void opngen_keyon(UINT chnum, REG8 value) {
OPNCH *ch;
OPNSLOT *slot;
REG8 bit;
UINT i;
sound_sync();
opngen.keyreg[chnum] = value;
opngen.playing++;
ch = opnch + chnum;
ch->playing |= value >> 4;
slot = ch->slot;
bit = 0x10;
for (i=0; i<4; i++) {
if (value & bit) { // keyon
if (slot->env_mode <= EM_RELEASE) {
slot->freq_cnt = 0;
if (i == OPNSLOT1) {
ch->op1fb = 0;
}
slot->env_mode = EM_ATTACK;
slot->env_inc = slot->env_inc_attack;
slot->env_cnt = EC_ATTACK;
slot->env_end = EC_DECAY;
}
}
else { // keyoff
if (slot->env_mode > EM_RELEASE) {
slot->env_mode = EM_RELEASE;
if (!(slot->env_cnt & EC_DECAY)) {
slot->env_cnt = (opncfg.envcurve[slot->env_cnt
>> ENV_BITS] << ENV_BITS) + EC_DECAY;
}
slot->env_end = EC_OFF;
slot->env_inc = slot->env_inc_release;
}
}
slot++;
bit <<= 1;
}
keydisp_fmkeyon((UINT8)chnum, value);
}

View File

@ -0,0 +1,212 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
#if defined(OPNGENX86)
#error use opngen.x86
#endif
extern OPNCFG opncfg;
#define CALCENV(e, c, s) \
(c)->slot[(s)].freq_cnt += (c)->slot[(s)].freq_inc; \
(c)->slot[(s)].env_cnt += (c)->slot[(s)].env_inc; \
if ((c)->slot[(s)].env_cnt >= (c)->slot[(s)].env_end) { \
switch((c)->slot[(s)].env_mode) { \
case EM_ATTACK: \
(c)->slot[(s)].env_mode = EM_DECAY1; \
(c)->slot[(s)].env_cnt = EC_DECAY; \
(c)->slot[(s)].env_end = (c)->slot[(s)].decaylevel; \
(c)->slot[(s)].env_inc = (c)->slot[(s)].env_inc_decay1; \
break; \
case EM_DECAY1: \
(c)->slot[(s)].env_mode = EM_DECAY2; \
(c)->slot[(s)].env_cnt = (c)->slot[(s)].decaylevel; \
(c)->slot[(s)].env_end = EC_OFF; \
(c)->slot[(s)].env_inc = (c)->slot[(s)].env_inc_decay2; \
break; \
case EM_RELEASE: \
(c)->slot[(s)].env_mode = EM_OFF; \
case EM_DECAY2: \
(c)->slot[(s)].env_cnt = EC_OFF; \
(c)->slot[(s)].env_end = EC_OFF + 1; \
(c)->slot[(s)].env_inc = 0; \
(c)->playing &= ~(1 << (s)); \
break; \
} \
} \
(e) = (c)->slot[(s)].totallevel - \
opncfg.envcurve[(c)->slot[(s)].env_cnt >> ENV_BITS];
#define SLOTOUT(s, e, c) \
((opncfg.sintable[(((s).freq_cnt + (c)) >> \
(FREQ_BITS - SIN_BITS)) & (SIN_ENT - 1)] * \
opncfg.envtable[(e)]) >> (ENVTBL_BIT+SINTBL_BIT-TL_BITS))
static void calcratechannel(OPNCH *ch) {
SINT32 envout;
SINT32 opout;
opngen.feedback2 = 0;
opngen.feedback3 = 0;
opngen.feedback4 = 0;
/* SLOT 1 */
CALCENV(envout, ch, 0);
if (envout > 0) {
if (ch->feedback) {
/* with self feed back */
opout = ch->op1fb;
ch->op1fb = SLOTOUT(ch->slot[0], envout,
(ch->op1fb >> ch->feedback));
opout = (opout + ch->op1fb) / 2;
}
else {
/* without self feed back */
opout = SLOTOUT(ch->slot[0], envout, 0);
}
/* output slot1 */
if (!ch->connect1) {
opngen.feedback2 = opngen.feedback3 = opngen.feedback4 = opout;
}
else {
*ch->connect1 += opout;
}
}
/* SLOT 2 */
CALCENV(envout, ch, 1);
if (envout > 0) {
*ch->connect2 += SLOTOUT(ch->slot[1], envout, opngen.feedback2);
}
/* SLOT 3 */
CALCENV(envout, ch, 2);
if (envout > 0) {
*ch->connect3 += SLOTOUT(ch->slot[2], envout, opngen.feedback3);
}
/* SLOT 4 */
CALCENV(envout, ch, 3);
if (envout > 0) {
*ch->connect4 += SLOTOUT(ch->slot[3], envout, opngen.feedback4);
}
}
void SOUNDCALL opngen_getpcm(void *hdl, SINT32 *pcm, UINT count) {
OPNCH *fm;
UINT i;
UINT playing;
SINT32 samp_l;
SINT32 samp_r;
if ((!opngen.playing) || (!count)) {
return;
}
fm = opnch;
do {
samp_l = opngen.outdl * (opngen.calcremain * -1);
samp_r = opngen.outdr * (opngen.calcremain * -1);
opngen.calcremain += FMDIV_ENT;
while(1) {
opngen.outdc = 0;
opngen.outdl = 0;
opngen.outdr = 0;
playing = 0;
for (i=0; i<opngen.playchannels; i++) {
if (fm[i].playing & fm[i].outslot) {
calcratechannel(fm + i);
playing++;
}
}
opngen.outdl += opngen.outdc;
opngen.outdr += opngen.outdc;
opngen.outdl >>= FMVOL_SFTBIT;
opngen.outdr >>= FMVOL_SFTBIT;
if (opngen.calcremain > opncfg.calc1024) {
samp_l += opngen.outdl * opncfg.calc1024;
samp_r += opngen.outdr * opncfg.calc1024;
opngen.calcremain -= opncfg.calc1024;
}
else {
break;
}
}
samp_l += opngen.outdl * opngen.calcremain;
samp_l >>= 8;
samp_l *= opncfg.fmvol;
samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[0] += samp_l;
samp_r += opngen.outdr * opngen.calcremain;
samp_r >>= 8;
samp_r *= opncfg.fmvol;
samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[1] += samp_r;
opngen.calcremain -= opncfg.calc1024;
pcm += 2;
} while(--count);
opngen.playing = playing;
(void)hdl;
}
void SOUNDCALL opngen_getpcmvr(void *hdl, SINT32 *pcm, UINT count) {
OPNCH *fm;
UINT i;
SINT32 samp_l;
SINT32 samp_r;
fm = opnch;
while(count--) {
samp_l = opngen.outdl * (opngen.calcremain * -1);
samp_r = opngen.outdr * (opngen.calcremain * -1);
opngen.calcremain += FMDIV_ENT;
while(1) {
opngen.outdc = 0;
opngen.outdl = 0;
opngen.outdr = 0;
for (i=0; i<opngen.playchannels; i++) {
calcratechannel(fm + i);
}
if (opncfg.vr_en) {
SINT32 tmpl;
SINT32 tmpr;
tmpl = (opngen.outdl >> 5) * opncfg.vr_l;
tmpr = (opngen.outdr >> 5) * opncfg.vr_r;
opngen.outdl += tmpr;
opngen.outdr += tmpl;
}
opngen.outdl += opngen.outdc;
opngen.outdr += opngen.outdc;
opngen.outdl >>= FMVOL_SFTBIT;
opngen.outdr >>= FMVOL_SFTBIT;
if (opngen.calcremain > opncfg.calc1024) {
samp_l += opngen.outdl * opncfg.calc1024;
samp_r += opngen.outdr * opncfg.calc1024;
opngen.calcremain -= opncfg.calc1024;
}
else {
break;
}
}
samp_l += opngen.outdl * opngen.calcremain;
samp_l >>= 8;
samp_l *= opncfg.fmvol;
samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[0] += samp_l;
samp_r += opngen.outdr * opngen.calcremain;
samp_r >>= 8;
samp_r *= opncfg.fmvol;
samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[1] += samp_r;
opngen.calcremain -= opncfg.calc1024;
pcm += 2;
}
(void)hdl;
}

View File

@ -0,0 +1,90 @@
enum {
PCM86_LOGICALBUF = 0x8000,
PCM86_BUFSIZE = (1 << 16),
PCM86_BUFMSK = ((1 << 16) - 1),
PCM86_DIVBIT = 10,
PCM86_DIVENV = (1 << PCM86_DIVBIT),
PCM86_RESCUE = 20
};
#define PCM86_EXTBUF pcm86.rescue // 救済延滞…
#define PCM86_REALBUFSIZE (PCM86_LOGICALBUF + PCM86_EXTBUF)
#define RECALC_NOWCLKWAIT(cnt) { \
pcm86.virbuf -= (cnt << pcm86.stepbit); \
if (pcm86.virbuf < 0) { \
pcm86.virbuf &= pcm86.stepmask; \
} \
}
typedef struct {
SINT32 divremain;
SINT32 div;
SINT32 div2;
SINT32 smp;
SINT32 lastsmp;
SINT32 smp_l;
SINT32 lastsmp_l;
SINT32 smp_r;
SINT32 lastsmp_r;
UINT32 readpos; // DSOUND再生位置
UINT32 wrtpos; // 書込み位置
SINT32 realbuf; // DSOUND用のデータ数
SINT32 virbuf; // 86PCM(bufsize:0x8000)のデータ数
SINT32 rescue;
SINT32 fifosize;
SINT32 volume;
SINT32 vol5;
UINT32 lastclock;
UINT32 stepclock;
UINT stepmask;
UINT8 fifo;
UINT8 extfunc;
UINT8 dactrl;
UINT8 _write;
UINT8 stepbit;
UINT8 reqirq;
UINT8 irqflag;
UINT8 padding[1];
UINT8 buffer[PCM86_BUFSIZE];
} _PCM86, *PCM86;
typedef struct {
UINT rate;
UINT vol;
} PCM86CFG;
#ifdef __cplusplus
extern "C" {
#endif
extern const UINT pcm86rate8[];
void pcm86_cb(NEVENTITEM item);
void pcm86gen_initialize(UINT rate);
void pcm86gen_setvol(UINT vol);
void pcm86_reset(void);
void pcm86gen_update(void);
void pcm86_setpcmrate(REG8 val);
void pcm86_setnextintr(void);
void SOUNDCALL pcm86gen_checkbuf(void);
void SOUNDCALL pcm86gen_getpcm(void *hdl, SINT32 *pcm, UINT count);
BOOL pcm86gen_intrq(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,170 @@
#include "compiler.h"
#include "cpucore.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
// サンプリングレートに8掛けた物
const UINT pcm86rate8[] = {352800, 264600, 176400, 132300,
88200, 66150, 44010, 33075};
// 32,24,16,12, 8, 6, 4, 3 - 最少公倍数: 96
// 3, 4, 6, 8,12,16,24,32
static const UINT clk25_128[] = {
0x00001bde, 0x00002527, 0x000037bb, 0x00004a4e,
0x00006f75, 0x0000949c, 0x0000df5f, 0x00012938};
static const UINT clk20_128[] = {
0x000016a4, 0x00001e30, 0x00002d48, 0x00003c60,
0x00005a8f, 0x000078bf, 0x0000b57d, 0x0000f17d};
PCM86CFG pcm86cfg;
void pcm86gen_initialize(UINT rate) {
pcm86cfg.rate = rate;
}
void pcm86gen_setvol(UINT vol) {
pcm86cfg.vol = vol;
pcm86gen_update();
}
void pcm86_reset(void) {
ZeroMemory(&pcm86, sizeof(pcm86));
pcm86.fifosize = 0x80;
pcm86.dactrl = 0x32;
pcm86.stepmask = (1 << 2) - 1;
pcm86.stepbit = 2;
pcm86.stepclock = (pccore.baseclock << 6);
pcm86.stepclock /= 44100;
pcm86.stepclock *= pccore.multiple;
pcm86.rescue = (PCM86_RESCUE * 32) << 2;
}
void pcm86gen_update(void) {
pcm86.volume = pcm86cfg.vol * pcm86.vol5;
pcm86_setpcmrate(pcm86.fifo);
}
void pcm86_setpcmrate(REG8 val) {
SINT32 rate;
rate = pcm86rate8[val & 7];
pcm86.stepclock = (pccore.baseclock << 6);
pcm86.stepclock /= rate;
pcm86.stepclock *= (pccore.multiple << 3);
if (pcm86cfg.rate) {
pcm86.div = (rate << (PCM86_DIVBIT - 3)) / pcm86cfg.rate;
pcm86.div2 = (pcm86cfg.rate << (PCM86_DIVBIT + 3)) / rate;
}
}
void pcm86_cb(NEVENTITEM item) {
if (pcm86.reqirq) {
sound_sync();
// RECALC_NOWCLKP;
if (pcm86.virbuf <= pcm86.fifosize) {
pcm86.reqirq = 0;
pcm86.irqflag = 1;
pic_setirq(fmtimer.irq);
}
else {
pcm86_setnextintr();
}
}
(void)item;
}
void pcm86_setnextintr(void) {
SINT32 cnt;
SINT32 clk;
if (pcm86.fifo & 0x80) {
cnt = pcm86.virbuf - pcm86.fifosize;
if (cnt > 0) {
cnt += pcm86.stepmask;
cnt >>= pcm86.stepbit;
// cnt += 4; // ちょっと延滞させる
// ここで clk = pccore.realclock * cnt / 86pcm_rate
// clk = ((pccore.baseclock / 86pcm_rate) * cnt) * pccore.multiple
if (pccore.cpumode & CPUMODE_8MHZ) {
clk = clk20_128[pcm86.fifo & 7];
}
else {
clk = clk25_128[pcm86.fifo & 7];
}
// cntは最大 8000h で 32bitで収まるように…
clk *= cnt;
clk >>= 7;
// clk++; // roundup
clk *= pccore.multiple;
nevent_set(NEVENT_86PCM, clk, pcm86_cb, NEVENT_ABSOLUTE);
}
}
}
void SOUNDCALL pcm86gen_checkbuf(void) {
long bufs;
UINT32 past;
past = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
past <<= 6;
past -= pcm86.lastclock;
if (past >= pcm86.stepclock) {
past = past / pcm86.stepclock;
pcm86.lastclock += (past * pcm86.stepclock);
RECALC_NOWCLKWAIT(past);
}
bufs = pcm86.realbuf - pcm86.virbuf;
if (bufs < 0) { // 処理落ちてる…
bufs &= ~3;
pcm86.virbuf += bufs;
if (pcm86.virbuf <= pcm86.fifosize) {
pcm86.reqirq = 0;
pcm86.irqflag = 1;
pic_setirq(fmtimer.irq);
}
else {
pcm86_setnextintr();
}
}
else {
bufs -= PCM86_EXTBUF;
if (bufs > 0) {
bufs &= ~3;
pcm86.realbuf -= bufs;
pcm86.readpos += bufs;
}
}
}
BOOL pcm86gen_intrq(void) {
if (pcm86.irqflag) {
return(TRUE);
}
if (pcm86.fifo & 0x20) {
sound_sync();
if ((pcm86.reqirq) && (pcm86.virbuf <= pcm86.fifosize)) {
pcm86.reqirq = 0;
pcm86.irqflag = 1;
return(TRUE);
}
}
return(FALSE);
}

View File

@ -0,0 +1,331 @@
#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
#define PCM86GET8(a) \
(a) = (SINT8)pcm86.buffer[pcm86.readpos & PCM86_BUFMSK] << 8; \
pcm86.readpos++;
#define PCM86GET16(a) \
(a) = (SINT8)pcm86.buffer[pcm86.readpos & PCM86_BUFMSK] << 8; \
pcm86.readpos++; \
(a) += pcm86.buffer[pcm86.readpos & PCM86_BUFMSK]; \
pcm86.readpos++;
#define BYVOLUME(s) ((((s) >> 6) * pcm86.volume) >> (PCM86_DIVBIT + 4))
static void pcm86mono16(SINT32 *pcm, UINT count) {
if (pcm86.div < PCM86_DIVENV) { // アップさんぷる
do {
SINT32 smp;
if (pcm86.divremain < 0) {
SINT32 dat;
pcm86.divremain += PCM86_DIVENV;
pcm86.realbuf -= 2;
if (pcm86.realbuf < 0) {
goto pm16_bufempty;
}
PCM86GET16(dat);
pcm86.lastsmp = pcm86.smp;
pcm86.smp = dat;
}
smp = (pcm86.lastsmp * pcm86.divremain) -
(pcm86.smp * (pcm86.divremain - PCM86_DIVENV));
pcm[0] += BYVOLUME(smp);
pcm += 2;
pcm86.divremain -= pcm86.div;
} while(--count);
}
else {
do {
SINT32 smp;
smp = pcm86.smp * (pcm86.divremain * -1);
pcm86.divremain += PCM86_DIVENV;
while(1) {
SINT32 dat;
pcm86.realbuf -= 2;
if (pcm86.realbuf < 0) {
goto pm16_bufempty;
}
PCM86GET16(dat);
pcm86.lastsmp = pcm86.smp;
pcm86.smp = dat;
if (pcm86.divremain > pcm86.div2) {
pcm86.divremain -= pcm86.div2;
smp += pcm86.smp * pcm86.div2;
}
else {
break;
}
}
smp += pcm86.smp * pcm86.divremain;
pcm[0] += BYVOLUME(smp);
pcm += 2;
pcm86.divremain -= pcm86.div2;
} while(--count);
}
return;
pm16_bufempty:
pcm86.realbuf += 2;
pcm86.divremain = 0;
pcm86.smp = 0;
pcm86.lastsmp = 0;
}
static void pcm86stereo16(SINT32 *pcm, UINT count) {
if (pcm86.div < PCM86_DIVENV) { // アップさんぷる
do {
SINT32 smp;
if (pcm86.divremain < 0) {
SINT32 dat;
pcm86.divremain += PCM86_DIVENV;
pcm86.realbuf -= 4;
if (pcm86.realbuf < 0) {
goto ps16_bufempty;
}
PCM86GET16(dat);
pcm86.lastsmp_l = pcm86.smp_l;
pcm86.smp_l = dat;
PCM86GET16(dat);
pcm86.lastsmp_r = pcm86.smp_r;
pcm86.smp_r = dat;
}
smp = (pcm86.lastsmp_l * pcm86.divremain) -
(pcm86.smp_l * (pcm86.divremain - PCM86_DIVENV));
pcm[0] += BYVOLUME(smp);
smp = (pcm86.lastsmp_r * pcm86.divremain) -
(pcm86.smp_r * (pcm86.divremain - PCM86_DIVENV));
pcm[1] += BYVOLUME(smp);
pcm += 2;
pcm86.divremain -= pcm86.div;
} while(--count);
}
else {
do {
SINT32 smp_l;
SINT32 smp_r;
smp_l = pcm86.smp_l * (pcm86.divremain * -1);
smp_r = pcm86.smp_r * (pcm86.divremain * -1);
pcm86.divremain += PCM86_DIVENV;
while(1) {
SINT32 dat;
pcm86.realbuf -= 4;
if (pcm86.realbuf < 4) {
goto ps16_bufempty;
}
PCM86GET16(dat);
pcm86.lastsmp_l = pcm86.smp_l;
pcm86.smp_l = dat;
PCM86GET16(dat);
pcm86.lastsmp_r = pcm86.smp_r;
pcm86.smp_r = dat;
if (pcm86.divremain > pcm86.div2) {
pcm86.divremain -= pcm86.div2;
smp_l += pcm86.smp_l * pcm86.div2;
smp_r += pcm86.smp_r * pcm86.div2;
}
else {
break;
}
}
smp_l += pcm86.smp_l * pcm86.divremain;
smp_r += pcm86.smp_r * pcm86.divremain;
pcm[0] += BYVOLUME(smp_l);
pcm[1] += BYVOLUME(smp_r);
pcm += 2;
pcm86.divremain -= pcm86.div2;
} while(--count);
}
return;
ps16_bufempty:
pcm86.realbuf += 4;
pcm86.divremain = 0;
pcm86.smp_l = 0;
pcm86.smp_r = 0;
pcm86.lastsmp_l = 0;
pcm86.lastsmp_r = 0;
}
static void pcm86mono8(SINT32 *pcm, UINT count) {
if (pcm86.div < PCM86_DIVENV) { // アップさんぷる
do {
SINT32 smp;
if (pcm86.divremain < 0) {
SINT32 dat;
pcm86.divremain += PCM86_DIVENV;
pcm86.realbuf--;
if (pcm86.realbuf < 0) {
goto pm8_bufempty;
}
PCM86GET8(dat);
pcm86.lastsmp = pcm86.smp;
pcm86.smp = dat;
}
smp = (pcm86.lastsmp * pcm86.divremain) -
(pcm86.smp * (pcm86.divremain - PCM86_DIVENV));
pcm[0] += BYVOLUME(smp);
pcm += 2;
pcm86.divremain -= pcm86.div;
} while(--count);
}
else {
do {
SINT32 smp;
smp = pcm86.smp * (pcm86.divremain * -1);
pcm86.divremain += PCM86_DIVENV;
while(1) {
SINT32 dat;
pcm86.realbuf--;
if (pcm86.realbuf < 0) {
goto pm8_bufempty;
}
PCM86GET8(dat);
pcm86.lastsmp = pcm86.smp;
pcm86.smp = dat;
if (pcm86.divremain > pcm86.div2) {
pcm86.divremain -= pcm86.div2;
smp += pcm86.smp * pcm86.div2;
}
else {
break;
}
}
smp += pcm86.smp * pcm86.divremain;
pcm[0] += BYVOLUME(smp);
pcm += 2;
pcm86.divremain -= pcm86.div2;
} while(--count);
}
return;
pm8_bufempty:
pcm86.realbuf += 1;
pcm86.divremain = 0;
pcm86.smp = 0;
pcm86.lastsmp = 0;
}
static void pcm86stereo8(SINT32 *pcm, UINT count) {
if (pcm86.div < PCM86_DIVENV) { // アップさんぷる
do {
SINT32 smp;
if (pcm86.divremain < 0) {
SINT32 dat;
pcm86.divremain += PCM86_DIVENV;
pcm86.realbuf -= 2;
if (pcm86.realbuf < 0) {
goto pm8_bufempty;
}
PCM86GET8(dat);
pcm86.lastsmp_l = pcm86.smp_l;
pcm86.smp_l = dat;
PCM86GET8(dat);
pcm86.lastsmp_r = pcm86.smp_r;
pcm86.smp_r = dat;
}
smp = (pcm86.lastsmp_l * pcm86.divremain) -
(pcm86.smp_l * (pcm86.divremain - PCM86_DIVENV));
pcm[0] += BYVOLUME(smp);
smp = (pcm86.lastsmp_r * pcm86.divremain) -
(pcm86.smp_r * (pcm86.divremain - PCM86_DIVENV));
pcm[1] += BYVOLUME(smp);
pcm += 2;
pcm86.divremain -= pcm86.div;
} while(--count);
}
else {
do {
SINT32 smp_l;
SINT32 smp_r;
smp_l = pcm86.smp_l * (pcm86.divremain * -1);
smp_r = pcm86.smp_r * (pcm86.divremain * -1);
pcm86.divremain += PCM86_DIVENV;
while(1) {
SINT32 dat;
pcm86.realbuf -= 2;
if (pcm86.realbuf < 0) {
goto pm8_bufempty;
}
PCM86GET8(dat);
pcm86.lastsmp_l = pcm86.smp_l;
pcm86.smp_l = dat;
PCM86GET8(dat);
pcm86.lastsmp_r = pcm86.smp_r;
pcm86.smp_r = dat;
if (pcm86.divremain > pcm86.div2) {
pcm86.divremain -= pcm86.div2;
smp_l += pcm86.smp_l * pcm86.div2;
smp_r += pcm86.smp_r * pcm86.div2;
}
else {
break;
}
}
smp_l += pcm86.smp_l * pcm86.divremain;
smp_r += pcm86.smp_r * pcm86.divremain;
pcm[0] += BYVOLUME(smp_l);
pcm[1] += BYVOLUME(smp_r);
pcm += 2;
pcm86.divremain -= pcm86.div2;
} while(--count);
}
return;
pm8_bufempty:
pcm86.realbuf += 2;
pcm86.divremain = 0;
pcm86.smp_l = 0;
pcm86.smp_r = 0;
pcm86.lastsmp_l = 0;
pcm86.lastsmp_r = 0;
}
void SOUNDCALL pcm86gen_getpcm(void *hdl, SINT32 *pcm, UINT count) {
if ((count) && (pcm86.fifo & 0x80) && (pcm86.div)) {
switch(pcm86.dactrl & 0x70) {
case 0x00: // 16bit-none
break;
case 0x10: // 16bit-right
pcm86mono16(pcm + 1, count);
break;
case 0x20: // 16bit-left
pcm86mono16(pcm, count);
break;
case 0x30: // 16bit-stereo
pcm86stereo16(pcm, count);
break;
case 0x40: // 8bit-none
break;
case 0x50: // 8bit-right
pcm86mono8(pcm + 1, count);
break;
case 0x60: // 8bit-left
pcm86mono8(pcm, count);
break;
case 0x70: // 8bit-stereo
pcm86stereo8(pcm, count);
break;
}
pcm86gen_checkbuf();
}
(void)hdl;
}

View File

@ -0,0 +1,81 @@
enum {
PSGFREQPADBIT = 12,
PSGADDEDBIT = 3
};
enum {
PSGENV_INC = 15,
PSGENV_ONESHOT = 16,
PSGENV_LASTON = 32,
PSGENV_ONECYCLE = 64
};
typedef struct {
SINT32 freq;
SINT32 count;
SINT32 *pvol; // !!
UINT16 puchi;
UINT8 pan;
UINT8 padding;
} PSGTONE;
typedef struct {
SINT32 freq;
SINT32 count;
UINT base;
} PSGNOISE;
typedef struct {
UINT8 tune[3][2]; // 0
UINT8 noise; // 6
UINT8 mixer; // 7
UINT8 vol[3]; // 8
UINT8 envtime[2]; // b
UINT8 env; // d
UINT8 io1;
UINT8 io2;
} PSGREG;
typedef struct {
PSGTONE tone[3];
PSGNOISE noise;
PSGREG reg;
UINT16 envcnt;
UINT16 envmax;
UINT8 mixer;
UINT8 envmode;
UINT8 envvol;
SINT8 envvolcnt;
SINT32 evol; // !!
UINT puchicount;
} _PSGGEN, *PSGGEN;
typedef struct {
SINT32 volume[16];
SINT32 voltbl[16];
UINT rate;
UINT32 base;
UINT16 puchidec;
} PSGGENCFG;
#ifdef __cplusplus
extern "C" {
#endif
void psggen_initialize(UINT rate);
void psggen_setvol(UINT vol);
void psggen_reset(PSGGEN psg);
void psggen_restore(PSGGEN psg);
void psggen_setreg(PSGGEN psg, UINT reg, REG8 val);
REG8 psggen_getreg(PSGGEN psg, UINT reg);
void psggen_setpan(PSGGEN psg, UINT ch, REG8 pan);
void SOUNDCALL psggen_getpcm(PSGGEN psg, SINT32 *pcm, UINT count);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,174 @@
#include "compiler.h"
#include <math.h>
#include "sound.h"
#include "psggen.h"
#include "keydisp.h"
PSGGENCFG psggencfg;
static const UINT8 psggen_deftbl[0x10] =
{0, 0, 0, 0, 0, 0, 0, 0xbf, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
static const UINT8 psgenv_pat[16] = {
PSGENV_ONESHOT,
PSGENV_ONESHOT,
PSGENV_ONESHOT,
PSGENV_ONESHOT,
PSGENV_ONESHOT | PSGENV_INC,
PSGENV_ONESHOT | PSGENV_INC,
PSGENV_ONESHOT | PSGENV_INC,
PSGENV_ONESHOT | PSGENV_INC,
PSGENV_ONECYCLE,
PSGENV_ONESHOT,
0,
PSGENV_ONESHOT | PSGENV_LASTON,
PSGENV_ONECYCLE | PSGENV_INC,
PSGENV_ONESHOT | PSGENV_INC | PSGENV_LASTON,
PSGENV_INC,
PSGENV_ONESHOT | PSGENV_INC};
void psggen_initialize(UINT rate) {
double pom;
UINT i;
ZeroMemory(&psggencfg, sizeof(psggencfg));
psggencfg.rate = rate;
pom = (double)0x0c00;
for (i=15; i; i--) {
psggencfg.voltbl[i] = (SINT32)pom;
pom /= 1.41492;
}
psggencfg.puchidec = (UINT16)(rate / 11025) * 2;
if (psggencfg.puchidec == 0) {
psggencfg.puchidec = 1;
}
if (rate) {
psggencfg.base = (5000 * (1 << (32 - PSGFREQPADBIT - PSGADDEDBIT)))
/ (rate / 25);
}
}
void psggen_setvol(UINT vol) {
UINT i;
for (i=1; i<16; i++) {
psggencfg.volume[i] = (psggencfg.voltbl[i] * vol) >>
(6 + PSGADDEDBIT);
}
}
void psggen_reset(PSGGEN psg) {
UINT i;
ZeroMemory(psg, sizeof(_PSGGEN));
for (i=0; i<3; i++) {
psg->tone[i].pvol = psggencfg.volume + 0;
}
for (i=0; i<sizeof(psggen_deftbl); i++) {
psggen_setreg(psg, i, psggen_deftbl[i]);
}
}
void psggen_restore(PSGGEN psg) {
UINT i;
for (i=0; i<0x0e; i++) {
psggen_setreg(psg, i, ((UINT8 *)&psg->reg)[i]);
}
}
void psggen_setreg(PSGGEN psg, UINT reg, REG8 value) {
UINT ch;
UINT freq;
reg = reg & 15;
if (reg < 14) {
sound_sync();
}
((UINT8 *)&psg->reg)[reg] = value;
switch(reg) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
ch = reg >> 1;
freq = LOADINTELWORD(psg->reg.tune[ch]) & 0xfff;
if (freq > 9) {
psg->tone[ch].freq = (psggencfg.base / freq) << PSGFREQPADBIT;
}
else {
psg->tone[ch].freq = 0;
}
break;
case 6:
freq = value & 0x1f;
if (freq == 0) {
freq = 1;
}
psg->noise.freq = psggencfg.base / freq;
psg->noise.freq <<= PSGFREQPADBIT;
break;
case 7:
keydisp_psgmix(psg);
psg->mixer = ~value;
psg->puchicount = psggencfg.puchidec;
// TRACEOUT(("psg %x 7 %d", (long)psg, value));
break;
case 8:
case 9:
case 10:
ch = reg - 8;
keydisp_psgvol(psg, (UINT8)ch);
if (value & 0x10) {
psg->tone[ch].pvol = &psg->evol;
}
else {
psg->tone[ch].pvol = psggencfg.volume + (value & 15);
}
psg->tone[ch].puchi = psggencfg.puchidec;
psg->puchicount = psggencfg.puchidec;
// TRACEOUT(("psg %x %x %d", (long)psg, reg, value));
break;
case 11:
case 12:
freq = LOADINTELWORD(psg->reg.envtime);
freq = psggencfg.rate * freq / 125000;
if (freq == 0) {
freq = 1;
}
psg->envmax = freq;
break;
case 13:
psg->envmode = psgenv_pat[value & 0x0f];
psg->envvolcnt = 16;
psg->envcnt = 1;
break;
}
}
REG8 psggen_getreg(PSGGEN psg, UINT reg) {
return(((UINT8 *)&psg->reg)[reg & 15]);
}
void psggen_setpan(PSGGEN psg, UINT ch, REG8 pan) {
if ((psg) && (ch < 3)) {
psg->tone[ch].pan = pan;
}
}

View File

@ -0,0 +1,125 @@
#include "compiler.h"
#include "parts.h"
#include "sound.h"
#include "psggen.h"
extern PSGGENCFG psggencfg;
void SOUNDCALL psggen_getpcm(PSGGEN psg, SINT32 *pcm, UINT count) {
SINT32 noisevol;
UINT8 mixer;
UINT noisetbl = 0;
PSGTONE *tone;
PSGTONE *toneterm;
SINT32 samp;
// UINT psgvol;
SINT32 vol;
UINT i;
UINT noise;
if ((psg->mixer & 0x3f) == 0) {
count = min(count, psg->puchicount);
psg->puchicount -= count;
}
if (count == 0) {
return;
}
do {
noisevol = 0;
if (psg->envcnt) {
psg->envcnt--;
if (psg->envcnt == 0) {
psg->envvolcnt--;
if (psg->envvolcnt < 0) {
if (psg->envmode & PSGENV_ONESHOT) {
psg->envvol = (psg->envmode & PSGENV_LASTON)?15:0;
}
else {
psg->envvolcnt = 15;
if (!(psg->envmode & PSGENV_ONECYCLE)) {
psg->envmode ^= PSGENV_INC;
}
psg->envcnt = psg->envmax;
psg->envvol = (psg->envvolcnt ^ psg->envmode) & 0x0f;
}
}
else {
psg->envcnt = psg->envmax;
psg->envvol = (psg->envvolcnt ^ psg->envmode) & 0x0f;
}
psg->evol = psggencfg.volume[psg->envvol];
}
}
mixer = psg->mixer;
if (mixer & 0x38) {
for (i=0; i<(1 << PSGADDEDBIT); i++) {
SINT32 countbak;
countbak = psg->noise.count;
psg->noise.count -= psg->noise.freq;
if (psg->noise.count > countbak) {
// psg->noise.base = GETRAND() & (1 << (1 << PSGADDEDBIT));
psg->noise.base = rand_get() & (1 << (1 << PSGADDEDBIT));
}
noisetbl += psg->noise.base;
noisetbl >>= 1;
}
}
tone = psg->tone;
toneterm = tone + 3;
do {
vol = *(tone->pvol);
if (vol) {
samp = 0;
switch(mixer & 9) {
case 0: // no mix
if (tone->puchi) {
tone->puchi--;
samp += vol << PSGADDEDBIT;
}
break;
case 1: // tone only
for (i=0; i<(1 << PSGADDEDBIT); i++) {
tone->count += tone->freq;
samp += vol * ((tone->count>=0)?1:-1);
}
break;
case 8: // noise only
noise = noisetbl;
for (i=0; i<(1 << PSGADDEDBIT); i++) {
samp += vol * ((noise & 1)?1:-1);
noise >>= 1;
}
break;
case 9:
noise = noisetbl;
for (i=0; i<(1 << PSGADDEDBIT); i++) {
tone->count += tone->freq;
if ((tone->count >= 0) || (noise & 1)) {
samp += vol;
}
else {
samp -= vol;
}
noise >>= 1;
}
break;
}
if (!(tone->pan & 1)) {
pcm[0] += samp;
}
if (!(tone->pan & 2)) {
pcm[1] += samp;
}
}
mixer >>= 1;
} while(++tone < toneterm);
pcm += 2;
} while(--count);
}

View File

@ -0,0 +1,27 @@
typedef struct {
PMIXHDR hdr;
PMIXTRK trk[6];
UINT vol;
UINT8 trkvol[8];
} _RHYTHM, *RHYTHM;
#ifdef __cplusplus
extern "C" {
#endif
void rhythm_initialize(UINT rate);
void rhythm_deinitialize(void);
UINT rhythm_getcaps(void);
void rhythm_setvol(UINT vol);
void rhythm_reset(RHYTHM rhy);
void rhythm_bind(RHYTHM rhy);
void rhythm_update(RHYTHM rhy);
void rhythm_setreg(RHYTHM rhy, UINT reg, REG8 val);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,156 @@
#include "compiler.h"
#include <math.h>
#include "pccore.h"
#include "sound.h"
#include "rhythm.h"
static const OEMCHAR file_2608bd[] = OEMTEXT("2608_bd.wav");
static const OEMCHAR file_2608sd[] = OEMTEXT("2608_sd.wav");
static const OEMCHAR file_2608top[] = OEMTEXT("2608_top.wav");
static const OEMCHAR file_2608hh[] = OEMTEXT("2608_hh.wav");
static const OEMCHAR file_2608tom[] = OEMTEXT("2608_tom.wav");
static const OEMCHAR file_2608rim[] = OEMTEXT("2608_rim.wav");
static const OEMCHAR *rhythmfile[6] = {
file_2608bd, file_2608sd, file_2608top,
file_2608hh, file_2608tom, file_2608rim};
typedef struct {
UINT rate;
UINT pcmexist;
PMIXDAT pcm[6];
UINT vol;
UINT voltbl[96];
} RHYTHMCFG;
static RHYTHMCFG rhythmcfg;
void rhythm_initialize(UINT rate) {
UINT i;
ZeroMemory(&rhythmcfg, sizeof(rhythmcfg));
rhythmcfg.rate = rate;
for (i=0; i<96; i++) {
rhythmcfg.voltbl[i] = (UINT)(32768.0 *
pow(2.0, (double)i * (-3.0) / 40.0));
}
}
void rhythm_deinitialize(void) {
UINT i;
SINT16 *ptr;
for (i=0; i<6; i++) {
ptr = rhythmcfg.pcm[i].sample;
rhythmcfg.pcm[i].sample = NULL;
if (ptr) {
_MFREE(ptr);
}
}
}
static void rhythm_load(void) {
int i;
OEMCHAR path[MAX_PATH];
for (i=0; i<6; i++) {
if (rhythmcfg.pcm[i].sample == NULL) {
getbiospath(path, rhythmfile[i], NELEMENTS(path));
pcmmix_regfile(rhythmcfg.pcm + i, path, rhythmcfg.rate);
}
}
}
UINT rhythm_getcaps(void) {
UINT ret;
UINT i;
ret = 0;
for (i=0; i<6; i++) {
if (rhythmcfg.pcm[i].sample) {
ret |= 1 << i;
}
}
return(ret);
}
void rhythm_setvol(UINT vol) {
rhythmcfg.vol = vol;
}
void rhythm_reset(RHYTHM rhy) {
ZeroMemory(rhy, sizeof(_RHYTHM));
}
void rhythm_bind(RHYTHM rhy) {
UINT i;
rhythm_load();
rhy->hdr.enable = 0x3f;
for (i=0; i<6; i++) {
rhy->trk[i].data = rhythmcfg.pcm[i];
}
rhythm_update(rhy);
sound_streamregist(rhy, (SOUNDCB)pcmmix_getpcm);
}
void rhythm_update(RHYTHM rhy) {
UINT i;
for (i=0; i<6; i++) {
rhy->trk[i].volume = (rhythmcfg.voltbl[rhy->vol + rhy->trkvol[i]] *
rhythmcfg.vol) >> 10;
}
}
void rhythm_setreg(RHYTHM rhy, UINT reg, REG8 value) {
PMIXTRK *trk;
REG8 bit;
if (reg == 0x10) {
sound_sync();
trk = rhy->trk;
bit = 0x01;
do {
if (value & bit) {
if (value & 0x80) {
rhy->hdr.playing &= ~((UINT)bit);
}
else if (trk->data.sample) {
trk->pcm = trk->data.sample;
trk->remain = trk->data.samples;
rhy->hdr.playing |= bit;
}
}
trk++;
bit <<= 1;
} while(bit < 0x40);
}
else if (reg == 0x11) {
sound_sync();
rhy->vol = (~value) & 0x3f;
rhythm_update(rhy);
}
else if ((reg >= 0x18) && (reg < 0x1e)) {
sound_sync();
trk = rhy->trk + (reg - 0x18);
trk->flag = ((value & 0x80) >> 7) + ((value & 0x40) >> 5);
value = (~value) & 0x1f;
rhy->trkvol[reg - 0x18] = (UINT8)value;
trk->volume = (rhythmcfg.voltbl[rhy->vol + value] *
rhythmcfg.vol) >> 10;
}
}

View File

@ -0,0 +1,192 @@
//
// PC-98 Sound logging
// for S98amp S98 Input plugin for Winamp Version 1.3.1+ by Mamiya
//
#include "compiler.h"
#if defined(SUPPORT_S98)
#include "dosio.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
#include "s98.h"
#define S98LOG_BUFSIZE (32 * 1024)
typedef struct {
UINT8 magic[3];
UINT8 formatversion;
UINT8 timerinfo[4];
UINT8 timerinfo2[4];
UINT8 compressing[4];
UINT8 offset[4];
UINT8 dumpdata[4];
UINT8 looppoint[4];
UINT8 headerreserved[0x24];
UINT8 title[0x40];
} S98HDR;
static struct {
FILEH fh;
UINT32 intcount;
SINT32 clock;
UINT p;
UINT8 buf[S98LOG_BUFSIZE];
} s98log;
static void s98timer(NEVENTITEM item);
static void sets98event(BOOL absolute) {
s98log.intcount++;
nevent_set(NEVENT_S98TIMER, s98log.clock, s98timer, NEVENT_RELATIVE);
(void)absolute;
}
static void s98timer(NEVENTITEM item) {
if (s98log.fh != FILEH_INVALID) {
sets98event(NEVENT_RELATIVE);
}
(void)item;
}
static void S98_flush(void) {
if (s98log.p) {
file_write(s98log.fh, s98log.buf, s98log.p);
s98log.p = 0;
}
}
static void S98_putc(REG8 data) {
s98log.buf[s98log.p++] = data;
if (s98log.p == S98LOG_BUFSIZE) {
S98_flush();
}
}
static void S98_putint(void) {
if (s98log.intcount) {
if (s98log.intcount == 1) {
S98_putc(0xFF); /* SYNC(1) */
}
else if (s98log.intcount == 2) {
S98_putc(0xFF); /* SYNC(1) */
S98_putc(0xFF); /* SYNC(1) */
}
else {
S98_putc(0xFE); /* SYNC(n) */
s98log.intcount -= 2;
while (s98log.intcount > 0x7f) {
S98_putc((REG8)(0x80 | (s98log.intcount & 0x7f)));
s98log.intcount >>= 7;
}
S98_putc((REG8)(s98log.intcount & 0x7f));
}
s98log.intcount = 0;
}
}
// ----
void S98_init(void) {
s98log.fh = FILEH_INVALID;
}
void S98_trash(void) {
S98_close();
}
BRESULT S98_open(const OEMCHAR *filename) {
UINT i;
S98HDR hdr;
// ファイルのオープン
s98log.fh = file_create(filename);
if (s98log.fh == FILEH_INVALID) {
return(FAILURE);
}
// 初期化
s98log.clock = pccore.realclock / 1000;
s98log.p = 0;
// ヘッダの保存
ZeroMemory(&hdr, sizeof(hdr));
hdr.magic[0] = 'S';
hdr.magic[1] = '9';
hdr.magic[2] = '8';
hdr.formatversion = '1';
STOREINTELDWORD(hdr.timerinfo, 1);
STOREINTELDWORD(hdr.offset, offsetof(S98HDR, title));
STOREINTELDWORD(hdr.dumpdata, sizeof(S98HDR));
for (i=0; i<sizeof(hdr); i++) {
S98_putc(*(((UINT8 *)&hdr) + i));
}
#if 1
// FM
for (i=0x30; i<0xb6; i++) {
if ((i & 3) != 3) {
S98_putc(NORMAL2608);
S98_putc((REG8)i);
S98_putc(opn.reg[i]);
S98_putc(EXTEND2608);
S98_putc((REG8)i);
S98_putc(opn.reg[i+0x100]);
}
}
// PSG
for (i=0x00; i<0x0e; i++) {
S98_putc(NORMAL2608);
S98_putc((REG8)i);
S98_putc(((UINT8 *)&psg1.reg)[i]);
}
#endif
// 一応パディング
s98log.intcount = 10;
sets98event(NEVENT_ABSOLUTE);
return(SUCCESS);
}
void S98_close(void) {
if (s98log.fh != FILEH_INVALID) {
S98_putint();
S98_putc(0xFD); /* END MARK */
S98_flush();
nevent_reset(NEVENT_S98TIMER);
file_close(s98log.fh);
s98log.fh = FILEH_INVALID;
}
}
void S98_put(REG8 module, UINT addr, REG8 data) {
if (s98log.fh != FILEH_INVALID) {
S98_putint();
S98_putc(module);
S98_putc((UINT8)addr);
S98_putc(data);
}
}
void S98_sync(void) {
}
#endif

View File

@ -0,0 +1,35 @@
enum {
NORMAL2608 = 0,
EXTEND2608 = 1
};
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(SUPPORT_S98) // コールすら面倒だ!
#define S98_init()
#define S98_trash()
#define S98_open(f) (FAILURE)
#define S98_close()
#define S98_put(m, a, d)
#define S98_sync()
#else
void S98_init(void);
void S98_trash(void);
BRESULT S98_open(const OEMCHAR *filename);
void S98_close(void);
void S98_put(REG8 module, UINT addr, REG8 data);
void S98_sync(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,23 @@
#include "compiler.h"
#include "sound.h"
#include "sndcsec.h"
#if defined(SOUND_CRITICAL)
#if defined(WIN32) || defined(_WIN32_WCE)
CRITICAL_SECTION sndcsec;
#elif defined(MACOS)
MPCriticalRegionID sndcsec;
#elif defined(X11) || defined(SLZAURUS)
pthread_mutex_t sndcsec; // = PTHREAD_MUTEX_INITIALIZER;
#endif
#endif

View File

@ -0,0 +1,49 @@
#if !defined(SOUND_CRITICAL)
#define SNDCSEC_INIT
#define SNDCSEC_TERM
#define SNDCSEC_ENTER
#define SNDCSEC_LEAVE
#else
#ifdef __cplusplus
extern "C" {
#endif
#if defined(WIN32) || defined(_WIN32_WCE)
extern CRITICAL_SECTION sndcsec;
#define SNDCSEC_INIT InitializeCriticalSection(&sndcsec)
#define SNDCSEC_TERM DeleteCriticalSection(&sndcsec)
#define SNDCSEC_ENTER EnterCriticalSection(&sndcsec)
#define SNDCSEC_LEAVE LeaveCriticalSection(&sndcsec)
#elif defined(MACOS)
extern MPCriticalRegionID sndcsec;
#define SNDCSEC_INIT MPCreateCriticalRegion(&sndcsec)
#define SNDCSEC_TERM MPDeleteCriticalRegion(sndcsec)
#define SNDCSEC_ENTER MPEnterCriticalRegion(sndcsec, kDurationForever)
#define SNDCSEC_LEAVE MPExitCriticalRegion(sndcsec)
#elif defined(X11) || defined(SLZAURUS)
extern pthread_mutex_t sndcsec;
#define SNDCSEC_INIT pthread_mutex_init(&sndcsec, NULL)
#define SNDCSEC_TERM pthread_mutex_destroy(&sndcsec)
#define SNDCSEC_ENTER pthread_mutex_lock(&sndcsec)
#define SNDCSEC_LEAVE pthread_mutex_unlock(&sndcsec)
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,529 @@
#include "compiler.h"
#include "wavefile.h"
#include "dosio.h"
#include "soundmng.h"
#include "cpucore.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "sndcsec.h"
#include "beep.h"
#include "getsnd.h"
SOUNDCFG soundcfg;
#define STREAM_CBMAX 16
typedef struct {
void *hdl;
SOUNDCB cbfn;
} CBTBL;
typedef struct {
SINT32 *buffer;
SINT32 *ptr;
UINT samples;
UINT reserve;
UINT remain;
#if defined(SUPPORT_WAVEREC)
WAVEWR rec;
#endif
CBTBL *cbreg;
CBTBL cb[STREAM_CBMAX];
} SNDSTREAM;
static SNDSTREAM sndstream;
static void streamreset(void) {
SNDCSEC_ENTER;
sndstream.ptr = sndstream.buffer;
sndstream.remain = sndstream.samples + sndstream.reserve;
sndstream.cbreg = sndstream.cb;
SNDCSEC_LEAVE;
}
static void streamprepare(UINT samples) {
CBTBL *cb;
UINT count;
count = min(sndstream.remain, samples);
if (count) {
ZeroMemory(sndstream.ptr, count * 2 * sizeof(SINT32));
cb = sndstream.cb;
while(cb < sndstream.cbreg) {
cb->cbfn(cb->hdl, sndstream.ptr, count);
cb++;
}
sndstream.ptr += count * 2;
sndstream.remain -= count;
}
}
#if defined(SUPPORT_WAVEREC)
// ---- wave rec
BOOL sound_recstart(const OEMCHAR *filename) {
WAVEWR rec;
sound_recstop();
if (sndstream.buffer == NULL) {
return(FAILURE);
}
rec = wavewr_open(filename, soundcfg.rate, 16, 2);
sndstream.rec = rec;
if (rec) {
return(SUCCESS);
}
return(FAILURE);
}
void sound_recstop(void) {
WAVEWR rec;
rec = sndstream.rec;
sndstream.rec = NULL;
wavewr_close(rec);
}
static void streamfilewrite(UINT samples) {
CBTBL *cb;
UINT count;
SINT32 buf32[2*512];
UINT8 buf[2*2*512];
UINT r;
UINT i;
SINT32 samp;
while(samples) {
count = min(samples, 512);
ZeroMemory(buf32, count * 2 * sizeof(SINT32));
cb = sndstream.cb;
while(cb < sndstream.cbreg) {
cb->cbfn(cb->hdl, buf32, count);
cb++;
}
r = min(sndstream.remain, count);
if (r) {
CopyMemory(sndstream.ptr, buf32, r * 2 * sizeof(SINT32));
sndstream.ptr += r * 2;
sndstream.remain -= r;
}
for (i=0; i<count*2; i++) {
samp = buf32[i];
if (samp > 32767) {
samp = 32767;
}
else if (samp < -32768) {
samp = -32768;
}
// little endianなので satuation_s16は使えない
buf[i*2+0] = (UINT8)samp;
buf[i*2+1] = (UINT8)(samp >> 8);
}
wavewr_write(sndstream.rec, buf, count * 4);
samples -= count;
}
}
static void filltailsample(UINT count) {
SINT32 *ptr;
UINT orgsize;
SINT32 sampl;
SINT32 sampr;
count = min(sndstream.remain, count);
if (count) {
ptr = sndstream.ptr;
orgsize = (ptr - sndstream.buffer) / 2;
if (orgsize == 0) {
sampl = 0;
sampr = 0;
}
else {
sampl = *(ptr - 2);
sampr = *(ptr - 1);
}
sndstream.ptr += count * 2;
sndstream.remain -= count;
do {
ptr[0] = sampl;
ptr[1] = sampr;
ptr += 2;
} while(--count);
}
}
#endif
// ----
BOOL sound_create(UINT rate, UINT ms) {
UINT samples;
UINT reserve;
ZeroMemory(&sndstream, sizeof(sndstream));
switch(rate) {
case 11025:
case 22050:
case 44100:
break;
default:
return(FAILURE);
}
samples = soundmng_create(rate, ms);
if (samples == 0) {
goto scre_err1;
}
soundmng_reset();
soundcfg.rate = rate;
sound_changeclock();
#if defined(SOUNDRESERVE)
reserve = rate * SOUNDRESERVE / 1000;
#else
reserve = 0;
#endif
sndstream.buffer = (SINT32 *)_MALLOC((samples + reserve) * 2
* sizeof(SINT32), "stream");
if (sndstream.buffer == NULL) {
goto scre_err2;
}
sndstream.samples = samples;
sndstream.reserve = reserve;
SNDCSEC_INIT;
streamreset();
return(SUCCESS);
scre_err2:
soundmng_destroy();
scre_err1:
return(FAILURE);
}
void sound_destroy(void) {
if (sndstream.buffer) {
#if defined(SUPPORT_WAVEREC)
sound_recstop();
#endif
soundmng_stop();
streamreset();
soundmng_destroy();
SNDCSEC_TERM;
_MFREE(sndstream.buffer);
sndstream.buffer = NULL;
}
}
void sound_reset(void) {
if (sndstream.buffer) {
soundmng_reset();
streamreset();
soundcfg.lastclock = CPU_CLOCK;
beep_eventreset();
}
}
void sound_changeclock(void) {
UINT32 clk;
UINT hz;
UINT hzmax;
if (sndstream.buffer == NULL) {
return;
}
// とりあえず 25で割り切れる。
clk = pccore.realclock / 25;
hz = soundcfg.rate / 25;
// で、クロック数に合せて調整。(64bit演算しろよな的)
hzmax = (1 << (32 - 8)) / (clk >> 8);
while(hzmax < hz) {
clk = (clk + 1) >> 1;
hz = (hz + 1) >> 1;
}
TRACEOUT(("hzbase/clockbase = %d/%d", hz, clk));
soundcfg.hzbase = hz;
soundcfg.clockbase = clk;
soundcfg.minclock = 2 * clk / hz;
soundcfg.lastclock = CPU_CLOCK;
}
void sound_streamregist(void *hdl, SOUNDCB cbfn) {
if (sndstream.buffer) {
if ((cbfn) &&
(sndstream.cbreg < (sndstream.cb + STREAM_CBMAX))) {
sndstream.cbreg->hdl = hdl;
sndstream.cbreg->cbfn = cbfn;
sndstream.cbreg++;
}
}
}
// ----
void sound_sync(void) {
UINT32 length;
if (sndstream.buffer == NULL) {
return;
}
length = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK - soundcfg.lastclock;
if (length < soundcfg.minclock) {
return;
}
length = (length * soundcfg.hzbase) / soundcfg.clockbase;
if (length == 0) {
return;
}
SNDCSEC_ENTER;
#if defined(SUPPORT_WAVEREC)
if (sndstream.rec) {
streamfilewrite(length);
}
else
#endif
streamprepare(length);
soundcfg.lastclock += length * soundcfg.clockbase / soundcfg.hzbase;
beep_eventreset();
SNDCSEC_LEAVE;
soundcfg.writecount += length;
if (soundcfg.writecount >= 100) {
soundcfg.writecount = 0;
soundmng_sync();
}
}
static volatile int locks = 0;
const SINT32 *sound_pcmlock(void) {
const SINT32 *ret;
if (locks) {
TRACEOUT(("sound pcm lock: already locked"));
return(NULL);
}
locks++;
ret = sndstream.buffer;
if (ret) {
SNDCSEC_ENTER;
if (sndstream.remain > sndstream.reserve)
#if defined(SUPPORT_WAVEREC)
if (sndstream.rec) {
filltailsample(sndstream.remain - sndstream.reserve);
}
else
#endif
{
streamprepare(sndstream.remain - sndstream.reserve);
soundcfg.lastclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
beep_eventreset();
}
}
else {
locks--;
}
return(ret);
}
void sound_pcmunlock(const SINT32 *hdl) {
int leng;
if (hdl) {
leng = sndstream.reserve - sndstream.remain;
if (leng > 0) {
CopyMemory(sndstream.buffer,
sndstream.buffer + (sndstream.samples * 2),
leng * 2 * sizeof(SINT32));
}
sndstream.ptr = sndstream.buffer + (leng * 2);
sndstream.remain = sndstream.samples + sndstream.reserve - leng;
// sndstream.remain += sndstream.samples;
SNDCSEC_LEAVE;
locks--;
}
}
// ---- pcmmix
BRESULT pcmmix_regist(PMIXDAT *dat, void *datptr, UINT datsize, UINT rate) {
GETSND gs;
UINT8 tmp[256];
UINT size;
UINT r;
SINT16 *buf;
gs = getsnd_create(datptr, datsize);
if (gs == NULL) {
goto pmr_err1;
}
if (getsnd_setmixproc(gs, rate, 1) != SUCCESS) {
goto pmr_err2;
}
size = 0;
do {
r = getsnd_getpcmbyleng(gs, tmp, sizeof(tmp));
size += r;
} while(r);
getsnd_destroy(gs);
if (size == 0) {
goto pmr_err1;
}
buf = (SINT16 *)_MALLOC(size, "PCM DATA");
if (buf == NULL) {
goto pmr_err1;
}
gs = getsnd_create(datptr, datsize);
if (gs == NULL) {
goto pmr_err1;
}
if (getsnd_setmixproc(gs, rate, 1) != SUCCESS) {
goto pmr_err2;
}
r = getsnd_getpcmbyleng(gs, buf, size);
getsnd_destroy(gs);
dat->sample = buf;
dat->samples = r / 2;
return(SUCCESS);
pmr_err2:
getsnd_destroy(gs);
pmr_err1:
return(FAILURE);
}
BRESULT pcmmix_regfile(PMIXDAT *dat, const OEMCHAR *fname, UINT rate) {
FILEH fh;
UINT size;
UINT8 *ptr;
BRESULT r;
r = FAILURE;
fh = file_open_rb(fname);
if (fh == FILEH_INVALID) {
goto pmrf_err1;
}
size = file_getsize(fh);
if (size == 0) {
goto pmrf_err2;
}
ptr = (UINT8 *)_MALLOC(size, fname);
if (ptr == NULL) {
goto pmrf_err2;
}
file_read(fh, ptr, size);
file_close(fh);
r = pcmmix_regist(dat, ptr, size, rate);
_MFREE(ptr);
return(r);
pmrf_err2:
file_close(fh);
pmrf_err1:
return(FAILURE);
}
void SOUNDCALL pcmmix_getpcm(PCMMIX hdl, SINT32 *pcm, UINT count) {
UINT32 bitmap;
PMIXTRK *t;
const SINT16 *s;
UINT srem;
SINT32 *d;
UINT drem;
UINT r;
UINT j;
UINT flag;
SINT32 vol;
SINT32 samp;
if ((hdl->hdr.playing == 0) || (count == 0)) {
return;
}
t = hdl->trk;
bitmap = 1;
do {
if (hdl->hdr.playing & bitmap) {
s = t->pcm;
srem = t->remain;
d = pcm;
drem = count;
flag = t->flag;
vol = t->volume;
do {
r = min(srem, drem);
switch(flag & (PMIXFLAG_L | PMIXFLAG_R)) {
case PMIXFLAG_L:
for (j=0; j<r; j++) {
d[j*2+0] += (s[j] * vol) >> 12;
}
break;
case PMIXFLAG_R:
for (j=0; j<r; j++) {
d[j*2+1] += (s[j] * vol) >> 12;
}
break;
case PMIXFLAG_L | PMIXFLAG_R:
for (j=0; j<r; j++) {
samp = (s[j] * vol) >> 12;
d[j*2+0] += samp;
d[j*2+1] += samp;
}
break;
}
s += r;
d += r*2;
srem -= r;
if (srem == 0) {
if (flag & PMIXFLAG_LOOP) {
s = t->data.sample;
srem = t->data.samples;
}
else {
hdl->hdr.playing &= ~bitmap;
break;
}
}
drem -= r;
} while(drem);
t->pcm = s;
t->remain = srem;
}
t++;
bitmap <<= 1;
} while(bitmap < hdl->hdr.enable);
}

View File

@ -0,0 +1,103 @@
#ifndef SOUNDCALL
#define SOUNDCALL
#endif
#if !defined(DISABLE_SOUND)
typedef void (SOUNDCALL * SOUNDCB)(void *hdl, SINT32 *pcm, UINT count);
typedef struct {
UINT rate;
UINT32 hzbase;
UINT32 clockbase;
UINT32 minclock;
UINT32 lastclock;
UINT writecount;
} SOUNDCFG;
#ifdef __cplusplus
extern "C" {
#endif
extern SOUNDCFG soundcfg;
BOOL sound_create(UINT rate, UINT ms);
void sound_destroy(void);
void sound_reset(void);
void sound_changeclock(void);
void sound_streamregist(void *hdl, SOUNDCB cbfn);
void sound_sync(void);
const SINT32 *sound_pcmlock(void);
void sound_pcmunlock(const SINT32 *hdl);
#if defined(SUPPORT_WAVEREC)
BOOL sound_recstart(const OEMCHAR *filename);
void sound_recstop(void);
#endif
#ifdef __cplusplus
}
#endif
// ---- PCM MIX
enum {
PMIXFLAG_L = 0x0001,
PMIXFLAG_R = 0x0002,
PMIXFLAG_LOOP = 0x0004
};
typedef struct {
UINT32 playing;
UINT32 enable;
} PMIXHDR;
typedef struct {
SINT16 *sample;
UINT samples;
} PMIXDAT;
typedef struct {
const SINT16 *pcm;
UINT remain;
PMIXDAT data;
UINT flag;
SINT32 volume;
} PMIXTRK;
typedef struct {
PMIXHDR hdr;
PMIXTRK trk[1];
} _PCMMIX, *PCMMIX;
#ifdef __cplusplus
extern "C" {
#endif
BRESULT pcmmix_regist(PMIXDAT *dat, void *datptr, UINT datsize, UINT rate);
BRESULT pcmmix_regfile(PMIXDAT *dat, const OEMCHAR *fname, UINT rate);
void SOUNDCALL pcmmix_getpcm(PCMMIX hdl, SINT32 *pcm, UINT count);
#ifdef __cplusplus
}
#endif
#else
#define sound_pcmlock() (NULL)
#define sound_pcmunlock(h)
#define sound_reset()
#define sound_changeclock()
#define sound_sync()
#endif

View File

@ -0,0 +1,85 @@
#include "compiler.h"
#include "dosio.h"
#include "cpucore.h"
#include "pccore.h"
#include "soundrom.h"
SOUNDROM soundrom;
static const OEMCHAR file_sound[] = OEMTEXT("sound");
static const OEMCHAR file_extrom[] = OEMTEXT(".rom");
static const UINT8 defsoundrom[9] = {
0x01,0x00,0x00,0x00,0xd2,0x00,0x08,0x00,0xcb};
static BRESULT loadsoundrom(UINT address, const OEMCHAR *name) {
OEMCHAR romname[24];
OEMCHAR path[MAX_PATH];
FILEH fh;
UINT rsize;
file_cpyname(romname, file_sound, NELEMENTS(romname));
if (name) {
file_catname(romname, name, NELEMENTS(romname));
}
file_catname(romname, file_extrom, NELEMENTS(romname));
getbiospath(path, romname, NELEMENTS(path));
fh = file_open_rb(path);
if (fh == FILEH_INVALID) {
goto lsr_err;
}
rsize = file_read(fh, mem + address, 0x4000);
file_close(fh);
if (rsize != 0x4000) {
goto lsr_err;
}
file_cpyname(soundrom.name, romname, NELEMENTS(soundrom.name));
soundrom.address = address;
if (address == 0xd0000) {
CPU_RAM_D000 &= ~(0x0f << 0);
}
else if (address == 0xd4000) {
CPU_RAM_D000 &= ~(0x0f << 4);
}
return(SUCCESS);
lsr_err:
return(FAILURE);
}
// ----
void soundrom_reset(void) {
ZeroMemory(&soundrom, sizeof(soundrom));
}
void soundrom_load(UINT32 address, const OEMCHAR *primary) {
if (primary != NULL) {
if (loadsoundrom(address, primary) == SUCCESS) {
return;
}
}
if (loadsoundrom(address, NULL) == SUCCESS) {
return;
}
CopyMemory(mem + address + 0x2e00, defsoundrom, sizeof(defsoundrom));
soundrom.name[0] = '\0';
soundrom.address = address;
}
void soundrom_loadex(UINT sw, const OEMCHAR *primary) {
if (sw < 4) {
soundrom_load((0xc8000 + ((UINT32)sw << 14)), primary);
}
else {
ZeroMemory(&soundrom, sizeof(soundrom));
}
}

View File

@ -0,0 +1,21 @@
typedef struct {
OEMCHAR name[24];
UINT32 address;
} SOUNDROM;
#ifdef __cplusplus
extern "C" {
#endif
extern SOUNDROM soundrom;
void soundrom_reset(void);
void soundrom_load(UINT32 address, const OEMCHAR *primary);
void soundrom_loadex(UINT sw, const OEMCHAR *primary);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,36 @@
typedef struct {
UINT32 freq;
UINT32 count;
} TMSCH;
typedef struct {
TMSCH ch[8];
UINT enable;
} _TMS3631, *TMS3631;
typedef struct {
UINT ratesft;
SINT32 left;
SINT32 right;
SINT32 feet[16];
} TMS3631CFG;
#ifdef __cplusplus
extern "C" {
#endif
void tms3631_initialize(UINT rate);
void tms3631_setvol(const UINT8 *vol);
void tms3631_reset(TMS3631 tms);
void tms3631_setkey(TMS3631 tms, REG8 ch, REG8 key);
void tms3631_setenable(TMS3631 tms, REG8 enable);
void SOUNDCALL tms3631_getpcm(TMS3631 tms, SINT32 *pcm, UINT count);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,72 @@
#include "compiler.h"
#include "sound.h"
#include "tms3631.h"
TMS3631CFG tms3631cfg;
static const UINT16 tms3631_freqtbl[] = {
0, 0x051B, 0x0569, 0x05BB, 0x0613, 0x066F, 0x06D1,
0x0739, 0x07A7, 0x081B, 0x0897, 0x091A, 0x09A4, 0,0,0,
0, 0x0A37, 0x0AD3, 0x0B77, 0x0C26, 0x0CDF, 0x0DA3,
0x0E72, 0x0F4E, 0x1037, 0x112E, 0x1234, 0x1349, 0,0,0,
0, 0x146E, 0x15A6, 0x16EF, 0x184C, 0x19BE, 0x1B46,
0x1CE5, 0x1E9D, 0x206F, 0x225D, 0x2468, 0x2692, 0,0,0,
0, 0x28DD, 0x2B4C, 0x2DDF, 0x3099, 0x337D, 0x368D,
0x39CB, 0x3D3B, 0x40DF, 0x44BA, 0x48D1, 0x4D25, 0x51BB, 0,0};
void tms3631_initialize(UINT rate) {
UINT sft;
ZeroMemory(&tms3631cfg, sizeof(tms3631cfg));
sft = 0;
if (rate == 11025) {
sft = 0;
}
else if (rate == 22050) {
sft = 1;
}
else if (rate == 44100) {
sft = 2;
}
tms3631cfg.ratesft = sft;
}
void tms3631_setvol(const UINT8 *vol) {
UINT i;
UINT j;
SINT32 data;
tms3631cfg.left = (vol[0] & 15) << 5;
tms3631cfg.right = (vol[1] & 15) << 5;
vol += 2;
for (i=0; i<16; i++) {
data = 0;
for (j=0; j<4; j++) {
data += (vol[j] & 15) * ((i & (1 << j))?1:-1);
}
tms3631cfg.feet[i] = data << 5;
}
}
// ----
void tms3631_reset(TMS3631 tms) {
ZeroMemory(tms, sizeof(_TMS3631));
}
void tms3631_setkey(TMS3631 tms, REG8 ch, REG8 key) {
tms->ch[ch & 7].freq = tms3631_freqtbl[key & 0x3f] >> tms3631cfg.ratesft;
}
void tms3631_setenable(TMS3631 tms, REG8 enable) {
tms->enable = enable;
}

View File

@ -0,0 +1,50 @@
#include "compiler.h"
#include "sound.h"
#include "tms3631.h"
extern TMS3631CFG tms3631cfg;
void SOUNDCALL tms3631_getpcm(TMS3631 tms, SINT32 *pcm, UINT count) {
UINT ch;
SINT32 data;
UINT i;
if (tms->enable == 0) {
return;
}
while(count--) {
ch = 0;
data = 0;
do { // centre
if ((tms->enable & (1 << ch)) && (tms->ch[ch].freq)) {
for (i=0; i<4; i++) {
tms->ch[ch].count += tms->ch[ch].freq;
data += (tms->ch[ch].count & 0x10000)?1:-1;
}
}
} while(++ch < 2);
pcm[0] += data * tms3631cfg.left;
pcm[1] += data * tms3631cfg.right;
do { // left
if ((tms->enable & (1 << ch)) && (tms->ch[ch].freq)) {
for (i=0; i<4; i++) {
tms->ch[ch].count += tms->ch[ch].freq;
pcm[0] += tms3631cfg.feet[(tms->ch[ch].count >> 16) & 15];
}
}
} while(++ch < 5);
do { // right
if ((tms->enable & (1 << ch)) && (tms->ch[ch].freq)) {
for (i=0; i<4; i++) {
tms->ch[ch].count += tms->ch[ch].freq;
pcm[1] += tms3631cfg.feet[(tms->ch[ch].count >> 16) & 15];
}
}
} while(++ch < 8);
pcm += 2;
}
}