replace AArt µPD1771C core with MAME
This commit is contained in:
parent
00ad4e4a46
commit
97402e6d41
|
@ -652,6 +652,7 @@ src/engine/platform/sound/sm8521.c
|
|||
|
||||
src/engine/platform/sound/supervision.c
|
||||
|
||||
src/engine/platform/sound/upd1771.cpp
|
||||
src/engine/platform/sound/upd1771c.c
|
||||
|
||||
src/engine/platform/sound/d65modified.c
|
||||
|
@ -790,7 +791,8 @@ src/engine/platform/k007232.cpp
|
|||
src/engine/platform/ga20.cpp
|
||||
src/engine/platform/sm8521.cpp
|
||||
src/engine/platform/supervision.cpp
|
||||
src/engine/platform/upd1771c.cpp
|
||||
src/engine/platform/scvwave.cpp
|
||||
src/engine/platform/scvtone.cpp
|
||||
src/engine/platform/pv1000.cpp
|
||||
src/engine/platform/k053260.cpp
|
||||
src/engine/platform/ted.cpp
|
||||
|
|
|
@ -257,9 +257,10 @@ size | description
|
|||
| - 0xdf: YM2612 XGM extended - 13 channels (UNAVAILABLE)
|
||||
| - 0xe0: QSound - 19 channels
|
||||
| - 0xe1: PS1 - 24 channels (UNAVAILABLE)
|
||||
| - 0xe2: C64 (6581) with PCM - 4 channels (UNAVAILABLE)
|
||||
| - 0xe2: C64 (6581) with PCM - 4 channels
|
||||
| - 0xe3: Watara Supervision - 4 channels
|
||||
| - 0xe4: µPD1771C - 1 channel
|
||||
| - 0xe4: µPD1771C-017 (wave mode) - 1 channel
|
||||
| - 0xe5: µPD1771C-017 (tone mode) - 4 channels
|
||||
| - 0xf0: SID2 - 3 channels
|
||||
| - 0xf1: 5E01 - 5 channels
|
||||
| - 0xf5: SID3 - 7 channels
|
||||
|
|
|
@ -77,7 +77,8 @@
|
|||
#include "platform/k007232.h"
|
||||
#include "platform/ga20.h"
|
||||
#include "platform/supervision.h"
|
||||
#include "platform/upd1771c.h"
|
||||
#include "platform/scvwave.h"
|
||||
#include "platform/scvtone.h"
|
||||
#include "platform/sm8521.h"
|
||||
#include "platform/pv1000.h"
|
||||
#include "platform/k053260.h"
|
||||
|
@ -732,7 +733,10 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
dispatch=new DivPlatformSupervision;
|
||||
break;
|
||||
case DIV_SYSTEM_UPD1771C:
|
||||
dispatch=new DivPlatformUPD1771c;
|
||||
dispatch=new DivPlatformSCVWave;
|
||||
break;
|
||||
case DIV_SYSTEM_UPD1771C_TONE:
|
||||
dispatch=new DivPlatformSCVTone;
|
||||
break;
|
||||
case DIV_SYSTEM_SM8521:
|
||||
dispatch=new DivPlatformSM8521;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "upd1771c.h"
|
||||
#include "scvtone.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include "furIcons.h"
|
||||
|
@ -28,15 +28,15 @@
|
|||
|
||||
#define CHIP_DIVIDER 64
|
||||
|
||||
const char* regCheatSheetUPD1771c[]={
|
||||
const char* regCheatSheetUPD1771cTone[]={
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformUPD1771c::getRegisterSheet() {
|
||||
return regCheatSheetUPD1771c;
|
||||
const char** DivPlatformSCVTone::getRegisterSheet() {
|
||||
return regCheatSheetUPD1771cTone;
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::acquire(short** buf, size_t len) {
|
||||
void DivPlatformSCVTone::acquire(short** buf, size_t len) {
|
||||
for (size_t h=0; h<len; h++) {
|
||||
while (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
|
@ -53,7 +53,7 @@ void DivPlatformUPD1771c::acquire(short** buf, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::tick(bool sysTick) {
|
||||
void DivPlatformSCVTone::tick(bool sysTick) {
|
||||
for (int i=0; i<1; i++) {
|
||||
|
||||
chan[i].std.next();
|
||||
|
@ -146,7 +146,7 @@ void DivPlatformUPD1771c::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
int DivPlatformUPD1771c::dispatch(DivCommand c) {
|
||||
int DivPlatformSCVTone::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C);
|
||||
|
@ -262,11 +262,11 @@ int DivPlatformUPD1771c::dispatch(DivCommand c) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::muteChannel(int ch, bool mute) {
|
||||
void DivPlatformSCVTone::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::forceIns() {
|
||||
void DivPlatformSCVTone::forceIns() {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
|
@ -274,31 +274,31 @@ void DivPlatformUPD1771c::forceIns() {
|
|||
}
|
||||
}
|
||||
|
||||
void* DivPlatformUPD1771c::getChanState(int ch) {
|
||||
void* DivPlatformSCVTone::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformUPD1771c::getChanMacroInt(int ch) {
|
||||
DivMacroInt* DivPlatformSCVTone::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformUPD1771c::getOscBuffer(int ch) {
|
||||
DivDispatchOscBuffer* DivPlatformSCVTone::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformUPD1771c::getRegisterPool() {
|
||||
unsigned char* DivPlatformSCVTone::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
||||
int DivPlatformUPD1771c::getRegisterPoolSize() {
|
||||
int DivPlatformSCVTone::getRegisterPoolSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::reset() {
|
||||
void DivPlatformSCVTone::reset() {
|
||||
writes.clear();
|
||||
memset(regPool,0,16);
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i]=DivPlatformUPD1771c::Channel();
|
||||
chan[i]=DivPlatformSCVTone::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
if (dumpWrites) {
|
||||
|
@ -311,21 +311,21 @@ void DivPlatformUPD1771c::reset() {
|
|||
memset(initWrite,1,1*sizeof(unsigned char));
|
||||
}
|
||||
|
||||
int DivPlatformUPD1771c::getOutputCount() {
|
||||
int DivPlatformSCVTone::getOutputCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool DivPlatformUPD1771c::keyOffAffectsArp(int ch) {
|
||||
bool DivPlatformSCVTone::keyOffAffectsArp(int ch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::notifyInsDeletion(void* ins) {
|
||||
void DivPlatformSCVTone::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::setFlags(const DivConfig& flags) {
|
||||
void DivPlatformSCVTone::setFlags(const DivConfig& flags) {
|
||||
chipClock=6000000;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/32;
|
||||
|
@ -335,15 +335,15 @@ void DivPlatformUPD1771c::setFlags(const DivConfig& flags) {
|
|||
upd1771c_sound_set_clock(&scv,(unsigned int)chipClock,8);
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::poke(unsigned int addr, unsigned short val) {
|
||||
void DivPlatformSCVTone::poke(unsigned int addr, unsigned short val) {
|
||||
rWrite(addr,val);
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::poke(std::vector<DivRegWrite>& wlist) {
|
||||
void DivPlatformSCVTone::poke(std::vector<DivRegWrite>& wlist) {
|
||||
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
int DivPlatformUPD1771c::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
int DivPlatformSCVTone::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
|
@ -356,11 +356,11 @@ int DivPlatformUPD1771c::init(DivEngine* p, int channels, int sugRate, const Div
|
|||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformUPD1771c::quit() {
|
||||
void DivPlatformSCVTone::quit() {
|
||||
for (int i=0; i<1; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformUPD1771c::~DivPlatformUPD1771c() {
|
||||
DivPlatformSCVTone::~DivPlatformSCVTone() {
|
||||
}
|
84
src/engine/platform/scvtone.h
Normal file
84
src/engine/platform/scvtone.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _SCV_TONE_H
|
||||
#define _SCV_TONE_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include "../../fixedQueue.h"
|
||||
#include "sound/upd1771c.h"
|
||||
|
||||
class DivPlatformSCVTone: public DivDispatch {
|
||||
struct Channel: public SharedChannel<signed char> {
|
||||
unsigned int wave;
|
||||
int pos, duty;
|
||||
Channel():
|
||||
SharedChannel<signed char>(15),
|
||||
wave(0),
|
||||
pos(0),
|
||||
duty(0) {}
|
||||
};
|
||||
Channel chan[4];
|
||||
DivDispatchOscBuffer* oscBuf[4];
|
||||
bool isMuted[4];
|
||||
struct QueuedWrite {
|
||||
unsigned char addr;
|
||||
unsigned char val;
|
||||
QueuedWrite(): addr(0), val(9) {}
|
||||
QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,512> writes;
|
||||
|
||||
int curChan;
|
||||
int tempL[32];
|
||||
int tempR[32];
|
||||
int coreQuality;
|
||||
unsigned char regPool[16];
|
||||
unsigned char kon[4];
|
||||
unsigned char initWrite[4];
|
||||
struct upd1771c_t scv;
|
||||
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
void acquire(short** buf, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
int getOutputCount();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void setFlags(const DivConfig& flags);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformSCVTone();
|
||||
};
|
||||
|
||||
#endif
|
383
src/engine/platform/scvwave.cpp
Normal file
383
src/engine/platform/scvwave.cpp
Normal file
|
@ -0,0 +1,383 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "scvwave.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include "furIcons.h"
|
||||
#include <math.h>
|
||||
|
||||
//#define rWrite(a,v) pendingWrites[a]=v;
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {packet[a]=v; writePacket=true; if (dumpWrites) {addWrite(a,v);} }
|
||||
|
||||
#define CHIP_DIVIDER 64
|
||||
|
||||
const char* regCheatSheetUPD1771c[]={
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformSCVWave::getRegisterSheet() {
|
||||
return regCheatSheetUPD1771c;
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::acquire(short** buf, size_t len) {
|
||||
for (size_t h=0; h<len; h++) {
|
||||
while (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
scv.write(w.val);
|
||||
regPool[w.addr&0xf]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
scv.sound_stream_update(&buf[0][h],1);
|
||||
/*
|
||||
if (isMuted[0]) s=0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=s;
|
||||
buf[0][h]=s;
|
||||
buf[1][h]=s;*/
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::tick(bool sysTick) {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&31,MIN(31,chan[i].std.vol.val),31);
|
||||
}
|
||||
if (NEW_ARP_STRAT) {
|
||||
chan[i].handleArp();
|
||||
} else if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
int f=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_PERIODIC(f);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
chan[i].wave=chan[i].std.wave.val&7;
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val&1;
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
chan[i].pos=chan[i].std.ex1.val&31;
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||
CLAMP_VAR(chan[i].pitch2,-32768,32767);
|
||||
} else {
|
||||
chan[i].pitch2=chan[i].std.pitch.val;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
|
||||
if (i==0) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
||||
}
|
||||
if (chan[i].freqChanged || initWrite[i] || chan[i].keyOn) {
|
||||
if (chan[i].duty == 0) {
|
||||
rWrite(0,2);
|
||||
rWrite(1,(chan[i].wave<<5)|chan[i].pos);
|
||||
float p = ((float)chan[i].freq)/((float)(31-chan[i].pos))*31.0;
|
||||
rWrite(2,MIN(MAX((int)p,0),255));
|
||||
rWrite(3,chan[i].outVol);
|
||||
} else if (chan[i].duty == 1) {
|
||||
rWrite(0,1);
|
||||
rWrite(1,(chan[i].wave<<5));
|
||||
rWrite(2,MIN(MAX(chan[i].freq>>7,0),255));
|
||||
rWrite(3,chan[i].outVol);
|
||||
} else {
|
||||
rWrite(0,0);
|
||||
}
|
||||
initWrite[i]=0;
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
rWrite(0,0);
|
||||
}
|
||||
if (chan[i].keyOn) kon[i]=1;
|
||||
if (chan[i].keyOff) kon[i]=0;
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
|
||||
if (kon[i]) {
|
||||
if (i==0) {
|
||||
if (chan[i].duty == 0) {
|
||||
rWrite(0,2);
|
||||
rWrite(1,(chan[i].wave<<5)|chan[i].pos);
|
||||
// TODO: improve
|
||||
float p = ((float)chan[i].freq)/((float)(32-chan[i].pos))*32.0;
|
||||
rWrite(2,MIN(MAX((int)p,0),255));
|
||||
rWrite(3,chan[i].outVol);
|
||||
} else if (chan[i].duty == 1) {
|
||||
rWrite(0,1);
|
||||
rWrite(1,(chan[i].wave<<5));
|
||||
rWrite(2,MIN(MAX(chan[i].freq>>7,0),255));
|
||||
rWrite(3,chan[i].outVol);
|
||||
} else {
|
||||
rWrite(0,0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (i == 0) {
|
||||
rWrite(0,0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if need be, write packet
|
||||
if (writePacket) {
|
||||
writePacket=false;
|
||||
int len=1;
|
||||
if (packet[0]==2) {
|
||||
len=4;
|
||||
} else if (packet[0]==1) {
|
||||
len=10;
|
||||
}
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
writes.push(QueuedWrite(0,packet[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformSCVWave::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=c.chan==3?c.value:NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
//chwrite(c.chan,0x04,0x80|chan[c.chan].vol);
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan[c.chan].ins!=c.value || c.value2==1) {
|
||||
chan[c.chan].ins=c.value;
|
||||
chan[c.chan].insChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_VOLUME:
|
||||
if (chan[c.chan].vol!=c.value) {
|
||||
chan[c.chan].vol=c.value;
|
||||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
if (chan[c.chan].active) {
|
||||
//chwrite(c.chan,0x04,0x80|chan[c.chan].outVol);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_GET_VOLUME:
|
||||
if (chan[c.chan].std.vol.has) {
|
||||
return chan[c.chan].vol;
|
||||
}
|
||||
return chan[c.chan].outVol;
|
||||
break;
|
||||
case DIV_CMD_PITCH:
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value;
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_STD_NOISE_MODE:
|
||||
chan[c.chan].wave=c.value&7;
|
||||
chan[c.chan].duty=c.value>>4&1;
|
||||
break;
|
||||
case DIV_CMD_N163_WAVE_POSITION:
|
||||
chan[c.chan].pos=c.value;
|
||||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 31;
|
||||
break;
|
||||
case DIV_CMD_MACRO_OFF:
|
||||
chan[c.chan].std.mask(c.value,true);
|
||||
break;
|
||||
case DIV_CMD_MACRO_ON:
|
||||
chan[c.chan].std.mask(c.value,false);
|
||||
break;
|
||||
case DIV_CMD_MACRO_RESTART:
|
||||
chan[c.chan].std.restart(c.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::forceIns() {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
//chwrite(i,0x05,isMuted[i]?0:chan[i].pan);
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformSCVWave::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformSCVWave::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSCVWave::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformSCVWave::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
||||
int DivPlatformSCVWave::getRegisterPoolSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::reset() {
|
||||
writes.clear();
|
||||
memset(regPool,0,16);
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i]=DivPlatformSCVWave::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
scv.device_reset();
|
||||
memset(tempL,0,32*sizeof(int));
|
||||
memset(tempR,0,32*sizeof(int));
|
||||
memset(kon,0,1*sizeof(unsigned char));
|
||||
memset(initWrite,1,1*sizeof(unsigned char));
|
||||
memset(packet,0,16);
|
||||
writePacket=false;
|
||||
}
|
||||
|
||||
int DivPlatformSCVWave::getOutputCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool DivPlatformSCVWave::keyOffAffectsArp(int ch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::setFlags(const DivConfig& flags) {
|
||||
chipClock=6000000;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/4;
|
||||
for (int i=0; i<1; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
//upd1771c_sound_set_clock(&scv,(unsigned int)chipClock,8);
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::poke(unsigned int addr, unsigned short val) {
|
||||
rWrite(addr,val);
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::poke(std::vector<DivRegWrite>& wlist) {
|
||||
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
int DivPlatformSCVWave::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<1; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformSCVWave::quit() {
|
||||
for (int i=0; i<1; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformSCVWave::~DivPlatformSCVWave() {
|
||||
}
|
|
@ -17,14 +17,14 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _UPD1771C_H
|
||||
#define _UPD1771C_H
|
||||
#ifndef _SCV_WAVE_H
|
||||
#define _SCV_WAVE_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include "../../fixedQueue.h"
|
||||
#include "sound/upd1771c.h"
|
||||
#include "sound/upd1771.h"
|
||||
|
||||
class DivPlatformUPD1771c: public DivDispatch {
|
||||
class DivPlatformSCVWave: public DivDispatch {
|
||||
struct Channel: public SharedChannel<signed char> {
|
||||
unsigned int wave;
|
||||
int pos, duty;
|
||||
|
@ -52,8 +52,11 @@ class DivPlatformUPD1771c: public DivDispatch {
|
|||
unsigned char regPool[16];
|
||||
unsigned char kon[1];
|
||||
unsigned char initWrite[1];
|
||||
struct upd1771c_t scv;
|
||||
upd1771c_device scv;
|
||||
|
||||
unsigned char packet[16];
|
||||
|
||||
bool writePacket;
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
@ -78,7 +81,7 @@ class DivPlatformUPD1771c: public DivDispatch {
|
|||
const char** getRegisterSheet();
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformUPD1771c();
|
||||
~DivPlatformSCVWave();
|
||||
};
|
||||
|
||||
#endif
|
508
src/engine/platform/sound/upd1771.cpp
Normal file
508
src/engine/platform/sound/upd1771.cpp
Normal file
|
@ -0,0 +1,508 @@
|
|||
// license:BSD-3-Clause
|
||||
// copyright-holders:David Viens
|
||||
/**********************************************************************
|
||||
|
||||
NEC uPD1771-017 as used in the Epoch Super Cassette Vision (SCV)
|
||||
|
||||
Made using recording/analysis on a Yeno (PAL Super Cassette Vision)
|
||||
by plgDavid
|
||||
|
||||
Full markings on my 2 specimens are
|
||||
"NEC JAPAN 8431K9 D1771C 017" (31st week of 1984, mask rom #017)
|
||||
|
||||
I've since (October 2012) got a Grandstand Firefox F-7 Handheld game
|
||||
(AKA Epoch GalagaX6/Epoch Astro Thunder 7/Tandy Astro Thunder),
|
||||
(http://www.handheldmuseum.com/Grandstand/Firefox.htm)
|
||||
which includes a
|
||||
"NEC JAPAN 8319K9 D1771C 011" (19th week of 1983, mask rom #011)
|
||||
Thanks to user 'Blanka' from Dragonslairfans for the nice catch!
|
||||
(http://www.dragonslairfans.com/smfor/index.php?topic=3061.0)
|
||||
|
||||
Since the chip generates tones using ROM wavetables,
|
||||
it is perfectly possible to generate other sounds with different rom code and data.
|
||||
|
||||
Most upd17XXX devices are typically 4bit NEC MCUs, however based on information
|
||||
in "Electronic Speech Synthesis" by Geoff Bristow (ISBN 0-07-007912-9, pages 148-152)
|
||||
the upd1770/1771 is not one of these 4-bit ones.
|
||||
|
||||
The uPD1770/uPD1771 SSM is a 16-bit-wide rom/ram mcu with 8kb (4kw) of rom code,
|
||||
64 bytes of ram (16x16bit words addressable as 16 or 2x8 bits each, the
|
||||
remaining 32 bytes acting as an 8-level stack), 182 instructions, a complex
|
||||
noise and tone internal interrupt system, external interrupts,
|
||||
and two 8-bit ports with multiple modes allowing for chips to operate as master
|
||||
or slave devices.
|
||||
SSM stands for "Sound Synthesis Microcomputer".
|
||||
|
||||
People who I *THINK* worked on the uPD1771 and what part I think they worked on:
|
||||
Toshio Oura - Project Lead(?), VSRSSS/TSRSSS speech synthesis engine (on upd1776C), master/slave i/o controls, author of bristow article and primary author of the IEEE article
|
||||
Hatsuhide Igarashi - Clock oscillator and pad layout, coauthor on the IEEE article, other IEEE stuff
|
||||
Tomoaki Isozaki - ? (senior NEC engineer?), coauthor on the IEEE article
|
||||
Sachiyuki Toufuku - ?, coauthor on the IEEE article
|
||||
Tojiro Mukawa - IGFETs and the DAC
|
||||
M. Sakai ? - digital filtering for VSRSSS? (IEEE 4131979, 1169295)
|
||||
M. Endo ? - digital design system or speech synthesis? (IEEE 4069656, another? person: IEEE 150330, 225838)
|
||||
H. Aoyama ? - logic design system used to assemble/lay out the chip? (IEEE 1585393)
|
||||
I. Fujitaka ? (no IEEE)
|
||||
Eiji Sugimoto - cpu design? 1156033 1155824
|
||||
F. Tsukuda ? (no IEEE)
|
||||
N. Miyake ? switched capacitor stuff? (IEEE nnnnnn)
|
||||
|
||||
|
||||
The uPD1771 internal workings are described to some extent by the Bristow book
|
||||
and the IEEE article "A Single-Chip Sound Synthesis Microcomputer" which complements the book
|
||||
and are covered by at least four US patents:
|
||||
4184152 - on IGFET-based DAC stuff
|
||||
4488061 - on the IGFET-based drive circuit part of the DAC.
|
||||
4408094 - covers the 3 pin DAC with the volume control/vref pin. Not all that interesting,
|
||||
except it might describe to some extent how the (9->5bit?) PWM works in the text.
|
||||
4470113 - covers the multiplexed PB0/1/2/3 pins and their use as /CS /WR /RD and ALE
|
||||
note as I have marked the pins below I assume the final pins connected
|
||||
to /CS /WR /RD and /ALE are PB7,6,5,4 but this is just a guess of mine:
|
||||
The actual order may well match the patent.
|
||||
4577343 - covers the VSRSSS implementation as discussed in the Bristow book.
|
||||
This patent has an internal diagram of the workings of the chips and
|
||||
a limited description of how many registers etc it has.
|
||||
4805508 - on the operation of the tone divider register and correction for accurate period when
|
||||
the tone interrupt frequency is not perfectly divisible from the clock.
|
||||
These next two may not be specific to the 1771 or even related at all!
|
||||
4321562 - on a self-adjusting circuit for internal coupling to the clock crystal inputs.
|
||||
This may be a generic NEC invention and probably isn't limited to the upd1771.
|
||||
4656491 - on a new method of distributing resistors and transistors on anti-ESD pin buffers
|
||||
This may be a generic NEC invention and probably isn't limited to the upd1771.
|
||||
|
||||
|
||||
Based on the 4577343 patent mostly, plus the bristow and IEEE article:
|
||||
* these are the registers:
|
||||
8bits:
|
||||
AH, AL (forming the 16-bit A' accumulator),
|
||||
B, C (a pair of general purpose registers),
|
||||
4bits (may be technically part of ALU):
|
||||
H -> points to one of the 16 words of ram
|
||||
1bit:
|
||||
L -> selector of left or right half of the ram word
|
||||
?bits:
|
||||
D (having to do with the DAC)
|
||||
N (3 bits? having to do with the pseudorandom noise interrupt, namely setting the clock divider ratio for the PRNG clock vs cpu clock)
|
||||
MODE (5 or more bits? enabling/disabling/acking the noise interrupt, and the tone interrupts (there are four!))
|
||||
SP (the stack pointer, probably 5 bits, points to the stack ram; may encompass H and L as above!)
|
||||
FLO: unsure. quite possibly 'flag overflow' used for branching. there likely exists other flags as well...
|
||||
ODF: 'output data flag?', selects which half of a selected ram word is output to the dac not really sure of this?
|
||||
|
||||
|
||||
Mask roms known:
|
||||
uPD1776C: mentioned in the bristow book, implements VSRSSS speech concatenation
|
||||
(see US Patent 4577343 which is a patent on this VSRSSS implementation)
|
||||
uPD1771C-006: used in NEC APC for sound as the "MPU"
|
||||
-011: used on Firefox F-4/Astro Thunder handheld
|
||||
-015: unknown, known to exist from part scalper sites only.
|
||||
-017: used on Epoch Super Cassette Vision for sound; This audio driver HLEs that part only.
|
||||
|
||||
Used pinout in the SCV:
|
||||
|
||||
NC 1 28 NC
|
||||
NC 2 27 NC
|
||||
NC 3 26 ACK
|
||||
!WR 4 25 D7
|
||||
!CS 5 24 D6
|
||||
RESET 6 23 D5
|
||||
NC 7 22 D4
|
||||
VCC 8 21 D3
|
||||
6Mhz XIN 9 20 D2
|
||||
6Mhz XOUT 10 19 D1
|
||||
AUDOUT 11 18 D0
|
||||
NC(recheck!)12 17 GND
|
||||
AUDOUT(inv) 13 16 VCC
|
||||
GND 14 15 ? tied to pin 16 (VCC) through a resistor (pullup?)
|
||||
|
||||
Pinout based on guesses and information in "Electronic Speech Synthesis" by Geoff Bristow
|
||||
(ISBN 0-07-007912-9, pages 148-152), and the data on page 233 of the Nec APC technical manual at
|
||||
http://bitsavers.trailing-edge.com/pdf/nec/APC/819-000100-1003_APC_System_Reference_Guide_Apr83.pdf
|
||||
I/O pin purpose based on testing by kevtris.
|
||||
[x] is unsure:
|
||||
PB3 <> 1 28 <> PB2
|
||||
PB4(/ALE) <> 2 27 <> PB1
|
||||
PB5(/RD) <> 3 26 <> PB0
|
||||
PB6(/WR) <> 4 25 <> D7(PA7)
|
||||
PB7(/CS) <> 5 24 <> D6(PA6)
|
||||
/RESET -> 6 23 <> D5(PA5)
|
||||
[/TSTOUT?] <- 7 22 <> D4(PA4)
|
||||
VCC -- 8 21 <> D3(PA3)
|
||||
XI(CLK) -> 9 20 <> D2(PA2)
|
||||
XO <- 10 19 <> D1(PA1)
|
||||
D/A OUT + <- 11 18 <> D0(PA0)
|
||||
D/A POWER -- 12 17 <- CH2
|
||||
D/A OUT - <- 13 16 <> /EXTINT and [/TSTOUT2?] (test out is related to pin 15 state)
|
||||
GND -- 14 15 <- CH1 tied to pin 16 (VCC) through a resistor, on APC to VCC thru a 12k resistor and thru a 10uf cap to gnd
|
||||
|
||||
CH1 and CH2 are mode selects, purpose based on testing by kevtris:
|
||||
CH1 CH2
|
||||
H L - 'master' mode, pb4-pb7 are i/o? /EXTINT is an input
|
||||
L L - 'slave' mode where pb4-pb7 are /ale /rd /wr /cs? /EXTINT may be an output in this mode?
|
||||
X H - test mode: the 512 byte 16-bit wide ROM is output sequentially on pins pa7-pa0 and pb7-pb0 for the high and low bytes of each word respectively
|
||||
D/A POWER is the FET source for the D/A OUT+ and D/A OUT- push-pull dac drains; it should be tied to VCC or thereabouts
|
||||
|
||||
In the SCV (info from plgDavid):
|
||||
pin 5 is tied to the !SCPU pin on the Epoch TV chip pin 29 (0x3600 writes)
|
||||
pin 6 is tied to the PC3 pin of the upD7801 CPU
|
||||
pin 26 is tied to the INT1 pin of the upD7801 (CPU pin 12),
|
||||
|
||||
1,2,3,28,27 don't generate any digital signals
|
||||
6 seems to be lowered 2.5 ms before an audio write
|
||||
7 is always low.
|
||||
12 is always high
|
||||
|
||||
(NOTE: the photomicrograph in the bristow book makes it fairly clear due to
|
||||
pad thicknessess that the real VCC is pin 8 and the real GND is pin 14.
|
||||
The function of pin 7 is unknown.
|
||||
|
||||
Pins 11 and 13 go to a special circuit, which according to kevtris's analysis
|
||||
of my schematics, consist of a balanced output (not unlike XLR cables),
|
||||
which are then combined together then sent to the RF box.
|
||||
(The bristow book explains that there are two DAC pins and one DAC
|
||||
VREF/volume pin. The dac+ and dac- are pins 11 and 13, and based on the
|
||||
photomicrograph it looks like dac vref is probably pin 12)
|
||||
|
||||
HLE:
|
||||
All writes are made through address 0x3600 on the upD7801
|
||||
Instead of using register=value, this chip require sending multiple
|
||||
bytes for each command, one after the other.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "upd1771.h"
|
||||
|
||||
//#define VERBOSE 1
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
Each of the 8 waveforms have been extracted from the uPD1771c-017 internal
|
||||
ROM, from offset 0x1fd (start of first waveform) to offset 0x2fc (end of
|
||||
last waveform).
|
||||
(note: given test mode dumping offset non-clarity it may be 0x200-0x2ff)
|
||||
The waveforms are stored in an 8-bit sign-magnitude format, so if in ROM the
|
||||
upper bit is 0x80, invert the lower 7 bits to get the 2's complement result
|
||||
seen here.
|
||||
Note that only the last 4 waveforms appear to have been intended for use as
|
||||
waveforms; the first four look as if they're playing back a piece of code as
|
||||
wave data.
|
||||
*/
|
||||
static const signed char WAVEFORMS[8][32]={
|
||||
{ 0, 0,-123,-123, -61, -23, 125, 107, 94, 83,-128,-128,-128, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,-128,-128,-128, 0, 0, 0, 0, 0, 0},
|
||||
{ 37, 16, 32, -21, 32, 52, 4, 4, 33, 18, 60, 56, 0, 8, 5, 16, 65, 19, 69, 16, -2, 19, 37, 16, 97, 19, 0, 87, 127, -3, 1, 2},
|
||||
{ 0, 8, 1, 52, 4, 0, 0, 77, 81,-109, 47, 97, -83,-109, 38, 97, 0, 52, 4, 0, 1, 4, 1, 22, 2, -46, 33, 97, 0, 8, -85, -99},
|
||||
{ 47, 97, 40, 97, -3, 25, 64, 17, 0, 52, 12, 5, 12, 5, 12, 5, 12, 5, 12, 5, 8, 4,-114, 19, 0, 52,-122, 21, 2, 5, 0, 8},
|
||||
{ -52, -96,-118,-128,-111, -74, -37, -5, 31, 62, 89, 112, 127, 125, 115, 93, 57, 23, 0, -16, -8, 15, 37, 54, 65, 70, 62, 54, 43, 31, 19, 0},
|
||||
{ -81,-128, -61, 13, 65, 93, 127, 47, 41, 44, 52, 55, 56, 58, 58, 34, 0, 68, 76, 72, 61, 108, 55, 29, 32, 39, 43, 49, 50, 51, 51, 0},
|
||||
{ -21, -45, -67, -88,-105,-114,-122,-128,-123,-116,-103, -87, -70, -53, -28, -9, 22, 46, 67, 86, 102, 114, 123, 125, 127, 117, 104, 91, 72, 51, 28, 0},
|
||||
{ -78,-118,-128,-102, -54, -3, 40, 65, 84, 88, 84, 80, 82, 88, 94, 103, 110, 119, 122, 125, 122, 122, 121, 123, 125, 126, 127, 127, 125, 118, 82, 0}
|
||||
};
|
||||
|
||||
|
||||
#define NOISE_SIZE 255
|
||||
|
||||
|
||||
static const unsigned char noise_tbl[]=
|
||||
{
|
||||
0x1c,0x86,0x8a,0x8f,0x98,0xa1,0xad,0xbe,0xd9,0x8a,0x66,0x4d,0x40,0x33,0x2b,0x23,
|
||||
0x1e,0x8a,0x90,0x97,0xa4,0xae,0xb8,0xd6,0xec,0xe9,0x69,0x4a,0x3e,0x34,0x2d,0x27,
|
||||
0x24,0x24,0x89,0x8e,0x93,0x9c,0xa5,0xb0,0xc1,0xdd,0x40,0x36,0x30,0x29,0x27,0x24,
|
||||
0x8b,0x90,0x96,0x9e,0xa7,0xb3,0xc4,0xe1,0x25,0x21,0x8a,0x8f,0x93,0x9d,0xa5,0xb2,
|
||||
0xc2,0xdd,0xdd,0x98,0xa2,0xaf,0xbf,0xd8,0xfd,0x65,0x4a,0x3c,0x31,0x2b,0x24,0x22,
|
||||
0x1e,0x87,0x8c,0x91,0x9a,0xa3,0xaf,0xc0,0xdb,0xbe,0xd9,0x8c,0x66,0x4d,0x40,0x34,
|
||||
0x2c,0x24,0x1f,0x88,0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4d,0x3d,0x34,0x2d,
|
||||
0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0xc1,0xda,0xff,0x67,0x4d,
|
||||
0x3d,0x33,0x2d,0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xdd,0xa3,0xb0,
|
||||
0xc0,0xd9,0xfe,0x66,0x4b,0x3c,0x32,0x2b,0x24,0x23,0x1e,0x88,0x8d,0x92,0x9b,0xa4,
|
||||
0xb0,0xc1,0xdc,0xad,0xbe,0xda,0x22,0x20,0x1c,0x85,0x8a,0x8f,0x98,0xa1,0xad,0xbe,
|
||||
0xda,0x20,0x1b,0x85,0x8d,0x97,0xa1,0xaf,0xbf,0xd8,0xfd,0x64,0x49,0x3a,0x30,0x2a,
|
||||
0x23,0x21,0x1d,0x86,0x8b,0x91,0x9a,0xa2,0xae,0xc0,0xdb,0x33,0x2b,0x24,0x1f,0x88,
|
||||
0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4c,0x3e,0x33,0x2d,0x25,0x24,0x1f,0x89,
|
||||
0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0x85,0x8e,0x98,0xa2,0xb0,0xc0,0xd9,0xfe,0x64,
|
||||
0x4b,0x3b,0x31,0x2a,0x23,0x22,0x1e,0x88,0x8c,0x91,0x9b,0xa3,0xaf,0xc1,0xdc,0xdc
|
||||
};
|
||||
|
||||
|
||||
#define STATE_SILENCE 0
|
||||
#define STATE_NOISE 1
|
||||
#define STATE_TONE 2
|
||||
#define STATE_ADPCM 3
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd1771c_device::device_reset()
|
||||
{
|
||||
m_index = 0;
|
||||
m_expected_bytes = 0;
|
||||
m_pc3 = 0;
|
||||
m_t_tpos = 0;
|
||||
m_t_ppos = 0;
|
||||
m_state = STATE_SILENCE;
|
||||
m_nw_tpos = 0;
|
||||
memset(m_n_value, 0x00, sizeof(m_n_value));
|
||||
memset(m_n_ppos, 0x00, sizeof(m_n_ppos));
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t upd1771c_device::read()
|
||||
{
|
||||
return 0x80; // TODO
|
||||
}
|
||||
|
||||
/*
|
||||
*************TONE*****************
|
||||
Tone consists of a wavetable playback mechanism.
|
||||
Each wavetable is a looping period of 32 samples but can be played with an offset from any point in the table
|
||||
effectively shrinking the sample loop, thus allowing different pitch "macros ranges" to be played.
|
||||
This method is rather crude because the spectrum of the sound get heavily altered...
|
||||
unless that was the intent.
|
||||
|
||||
Tone Write (4 bytes):
|
||||
|
||||
Byte0: 0x02
|
||||
|
||||
Byte1: 0bTTTOOOOO
|
||||
MSB 3 bits of Timbre (8 wavetables)
|
||||
LSB 5 bits offset in the table.
|
||||
|
||||
Byte2: 0bPPPPPPPP
|
||||
8bits of clock divider/period
|
||||
Anything under <= 0x20 give the same value
|
||||
|
||||
Byte3: 0b???VVVVV
|
||||
MSB 3 bits unknown
|
||||
LSB 5 bits of "Volume"
|
||||
|
||||
Note: volume is not a volume in a normal sense but some kind
|
||||
of bit cropping/rounding.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*************NOISE*****************
|
||||
Noise consists on 4 different components
|
||||
A weird Wavetable LFSR (for lack of a better term),
|
||||
and three independent (but equal) low frequency
|
||||
50/50 pulse wavs.
|
||||
|
||||
The 4 components are mixed in a mysterious way,
|
||||
a weird ORing with volume having a huge effect.
|
||||
|
||||
Byte0: 0x01
|
||||
|
||||
Byte1: 0bTTTOOOOO
|
||||
MSB 3 bits of LFSR Timbre (8 wavetables)
|
||||
LSB 5 bits ?????????
|
||||
|
||||
Byte2: 0bPPPPPPPP
|
||||
8bits of clock divider/period
|
||||
|
||||
Byte3: 0b???VVVVV
|
||||
MSB 3 bits unknown
|
||||
LSB 5 bits of "Volume"
|
||||
|
||||
|
||||
Byte4: 0bPPPPPPPP Low Freq0 period(if not 0 this periodically resets the Wavetable LFSR)
|
||||
Byte5: 0bPPPPPPPP Low Freq1 period(if not 0 this periodically resets the Wavetable LFSR)
|
||||
Byte6: 0bPPPPPPPP Low Freq2 period(if not 0 this periodically resets the Wavetable LFSR)
|
||||
|
||||
Byte7: 0b???VVVVV Low Freq0 volume
|
||||
Byte8: 0b???VVVVV Low Freq1 volume
|
||||
Byte9: 0b???VVVVV Low Freq2 volume
|
||||
*/
|
||||
|
||||
void upd1771c_device::write(uint8_t data)
|
||||
{
|
||||
//LOG("upd1771_w: received byte 0x%02x\n", data);
|
||||
|
||||
if (m_index < MAX_PACKET_SIZE)
|
||||
m_packet[m_index++] = data;
|
||||
else
|
||||
{
|
||||
//logerror("upd1771_w: received byte 0x%02x overload!\n", data);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_packet[0])
|
||||
{
|
||||
case 0:
|
||||
m_state = STATE_SILENCE;
|
||||
m_index = 0;
|
||||
//logerror( "upd1771_w: ----------------silence state reset\n");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (m_index == 10)
|
||||
{
|
||||
m_state = STATE_NOISE;
|
||||
m_index = 0;
|
||||
|
||||
m_nw_timbre = (m_packet[1] & 0xe0) >> 5;
|
||||
m_nw_period = ((uint32_t)m_packet[2] + 1) << 7;
|
||||
m_nw_volume = m_packet[3] & 0x1f;
|
||||
|
||||
//very long clocked periods.. used for engine drones
|
||||
m_n_period[0] = (((uint32_t)m_packet[4]) + 1) << 7;
|
||||
m_n_period[1] = (((uint32_t)m_packet[5]) + 1) << 7;
|
||||
m_n_period[2] = (((uint32_t)m_packet[6]) + 1) << 7;
|
||||
|
||||
m_n_volume[0] = m_packet[7] & 0x1f;
|
||||
m_n_volume[1] = m_packet[8] & 0x1f;
|
||||
m_n_volume[2] = m_packet[9] & 0x1f;
|
||||
|
||||
//logerror( "upd1771_w: ----------------noise state reset\n");
|
||||
} else {
|
||||
// supposedly timer adjusts here, to 512 cycles
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (m_index == 4)
|
||||
{
|
||||
//logerror( "upd1771_w: ----------------tone state reset\n");
|
||||
m_t_timbre = (m_packet[1] & 0xe0) >> 5;
|
||||
m_t_offset = (m_packet[1] & 0x1f);
|
||||
m_t_period = m_packet[2];
|
||||
//smaller periods don't all equal to 0x20
|
||||
if (m_t_period < 0x20)
|
||||
m_t_period = 0x20;
|
||||
|
||||
m_t_volume = m_packet[3] & 0x1f;
|
||||
m_state = STATE_TONE;
|
||||
m_index = 0;
|
||||
} else {
|
||||
// supposedly timer adjusts here, to 512 cycles
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1f:
|
||||
//6Khz(ish) DIGI playback
|
||||
|
||||
//end capture
|
||||
{
|
||||
bool have_all_data = false;
|
||||
if (m_index >= 2 && m_packet[m_index - 2] == 0xfe && m_packet[m_index - 1] == 0x00)
|
||||
{
|
||||
//TODO play capture!
|
||||
if (m_index >= 6)
|
||||
{
|
||||
// offsets 2 and 3 in the transferred pcm data seem to contain the number of samples
|
||||
uint16_t count = (m_packet[4] << 8) | m_packet[3];
|
||||
count--;
|
||||
m_packet[3] = count & 0xff;
|
||||
m_packet[4] = (count >> 8);
|
||||
if (count == 0)
|
||||
{
|
||||
m_index = 0;
|
||||
m_packet[0] = 0;
|
||||
m_state = STATE_ADPCM;
|
||||
have_all_data = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!have_all_data) {
|
||||
// supposedly timer adjusts here, to 512 cycles
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//garbage: wipe stack
|
||||
default:
|
||||
m_state = STATE_SILENCE;
|
||||
m_index = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void upd1771c_device::pcm_write(int state)
|
||||
{
|
||||
//RESET upon HIGH
|
||||
if (state != m_pc3)
|
||||
{
|
||||
//logerror("upd1771_pc3 change!: state = %d\n", state);
|
||||
m_index = 0;
|
||||
m_packet[0] = 0;
|
||||
m_state = STATE_SILENCE;
|
||||
}
|
||||
|
||||
m_pc3 = state;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// sound_stream_update - handle a stream update
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd1771c_device::sound_stream_update(short* output, int len)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_TONE:
|
||||
//logerror( "upd1771_STATE_TONE samps:%d %d %d %d %d %d\n",(int)samples,
|
||||
// (int)m_t_timbre,(int)m_t_offset,(int)m_t_volume,(int)m_t_period,(int)m_t_tpos);
|
||||
|
||||
for (int sampindex = 0; sampindex < len; sampindex++)
|
||||
{
|
||||
output[sampindex]=(WAVEFORMS[m_t_timbre][m_t_tpos]) * m_t_volume * 8;
|
||||
|
||||
m_t_ppos++;
|
||||
if (m_t_ppos >= m_t_period)
|
||||
{
|
||||
m_t_tpos++;
|
||||
if (m_t_tpos == 32)
|
||||
m_t_tpos = m_t_offset;
|
||||
|
||||
m_t_ppos = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_NOISE:
|
||||
for (int sampindex = 0; sampindex < len; sampindex++)
|
||||
{
|
||||
//"wavetable-LFSR" component
|
||||
int wlfsr_val = ((int)noise_tbl[m_nw_tpos]) - 127;//data too wide
|
||||
|
||||
m_nw_ppos++;
|
||||
if (m_nw_ppos >= m_nw_period)
|
||||
{
|
||||
m_nw_tpos++;
|
||||
if (m_nw_tpos == NOISE_SIZE)
|
||||
m_nw_tpos = 0;
|
||||
m_nw_ppos = 0;
|
||||
}
|
||||
|
||||
//mix in each of the noise's 3 pulse components
|
||||
char res[3];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
res[i] = m_n_value[i] * 127;
|
||||
m_n_ppos[i]++;
|
||||
if (m_n_ppos[i] >= m_n_period[i])
|
||||
{
|
||||
m_n_ppos[i] = 0;
|
||||
m_n_value[i] = !m_n_value[i];
|
||||
}
|
||||
}
|
||||
//not quite, but close.
|
||||
output[sampindex]=
|
||||
((wlfsr_val * m_nw_volume) |
|
||||
(res[0] * m_n_volume[0]) |
|
||||
(res[1] * m_n_volume[1]) |
|
||||
(res[2] * m_n_volume[2])) * 8;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//fill buffer with silence
|
||||
memset(output,0,sizeof(short)*len);
|
||||
break;
|
||||
}
|
||||
}
|
66
src/engine/platform/sound/upd1771.h
Normal file
66
src/engine/platform/sound/upd1771.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// license:BSD-3-Clause
|
||||
// copyright-holders:Wilbert Pol
|
||||
/**********************************************************************
|
||||
|
||||
NEC uPD1771
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MAME_SOUND_UPD1771_H
|
||||
#define MAME_SOUND_UPD1771_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MACROS / CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
class upd1771c_device
|
||||
{
|
||||
public:
|
||||
uint8_t read();
|
||||
void write(uint8_t data);
|
||||
void pcm_write(int state);
|
||||
|
||||
// device-level overrides
|
||||
void device_reset();
|
||||
|
||||
// sound stream update overrides
|
||||
void sound_stream_update(short* output, int len);
|
||||
|
||||
private:
|
||||
static constexpr unsigned MAX_PACKET_SIZE = 0x8000;
|
||||
|
||||
// internal state
|
||||
|
||||
uint8_t m_packet[MAX_PACKET_SIZE];
|
||||
uint32_t m_index;
|
||||
uint8_t m_expected_bytes;
|
||||
|
||||
uint8_t m_state;//0:silence, 1 noise, 2 tone
|
||||
uint8_t m_pc3;
|
||||
|
||||
//tone
|
||||
uint8_t m_t_timbre; //[0; 7]
|
||||
uint8_t m_t_offset; //[0; 32]
|
||||
uint16_t m_t_period; //[0;255]
|
||||
uint8_t m_t_volume; //[0; 31]
|
||||
uint8_t m_t_tpos;//timbre pos
|
||||
uint16_t m_t_ppos;//period pos
|
||||
|
||||
//noise wavetable LFSR
|
||||
uint8_t m_nw_timbre; //[0; 7]
|
||||
uint8_t m_nw_volume; //[0; 31]
|
||||
uint32_t m_nw_period;
|
||||
uint32_t m_nw_tpos; //timbre pos
|
||||
uint32_t m_nw_ppos; //period pos
|
||||
|
||||
//noise pulse components
|
||||
uint8_t m_n_value[3]; //[0;1]
|
||||
uint16_t m_n_volume[3]; //[0; 31]
|
||||
uint32_t m_n_period[3];
|
||||
uint32_t m_n_ppos[3]; //period pos
|
||||
};
|
||||
|
||||
#endif // MAME_SOUND_UPD1771_H
|
|
@ -1,300 +0,0 @@
|
|||
// SOME CODE IS TAKEN FROM MAME'S EMULATION OF THE UPD1771C
|
||||
// MADE BY AART1256 IN 2024
|
||||
|
||||
#include "upd1771c.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
Each of the 8 waveforms have been extracted from the uPD1771c-017 internal
|
||||
ROM, from offset 0x1fd (start of first waveform) to offset 0x2fc (end of
|
||||
last waveform).
|
||||
(note: given test mode dumping offset non-clarity it may be 0x200-0x2ff)
|
||||
The waveforms are stored in an 8-bit sign-magnitude format, so if in ROM the
|
||||
upper bit is 0x80, invert the lower 7 bits to get the 2's complement result
|
||||
seen here.
|
||||
Note that only the last 4 waveforms appear to have been intended for use as
|
||||
waveforms; the first four look as if they're playing back a piece of code as
|
||||
wave data.
|
||||
*/
|
||||
const signed char WAVEFORMS[8][32]={
|
||||
{ 0, 0,-123,-123, -61, -23, 125, 107, 94, 83,-128,-128,-128, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,-128,-128,-128, 0, 0, 0, 0, 0, 0},
|
||||
{ 37, 16, 32, -21, 32, 52, 4, 4, 33, 18, 60, 56, 0, 8, 5, 16, 65, 19, 69, 16, -2, 19, 37, 16, 97, 19, 0, 87, 127, -3, 1, 2},
|
||||
{ 0, 8, 1, 52, 4, 0, 0, 77, 81,-109, 47, 97, -83,-109, 38, 97, 0, 52, 4, 0, 1, 4, 1, 22, 2, -46, 33, 97, 0, 8, -85, -99},
|
||||
{ 47, 97, 40, 97, -3, 25, 64, 17, 0, 52, 12, 5, 12, 5, 12, 5, 12, 5, 12, 5, 8, 4,-114, 19, 0, 52,-122, 21, 2, 5, 0, 8},
|
||||
{ -52, -96,-118,-128,-111, -74, -37, -5, 31, 62, 89, 112, 127, 125, 115, 93, 57, 23, 0, -16, -8, 15, 37, 54, 65, 70, 62, 54, 43, 31, 19, 0},
|
||||
{ -81,-128, -61, 13, 65, 93, 127, 47, 41, 44, 52, 55, 56, 58, 58, 34, 0, 68, 76, 72, 61, 108, 55, 29, 32, 39, 43, 49, 50, 51, 51, 0},
|
||||
{ -21, -45, -67, -88,-105,-114,-122,-128,-123,-116,-103, -87, -70, -53, -28, -9, 22, 46, 67, 86, 102, 114, 123, 125, 127, 117, 104, 91, 72, 51, 28, 0},
|
||||
{ -78,-118,-128,-102, -54, -3, 40, 65, 84, 88, 84, 80, 82, 88, 94, 103, 110, 119, 122, 125, 122, 122, 121, 123, 125, 126, 127, 127, 125, 118, 82, 0}
|
||||
};
|
||||
|
||||
|
||||
#define NOISE_SIZE 255
|
||||
|
||||
|
||||
/*
|
||||
const unsigned char noise_tbl[]=
|
||||
{
|
||||
0x1c,0x86,0x8a,0x8f,0x98,0xa1,0xad,0xbe,0xd9,0x8a,0x66,0x4d,0x40,0x33,0x2b,0x23,
|
||||
0x1e,0x8a,0x90,0x97,0xa4,0xae,0xb8,0xd6,0xec,0xe9,0x69,0x4a,0x3e,0x34,0x2d,0x27,
|
||||
0x24,0x24,0x89,0x8e,0x93,0x9c,0xa5,0xb0,0xc1,0xdd,0x40,0x36,0x30,0x29,0x27,0x24,
|
||||
0x8b,0x90,0x96,0x9e,0xa7,0xb3,0xc4,0xe1,0x25,0x21,0x8a,0x8f,0x93,0x9d,0xa5,0xb2,
|
||||
0xc2,0xdd,0xdd,0x98,0xa2,0xaf,0xbf,0xd8,0xfd,0x65,0x4a,0x3c,0x31,0x2b,0x24,0x22,
|
||||
0x1e,0x87,0x8c,0x91,0x9a,0xa3,0xaf,0xc0,0xdb,0xbe,0xd9,0x8c,0x66,0x4d,0x40,0x34,
|
||||
0x2c,0x24,0x1f,0x88,0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4d,0x3d,0x34,0x2d,
|
||||
0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0xc1,0xda,0xff,0x67,0x4d,
|
||||
0x3d,0x33,0x2d,0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xdd,0xa3,0xb0,
|
||||
0xc0,0xd9,0xfe,0x66,0x4b,0x3c,0x32,0x2b,0x24,0x23,0x1e,0x88,0x8d,0x92,0x9b,0xa4,
|
||||
0xb0,0xc1,0xdc,0xad,0xbe,0xda,0x22,0x20,0x1c,0x85,0x8a,0x8f,0x98,0xa1,0xad,0xbe,
|
||||
0xda,0x20,0x1b,0x85,0x8d,0x97,0xa1,0xaf,0xbf,0xd8,0xfd,0x64,0x49,0x3a,0x30,0x2a,
|
||||
0x23,0x21,0x1d,0x86,0x8b,0x91,0x9a,0xa2,0xae,0xc0,0xdb,0x33,0x2b,0x24,0x1f,0x88,
|
||||
0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4c,0x3e,0x33,0x2d,0x25,0x24,0x1f,0x89,
|
||||
0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0x85,0x8e,0x98,0xa2,0xb0,0xc0,0xd9,0xfe,0x64,
|
||||
0x4b,0x3b,0x31,0x2a,0x23,0x22,0x1e,0x88,0x8c,0x91,0x9b,0xa3,0xaf,0xc1,0xdc,0xdc
|
||||
};
|
||||
*/
|
||||
|
||||
const unsigned char noise_tbl[8][256] = {
|
||||
{
|
||||
0x84, 0x87, 0x8c, 0x93, 0x9a, 0xa4, 0xb2, 0xc8, 0x8a, 0x6c, 0x58, 0x4e, 0x43, 0x3d, 0x37, 0x33,
|
||||
0x86, 0x8d, 0x95, 0x9d, 0xa8, 0xb5, 0xc9, 0xe7, 0x6d, 0x58, 0x4b, 0x43, 0x3e, 0x38, 0x37, 0x34,
|
||||
0x87, 0x8b, 0x8f, 0x96, 0x9d, 0xa7, 0xb5, 0xcb, 0x4d, 0x45, 0x40, 0x3a, 0x39, 0x35, 0x89, 0x8d,
|
||||
0x91, 0x98, 0x9f, 0xa9, 0xb7, 0xcd, 0x37, 0x34, 0x87, 0x8c, 0x90, 0x97, 0x9e, 0xa8, 0xb5, 0xcb,
|
||||
0xca, 0x93, 0x9b, 0xa6, 0xb3, 0xc7, 0xe5, 0x6b, 0x56, 0x49, 0x41, 0x3c, 0x36, 0x35, 0x32, 0x86,
|
||||
0x89, 0x8e, 0x95, 0x9c, 0xa6, 0xb4, 0xc9, 0xb2, 0xc8, 0x8a, 0x6c, 0x58, 0x4d, 0x43, 0x3d, 0x37,
|
||||
0x33, 0x86, 0x8d, 0x95, 0x9d, 0xa8, 0xb5, 0xc9, 0xe7, 0x6d, 0x58, 0x4b, 0x43, 0x3e, 0x38, 0x37,
|
||||
0x34, 0x87, 0x8b, 0x8f, 0x97, 0x9e, 0xa8, 0xb5, 0xcb, 0xb5, 0xc9, 0xe6, 0x6d, 0x58, 0x4b, 0x43,
|
||||
0x3d, 0x38, 0x37, 0x33, 0x87, 0x8b, 0x8f, 0x96, 0x9e, 0xa7, 0xb5, 0xcb, 0x9c, 0xa7, 0xb3, 0xc8,
|
||||
0xe6, 0x6c, 0x56, 0x4a, 0x42, 0x3d, 0x37, 0x36, 0x33, 0x86, 0x8a, 0x8e, 0x95, 0x9c, 0xa6, 0xb4,
|
||||
0xca, 0xa4, 0xb2, 0xc8, 0x35, 0x33, 0x30, 0x84, 0x88, 0x8c, 0x93, 0x9a, 0xa5, 0xb2, 0xc8, 0x34,
|
||||
0x30, 0x84, 0x8a, 0x93, 0x9a, 0xa5, 0xb2, 0xc6, 0xe4, 0x6a, 0x55, 0x49, 0x41, 0x3b, 0x36, 0x34,
|
||||
0x31, 0x85, 0x89, 0x8d, 0x94, 0x9b, 0xa5, 0xb3, 0xc9, 0x43, 0x3d, 0x37, 0x33, 0x86, 0x8d, 0x95,
|
||||
0x9d, 0xa8, 0xb4, 0xc9, 0xe7, 0x6d, 0x57, 0x4b, 0x43, 0x3e, 0x38, 0x37, 0x33, 0x87, 0x8b, 0x8f,
|
||||
0x96, 0x9d, 0xa7, 0xb5, 0xcb, 0x85, 0x8b, 0x93, 0x9b, 0xa6, 0xb3, 0xc7, 0xe5, 0x6b, 0x56, 0x4a,
|
||||
0x41, 0x3c, 0x36, 0x35, 0x32, 0x86, 0x89, 0x8e, 0x95, 0x9c, 0xa6, 0xb4, 0xca, 0x30
|
||||
},
|
||||
|
||||
{
|
||||
0x95, 0x95, 0x98, 0x9c, 0x9e, 0xa3, 0xaa, 0xb4, 0xb3, 0x98, 0x9c, 0xa1, 0xa7, 0xb1, 0xc0, 0x57,
|
||||
0x4f, 0x49, 0x48, 0x44, 0x42, 0x40, 0x40, 0x94, 0x95, 0x96, 0x9a, 0x9d, 0xa2, 0xa9, 0xb3, 0xa8,
|
||||
0xb1, 0x66, 0x59, 0x50, 0x4c, 0x4a, 0x46, 0x44, 0x41, 0x94, 0x97, 0x9b, 0x9e, 0xa4, 0xaa, 0xb3,
|
||||
0xc2, 0x59, 0x52, 0x4c, 0x4a, 0x46, 0x45, 0x43, 0x43, 0x96, 0x97, 0x99, 0x9d, 0x9f, 0xa5, 0xab,
|
||||
0xb5, 0xaa, 0xb4, 0xc2, 0x5a, 0x52, 0x4c, 0x4b, 0x47, 0x45, 0x43, 0x43, 0x96, 0x97, 0x99, 0x9d,
|
||||
0xa0, 0xa5, 0xab, 0xb5, 0x9d, 0xa3, 0xa9, 0xb3, 0xc2, 0x59, 0x51, 0x4b, 0x4a, 0x46, 0x44, 0x42,
|
||||
0x42, 0x96, 0x97, 0x98, 0x9c, 0x9f, 0xa4, 0xab, 0xb4, 0xa2, 0xa9, 0xb3, 0x41, 0x40, 0x40, 0x93,
|
||||
0x94, 0x96, 0x9a, 0x9d, 0xa2, 0xa8, 0xb2, 0x41, 0x3e, 0x92, 0x94, 0x99, 0x9b, 0xa2, 0xa7, 0xb1,
|
||||
0xc0, 0x57, 0x4f, 0x4a, 0x48, 0x44, 0x42, 0x40, 0x40, 0x94, 0x95, 0x97, 0x9a, 0x9d, 0xa2, 0xa9,
|
||||
0xb3, 0x48, 0x45, 0x43, 0x41, 0x94, 0x97, 0x9b, 0x9d, 0xa3, 0xa9, 0xb3, 0xc1, 0x59, 0x51, 0x4b,
|
||||
0x4a, 0x45, 0x44, 0x42, 0x42, 0x95, 0x97, 0x98, 0x9c, 0x9f, 0xa4, 0xab, 0xb4, 0x92, 0x95, 0x99,
|
||||
0x9c, 0xa2, 0xa8, 0xb1, 0xc0, 0x57, 0x4f, 0x4a, 0x48, 0x44, 0x42, 0x41, 0x41, 0x94, 0x95, 0x97,
|
||||
0x9b, 0x9e, 0xa3, 0xa9, 0xb3, 0x3e, 0x92, 0x93, 0x95, 0x98, 0x9b, 0xa0, 0xa7, 0xb1, 0x65, 0x58,
|
||||
0x50, 0x4b, 0x49, 0x45, 0x43, 0x41, 0x94, 0x97, 0x9b, 0x9e, 0xa4, 0xa9, 0xb3, 0xc2, 0x59, 0x51,
|
||||
0x4b, 0x4a, 0x46, 0x45, 0x42, 0x42, 0x96, 0x96, 0x99, 0x9c, 0x9f, 0xa4, 0xab, 0xb5, 0x4d, 0x4b,
|
||||
0x47, 0x45, 0x43, 0x43, 0x97, 0x97, 0x9a, 0x9d, 0xa0, 0xa5, 0xac, 0xb6, 0x41, 0x42
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
0x93, 0x93, 0x93, 0x94, 0x95, 0x99, 0x9c, 0xa1, 0xa8, 0x4e, 0x48, 0x45, 0x43, 0x44, 0x42, 0x42,
|
||||
0x95, 0x95, 0x95, 0x96, 0x97, 0x98, 0x9b, 0x9e, 0xa6, 0x43, 0x41, 0x41, 0x95, 0x94, 0x94, 0x95,
|
||||
0x97, 0x9b, 0x9d, 0xa3, 0xa9, 0x4f, 0x4a, 0x46, 0x45, 0x45, 0x43, 0x43, 0x97, 0x96, 0x96, 0x97,
|
||||
0x99, 0x9a, 0x9c, 0x9f, 0xa7, 0x94, 0x93, 0x94, 0x96, 0x9a, 0x9d, 0xa2, 0xa9, 0x4f, 0x49, 0x45,
|
||||
0x44, 0x45, 0x43, 0x43, 0x96, 0x96, 0x96, 0x96, 0x98, 0x99, 0x9c, 0x9f, 0xa7, 0x93, 0x93, 0x93,
|
||||
0x93, 0x95, 0x96, 0x99, 0x9c, 0xa4, 0x50, 0x4b, 0x49, 0x45, 0x44, 0x42, 0x42, 0x95, 0x95, 0x95,
|
||||
0x96, 0x97, 0x9b, 0x9e, 0xa3, 0xaa, 0x50, 0x4b, 0x46, 0x46, 0x46, 0x44, 0x44, 0x97, 0x97, 0x97,
|
||||
0x97, 0x99, 0x9a, 0x9d, 0x9f, 0xa8, 0x47, 0x46, 0x46, 0x44, 0x44, 0x98, 0x98, 0x97, 0x98, 0x9a,
|
||||
0x9b, 0x9d, 0xa0, 0xa8, 0x42, 0x96, 0x95, 0x95, 0x96, 0x98, 0x98, 0x9b, 0x9e, 0xa6, 0xa6, 0x93,
|
||||
0x95, 0x99, 0x9c, 0xa1, 0xa7, 0x4e, 0x48, 0x44, 0x43, 0x44, 0x41, 0x42, 0x95, 0x95, 0x95, 0x95,
|
||||
0x97, 0x98, 0x9b, 0x9e, 0xa6, 0x9d, 0xa5, 0x52, 0x4c, 0x4b, 0x46, 0x45, 0x42, 0x43, 0x97, 0x96,
|
||||
0x96, 0x97, 0x98, 0x9c, 0x9f, 0xa4, 0xab, 0x51, 0x4b, 0x48, 0x46, 0x47, 0x44, 0x45, 0x98, 0x98,
|
||||
0x98, 0x98, 0x9a, 0x9b, 0x9e, 0xa0, 0xa8, 0x9f, 0xa4, 0xab, 0x51, 0x4c, 0x48, 0x47, 0x47, 0x45,
|
||||
0x45, 0x99, 0x98, 0x98, 0x99, 0x9a, 0x9b, 0x9e, 0xa1, 0xa9, 0x98, 0x9d, 0x9f, 0xa4, 0xab, 0x51,
|
||||
0x4b, 0x47, 0x47, 0x47, 0x45, 0x45, 0x98, 0x98, 0x98, 0x98, 0x9a, 0x9b, 0x9e, 0xa1, 0xa8, 0x9c,
|
||||
0x9f, 0xa7, 0x42, 0x42, 0x95, 0x95, 0x95, 0x96, 0x97, 0x98, 0x9b, 0x9e, 0xa6, 0x3f
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
0x94, 0x93, 0x92, 0x92, 0x93, 0x95, 0x96, 0x99, 0x9c, 0x43, 0x43, 0x43, 0x41, 0x41, 0x42, 0x95,
|
||||
0x95, 0x95, 0x94, 0x94, 0x94, 0x95, 0x97, 0x97, 0x9a, 0x40, 0x40, 0x41, 0x95, 0x95, 0x94, 0x95,
|
||||
0x95, 0x97, 0x97, 0x9a, 0x9e, 0x45, 0x44, 0x44, 0x42, 0x42, 0x43, 0x97, 0x96, 0x96, 0x96, 0x96,
|
||||
0x95, 0x96, 0x98, 0x99, 0x9c, 0x94, 0x94, 0x94, 0x94, 0x96, 0x97, 0x9a, 0x9d, 0x44, 0x43, 0x44,
|
||||
0x42, 0x42, 0x43, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x96, 0x98, 0x98, 0x9b, 0x93, 0x93, 0x93,
|
||||
0x92, 0x92, 0x93, 0x95, 0x95, 0x98, 0x49, 0x44, 0x43, 0x44, 0x42, 0x42, 0x43, 0x96, 0x96, 0x96,
|
||||
0x95, 0x96, 0x98, 0x99, 0x9b, 0x9f, 0x46, 0x45, 0x45, 0x43, 0x44, 0x44, 0x98, 0x98, 0x97, 0x97,
|
||||
0x97, 0x97, 0x97, 0x99, 0x9a, 0x9d, 0x45, 0x43, 0x43, 0x44, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97,
|
||||
0x97, 0x99, 0x9a, 0x9d, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x96, 0x97, 0x9a, 0x9a, 0x92,
|
||||
0x93, 0x94, 0x95, 0x98, 0x9c, 0x43, 0x42, 0x43, 0x40, 0x40, 0x41, 0x95, 0x95, 0x94, 0x94, 0x94,
|
||||
0x93, 0x94, 0x96, 0x97, 0x9a, 0x96, 0x99, 0x4a, 0x45, 0x44, 0x44, 0x42, 0x42, 0x43, 0x97, 0x96,
|
||||
0x96, 0x96, 0x97, 0x98, 0x99, 0x9c, 0xa0, 0x47, 0x46, 0x46, 0x44, 0x44, 0x45, 0x98, 0x98, 0x98,
|
||||
0x98, 0x97, 0x97, 0x98, 0x99, 0x9a, 0x9d, 0x9a, 0x9c, 0xa0, 0x47, 0x46, 0x46, 0x44, 0x44, 0x45,
|
||||
0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x98, 0x9a, 0x9a, 0x9e, 0x97, 0x98, 0x99, 0x9c, 0xa0, 0x47,
|
||||
0x46, 0x46, 0x44, 0x44, 0x45, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, 0x98, 0x9a, 0x9a, 0x9d, 0x98,
|
||||
0x99, 0x9c, 0x42, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x95, 0x96, 0x97, 0x9a, 0x40
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
0xe6, 0x1c, 0x87, 0xcb, 0x42, 0x9b, 0x87, 0x35, 0xd8, 0x1c, 0xa3, 0x58, 0x84, 0xa4, 0x28, 0x71,
|
||||
0xd9, 0x3e, 0x82, 0xbb, 0x28, 0xd2, 0x80, 0x63, 0xe0, 0x38, 0x71, 0xcb, 0x22, 0x81, 0x9b, 0x83,
|
||||
0xa4, 0x28, 0x71, 0xd8, 0x3e, 0x81, 0xbb, 0x28, 0xd2, 0x80, 0x63, 0xe0, 0x37, 0x71, 0xcb, 0x22,
|
||||
0x81, 0x9b, 0xa3, 0x57, 0x83, 0xa3, 0x28, 0x70, 0xd8, 0x3e, 0x81, 0xba, 0x28, 0xd1, 0x80, 0x63,
|
||||
0xe0, 0x37, 0x70, 0xcb, 0x22, 0x81, 0x9b, 0x23, 0x82, 0x9b, 0x28, 0xd2, 0x80, 0x63, 0xe1, 0x38,
|
||||
0x71, 0xcc, 0x23, 0x81, 0x9b, 0x9c, 0x88, 0x36, 0xd9, 0x1d, 0xa4, 0x58, 0x84, 0xa5, 0x28, 0x72,
|
||||
0xd9, 0x3f, 0x82, 0xbb, 0x29, 0xd2, 0x81, 0x64, 0xe1, 0x38, 0x72, 0xcc, 0x23, 0x82, 0x9b, 0xcc,
|
||||
0x43, 0x9c, 0x88, 0x36, 0xd8, 0x1d, 0xa4, 0x58, 0x84, 0xa5, 0x29, 0x71, 0xd9, 0x3f, 0x82, 0xbc,
|
||||
0x29, 0xd2, 0x81, 0x64, 0xe1, 0x39, 0x72, 0xcc, 0x23, 0x82, 0x9c, 0x37, 0xd9, 0x1d, 0xa4, 0x59,
|
||||
0x85, 0xa6, 0x29, 0x72, 0xda, 0x40, 0x83, 0xbc, 0x2a, 0xd3, 0x82, 0x64, 0xe2, 0x39, 0x72, 0xcc,
|
||||
0x24, 0x82, 0x9c, 0x82, 0x64, 0xe1, 0x3a, 0x72, 0xcc, 0x24, 0x82, 0x9c, 0x40, 0xe8, 0x1e, 0x89,
|
||||
0xcd, 0x44, 0x9d, 0x89, 0x37, 0xd9, 0x1e, 0xa5, 0x59, 0x85, 0xa6, 0x2a, 0x73, 0xda, 0x40, 0x84,
|
||||
0xbd, 0x2a, 0xd3, 0x82, 0x65, 0xe2, 0x39, 0x73, 0xcd, 0x24, 0x83, 0x9c, 0x40, 0x83, 0xbd, 0x2a,
|
||||
0xd3, 0x82, 0x65, 0xe2, 0x39, 0x73, 0xcd, 0x24, 0x83, 0x9c, 0xd2, 0x81, 0x63, 0xe0, 0x39, 0x71,
|
||||
0xcc, 0x23, 0x82, 0x9b, 0x9b, 0x1d, 0xa4, 0x59, 0x84, 0xa5, 0x29, 0x72, 0xd9, 0x3f, 0x83, 0xbc,
|
||||
0x29, 0xd3, 0x81, 0x64, 0xe1, 0x39, 0x72, 0xcc, 0x24, 0x82, 0x9c, 0x82, 0x9c, 0x3f
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
0xe7, 0x89, 0x1b, 0x8b, 0xe6, 0x89, 0x1b, 0x8b, 0xe6, 0x89, 0x1b, 0x8a, 0xe6, 0x88, 0x1b, 0x8a,
|
||||
0xe6, 0x88, 0x1a, 0x8a, 0x1c, 0x8b, 0xe7, 0x89, 0x1b, 0x8b, 0xe6, 0x89, 0x1b, 0x8a, 0xe6, 0x89,
|
||||
0x1b, 0x8a, 0xe6, 0x89, 0x1b, 0x8a, 0xe6, 0x89, 0x1a, 0x8a, 0xe6, 0x88, 0x1a, 0x89, 0xe5, 0x88,
|
||||
0x1a, 0x89, 0xe5, 0x88, 0x1a, 0xe5, 0x88, 0x1a, 0x89, 0xe5, 0x88, 0x1a, 0x89, 0xe4, 0x87, 0x19,
|
||||
0x89, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x1a, 0x8a, 0xe5, 0x88, 0x1a, 0x89, 0xe5, 0x88,
|
||||
0x1a, 0x89, 0xe5, 0x88, 0x1a, 0x89, 0xe4, 0x87, 0x19, 0x89, 0xe4, 0x87, 0x19, 0xe4, 0x87, 0x19,
|
||||
0xe4, 0x87, 0x1a, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0x1a, 0x89, 0xe5, 0x88,
|
||||
0x1a, 0x89, 0xe5, 0x88, 0x1a, 0x89, 0xe5, 0x87, 0x1a, 0x89, 0xe4, 0x88, 0x19, 0x89, 0xe4, 0x87,
|
||||
0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87,
|
||||
0x19, 0x88, 0xe3, 0x86, 0x19, 0x88, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x88, 0xe3, 0x86,
|
||||
0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86,
|
||||
0x18, 0x87, 0xe2, 0x85, 0x18, 0x87, 0xe3, 0x85, 0x17, 0x19, 0x88, 0xe3, 0x86, 0x19, 0x88, 0xe4,
|
||||
0x86, 0x19, 0x88, 0xe3, 0x86, 0x18, 0x88, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3,
|
||||
0x86, 0x18, 0x87, 0xe3, 0x85, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3,
|
||||
0x85, 0x18, 0x87, 0x19, 0x88, 0xe3, 0x86, 0x19, 0x88, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18,
|
||||
0x87, 0x1a, 0x89, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x1b, 0x89, 0x1c, 0x8b
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
0xa1, 0xe6, 0xcf, 0x79, 0x58, 0x4a, 0x78, 0x7a, 0x53, 0x7b, 0xc2, 0xc3, 0x82, 0x36, 0x48, 0x84,
|
||||
0xcb, 0xa6, 0x67, 0x2e, 0x49, 0x7c, 0xaa, 0x93, 0x87, 0x73, 0x62, 0x6c, 0xa4, 0xaa, 0x71, 0xa7,
|
||||
0x67, 0x2f, 0x4a, 0x7c, 0xab, 0x94, 0x87, 0x74, 0x62, 0x6d, 0xa4, 0xab, 0x72, 0x7b, 0xaa, 0x93,
|
||||
0x87, 0x72, 0x61, 0x6c, 0xa4, 0xaa, 0x71, 0x72, 0x7b, 0xc2, 0xc3, 0x81, 0x36, 0x48, 0x84, 0xcb,
|
||||
0xa6, 0x67, 0x2e, 0x49, 0x7b, 0xaa, 0x93, 0x87, 0x72, 0x61, 0x6c, 0xa4, 0xaa, 0x71, 0xaa, 0x71,
|
||||
0x59, 0xa0, 0xe5, 0xce, 0x78, 0x57, 0x49, 0x77, 0x79, 0x52, 0x7a, 0xc1, 0xc2, 0x81, 0x35, 0x47,
|
||||
0x83, 0xca, 0xa6, 0x66, 0x2d, 0x48, 0x7b, 0xa9, 0x92, 0x86, 0x72, 0x61, 0x6b, 0xa3, 0xa9, 0x70,
|
||||
0x82, 0x36, 0x49, 0x84, 0xcc, 0xa7, 0x67, 0x2e, 0x4a, 0x7c, 0xab, 0x94, 0x87, 0x73, 0x62, 0x6c,
|
||||
0xa4, 0xab, 0x72, 0xc2, 0xc3, 0x82, 0x36, 0x48, 0x84, 0xcb, 0xa6, 0x67, 0x2e, 0x4a, 0x7c, 0xaa,
|
||||
0x93, 0x87, 0x73, 0x62, 0x6c, 0xa4, 0xaa, 0x71, 0xa3, 0xaa, 0x70, 0x49, 0x7b, 0xa9, 0x92, 0x86,
|
||||
0x72, 0x61, 0x6b, 0xa3, 0xaa, 0x70, 0x4b, 0x78, 0x7a, 0x53, 0x7c, 0xc2, 0xc3, 0x82, 0x36, 0x49,
|
||||
0x84, 0xcc, 0xa6, 0x67, 0x2f, 0x4a, 0x7c, 0xaa, 0x93, 0x87, 0x73, 0x62, 0x6c, 0xa4, 0xab, 0x72,
|
||||
0x7b, 0x5a, 0x4c, 0x7a, 0x7c, 0x55, 0x7e, 0xc4, 0xc5, 0x83, 0x38, 0x4a, 0x85, 0xcd, 0xa8, 0x69,
|
||||
0x30, 0x4b, 0x7d, 0xac, 0x95, 0x88, 0x74, 0x63, 0x6e, 0xa5, 0xac, 0x73, 0x7c, 0x55, 0x7d, 0xc4,
|
||||
0xc5, 0x83, 0x37, 0x4a, 0x85, 0xcd, 0xa8, 0x68, 0x30, 0x4b, 0x7d, 0xac, 0x95, 0x88, 0x74, 0x63,
|
||||
0x6e, 0xa6, 0xac, 0x73, 0xab, 0x94, 0x87, 0x73, 0x62, 0x6d, 0xa5, 0xab, 0x72, 0x5a
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
0xbf, 0xdc, 0xd4, 0xaa, 0x82, 0x81, 0x35, 0x34, 0x4d, 0x75, 0x95, 0xcb, 0xde, 0xc9, 0x91, 0x72,
|
||||
0x4a, 0x30, 0x6b, 0x57, 0x69, 0x7d, 0x65, 0x3f, 0x33, 0x4f, 0x69, 0x81, 0xc1, 0xde, 0xd6, 0xac,
|
||||
0x83, 0x82, 0x37, 0x36, 0x4f, 0x77, 0x96, 0xcd, 0xe0, 0xca, 0x93, 0x73, 0x4c, 0x31, 0x6d, 0x58,
|
||||
0x6a, 0x4f, 0x68, 0x80, 0xc0, 0xdd, 0xd5, 0xab, 0x82, 0x82, 0x36, 0x35, 0x4e, 0x76, 0x95, 0xcc,
|
||||
0xdf, 0xca, 0x92, 0x73, 0x4b, 0x31, 0x6c, 0x57, 0x6a, 0xe0, 0xca, 0x92, 0x73, 0x4c, 0x31, 0x6c,
|
||||
0x58, 0x6a, 0xad, 0xd5, 0xdb, 0xbc, 0x7b, 0x63, 0x3c, 0x31, 0x4e, 0x66, 0x7e, 0xbe, 0xdb, 0xd3,
|
||||
0xaa, 0x81, 0x80, 0x34, 0x33, 0x4c, 0x75, 0x94, 0xcb, 0xde, 0xc8, 0x91, 0x71, 0x4a, 0x2f, 0x6b,
|
||||
0x56, 0x68, 0x35, 0x4e, 0x76, 0x95, 0xcc, 0xdf, 0xca, 0x92, 0x72, 0x4b, 0x30, 0x6c, 0x57, 0x6a,
|
||||
0xcc, 0xdf, 0xca, 0x91, 0x72, 0x4b, 0x30, 0x6c, 0x57, 0x69, 0x69, 0x7e, 0xbe, 0xdb, 0xd3, 0xa9,
|
||||
0x81, 0x80, 0x34, 0x33, 0x4c, 0x74, 0x94, 0xcb, 0xdd, 0xc8, 0x90, 0x71, 0x4a, 0x2f, 0x6b, 0x55,
|
||||
0x68, 0x56, 0x69, 0xac, 0xd4, 0xd9, 0xbb, 0x7a, 0x62, 0x3c, 0x30, 0x4c, 0x65, 0x7d, 0xbd, 0xda,
|
||||
0xd2, 0xa8, 0x80, 0x7f, 0x34, 0x33, 0x4c, 0x74, 0x94, 0xca, 0xdd, 0xc8, 0x90, 0x71, 0x49, 0x2e,
|
||||
0x6a, 0x55, 0x67, 0xd3, 0xa9, 0x81, 0x80, 0x34, 0x33, 0x4c, 0x74, 0x94, 0xca, 0xde, 0xc8, 0x91,
|
||||
0x71, 0x4a, 0x2f, 0x6a, 0x56, 0x68, 0xbd, 0xda, 0xd2, 0xa8, 0x7f, 0x7e, 0x33, 0x32, 0x4b, 0x73,
|
||||
0x92, 0xc9, 0xdc, 0xc7, 0x8f, 0x70, 0x49, 0x2e, 0x69, 0x54, 0x67, 0x6a, 0x56, 0x68, 0x93, 0xca,
|
||||
0xdd, 0xc8, 0x90, 0x70, 0x49, 0x2e, 0x6a, 0x55, 0x68, 0x3d, 0x31, 0x4e, 0x67, 0x7f
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
void upd1771c_reset(struct upd1771c_t *scv) {
|
||||
memset(scv->upd1771c_packets,0,16);
|
||||
scv->upd1771c_mode = 0;
|
||||
scv->upd1771c_pos = 0;
|
||||
scv->upd1771c_posc = 0;
|
||||
scv->upd1771c_wave = 0;
|
||||
scv->upd1771c_vol = 0;
|
||||
scv->upd1771c_period = 0;
|
||||
scv->upd1771c_off = 0;
|
||||
scv->upd1771c_npos = 0;
|
||||
//scv->upd1771c_repsamp = 0;
|
||||
}
|
||||
|
||||
void upd1771c_write_packet(struct upd1771c_t *scv, uint8_t ind, uint8_t val) {
|
||||
scv->upd1771c_packets[ind&15] = val;
|
||||
switch (scv->upd1771c_packets[0]) {
|
||||
case 1:
|
||||
if (ind == 3) {
|
||||
scv->upd1771c_mode = 1;
|
||||
scv->upd1771c_wave = (scv->upd1771c_packets[1]&0xe0)>>5;
|
||||
scv->upd1771c_off = 0; //?
|
||||
scv->upd1771c_period = scv->upd1771c_packets[2];
|
||||
scv->upd1771c_vol = scv->upd1771c_packets[3]&0x1f;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ind == 3) {
|
||||
scv->upd1771c_mode = 2;
|
||||
scv->upd1771c_wave = (scv->upd1771c_packets[1]&0xe0)>>5;
|
||||
scv->upd1771c_off = scv->upd1771c_packets[1]&0x1f;
|
||||
scv->upd1771c_period = scv->upd1771c_packets[2]<0x20?0x20:scv->upd1771c_packets[2];
|
||||
scv->upd1771c_vol = scv->upd1771c_packets[3]&0x1f;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case 0:
|
||||
scv->upd1771c_mode = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void upd1771c_sound_set_clock(struct upd1771c_t *scv, unsigned int clock, unsigned int divi) {
|
||||
scv->upd1771c_repsamp = divi;
|
||||
}
|
||||
|
||||
int16_t upd1771c_sound_stream_update(struct upd1771c_t *scv) {
|
||||
int16_t s = 0;
|
||||
for (int i = 0; i < scv->upd1771c_repsamp; i++) {
|
||||
s = 0;
|
||||
switch (scv->upd1771c_mode) {
|
||||
case 2:
|
||||
s = ((int16_t)WAVEFORMS[scv->upd1771c_wave][scv->upd1771c_posc])*scv->upd1771c_vol;
|
||||
scv->upd1771c_pos++;
|
||||
if (scv->upd1771c_pos >= scv->upd1771c_period) {
|
||||
scv->upd1771c_pos=0;
|
||||
scv->upd1771c_posc++;
|
||||
if (scv->upd1771c_posc == 32)
|
||||
scv->upd1771c_posc = scv->upd1771c_off;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
scv->upd1771c_pos++;
|
||||
if (scv->upd1771c_pos >= ((((uint32_t)scv->upd1771c_period) + 1)*128)) {
|
||||
scv->upd1771c_pos=0;
|
||||
scv->upd1771c_posc++;
|
||||
if (scv->upd1771c_posc == NOISE_SIZE)
|
||||
scv->upd1771c_posc = 0;
|
||||
}
|
||||
uint16_t p = scv->upd1771c_posc;
|
||||
p = p>=254?253:p;
|
||||
s = ((int16_t)(noise_tbl[scv->upd1771c_wave][p])-127)*scv->upd1771c_vol;
|
||||
// inaccurate noise mixing :/
|
||||
// s |= (scv->upd1771c_npos&128)?127*scv->upd1771c_vol:0;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#ifndef __UPD1771C_SOUND_H__
|
||||
#define __UPD1771C_SOUND_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct upd1771c_t {
|
||||
uint8_t upd1771c_packets[16];
|
||||
uint8_t upd1771c_mode;
|
||||
uint32_t upd1771c_pos;
|
||||
uint8_t upd1771c_off;
|
||||
uint8_t upd1771c_posc;
|
||||
uint8_t upd1771c_wave;
|
||||
uint8_t upd1771c_vol;
|
||||
uint8_t upd1771c_period;
|
||||
uint8_t upd1771c_npos;
|
||||
int upd1771c_repsamp;
|
||||
};
|
||||
|
||||
void upd1771c_reset(struct upd1771c_t *scv);
|
||||
void upd1771c_write_packet(struct upd1771c_t *scv, uint8_t ind, uint8_t val);
|
||||
int16_t upd1771c_sound_stream_update(struct upd1771c_t *scv);
|
||||
void upd1771c_sound_set_clock(struct upd1771c_t *scv, unsigned int clock, unsigned int divi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -146,6 +146,7 @@ enum DivSystem {
|
|||
DIV_SYSTEM_UPD1771C,
|
||||
DIV_SYSTEM_SID3,
|
||||
DIV_SYSTEM_C64_PCM,
|
||||
DIV_SYSTEM_UPD1771C_TONE,
|
||||
|
||||
DIV_SYSTEM_MAX
|
||||
};
|
||||
|
|
|
@ -2061,8 +2061,8 @@ void DivEngine::registerSystems() {
|
|||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_UPD1771C]=new DivSysDef(
|
||||
_("NEC μPD1771C"), NULL, 0xe4, 0, 1, false, true, 0, false, 0, 0, 0,
|
||||
_("this was an SoC with some funky wavetable/noise hardware"),
|
||||
_("NEC μPD1771C-017 (wave mode)"), NULL, 0xe4, 0, 1, false, true, 0, false, 0, 0, 0,
|
||||
_("a microcontroller which has been used as a sound generator in the Super Cassette Vision. this is the waveform mode."),
|
||||
{_("Wave/Noise")},
|
||||
{"W"},
|
||||
{DIV_CH_NOISE},
|
||||
|
@ -2074,6 +2074,17 @@ void DivEngine::registerSystems() {
|
|||
}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_UPD1771C_TONE]=new DivSysDef(
|
||||
_("NEC μPD1771C-017 (tone mode)"), NULL, 0xe5, 0, 4, false, true, 0, false, 0, 0, 0,
|
||||
_("a microcontroller which has been used as a sound generator in the Super Cassette Vision. this is the tone mode."),
|
||||
{_("Square 1"), _("Square 2"), _("Square 3"), _("Noise")},
|
||||
{"W"},
|
||||
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE},
|
||||
{DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_UPD1771C},
|
||||
{},
|
||||
{}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_SM8521]=new DivSysDef(
|
||||
_("Sharp SM8521"), NULL, 0xc8, 0, 3, false, true, 0, false, 0, 32, 16,
|
||||
_("a SoC with wavetable sound hardware."),
|
||||
|
|
|
@ -139,6 +139,7 @@ const char* aboutLine[]={
|
|||
_N("MAME YMZ280B core by Aaron Giles"),
|
||||
_N("MAME GA20 core by Acho A. Tang and R. Belmont"),
|
||||
_N("MAME SegaPCM core by Hiromitsu Shioya and Olivier Galibert"),
|
||||
_N("MAME µPD1771C-017 HLE core by David Viens"),
|
||||
_N("SAASound by Dave Hooper and Simon Owen"),
|
||||
_N("SameBoy by Lior Halphon"),
|
||||
_N("Mednafen PCE, WonderSwan, T6W28 and Virtual Boy audio cores"),
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
#define FM_PREVIEW_SIZE 512
|
||||
|
||||
#define CHECK_HIDDEN_SYSTEM(x) \
|
||||
(x==DIV_SYSTEM_YMU759 || x==DIV_SYSTEM_UPD1771C || x==DIV_SYSTEM_DUMMY || x==DIV_SYSTEM_SEGAPCM_COMPAT || x==DIV_SYSTEM_PONG)
|
||||
(x==DIV_SYSTEM_YMU759 || x==DIV_SYSTEM_DUMMY || x==DIV_SYSTEM_SEGAPCM_COMPAT || x==DIV_SYSTEM_PONG)
|
||||
|
||||
enum FurnaceGUIRenderBackend {
|
||||
GUI_BACKEND_SDL=0,
|
||||
|
|
|
@ -1320,6 +1320,7 @@ const int availableSystems[]={
|
|||
DIV_SYSTEM_OPL4_DRUMS,
|
||||
DIV_SYSTEM_SUPERVISION,
|
||||
DIV_SYSTEM_UPD1771C,
|
||||
DIV_SYSTEM_UPD1771C_TONE,
|
||||
DIV_SYSTEM_SID3,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
@ -1425,6 +1426,7 @@ const int chipsSpecial[]={
|
|||
DIV_SYSTEM_SID2,
|
||||
DIV_SYSTEM_SUPERVISION,
|
||||
DIV_SYSTEM_UPD1771C,
|
||||
DIV_SYSTEM_UPD1771C_TONE,
|
||||
DIV_SYSTEM_SID3,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
|
|
@ -1561,13 +1561,23 @@ void FurnaceGUI::initSystemPresets() {
|
|||
}
|
||||
);
|
||||
ENTRY(
|
||||
_("Sord M5"), {
|
||||
CH(DIV_SYSTEM_SMS, 1.0f, 0,
|
||||
"customClock=1773447\n"
|
||||
"chipType=1\n"
|
||||
)
|
||||
}
|
||||
);
|
||||
_("Sord M5"), {
|
||||
CH(DIV_SYSTEM_SMS, 1.0f, 0,
|
||||
"customClock=1773447\n"
|
||||
"chipType=1\n"
|
||||
)
|
||||
}
|
||||
);
|
||||
ENTRY(
|
||||
"Epoch Super Cassette Vision (wave mode)", {
|
||||
CH(DIV_SYSTEM_UPD1771C, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
ENTRY(
|
||||
"Epoch Super Cassette Vision (tone mode)", {
|
||||
CH(DIV_SYSTEM_UPD1771C_TONE, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
CATEGORY_END;
|
||||
|
||||
CATEGORY_BEGIN(_("Arcade systems"),_("INSERT COIN"));
|
||||
|
|
|
@ -2649,6 +2649,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
case DIV_SYSTEM_BIFURCATOR:
|
||||
case DIV_SYSTEM_POWERNOISE:
|
||||
case DIV_SYSTEM_UPD1771C:
|
||||
case DIV_SYSTEM_UPD1771C_TONE:
|
||||
break;
|
||||
case DIV_SYSTEM_YMU759:
|
||||
case DIV_SYSTEM_ESFM:
|
||||
|
|
|
@ -286,7 +286,8 @@ const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) {
|
|||
return "Watara Supervision";
|
||||
break;
|
||||
case DIV_SYSTEM_UPD1771C:
|
||||
return "μPD1771C";
|
||||
case DIV_SYSTEM_UPD1771C_TONE:
|
||||
return "μPD1771C-017";
|
||||
break;
|
||||
default:
|
||||
return FurnaceGUI::getSystemName(sys);
|
||||
|
|
|
@ -315,6 +315,7 @@ TAParamResult pVersion(String) {
|
|||
printf("- MAME YMZ280B core by Aaron Giles (BSD 3-clause)\n");
|
||||
printf("- MAME GA20 core by Acho A. Tang and R. Belmont (BSD 3-clause)\n");
|
||||
printf("- MAME SegaPCM core by Hiromitsu Shioya and Olivier Galibert (BSD 3-clause)\n");
|
||||
printf("- MAME µPD1771C-017 HLE core by David Viens (BSD 3-clause)\n");
|
||||
printf("- QSound core by superctr (BSD 3-clause)\n");
|
||||
printf("- VICE VIC-20 by Rami Rasanen and viznut (GPLv2)\n");
|
||||
printf("- VICE TED by Andreas Boose, Tibor Biczo and Marco van den Heuvel (GPLv2)\n");
|
||||
|
|
Loading…
Reference in a new issue