mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-02 02:52:40 +00:00
GBA: implement memory composition and status
This commit is contained in:
parent
67253245ab
commit
48b51f5108
6 changed files with 106 additions and 6 deletions
|
@ -480,6 +480,7 @@ enum DivMemoryWaveView: unsigned char {
|
|||
DIV_MEMORY_WAVE_NONE=0,
|
||||
DIV_MEMORY_WAVE_4BIT, // Namco 163
|
||||
DIV_MEMORY_WAVE_6BIT, // Virtual Boy
|
||||
DIV_MEMORY_WAVE_8BIT_SIGNED, // SCC
|
||||
};
|
||||
|
||||
struct DivMemoryComposition {
|
||||
|
|
|
@ -195,6 +195,7 @@ int DivPlatformGBADMA::dispatch(DivCommand c) {
|
|||
if (ins->amiga.useWave) {
|
||||
chan[c.chan].useWave=true;
|
||||
chan[c.chan].audLen=ins->amiga.waveLen+1;
|
||||
wtMemCompo.entries[c.chan].end=wtMemCompo.entries[c.chan].begin+chan[c.chan].audLen;
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
|
@ -392,11 +393,14 @@ unsigned short DivPlatformGBADMA::getPan(int ch) {
|
|||
}
|
||||
|
||||
DivSamplePos DivPlatformGBADMA::getSamplePos(int ch) {
|
||||
if (ch>=2) return DivSamplePos();
|
||||
if (ch>=2 || !chan[ch].active ||
|
||||
chan[ch].sample<0 || chan[ch].sample>=parent->song.sampleLen) {
|
||||
return DivSamplePos();
|
||||
}
|
||||
return DivSamplePos(
|
||||
chan[ch].sample,
|
||||
chan[ch].audPos,
|
||||
chan[ch].freq
|
||||
chipClock/chan[ch].freq
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -441,9 +445,19 @@ bool DivPlatformGBADMA::isSampleLoaded(int index, int sample) {
|
|||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
const DivMemoryComposition* DivPlatformGBADMA::getMemCompo(int index) {
|
||||
switch (index) {
|
||||
case 0: return &romMemCompo;
|
||||
case 1: return &wtMemCompo;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformGBADMA::renderSamples(int sysID) {
|
||||
size_t maxPos=getSampleMemCapacity();
|
||||
memset(sampleMem,0,maxPos);
|
||||
romMemCompo.entries.clear();
|
||||
romMemCompo.capacity=maxPos;
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
|
@ -466,8 +480,10 @@ void DivPlatformGBADMA::renderSamples(int sysID) {
|
|||
sampleLoaded[i]=true;
|
||||
// pad to multiple of 16 bytes
|
||||
memPos=(memPos+15)&~15;
|
||||
romMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE,"PCM",i,sampleOff[i],memPos));
|
||||
}
|
||||
sampleMemLen=memPos;
|
||||
romMemCompo.used=sampleMemLen;
|
||||
}
|
||||
|
||||
void DivPlatformGBADMA::setFlags(const DivConfig& flags) {
|
||||
|
@ -484,9 +500,18 @@ int DivPlatformGBADMA::init(DivEngine* p, int channels, int sugRate, const DivCo
|
|||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
romMemCompo=DivMemoryComposition();
|
||||
romMemCompo.name="Sample ROM";
|
||||
wtMemCompo=DivMemoryComposition();
|
||||
wtMemCompo.name="Wavetable RAM";
|
||||
wtMemCompo.used=256*2;
|
||||
wtMemCompo.capacity=256*2;
|
||||
wtMemCompo.memory=(unsigned char*)wtMem;
|
||||
wtMemCompo.waveformView=DIV_MEMORY_WAVE_8BIT_SIGNED;
|
||||
for (int i=0; i<2; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
wtMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_WAVE_RAM, fmt::sprintf("Channel %d",i),-1,i*256,i*256));
|
||||
}
|
||||
sampleMem=new signed char[getSampleMemCapacity()];
|
||||
sampleMemLen=0;
|
||||
|
|
|
@ -62,6 +62,9 @@ class DivPlatformGBADMA: public DivDispatch {
|
|||
size_t sampleMemLen;
|
||||
// maximum wavetable length is currently hardcoded to 256
|
||||
signed char wtMem[256*2];
|
||||
DivMemoryComposition romMemCompo;
|
||||
DivMemoryComposition wtMemCompo;
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
|
@ -86,10 +89,11 @@ class DivPlatformGBADMA: public DivDispatch {
|
|||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
const DivMemoryComposition* getMemCompo(int index);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
|
||||
|
||||
private:
|
||||
void updateWave(int ch);
|
||||
};
|
||||
|
|
|
@ -142,6 +142,8 @@ void DivPlatformGBAMinMod::acquire(short** buf, size_t len) {
|
|||
while (updTimer>=updCycles) {
|
||||
// flip buffer
|
||||
// logV("ut=%d,pg=%d,w=%d,r=%d,sc=%d,st=%d",updTimer,mixBufPage,mixBufWritePos,mixBufReadPos,sampCycles,sampTimer);
|
||||
mixMemCompo.entries[mixBufPage].end=mixMemCompo.entries[mixBufPage].begin+mixBufWritePos;
|
||||
mixMemCompo.entries[mixBufPage+1].end=mixMemCompo.entries[mixBufPage+1].begin+mixBufWritePos;
|
||||
mixBufPage=(mixBufPage+2)%(mixBufs*2);
|
||||
memset(mixBuf[mixBufPage],0,sizeof(mixBuf[mixBufPage]));
|
||||
memset(mixBuf[mixBufPage+1],0,sizeof(mixBuf[mixBufPage+1]));
|
||||
|
@ -298,9 +300,9 @@ void DivPlatformGBAMinMod::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].keyOn) {
|
||||
unsigned int start, end, loop;
|
||||
if (chan[i].echo!=0) {
|
||||
if ((chan[i].echo&0xf)!=0) {
|
||||
// make sure echo channels' frequency can't be faster than the sample rate
|
||||
if (chan[i].echo!=0 && chan[i].freq>CHIP_FREQBASE) {
|
||||
if (chan[i].freq>CHIP_FREQBASE) {
|
||||
chan[i].freq=CHIP_FREQBASE;
|
||||
}
|
||||
// this is only to match the HLE implementation
|
||||
|
@ -381,6 +383,9 @@ int DivPlatformGBAMinMod::dispatch(DivCommand c) {
|
|||
if (ins->amiga.useWave) {
|
||||
chan[c.chan].useWave=true;
|
||||
chan[c.chan].wtLen=ins->amiga.waveLen+1;
|
||||
if (c.chan<chanMax) {
|
||||
wtMemCompo.entries[c.chan].end=wtMemCompo.entries[c.chan].begin+chan[c.chan].wtLen;
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
|
@ -558,6 +563,20 @@ unsigned short DivPlatformGBAMinMod::getPan(int ch) {
|
|||
return (chan[ch].chPanL<<8)|(chan[ch].chPanR);
|
||||
}
|
||||
|
||||
DivSamplePos DivPlatformGBAMinMod::getSamplePos(int ch) {
|
||||
if (ch>=chanMax ||
|
||||
chan[ch].sample<0 || chan[ch].sample>=parent->song.sampleLen ||
|
||||
!chan[ch].active || (chan[ch].echo&0xf)!=0
|
||||
) {
|
||||
return DivSamplePos();
|
||||
}
|
||||
return DivSamplePos(
|
||||
chan[ch].sample,
|
||||
(((int)regPool[ch*16+2]|((int)regPool[ch*16+3]<<16))&0x01ffffff)-sampleOff[chan[ch].sample],
|
||||
(long long)chan[ch].freq*chipClock/CHIP_FREQBASE
|
||||
);
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformGBAMinMod::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
@ -577,6 +596,7 @@ void DivPlatformGBAMinMod::reset() {
|
|||
void DivPlatformGBAMinMod::resetMixer() {
|
||||
sampTimer=sampCycles;
|
||||
updTimer=0;
|
||||
updCycles=0;
|
||||
mixBufReadPos=0;
|
||||
mixBufWritePos=0;
|
||||
mixBufPage=0;
|
||||
|
@ -651,9 +671,20 @@ bool DivPlatformGBAMinMod::isSampleLoaded(int index, int sample) {
|
|||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
const DivMemoryComposition* DivPlatformGBAMinMod::getMemCompo(int index) {
|
||||
switch (index) {
|
||||
case 0: return &romMemCompo;
|
||||
case 1: return &wtMemCompo;
|
||||
case 2: return &mixMemCompo;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformGBAMinMod::renderSamples(int sysID) {
|
||||
size_t maxPos=getSampleMemCapacity();
|
||||
memset(sampleMem,0,maxPos);
|
||||
romMemCompo.entries.clear();
|
||||
romMemCompo.capacity=maxPos;
|
||||
|
||||
// dummy zero-length samples are at pos 0 as the engine still outputs them
|
||||
size_t memPos=1;
|
||||
|
@ -677,6 +708,7 @@ void DivPlatformGBAMinMod::renderSamples(int sysID) {
|
|||
memset(&sampleMem[memPos],0,oneShotLen);
|
||||
memPos+=oneShotLen;
|
||||
}
|
||||
romMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE,"PCM",i,sampleOff[i],memPos));
|
||||
}
|
||||
if (actualLength<length) {
|
||||
logW("out of GBA MinMod PCM memory for sample %d!",i);
|
||||
|
@ -685,6 +717,7 @@ void DivPlatformGBAMinMod::renderSamples(int sysID) {
|
|||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleMemLen=memPos;
|
||||
romMemCompo.used=sampleMemLen;
|
||||
}
|
||||
|
||||
void DivPlatformGBAMinMod::setFlags(const DivConfig& flags) {
|
||||
|
@ -699,12 +732,35 @@ void DivPlatformGBAMinMod::setFlags(const DivConfig& flags) {
|
|||
sampCycles=16777216/flags.getInt("sampRate",21845);
|
||||
chipClock=16777216/sampCycles;
|
||||
resetMixer();
|
||||
wtMemCompo.used=256*chanMax;
|
||||
mixMemCompo.used=2048*mixBufs;
|
||||
wtMemCompo.entries.clear();
|
||||
mixMemCompo.entries.clear();
|
||||
for (int i=0; i<chanMax; i++) {
|
||||
wtMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_WAVE_RAM, fmt::sprintf("Channel %d",i),-1,i*256,i*256));
|
||||
}
|
||||
for (int i=0; i<mixBufs; i++) {
|
||||
mixMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_WAVE_RAM, fmt::sprintf("Buffer %d Left",i),-1,i*2048,i*2048));
|
||||
mixMemCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_WAVE_RAM, fmt::sprintf("Buffer %d Right",i),-1,i*2048+1024,i*2048+1024));
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformGBAMinMod::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
romMemCompo=DivMemoryComposition();
|
||||
romMemCompo.name="Sample ROM";
|
||||
wtMemCompo=DivMemoryComposition();
|
||||
wtMemCompo.name="Wavetable RAM";
|
||||
wtMemCompo.capacity=256*16;
|
||||
wtMemCompo.memory=(unsigned char*)wtMem;
|
||||
wtMemCompo.waveformView=DIV_MEMORY_WAVE_8BIT_SIGNED;
|
||||
mixMemCompo=DivMemoryComposition();
|
||||
mixMemCompo.name="Mix/Echo Buffer";
|
||||
mixMemCompo.capacity=2048*15;
|
||||
mixMemCompo.memory=(unsigned char*)mixBuf;
|
||||
mixMemCompo.waveformView=DIV_MEMORY_WAVE_8BIT_SIGNED;
|
||||
for (int i=0; i<16; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
|
|
|
@ -81,8 +81,12 @@ class DivPlatformGBAMinMod: public DivDispatch {
|
|||
signed char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
// maximum wavetable length is currently hardcoded to 256
|
||||
signed char wtMem[256*16];
|
||||
unsigned short regPool[16*16];
|
||||
signed char wtMem[256*16];
|
||||
DivMemoryComposition romMemCompo;
|
||||
DivMemoryComposition mixMemCompo;
|
||||
DivMemoryComposition wtMemCompo;
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
|
@ -92,6 +96,7 @@ class DivPlatformGBAMinMod: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivSamplePos getSamplePos(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
@ -111,6 +116,7 @@ class DivPlatformGBAMinMod: public DivDispatch {
|
|||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
const DivMemoryComposition* getMemCompo(int index);
|
||||
void renderSamples(int chipID);
|
||||
void setFlags(const DivConfig& flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
|
|
|
@ -109,6 +109,14 @@ void FurnaceGUI::drawMemory() {
|
|||
dl->AddRectFilled(pos1,pos2,ImGui::GetColorU32(uiColors[GUI_COLOR_MEMORY_DATA]));
|
||||
}
|
||||
break;
|
||||
case DIV_MEMORY_WAVE_8BIT_SIGNED:
|
||||
for (int k=0; k<mc->capacity; k++) {
|
||||
signed char val=(signed char)mc->memory[k];
|
||||
ImVec2 pos1=ImLerp(dataRect.Min,dataRect.Max,ImVec2((double)k/(double)(mc->capacity),1.0f-((float)(val+129)/256.0f)));
|
||||
ImVec2 pos2=ImLerp(dataRect.Min,dataRect.Max,ImVec2((double)(k+1)/(double)(mc->capacity),1.0f));
|
||||
dl->AddRectFilled(pos1,pos2,ImGui::GetColorU32(uiColors[GUI_COLOR_MEMORY_DATA]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue