Prepare for backward and bi-directional loop
This commit is contained in:
parent
da8f7dabd5
commit
d44f5f0b2b
|
@ -974,6 +974,7 @@ void DivEngine::renderSamplesP() {
|
|||
void DivEngine::renderSamples() {
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
|
||||
// step 1: render samples
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
|
@ -1686,6 +1687,7 @@ void DivEngine::play() {
|
|||
sPreview.sample=-1;
|
||||
sPreview.wave=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
if (stepPlay==0) {
|
||||
freelance=false;
|
||||
playSub(false);
|
||||
|
@ -1708,6 +1710,7 @@ void DivEngine::playToRow(int row) {
|
|||
sPreview.sample=-1;
|
||||
sPreview.wave=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
freelance=false;
|
||||
playSub(false,row);
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
|
@ -1745,6 +1748,7 @@ void DivEngine::stop() {
|
|||
sPreview.sample=-1;
|
||||
sPreview.wave=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
disCont[i].dispatch->notifyPlaybackStop();
|
||||
}
|
||||
|
@ -1914,9 +1918,11 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
|||
BUSY_BEGIN;
|
||||
sPreview.pBegin=pStart;
|
||||
sPreview.pEnd=pEnd;
|
||||
sPreview.dir=false;
|
||||
if (sample<0 || sample>=(int)song.sample.size()) {
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
BUSY_END;
|
||||
return;
|
||||
}
|
||||
|
@ -1932,6 +1938,7 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
|||
sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0;
|
||||
sPreview.sample=sample;
|
||||
sPreview.wave=-1;
|
||||
sPreview.dir=false;
|
||||
BUSY_END;
|
||||
}
|
||||
|
||||
|
@ -1939,6 +1946,7 @@ void DivEngine::stopSamplePreview() {
|
|||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
BUSY_END;
|
||||
}
|
||||
|
||||
|
@ -1947,6 +1955,7 @@ void DivEngine::previewWave(int wave, int note) {
|
|||
if (wave<0 || wave>=(int)song.wave.size()) {
|
||||
sPreview.wave=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
BUSY_END;
|
||||
return;
|
||||
}
|
||||
|
@ -1962,6 +1971,7 @@ void DivEngine::previewWave(int wave, int note) {
|
|||
sPreview.pos=0;
|
||||
sPreview.sample=-1;
|
||||
sPreview.wave=wave;
|
||||
sPreview.dir=false;
|
||||
BUSY_END;
|
||||
}
|
||||
|
||||
|
@ -1969,6 +1979,7 @@ void DivEngine::stopWavePreview() {
|
|||
BUSY_BEGIN;
|
||||
sPreview.wave=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
BUSY_END;
|
||||
}
|
||||
|
||||
|
@ -2382,6 +2393,7 @@ int DivEngine::addSample() {
|
|||
song.sampleLen=sampleCount+1;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
BUSY_END;
|
||||
|
@ -2601,13 +2613,16 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
inst.detune = inst.detune - 100;
|
||||
short pitch = ((0x3c-inst.basenote)*100) + inst.detune;
|
||||
sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0));
|
||||
if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD)
|
||||
if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD)
|
||||
{
|
||||
sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD);
|
||||
sample->loopStart=inst.loops[0].start;
|
||||
sample->loopEnd=inst.loops[0].end;
|
||||
if(inst.loops[0].end < (unsigned int)sampleCount)
|
||||
sampleCount=inst.loops[0].end;
|
||||
}
|
||||
else
|
||||
sample->loop=false;
|
||||
}
|
||||
|
||||
if (sample->centerRate<4000) sample->centerRate=4000;
|
||||
|
@ -2627,6 +2642,7 @@ void DivEngine::delSample(int index) {
|
|||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
saveLock.lock();
|
||||
if (index>=0 && index<(int)song.sample.size()) {
|
||||
delete song.sample[index];
|
||||
|
@ -2843,6 +2859,7 @@ bool DivEngine::moveSampleUp(int which) {
|
|||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
DivSample* prev=song.sample[which];
|
||||
saveLock.lock();
|
||||
song.sample[which]=song.sample[which-1];
|
||||
|
@ -2882,6 +2899,7 @@ bool DivEngine::moveSampleDown(int which) {
|
|||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
DivSample* prev=song.sample[which];
|
||||
saveLock.lock();
|
||||
song.sample[which]=song.sample[which+1];
|
||||
|
|
|
@ -353,14 +353,16 @@ class DivEngine {
|
|||
struct SamplePreview {
|
||||
int sample;
|
||||
int wave;
|
||||
unsigned int pos;
|
||||
int pos;
|
||||
int pBegin, pEnd;
|
||||
bool dir;
|
||||
SamplePreview():
|
||||
sample(-1),
|
||||
wave(-1),
|
||||
pos(0),
|
||||
pBegin(-1),
|
||||
pEnd(-1) {}
|
||||
pEnd(-1),
|
||||
dir(false) {}
|
||||
} sPreview;
|
||||
|
||||
short vibTable[64];
|
||||
|
|
|
@ -1669,6 +1669,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
|
||||
sample->loopStart=reader.readI();
|
||||
sample->loopEnd=reader.readI();
|
||||
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
reader.readI();
|
||||
|
@ -1694,6 +1695,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
|
||||
if (ds.version>=19) {
|
||||
sample->loopStart=reader.readI();
|
||||
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
|
@ -1948,6 +1950,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
if (loopLen>=2) {
|
||||
sample->loopStart=loopStart;
|
||||
sample->loopEnd=loopEnd;
|
||||
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||
}
|
||||
sample->init(slen);
|
||||
ds.sample.push_back(sample);
|
||||
|
@ -2485,6 +2488,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
}
|
||||
s->loopStart=sample[i].loopStart*2;
|
||||
s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2;
|
||||
s->loop=(s->loopStart>=0)&&(s->loopEnd>=0);
|
||||
reader.read(s->data8,sample[i].len);
|
||||
ds.sample.push_back(s);
|
||||
}
|
||||
|
@ -3586,8 +3590,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(0); // reserved
|
||||
w->writeC(0);
|
||||
w->writeC(0);
|
||||
w->writeI(sample->loopStart);
|
||||
w->writeI(sample->loopEnd);
|
||||
w->writeI(sample->loop?sample->loopStart:-1);
|
||||
w->writeI(sample->loop?sample->loopEnd:-1);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
w->writeI(0xffffffff);
|
||||
|
|
|
@ -110,13 +110,13 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
|
|||
}
|
||||
} else {
|
||||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
if (s->samples>0) {
|
||||
if (chan[i].audPos<s->samples) {
|
||||
if (s->getEndPosition()>0) {
|
||||
if (chan[i].audPos<(unsigned int)s->getEndPosition()) {
|
||||
writeAudDat(s->data8[chan[i].audPos++]);
|
||||
}
|
||||
if (s->isLoopable() && chan[i].audPos>=MIN(131071,s->getEndPosition())) {
|
||||
chan[i].audPos=s->loopStart;
|
||||
} else if (chan[i].audPos>=MIN(131071,s->samples)) {
|
||||
if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->getLoopEndPosition())) {
|
||||
chan[i].audPos=s->getLoopStartPosition();
|
||||
} else if (chan[i].audPos>=MIN(131071,(unsigned int)s->getEndPosition())) {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -154,9 +154,9 @@ void DivPlatformGenesis::processDAC() {
|
|||
if (s->samples>0) {
|
||||
while (chan[i].dacPeriod>=(chipClock/576)) {
|
||||
++chan[i].dacPos;
|
||||
if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=s->getEndPosition())) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else if (chan[i].dacPos>=s->samples) {
|
||||
if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition())) {
|
||||
chan[i].dacPos=s->getLoopStartPosition();
|
||||
} else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) {
|
||||
chan[i].dacSample=-1;
|
||||
chan[i].dacPeriod=0;
|
||||
break;
|
||||
|
@ -200,9 +200,9 @@ void DivPlatformGenesis::processDAC() {
|
|||
}
|
||||
}
|
||||
chan[5].dacPos++;
|
||||
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=s->getEndPosition())) {
|
||||
chan[5].dacPos=s->loopStart;
|
||||
} else if (chan[5].dacPos>=s->samples) {
|
||||
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->getLoopEndPosition())) {
|
||||
chan[5].dacPos=s->getLoopStartPosition();
|
||||
} else if (chan[5].dacPos>=(unsigned int)s->getEndPosition()) {
|
||||
chan[5].dacSample=-1;
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
|
|
|
@ -158,9 +158,9 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7);
|
||||
}
|
||||
|
||||
if (s->isLoopable() && chan[i].samplePos>=(int)s->getEndPosition()) {
|
||||
chan[i].samplePos=s->loopStart;
|
||||
} else if (chan[i].samplePos>=(int)s->samples) {
|
||||
if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) {
|
||||
chan[i].samplePos=s->getLoopStartPosition();
|
||||
} else if (chan[i].samplePos>=s->getEndPosition()) {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,14 +58,14 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
dacPeriod+=dacRate;
|
||||
if (dacPeriod>=rate) {
|
||||
DivSample* s=parent->getSample(dacSample);
|
||||
if (s->samples>0) {
|
||||
if (s->getEndPosition()>0) {
|
||||
if (!isMuted[2]) {
|
||||
rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80));
|
||||
}
|
||||
dacPos++;
|
||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) {
|
||||
dacPos=s->loopStart;
|
||||
} else if (dacPos>=s->samples) {
|
||||
if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
dacPos=s->getLoopStartPosition();
|
||||
} else if (dacPos>=(unsigned int)s->getEndPosition()) {
|
||||
dacSample=-1;
|
||||
}
|
||||
dacPeriod-=rate;
|
||||
|
|
|
@ -97,7 +97,7 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
|||
dacPeriod+=dacRate; \
|
||||
if (dacPeriod>=rate) { \
|
||||
DivSample* s=parent->getSample(dacSample); \
|
||||
if (s->samples>0) { \
|
||||
if (s->getEndPosition()>0) { \
|
||||
if (!isMuted[4]) { \
|
||||
unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \
|
||||
if (dacAntiClickOn && dacAntiClick<next) { \
|
||||
|
@ -109,9 +109,9 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
|||
} \
|
||||
} \
|
||||
dacPos++; \
|
||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) { \
|
||||
dacPos=s->loopStart; \
|
||||
} else if (dacPos>=s->samples) { \
|
||||
if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { \
|
||||
dacPos=s->getLoopStartPosition(); \
|
||||
} else if (dacPos>=(unsigned int)s->getEndPosition()) { \
|
||||
dacSample=-1; \
|
||||
} \
|
||||
dacPeriod-=rate; \
|
||||
|
|
|
@ -82,7 +82,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
chan[i].dacPeriod+=chan[i].dacRate;
|
||||
if (chan[i].dacPeriod>rate) {
|
||||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (s->samples<=0) {
|
||||
if (s->getEndPosition()<=0) {
|
||||
chan[i].dacSample=-1;
|
||||
continue;
|
||||
}
|
||||
|
@ -90,9 +90,9 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
chWrite(i,0x04,0xdf);
|
||||
chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3));
|
||||
chan[i].dacPos++;
|
||||
if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else if (chan[i].dacPos>=s->samples) {
|
||||
if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
chan[i].dacPos=s->getLoopStartPosition();
|
||||
} else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) {
|
||||
chan[i].dacSample=-1;
|
||||
}
|
||||
chan[i].dacPeriod-=rate;
|
||||
|
|
|
@ -49,13 +49,13 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
output=(chan.ws.output[chan.audPos]^0x80)<<8;
|
||||
} else {
|
||||
DivSample* s=parent->getSample(chan.sample);
|
||||
if (s->samples>0) {
|
||||
if (s->isLoopable() && chan.audPos>=s->getEndPosition()) {
|
||||
chan.audPos=s->loopStart;
|
||||
} else if (chan.audPos>=s->samples) {
|
||||
if (s->getEndPosition()>0) {
|
||||
if (s->isLoopable() && chan.audPos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
chan.audPos=s->getLoopStartPosition();
|
||||
} else if (chan.audPos>=(unsigned int)s->getEndPosition()) {
|
||||
chan.sample=-1;
|
||||
}
|
||||
if (chan.audPos<s->samples) {
|
||||
if (chan.audPos<(unsigned int)s->getEndPosition()) {
|
||||
output=s->data16[chan.audPos];
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -301,16 +301,17 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
qsound_bank = 0x8000 | (s->offQSound >> 16);
|
||||
qsound_addr = s->offQSound & 0xffff;
|
||||
|
||||
int length = s->getEndPosition();
|
||||
int loopStart=s->getLoopStartPosition();
|
||||
int length = s->getLoopEndPosition();
|
||||
if (length > 65536 - 16) {
|
||||
length = 65536 - 16;
|
||||
}
|
||||
if (s->loopStart == -1 || s->loopStart >= length) {
|
||||
if (loopStart == -1 || loopStart >= length) {
|
||||
qsound_end = s->offQSound + length + 15;
|
||||
qsound_loop = 15;
|
||||
} else {
|
||||
qsound_end = s->offQSound + length;
|
||||
qsound_loop = length - s->loopStart;
|
||||
qsound_loop = length - loopStart;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
|
|
|
@ -143,7 +143,7 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
|||
start=start+MIN(chan[i].audPos,s->length8);
|
||||
}
|
||||
if (s->isLoopable()) {
|
||||
loop=start+s->loopStart;
|
||||
loop=start+s->getLoopStartPosition();
|
||||
}
|
||||
start=MIN(start,getSampleMemCapacity()-31);
|
||||
loop=MIN(loop,getSampleMemCapacity()-31);
|
||||
|
@ -393,7 +393,7 @@ void DivPlatformRF5C68::renderSamples() {
|
|||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
int length=s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
||||
if (actualLength>0) {
|
||||
s->offRF5C68=memPos;
|
||||
|
|
|
@ -45,7 +45,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
for (int i=0; i<16; i++) {
|
||||
if (chan[i].pcm.sample>=0 && chan[i].pcm.sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].pcm.sample);
|
||||
if (s->samples<=0) {
|
||||
if (s->getEndPosition()<=0) {
|
||||
chan[i].pcm.sample=-1;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=0;
|
||||
continue;
|
||||
|
@ -56,9 +56,9 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR);
|
||||
}
|
||||
chan[i].pcm.pos+=chan[i].pcm.freq;
|
||||
if (s->isLoopable() && chan[i].pcm.pos>=(s->getEndPosition()<<8)) {
|
||||
chan[i].pcm.pos=s->loopStart<<8;
|
||||
} else if (chan[i].pcm.pos>=(s->samples<<8)) {
|
||||
if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->getLoopEndPosition()<<8)) {
|
||||
chan[i].pcm.pos=s->getLoopStartPosition()<<8;
|
||||
} else if (chan[i].pcm.pos>=((unsigned int)s->getEndPosition()<<8)) {
|
||||
chan[i].pcm.sample=-1;
|
||||
}
|
||||
} else {
|
||||
|
@ -200,16 +200,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroInit(ins);
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
|
||||
int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
if (actualLength>0xfeff) actualLength=0xfeff;
|
||||
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
|
||||
addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff);
|
||||
addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff);
|
||||
addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
|
||||
if (s->loopStart<0 || s->loopStart>=actualLength) {
|
||||
if (loopStart<0 || loopStart>=actualLength) {
|
||||
addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP;
|
||||
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(c.chan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3));
|
||||
|
@ -233,16 +234,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].furnacePCM=false;
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
|
||||
int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
if (actualLength>65536) actualLength=65536;
|
||||
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
|
||||
addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff);
|
||||
addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff);
|
||||
addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
|
||||
if (s->loopStart<0 || s->loopStart>=actualLength) {
|
||||
if (loopStart<0 || loopStart>=actualLength) {
|
||||
addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP;
|
||||
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(c.chan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3));
|
||||
|
|
|
@ -220,7 +220,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
|||
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->getEndPosition());
|
||||
unsigned int sampleEnd=sample->offSU+(sample->getLoopEndPosition());
|
||||
unsigned int off=sample->offSU+chan[i].hasOffset;
|
||||
chan[i].hasOffset=0;
|
||||
if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1;
|
||||
|
@ -229,7 +229,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->loopStart;
|
||||
unsigned int sampleLoop=sample->offSU+sample->getLoopStartPosition();
|
||||
if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1;
|
||||
chWrite(i,0x0e,sampleLoop&0xff);
|
||||
chWrite(i,0x0f,sampleLoop>>8);
|
||||
|
@ -603,7 +603,7 @@ void DivPlatformSoundUnit::renderSamples() {
|
|||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (s->data8==NULL) continue;
|
||||
int paddedLen=s->samples;
|
||||
int paddedLen=s->getEndPosition();
|
||||
if (memPos>=getSampleMemCapacity(0)) {
|
||||
logW("out of PCM memory for sample %d!",i);
|
||||
break;
|
||||
|
|
|
@ -78,14 +78,14 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
dacPeriod+=dacRate;
|
||||
while (dacPeriod>rate) {
|
||||
DivSample* s=parent->getSample(dacSample);
|
||||
if (s->samples<=0) {
|
||||
if (s->getEndPosition()<=0) {
|
||||
dacSample=-1;
|
||||
continue;
|
||||
}
|
||||
rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80);
|
||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) {
|
||||
dacPos=s->loopStart;
|
||||
} else if (dacPos>=s->samples) {
|
||||
if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
dacPos=s->getLoopStartPosition();
|
||||
} else if (dacPos>=(unsigned int)s->getEndPosition()) {
|
||||
dacSample=-1;
|
||||
}
|
||||
dacPeriod-=rate;
|
||||
|
|
|
@ -70,7 +70,7 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
size_t pos=start;
|
||||
DivSample* s=parent->getSample(chan[16].pcm.sample);
|
||||
while (len>0) {
|
||||
if (s->samples>0) {
|
||||
if (s->getEndPosition()>0) {
|
||||
while (pcm_is_fifo_almost_empty(pcm)) {
|
||||
short tmp_l=0;
|
||||
short tmp_r=0;
|
||||
|
@ -96,9 +96,9 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
rWritePCMData(tmp_r&0xff);
|
||||
}
|
||||
chan[16].pcm.pos++;
|
||||
if (s->isLoopable() && chan[16].pcm.pos>=s->getEndPosition()) {
|
||||
chan[16].pcm.pos=s->loopStart;
|
||||
} else if (chan[16].pcm.pos>=s->samples) {
|
||||
if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
chan[16].pcm.pos=s->getLoopStartPosition();
|
||||
} else if (chan[16].pcm.pos>=(unsigned int)s->getEndPosition()) {
|
||||
chan[16].pcm.sample=-1;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
chan[i].dacPeriod+=chan[i].dacRate;
|
||||
if (chan[i].dacPeriod>rate) {
|
||||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (s->samples<=0) {
|
||||
if (s->getEndPosition()<=0) {
|
||||
chan[i].dacSample=-1;
|
||||
chWrite(i,0,0);
|
||||
continue;
|
||||
|
@ -77,9 +77,9 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
chWrite(i,0,0x80|chan[i].dacOut);
|
||||
}
|
||||
chan[i].dacPos++;
|
||||
if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else if (chan[i].dacPos>=s->samples) {
|
||||
if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
chan[i].dacPos=s->getLoopStartPosition();
|
||||
} else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) {
|
||||
chan[i].dacSample=-1;
|
||||
chWrite(i,0,0);
|
||||
}
|
||||
|
|
|
@ -46,9 +46,9 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
if (curSample>=0 && curSample<parent->song.sampleLen) {
|
||||
if (--curSamplePeriod<0) {
|
||||
DivSample* s=parent->getSample(curSample);
|
||||
if (s->samples>0) {
|
||||
if (s->getEndPosition()>0) {
|
||||
sampleOut=(s->data8[curSamplePos++]>0);
|
||||
if (curSamplePos>=s->samples) curSample=-1;
|
||||
if (curSamplePos>=(unsigned int)s->getEndPosition()) curSample=-1;
|
||||
// 256 bits
|
||||
if (curSamplePos>2047) curSample=-1;
|
||||
|
||||
|
|
|
@ -760,6 +760,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
sPreview.sample=-1;
|
||||
sPreview.wave=-1;
|
||||
sPreview.pos=0;
|
||||
sPreview.dir=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1268,26 +1269,109 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
DivSample* s=song.sample[sPreview.sample];
|
||||
|
||||
for (size_t i=0; i<prevtotal; i++) {
|
||||
if (sPreview.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
||||
if (sPreview.pos>=(int)s->samples || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) {
|
||||
samp_temp=0;
|
||||
} else {
|
||||
samp_temp=s->data16[sPreview.pos++];
|
||||
samp_temp=s->data16[sPreview.pos];
|
||||
if (sPreview.dir) {
|
||||
sPreview.pos--;
|
||||
}
|
||||
else {
|
||||
sPreview.pos++;
|
||||
}
|
||||
}
|
||||
blip_add_delta(samp_bb,i,samp_temp-samp_prevSample);
|
||||
samp_prevSample=samp_temp;
|
||||
|
||||
if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
||||
if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) {
|
||||
sPreview.pos=s->loopStart;
|
||||
if (sPreview.dir) { // backward
|
||||
if (sPreview.pos<s->getLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.pos<sPreview.pBegin)) {
|
||||
if (s->isLoopable() && sPreview.pos<s->getLoopEndPosition()) {
|
||||
switch (s->loopMode) {
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||
sPreview.pos=s->getLoopStartPosition();
|
||||
sPreview.dir=false;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||
sPreview.pos=s->getLoopEndPosition()-1;
|
||||
sPreview.dir=true;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||
sPreview.pos=s->getLoopStartPosition();
|
||||
sPreview.dir=false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // forward
|
||||
if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) {
|
||||
if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) {
|
||||
switch (s->loopMode) {
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||
sPreview.pos=s->getLoopStartPosition();
|
||||
sPreview.dir=false;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||
sPreview.pos=s->getLoopEndPosition()-1;
|
||||
sPreview.dir=true;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||
sPreview.pos=s->getLoopEndPosition()-1;
|
||||
sPreview.dir=true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
||||
if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) {
|
||||
sPreview.pos=s->loopStart;
|
||||
} else if (sPreview.pos>=s->samples) {
|
||||
sPreview.sample=-1;
|
||||
if (sPreview.dir) { // backward
|
||||
if (sPreview.pos<=s->getLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) {
|
||||
if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) {
|
||||
switch (s->loopMode) {
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||
sPreview.pos=s->getLoopStartPosition();
|
||||
sPreview.dir=false;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||
sPreview.pos=s->getLoopEndPosition()-1;
|
||||
sPreview.dir=true;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||
sPreview.pos=s->getLoopStartPosition();
|
||||
sPreview.dir=false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (sPreview.pos<0) {
|
||||
sPreview.sample=-1;
|
||||
}
|
||||
}
|
||||
} else { // forward
|
||||
if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) {
|
||||
if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) {
|
||||
switch (s->loopMode) {
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||
sPreview.pos=s->getLoopStartPosition();
|
||||
sPreview.dir=false;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||
sPreview.pos=s->getLoopEndPosition()-1;
|
||||
sPreview.dir=true;
|
||||
break;
|
||||
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||
sPreview.pos=s->getLoopEndPosition()-1;
|
||||
sPreview.dir=true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (sPreview.pos>=s->getEndPosition()) {
|
||||
sPreview.sample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size()) {
|
||||
|
@ -1298,7 +1382,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
} else {
|
||||
samp_temp=((MIN(wave->data[sPreview.pos],wave->max)<<14)/wave->max)-8192;
|
||||
}
|
||||
if (++sPreview.pos>=(unsigned int)wave->len) {
|
||||
if (++sPreview.pos>=wave->len) {
|
||||
sPreview.pos=0;
|
||||
}
|
||||
blip_add_delta(samp_bb,i,samp_temp-samp_prevSample);
|
||||
|
|
|
@ -39,57 +39,143 @@ DivSampleHistory::~DivSampleHistory() {
|
|||
}
|
||||
|
||||
bool DivSample::isLoopable() {
|
||||
return (loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples);
|
||||
return loop && ((loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples));
|
||||
}
|
||||
|
||||
unsigned int DivSample::getEndPosition(DivSampleDepth depth) {
|
||||
int end=loopEnd;
|
||||
unsigned int len=samples;
|
||||
int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
|
||||
if ((length==0) || (offset==length)) {
|
||||
int off=offset;
|
||||
switch (depth) {
|
||||
case DIV_SAMPLE_DEPTH_1BIT:
|
||||
off=(offset+7)/8;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||
off=(offset+7)/8;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||
off=(offset+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||
off=(offset+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||
off=(offset+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
off=(offset+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_8BIT:
|
||||
off=offset;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_BRR:
|
||||
off=9*((offset+15)/16);
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
off=(offset+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
off=offset*2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return off;
|
||||
} else {
|
||||
int off=offset;
|
||||
int len=length;
|
||||
switch (depth) {
|
||||
case DIV_SAMPLE_DEPTH_1BIT:
|
||||
off=(offset+7)/8;
|
||||
len=(length+7)/8;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||
off=(offset+7)/8;
|
||||
len=(length+7)/8;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||
off=(offset+1)/2;
|
||||
len=(length+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||
off=(offset+1)/2;
|
||||
len=(length+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||
off=(offset+1)/2;
|
||||
len=(length+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
off=(offset+1)/2;
|
||||
len=(length+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_8BIT:
|
||||
off=offset;
|
||||
len=length;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_BRR:
|
||||
off=9*((offset+15)/16);
|
||||
len=9*((length+15)/16);
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
off=(offset+1)/2;
|
||||
len=(length+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
off=offset*2;
|
||||
len=length*2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return isLoopable()?off:len;
|
||||
}
|
||||
}
|
||||
|
||||
int DivSample::getLoopStartPosition(DivSampleDepth depth) {
|
||||
return getSampleOffset(loopStart,0,depth);
|
||||
}
|
||||
|
||||
int DivSample::getLoopEndPosition(DivSampleDepth depth) {
|
||||
return getSampleOffset(loopEnd,samples,depth);
|
||||
}
|
||||
|
||||
int DivSample::getEndPosition(DivSampleDepth depth) {
|
||||
int off=samples;
|
||||
switch (depth) {
|
||||
case DIV_SAMPLE_DEPTH_1BIT:
|
||||
end=(loopEnd+7)/8;
|
||||
len=length1;
|
||||
off=length1;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||
end=(loopEnd+7)/8;
|
||||
len=lengthDPCM;
|
||||
off=lengthDPCM;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||
end=(loopEnd+1)/2;
|
||||
len=lengthZ;
|
||||
off=lengthZ;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||
end=(loopEnd+1)/2;
|
||||
len=lengthQSoundA;
|
||||
off=lengthQSoundA;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||
end=(loopEnd+1)/2;
|
||||
len=lengthA;
|
||||
off=lengthA;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
end=(loopEnd+1)/2;
|
||||
len=lengthB;
|
||||
off=lengthB;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_8BIT:
|
||||
end=loopEnd;
|
||||
len=length8;
|
||||
off=length8;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_BRR:
|
||||
end=9*((loopEnd+15)/16);
|
||||
len=lengthBRR;
|
||||
off=lengthBRR;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
end=(loopEnd+1)/2;
|
||||
len=lengthVOX;
|
||||
off=lengthVOX;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
end=loopEnd*2;
|
||||
len=length16;
|
||||
off=length16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return isLoopable()?end:len;
|
||||
return off;
|
||||
}
|
||||
|
||||
void DivSample::setSampleCount(unsigned int count) {
|
||||
|
@ -138,7 +224,7 @@ bool DivSample::save(const char* path) {
|
|||
if(isLoopable())
|
||||
{
|
||||
inst.loop_count = 1;
|
||||
inst.loops[0].mode = SF_LOOP_FORWARD;
|
||||
inst.loops[0].mode = (int)loopMode+SF_LOOP_FORWARD;
|
||||
inst.loops[0].start = loopStart;
|
||||
inst.loops[0].end = loopEnd;
|
||||
}
|
||||
|
@ -895,9 +981,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
|||
duplicate=new unsigned char[getCurBufLen()];
|
||||
memcpy(duplicate,getCurBuf(),getCurBufLen());
|
||||
}
|
||||
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd);
|
||||
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,loopMode);
|
||||
} else {
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd);
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,loopMode);
|
||||
}
|
||||
if (!doNotPush) {
|
||||
while (!redoHist.empty()) {
|
||||
|
@ -928,7 +1014,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
|||
rate=h->rate; \
|
||||
centerRate=h->centerRate; \
|
||||
loopStart=h->loopStart; \
|
||||
loopEnd=h->loopEnd;
|
||||
loopEnd=h->loopEnd; \
|
||||
loop=h->loop; \
|
||||
loopMode=h->loopMode;
|
||||
|
||||
|
||||
int DivSample::undo() {
|
||||
|
|
|
@ -25,6 +25,13 @@
|
|||
#include "../ta-utils.h"
|
||||
#include <deque>
|
||||
|
||||
enum DivSampleLoopMode: unsigned char {
|
||||
DIV_SAMPLE_LOOP_FORWARD=0,
|
||||
DIV_SAMPLE_LOOP_BACKWARD,
|
||||
DIV_SAMPLE_LOOP_PINGPONG,
|
||||
DIV_SAMPLE_LOOP_MAX // boundary for loop mode
|
||||
};
|
||||
|
||||
enum DivSampleDepth: unsigned char {
|
||||
DIV_SAMPLE_DEPTH_1BIT=0,
|
||||
DIV_SAMPLE_DEPTH_1BIT_DPCM=1,
|
||||
|
@ -53,8 +60,10 @@ struct DivSampleHistory {
|
|||
unsigned int length, samples;
|
||||
DivSampleDepth depth;
|
||||
int rate, centerRate, loopStart, loopEnd;
|
||||
bool loop;
|
||||
DivSampleLoopMode loopMode;
|
||||
bool hasSample;
|
||||
DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le):
|
||||
DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm):
|
||||
data((unsigned char*)d),
|
||||
length(l),
|
||||
samples(s),
|
||||
|
@ -63,8 +72,10 @@ struct DivSampleHistory {
|
|||
centerRate(cr),
|
||||
loopStart(ls),
|
||||
loopEnd(le),
|
||||
loop(lp),
|
||||
loopMode(lm),
|
||||
hasSample(true) {}
|
||||
DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le):
|
||||
DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm):
|
||||
data(NULL),
|
||||
length(0),
|
||||
samples(0),
|
||||
|
@ -73,6 +84,8 @@ struct DivSampleHistory {
|
|||
centerRate(cr),
|
||||
loopStart(ls),
|
||||
loopEnd(le),
|
||||
loop(lp),
|
||||
loopMode(lm),
|
||||
hasSample(false) {}
|
||||
~DivSampleHistory();
|
||||
};
|
||||
|
@ -92,6 +105,13 @@ struct DivSample {
|
|||
// - 10: VOX ADPCM
|
||||
// - 16: 16-bit PCM
|
||||
DivSampleDepth depth;
|
||||
bool loop;
|
||||
// valid values are:
|
||||
// - 0: No loop
|
||||
// - 1: Forward loop
|
||||
// - 2: Backward loop
|
||||
// - 3: Pingpong loop
|
||||
DivSampleLoopMode loopMode;
|
||||
|
||||
// these are the new data structures.
|
||||
signed char* data8; // 8
|
||||
|
@ -120,11 +140,29 @@ struct DivSample {
|
|||
*/
|
||||
bool isLoopable();
|
||||
|
||||
/**
|
||||
* get sample start position
|
||||
* @return the samples start position.
|
||||
*/
|
||||
int getLoopStartPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||
|
||||
/**
|
||||
* get sample loop end position
|
||||
* @return the samples loop end position.
|
||||
*/
|
||||
int getLoopEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||
|
||||
/**
|
||||
* get sample end position
|
||||
* @return the samples end position.
|
||||
*/
|
||||
unsigned int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||
int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||
|
||||
/**
|
||||
* get sample offset
|
||||
* @return the sample offset.
|
||||
*/
|
||||
int getSampleOffset(int offset, int length, DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||
|
||||
/**
|
||||
* @warning DO NOT USE - internal functions
|
||||
|
@ -253,6 +291,8 @@ struct DivSample {
|
|||
loopEnd(-1),
|
||||
loopOffP(0),
|
||||
depth(DIV_SAMPLE_DEPTH_16BIT),
|
||||
loop(false),
|
||||
loopMode(DIV_SAMPLE_LOOP_FORWARD),
|
||||
data8(NULL),
|
||||
data16(NULL),
|
||||
data1(NULL),
|
||||
|
|
|
@ -511,7 +511,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(write.val); // sample number
|
||||
w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||
if (sample->isLoopable() && !sampleDir[streamID]) {
|
||||
loopTimer[streamID]=sample->length8;
|
||||
loopSample[streamID]=write.val;
|
||||
|
@ -1549,7 +1549,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
size_t memPos=0;
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
DivSample* sample=song.sample[i];
|
||||
unsigned int alignedSize=(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff);
|
||||
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;
|
||||
|
@ -1559,9 +1559,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
sample->offSegaPCM=memPos;
|
||||
unsigned int readPos=0;
|
||||
for (unsigned int j=0; j<alignedSize; j++) {
|
||||
if (readPos>=sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||
if (readPos>=sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||
if (sample->isLoopable()) {
|
||||
readPos=sample->loopStart;
|
||||
readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
|
||||
} else {
|
||||
pcmMem[memPos++]=0x80;
|
||||
|
@ -1572,7 +1572,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
readPos++;
|
||||
if (memPos>=16777216) break;
|
||||
}
|
||||
sample->loopOffP=readPos-sample->loopStart;
|
||||
sample->loopOffP=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
if (memPos>=16777216) break;
|
||||
}
|
||||
|
||||
|
@ -1897,12 +1897,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
if (loopSample[nextToTouch]<song.sampleLen) {
|
||||
DivSample* sample=song.sample[loopSample[nextToTouch]];
|
||||
// insert loop
|
||||
if (sample->loopStart<(int)sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||
if (sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)<sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||
w->writeC(0x93);
|
||||
w->writeC(nextToTouch);
|
||||
w->writeI(sample->off8+sample->loopStart);
|
||||
w->writeI(sample->off8+sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
w->writeC(0x81);
|
||||
w->writeI(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->loopStart);
|
||||
w->writeI(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
}
|
||||
}
|
||||
loopSample[nextToTouch]=-1;
|
||||
|
|
|
@ -157,10 +157,11 @@ void FurnaceGUI::drawDebug() {
|
|||
ImGui::Text("loopStart: %d",sample->loopStart);
|
||||
ImGui::Text("loopEnd: %d", sample->loopEnd);
|
||||
ImGui::Text("loopOffP: %d",sample->loopOffP);
|
||||
if (sampleDepths[sample->depth]!=NULL) {
|
||||
ImGui::Text("depth: %d (%s)",(unsigned char)sample->depth,sampleDepths[sample->depth]);
|
||||
ImGui::Text(sample->loop?"loop: Enabled":"loop: Disabled");
|
||||
if (sampleLoopModes[sample->loopMode]!=NULL) {
|
||||
ImGui::Text("loopMode: %d (%s)",(unsigned char)sample->loopMode,sampleLoopModes[sample->loopMode]);
|
||||
} else {
|
||||
ImGui::Text("depth: %d (<NULL!>)",(unsigned char)sample->depth);
|
||||
ImGui::Text("loopMode: %d (<NULL!>)",(unsigned char)sample->loopMode);
|
||||
}
|
||||
|
||||
ImGui::Text("length8: %d",sample->length8);
|
||||
|
|
|
@ -710,6 +710,8 @@ void FurnaceGUI::doAction(int what) {
|
|||
sample->name=prevSample->name;
|
||||
sample->loopStart=prevSample->loopStart;
|
||||
sample->loopEnd=prevSample->loopEnd;
|
||||
sample->loop=prevSample->loop;
|
||||
sample->loopMode=prevSample->loopMode;
|
||||
sample->depth=prevSample->depth;
|
||||
if (sample->init(prevSample->samples)) {
|
||||
if (prevSample->getCurBuf()!=NULL) {
|
||||
|
@ -1264,6 +1266,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
|
||||
sample->loopStart=start;
|
||||
sample->loopEnd=end;
|
||||
sample->loop=true;
|
||||
updateSampleTex=true;
|
||||
|
||||
e->renderSamples();
|
||||
|
|
|
@ -116,6 +116,12 @@ const char* insTypes[DIV_INS_MAX+1]={
|
|||
NULL
|
||||
};
|
||||
|
||||
const char* sampleLoopModes[DIV_SAMPLE_LOOP_MAX]={
|
||||
"Forward",
|
||||
"Backward",
|
||||
"Ping pong"
|
||||
};
|
||||
|
||||
const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
|
||||
"1-bit PCM",
|
||||
"1-bit DPCM",
|
||||
|
|
|
@ -40,6 +40,7 @@ extern const char* noteNames[180];
|
|||
extern const char* noteNamesG[180];
|
||||
extern const char* pitchLabel[11];
|
||||
extern const char* insTypes[];
|
||||
extern const char* sampleLoopModes[];
|
||||
extern const char* sampleDepths[];
|
||||
extern const char* resampleStrats[];
|
||||
extern const int availableSystems[];
|
||||
|
|
|
@ -46,6 +46,12 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sampleType=sampleDepths[sample->depth];
|
||||
}
|
||||
}
|
||||
String loopType="Invalid";
|
||||
if (sample->loopMode<DIV_SAMPLE_LOOP_MAX) {
|
||||
if (sampleLoopModes[sample->loopMode]!=NULL) {
|
||||
loopType=sampleLoopModes[sample->loopMode];
|
||||
}
|
||||
}
|
||||
if (!settings.sampleLayout) {
|
||||
ImGui::Text("Name");
|
||||
ImGui::SameLine();
|
||||
|
@ -96,9 +102,11 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
bool doLoop=(sample->isLoopable());
|
||||
if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED
|
||||
if (doLoop) {
|
||||
sample->loop=true;
|
||||
sample->loopStart=0;
|
||||
sample->loopEnd=sample->samples;
|
||||
} else {
|
||||
sample->loop=false;
|
||||
sample->loopStart=-1;
|
||||
sample->loopEnd=sample->samples;
|
||||
}
|
||||
|
@ -107,6 +115,23 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (doLoop) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Mode");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::BeginCombo("##SampleLoopMode",loopType.c_str())) {
|
||||
for (int i=0; i<DIV_SAMPLE_LOOP_MAX; i++) {
|
||||
if (sampleLoopModes[i]==NULL) continue;
|
||||
if (ImGui::Selectable(sampleLoopModes[i])) {
|
||||
sample->prepareUndo(true);
|
||||
sample->loopMode=(DivSampleLoopMode)i;
|
||||
e->renderSamplesP();
|
||||
updateSampleTex=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Start");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -631,15 +656,35 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
bool doLoop=(sample->isLoopable());
|
||||
if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED
|
||||
if (doLoop) {
|
||||
sample->loop=true;
|
||||
sample->loopStart=0;
|
||||
sample->loopEnd=sample->samples;
|
||||
} else {
|
||||
sample->loop=false;
|
||||
sample->loopStart=-1;
|
||||
sample->loopEnd=sample->samples;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (doLoop) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Mode");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::BeginCombo("##SampleLoopMode",loopType.c_str())) {
|
||||
for (int i=0; i<DIV_SAMPLE_LOOP_MAX; i++) {
|
||||
if (sampleLoopModes[i]==NULL) continue;
|
||||
if (ImGui::Selectable(sampleLoopModes[i])) {
|
||||
sample->prepareUndo(true);
|
||||
sample->loopMode=(DivSampleLoopMode)i;
|
||||
e->renderSamplesP();
|
||||
updateSampleTex=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Start");
|
||||
|
|
Loading…
Reference in New Issue