Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt

This commit is contained in:
cam900 2022-09-27 00:01:10 +09:00
commit 013c7b92fb
42 changed files with 383 additions and 248 deletions

View File

@ -75,6 +75,7 @@ additional guidelines:
- if you are making major changes to the playback routine, make sure to test with older songs to ensure nothing breaks.
- I will run a test suite to make sure this is the case.
- if something breaks, you might want to add a compatibility flag (this requires changing the format though).
- do not use `#pragma once`.
## Demo Songs

View File

@ -3685,6 +3685,8 @@ bool DivEngine::initAudioBackend() {
clampSamples=getConfInt("clampSamples",0);
lowLatency=getConfInt("lowLatency",0);
metroVol=(float)(getConfInt("metroVol",100))/100.0f;
midiOutClock=getConfInt("midiOutClock",0);
midiOutMode=getConfInt("midiOutMode",DIV_MIDI_MODE_NOTE);
if (metroVol<0.0f) metroVol=0.0f;
if (metroVol>2.0f) metroVol=2.0f;

View File

@ -83,6 +83,12 @@ enum DivHaltPositions {
DIV_HALT_BREAKPOINT
};
enum DivMIDIModes {
DIV_MIDI_MODE_OFF=0,
DIV_MIDI_MODE_NOTE,
DIV_MIDI_MODE_LIGHT_SHOW
};
struct DivChannelState {
std::vector<DivDelayedCommand> delayed;
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
@ -340,6 +346,8 @@ class DivEngine {
bool lowLatency;
bool systemsRegistered;
bool hasLoadedSomething;
bool midiOutClock;
int midiOutMode;
int softLockCount;
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed;
size_t curSubSongIndex;
@ -1008,6 +1016,8 @@ class DivEngine {
lowLatency(false),
systemsRegistered(false),
hasLoadedSomething(false),
midiOutClock(false),
midiOutMode(DIV_MIDI_MODE_NOTE),
softLockCount(0),
subticks(0),
ticks(0),

View File

@ -115,7 +115,7 @@ const unsigned char dacLogTableAY[256]={
void DivPlatformAY8910::runDAC() {
for (int i=0; i<3; i++) {
if (chan[i].active && chan[i].currPSGMode.dac && chan[i].dac.sample!=-1) {
if (chan[i].active && chan[i].curPSGMode.dac && chan[i].dac.sample!=-1) {
chan[i].dac.period+=chan[i].dac.rate;
bool end=false;
bool changed=false;
@ -215,22 +215,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
void DivPlatformAY8910::updateOutSel(bool immediate) {
if (immediate) {
immWrite(0x07,
~((chan[0].currPSGMode.getTone())|
((chan[1].currPSGMode.getTone())<<1)|
((chan[2].currPSGMode.getTone())<<2)|
((chan[0].currPSGMode.getNoise())<<2)|
((chan[1].currPSGMode.getNoise())<<3)|
((chan[2].currPSGMode.getNoise())<<4)|
~((chan[0].curPSGMode.getTone())|
((chan[1].curPSGMode.getTone())<<1)|
((chan[2].curPSGMode.getTone())<<2)|
((chan[0].curPSGMode.getNoise())<<2)|
((chan[1].curPSGMode.getNoise())<<3)|
((chan[2].curPSGMode.getNoise())<<4)|
((!ioPortA)<<6)|
((!ioPortB)<<7)));
} else {
rWrite(0x07,
~((chan[0].currPSGMode.getTone())|
((chan[1].currPSGMode.getTone())<<1)|
((chan[2].currPSGMode.getTone())<<2)|
((chan[0].currPSGMode.getNoise())<<2)|
((chan[1].currPSGMode.getNoise())<<3)|
((chan[2].currPSGMode.getNoise())<<4)|
~((chan[0].curPSGMode.getTone())|
((chan[1].curPSGMode.getTone())<<1)|
((chan[2].curPSGMode.getTone())<<2)|
((chan[0].curPSGMode.getNoise())<<2)|
((chan[1].curPSGMode.getNoise())<<3)|
((chan[2].curPSGMode.getNoise())<<4)|
((!ioPortA)<<6)|
((!ioPortB)<<7)));
}
@ -266,7 +266,7 @@ void DivPlatformAY8910::tick(bool sysTick) {
if (!chan[i].nextPSGMode.dac) {
chan[i].nextPSGMode.val=(chan[i].std.wave.val+1)&7;
if (chan[i].active) {
chan[i].currPSGMode.val=chan[i].nextPSGMode.val;
chan[i].curPSGMode.val=chan[i].nextPSGMode.val;
}
if (isMuted[i]) {
rWrite(0x08+i,0);
@ -340,11 +340,11 @@ void DivPlatformAY8910::tick(bool sysTick) {
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
//rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
if (!chan[i].nextPSGMode.dac) {
chan[i].currPSGMode.val=chan[i].nextPSGMode.val;
chan[i].curPSGMode.val=chan[i].nextPSGMode.val;
}
}
if (chan[i].keyOff) {
chan[i].currPSGMode.val=0;
chan[i].curPSGMode.val=0;
rWrite(0x08+i,0);
}
rWrite((i)<<1,chan[i].freq&0xff);
@ -448,7 +448,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
}
chan[c.chan].dac.furnaceDAC=false;
}
chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac;
chan[c.chan].curPSGMode.dac=chan[c.chan].nextPSGMode.dac;
break;
}
if (c.value!=DIV_NOTE_NULL) {
@ -553,7 +553,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
if (c.value<16) {
chan[c.chan].nextPSGMode.val=(c.value+1)&7;
if (chan[c.chan].active) {
chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val;
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
@ -579,7 +579,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
chan[c.chan].nextPSGMode.envelope&=~1;
}
if (!chan[c.chan].nextPSGMode.dac && chan[c.chan].active) {
chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val;
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
@ -626,7 +626,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
case DIV_CMD_SAMPLE_MODE:
chan[c.chan].nextPSGMode.dac=(c.value>0)?1:0;
if (chan[c.chan].active) {
chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac;
chan[c.chan].curPSGMode.dac=chan[c.chan].nextPSGMode.dac;
}
break;
case DIV_CMD_SAMPLE_BANK:

View File

@ -57,7 +57,7 @@ class DivPlatformAY8910: public DivDispatch {
PSGMode(unsigned char v=0):
val(v) {}
};
PSGMode currPSGMode;
PSGMode curPSGMode;
PSGMode nextPSGMode;
struct DAC {
@ -85,7 +85,7 @@ class DivPlatformAY8910: public DivDispatch {
pitch2=0;
}
Channel():
currPSGMode(PSGMode(0)),
curPSGMode(PSGMode(0)),
nextPSGMode(PSGMode(1)),
dac(DAC()),
freq(0),

View File

@ -111,7 +111,7 @@ const unsigned char dacLogTableAY8930[256]={
void DivPlatformAY8930::runDAC() {
for (int i=0; i<3; i++) {
if (chan[i].active && chan[i].currPSGMode.dac && chan[i].dac.sample!=-1) {
if (chan[i].active && chan[i].curPSGMode.dac && chan[i].dac.sample!=-1) {
chan[i].dac.period+=chan[i].dac.rate;
bool end=false;
bool changed=false;
@ -195,22 +195,22 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l
void DivPlatformAY8930::updateOutSel(bool immediate) {
if (immediate) {
immWrite(0x07,
~((chan[0].currPSGMode.getTone())|
((chan[1].currPSGMode.getTone())<<1)|
((chan[2].currPSGMode.getTone())<<2)|
((chan[0].currPSGMode.getNoise())<<2)|
((chan[1].currPSGMode.getNoise())<<3)|
((chan[2].currPSGMode.getNoise())<<4)|
~((chan[0].curPSGMode.getTone())|
((chan[1].curPSGMode.getTone())<<1)|
((chan[2].curPSGMode.getTone())<<2)|
((chan[0].curPSGMode.getNoise())<<2)|
((chan[1].curPSGMode.getNoise())<<3)|
((chan[2].curPSGMode.getNoise())<<4)|
((!ioPortA)<<6)|
((!ioPortB)<<7)));
} else {
rWrite(0x07,
~((chan[0].currPSGMode.getTone())|
((chan[1].currPSGMode.getTone())<<1)|
((chan[2].currPSGMode.getTone())<<2)|
((chan[0].currPSGMode.getNoise())<<2)|
((chan[1].currPSGMode.getNoise())<<3)|
((chan[2].currPSGMode.getNoise())<<4)|
~((chan[0].curPSGMode.getTone())|
((chan[1].curPSGMode.getTone())<<1)|
((chan[2].curPSGMode.getTone())<<2)|
((chan[0].curPSGMode.getNoise())<<2)|
((chan[1].curPSGMode.getNoise())<<3)|
((chan[2].curPSGMode.getNoise())<<4)|
((!ioPortA)<<6)|
((!ioPortB)<<7)));
}
@ -256,7 +256,7 @@ void DivPlatformAY8930::tick(bool sysTick) {
if (!chan[i].nextPSGMode.dac) {
chan[i].nextPSGMode.val=(chan[i].std.wave.val+1)&7;
if (chan[i].active) {
chan[i].currPSGMode.val=chan[i].nextPSGMode.val;
chan[i].curPSGMode.val=chan[i].nextPSGMode.val;
}
if (isMuted[i]) {
rWrite(0x08+i,0);
@ -337,7 +337,7 @@ void DivPlatformAY8930::tick(bool sysTick) {
if (chan[i].freq>65535) chan[i].freq=65535;
if (chan[i].keyOn) {
if (!chan[i].nextPSGMode.dac) {
chan[i].currPSGMode.val=chan[i].nextPSGMode.val;
chan[i].curPSGMode.val=chan[i].nextPSGMode.val;
}
if (chan[i].insChanged) {
if (!chan[i].std.ex1.will) immWrite(0x16+i,chan[i].duty);
@ -345,7 +345,7 @@ void DivPlatformAY8930::tick(bool sysTick) {
}
}
if (chan[i].keyOff) {
chan[i].currPSGMode.val=0;
chan[i].curPSGMode.val=0;
rWrite(0x08+i,0);
}
rWrite((i)<<1,chan[i].freq&0xff);
@ -449,7 +449,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
}
chan[c.chan].dac.furnaceDAC=false;
}
chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac;
chan[c.chan].curPSGMode.dac=chan[c.chan].nextPSGMode.dac;
break;
}
if (c.value!=DIV_NOTE_NULL) {
@ -547,7 +547,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
if (!chan[c.chan].nextPSGMode.dac) {
chan[c.chan].nextPSGMode.val=(c.value+1)&7;
if (chan[c.chan].active) {
chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val;
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
@ -572,7 +572,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
chan[c.chan].nextPSGMode.envelope&=~1;
}
if (!chan[c.chan].nextPSGMode.dac && chan[c.chan].active) {
chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val;
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
@ -627,7 +627,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
break;
case DIV_CMD_SAMPLE_MODE:
chan[c.chan].nextPSGMode.dac=(c.value>0)?1:0;
chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac;
chan[c.chan].curPSGMode.dac=chan[c.chan].nextPSGMode.dac;
break;
case DIV_CMD_SAMPLE_BANK:
sampleBank=c.value;

View File

@ -65,7 +65,7 @@ class DivPlatformAY8930: public DivDispatch {
PSGMode(unsigned char v=0):
val(v) {}
};
PSGMode currPSGMode;
PSGMode curPSGMode;
PSGMode nextPSGMode;
struct DAC {
@ -94,7 +94,7 @@ class DivPlatformAY8930: public DivDispatch {
}
Channel():
envelope(Envelope()),
currPSGMode(PSGMode(0)),
curPSGMode(PSGMode(0)),
nextPSGMode(PSGMode(1)),
dac(DAC()),
freq(0),

View File

@ -220,6 +220,7 @@ void DivPlatformES5506::e_pin(bool state)
DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next];
int sample=transWaveInd.ind;
if (sample>=0 && sample<parent->song.sampleLen) {
const unsigned int offES5506=sampleOffES5506[sample];
chan[ch].pcm.index=sample;
chan[ch].transWave.ind=next;
DivSample* s=parent->getSample(sample);
@ -254,13 +255,13 @@ void DivPlatformES5506::e_pin(bool state)
if (transWaveInd.reversed!=2) {
reversed=transWaveInd.reversed;
}
const unsigned int start=s->offES5506<<10;
const unsigned int start=offES5506<<10;
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
const double nextFreqOffs=PITCH_OFFSET*off;
chan[ch].pcm.loopMode=loopMode;
chan[ch].pcm.reversed=reversed;
chan[ch].pcm.bank=(s->offES5506>>22)&3;
chan[ch].pcm.bank=(offES5506>>22)&3;
chan[ch].pcm.start=start;
chan[ch].pcm.loopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800;
chan[ch].pcm.loopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80;
@ -633,6 +634,7 @@ void DivPlatformES5506::tick(bool sysTick) {
sample=noteMapind.map;
}
if (sample>=0 && sample<parent->song.sampleLen) {
const unsigned int offES5506=sampleOffES5506[sample];
sampleVaild=true;
chan[i].pcm.index=sample;
chan[i].pcm.isNoteMap=ins->amiga.useNoteMap && !ins->amiga.transWave.enable;
@ -678,10 +680,10 @@ void DivPlatformES5506::tick(bool sysTick) {
} else if (ins->amiga.useNoteMap&&noteMapind.reversed!=2) {
reversed=noteMapind.reversed;
}
const unsigned int start=s->offES5506<<10;
const unsigned int start=offES5506<<10;
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
const unsigned int nextBank=(s->offES5506>>22)&3;
const unsigned int nextBank=(offES5506>>22)&3;
const double nextFreqOffs=PITCH_OFFSET*off;
chan[i].pcm.loopMode=loopMode;
chan[i].pcm.reversed=reversed;
@ -722,7 +724,7 @@ void DivPlatformES5506::tick(bool sysTick) {
loopStart=chan[i].transWave.sliceStart;
loopEnd=chan[i].transWave.sliceEnd;
}
const unsigned int start=s->offES5506<<10;
const unsigned int start=sampleOffES5506[chan[i].pcm.index]<<10;
const unsigned int nextLoopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800;
const unsigned int nextLoopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80;
if ((chan[i].pcm.loopStart!=nextLoopStart) || (chan[i].pcm.loopEnd!=nextLoopEnd)) {
@ -941,6 +943,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
sample=noteMapind.map;
}
if (sample>=0 && sample<parent->song.sampleLen) {
const unsigned int offES5506=sampleOffES5506[sample];
sampleVaild=true;
chan[c.chan].pcm.index=chan[c.chan].pcm.next=sample;
chan[c.chan].pcm.pause=(chan[c.chan].std.alg.will)?(chan[c.chan].std.alg.val&1):false;
@ -989,13 +992,13 @@ int DivPlatformES5506::dispatch(DivCommand c) {
} else if (ins->amiga.useNoteMap&&noteMapind.reversed!=2) {
reversed=noteMapind.reversed;
}
const unsigned int start=s->offES5506<<10;
const unsigned int start=offES5506<<10;
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
chan[c.chan].pcm.loopMode=loopMode;
chan[c.chan].pcm.freqOffs=PITCH_OFFSET*off;
chan[c.chan].pcm.reversed=reversed;
chan[c.chan].pcm.bank=(s->offES5506>>22)&3;
chan[c.chan].pcm.bank=(offES5506>>22)&3;
chan[c.chan].pcm.start=start;
chan[c.chan].pcm.end=end;
chan[c.chan].pcm.length=length;
@ -1372,6 +1375,7 @@ size_t DivPlatformES5506::getSampleMemUsage(int index) {
void DivPlatformES5506::renderSamples() {
memset(sampleMem,0,getSampleMemCapacity());
memset(sampleOffES5506,0,256*sizeof(unsigned int));
size_t memPos=128;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -1394,7 +1398,7 @@ void DivPlatformES5506::renderSamples() {
} else {
memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length);
}
s->offES5506=memPos;
sampleOffES5506[i]=memPos;
memPos+=length;
}
sampleMemLen=memPos+256;

View File

@ -212,6 +212,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
bool isMuted[32];
signed short* sampleMem; // ES5506 uses 16 bit data bus for samples
size_t sampleMemLen;
unsigned int sampleOffES5506[256];
struct QueuedHostIntf {
unsigned char state;
unsigned char step;

View File

@ -432,7 +432,11 @@ int DivPlatformGB::dispatch(DivCommand c) {
chan[c.chan].envVol=chan[c.chan].vol;
chan[c.chan].soManyHacksToMakeItDefleCompatible=true;
} else if (c.chan!=2) {
chan[c.chan].envVol=chan[c.chan].vol;
if (chan[c.chan].std.vol.will && !chan[c.chan].std.vol.finished) {
chan[c.chan].outVol=VOL_SCALE_LINEAR(chan[c.chan].vol&15,MIN(15,chan[c.chan].std.vol.val),15);
}
chan[c.chan].envVol=chan[c.chan].outVol;
if (!chan[c.chan].keyOn) chan[c.chan].killIt=true;
chan[c.chan].freqChanged=true;
}

View File

@ -382,7 +382,6 @@ void DivPlatformMSM6258::renderSamples() {
} else {
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
}
s->offVOX=memPos;
memPos+=paddedLen;
}
adpcmMemLen=memPos+256;

View File

@ -336,7 +336,10 @@ size_t DivPlatformMSM6295::getSampleMemUsage(int index) {
}
void DivPlatformMSM6295::renderSamples() {
unsigned int sampleOffVOX[256];
memset(adpcmMem,0,getSampleMemCapacity(0));
memset(sampleOffVOX,0,256*sizeof(unsigned int));
// sample data
size_t memPos=128*8;
@ -355,7 +358,7 @@ void DivPlatformMSM6295::renderSamples() {
} else {
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
}
s->offVOX=memPos;
sampleOffVOX[i]=memPos;
memPos+=paddedLen;
}
adpcmMemLen=memPos+256;
@ -363,10 +366,10 @@ void DivPlatformMSM6295::renderSamples() {
// phrase book
for (int i=0; i<sampleCount; i++) {
DivSample* s=parent->song.sample[i];
int endPos=s->offVOX+s->lengthVOX;
adpcmMem[i*8]=(s->offVOX>>16)&0xff;
adpcmMem[1+i*8]=(s->offVOX>>8)&0xff;
adpcmMem[2+i*8]=(s->offVOX)&0xff;
int endPos=sampleOffVOX[i]+s->lengthVOX;
adpcmMem[i*8]=(sampleOffVOX[i]>>16)&0xff;
adpcmMem[1+i*8]=(sampleOffVOX[i]>>8)&0xff;
adpcmMem[2+i*8]=(sampleOffVOX[i])&0xff;
adpcmMem[3+i*8]=(endPos>>16)&0xff;
adpcmMem[4+i*8]=(endPos>>8)&0xff;
adpcmMem[5+i*8]=(endPos)&0xff;

View File

@ -317,7 +317,7 @@ void DivPlatformNES::tick(bool sysTick) {
dacRate=MIN(chan[4].freq*off,32000);
if (chan[4].keyOn) {
if (dpcmMode && !skipRegisterWrites && dacSample>=0 && dacSample<parent->song.sampleLen) {
unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM;
unsigned int dpcmAddr=sampleOffDPCM[dacSample];
unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4;
if (dpcmLen>255) dpcmLen=255;
goingToLoop=parent->getSample(dacSample)->isLoopable();
@ -383,7 +383,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate);
chan[c.chan].furnaceDac=false;
if (dpcmMode && !skipRegisterWrites) {
unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM;
unsigned int dpcmAddr=sampleOffDPCM[dacSample];
unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4;
if (dpcmLen>255) dpcmLen=255;
goingToLoop=parent->getSample(dacSample)->isLoopable();
@ -724,7 +724,7 @@ void DivPlatformNES::renderSamples() {
} else {
memcpy(dpcmMem+memPos,s->dataDPCM,MIN(s->lengthDPCM,paddedLen));
}
s->offDPCM=memPos;
sampleOffDPCM[i]=memPos;
memPos+=paddedLen;
}
dpcmMemLen=memPos;

View File

@ -78,6 +78,7 @@ class DivPlatformNES: public DivDispatch {
xgm::NES_APU* nes1_NP;
xgm::NES_DMC* nes2_NP;
unsigned char regPool[128];
unsigned int sampleOffDPCM[256];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);

View File

@ -690,9 +690,9 @@ int DivPlatformOPL::dispatch(DivCommand c) {
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[c.chan].sample);
immWrite(8,0);
immWrite(9,(s->offB>>2)&0xff);
immWrite(10,(s->offB>>10)&0xff);
int end=s->offB+s->lengthB-1;
immWrite(9,(sampleOffB[chan[c.chan].sample]>>2)&0xff);
immWrite(10,(sampleOffB[chan[c.chan].sample]>>10)&0xff);
int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1;
immWrite(11,(end>>2)&0xff);
immWrite(12,(end>>10)&0xff);
if (c.value!=DIV_NOTE_NULL) {
@ -721,9 +721,9 @@ int DivPlatformOPL::dispatch(DivCommand c) {
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
immWrite(8,0);
immWrite(9,(s->offB>>2)&0xff);
immWrite(10,(s->offB>>10)&0xff);
int end=s->offB+s->lengthB-1;
immWrite(9,(sampleOffB[chan[c.chan].sample]>>2)&0xff);
immWrite(10,(sampleOffB[chan[c.chan].sample]>>10)&0xff);
int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1;
immWrite(11,(end>>2)&0xff);
immWrite(12,(end>>10)&0xff);
int freq=(65536.0*(double)s->rate)/(double)chipRateBase;
@ -1760,6 +1760,7 @@ size_t DivPlatformOPL::getSampleMemUsage(int index) {
void DivPlatformOPL::renderSamples() {
if (adpcmChan<0) return;
memset(adpcmBMem,0,getSampleMemCapacity(0));
memset(sampleOffB,0,256*sizeof(unsigned int));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -1778,7 +1779,7 @@ void DivPlatformOPL::renderSamples() {
} else {
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
}
s->offB=memPos;
sampleOffB[i]=memPos;
memPos+=paddedLen;
}
adpcmBMemLen=memPos+256;

View File

@ -90,6 +90,7 @@ class DivPlatformOPL: public DivDispatch {
unsigned char* adpcmBMem;
size_t adpcmBMemLen;
DivOPLAInterface iface;
unsigned int sampleOffB[256];
ymfm::adpcm_b_engine* adpcmB;
const unsigned char** slotsNonDrums;

View File

@ -286,8 +286,8 @@ void DivPlatformQSound::tick(bool sysTick) {
uint16_t qsound_end = 0;
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[i].sample);
qsound_bank = 0x8000 | (s->offQSound >> 16);
qsound_addr = s->offQSound & 0xffff;
qsound_bank = 0x8000 | (offPCM[chan[i].sample] >> 16);
qsound_addr = offPCM[chan[i].sample] & 0xffff;
int loopStart=s->loopStart;
int length = s->loopEnd;
@ -295,10 +295,10 @@ void DivPlatformQSound::tick(bool sysTick) {
length = 65536 - 16;
}
if (loopStart == -1 || loopStart >= length) {
qsound_end = s->offQSound + length + 15;
qsound_end = offPCM[chan[i].sample] + length + 15;
qsound_loop = 15;
} else {
qsound_end = s->offQSound + length;
qsound_end = offPCM[chan[i].sample] + length;
qsound_loop = length - loopStart;
}
}
@ -644,6 +644,7 @@ size_t DivPlatformQSound::getSampleMemUsage(int index) {
return index == 0 ? sampleMemLen : 0;
}
// TODO: ADPCM... come on...
void DivPlatformQSound::renderSamples() {
memset(sampleMem,0,getSampleMemCapacity());
@ -671,7 +672,7 @@ void DivPlatformQSound::renderSamples() {
sampleMem[(memPos+i)^0x8000]=s->data8[i];
}
}
s->offQSound=memPos^0x8000;
offPCM[i]=memPos^0x8000;
memPos+=length+16;
}
sampleMemLen=memPos+256;

View File

@ -72,6 +72,9 @@ class DivPlatformQSound: public DivDispatch {
struct qsound_chip chip;
unsigned short regPool[512];
unsigned int offPCM[256];
unsigned int offBS[256];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);

View File

@ -130,8 +130,12 @@ void DivPlatformRF5C68::tick(bool sysTick) {
chan[i].freq=(int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE));
if (chan[i].freq>65535) chan[i].freq=65535;
if (chan[i].keyOn) {
unsigned int start=s->offRF5C68;
unsigned int loop=start+s->length8;
unsigned int start=0;
unsigned int loop=0;
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
start=sampleOffRFC[chan[i].sample];
loop=start+s->length8;
}
if (chan[i].audPos>0) {
start=start+MIN(chan[i].audPos,s->length8);
}
@ -383,6 +387,7 @@ size_t DivPlatformRF5C68::getSampleMemUsage(int index) {
void DivPlatformRF5C68::renderSamples() {
memset(sampleMem,0,getSampleMemCapacity());
memset(sampleOffRFC,0,256*sizeof(unsigned int));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -390,7 +395,7 @@ void DivPlatformRF5C68::renderSamples() {
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
if (actualLength>0) {
s->offRF5C68=memPos;
sampleOffRFC[i]=memPos;
for (int j=0; j<actualLength; j++) {
// convert to signed magnitude
signed char val=s->data8[j];

View File

@ -66,6 +66,7 @@ class DivPlatformRF5C68: public DivDispatch {
bool isMuted[8];
int chipType;
unsigned char curChan;
unsigned int sampleOffRFC[256];
unsigned char* sampleMem;
size_t sampleMemLen;

View File

@ -20,6 +20,7 @@
// TODO: new macro formula
#include "segapcm.h"
#include "../engine.h"
#include "../../ta-log.h"
#include <string.h>
#include <math.h>
@ -159,17 +160,17 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff;
addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3));
addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff);
addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff);
addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
addWrite(0x10086+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
addWrite(0x10084+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
addWrite(0x10085+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
addWrite(0x10006+(i<<3),MIN(255,((sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+actualLength-1)>>8));
if (loopStart<0 || loopStart>=actualLength) {
addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3));
addWrite(0x10086+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
} else {
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart+s->loopOffP;
addWrite(0x10004+(i<<3),loopPos&0xff);
addWrite(0x10005+(i<<3),(loopPos>>8)&0xff);
addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3));
addWrite(0x10086+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
}
}
} else {
@ -178,17 +179,17 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>65536) actualLength=65536;
addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3));
addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff);
addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff);
addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
addWrite(0x10086+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
addWrite(0x10084+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
addWrite(0x10085+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
addWrite(0x10006+(i<<3),MIN(255,((sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+actualLength-1)>>8));
if (loopStart<0 || loopStart>=actualLength) {
addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3));
addWrite(0x10086+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
} else {
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart+s->loopOffP;
addWrite(0x10004+(i<<3),loopPos&0xff);
addWrite(0x10005+(i<<3),(loopPos>>8)&0xff);
addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3));
addWrite(0x10086+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
}
addWrite(0x10007+(i<<3),chan[i].pcm.freq);
}
@ -451,6 +452,39 @@ void DivPlatformSegaPCM::reset() {
}
}
void DivPlatformSegaPCM::renderSamples() {
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
DivSample* sample=parent->getSample(i);
unsigned int alignedSize=(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff);
if (alignedSize>65536) alignedSize=65536;
if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) {
memPos=(memPos+0xffff)&0xff0000;
}
logV("- sample %d will be at %x with length %x",i,memPos,alignedSize);
if (memPos>=16777216) break;
sampleOffSegaPCM[i]=memPos;
unsigned int readPos=0;
for (unsigned int j=0; j<alignedSize; j++) {
if (readPos>=(unsigned int)sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
if (sample->isLoopable()) {
readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
memPos++;
} else {
memPos++;
}
} else {
memPos++;
}
readPos++;
if (memPos>=16777216) break;
}
sample->loopOffP=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
if (memPos>=16777216) break;
}
}
void DivPlatformSegaPCM::setFlags(unsigned int flags) {
chipClock=8000000.0;
rate=31250;

View File

@ -91,6 +91,8 @@ class DivPlatformSegaPCM: public DivDispatch {
short oldWrites[256];
short pendingWrites[256];
unsigned int sampleOffSegaPCM[256];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
@ -108,6 +110,7 @@ class DivPlatformSegaPCM: public DivDispatch {
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void notifyInsChange(int ins);
void renderSamples();
void setFlags(unsigned int flags);
bool isStereo();
void poke(unsigned int addr, unsigned short val);

View File

@ -83,7 +83,13 @@ void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len
bufL[h]=out[0];
bufR[h]=out[1];
for (int i=0; i<8; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=chOut[i*2]+chOut[i*2+1];
int next=chOut[i*2]+chOut[i*2+1];
if (next<-32768) next=-32768;
if (next>32767) next=32767;
next=(next*254)/MAX(1,globalVolL+globalVolR);
if (next<-32768) next=-32768;
if (next>32767) next=32767;
oscBuf[i]->data[oscBuf[i]->needle++]=next;
}
}
}
@ -133,12 +139,10 @@ void DivPlatformSNES::tick(bool sysTick) {
chan[i].freqChanged=true;
}
if (chan[i].std.panL.had) {
int val=chan[i].std.panL.val&0x7f;
chan[i].panL=(val<<1)|(val>>6);
chan[i].panL=chan[i].std.panL.val&0x7f;
}
if (chan[i].std.panR.had) {
int val=chan[i].std.panR.val&0x7f;
chan[i].panR=(val<<1)|(val>>6);
chan[i].panR=chan[i].std.panR.val&0x7f;
}
bool hasInverted=false;
if (chan[i].std.ex1.had) {
@ -190,8 +194,8 @@ void DivPlatformSNES::tick(bool sysTick) {
if (chan[i].useWave) {
start=waveTableAddr(i);
loop=start;
} else {
start=s->offSNES;
} else if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
start=sampleOff[chan[i].sample];
end=MIN(start+MAX(s->lengthBRR,1),getSampleMemCapacity());
loop=MAX(start,end-1);
if (chan[i].audPos>0) {
@ -200,6 +204,10 @@ void DivPlatformSNES::tick(bool sysTick) {
if (s->loopStart>=0) {
loop=start+s->loopStart/16*9;
}
} else {
start=0;
end=0;
loop=0;
}
sampleMem[tabAddr+0]=start&0xff;
sampleMem[tabAddr+1]=start>>8;
@ -358,8 +366,8 @@ int DivPlatformSNES::dispatch(DivCommand c) {
return chan[c.chan].vol;
break;
case DIV_CMD_PANNING:
chan[c.chan].panL=c.value;
chan[c.chan].panR=c.value2;
chan[c.chan].panL=c.value>>1;
chan[c.chan].panR=c.value2>>1;
writeOutVol(c.chan);
break;
case DIV_CMD_PITCH:
@ -505,7 +513,7 @@ void DivPlatformSNES::reset() {
chan[i]=Channel();
chan[i].std.setEngine(parent);
chan[i].ws.setEngine(parent);
chan[i].ws.init(NULL,32,255);
chan[i].ws.init(NULL,32,15);
writeOutVol(i);
chWrite(i,4,i); // source number
}
@ -567,6 +575,7 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) {
void DivPlatformSNES::renderSamples() {
memset(sampleMem,0,getSampleMemCapacity());
memset(sampleOff,0,256*sizeof(unsigned int));
// skip past sample table and wavetable buffer
size_t memPos=sampleTableBase+8*4+8*9*16;
@ -575,7 +584,7 @@ void DivPlatformSNES::renderSamples() {
int length=s->lengthBRR;
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
if (actualLength>0) {
s->offSNES=memPos;
sampleOff[i]=memPos;
memcpy(&sampleMem[memPos],s->dataBRR,actualLength);
memPos+=actualLength;
}

View File

@ -75,7 +75,7 @@ class DivPlatformSNES: public DivDispatch {
Channel chan[8];
DivDispatchOscBuffer* oscBuf[8];
bool isMuted[8];
signed char globalVolL, globalVolR;
int globalVolL, globalVolR;
unsigned char noiseFreq;
size_t sampleTableBase;
bool writeControl;
@ -92,6 +92,7 @@ class DivPlatformSNES: public DivDispatch {
signed char sampleMem[65536];
size_t sampleMemLen;
unsigned int sampleOff[256];
unsigned char regPool[0x80];
SPC_DSP dsp;
friend void putDispatchChan(void*,int,int);

View File

@ -161,10 +161,11 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
if (chan[i].keyOn) {
if (chan[i].pcm) {
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note));
if (sample!=NULL) {
unsigned int sampleEnd=sample->offSU+(sample->getLoopEndPosition());
unsigned int off=sample->offSU+chan[i].hasOffset;
int sNum=ins->amiga.getSample(chan[i].note);
DivSample* sample=parent->getSample(sNum);
if (sample!=NULL && sNum>=0 && sNum<parent->song.sampleLen) {
unsigned int sampleEnd=sampleOffSU[sNum]+(sample->getLoopEndPosition());
unsigned int off=sampleOffSU[sNum]+chan[i].hasOffset;
chan[i].hasOffset=0;
if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1;
chWrite(i,0x0a,off&0xff);
@ -172,7 +173,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
chWrite(i,0x0c,sampleEnd&0xff);
chWrite(i,0x0d,sampleEnd>>8);
if (sample->isLoopable()) {
unsigned int sampleLoop=sample->offSU+sample->getLoopStartPosition();
unsigned int sampleLoop=sampleOffSU[sNum]+sample->getLoopStartPosition();
if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1;
chWrite(i,0x0e,sampleLoop&0xff);
chWrite(i,0x0f,sampleLoop>>8);
@ -547,6 +548,7 @@ size_t DivPlatformSoundUnit::getSampleMemUsage(int index) {
void DivPlatformSoundUnit::renderSamples() {
memset(su->pcm,0,getSampleMemCapacity(0));
memset(sampleOffSU,0,256*sizeof(unsigned int));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -563,7 +565,7 @@ void DivPlatformSoundUnit::renderSamples() {
} else {
memcpy(su->pcm+memPos,s->data8,paddedLen);
}
s->offSU=memPos;
sampleOffSU[i]=memPos;
memPos+=paddedLen;
}
sampleMemLen=memPos;

View File

@ -101,6 +101,7 @@ class DivPlatformSoundUnit: public DivDispatch {
unsigned char ilCtrl, ilSize, fil1;
unsigned char initIlCtrl, initIlSize, initFil1;
signed char echoVol, initEchoVol;
unsigned int sampleOffSU[256];
int cycles, curChan, delay;
short tempL;

View File

@ -541,14 +541,14 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
DivSample* s=parent->getSample(chan[c.chan].sample);
if (isBanked) {
chan[c.chan].bankSlot=ins->x1_010.bankSlot;
bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17;
unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff);
bankSlot[chan[c.chan].bankSlot]=sampleOffX1[chan[c.chan].sample]>>17;
unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(sampleOffX1[chan[c.chan].sample]&0x1ffff);
chWrite(c.chan,4,(bankedOffs>>12)&0xff);
int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
} else {
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
chWrite(c.chan,4,(sampleOffX1[chan[c.chan].sample]>>12)&0xff);
int end=(sampleOffX1[chan[c.chan].sample]+s->length8+0xfff)&~0xfff; // padded
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
}
if (c.value!=DIV_NOTE_NULL) {
@ -581,14 +581,14 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
}
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
if (isBanked) {
bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17;
unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff);
bankSlot[chan[c.chan].bankSlot]=sampleOffX1[chan[c.chan].sample]>>17;
unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(sampleOffX1[chan[c.chan].sample]&0x1ffff);
chWrite(c.chan,4,(bankedOffs>>12)&0xff);
int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
} else {
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
chWrite(c.chan,4,(sampleOffX1[chan[c.chan].sample]>>12)&0xff);
int end=(sampleOffX1[chan[c.chan].sample]+s->length8+0xfff)&~0xfff; // padded
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
}
chan[c.chan].baseFreq=(((unsigned int)s->rate)<<4)/(chipClock/512);
@ -945,6 +945,7 @@ size_t DivPlatformX1_010::getSampleMemUsage(int index) {
void DivPlatformX1_010::renderSamples() {
memset(sampleMem,0,getSampleMemCapacity());
memset(sampleOffX1,0,256*sizeof(unsigned int));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -969,7 +970,7 @@ void DivPlatformX1_010::renderSamples() {
} else {
memcpy(sampleMem+memPos,s->data8,paddedLen);
}
s->offX1_010=memPos;
sampleOffX1[i]=memPos;
memPos+=paddedLen;
}
sampleMemLen=memPos+256;

View File

@ -115,6 +115,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
bool isBanked=false;
unsigned int bankSlot[8];
unsigned int sampleOffX1[256];
unsigned char regPool[0x2000];
double NoteX1_010(int ch, int note);

View File

@ -684,9 +684,9 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
chan[c.chan].sample=ins->amiga.getSample(c.value);
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[c.chan].sample);
immWrite(0x102,(s->offB>>5)&0xff);
immWrite(0x103,(s->offB>>13)&0xff);
int end=s->offB+s->lengthB-1;
immWrite(0x102,(sampleOffB[chan[c.chan].sample]>>5)&0xff);
immWrite(0x103,(sampleOffB[chan[c.chan].sample]>>13)&0xff);
int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1;
immWrite(0x104,(end>>5)&0xff);
immWrite(0x105,(end>>13)&0xff);
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
@ -715,9 +715,9 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
chan[c.chan].sample=12*sampleBank+c.value%12;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[c.chan].sample);
immWrite(0x102,(s->offB>>5)&0xff);
immWrite(0x103,(s->offB>>13)&0xff);
int end=s->offB+s->lengthB-1;
immWrite(0x102,(sampleOffB[chan[c.chan].sample]>>5)&0xff);
immWrite(0x103,(sampleOffB[chan[c.chan].sample]>>13)&0xff);
int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1;
immWrite(0x104,(end>>5)&0xff);
immWrite(0x105,(end>>13)&0xff);
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
@ -1334,6 +1334,7 @@ size_t DivPlatformYM2608::getSampleMemUsage(int index) {
void DivPlatformYM2608::renderSamples() {
memset(adpcmBMem,0,getSampleMemCapacity(0));
memset(sampleOffB,0,256*sizeof(unsigned int));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -1352,7 +1353,7 @@ void DivPlatformYM2608::renderSamples() {
} else {
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
}
s->offB=memPos;
sampleOffB[i]=memPos;
memPos+=paddedLen;
}
adpcmBMemLen=memPos+256;

View File

@ -99,6 +99,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
unsigned char* adpcmBMem;
size_t adpcmBMemLen;
DivYM2608Interface iface;
unsigned int sampleOffB[256];
DivPlatformAY8910* ay;
unsigned char sampleBank;

View File

@ -623,9 +623,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
chan[c.chan].sample=ins->amiga.getSample(c.value);
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[c.chan].sample);
immWrite(0x12,(s->offB>>8)&0xff);
immWrite(0x13,s->offB>>16);
int end=((s->offB+s->lengthB+0xff)&~0xff)-1;
immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff);
immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16);
int end=((sampleOffB[chan[c.chan].sample]+s->lengthB+0xff)&~0xff)-1;
immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
@ -654,9 +654,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
chan[c.chan].sample=12*sampleBank+c.value%12;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
immWrite(0x12,(s->offB>>8)&0xff);
immWrite(0x13,s->offB>>16);
int end=s->offB+s->lengthB-1;
immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff);
immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16);
int end=((sampleOffB[chan[c.chan].sample]+s->lengthB+0xff)&~0xff)-1;
immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
@ -694,9 +694,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
chan[c.chan].sample=ins->amiga.getSample(c.value);
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[c.chan].sample);
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
int end=s->offA+s->lengthA-1;
immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16);
int end=((sampleOffA[chan[c.chan].sample]+s->lengthA+0xff)&~0xff)-1;
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
@ -725,9 +725,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
chan[c.chan].sample=12*sampleBank+c.value%12;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
int end=s->offA+s->lengthA-1;
immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16);
int end=((sampleOffA[chan[c.chan].sample]+s->lengthA+0xff)&~0xff)-1;
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));

View File

@ -686,9 +686,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
chan[c.chan].sample=ins->amiga.getSample(c.value);
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[c.chan].sample);
immWrite(0x12,(s->offB>>8)&0xff);
immWrite(0x13,s->offB>>16);
int end=((s->offB+s->lengthB+0xff)&~0xff)-1;
immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff);
immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16);
int end=((sampleOffB[chan[c.chan].sample]+s->lengthB+0xff)&~0xff)-1;
immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
@ -717,9 +717,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
chan[c.chan].sample=12*sampleBank+c.value%12;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
immWrite(0x12,(s->offB>>8)&0xff);
immWrite(0x13,s->offB>>16);
int end=s->offB+s->lengthB-1;
immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff);
immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16);
int end=((sampleOffB[chan[c.chan].sample]+s->lengthB+0xff)&~0xff)-1;
immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
@ -757,9 +757,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
chan[c.chan].sample=ins->amiga.getSample(c.value);
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(chan[c.chan].sample);
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
int end=s->offA+s->lengthA-1;
immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16);
int end=((sampleOffA[chan[c.chan].sample]+s->lengthA+0xff)&~0xff)-1;
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
@ -788,9 +788,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
chan[c.chan].sample=12*sampleBank+c.value%12;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
int end=s->offA+s->lengthA-1;
immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff);
immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16);
int end=((sampleOffA[chan[c.chan].sample]+s->lengthA+0xff)&~0xff)-1;
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));

View File

@ -136,6 +136,9 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
size_t adpcmBMemLen;
DivYM2610Interface iface;
unsigned int sampleOffA[256];
unsigned int sampleOffB[256];
unsigned char sampleBank;
bool extMode;
@ -207,6 +210,8 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
void renderSamples() {
memset(adpcmAMem,0,getSampleMemCapacity(0));
memset(sampleOffA,0,256*sizeof(unsigned int));
memset(sampleOffB,0,256*sizeof(unsigned int));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -225,7 +230,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
} else {
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
}
s->offA=memPos;
sampleOffA[i]=memPos;
memPos+=paddedLen;
}
adpcmAMemLen=memPos+256;
@ -249,7 +254,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
} else {
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
}
s->offB=memPos;
sampleOffB[i]=memPos;
memPos+=paddedLen;
}
adpcmBMemLen=memPos+256;

View File

@ -146,10 +146,14 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
if (s->depth==DIV_SAMPLE_DEPTH_YMZ_ADPCM && chan[i].freq>255) chan[i].freq=255;
ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|(chan[i].freq>>8);
if (chan[i].keyOn) {
unsigned int start=s->offYMZ280B;
unsigned int start=0;
unsigned int loopStart=0;
unsigned int loopEnd=0;
unsigned int end=MIN(start+s->getCurBufLen(),getSampleMemCapacity()-1);
unsigned int end=0;
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
start=sampleOff[chan[i].sample];
end=MIN(start+s->getCurBufLen(),getSampleMemCapacity()-1);
}
if (chan[i].audPos>0) {
switch (s->depth) {
case DIV_SAMPLE_DEPTH_YMZ_ADPCM: start+=chan[i].audPos/2; break;
@ -418,6 +422,7 @@ size_t DivPlatformYMZ280B::getSampleMemUsage(int index) {
void DivPlatformYMZ280B::renderSamples() {
memset(sampleMem,0,getSampleMemCapacity());
memset(sampleOff,0,256*sizeof(unsigned int));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
@ -427,7 +432,7 @@ void DivPlatformYMZ280B::renderSamples() {
int actualLength=MIN((int)(getSampleMemCapacity()-memPos),length);
if (actualLength>0) {
memcpy(&sampleMem[memPos],src,actualLength);
s->offYMZ280B=memPos;
sampleOff[i]=memPos;
memPos+=length;
}
if (actualLength<length) {

View File

@ -66,6 +66,7 @@ class DivPlatformYMZ280B: public DivDispatch {
DivDispatchOscBuffer* oscBuf[8];
bool isMuted[8];
int chipType;
unsigned int sampleOff[256];
unsigned char* sampleMem;
size_t sampleMemLen;

View File

@ -271,48 +271,79 @@ int DivEngine::dispatchCmd(DivCommand c) {
if (output) if (!skipping && output->midiOut!=NULL) {
if (output->midiOut->isDeviceOpen()) {
int scaledVol=(chan[c.chan].volume*127)/MAX(1,chan[c.chan].volMax);
if (scaledVol<0) scaledVol=0;
if (scaledVol>127) scaledVol=127;
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
case DIV_CMD_LEGATO:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
if (midiOutMode==DIV_MIDI_MODE_NOTE) {
int scaledVol=(chan[c.chan].volume*127)/MAX(1,chan[c.chan].volMax);
if (scaledVol<0) scaledVol=0;
if (scaledVol>127) scaledVol=127;
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
case DIV_CMD_LEGATO:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].curMidiNote=c.value+12;
if (chan[c.chan].curMidiNote<0) chan[c.chan].curMidiNote=0;
if (chan[c.chan].curMidiNote>127) chan[c.chan].curMidiNote=127;
}
output->midiOut->send(TAMidiMessage(0x90|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
break;
case DIV_CMD_NOTE_OFF:
case DIV_CMD_NOTE_OFF_ENV:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
chan[c.chan].curMidiNote=-1;
break;
case DIV_CMD_INSTRUMENT:
if (chan[c.chan].lastIns!=c.value) {
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
}
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].curMidiNote>=0 && chan[c.chan].midiAftertouch) {
chan[c.chan].midiAftertouch=false;
output->midiOut->send(TAMidiMessage(0xa0|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
break;
case DIV_CMD_PITCH: {
int pitchBend=8192+(c.value<<5);
if (pitchBend<0) pitchBend=0;
if (pitchBend>16383) pitchBend=16383;
if (pitchBend!=chan[c.chan].midiPitch) {
chan[c.chan].midiPitch=pitchBend;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
}
break;
}
if (c.value!=DIV_NOTE_NULL) chan[c.chan].curMidiNote=c.value+12;
output->midiOut->send(TAMidiMessage(0x90|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
break;
case DIV_CMD_NOTE_OFF:
case DIV_CMD_NOTE_OFF_ENV:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
case DIV_CMD_PANNING: {
int pan=convertPanSplitToLinearLR(c.value,c.value2,127);
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x0a,pan));
break;
}
chan[c.chan].curMidiNote=-1;
break;
case DIV_CMD_INSTRUMENT:
if (chan[c.chan].lastIns!=c.value) {
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
case DIV_CMD_HINT_PORTA: {
if (c.value2>0) {
if (c.value<=0 || c.value>=255) break;
//output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
int target=c.value+12;
if (target<0) target=0;
if (target>127) target=127;
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x54,chan[c.chan].curMidiNote));
}
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x05,1/*MIN(0x7f,c.value2/4)*/));
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x41,0x7f));
output->midiOut->send(TAMidiMessage(0x90|(c.chan&15),target,scaledVol));
} else {
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x41,0));
}
break;
}
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].curMidiNote>=0 && chan[c.chan].midiAftertouch) {
chan[c.chan].midiAftertouch=false;
output->midiOut->send(TAMidiMessage(0xa0|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
break;
case DIV_CMD_PITCH: {
int pitchBend=8192+(c.value<<5);
if (pitchBend<0) pitchBend=0;
if (pitchBend>16383) pitchBend=16383;
if (pitchBend!=chan[c.chan].midiPitch) {
chan[c.chan].midiPitch=pitchBend;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
}
break;
default:
break;
}
default:
break;
}
}
}
@ -1065,11 +1096,6 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
cycles++;
}
// MIDI clock
if (output) if (!skipping && output->midiOut!=NULL) {
//output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
}
if (!pendingNotes.empty()) {
bool isOn[DIV_MAX_CHANS];
memset(isOn,0,DIV_MAX_CHANS*sizeof(bool));
@ -1116,6 +1142,12 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
if (!freelance) {
if (--subticks<=0) {
subticks=tickMult;
// MIDI clock
if (output) if (!skipping && output->midiOut!=NULL && midiOutClock) {
output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
}
if (stepPlay!=1) {
tempoAccum+=curSubSong->virtualTempoN;
while (tempoAccum>=curSubSong->virtualTempoD) {

View File

@ -20,8 +20,6 @@
#ifndef _SAMPLE_H
#define _SAMPLE_H
#pragma once
#include "../ta-utils.h"
#include <deque>
@ -93,6 +91,7 @@ struct DivSampleHistory {
struct DivSample {
String name;
// TODO: get rid of loopOffP
int rate, centerRate, loopStart, loopEnd, loopOffP;
// valid values are:
// - 0: ZX Spectrum overlay drum (1-bit)
@ -126,8 +125,6 @@ struct DivSample {
unsigned char* dataVOX; // 10
unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthBRR, lengthVOX;
unsigned int off8, off16, off1, offDPCM, offZ, offQSoundA, offA, offB, offBRR, offVOX;
unsigned int offSegaPCM, offQSound, offX1_010, offES5506, offSU, offYMZ280B, offRF5C68, offSNES;
unsigned int samples;
@ -313,24 +310,6 @@ struct DivSample {
lengthB(0),
lengthBRR(0),
lengthVOX(0),
off8(0),
off16(0),
off1(0),
offDPCM(0),
offZ(0),
offQSoundA(0),
offA(0),
offB(0),
offBRR(0),
offVOX(0),
offSegaPCM(0),
offQSound(0),
offX1_010(0),
offES5506(0),
offSU(0),
offYMZ280B(0),
offRF5C68(0),
offSNES(0),
samples(0) {}
~DivSample();
};

View File

@ -926,6 +926,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
int loopPos=-1;
int loopTick=-1;
unsigned int sampleOff8[256];
unsigned int sampleOffSegaPCM[256];
SafeWriter* w=new SafeWriter;
w->init();
@ -1555,12 +1558,16 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
unsigned int songOff=w->tell();
// initialize sample offsets
memset(sampleOff8,0,256*sizeof(unsigned int));
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
// write samples
unsigned int sampleSeek=0;
for (int i=0; i<song.sampleLen; i++) {
DivSample* sample=song.sample[i];
logI("setting seek to %d",sampleSeek);
sample->off8=sampleSeek;
sampleOff8[i]=sampleSeek;
sampleSeek+=sample->length8;
}
@ -1610,7 +1617,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
}
logV("- sample %d will be at %x with length %x",i,memPos,alignedSize);
if (memPos>=16777216) break;
sample->offSegaPCM=memPos;
sampleOffSegaPCM[i]=memPos;
unsigned int readPos=0;
for (unsigned int j=0; j<alignedSize; j++) {
if (readPos>=(unsigned int)sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
@ -1715,6 +1722,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
size_t sampleMemLen=writeZ280[i]->getSampleMemUsage();
unsigned char* sampleMem=new unsigned char[sampleMemLen];
memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen);
// TODO: please fix this later
/*
for (int i=0; i<song.sampleLen; i++) {
DivSample* s=song.sample[i];
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
@ -1727,6 +1736,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
}
}
}
*/
w->writeC(0x67);
w->writeC(0x66);
w->writeC(0x86);
@ -1967,7 +1977,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)<sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
w->writeC(0x93);
w->writeC(nextToTouch);
w->writeI(sample->off8+sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT));
w->writeI(sampleOff8[loopSample[nextToTouch]]+sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT));
w->writeC(0x81);
w->writeI(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT));
}

View File

@ -847,10 +847,10 @@ void putDispatchChan(void* data, int chanNum, int type) {
ImGui::Text("- ins: %d",ch->ins);
ImGui::Text("* psgMode:");
ImGui::Text(" * curr:");
ImGui::Text(" - tone: %d",ch->currPSGMode.tone);
ImGui::Text(" - noise: %d",ch->currPSGMode.noise);
ImGui::Text(" - envelope: %d",ch->currPSGMode.envelope);
ImGui::Text(" - dac: %d",ch->currPSGMode.dac);
ImGui::Text(" - tone: %d",ch->curPSGMode.tone);
ImGui::Text(" - noise: %d",ch->curPSGMode.noise);
ImGui::Text(" - envelope: %d",ch->curPSGMode.envelope);
ImGui::Text(" - dac: %d",ch->curPSGMode.dac);
ImGui::Text(" * next:");
ImGui::Text(" - tone: %d",ch->nextPSGMode.tone);
ImGui::Text(" - noise: %d",ch->nextPSGMode.noise);
@ -893,10 +893,10 @@ void putDispatchChan(void* data, int chanNum, int type) {
ImGui::Text(" - low: %d",ch->envelope.slideLow);
ImGui::Text("* psgMode:");
ImGui::Text(" * curr:");
ImGui::Text(" - tone: %d",ch->currPSGMode.tone);
ImGui::Text(" - noise: %d",ch->currPSGMode.noise);
ImGui::Text(" - envelope: %d",ch->currPSGMode.envelope);
ImGui::Text(" - dac: %d",ch->currPSGMode.dac);
ImGui::Text(" - tone: %d",ch->curPSGMode.tone);
ImGui::Text(" - noise: %d",ch->curPSGMode.noise);
ImGui::Text(" - envelope: %d",ch->curPSGMode.envelope);
ImGui::Text(" - dac: %d",ch->curPSGMode.dac);
ImGui::Text(" * next:");
ImGui::Text(" - tone: %d",ch->nextPSGMode.tone);
ImGui::Text(" - noise: %d",ch->nextPSGMode.noise);

View File

@ -192,24 +192,6 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("lengthBRR: %d",sample->lengthBRR);
ImGui::Text("lengthVOX: %d",sample->lengthVOX);
ImGui::Text("off8: %x",sample->off8);
ImGui::Text("off16: %x",sample->off16);
ImGui::Text("off1: %x",sample->off1);
ImGui::Text("offDPCM: %x",sample->offDPCM);
ImGui::Text("offZ: %x",sample->offZ);
ImGui::Text("offQSoundA: %x",sample->offQSoundA);
ImGui::Text("offA: %x",sample->offA);
ImGui::Text("offB: %x",sample->offB);
ImGui::Text("offBRR: %x",sample->offBRR);
ImGui::Text("offVOX: %x",sample->offVOX);
ImGui::Text("offSegaPCM: %x",sample->offSegaPCM);
ImGui::Text("offQSound: %x",sample->offQSound);
ImGui::Text("offX1_010: %x",sample->offX1_010);
ImGui::Text("offES5506: %x",sample->offES5506);
ImGui::Text("offSU: %x",sample->offSU);
ImGui::Text("offYMZ280B: %x",sample->offYMZ280B);
ImGui::Text("offRF5C68: %x",sample->offRF5C68);
ImGui::Text("samples: %d",sample->samples);
ImGui::TreePop();
}

View File

@ -1195,6 +1195,8 @@ class FurnaceGUI {
int channelFeedbackStyle;
int channelFont;
int channelTextCenter;
int midiOutClock;
int midiOutMode;
int maxRecentFile;
unsigned int maxUndoSteps;
String mainFontPath;
@ -1318,6 +1320,8 @@ class FurnaceGUI {
channelFeedbackStyle(1),
channelFont(1),
channelTextCenter(1),
midiOutClock(0),
midiOutMode(1),
maxRecentFile(10),
maxUndoSteps(100),
mainFontPath(""),

View File

@ -955,6 +955,26 @@ void FurnaceGUI::drawSettings() {
ImGui::EndTable();
}
ImGui::TreePop();
}
if (ImGui::TreeNode("MIDI output settings")) {
ImGui::Text("Output mode:");
if (ImGui::RadioButton("Off (use for TX81Z)",settings.midiOutMode==0)) {
settings.midiOutMode=0;
}
if (ImGui::RadioButton("Melodic",settings.midiOutMode==1)) {
settings.midiOutMode=1;
}
/*
if (ImGui::RadioButton("Light Show (use for Launchpad)",settings.midiOutMode==2)) {
settings.midiOutMode=2;
}*/
bool midiOutClockB=settings.midiOutClock;
if (ImGui::Checkbox("Send MIDI clock",&midiOutClockB)) {
settings.midiOutClock=midiOutClockB;
}
ImGui::TreePop();
}
}
@ -2314,6 +2334,8 @@ void FurnaceGUI::syncSettings() {
settings.channelFont=e->getConfInt("channelFont",1);
settings.channelTextCenter=e->getConfInt("channelTextCenter",1);
settings.maxRecentFile=e->getConfInt("maxRecentFile",10);
settings.midiOutClock=e->getConfInt("midiOutClock",0);
settings.midiOutMode=e->getConfInt("midiOutMode",1);
clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96);
@ -2415,6 +2437,8 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.channelFont,0,1);
clampSetting(settings.channelTextCenter,0,1);
clampSetting(settings.maxRecentFile,0,30);
clampSetting(settings.midiOutClock,0,1);
clampSetting(settings.midiOutMode,0,2);
settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys",""));
if (settings.initialSys.size()<4) {
@ -2572,6 +2596,8 @@ void FurnaceGUI::commitSettings() {
e->setConf("channelFont",settings.channelFont);
e->setConf("channelTextCenter",settings.channelTextCenter);
e->setConf("maxRecentFile",settings.maxRecentFile);
e->setConf("midiOutClock",settings.midiOutClock);
e->setConf("midiOutMode",settings.midiOutMode);
// colors
for (int i=0; i<GUI_COLOR_MAX; i++) {