C219: initial work

This commit is contained in:
tildearrow 2023-08-27 18:46:10 -05:00
parent 80961354f7
commit 859182bb08
13 changed files with 207 additions and 69 deletions

View File

@ -222,7 +222,7 @@ size | description
| - 0xcc: K053260 - 4 channels
| - 0xcd: TED - 2 channels
| - 0xce: Namco C140 - 24 channels
| - 0xcf: Namco C219 - 16 channels (UNAVAILABLE)
| - 0xcf: Namco C219 - 16 channels
| - 0xd0: Namco C352 - 32 channels (UNAVAILABLE)
| - 0xde: YM2610B extended - 19 channels
| - 0xe0: QSound - 19 channels

View File

@ -120,6 +120,7 @@ the following instrument types are available:
- 50: K053260
- 52: TED
- 53: C140
- 54: C219
the following feature codes are recognized:

View File

@ -587,6 +587,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
break;
case DIV_SYSTEM_C140:
dispatch=new DivPlatformC140;
((DivPlatformC140*)dispatch)->set219(false);
break;
case DIV_SYSTEM_C219:
dispatch=new DivPlatformC140;
((DivPlatformC140*)dispatch)->set219(true);
break;
case DIV_SYSTEM_PCM_DAC:
dispatch=new DivPlatformPCMDAC;

View File

@ -54,9 +54,9 @@
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
//#define DIV_UNSTABLE
#define DIV_UNSTABLE
#define DIV_VERSION "0.6pre9"
#define DIV_VERSION "dev169"
#define DIV_ENGINE_VERSION 169
// for imports
#define DIV_VERSION_MOD 0xff01

View File

@ -967,6 +967,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) {
featureSM=true;
featureSL=true;
break;
case DIV_INS_C219:
featureSM=true;
featureSL=true;
break;
case DIV_INS_MAX:
break;

View File

@ -84,6 +84,7 @@ enum DivInstrumentType: unsigned short {
// DIV_INS_YMF292=51,
DIV_INS_TED=52,
DIV_INS_C140=53,
DIV_INS_C219=54,
DIV_INS_MAX,
DIV_INS_NULL
};

View File

@ -49,11 +49,40 @@ const char** DivPlatformC140::getRegisterSheet() {
return regCheatSheetC140;
}
void DivPlatformC140::acquire(short** buf, size_t len) {
void DivPlatformC140::acquire_219(short** buf, size_t len) {
for (size_t h=0; h<len; h++) {
while (!writes.empty()) {
QueuedWrite w=writes.front();
c140_write(&c140, w.addr,w.val);
c219_write(&c219,w.addr,w.val);
regPool[w.addr&0x1ff]=w.val;
writes.pop();
}
c219_tick(&c219, 1);
// scale as 16bit
c219.lout >>= 10;
c219.rout >>= 10;
if (c219.lout<-32768) c219.lout=-32768;
if (c219.lout>32767) c219.lout=32767;
if (c219.rout<-32768) c219.rout=-32768;
if (c219.rout>32767) c219.rout=32767;
buf[0][h]=c219.lout;
buf[1][h]=c219.rout;
for (int i=0; i<totalChans; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=(c219.voice[i].lout+c219.voice[i].rout)>>10;
}
}
}
void DivPlatformC140::acquire_140(short** buf, size_t len) {
for (size_t h=0; h<len; h++) {
while (!writes.empty()) {
QueuedWrite w=writes.front();
c140_write(&c140,w.addr,w.val);
regPool[w.addr&0x1ff]=w.val;
writes.pop();
}
@ -72,14 +101,22 @@ void DivPlatformC140::acquire(short** buf, size_t len) {
buf[0][h]=c140.lout;
buf[1][h]=c140.rout;
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=(c140.voice[i].lout+c140.voice[i].rout)>>10;
}
}
}
void DivPlatformC140::acquire(short** buf, size_t len) {
if (is219) {
acquire_219(buf,len);
} else {
acquire_140(buf,len);
}
}
void DivPlatformC140::tick(bool sysTick) {
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
@ -144,26 +181,47 @@ void DivPlatformC140::tick(bool sysTick) {
chan[i].freq=(int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE));
if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>65535) chan[i].freq=65535;
ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0);
if (is219) {
ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?1:0);
} else {
ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0);
}
if (chan[i].keyOn) {
unsigned int bank=0;
unsigned int start=0;
unsigned int loop=0;
unsigned int end=0;
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
bank=(sampleOff[chan[i].sample]>>16)&0xff;
start=sampleOff[chan[i].sample]&0xffff;
end=MIN(start+s->length8-1,65535);
if (is219) {
bank=(sampleOff[chan[i].sample]>>16)&0xff;
start=sampleOff[chan[i].sample]&0xffff;
end=MIN(start+(s->length8>>1)-1,65535);
logV("sampleOff[%d]=%d",chan[i].sample,sampleOff[chan[i].sample]);
} else {
bank=(sampleOff[chan[i].sample]>>16)&0xff;
start=sampleOff[chan[i].sample]&0xffff;
end=MIN(start+s->length8-1,65535);
}
}
if (chan[i].audPos>0) {
start=MIN(start+MIN(chan[i].audPos,s->length8),65535);
start=MIN(start+(MIN(chan[i].audPos,s->length8)>>1),65535);
}
if (s->isLoopable()) {
loop=MIN(start+s->loopStart,65535);
end=MIN(start+s->loopEnd-1,65535);
if (is219) {
loop=MIN(start+(s->loopStart>>1),65535);
end=MIN(start+(s->loopEnd>>1)-1,65535);
} else {
loop=MIN(start+s->loopStart,65535);
end=MIN(start+s->loopEnd-1,65535);
}
}
rWrite(0x05+(i<<4),0); // force keyoff first
rWrite(0x04+(i<<4),bank);
if (is219) {
// TODO; group banking
} else {
rWrite(0x04+(i<<4),bank);
}
rWrite(0x06+(i<<4),(start>>8)&0xff);
rWrite(0x07+(i<<4),start&0xff);
rWrite(0x08+(i<<4),(end>>8)&0xff);
@ -323,11 +381,15 @@ int DivPlatformC140::dispatch(DivCommand c) {
void DivPlatformC140::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
c140.voice[ch].muted=mute;
if (is219) {
c219.voice[ch].muted=mute;
} else {
c140.voice[ch].muted=mute;
}
}
void DivPlatformC140::forceIns() {
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
chan[i].insChanged=true;
chan[i].freqChanged=true;
chan[i].volChangedL=true;
@ -355,8 +417,12 @@ DivDispatchOscBuffer* DivPlatformC140::getOscBuffer(int ch) {
void DivPlatformC140::reset() {
while (!writes.empty()) writes.pop();
memset(regPool,0,512);
c140_reset(&c140);
for (int i=0; i<24; i++) {
if (is219) {
c219_reset(&c219);
} else {
c140_reset(&c140);
}
for (int i=0; i<totalChans; i++) {
chan[i]=DivPlatformC140::Channel();
chan[i].std.setEngine(parent);
rWrite(0x05+(i<<4),0);
@ -368,7 +434,7 @@ int DivPlatformC140::getOutputCount() {
}
void DivPlatformC140::notifyInsChange(int ins) {
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
@ -381,7 +447,7 @@ void DivPlatformC140::notifyWaveChange(int wave) {
}
void DivPlatformC140::notifyInsDeletion(void* ins) {
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
}
@ -437,53 +503,84 @@ void DivPlatformC140::renderSamples(int sysID) {
continue;
}
unsigned int length=s->length16;
// fit sample size to single bank size
if (length>(131072)) {
length=131072;
}
if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) {
memPos=((memPos+0x1ffff)&0xfe0000);
}
if (memPos>=(getSampleMemCapacity())) {
logW("out of C140 memory for sample %d!",i);
break;
}
// why is C140 not G.711-compliant? this weird bit mangling had me puzzled for 3 hours...
if (memPos+length>=(getSampleMemCapacity())) {
if (s->depth==DIV_SAMPLE_DEPTH_MULAW) {
for (unsigned int i=0; i<(getSampleMemCapacity())-memPos; i++) {
if (i>=s->lengthMuLaw) break;
unsigned char x=s->dataMuLaw[i]^0xff;
if (x&0x80) x^=15;
unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4);
sampleMem[i+(memPos/sizeof(short))]=((c140Mu)<<8);
}
} else {
memcpy(sampleMem+(memPos/sizeof(short)),s->data16,(getSampleMemCapacity())-memPos);
if (is219) { // C219 (8-bit)
unsigned int length=s->length8;
// fit sample size to single bank size
if (length>131072) {
length=131072;
}
if (length&1) length++;
if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) {
memPos=((memPos+0x1ffff)&0xfe0000);
}
if (memPos>=(getSampleMemCapacity())) {
logW("out of C219 memory for sample %d!",i);
break;
}
if (memPos+length>=(getSampleMemCapacity())) {
length=getSampleMemCapacity()-memPos;
logW("out of C219 memory for sample %d!",i);
}
logW("out of C140 memory for sample %d!",i);
} else {
if (s->depth==DIV_SAMPLE_DEPTH_MULAW) {
for (unsigned int i=0; i<length; i++) {
if (i>=s->lengthMuLaw) break;
unsigned char x=s->dataMuLaw[i]^0xff;
if (x&0x80) x^=15;
unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4);
sampleMem[i+(memPos/sizeof(short))]=((c140Mu)<<8);
if (i>=s->lengthMuLaw) {
sampleMem[i+memPos]=0;
} else {
unsigned char x=s->dataMuLaw[i]^0xff;
sampleMem[i+memPos]=x;
}
}
} else {
memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length);
for (unsigned int i=0; i<length; i++) {
if (i>=s->length8) {
sampleMem[memPos+i]=0;
} else {
sampleMem[memPos+i]=s->data8[i];
}
}
}
sampleOff[i]=memPos>>1;
sampleLoaded[i]=true;
memPos+=length;
} else { // C140 (16-bit)
unsigned int length=s->length16;
// fit sample size to single bank size
if (length>(131072)) {
length=131072;
}
if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) {
memPos=((memPos+0x1ffff)&0xfe0000);
}
if (memPos>=(getSampleMemCapacity())) {
logW("out of C140 memory for sample %d!",i);
break;
}
// why is C140 not G.711-compliant? this weird bit mangling had me puzzled for 3 hours...
if (memPos+length>=(getSampleMemCapacity())) {
length=getSampleMemCapacity()-memPos;
logW("out of C140 memory for sample %d!",i);
}
if (s->depth==DIV_SAMPLE_DEPTH_MULAW) {
for (unsigned int i=0; i<length; i+=2) {
if ((i>>1)>=s->lengthMuLaw) break;
unsigned char x=s->dataMuLaw[i>>1]^0xff;
if (x&0x80) x^=15;
unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4);
sampleMem[i+memPos]=0;
sampleMem[1+i+memPos]=c140Mu;
}
} else {
memcpy(sampleMem+memPos,s->data16,length);
}
sampleOff[i]=memPos>>1;
sampleLoaded[i]=true;
memPos+=length;
}
sampleOff[i]=memPos>>1;
sampleLoaded[i]=true;
memPos+=length;
}
sampleMemLen=memPos+256;
}
void DivPlatformC219::set219(bool is_219) {
void DivPlatformC140::set219(bool is_219) {
is219=is_219;
totalChans=is219?16:24;
}
@ -492,7 +589,7 @@ void DivPlatformC140::setFlags(const DivConfig& flags) {
chipClock=32000*256; // 8.192MHz and 12.288MHz input, verified from Assault Schematics
CHECK_CUSTOM_CLOCK;
rate=chipClock/192;
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
oscBuf[i]->rate=rate;
}
}
@ -502,23 +599,28 @@ int DivPlatformC140::init(DivEngine* p, int channels, int sugRate, const DivConf
dumpWrites=false;
skipRegisterWrites=false;
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
sampleMem=new short[getSampleMemCapacity()>>1];
sampleMem=new unsigned char[getSampleMemCapacity()];
sampleMemLen=0;
c140_init(&c140);
c140.sample_mem=sampleMem;
if (is219) {
c219_init(&c219);
c219.sample_mem=(signed char*)sampleMem;
} else {
c140_init(&c140);
c140.sample_mem=(short*)sampleMem;
}
setFlags(flags);
reset();
return 24;
return totalChans;
}
void DivPlatformC140::quit() {
delete[] sampleMem;
for (int i=0; i<24; i++) {
for (int i=0; i<totalChans; i++) {
delete oscBuf[i];
}
}

View File

@ -56,7 +56,7 @@ class DivPlatformC140: public DivDispatch {
bool is219;
int totalChans;
signed short* sampleMem;
unsigned char* sampleMem;
size_t sampleMemLen;
struct QueuedWrite {
unsigned short addr;
@ -67,10 +67,14 @@ class DivPlatformC140: public DivDispatch {
};
FixedQueue<QueuedWrite,2048> writes;
struct c140_t c140;
struct c219_t c219;
unsigned char regPool[512];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
void acquire_219(short** buf, size_t len);
void acquire_140(short** buf, size_t len);
public:
void acquire(short** buf, size_t len);
int dispatch(DivCommand c);

View File

@ -130,7 +130,8 @@ enum DivSystem {
DIV_SYSTEM_PV1000,
DIV_SYSTEM_K053260,
DIV_SYSTEM_TED,
DIV_SYSTEM_C140
DIV_SYSTEM_C140,
DIV_SYSTEM_C219
};
enum DivEffectType: unsigned short {

View File

@ -1887,6 +1887,20 @@ void DivEngine::registerSystems() {
{}
);
sysDefs[DIV_SYSTEM_C219]=new DivSysDef(
"Namco C219", NULL, 0xcf, 0, 16, false, true, 0x161, false, (1U<<DIV_SAMPLE_DEPTH_MULAW)|(1U<<DIV_SAMPLE_DEPTH_8BIT),
"Namco's PCM chip used in their NA1/2 hardware.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
{DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219, DIV_INS_C219},
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
{},
{
{0x10, {DIV_CMD_STD_NOISE_MODE, "10xx: Set noise/invert mode (bit 0: noise; bit 1: invert left output; bit 2: invert output)"}}
}
);
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false, 0,
"this is a system designed for testing purposes.",

View File

@ -1,7 +1,7 @@
// not auto-generated. update every time you change icons.ttf!
#define ICON_MIN_FUR 0xe0f0
#define ICON_MAX_FUR 0xe141
#define ICON_MAX_FUR 0xe142
// test
#define ICON_FUR_TEST0 u8"\ue0f0"
@ -65,6 +65,7 @@
#define ICON_FUR_INS_SCSP u8"\ue133"
#define ICON_FUR_INS_TED u8"\ue134"
#define ICON_FUR_INS_C140 u8"\ue135"
#define ICON_FUR_INS_C219 u8"\ue142"
// sample editor
#define ICON_FUR_SAMPLE_APPLY_SILENCE u8"\ue136"
@ -78,4 +79,4 @@
#define ICON_FUR_SAMPLE_RESIZE u8"\ue13e"
#define ICON_FUR_SAMPLE_REVERSE u8"\ue13f"
#define ICON_FUR_SAMPLE_SIGN u8"\ue140"
#define ICON_FUR_SAMPLE_TRIM u8"\ue141"
#define ICON_FUR_SAMPLE_TRIM u8"\ue141"

View File

@ -259,6 +259,7 @@ enum FurnaceGUIColors {
GUI_COLOR_INSTR_SCSP,
GUI_COLOR_INSTR_TED,
GUI_COLOR_INSTR_C140,
GUI_COLOR_INSTR_C219,
GUI_COLOR_INSTR_UNKNOWN,
GUI_COLOR_CHANNEL_BG,

View File

@ -174,6 +174,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={
{"SCSP",ICON_FA_QUESTION,ICON_FUR_INS_SCSP},
{"TED",ICON_FA_BAR_CHART,ICON_FUR_INS_TED},
{"C140",ICON_FA_VOLUME_UP,ICON_FUR_INS_C140},
{"C219",ICON_FA_VOLUME_UP,ICON_FUR_INS_C219},
{NULL,ICON_FA_QUESTION,ICON_FA_QUESTION}
};
@ -939,6 +940,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
D(GUI_COLOR_INSTR_SCSP,"",ImVec4(0.5f,0.5f,0.5f,1.0f)),
D(GUI_COLOR_INSTR_TED,"",ImVec4(0.7f,0.6f,1.0f,1.0f)),
D(GUI_COLOR_INSTR_C140,"",ImVec4(1.0f,1.0f,0.0f,1.0f)),
D(GUI_COLOR_INSTR_C219,"",ImVec4(1.0f,0.8f,0.0f,1.0f)),
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),
@ -1125,6 +1127,7 @@ const int availableSystems[]={
DIV_SYSTEM_K053260,
DIV_SYSTEM_TED,
DIV_SYSTEM_C140,
DIV_SYSTEM_C219,
DIV_SYSTEM_PCM_DAC,
DIV_SYSTEM_PONG,
0 // don't remove this last one!
@ -1236,6 +1239,7 @@ const int chipsSample[]={
DIV_SYSTEM_ES5506,
DIV_SYSTEM_K053260,
DIV_SYSTEM_C140,
DIV_SYSTEM_C219,
0 // don't remove this last one!
};
@ -1263,4 +1267,4 @@ const char* chipCategoryNames[]={
const char* insIcons[]={
ICON_FA_AREA_CHART,
};
};