mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-09 03:41:10 +08:00
Begin re-porting FM code from NP2
This commit is contained in:
parent
6e879a8562
commit
d3732007e3
@ -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);
|
||||
|
||||
// TEhI/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
193
src/hardware/sound_pc98/cbus/board118.c
Normal file
193
src/hardware/sound_pc98/cbus/board118.c
Normal 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);
|
||||
}
|
||||
|
12
src/hardware/sound_pc98/cbus/board118.h
Normal file
12
src/hardware/sound_pc98/cbus/board118.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void board118_reset(const NP2CFG *pConfig);
|
||||
void board118_bind(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
212
src/hardware/sound_pc98/cbus/board14.c
Normal file
212
src/hardware/sound_pc98/cbus/board14.c
Normal 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]);
|
||||
}
|
||||
}
|
||||
|
17
src/hardware/sound_pc98/cbus/board14.h
Normal file
17
src/hardware/sound_pc98/cbus/board14.h
Normal 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
|
||||
|
99
src/hardware/sound_pc98/cbus/board26k.c
Normal file
99
src/hardware/sound_pc98/cbus/board26k.c
Normal 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);
|
||||
}
|
||||
|
12
src/hardware/sound_pc98/cbus/board26k.h
Normal file
12
src/hardware/sound_pc98/cbus/board26k.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void board26k_reset(const NP2CFG *pConfig);
|
||||
void board26k_bind(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
271
src/hardware/sound_pc98/cbus/board86.c
Normal file
271
src/hardware/sound_pc98/cbus/board86.c
Normal 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);
|
||||
}
|
||||
|
14
src/hardware/sound_pc98/cbus/board86.h
Normal file
14
src/hardware/sound_pc98/cbus/board86.h
Normal 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
|
||||
|
741
src/hardware/sound_pc98/cbus/boardpx.c
Normal file
741
src/hardware/sound_pc98/cbus/boardpx.c
Normal 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)
|
||||
|
19
src/hardware/sound_pc98/cbus/boardpx.h
Normal file
19
src/hardware/sound_pc98/cbus/boardpx.h
Normal 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)
|
||||
|
309
src/hardware/sound_pc98/cbus/boardspb.c
Normal file
309
src/hardware/sound_pc98/cbus/boardspb.c
Normal 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);
|
||||
}
|
||||
|
15
src/hardware/sound_pc98/cbus/boardspb.h
Normal file
15
src/hardware/sound_pc98/cbus/boardspb.h
Normal 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
|
||||
|
271
src/hardware/sound_pc98/cbus/boardx2.c
Normal file
271
src/hardware/sound_pc98/cbus/boardx2.c
Normal 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);
|
||||
}
|
||||
|
12
src/hardware/sound_pc98/cbus/boardx2.h
Normal file
12
src/hardware/sound_pc98/cbus/boardx2.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void boardx2_reset(const NP2CFG *pConfig);
|
||||
void boardx2_bind(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
256
src/hardware/sound_pc98/cbus/pcm86io.c
Normal file
256
src/hardware/sound_pc98/cbus/pcm86io.c
Normal 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);
|
||||
}
|
||||
|
12
src/hardware/sound_pc98/cbus/pcm86io.h
Normal file
12
src/hardware/sound_pc98/cbus/pcm86io.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void pcm86io_bind(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
77
src/hardware/sound_pc98/sound/adpcm.h
Normal file
77
src/hardware/sound_pc98/sound/adpcm.h
Normal 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
|
||||
|
122
src/hardware/sound_pc98/sound/adpcmc.c
Normal file
122
src/hardware/sound_pc98/sound/adpcmc.c
Normal 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);
|
||||
}
|
||||
|
292
src/hardware/sound_pc98/sound/adpcmg.c
Normal file
292
src/hardware/sound_pc98/sound/adpcmg.c
Normal 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;
|
||||
}
|
||||
|
74
src/hardware/sound_pc98/sound/beep.h
Normal file
74
src/hardware/sound_pc98/sound/beep.h
Normal 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
|
||||
|
175
src/hardware/sound_pc98/sound/beepc.c
Normal file
175
src/hardware/sound_pc98/sound/beepc.c
Normal 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();
|
||||
}
|
||||
}
|
||||
|
160
src/hardware/sound_pc98/sound/beepg.c
Normal file
160
src/hardware/sound_pc98/sound/beepg.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
358
src/hardware/sound_pc98/sound/fmboard.c
Normal file
358
src/hardware/sound_pc98/sound/fmboard.c
Normal 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)
|
||||
|
103
src/hardware/sound_pc98/sound/fmboard.h
Normal file
103
src/hardware/sound_pc98/sound/fmboard.h
Normal 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
|
||||
|
134
src/hardware/sound_pc98/sound/fmtimer.c
Normal file
134
src/hardware/sound_pc98/sound/fmtimer.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
26
src/hardware/sound_pc98/sound/fmtimer.h
Normal file
26
src/hardware/sound_pc98/sound/fmtimer.h
Normal 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
|
||||
|
113
src/hardware/sound_pc98/sound/getsnd/getmp3.c
Normal file
113
src/hardware/sound_pc98/sound/getsnd/getmp3.c
Normal 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
|
||||
|
264
src/hardware/sound_pc98/sound/getsnd/getogg.c
Normal file
264
src/hardware/sound_pc98/sound/getsnd/getogg.c
Normal 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
|
||||
|
153
src/hardware/sound_pc98/sound/getsnd/getsmix.c
Normal file
153
src/hardware/sound_pc98/sound/getsnd/getsmix.c
Normal 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);
|
||||
}
|
||||
|
102
src/hardware/sound_pc98/sound/getsnd/getsnd.c
Normal file
102
src/hardware/sound_pc98/sound/getsnd/getsnd.c
Normal 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);
|
||||
}
|
||||
|
57
src/hardware/sound_pc98/sound/getsnd/getsnd.h
Normal file
57
src/hardware/sound_pc98/sound/getsnd/getsnd.h
Normal 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
|
||||
|
160
src/hardware/sound_pc98/sound/getsnd/getsndmn.mcr
Normal file
160
src/hardware/sound_pc98/sound/getsnd/getsndmn.mcr
Normal 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
|
||||
|
173
src/hardware/sound_pc98/sound/getsnd/getsndst.mcr
Normal file
173
src/hardware/sound_pc98/sound/getsnd/getsndst.mcr
Normal 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
|
||||
|
576
src/hardware/sound_pc98/sound/getsnd/getwave.c
Normal file
576
src/hardware/sound_pc98/sound/getsnd/getwave.c
Normal 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);
|
||||
}
|
||||
|
184
src/hardware/sound_pc98/sound/opngen.h
Normal file
184
src/hardware/sound_pc98/sound/opngen.h
Normal 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
|
||||
|
626
src/hardware/sound_pc98/sound/opngenc.c
Normal file
626
src/hardware/sound_pc98/sound/opngenc.c
Normal 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);
|
||||
}
|
||||
|
212
src/hardware/sound_pc98/sound/opngeng.c
Normal file
212
src/hardware/sound_pc98/sound/opngeng.c
Normal 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;
|
||||
}
|
||||
|
90
src/hardware/sound_pc98/sound/pcm86.h
Normal file
90
src/hardware/sound_pc98/sound/pcm86.h
Normal 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
|
||||
|
170
src/hardware/sound_pc98/sound/pcm86c.c
Normal file
170
src/hardware/sound_pc98/sound/pcm86c.c
Normal 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);
|
||||
}
|
||||
|
331
src/hardware/sound_pc98/sound/pcm86g.c
Normal file
331
src/hardware/sound_pc98/sound/pcm86g.c
Normal 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;
|
||||
}
|
||||
|
81
src/hardware/sound_pc98/sound/psggen.h
Normal file
81
src/hardware/sound_pc98/sound/psggen.h
Normal 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
|
||||
|
174
src/hardware/sound_pc98/sound/psggenc.c
Normal file
174
src/hardware/sound_pc98/sound/psggenc.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
125
src/hardware/sound_pc98/sound/psggeng.c
Normal file
125
src/hardware/sound_pc98/sound/psggeng.c
Normal 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);
|
||||
}
|
||||
|
27
src/hardware/sound_pc98/sound/rhythm.h
Normal file
27
src/hardware/sound_pc98/sound/rhythm.h
Normal 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
|
||||
|
156
src/hardware/sound_pc98/sound/rhythmc.c
Normal file
156
src/hardware/sound_pc98/sound/rhythmc.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
192
src/hardware/sound_pc98/sound/s98.c
Normal file
192
src/hardware/sound_pc98/sound/s98.c
Normal 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
|
||||
|
35
src/hardware/sound_pc98/sound/s98.h
Normal file
35
src/hardware/sound_pc98/sound/s98.h
Normal 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
|
||||
|
23
src/hardware/sound_pc98/sound/sndcsec.c
Normal file
23
src/hardware/sound_pc98/sound/sndcsec.c
Normal 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
|
||||
|
49
src/hardware/sound_pc98/sound/sndcsec.h
Normal file
49
src/hardware/sound_pc98/sound/sndcsec.h
Normal 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
|
||||
|
529
src/hardware/sound_pc98/sound/sound.c
Normal file
529
src/hardware/sound_pc98/sound/sound.c
Normal 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);
|
||||
}
|
||||
|
103
src/hardware/sound_pc98/sound/sound.h
Normal file
103
src/hardware/sound_pc98/sound/sound.h
Normal 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
|
||||
|
85
src/hardware/sound_pc98/sound/soundrom.c
Normal file
85
src/hardware/sound_pc98/sound/soundrom.c
Normal 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));
|
||||
}
|
||||
}
|
||||
|
21
src/hardware/sound_pc98/sound/soundrom.h
Normal file
21
src/hardware/sound_pc98/sound/soundrom.h
Normal 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
|
||||
|
36
src/hardware/sound_pc98/sound/tms3631.h
Normal file
36
src/hardware/sound_pc98/sound/tms3631.h
Normal 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
|
||||
|
72
src/hardware/sound_pc98/sound/tms3631c.c
Normal file
72
src/hardware/sound_pc98/sound/tms3631c.c
Normal 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;
|
||||
}
|
||||
|
50
src/hardware/sound_pc98/sound/tms3631g.c
Normal file
50
src/hardware/sound_pc98/sound/tms3631g.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user