Merge branch 'tildearrow:master' into guimprove
This commit is contained in:
commit
4078da6685
25 changed files with 533 additions and 114 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -45,15 +45,63 @@ const char* regCheatSheetC140[]={
|
|||
NULL
|
||||
};
|
||||
|
||||
const char* regCheatSheetC219[]={
|
||||
"CHx_RVol", "00+x*10",
|
||||
"CHx_LVol", "01+x*10",
|
||||
"CHx_FreqH", "02+x*10",
|
||||
"CHx_FreqL", "03+x*10",
|
||||
"CHx_Ctrl", "05+x*10",
|
||||
"CHx_StartH", "06+x*10",
|
||||
"CHx_StartL", "07+x*10",
|
||||
"CHx_EndH", "08+x*10",
|
||||
"CHx_EndL", "09+x*10",
|
||||
"CHx_LoopH", "0A+x*10",
|
||||
"CHx_LoopL", "0B+x*10",
|
||||
"BankA", "1F7",
|
||||
"BankB", "1F1",
|
||||
"BankC", "1F3",
|
||||
"BankD", "1F5",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformC140::getRegisterSheet() {
|
||||
return regCheatSheetC140;
|
||||
return is219?regCheatSheetC219: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 +120,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 +200,48 @@ 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)|(chan[i].invert?0x40:0)|(chan[i].surround?8:0)|(chan[i].noise?4: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)&3;
|
||||
start=sampleOff[chan[i].sample]&0xffff;
|
||||
end=MIN(start+(s->length8>>1)-1,65535);
|
||||
} 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) {
|
||||
if (groupBank[i>>2]!=bank) {
|
||||
groupBank[i>>2]=bank;
|
||||
}
|
||||
rWrite(0x1f1+(((3+(i>>2))&3)<<1),groupBank[i>>2]);
|
||||
} 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 +401,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,12 +437,19 @@ 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);
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
groupBank[i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformC140::getOutputCount() {
|
||||
|
|
@ -368,7 +457,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 +470,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);
|
||||
}
|
||||
}
|
||||
|
|
@ -411,7 +500,7 @@ const void* DivPlatformC140::getSampleMem(int index) {
|
|||
}
|
||||
|
||||
size_t DivPlatformC140::getSampleMemCapacity(int index) {
|
||||
return index == 0 ? 16777216 : 0;
|
||||
return index == 0 ? (is219?524288:16777216) : 0;
|
||||
}
|
||||
|
||||
size_t DivPlatformC140::getSampleMemUsage(int index) {
|
||||
|
|
@ -437,57 +526,93 @@ 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 DivPlatformC140::set219(bool is_219) {
|
||||
is219=is_219;
|
||||
totalChans=is219?16:24;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -497,23 +622,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];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@
|
|||
#define _C140_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include "sound/c140.h"
|
||||
#include "sound/c140_c219.h"
|
||||
#include "../fixedQueue.h"
|
||||
|
||||
class DivPlatformC140: public DivDispatch {
|
||||
struct Channel: public SharedChannel<int> {
|
||||
unsigned int audPos;
|
||||
int sample, wave;
|
||||
bool setPos, volChangedL, volChangedR;
|
||||
bool setPos, invert, surround, noise, volChangedL, volChangedR;
|
||||
int chPanL, chPanR;
|
||||
int chVolL, chVolR;
|
||||
int macroVolMul;
|
||||
|
|
@ -39,6 +39,9 @@ class DivPlatformC140: public DivDispatch {
|
|||
sample(-1),
|
||||
wave(-1),
|
||||
setPos(false),
|
||||
invert(false),
|
||||
surround(false),
|
||||
noise(false),
|
||||
volChangedL(false),
|
||||
volChangedR(false),
|
||||
chPanL(255),
|
||||
|
|
@ -53,8 +56,11 @@ class DivPlatformC140: public DivDispatch {
|
|||
bool isMuted[24];
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
bool is219;
|
||||
int totalChans;
|
||||
unsigned char groupBank[4];
|
||||
|
||||
signed short* sampleMem;
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
|
|
@ -65,10 +71,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);
|
||||
|
|
@ -95,6 +105,7 @@ class DivPlatformC140: public DivDispatch {
|
|||
size_t getSampleMemUsage(int index = 0);
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
void set219(bool is_219);
|
||||
void setFlags(const DivConfig& flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
============================================================================
|
||||
|
||||
MODIFIED Namco C140 sound emulator - MODIFIED VERSION
|
||||
MODIFIED Namco C140/C219 sound emulator - MODIFIED VERSION
|
||||
by cam900
|
||||
|
||||
MODIFICATION by tildearrow - adds muting function and fixes overflow
|
||||
|
|
@ -41,7 +41,7 @@ TODO:
|
|||
|
||||
*/
|
||||
|
||||
#include "c140.h"
|
||||
#include "c140_c219.h"
|
||||
|
||||
static int c140_max(int a, int b) { return (a > b) ? a : b; }
|
||||
static int c140_min(int a, int b) { return (a < b) ? a : b; }
|
||||
|
|
@ -61,6 +61,18 @@ void c140_tick(struct c140_t *c140, const int cycle)
|
|||
}
|
||||
}
|
||||
|
||||
void c219_tick(struct c219_t *c219, const int cycle)
|
||||
{
|
||||
c219->lout = 0;
|
||||
c219->rout = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
c219_voice_tick(c219, i, cycle);
|
||||
c219->lout += c219->voice[i].lout;
|
||||
c219->rout += c219->voice[i].rout;
|
||||
}
|
||||
}
|
||||
|
||||
void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle)
|
||||
{
|
||||
struct c140_voice_t *voice = &c140->voice[v];
|
||||
|
|
@ -117,6 +129,84 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle
|
|||
}
|
||||
}
|
||||
|
||||
void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle)
|
||||
{
|
||||
struct c140_voice_t *voice = &c219->voice[v];
|
||||
if (voice->busy && voice->keyon)
|
||||
{
|
||||
for (int c = 0; c < cycle; c++)
|
||||
{
|
||||
voice->frac += voice->freq;
|
||||
if (voice->frac > 0xffff)
|
||||
{
|
||||
voice->addr += voice->frac >> 16;
|
||||
if ((voice->addr >> 1) > voice->end_addr)
|
||||
{
|
||||
if (voice->loop)
|
||||
{
|
||||
voice->addr = (voice->addr + (voice->loop_addr << 1)) - (voice->end_addr << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
voice->keyon = false;
|
||||
voice->lout = 0;
|
||||
voice->rout = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (voice->noise)
|
||||
{
|
||||
c219->lfsr = (c219->lfsr >> 1) ^ ((-(c219->lfsr & 1)) & 0xfff6);
|
||||
}
|
||||
voice->frac &= 0xffff;
|
||||
}
|
||||
}
|
||||
if (!voice->muted)
|
||||
{
|
||||
signed int sample = 0;
|
||||
if (voice->noise)
|
||||
{
|
||||
sample = (signed int)((signed short)(c219->lfsr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// fetch 8 bit sample
|
||||
signed short s1 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | voice->addr];
|
||||
signed short s2 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | ((voice->addr + 1) & 0x1ffff)];
|
||||
if (voice->compressed)
|
||||
{
|
||||
s1 = c219->mulaw[s1];
|
||||
s2 = c219->mulaw[s2];
|
||||
}
|
||||
else
|
||||
{
|
||||
s1 = (signed short)((signed char)(s1) << 8);
|
||||
s2 = (signed short)((signed char)(s2) << 8);
|
||||
}
|
||||
if (voice->inv_sign)
|
||||
{
|
||||
s1 = -s1;
|
||||
s2 = -s2;
|
||||
}
|
||||
// interpolate (originally was >>16, but I had to reduce it to 15 to prevent overflow)
|
||||
sample = s1 + (((voice->frac >> 1) * (s2 - s1)) >> 15);
|
||||
}
|
||||
voice->lout = (voice->inv_lout ? (-sample) : sample) * voice->lvol;
|
||||
voice->rout = sample * voice->rvol;
|
||||
}
|
||||
else
|
||||
{
|
||||
voice->lout = 0;
|
||||
voice->rout = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
voice->lout = 0;
|
||||
voice->rout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void c140_keyon(struct c140_voice_t *c140_voice)
|
||||
{
|
||||
c140_voice->busy = true;
|
||||
|
|
@ -125,6 +215,14 @@ void c140_keyon(struct c140_voice_t *c140_voice)
|
|||
c140_voice->addr = c140_voice->start_addr;
|
||||
}
|
||||
|
||||
void c219_keyon(struct c140_voice_t *c140_voice)
|
||||
{
|
||||
c140_voice->busy = true;
|
||||
c140_voice->keyon = true;
|
||||
c140_voice->frac = 0;
|
||||
c140_voice->addr = c140_voice->start_addr << 1;
|
||||
}
|
||||
|
||||
void c140_init(struct c140_t *c140)
|
||||
{
|
||||
// u-law table verified from Wii Virtual Console Arcade Starblade
|
||||
|
|
@ -149,6 +247,41 @@ void c140_init(struct c140_t *c140)
|
|||
}
|
||||
}
|
||||
|
||||
void c219_init(struct c219_t *c219)
|
||||
{
|
||||
// u-law table verified from Wii Virtual Console Arcade Knuckle Heads
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
signed int compressed_sample = 0;
|
||||
if (i < 16)
|
||||
{
|
||||
compressed_sample = 0x20 * i;
|
||||
}
|
||||
else if (i < 24)
|
||||
{
|
||||
compressed_sample = (0x200 + (0x40 * i)) - 0x400;
|
||||
}
|
||||
else if (i < 48)
|
||||
{
|
||||
compressed_sample = (0x400 + (0x80 * i)) - 0xc00;
|
||||
}
|
||||
else if (i < 100)
|
||||
{
|
||||
compressed_sample = (0x1000 + (0x100 * i)) - 0x3000;
|
||||
}
|
||||
else
|
||||
{
|
||||
compressed_sample = (0x4400 + (0x200 * i)) - 0xc800;
|
||||
}
|
||||
c219->mulaw[i] = compressed_sample;
|
||||
c219->mulaw[i + 128] = (~compressed_sample) & 0xffe0;
|
||||
}
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
c219->voice[i].muted = false;
|
||||
}
|
||||
}
|
||||
|
||||
void c140_reset(struct c140_t *c140)
|
||||
{
|
||||
for (int i = 0; i < 24; i++)
|
||||
|
|
@ -171,6 +304,35 @@ void c140_reset(struct c140_t *c140)
|
|||
}
|
||||
}
|
||||
|
||||
void c219_reset(struct c219_t *c219)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
c219->voice[i].busy = false;
|
||||
c219->voice[i].keyon = false;
|
||||
c219->voice[i].freq = 0;
|
||||
c219->voice[i].start_addr = 0;
|
||||
c219->voice[i].loop_addr = 0;
|
||||
c219->voice[i].end_addr = 0;
|
||||
c219->voice[i].lvol = 0;
|
||||
c219->voice[i].rvol = 0;
|
||||
c219->voice[i].noise = false;
|
||||
c219->voice[i].inv_lout = false;
|
||||
c219->voice[i].inv_sign = false;
|
||||
c219->voice[i].compressed = false;
|
||||
c219->voice[i].loop = false;
|
||||
c219->voice[i].addr = 0;
|
||||
c219->voice[i].frac = 0;
|
||||
c219->voice[i].lout = 0;
|
||||
c219->voice[i].rout = 0;
|
||||
}
|
||||
c219->lfsr = 0x1234;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
c219->bank[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned char data)
|
||||
{
|
||||
// voice register
|
||||
|
|
@ -203,3 +365,47 @@ void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned c
|
|||
}
|
||||
// Timer
|
||||
}
|
||||
|
||||
void c219_write(struct c219_t *c219, const unsigned short addr, const unsigned char data)
|
||||
{
|
||||
// voice register
|
||||
if (addr < 0x180)
|
||||
{
|
||||
struct c140_voice_t *voice = &c219->voice[addr >> 4];
|
||||
switch (addr & 0xf)
|
||||
{
|
||||
case 0x0: voice->rvol = data; break;
|
||||
case 0x1: voice->lvol = data; break;
|
||||
case 0x2: voice->freq = (voice->freq & ~0xff00) | (unsigned int)(data << 8); break;
|
||||
case 0x3: voice->freq = (voice->freq & ~0x00ff) | data; break;
|
||||
//case 0x4: break; // Unknown
|
||||
case 0x5:
|
||||
voice->compressed = c140_bit(data, 0);
|
||||
voice->noise = c140_bit(data, 2);
|
||||
voice->inv_lout = c140_bit(data, 3);
|
||||
voice->loop = c140_bit(data, 4);
|
||||
voice->inv_sign = c140_bit(data, 6);
|
||||
if (data & 0x80)
|
||||
c219_keyon(voice);
|
||||
else
|
||||
voice->busy = false;
|
||||
break;
|
||||
case 0x6: voice->start_addr = (voice->start_addr & ~0xff00) | (unsigned int)(data << 8); break;
|
||||
case 0x7: voice->start_addr = (voice->start_addr & ~0x00ff) | data; break;
|
||||
case 0x8: voice->end_addr = (voice->end_addr & ~0xff00) | (unsigned int)(data << 8); break;
|
||||
case 0x9: voice->end_addr = (voice->end_addr & ~0x00ff) | data; break;
|
||||
case 0xa: voice->loop_addr = (voice->loop_addr & ~0xff00) | (unsigned int)(data << 8); break;
|
||||
case 0xb: voice->loop_addr = (voice->loop_addr & ~0x00ff) | data; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
// bank
|
||||
else if (addr >= 0x1f0)
|
||||
{
|
||||
if (addr & 1)
|
||||
{
|
||||
const unsigned short bankaddr = (addr >> 1) & 3;
|
||||
c219->bank[(bankaddr + 1) & 3] = (data & 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
============================================================================
|
||||
|
||||
MODIFIED Namco C140 sound emulator - MODIFIED VERSION
|
||||
MODIFIED Namco C140/C219 sound emulator - MODIFIED VERSION
|
||||
by cam900
|
||||
|
||||
MODIFICATION by tildearrow - adds muting function
|
||||
|
|
@ -41,8 +41,8 @@ TODO:
|
|||
|
||||
*/
|
||||
|
||||
#ifndef _C140_EMU_H
|
||||
#define _C140_EMU_H
|
||||
#ifndef _C140_C219_EMU_H
|
||||
#define _C140_C219_EMU_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
|
@ -58,13 +58,16 @@ struct c140_voice_t
|
|||
bool keyon; // key on flag
|
||||
unsigned short freq; // sample frequency
|
||||
unsigned char bank; // sample bank
|
||||
unsigned short start_addr; // sample start address
|
||||
unsigned short loop_addr; // sample loop address
|
||||
unsigned short end_addr; // sample end address
|
||||
unsigned int start_addr; // sample start address
|
||||
unsigned int loop_addr; // sample loop address
|
||||
unsigned int end_addr; // sample end address
|
||||
int lvol, rvol; // left/right volume
|
||||
bool noise; // noise flag
|
||||
bool inv_lout; // invert left output flag
|
||||
bool inv_sign; // invert sign bit flag
|
||||
bool compressed; // compressed sample flag
|
||||
bool loop; // loop flag
|
||||
unsigned short addr; // sample address
|
||||
unsigned int addr; // sample address
|
||||
int frac; // frequency counter (.16 fixed point)
|
||||
int lout, rout; // left/right output
|
||||
};
|
||||
|
|
@ -77,20 +80,42 @@ struct c140_t
|
|||
signed short *sample_mem;
|
||||
};
|
||||
|
||||
struct c219_t
|
||||
{
|
||||
struct c140_voice_t voice[16];
|
||||
signed int lout, rout;
|
||||
signed short mulaw[256];
|
||||
unsigned short lfsr;
|
||||
unsigned char bank[4];
|
||||
signed char *sample_mem;
|
||||
};
|
||||
|
||||
void c140_tick(struct c140_t *c140, const int cycle);
|
||||
|
||||
void c219_tick(struct c219_t *c219, const int cycle);
|
||||
|
||||
void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle);
|
||||
|
||||
void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle);
|
||||
|
||||
void c140_keyon(struct c140_voice_t *c140_voice);
|
||||
|
||||
void c219_keyon(struct c140_voice_t *c140_voice);
|
||||
|
||||
void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned char data);
|
||||
|
||||
void c219_write(struct c219_t *c219, const unsigned short addr, const unsigned char data);
|
||||
|
||||
void c140_init(struct c140_t *c140);
|
||||
|
||||
void c219_init(struct c219_t *c219);
|
||||
|
||||
void c140_reset(struct c140_t *c140);
|
||||
|
||||
void c219_reset(struct c219_t *c219);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _C140_EMU_H
|
||||
#endif // _C140_C219_EMU_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 {
|
||||
|
|
|
|||
|
|
@ -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"},
|
||||
{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.",
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ const char* aboutLine[]={
|
|||
"vgsound_emu (second version, modified version) by cam900",
|
||||
"SM8521 emulator (modified version) by cam900",
|
||||
"D65010G031 emulator (modified version) by cam900",
|
||||
"Namco C140 (modified version) emulator by cam900",
|
||||
"Namco C140/C219 emulator (modified version) by cam900",
|
||||
"",
|
||||
"greetings to:",
|
||||
"NEOART Costa Rica",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ TAParamResult pVersion(String) {
|
|||
printf("- ASAP POKEY emulator by Piotr Fusik ported to C++ by laoo (GPLv2)\n");
|
||||
printf("- SM8521 emulator (modified version) by cam900 (zlib license)\n");
|
||||
printf("- D65010G031 emulator (modified version) by cam900 (zlib license)\n");
|
||||
printf("- C140 emulator (modified version) by cam900 (zlib license)\n");
|
||||
printf("- C140/C219 emulator (modified version) by cam900 (zlib license)\n");
|
||||
return TA_PARAM_QUIT;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue