From 3e774ddb6fc57806a2c132a5cd3b669fe0a4ee30 Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Fri, 9 Aug 2024 00:36:34 +0300 Subject: [PATCH] finally added DMA sample support and panning --- src/engine/platform/sound/supervision.c | 21 ++-- src/engine/platform/sound/supervision.h | 2 + src/engine/platform/supervision.cpp | 130 ++++++++++++++++++++++-- src/engine/platform/supervision.h | 20 +++- src/gui/insEdit.cpp | 1 + 5 files changed, 157 insertions(+), 17 deletions(-) diff --git a/src/engine/platform/sound/supervision.c b/src/engine/platform/sound/supervision.c index cc0a4e610..813f5f812 100644 --- a/src/engine/platform/sound/supervision.c +++ b/src/engine/platform/sound/supervision.c @@ -8,6 +8,8 @@ uint32 UNSCALED_CLOCK = 4000000; uint32 decrement_tick = 0; +uint8 supervision_dma_mem[65536]; + void supervision_sound_set_clock(uint32 clock) { UNSCALED_CLOCK = clock; } @@ -169,30 +171,33 @@ void supervision_sound_stream_update(uint8 *stream, uint32 len) } } -/* + chout[2] = 0; if (m_dma.on) { uint8 sample; uint16 addr = m_dma.start + (uint16)m_dma.pos / 2; if (addr >= 0x8000 && addr < 0xc000) { - sample = memorymap_getRomPointer()[(addr & 0x3fff) | m_dma.ca14to16]; - } - else { - sample = Rd6502(addr); + sample = supervision_dma_mem[(addr & 0x3fff) | m_dma.ca14to16]; } if (((uint16)m_dma.pos) & 1) s = (sample & 0xf); else s = (sample & 0xf0) >> 4; - if (m_dma.left) + s <<= 2; + chout[2] = 0; + if (m_dma.left) { *left += s; - if (m_dma.right) + chout[2] = s; + } + if (m_dma.right) { *right += s; + chout[2] = s; + } m_dma.pos += m_dma.step; if (m_dma.pos >= m_dma.size) { m_dma.on = FALSE; } } -*/ + if (decrement_tick > SV_DEC_TICK) { decrement_tick = 0; supervision_sound_decrement(); diff --git a/src/engine/platform/sound/supervision.h b/src/engine/platform/sound/supervision.h index d18b7317b..b1ffb3876 100644 --- a/src/engine/platform/sound/supervision.h +++ b/src/engine/platform/sound/supervision.h @@ -28,6 +28,8 @@ void supervision_memorymap_registers_write(uint32 Addr, uint8 Value); void supervision_set_mute_mask(uint32 mask); void supervision_sound_set_flags(uint32 flags_set); +extern uint8 supervision_dma_mem[65536]; + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/engine/platform/supervision.cpp b/src/engine/platform/supervision.cpp index 339eff114..e5a2aec32 100644 --- a/src/engine/platform/supervision.cpp +++ b/src/engine/platform/supervision.cpp @@ -19,6 +19,7 @@ #include "supervision.h" #include "../engine.h" +#include "../../ta-log.h" #include "furIcons.h" #include @@ -60,6 +61,9 @@ const char** DivPlatformSupervision::getRegisterSheet() { return regCheatSheetSupervision; } + +unsigned char* sampleMem = supervision_dma_mem; + unsigned char duty_swap = 0; unsigned char otherFlags = 0; @@ -107,7 +111,7 @@ void DivPlatformSupervision::tick(bool sysTick) { } else if (chan[i].std.arp.had) { if (!chan[i].inPorta) { int f = parent->calcArp(chan[i].note,chan[i].std.arp.val); - if (i == 3) { + if (i==2 || i==3) { chan[i].baseFreq=f; //if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; @@ -120,6 +124,9 @@ void DivPlatformSupervision::tick(bool sysTick) { if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; } + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { chan[i].pitch2+=chan[i].std.pitch.val; @@ -156,6 +163,25 @@ void DivPlatformSupervision::tick(bool sysTick) { if (noiseReg[0] != r) rWrite(0x28,r); noiseReg[0] = r; } + if (chan[i].keyOn && i==2) { + if (chan[i].pcm) { + int ntPos=chan[i].sampleNote; + ntPos+=chan[i].pitch2; + chan[i].freq=3-(ntPos&3); + int sNum=chan[i].sample; + DivSample* sample=parent->getSample(sNum); + if (sample!=NULL && sNum>=0 && sNumsong.sampleLen) { + unsigned int off=MIN(sampleOff[sNum]+chan[i].hasOffset,sampleOff[sNum]+sampleLen[sNum]); + unsigned int len=MAX(sampleLen[sNum]-chan[i].hasOffset,0); + chan[i].hasOffset=0; + rWrite(0x18,off&0xff); + rWrite(0x19,(off>>8&0x3f)|0x80); + rWrite(0x1A,MIN(MAX(len>>4,0),255)); + rWrite(0x1B,chan[i].freq|((chan[i].pan&3)<<2)|((off>>14&7)<<4)); + rWrite(0x1C,0x80); + } + } + } if (chan[i].keyOn) kon[i] = 1; if (chan[i].keyOff) kon[i] = 0; if (chan[i].keyOn) chan[i].keyOn=false; @@ -169,7 +195,7 @@ void DivPlatformSupervision::tick(bool sysTick) { rWrite(0x13|(i<<2),0xc8); } else if (i == 3) { rWrite(0x29,0xc8); - unsigned char r = ((chan[i].duty&1)^duty_swap)|(0x02|0x10)|(4|8); + unsigned char r = ((chan[i].duty&1)^duty_swap)|(0x02|0x10)|(chan[i].pan<<2); if (noiseReg[2] != r) rWrite(0x2A,r); noiseReg[2] = r; } @@ -191,10 +217,21 @@ void DivPlatformSupervision::tick(bool sysTick) { int DivPlatformSupervision::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE); - - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SUPERVISION); + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].pcm=true; + } else { + chan[c.chan].pcm=false; + } + if (chan[c.chan].pcm) { + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].sample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + } + } else { + chan[c.chan].sampleNote=DIV_NOTE_NULL; + chan[c.chan].sampleNoteDelta=0; + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=c.chan==3?c.value:NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -273,6 +310,10 @@ int DivPlatformSupervision::dispatch(DivCommand c) { case DIV_CMD_STD_NOISE_MODE: chan[c.chan].duty=c.value; break; + case DIV_CMD_SAMPLE_POS: + chan[c.chan].hasOffset=c.value; + chan[c.chan].keyOn=true; + break; case DIV_CMD_LEGATO: chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; @@ -280,7 +321,7 @@ int DivPlatformSupervision::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SUPERVISION)); } if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; @@ -400,6 +441,79 @@ void DivPlatformSupervision::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); } +const void* DivPlatformSupervision::getSampleMem(int index) { + return index==0?sampleMem:NULL; +} + +size_t DivPlatformSupervision::getSampleMemCapacity(int index) { + return index==0?65536:0; +} + +size_t DivPlatformSupervision::getSampleMemUsage(int index) { + return index==0?sampleMemLen:0; +} + +bool DivPlatformSupervision::isSampleLoaded(int index, int sample) { + if (index!=0) return false; + if (sample<0 || sample>255) return false; + return sampleLoaded[sample]; +} + +const DivMemoryComposition* DivPlatformSupervision::getMemCompo(int index) { + if (index!=0) return NULL; + return &memCompo; +} + +void DivPlatformSupervision::renderSamples(int sysID) { + memset(sampleMem,0,getSampleMemCapacity(0)); + memset(sampleLoaded,0,256*sizeof(bool)); + + memCompo=DivMemoryComposition(); + memCompo.name="Sample Memory"; + + size_t memPos=0; + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + if (!s->renderOn[0][sysID]) { + sampleOff[i]=0; + continue; + } + unsigned int paddedLen=((s->length8>>1)+63)&(~0x3f); + logV("%d padded length: %d",i,paddedLen); + if ((memPos&(~0x3fff))!=((memPos+paddedLen)&(~0x3fff))) { + memPos=(memPos+0x3fff)&(~0x3fff); + } + if (paddedLen>=4096) { + paddedLen=4096; + } + if (memPos>=getSampleMemCapacity(0)) { + logW("out of memory for sample %d!",i); + break; + } + if (memPos+paddedLen>=getSampleMemCapacity(0)) { + sampleLen[i] = (getSampleMemCapacity(0)-memPos)>>1; + for (size_t i=0; i<(getSampleMemCapacity(0)-memPos)>>1; i++) { + sampleMem[memPos+i] = (((s->data8[i*2+0]+128)>>4)<<4&0xf0)|(((s->data8[i*2+1]+128)>>4)&0xf); + } + logW("out of memory for sample %d!",i); + } else { + size_t len = MIN((s->length8>>1),paddedLen); + sampleLen[i] = (unsigned int)len; + for (size_t i=0; i>1; i++) { + sampleMem[memPos+i] = (((s->data8[i*2+0]+128)>>4)<<4&0xf0)|(((s->data8[i*2+1]+128)>>4)&0xf); + } + sampleLoaded[i]=true; + } + sampleOff[i]=memPos; + memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE,"Sample",i,memPos,memPos+paddedLen)); + memPos+=paddedLen; + } + sampleMemLen=memPos; + + memCompo.capacity=65536; + memCompo.used=sampleMemLen; +} + int DivPlatformSupervision::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { parent=p; dumpWrites=false; @@ -408,6 +522,8 @@ int DivPlatformSupervision::init(DivEngine* p, int channels, int sugRate, const isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } + sampleMemLen=0; + memset(sampleMem,0,65536); setFlags(flags); reset(); return 4; diff --git a/src/engine/platform/supervision.h b/src/engine/platform/supervision.h index 9a670efa0..f5025bc47 100644 --- a/src/engine/platform/supervision.h +++ b/src/engine/platform/supervision.h @@ -26,13 +26,16 @@ class DivPlatformSupervision: public DivDispatch { struct Channel: public SharedChannel { - int dacPeriod, dacRate, dacOut; - unsigned int duty, len; + unsigned int duty, len, pan, pcm; // pcm is channel 3 ONLY + int sample, hasOffset; // again, for channel 3 ONLY bool setPos; Channel(): SharedChannel(31), duty(0), len(0x1f), + pan(3), + pcm(false), + hasOffset(0), setPos(false) {} }; Channel chan[4]; @@ -51,6 +54,13 @@ class DivPlatformSupervision: public DivDispatch { int tempR[32]; int coreQuality; unsigned char regPool[64]; + unsigned int sampleOff[256]; + unsigned int sampleLen[256]; + bool sampleLoaded[256]; + DivMemoryComposition memCompo; + + size_t sampleMemLen; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: @@ -72,6 +82,12 @@ class DivPlatformSupervision: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); + const void* getSampleMem(int index); + size_t getSampleMemCapacity(int index); + size_t getSampleMemUsage(int index); + 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(); ~DivPlatformSupervision(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 92f40e44d..8eb5a2f6a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -7411,6 +7411,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Noise"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); + macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break;