From 859182bb089a53b0f3e48bc2dfa72a70203e52ab Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 27 Aug 2023 18:46:10 -0500 Subject: [PATCH] C219: initial work --- papers/format.md | 2 +- papers/newIns.md | 1 + src/engine/dispatchContainer.cpp | 5 + src/engine/engine.h | 4 +- src/engine/instrument.cpp | 4 + src/engine/instrument.h | 1 + src/engine/platform/c140.cpp | 224 ++++++++++++++++++++++--------- src/engine/platform/c140.h | 6 +- src/engine/song.h | 3 +- src/engine/sysDef.cpp | 14 ++ src/gui/furIcons.h | 5 +- src/gui/gui.h | 1 + src/gui/guiConst.cpp | 6 +- 13 files changed, 207 insertions(+), 69 deletions(-) diff --git a/papers/format.md b/papers/format.md index a09579bd..66bec724 100644 --- a/papers/format.md +++ b/papers/format.md @@ -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 diff --git a/papers/newIns.md b/papers/newIns.md index 4ef3be31..27a505c1 100644 --- a/papers/newIns.md +++ b/papers/newIns.md @@ -120,6 +120,7 @@ the following instrument types are available: - 50: K053260 - 52: TED - 53: C140 +- 54: C219 the following feature codes are recognized: diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 49222c39..8ff1a33c 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -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; diff --git a/src/engine/engine.h b/src/engine/engine.h index 7fb6b511..8df2652d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -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 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 842b88fc..28cb99bc 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -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; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index cd8c5652..a019198f 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -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 }; diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index d95a3216..05aa963c 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -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>= 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; idata[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; hdata[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; icalcFreq(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].samplesong.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; ilength16; - // 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=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=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>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; irate=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>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 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); diff --git a/src/engine/song.h b/src/engine/song.h index f0510079..78c49b4e 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -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 { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 9fc6ab9d..f4273195 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1887,6 +1887,20 @@ void DivEngine::registerSystems() { {} ); + sysDefs[DIV_SYSTEM_C219]=new DivSysDef( + "Namco C219", NULL, 0xcf, 0, 16, false, true, 0x161, false, (1U<