mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-26 14:33:01 +00:00
finally added DMA sample support and panning
This commit is contained in:
parent
6f370e9d62
commit
3e774ddb6f
5 changed files with 157 additions and 17 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "supervision.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include "furIcons.h"
|
||||
#include <math.h>
|
||||
|
||||
|
@ -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 && 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].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<DivRegWrite>& 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; 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) {
|
||||
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;
|
||||
|
|
|
@ -26,13 +26,16 @@
|
|||
|
||||
class DivPlatformSupervision: public DivDispatch {
|
||||
struct Channel: public SharedChannel<signed char> {
|
||||
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<signed char>(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<DivRegWrite>& 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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue