finally added DMA sample support and panning

This commit is contained in:
AArt1256 2024-08-09 00:36:34 +03:00
parent 6f370e9d62
commit 3e774ddb6f
5 changed files with 157 additions and 17 deletions

View file

@ -8,6 +8,8 @@ uint32 UNSCALED_CLOCK = 4000000;
uint32 decrement_tick = 0; uint32 decrement_tick = 0;
uint8 supervision_dma_mem[65536];
void supervision_sound_set_clock(uint32 clock) { void supervision_sound_set_clock(uint32 clock) {
UNSCALED_CLOCK = clock; UNSCALED_CLOCK = clock;
} }
@ -169,30 +171,33 @@ void supervision_sound_stream_update(uint8 *stream, uint32 len)
} }
} }
/* chout[2] = 0;
if (m_dma.on) { if (m_dma.on) {
uint8 sample; uint8 sample;
uint16 addr = m_dma.start + (uint16)m_dma.pos / 2; uint16 addr = m_dma.start + (uint16)m_dma.pos / 2;
if (addr >= 0x8000 && addr < 0xc000) { if (addr >= 0x8000 && addr < 0xc000) {
sample = memorymap_getRomPointer()[(addr & 0x3fff) | m_dma.ca14to16]; sample = supervision_dma_mem[(addr & 0x3fff) | m_dma.ca14to16];
}
else {
sample = Rd6502(addr);
} }
if (((uint16)m_dma.pos) & 1) if (((uint16)m_dma.pos) & 1)
s = (sample & 0xf); s = (sample & 0xf);
else else
s = (sample & 0xf0) >> 4; s = (sample & 0xf0) >> 4;
if (m_dma.left) s <<= 2;
chout[2] = 0;
if (m_dma.left) {
*left += s; *left += s;
if (m_dma.right) chout[2] = s;
}
if (m_dma.right) {
*right += s; *right += s;
chout[2] = s;
}
m_dma.pos += m_dma.step; m_dma.pos += m_dma.step;
if (m_dma.pos >= m_dma.size) { if (m_dma.pos >= m_dma.size) {
m_dma.on = FALSE; m_dma.on = FALSE;
} }
} }
*/
if (decrement_tick > SV_DEC_TICK) { if (decrement_tick > SV_DEC_TICK) {
decrement_tick = 0; decrement_tick = 0;
supervision_sound_decrement(); supervision_sound_decrement();

View file

@ -28,6 +28,8 @@ void supervision_memorymap_registers_write(uint32 Addr, uint8 Value);
void supervision_set_mute_mask(uint32 mask); void supervision_set_mute_mask(uint32 mask);
void supervision_sound_set_flags(uint32 flags_set); void supervision_sound_set_flags(uint32 flags_set);
extern uint8 supervision_dma_mem[65536];
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View file

@ -19,6 +19,7 @@
#include "supervision.h" #include "supervision.h"
#include "../engine.h" #include "../engine.h"
#include "../../ta-log.h"
#include "furIcons.h" #include "furIcons.h"
#include <math.h> #include <math.h>
@ -60,6 +61,9 @@ const char** DivPlatformSupervision::getRegisterSheet() {
return regCheatSheetSupervision; return regCheatSheetSupervision;
} }
unsigned char* sampleMem = supervision_dma_mem;
unsigned char duty_swap = 0; unsigned char duty_swap = 0;
unsigned char otherFlags = 0; unsigned char otherFlags = 0;
@ -107,7 +111,7 @@ void DivPlatformSupervision::tick(bool sysTick) {
} else if (chan[i].std.arp.had) { } else if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
int f = parent->calcArp(chan[i].note,chan[i].std.arp.val); int f = parent->calcArp(chan[i].note,chan[i].std.arp.val);
if (i == 3) { if (i==2 || i==3) {
chan[i].baseFreq=f; chan[i].baseFreq=f;
//if (chan[i].baseFreq>255) chan[i].baseFreq=255; //if (chan[i].baseFreq>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0; if (chan[i].baseFreq<0) chan[i].baseFreq=0;
@ -120,6 +124,9 @@ void DivPlatformSupervision::tick(bool sysTick) {
if (chan[i].std.duty.had) { if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val; 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.had) {
if (chan[i].std.pitch.mode) { if (chan[i].std.pitch.mode) {
chan[i].pitch2+=chan[i].std.pitch.val; chan[i].pitch2+=chan[i].std.pitch.val;
@ -156,6 +163,25 @@ void DivPlatformSupervision::tick(bool sysTick) {
if (noiseReg[0] != r) rWrite(0x28,r); if (noiseReg[0] != r) rWrite(0x28,r);
noiseReg[0] = 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 && sNum<parent->song.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].keyOn) kon[i] = 1;
if (chan[i].keyOff) kon[i] = 0; if (chan[i].keyOff) kon[i] = 0;
if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOn) chan[i].keyOn=false;
@ -169,7 +195,7 @@ void DivPlatformSupervision::tick(bool sysTick) {
rWrite(0x13|(i<<2),0xc8); rWrite(0x13|(i<<2),0xc8);
} else if (i == 3) { } else if (i == 3) {
rWrite(0x29,0xc8); 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); if (noiseReg[2] != r) rWrite(0x2A,r);
noiseReg[2] = r; noiseReg[2] = r;
} }
@ -191,10 +217,21 @@ void DivPlatformSupervision::tick(bool sysTick) {
int DivPlatformSupervision::dispatch(DivCommand c) { int DivPlatformSupervision::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE); DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SUPERVISION);
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
chan[c.chan].sampleNote=DIV_NOTE_NULL; chan[c.chan].pcm=true;
chan[c.chan].sampleNoteDelta=0; } 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) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=c.chan==3?c.value:NOTE_PERIODIC(c.value); chan[c.chan].baseFreq=c.chan==3?c.value:NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
@ -273,6 +310,10 @@ int DivPlatformSupervision::dispatch(DivCommand c) {
case DIV_CMD_STD_NOISE_MODE: case DIV_CMD_STD_NOISE_MODE:
chan[c.chan].duty=c.value; chan[c.chan].duty=c.value;
break; break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].hasOffset=c.value;
chan[c.chan].keyOn=true;
break;
case DIV_CMD_LEGATO: 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].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
@ -280,7 +321,7 @@ int DivPlatformSupervision::dispatch(DivCommand c) {
break; break;
case DIV_CMD_PRE_PORTA: case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) { 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); 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; chan[c.chan].inPorta=c.value;
@ -400,6 +441,79 @@ void DivPlatformSupervision::poke(std::vector<DivRegWrite>& wlist) {
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); 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; i<parent->song.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<len>>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) { int DivPlatformSupervision::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p; parent=p;
dumpWrites=false; dumpWrites=false;
@ -408,6 +522,8 @@ int DivPlatformSupervision::init(DivEngine* p, int channels, int sugRate, const
isMuted[i]=false; isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer; oscBuf[i]=new DivDispatchOscBuffer;
} }
sampleMemLen=0;
memset(sampleMem,0,65536);
setFlags(flags); setFlags(flags);
reset(); reset();
return 4; return 4;

View file

@ -26,13 +26,16 @@
class DivPlatformSupervision: public DivDispatch { class DivPlatformSupervision: public DivDispatch {
struct Channel: public SharedChannel<signed char> { struct Channel: public SharedChannel<signed char> {
int dacPeriod, dacRate, dacOut; unsigned int duty, len, pan, pcm; // pcm is channel 3 ONLY
unsigned int duty, len; int sample, hasOffset; // again, for channel 3 ONLY
bool setPos; bool setPos;
Channel(): Channel():
SharedChannel<signed char>(31), SharedChannel<signed char>(31),
duty(0), duty(0),
len(0x1f), len(0x1f),
pan(3),
pcm(false),
hasOffset(0),
setPos(false) {} setPos(false) {}
}; };
Channel chan[4]; Channel chan[4];
@ -51,6 +54,13 @@ class DivPlatformSupervision: public DivDispatch {
int tempR[32]; int tempR[32];
int coreQuality; int coreQuality;
unsigned char regPool[64]; 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 putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
public: public:
@ -72,6 +82,12 @@ class DivPlatformSupervision: public DivDispatch {
void poke(unsigned int addr, unsigned short val); void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist); void poke(std::vector<DivRegWrite>& wlist);
const char** getRegisterSheet(); 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); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void quit(); void quit();
~DivPlatformSupervision(); ~DivPlatformSupervision();

View file

@ -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(_("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(_("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(_("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(_("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)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
break; break;