From 48b51f5108d3d0313ce9871faa4c7091a1611f92 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Sat, 16 Mar 2024 23:16:40 +0700 Subject: [PATCH] GBA: implement memory composition and status --- src/engine/dispatch.h | 1 + src/engine/platform/gbadma.cpp | 29 +++++++++++++-- src/engine/platform/gbadma.h | 6 +++- src/engine/platform/gbaminmod.cpp | 60 +++++++++++++++++++++++++++++-- src/engine/platform/gbaminmod.h | 8 ++++- src/gui/memory.cpp | 8 +++++ 6 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 079a49022..dee8efe75 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -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 { diff --git a/src/engine/platform/gbadma.cpp b/src/engine/platform/gbadma.cpp index 9a0ac2fab..af61fa543 100644 --- a/src/engine/platform/gbadma.cpp +++ b/src/engine/platform/gbadma.cpp @@ -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; isong.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; diff --git a/src/engine/platform/gbadma.h b/src/engine/platform/gbadma.h index aff18d3df..8ea38e545 100644 --- a/src/engine/platform/gbadma.h +++ b/src/engine/platform/gbadma.h @@ -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); }; diff --git a/src/engine/platform/gbaminmod.cpp b/src/engine/platform/gbaminmod.cpp index 118882687..4d3605195 100644 --- a/src/engine/platform/gbaminmod.cpp +++ b/src/engine/platform/gbaminmod.cpp @@ -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 || + 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 (actualLengthAddRectFilled(pos1,pos2,ImGui::GetColorU32(uiColors[GUI_COLOR_MEMORY_DATA])); } break; + case DIV_MEMORY_WAVE_8BIT_SIGNED: + for (int k=0; kcapacity; 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; }