Implement sample loop end position, enum-ise sample depth (#557)

TODO: new sample format
This commit is contained in:
cam900 2022-07-22 13:36:42 +09:00 committed by GitHub
parent a137eefd20
commit 5127d5ef18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 461 additions and 306 deletions

View File

@ -2226,7 +2226,7 @@ int DivEngine::addSampleFromFile(const char* path) {
sample->rate=33144; sample->rate=33144;
sample->centerRate=33144; sample->centerRate=33144;
sample->depth=1; sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM;
sample->init(len*8); sample->init(len*8);
if (fread(sample->dataDPCM,1,len,f)==0) { if (fread(sample->dataDPCM,1,len,f)==0) {
@ -2301,9 +2301,9 @@ int DivEngine::addSampleFromFile(const char* path) {
int index=0; int index=0;
if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) {
sample->depth=8; sample->depth=DIV_SAMPLE_DEPTH_8BIT;
} else { } else {
sample->depth=16; sample->depth=DIV_SAMPLE_DEPTH_16BIT;
} }
sample->init(si.frames); sample->init(si.frames);
if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) {
@ -2358,6 +2358,7 @@ int DivEngine::addSampleFromFile(const char* path) {
if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD) if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD)
{ {
sample->loopStart=inst.loops[0].start; sample->loopStart=inst.loops[0].start;
sample->loopEnd=inst.loops[0].end;
if(inst.loops[0].end < (unsigned int)sampleCount) if(inst.loops[0].end < (unsigned int)sampleCount)
sampleCount=inst.loops[0].end; sampleCount=inst.loops[0].end;
} }

View File

@ -799,17 +799,17 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
sample->rate=ymuSampleRate*400; sample->rate=ymuSampleRate*400;
} }
if (ds.version>0x15) { if (ds.version>0x15) {
sample->depth=reader.readC(); sample->depth=(DivSampleDepth)reader.readC();
if (sample->depth!=8 && sample->depth!=16) { if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
logW("%d: sample depth is wrong! (%d)",i,sample->depth); logW("%d: sample depth is wrong! (%d)",i,sample->depth);
sample->depth=16; sample->depth=DIV_SAMPLE_DEPTH_16BIT;
} }
} else { } else {
if (ds.version>0x08) { if (ds.version>0x08) {
sample->depth=16; sample->depth=DIV_SAMPLE_DEPTH_16BIT;
} else { } else {
// it appears samples were stored as ADPCM back then // it appears samples were stored as ADPCM back then
sample->depth=3; sample->depth=DIV_SAMPLE_DEPTH_YMZ_ADPCM;
} }
} }
if (length>0) { if (length>0) {
@ -838,7 +838,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
if (k>=sample->samples) { if (k>=sample->samples) {
break; break;
} }
if (sample->depth==8) { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
float next=(float)(data[(unsigned int)j]-0x80)*mult; float next=(float)(data[(unsigned int)j]-0x80)*mult;
sample->data8[k++]=fmin(fmax(next,-128),127); sample->data8[k++]=fmin(fmax(next,-128),127);
} else { } else {
@ -1631,7 +1631,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
logD("reading sample %d at %x...",i,samplePtr[i]); logD("reading sample %d at %x...",i,samplePtr[i]);
sample->name=reader.readString(); sample->name=reader.readString();
sample->samples=reader.readI(); sample->samples=sample->loopEnd=reader.readI();
sample->rate=reader.readI(); sample->rate=reader.readI();
if (ds.version<58) { if (ds.version<58) {
vol=reader.readS(); vol=reader.readS();
@ -1639,7 +1639,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
} else { } else {
reader.readI(); reader.readI();
} }
sample->depth=reader.readC(); sample->depth=(DivSampleDepth)reader.readC();
// reserved // reserved
reader.readC(); reader.readC();
@ -1657,6 +1657,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
reader.readI(); reader.readI();
} }
/*
if (ds.version>=100) {
sample->loopEnd=reader.readI();
} else {
reader.readI();
}
*/
if (ds.version>=58) { // modern sample if (ds.version>=58) { // modern sample
sample->init(sample->samples); sample->init(sample->samples);
reader.read(sample->getCurBuf(),sample->getCurBufLen()); reader.read(sample->getCurBuf(),sample->getCurBufLen());
@ -1670,9 +1677,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
} }
// render data // render data
if (sample->depth!=8 && sample->depth!=16) { if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
logW("%d: sample depth is wrong! (%d)",i,sample->depth); logW("%d: sample depth is wrong! (%d)",i,sample->depth);
sample->depth=16; sample->depth=DIV_SAMPLE_DEPTH_16BIT;
} }
sample->samples=(double)sample->samples/samplePitches[pitch]; sample->samples=(double)sample->samples/samplePitches[pitch];
sample->init(sample->samples); sample->init(sample->samples);
@ -1683,7 +1690,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (k>=sample->samples) { if (k>=sample->samples) {
break; break;
} }
if (sample->depth==8) { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
float next=(float)(data[(unsigned int)j]-0x80)*mult; float next=(float)(data[(unsigned int)j]-0x80)*mult;
sample->data8[k++]=fmin(fmax(next,-128),127); sample->data8[k++]=fmin(fmax(next,-128),127);
} else { } else {
@ -1877,7 +1884,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
logD("reading samples... (%d)",insCount); logD("reading samples... (%d)",insCount);
for (int i=0; i<insCount; i++) { for (int i=0; i<insCount; i++) {
DivSample* sample=new DivSample; DivSample* sample=new DivSample;
sample->depth=8; sample->depth=DIV_SAMPLE_DEPTH_8BIT;
sample->name=reader.readString(22); sample->name=reader.readString(22);
logD("%d: %s",i+1,sample->name); logD("%d: %s",i+1,sample->name);
int slen=((unsigned short)reader.readS_BE())*2; int slen=((unsigned short)reader.readS_BE())*2;
@ -1897,8 +1904,8 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
loopLen=0; loopLen=0;
} }
if (loopLen>=2) { if (loopLen>=2) {
if (loopEnd<slen) slen=loopEnd;
sample->loopStart=loopStart; sample->loopStart=loopStart;
sample->loopEnd=loopEnd;
} }
sample->init(slen); sample->init(slen);
ds.sample.push_back(sample); ds.sample.push_back(sample);
@ -3043,6 +3050,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeC(0); w->writeC(0);
w->writeS(sample->centerRate); w->writeS(sample->centerRate);
w->writeI(sample->loopStart); w->writeI(sample->loopStart);
//w->writeI(sample->loopEnd);
w->write(sample->getCurBuf(),sample->getCurBufLen()); w->write(sample->getCurBuf(),sample->getCurBufLen());

View File

@ -114,12 +114,10 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
if (chan[i].audPos<s->samples) { if (chan[i].audPos<s->samples) {
writeAudDat(s->data8[chan[i].audPos++]); writeAudDat(s->data8[chan[i].audPos++]);
} }
if (chan[i].audPos>=s->samples || chan[i].audPos>=131071) { if (s->isLoopable() && chan[i].audPos>=MIN(131071,s->getEndPosition())) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { chan[i].audPos=s->loopStart;
chan[i].audPos=s->loopStart; } else if (chan[i].audPos>=MIN(131071,s->samples)) {
} else { chan[i].sample=-1;
chan[i].sample=-1;
}
} }
} else { } else {
chan[i].sample=-1; chan[i].sample=-1;

View File

@ -153,14 +153,13 @@ void DivPlatformGenesis::processDAC() {
if (chan[i].dacPeriod>=(chipClock/576)) { if (chan[i].dacPeriod>=(chipClock/576)) {
if (s->samples>0) { if (s->samples>0) {
while (chan[i].dacPeriod>=(chipClock/576)) { while (chan[i].dacPeriod>=(chipClock/576)) {
if (++chan[i].dacPos>=s->samples) { ++chan[i].dacPos;
if (s->loopStart>=0 && s->loopStart<(int)s->samples && !chan[i].dacDirection) { if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=s->getEndPosition())) {
chan[i].dacPos=s->loopStart; chan[i].dacPos=s->loopStart;
} else { } else if (chan[i].dacPos>=s->samples) {
chan[i].dacSample=-1; chan[i].dacSample=-1;
chan[i].dacPeriod=0; chan[i].dacPeriod=0;
break; break;
}
} }
chan[i].dacPeriod-=(chipClock/576); chan[i].dacPeriod-=(chipClock/576);
} }
@ -200,14 +199,13 @@ void DivPlatformGenesis::processDAC() {
chan[5].dacReady=false; chan[5].dacReady=false;
} }
} }
if (++chan[5].dacPos>=s->samples) { chan[5].dacPos++;
if (s->loopStart>=0 && s->loopStart<(int)s->samples && !chan[5].dacDirection) { if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=s->getEndPosition())) {
chan[5].dacPos=s->loopStart; chan[5].dacPos=s->loopStart;
} else { } else if (chan[5].dacPos>=s->samples) {
chan[5].dacSample=-1; chan[5].dacSample=-1;
if (parent->song.brokenDACMode) { if (parent->song.brokenDACMode) {
rWrite(0x2b,0); rWrite(0x2b,0);
}
} }
} }
while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate; while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate;

View File

@ -158,12 +158,10 @@ 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); WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7);
} }
if (chan[i].samplePos>=(int)s->samples) { if (s->isLoopable() && chan[i].samplePos>=(int)s->getEndPosition()) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { chan[i].samplePos=s->loopStart;
chan[i].samplePos=s->loopStart; } else if (chan[i].samplePos>=(int)s->samples) {
} else { chan[i].sample=-1;
chan[i].sample=-1;
}
} }
} }
} }

View File

@ -62,12 +62,11 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
if (!isMuted[2]) { if (!isMuted[2]) {
rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80));
} }
if (++dacPos>=s->samples) { dacPos++;
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { if (s->isLoopable() && dacPos>=s->getEndPosition()) {
dacPos=s->loopStart; dacPos=s->loopStart;
} else { } else if (dacPos>=s->samples) {
dacSample=-1; dacSample=-1;
}
} }
dacPeriod-=rate; dacPeriod-=rate;
} else { } else {

View File

@ -108,12 +108,11 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
rWrite(0x4011,next); \ rWrite(0x4011,next); \
} \ } \
} \ } \
if (++dacPos>=s->samples) { \ dacPos++; \
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { \ if (s->isLoopable() && dacPos>=s->getEndPosition()) { \
dacPos=s->loopStart; \ dacPos=s->loopStart; \
} else { \ } else if (dacPos>=s->samples) { \
dacSample=-1; \ dacSample=-1; \
} \
} \ } \
dacPeriod-=rate; \ dacPeriod-=rate; \
} else { \ } else { \

View File

@ -771,7 +771,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
int end=s->offB+s->lengthB-1; int end=s->offB+s->lengthB-1;
immWrite(11,(end>>2)&0xff); immWrite(11,(end>>2)&0xff);
immWrite(12,(end>>10)&0xff); immWrite(12,(end>>10)&0xff);
immWrite(7,(s->loopStart>=0)?0xb0:0xa0); // start/repeat immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
@ -807,7 +807,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
int end=s->offB+s->lengthB-1; int end=s->offB+s->lengthB-1;
immWrite(11,(end>>2)&0xff); immWrite(11,(end>>2)&0xff);
immWrite(12,(end>>10)&0xff); immWrite(12,(end>>10)&0xff);
immWrite(7,(s->loopStart>=0)?0xb0:0xa0); // start/repeat immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat
int freq=(65536.0*(double)s->rate)/(double)chipRateBase; int freq=(65536.0*(double)s->rate)/(double)chipRateBase;
immWrite(16,freq&0xff); immWrite(16,freq&0xff);
immWrite(17,(freq>>8)&0xff); immWrite(17,(freq>>8)&0xff);

View File

@ -90,12 +90,10 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len)
chWrite(i,0x04,0xdf); chWrite(i,0x04,0xdf);
chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3)); chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3));
chan[i].dacPos++; chan[i].dacPos++;
if (chan[i].dacPos>=s->samples) { if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { chan[i].dacPos=s->loopStart;
chan[i].dacPos=s->loopStart; } else if (chan[i].dacPos>=s->samples) {
} else { chan[i].dacSample=-1;
chan[i].dacSample=-1;
}
} }
chan[i].dacPeriod-=rate; chan[i].dacPeriod-=rate;
} }

View File

@ -301,7 +301,7 @@ void DivPlatformQSound::tick(bool sysTick) {
qsound_bank = 0x8000 | (s->offQSound >> 16); qsound_bank = 0x8000 | (s->offQSound >> 16);
qsound_addr = s->offQSound & 0xffff; qsound_addr = s->offQSound & 0xffff;
int length = s->samples; int length = s->getEndPosition();
if (length > 65536 - 16) { if (length > 65536 - 16) {
length = 65536 - 16; length = 65536 - 16;
} }

View File

@ -142,7 +142,7 @@ void DivPlatformRF5C68::tick(bool sysTick) {
if (chan[i].audPos>0) { if (chan[i].audPos>0) {
start=start+MIN(chan[i].audPos,s->length8); start=start+MIN(chan[i].audPos,s->length8);
} }
if (s->loopStart>=0) { if (s->isLoopable()) {
loop=start+s->loopStart; loop=start+s->loopStart;
} }
start=MIN(start,getSampleMemCapacity()-31); start=MIN(start,getSampleMemCapacity()-31);
@ -393,7 +393,7 @@ void DivPlatformRF5C68::renderSamples() {
size_t memPos=0; size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) { for (int i=0; i<parent->song.sampleLen; i++) {
DivSample* s=parent->song.sample[i]; DivSample* s=parent->song.sample[i];
int length=s->length8; int length=s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length); int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
if (actualLength>0) { if (actualLength>0) {
s->offRF5C68=memPos; s->offRF5C68=memPos;

View File

@ -56,12 +56,10 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t
pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR); pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR);
} }
chan[i].pcm.pos+=chan[i].pcm.freq; chan[i].pcm.pos+=chan[i].pcm.freq;
if (chan[i].pcm.pos>=(s->samples<<8)) { if (s->isLoopable() && chan[i].pcm.pos>=(s->getEndPosition()<<8)) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { chan[i].pcm.pos=s->loopStart<<8;
chan[i].pcm.pos=s->loopStart<<8; } else if (chan[i].pcm.pos>=(s->samples<<8)) {
} else { chan[i].pcm.sample=-1;
chan[i].pcm.sample=-1;
}
} }
} else { } else {
oscBuf[i]->data[oscBuf[i]->needle++]=0; oscBuf[i]->data[oscBuf[i]->needle++]=0;
@ -202,7 +200,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].macroInit(ins); chan[c.chan].macroInit(ins);
if (dumpWrites) { // Sega PCM writes if (dumpWrites) { // Sega PCM writes
DivSample* s=parent->getSample(chan[c.chan].pcm.sample); DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
int actualLength=(int)s->length8; int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff; if (actualLength>0xfeff) actualLength=0xfeff;
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff);
@ -235,7 +233,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].furnacePCM=false; chan[c.chan].furnacePCM=false;
if (dumpWrites) { // Sega PCM writes if (dumpWrites) { // Sega PCM writes
DivSample* s=parent->getSample(chan[c.chan].pcm.sample); DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
int actualLength=(int)s->length8; int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>65536) actualLength=65536; if (actualLength>65536) actualLength=65536;
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff);

View File

@ -213,7 +213,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note)); DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note));
if (sample!=NULL) { if (sample!=NULL) {
unsigned int sampleEnd=sample->offSU+sample->samples; unsigned int sampleEnd=sample->offSU+(sample->getEndPosition());
unsigned int off=sample->offSU+chan[i].hasOffset; unsigned int off=sample->offSU+chan[i].hasOffset;
chan[i].hasOffset=0; chan[i].hasOffset=0;
if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1; if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1;
@ -221,7 +221,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
chWrite(i,0x0b,off>>8); chWrite(i,0x0b,off>>8);
chWrite(i,0x0c,sampleEnd&0xff); chWrite(i,0x0c,sampleEnd&0xff);
chWrite(i,0x0d,sampleEnd>>8); chWrite(i,0x0d,sampleEnd>>8);
if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples) { if (sample->isLoopable()) {
unsigned int sampleLoop=sample->offSU+sample->loopStart; unsigned int sampleLoop=sample->offSU+sample->loopStart;
if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1; if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1;
chWrite(i,0x0e,sampleLoop&0xff); chWrite(i,0x0e,sampleLoop&0xff);

View File

@ -83,12 +83,10 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len
continue; continue;
} }
rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80);
if (dacPos>=s->samples) { if (s->isLoopable() && dacPos>=s->getEndPosition()) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { dacPos=s->loopStart;
dacPos=s->loopStart; } else if (dacPos>=s->samples) {
} else { dacSample=-1;
dacSample=-1;
}
} }
dacPeriod-=rate; dacPeriod-=rate;
} }

View File

@ -96,13 +96,11 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
rWritePCMData(tmp_r&0xff); rWritePCMData(tmp_r&0xff);
} }
chan[16].pcm.pos++; chan[16].pcm.pos++;
if (chan[16].pcm.pos>=s->samples) { if (s->isLoopable() && chan[16].pcm.pos>=s->getEndPosition()) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { chan[16].pcm.pos=s->loopStart;
chan[16].pcm.pos=s->loopStart; } else if (chan[16].pcm.pos>=s->samples) {
} else { chan[16].pcm.sample=-1;
chan[16].pcm.sample=-1; break;
break;
}
} }
} }
} else { } else {
@ -267,12 +265,12 @@ int DivPlatformVERA::dispatch(DivCommand c) {
chan[16].pcm.pos=0; chan[16].pcm.pos=0;
DivSample* s=parent->getSample(chan[16].pcm.sample); DivSample* s=parent->getSample(chan[16].pcm.sample);
unsigned char ctrl=0x90|chan[16].vol; // always stereo unsigned char ctrl=0x90|chan[16].vol; // always stereo
if (s->depth==16) { if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
chan[16].pcm.depth16=true; chan[16].pcm.depth16=true;
ctrl|=0x20; ctrl|=0x20;
} else { } else {
chan[16].pcm.depth16=false; chan[16].pcm.depth16=false;
if (s->depth!=8) chan[16].pcm.sample=-1; if (s->depth!=DIV_SAMPLE_DEPTH_8BIT) chan[16].pcm.sample=-1;
} }
rWritePCMCtrl(ctrl); rWritePCMCtrl(ctrl);
} }

View File

@ -77,13 +77,11 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len
chWrite(i,0,0x80|chan[i].dacOut); chWrite(i,0,0x80|chan[i].dacOut);
} }
chan[i].dacPos++; chan[i].dacPos++;
if (chan[i].dacPos>=s->samples) { if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { chan[i].dacPos=s->loopStart;
chan[i].dacPos=s->loopStart; } else if (chan[i].dacPos>=s->samples) {
} else { chan[i].dacSample=-1;
chan[i].dacSample=-1; chWrite(i,0,0);
chWrite(i,0,0);
}
} }
chan[i].dacPeriod-=rate; chan[i].dacPeriod-=rate;
} }

View File

@ -761,7 +761,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
immWrite(0x104,(end>>5)&0xff); immWrite(0x104,(end>>5)&0xff);
immWrite(0x105,(end>>13)&0xff); immWrite(0x105,(end>>13)&0xff);
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
immWrite(0x100,(s->loopStart>=0)?0xb0:0xa0); // start/repeat immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
@ -796,7 +796,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
immWrite(0x104,(end>>5)&0xff); immWrite(0x104,(end>>5)&0xff);
immWrite(0x105,(end>>13)&0xff); immWrite(0x105,(end>>13)&0xff);
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
immWrite(0x100,(s->loopStart>=0)?0xb0:0xa0); // start/repeat immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
immWrite(0x109,freq&0xff); immWrite(0x109,freq&0xff);
immWrite(0x10a,(freq>>8)&0xff); immWrite(0x10a,(freq>>8)&0xff);

View File

@ -793,7 +793,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
immWrite(0x14,(end>>8)&0xff); immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16); immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
@ -828,7 +828,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
immWrite(0x14,(end>>8)&0xff); immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16); immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
immWrite(0x19,freq&0xff); immWrite(0x19,freq&0xff);
immWrite(0x1a,(freq>>8)&0xff); immWrite(0x1a,(freq>>8)&0xff);

View File

@ -775,7 +775,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
immWrite(0x14,(end>>8)&0xff); immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16); immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
@ -810,7 +810,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
immWrite(0x14,(end>>8)&0xff); immWrite(0x14,(end>>8)&0xff);
immWrite(0x15,end>>16); immWrite(0x15,end>>16);
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
immWrite(0x19,freq&0xff); immWrite(0x19,freq&0xff);
immWrite(0x1a,(freq>>8)&0xff); immWrite(0x1a,(freq>>8)&0xff);

View File

@ -136,9 +136,9 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
DivSample* s=parent->getSample(chan[i].sample); DivSample* s=parent->getSample(chan[i].sample);
unsigned char ctrl; unsigned char ctrl;
switch (s->depth) { switch (s->depth) {
case 3: ctrl=0x20; break; case DIV_SAMPLE_DEPTH_YMZ_ADPCM: ctrl=0x20; break;
case 8: ctrl=0x40; break; case DIV_SAMPLE_DEPTH_8BIT: ctrl=0x40; break;
case 16: ctrl=0x60; break; case DIV_SAMPLE_DEPTH_16BIT: ctrl=0x60; break;
default: ctrl=0; default: ctrl=0;
} }
double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0; double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0;
@ -146,40 +146,44 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>511) chan[i].freq=511; if (chan[i].freq>511) chan[i].freq=511;
// ADPCM has half the range // ADPCM has half the range
if (s->depth==3 && chan[i].freq>255) chan[i].freq=255; if (s->depth==DIV_SAMPLE_DEPTH_YMZ_ADPCM && chan[i].freq>255) chan[i].freq=255;
ctrl|=(chan[i].active?0x80:0)|((s->loopStart>=0)?0x10:0)|(chan[i].freq>>8); ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|(chan[i].freq>>8);
if (chan[i].keyOn) { if (chan[i].keyOn) {
unsigned int start=s->offYMZ280B; unsigned int start=s->offYMZ280B;
unsigned int loop=0; unsigned int loopStart=0;
unsigned int loopEnd=0;
unsigned int end=MIN(start+s->getCurBufLen(),getSampleMemCapacity()-1); unsigned int end=MIN(start+s->getCurBufLen(),getSampleMemCapacity()-1);
if (chan[i].audPos>0) { if (chan[i].audPos>0) {
switch (s->depth) { switch (s->depth) {
case 3: start+=chan[i].audPos/2; break; case DIV_SAMPLE_DEPTH_YMZ_ADPCM: start+=chan[i].audPos/2; break;
case 8: start+=chan[i].audPos; break; case DIV_SAMPLE_DEPTH_8BIT: start+=chan[i].audPos; break;
case 16: start+=chan[i].audPos*2; break; case DIV_SAMPLE_DEPTH_16BIT: start+=chan[i].audPos*2; break;
default: break;
} }
start=MIN(start,end); start=MIN(start,end);
} }
if (s->loopStart>=0) { if (s->isLoopable()) {
switch (s->depth) { switch (s->depth) {
case 3: loop=start+s->loopStart/2; break; case DIV_SAMPLE_DEPTH_YMZ_ADPCM: loopStart=start+s->loopStart/2; loopEnd=start+s->loopEnd/2; break;
case 8: loop=start+s->loopStart; break; case DIV_SAMPLE_DEPTH_8BIT: loopStart=start+s->loopStart; loopEnd=start+s->loopEnd; break;
case 16: loop=start+s->loopStart*2; break; case DIV_SAMPLE_DEPTH_16BIT: loopStart=start+s->loopStart*2; loopEnd=start+s->loopEnd*2; break;
default: break;
} }
loop=MIN(loop,end); loopEnd=MIN(loopEnd,end);
loopStart=MIN(loopStart,loopEnd);
} }
rWrite(0x01+i*4,ctrl&~0x80); // force keyoff first rWrite(0x01+i*4,ctrl&~0x80); // force keyoff first
rWrite(0x20+i*4,(start>>16)&0xff); rWrite(0x20+i*4,(start>>16)&0xff);
rWrite(0x21+i*4,(loop>>16)&0xff); rWrite(0x21+i*4,(loopStart>>16)&0xff);
rWrite(0x22+i*4,(end>>16)&0xff); rWrite(0x22+i*4,(loopEnd>>16)&0xff);
rWrite(0x23+i*4,(end>>16)&0xff); rWrite(0x23+i*4,(end>>16)&0xff);
rWrite(0x40+i*4,(start>>8)&0xff); rWrite(0x40+i*4,(start>>8)&0xff);
rWrite(0x41+i*4,(loop>>8)&0xff); rWrite(0x41+i*4,(loopStart>>8)&0xff);
rWrite(0x42+i*4,(end>>8)&0xff); rWrite(0x42+i*4,(loopEnd>>8)&0xff);
rWrite(0x43+i*4,(end>>8)&0xff); rWrite(0x43+i*4,(end>>8)&0xff);
rWrite(0x60+i*4,start&0xff); rWrite(0x60+i*4,start&0xff);
rWrite(0x61+i*4,loop&0xff); rWrite(0x61+i*4,loopStart&0xff);
rWrite(0x62+i*4,end&0xff); rWrite(0x62+i*4,loopEnd&0xff);
rWrite(0x63+i*4,end&0xff); rWrite(0x63+i*4,end&0xff);
if (!chan[i].std.vol.had) { if (!chan[i].std.vol.had) {
chan[i].outVol=chan[i].vol; chan[i].outVol=chan[i].vol;

View File

@ -1204,17 +1204,17 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); blip_add_delta(samp_bb,i,samp_temp-samp_prevSample);
samp_prevSample=samp_temp; samp_prevSample=samp_temp;
if (sPreview.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples && (int)sPreview.pos>=s->loopStart) { if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) {
sPreview.pos=s->loopStart; sPreview.pos=s->loopStart;
} }
} }
} }
if (sPreview.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
if (s->loopStart>=0 && s->loopStart<(int)s->samples && (int)sPreview.pos>=s->loopStart) { if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) {
sPreview.pos=s->loopStart; sPreview.pos=s->loopStart;
} else { } else if (sPreview.pos>=s->samples) {
sPreview.sample=-1; sPreview.sample=-1;
} }
} }

View File

@ -38,6 +38,65 @@ DivSampleHistory::~DivSampleHistory() {
if (data!=NULL) delete[] data; if (data!=NULL) delete[] data;
} }
bool DivSample::isLoopable() {
return (loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples);
}
unsigned int DivSample::getEndPosition(DivSampleDepth depth) {
int end=loopEnd;
unsigned int len=samples;
switch (depth) {
case DIV_SAMPLE_DEPTH_1BIT:
end=(loopEnd+7)/8;
len=length1;
break;
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
end=(loopEnd+7)/8;
len=lengthDPCM;
break;
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
end=(loopEnd+1)/2;
len=lengthZ;
break;
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
end=(loopEnd+1)/2;
len=lengthQSoundA;
break;
case DIV_SAMPLE_DEPTH_ADPCM_A:
end=(loopEnd+1)/2;
len=lengthA;
break;
case DIV_SAMPLE_DEPTH_ADPCM_B:
end=(loopEnd+1)/2;
len=lengthB;
break;
case DIV_SAMPLE_DEPTH_8BIT:
end=loopEnd;
len=length8;
break;
case DIV_SAMPLE_DEPTH_BRR:
end=9*((loopEnd+15)/16);
len=lengthBRR;
break;
case DIV_SAMPLE_DEPTH_VOX:
end=(loopEnd+1)/2;
len=lengthVOX;
break;
case DIV_SAMPLE_DEPTH_16BIT:
end=loopEnd*2;
len=length16;
break;
default:
break;
}
return isLoopable()?end:len;
}
void DivSample::setSampleCount(unsigned int count) {
samples=count;
if ((!isLoopable()) || loopEnd<0 || loopEnd>(int)samples) loopEnd=samples;
}
bool DivSample::save(const char* path) { bool DivSample::save(const char* path) {
#ifndef HAVE_SNDFILE #ifndef HAVE_SNDFILE
logE("Furnace was not compiled with libsndfile!"); logE("Furnace was not compiled with libsndfile!");
@ -53,7 +112,7 @@ bool DivSample::save(const char* path) {
si.channels=1; si.channels=1;
si.samplerate=rate; si.samplerate=rate;
switch (depth) { switch (depth) {
case 8: // 8-bit case DIV_SAMPLE_DEPTH_8BIT: // 8-bit
si.format=SF_FORMAT_PCM_U8|SF_FORMAT_WAV; si.format=SF_FORMAT_PCM_U8|SF_FORMAT_WAV;
break; break;
default: // 16-bit default: // 16-bit
@ -76,17 +135,17 @@ bool DivSample::save(const char* path) {
inst.detune = 50 - (pitch % 100); inst.detune = 50 - (pitch % 100);
inst.velocity_hi = 0x7f; inst.velocity_hi = 0x7f;
inst.key_hi = 0x7f; inst.key_hi = 0x7f;
if(loopStart != -1) if(isLoopable())
{ {
inst.loop_count = 1; inst.loop_count = 1;
inst.loops[0].mode = SF_LOOP_FORWARD; inst.loops[0].mode = SF_LOOP_FORWARD;
inst.loops[0].start = loopStart; inst.loops[0].start = loopStart;
inst.loops[0].end = samples; inst.loops[0].end = loopEnd;
} }
sf_command(f, SFC_SET_INSTRUMENT, &inst, sizeof(inst)); sf_command(f, SFC_SET_INSTRUMENT, &inst, sizeof(inst));
switch (depth) { switch (depth) {
case 8: { case DIV_SAMPLE_DEPTH_8BIT: {
// convert from signed to unsigned // convert from signed to unsigned
unsigned char* buf=new unsigned char[length8]; unsigned char* buf=new unsigned char[length8];
for (size_t i=0; i<length8; i++) { for (size_t i=0; i<length8; i++) {
@ -108,65 +167,65 @@ bool DivSample::save(const char* path) {
} }
// 16-bit memory is padded to 512, to make things easier for ADPCM-A/B. // 16-bit memory is padded to 512, to make things easier for ADPCM-A/B.
bool DivSample::initInternal(unsigned char d, int count) { bool DivSample::initInternal(DivSampleDepth d, int count) {
switch (d) { switch (d) {
case 0: // 1-bit case DIV_SAMPLE_DEPTH_1BIT: // 1-bit
if (data1!=NULL) delete[] data1; if (data1!=NULL) delete[] data1;
length1=(count+7)/8; length1=(count+7)/8;
data1=new unsigned char[length1]; data1=new unsigned char[length1];
memset(data1,0,length1); memset(data1,0,length1);
break; break;
case 1: // DPCM case DIV_SAMPLE_DEPTH_1BIT_DPCM: // DPCM
if (dataDPCM!=NULL) delete[] dataDPCM; if (dataDPCM!=NULL) delete[] dataDPCM;
lengthDPCM=(count+7)/8; lengthDPCM=(count+7)/8;
dataDPCM=new unsigned char[lengthDPCM]; dataDPCM=new unsigned char[lengthDPCM];
memset(dataDPCM,0,lengthDPCM); memset(dataDPCM,0,lengthDPCM);
break; break;
case 3: // YMZ ADPCM case DIV_SAMPLE_DEPTH_YMZ_ADPCM: // YMZ ADPCM
if (dataZ!=NULL) delete[] dataZ; if (dataZ!=NULL) delete[] dataZ;
lengthZ=(count+1)/2; lengthZ=(count+1)/2;
// for padding AICA sample // for padding AICA sample
dataZ=new unsigned char[(lengthZ+3)&(~0x03)]; dataZ=new unsigned char[(lengthZ+3)&(~0x03)];
memset(dataZ,0,(lengthZ+3)&(~0x03)); memset(dataZ,0,(lengthZ+3)&(~0x03));
break; break;
case 4: // QSound ADPCM case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: // QSound ADPCM
if (dataQSoundA!=NULL) delete[] dataQSoundA; if (dataQSoundA!=NULL) delete[] dataQSoundA;
lengthQSoundA=(count+1)/2; lengthQSoundA=(count+1)/2;
dataQSoundA=new unsigned char[lengthQSoundA]; dataQSoundA=new unsigned char[lengthQSoundA];
memset(dataQSoundA,0,lengthQSoundA); memset(dataQSoundA,0,lengthQSoundA);
break; break;
case 5: // ADPCM-A case DIV_SAMPLE_DEPTH_ADPCM_A: // ADPCM-A
if (dataA!=NULL) delete[] dataA; if (dataA!=NULL) delete[] dataA;
lengthA=(count+1)/2; lengthA=(count+1)/2;
dataA=new unsigned char[(lengthA+255)&(~0xff)]; dataA=new unsigned char[(lengthA+255)&(~0xff)];
memset(dataA,0,(lengthA+255)&(~0xff)); memset(dataA,0,(lengthA+255)&(~0xff));
break; break;
case 6: // ADPCM-B case DIV_SAMPLE_DEPTH_ADPCM_B: // ADPCM-B
if (dataB!=NULL) delete[] dataB; if (dataB!=NULL) delete[] dataB;
lengthB=(count+1)/2; lengthB=(count+1)/2;
dataB=new unsigned char[(lengthB+255)&(~0xff)]; dataB=new unsigned char[(lengthB+255)&(~0xff)];
memset(dataB,0,(lengthB+255)&(~0xff)); memset(dataB,0,(lengthB+255)&(~0xff));
break; break;
case 8: // 8-bit case DIV_SAMPLE_DEPTH_8BIT: // 8-bit
if (data8!=NULL) delete[] data8; if (data8!=NULL) delete[] data8;
length8=count; length8=count;
// for padding X1-010 sample // for padding X1-010 sample
data8=new signed char[(count+4095)&(~0xfff)]; data8=new signed char[(count+4095)&(~0xfff)];
memset(data8,0,(count+4095)&(~0xfff)); memset(data8,0,(count+4095)&(~0xfff));
break; break;
case 9: // BRR case DIV_SAMPLE_DEPTH_BRR: // BRR
if (dataBRR!=NULL) delete[] dataBRR; if (dataBRR!=NULL) delete[] dataBRR;
lengthBRR=9*((count+15)/16); lengthBRR=9*((count+15)/16);
dataBRR=new unsigned char[lengthBRR]; dataBRR=new unsigned char[lengthBRR];
memset(dataBRR,0,lengthBRR); memset(dataBRR,0,lengthBRR);
break; break;
case 10: // VOX case DIV_SAMPLE_DEPTH_VOX: // VOX
if (dataVOX!=NULL) delete[] dataVOX; if (dataVOX!=NULL) delete[] dataVOX;
lengthVOX=(count+1)/2; lengthVOX=(count+1)/2;
dataVOX=new unsigned char[lengthVOX]; dataVOX=new unsigned char[lengthVOX];
memset(dataVOX,0,lengthVOX); memset(dataVOX,0,lengthVOX);
break; break;
case 16: // 16-bit case DIV_SAMPLE_DEPTH_16BIT: // 16-bit
if (data16!=NULL) delete[] data16; if (data16!=NULL) delete[] data16;
length16=count*2; length16=count*2;
data16=new short[(count+511)&(~0x1ff)]; data16=new short[(count+511)&(~0x1ff)];
@ -180,34 +239,34 @@ bool DivSample::initInternal(unsigned char d, int count) {
bool DivSample::init(unsigned int count) { bool DivSample::init(unsigned int count) {
if (!initInternal(depth,count)) return false; if (!initInternal(depth,count)) return false;
samples=count; setSampleCount(count);
return true; return true;
} }
bool DivSample::resize(unsigned int count) { bool DivSample::resize(unsigned int count) {
if (depth==8) { if (depth==DIV_SAMPLE_DEPTH_8BIT) {
if (data8!=NULL) { if (data8!=NULL) {
signed char* oldData8=data8; signed char* oldData8=data8;
data8=NULL; data8=NULL;
initInternal(8,count); initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
memcpy(data8,oldData8,MIN(count,samples)); memcpy(data8,oldData8,MIN(count,samples));
delete[] oldData8; delete[] oldData8;
} else { } else {
initInternal(8,count); initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
} }
samples=count; setSampleCount(count);
return true; return true;
} else if (depth==16) { } else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
if (data16!=NULL) { if (data16!=NULL) {
short* oldData16=data16; short* oldData16=data16;
data16=NULL; data16=NULL;
initInternal(16,count); initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
memcpy(data16,oldData16,sizeof(short)*MIN(count,samples)); memcpy(data16,oldData16,sizeof(short)*MIN(count,samples));
delete[] oldData16; delete[] oldData16;
} else { } else {
initInternal(16,count); initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
} }
samples=count; setSampleCount(count);
return true; return true;
} }
return false; return false;
@ -218,11 +277,11 @@ bool DivSample::strip(unsigned int begin, unsigned int end) {
if (end>samples) end=samples; if (end>samples) end=samples;
int count=samples-(end-begin); int count=samples-(end-begin);
if (count<=0) return resize(0); if (count<=0) return resize(0);
if (depth==8) { if (depth==DIV_SAMPLE_DEPTH_8BIT) {
if (data8!=NULL) { if (data8!=NULL) {
signed char* oldData8=data8; signed char* oldData8=data8;
data8=NULL; data8=NULL;
initInternal(8,count); initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
if (begin>0) { if (begin>0) {
memcpy(data8,oldData8,begin); memcpy(data8,oldData8,begin);
} }
@ -234,13 +293,13 @@ bool DivSample::strip(unsigned int begin, unsigned int end) {
// do nothing // do nothing
return true; return true;
} }
samples=count; setSampleCount(count);
return true; return true;
} else if (depth==16) { } else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
if (data16!=NULL) { if (data16!=NULL) {
short* oldData16=data16; short* oldData16=data16;
data16=NULL; data16=NULL;
initInternal(16,count); initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
if (begin>0) { if (begin>0) {
memcpy(data16,oldData16,sizeof(short)*begin); memcpy(data16,oldData16,sizeof(short)*begin);
} }
@ -252,7 +311,7 @@ bool DivSample::strip(unsigned int begin, unsigned int end) {
// do nothing // do nothing
return true; return true;
} }
samples=count; setSampleCount(count);
return true; return true;
} }
return false; return false;
@ -262,31 +321,31 @@ bool DivSample::trim(unsigned int begin, unsigned int end) {
int count=end-begin; int count=end-begin;
if (count==0) return true; if (count==0) return true;
if (begin==0 && end==samples) return true; if (begin==0 && end==samples) return true;
if (depth==8) { if (depth==DIV_SAMPLE_DEPTH_8BIT) {
if (data8!=NULL) { if (data8!=NULL) {
signed char* oldData8=data8; signed char* oldData8=data8;
data8=NULL; data8=NULL;
initInternal(8,count); initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
memcpy(data8,oldData8+begin,count); memcpy(data8,oldData8+begin,count);
delete[] oldData8; delete[] oldData8;
} else { } else {
// do nothing // do nothing
return true; return true;
} }
samples=count; setSampleCount(count);
return true; return true;
} else if (depth==16) { } else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
if (data16!=NULL) { if (data16!=NULL) {
short* oldData16=data16; short* oldData16=data16;
data16=NULL; data16=NULL;
initInternal(16,count); initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
memcpy(data16,&(oldData16[begin]),sizeof(short)*count); memcpy(data16,&(oldData16[begin]),sizeof(short)*count);
delete[] oldData16; delete[] oldData16;
} else { } else {
// do nothing // do nothing
return true; return true;
} }
samples=count; setSampleCount(count);
return true; return true;
} }
return false; return false;
@ -294,11 +353,11 @@ bool DivSample::trim(unsigned int begin, unsigned int end) {
bool DivSample::insert(unsigned int pos, unsigned int length) { bool DivSample::insert(unsigned int pos, unsigned int length) {
unsigned int count=samples+length; unsigned int count=samples+length;
if (depth==8) { if (depth==DIV_SAMPLE_DEPTH_8BIT) {
if (data8!=NULL) { if (data8!=NULL) {
signed char* oldData8=data8; signed char* oldData8=data8;
data8=NULL; data8=NULL;
initInternal(8,count); initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
if (pos>0) { if (pos>0) {
memcpy(data8,oldData8,pos); memcpy(data8,oldData8,pos);
} }
@ -307,15 +366,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
} }
delete[] oldData8; delete[] oldData8;
} else { } else {
initInternal(8,count); initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
} }
samples=count; setSampleCount(count);
return true; return true;
} else if (depth==16) { } else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
if (data16!=NULL) { if (data16!=NULL) {
short* oldData16=data16; short* oldData16=data16;
data16=NULL; data16=NULL;
initInternal(16,count); initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
if (pos>0) { if (pos>0) {
memcpy(data16,oldData16,sizeof(short)*pos); memcpy(data16,oldData16,sizeof(short)*pos);
} }
@ -324,9 +383,9 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
} }
delete[] oldData16; delete[] oldData16;
} else { } else {
initInternal(16,count); initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
} }
samples=count; setSampleCount(count);
return true; return true;
} }
return false; return false;
@ -337,15 +396,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
int finalCount=(double)samples*(r/(double)rate); \ int finalCount=(double)samples*(r/(double)rate); \
signed char* oldData8=data8; \ signed char* oldData8=data8; \
short* oldData16=data16; \ short* oldData16=data16; \
if (depth==16) { \ if (depth==DIV_SAMPLE_DEPTH_16BIT) { \
if (data16!=NULL) { \ if (data16!=NULL) { \
data16=NULL; \ data16=NULL; \
initInternal(16,finalCount); \ initInternal(DIV_SAMPLE_DEPTH_16BIT,finalCount); \
} \ } \
} else if (depth==8) { \ } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \
if (data8!=NULL) { \ if (data8!=NULL) { \
data8=NULL; \ data8=NULL; \
initInternal(8,finalCount); \ initInternal(DIV_SAMPLE_DEPTH_8BIT,finalCount); \
} \ } \
} else { \ } else { \
return false; \ return false; \
@ -353,19 +412,20 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
#define RESAMPLE_END \ #define RESAMPLE_END \
if (loopStart>=0) loopStart=(double)loopStart*(r/(double)rate); \ if (loopStart>=0) loopStart=(double)loopStart*(r/(double)rate); \
if (loopEnd>=0) loopEnd=(double)loopEnd*(r/(double)rate); \
centerRate=(int)((double)centerRate*(r/(double)rate)); \ centerRate=(int)((double)centerRate*(r/(double)rate)); \
rate=r; \ rate=r; \
samples=finalCount; \ samples=finalCount; \
if (depth==16) { \ if (depth==DIV_SAMPLE_DEPTH_16BIT) { \
delete[] oldData16; \ delete[] oldData16; \
} else if (depth==8) { \ } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \
delete[] oldData8; \ delete[] oldData8; \
} }
bool DivSample::resampleNone(double r) { bool DivSample::resampleNone(double r) {
RESAMPLE_BEGIN; RESAMPLE_BEGIN;
if (depth==16) { if (depth==DIV_SAMPLE_DEPTH_16BIT) {
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
unsigned int pos=(unsigned int)((double)i*((double)rate/r)); unsigned int pos=(unsigned int)((double)i*((double)rate/r));
if (pos>=samples) { if (pos>=samples) {
@ -374,7 +434,7 @@ bool DivSample::resampleNone(double r) {
data16[i]=oldData16[pos]; data16[i]=oldData16[pos];
} }
} }
} else if (depth==8) { } else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
unsigned int pos=(unsigned int)((double)i*((double)rate/r)); unsigned int pos=(unsigned int)((double)i*((double)rate/r));
if (pos>=samples) { if (pos>=samples) {
@ -396,7 +456,7 @@ bool DivSample::resampleLinear(double r) {
unsigned int posInt=0; unsigned int posInt=0;
double factor=(double)rate/r; double factor=(double)rate/r;
if (depth==16) { if (depth==DIV_SAMPLE_DEPTH_16BIT) {
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
short s1=(posInt>=samples)?0:oldData16[posInt]; short s1=(posInt>=samples)?0:oldData16[posInt];
short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1]; short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1];
@ -409,7 +469,7 @@ bool DivSample::resampleLinear(double r) {
posInt++; posInt++;
} }
} }
} else if (depth==8) { } else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
short s1=(posInt>=samples)?0:oldData8[posInt]; short s1=(posInt>=samples)?0:oldData8[posInt];
short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1]; short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1];
@ -436,7 +496,7 @@ bool DivSample::resampleCubic(double r) {
double factor=(double)rate/r; double factor=(double)rate/r;
float* cubicTable=DivFilterTables::getCubicTable(); float* cubicTable=DivFilterTables::getCubicTable();
if (depth==16) { if (depth==DIV_SAMPLE_DEPTH_16BIT) {
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
unsigned int n=((unsigned int)(posFrac*1024.0))&1023; unsigned int n=((unsigned int)(posFrac*1024.0))&1023;
float* t=&cubicTable[n<<2]; float* t=&cubicTable[n<<2];
@ -456,7 +516,7 @@ bool DivSample::resampleCubic(double r) {
posInt++; posInt++;
} }
} }
} else if (depth==8) { } else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
unsigned int n=((unsigned int)(posFrac*1024.0))&1023; unsigned int n=((unsigned int)(posFrac*1024.0))&1023;
float* t=&cubicTable[n<<2]; float* t=&cubicTable[n<<2];
@ -493,7 +553,7 @@ bool DivSample::resampleBlep(double r) {
memset(s,0,16*sizeof(float)); memset(s,0,16*sizeof(float));
if (depth==16) { if (depth==DIV_SAMPLE_DEPTH_16BIT) {
memset(data16,0,finalCount*sizeof(short)); memset(data16,0,finalCount*sizeof(short));
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
if (posInt<samples) { if (posInt<samples) {
@ -529,7 +589,7 @@ bool DivSample::resampleBlep(double r) {
} }
} }
} }
} else if (depth==8) { } else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
memset(data8,0,finalCount); memset(data8,0,finalCount);
for (int i=0; i<finalCount; i++) { for (int i=0; i<finalCount; i++) {
if (posInt<samples) { if (posInt<samples) {
@ -582,7 +642,7 @@ bool DivSample::resampleSinc(double r) {
memset(s,0,16*sizeof(float)); memset(s,0,16*sizeof(float));
if (depth==16) { if (depth==DIV_SAMPLE_DEPTH_16BIT) {
for (int i=0; i<finalCount+8; i++) { for (int i=0; i<finalCount+8; i++) {
unsigned int n=((unsigned int)(posFrac*8192.0))&8191; unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
float result=0; float result=0;
@ -607,7 +667,7 @@ bool DivSample::resampleSinc(double r) {
s[15]=(posInt>=samples)?0:oldData16[posInt]; s[15]=(posInt>=samples)?0:oldData16[posInt];
} }
} }
} else if (depth==8) { } else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
for (int i=0; i<finalCount+8; i++) { for (int i=0; i<finalCount+8; i++) {
unsigned int n=((unsigned int)(posFrac*8192.0))&8191; unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
float result=0; float result=0;
@ -639,7 +699,7 @@ bool DivSample::resampleSinc(double r) {
} }
bool DivSample::resample(double r, int filter) { bool DivSample::resample(double r, int filter) {
if (depth!=8 && depth!=16) return false; if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) return false;
switch (filter) { switch (filter) {
case DIV_RESAMPLE_NONE: case DIV_RESAMPLE_NONE:
return resampleNone(r); return resampleNone(r);
@ -669,15 +729,15 @@ bool DivSample::resample(double r, int filter) {
void DivSample::render() { void DivSample::render() {
// step 1: convert to 16-bit if needed // step 1: convert to 16-bit if needed
if (depth!=16) { if (depth!=DIV_SAMPLE_DEPTH_16BIT) {
if (!initInternal(16,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_16BIT,samples)) return;
switch (depth) { switch (depth) {
case 0: // 1-bit case DIV_SAMPLE_DEPTH_1BIT: // 1-bit
for (unsigned int i=0; i<samples; i++) { for (unsigned int i=0; i<samples; i++) {
data16[i]=((data1[i>>3]>>(i&7))&1)?0x7fff:-0x7fff; data16[i]=((data1[i>>3]>>(i&7))&1)?0x7fff:-0x7fff;
} }
break; break;
case 1: { // DPCM case DIV_SAMPLE_DEPTH_1BIT_DPCM: { // DPCM
int accum=0; int accum=0;
for (unsigned int i=0; i<samples; i++) { for (unsigned int i=0; i<samples; i++) {
accum+=((dataDPCM[i>>3]>>(i&7))&1)?1:-1; accum+=((dataDPCM[i>>3]>>(i&7))&1)?1:-1;
@ -687,27 +747,27 @@ void DivSample::render() {
} }
break; break;
} }
case 3: // YMZ ADPCM case DIV_SAMPLE_DEPTH_YMZ_ADPCM: // YMZ ADPCM
ymz_decode(dataZ,data16,samples); ymz_decode(dataZ,data16,samples);
break; break;
case 4: // QSound ADPCM case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: // QSound ADPCM
bs_decode(dataQSoundA,data16,samples); bs_decode(dataQSoundA,data16,samples);
break; break;
case 5: // ADPCM-A case DIV_SAMPLE_DEPTH_ADPCM_A: // ADPCM-A
yma_decode(dataA,data16,samples); yma_decode(dataA,data16,samples);
break; break;
case 6: // ADPCM-B case DIV_SAMPLE_DEPTH_ADPCM_B: // ADPCM-B
ymb_decode(dataB,data16,samples); ymb_decode(dataB,data16,samples);
break; break;
case 8: // 8-bit PCM case DIV_SAMPLE_DEPTH_8BIT: // 8-bit PCM
for (unsigned int i=0; i<samples; i++) { for (unsigned int i=0; i<samples; i++) {
data16[i]=data8[i]<<8; data16[i]=data8[i]<<8;
} }
break; break;
case 9: // BRR case DIV_SAMPLE_DEPTH_BRR: // BRR
// TODO! // TODO!
break; break;
case 10: // VOX case DIV_SAMPLE_DEPTH_VOX: // VOX
oki_decode(dataVOX,data16,samples); oki_decode(dataVOX,data16,samples);
break; break;
default: default:
@ -716,16 +776,16 @@ void DivSample::render() {
} }
// step 2: render to other formats // step 2: render to other formats
if (depth!=0) { // 1-bit if (depth!=DIV_SAMPLE_DEPTH_1BIT) { // 1-bit
if (!initInternal(0,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_1BIT,samples)) return;
for (unsigned int i=0; i<samples; i++) { for (unsigned int i=0; i<samples; i++) {
if (data16[i]>0) { if (data16[i]>0) {
data1[i>>3]|=1<<(i&7); data1[i>>3]|=1<<(i&7);
} }
} }
} }
if (depth!=1) { // DPCM if (depth!=DIV_SAMPLE_DEPTH_1BIT_DPCM) { // DPCM
if (!initInternal(1,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_1BIT_DPCM,samples)) return;
int accum=63; int accum=63;
for (unsigned int i=0; i<samples; i++) { for (unsigned int i=0; i<samples; i++) {
int next=((unsigned short)(data16[i]^0x8000))>>9; int next=((unsigned short)(data16[i]^0x8000))>>9;
@ -739,84 +799,88 @@ void DivSample::render() {
if (accum>127) accum=127; if (accum>127) accum=127;
} }
} }
if (depth!=3) { // YMZ ADPCM if (depth!=DIV_SAMPLE_DEPTH_YMZ_ADPCM) { // YMZ ADPCM
if (!initInternal(3,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_YMZ_ADPCM,samples)) return;
ymz_encode(data16,dataZ,(samples+7)&(~0x7)); ymz_encode(data16,dataZ,(samples+7)&(~0x7));
} }
if (depth!=4) { // QSound ADPCM if (depth!=DIV_SAMPLE_DEPTH_QSOUND_ADPCM) { // QSound ADPCM
if (!initInternal(4,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_QSOUND_ADPCM,samples)) return;
bs_encode(data16,dataQSoundA,samples); bs_encode(data16,dataQSoundA,samples);
} }
// TODO: pad to 256. // TODO: pad to 256.
if (depth!=5) { // ADPCM-A if (depth!=DIV_SAMPLE_DEPTH_ADPCM_A) { // ADPCM-A
if (!initInternal(5,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_A,samples)) return;
yma_encode(data16,dataA,(samples+511)&(~0x1ff)); yma_encode(data16,dataA,(samples+511)&(~0x1ff));
} }
if (depth!=6) { // ADPCM-B if (depth!=DIV_SAMPLE_DEPTH_ADPCM_B) { // ADPCM-B
if (!initInternal(6,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_B,samples)) return;
ymb_encode(data16,dataB,(samples+511)&(~0x1ff)); ymb_encode(data16,dataB,(samples+511)&(~0x1ff));
} }
if (depth!=8) { // 8-bit PCM if (depth!=DIV_SAMPLE_DEPTH_8BIT) { // 8-bit PCM
if (!initInternal(8,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return;
for (unsigned int i=0; i<samples; i++) { for (unsigned int i=0; i<samples; i++) {
data8[i]=data16[i]>>8; data8[i]=data16[i]>>8;
} }
} }
// TODO: BRR! // TODO: BRR!
if (depth!=10) { // VOX if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX
if (!initInternal(10,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
oki_encode(data16,dataVOX,samples); oki_encode(data16,dataVOX,samples);
} }
} }
void* DivSample::getCurBuf() { void* DivSample::getCurBuf() {
switch (depth) { switch (depth) {
case 0: case DIV_SAMPLE_DEPTH_1BIT:
return data1; return data1;
case 1: case DIV_SAMPLE_DEPTH_1BIT_DPCM:
return dataDPCM; return dataDPCM;
case 3: case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
return dataZ; return dataZ;
case 4: case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
return dataQSoundA; return dataQSoundA;
case 5: case DIV_SAMPLE_DEPTH_ADPCM_A:
return dataA; return dataA;
case 6: case DIV_SAMPLE_DEPTH_ADPCM_B:
return dataB; return dataB;
case 8: case DIV_SAMPLE_DEPTH_8BIT:
return data8; return data8;
case 9: case DIV_SAMPLE_DEPTH_BRR:
return dataBRR; return dataBRR;
case 10: case DIV_SAMPLE_DEPTH_VOX:
return dataVOX; return dataVOX;
case 16: case DIV_SAMPLE_DEPTH_16BIT:
return data16; return data16;
default:
return NULL;
} }
return NULL; return NULL;
} }
unsigned int DivSample::getCurBufLen() { unsigned int DivSample::getCurBufLen() {
switch (depth) { switch (depth) {
case 0: case DIV_SAMPLE_DEPTH_1BIT:
return length1; return length1;
case 1: case DIV_SAMPLE_DEPTH_1BIT_DPCM:
return lengthDPCM; return lengthDPCM;
case 3: case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
return lengthZ; return lengthZ;
case 4: case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
return lengthQSoundA; return lengthQSoundA;
case 5: case DIV_SAMPLE_DEPTH_ADPCM_A:
return lengthA; return lengthA;
case 6: case DIV_SAMPLE_DEPTH_ADPCM_B:
return lengthB; return lengthB;
case 8: case DIV_SAMPLE_DEPTH_8BIT:
return length8; return length8;
case 9: case DIV_SAMPLE_DEPTH_BRR:
return lengthBRR; return lengthBRR;
case 10: case DIV_SAMPLE_DEPTH_VOX:
return lengthVOX; return lengthVOX;
case 16: case DIV_SAMPLE_DEPTH_16BIT:
return length16; return length16;
default:
return 0;
} }
return 0; return 0;
} }
@ -831,9 +895,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
duplicate=new unsigned char[getCurBufLen()]; duplicate=new unsigned char[getCurBufLen()];
memcpy(duplicate,getCurBuf(),getCurBufLen()); memcpy(duplicate,getCurBuf(),getCurBufLen());
} }
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart); h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd);
} else { } else {
h=new DivSampleHistory(depth,rate,centerRate,loopStart); h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd);
} }
if (!doNotPush) { if (!doNotPush) {
while (!redoHist.empty()) { while (!redoHist.empty()) {
@ -863,7 +927,8 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
} \ } \
rate=h->rate; \ rate=h->rate; \
centerRate=h->centerRate; \ centerRate=h->centerRate; \
loopStart=h->loopStart; loopStart=h->loopStart; \
loopEnd=h->loopEnd;
int DivSample::undo() { int DivSample::undo() {

View File

@ -17,9 +17,28 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef _SAMPLE_H
#define _SAMPLE_H
#pragma once
#include "../ta-utils.h" #include "../ta-utils.h"
#include <deque> #include <deque>
enum DivSampleDepth: unsigned char {
DIV_SAMPLE_DEPTH_1BIT=0,
DIV_SAMPLE_DEPTH_1BIT_DPCM=1,
DIV_SAMPLE_DEPTH_YMZ_ADPCM=3,
DIV_SAMPLE_DEPTH_QSOUND_ADPCM=4,
DIV_SAMPLE_DEPTH_ADPCM_A=5,
DIV_SAMPLE_DEPTH_ADPCM_B=6,
DIV_SAMPLE_DEPTH_8BIT=8,
DIV_SAMPLE_DEPTH_BRR=9,
DIV_SAMPLE_DEPTH_VOX=10,
DIV_SAMPLE_DEPTH_16BIT=16,
DIV_SAMPLE_DEPTH_MAX // boundary for sample depth
};
enum DivResampleFilters { enum DivResampleFilters {
DIV_RESAMPLE_NONE=0, DIV_RESAMPLE_NONE=0,
DIV_RESAMPLE_LINEAR, DIV_RESAMPLE_LINEAR,
@ -32,10 +51,10 @@ enum DivResampleFilters {
struct DivSampleHistory { struct DivSampleHistory {
unsigned char* data; unsigned char* data;
unsigned int length, samples; unsigned int length, samples;
unsigned char depth; DivSampleDepth depth;
int rate, centerRate, loopStart; int rate, centerRate, loopStart, loopEnd;
bool hasSample; bool hasSample;
DivSampleHistory(void* d, unsigned int l, unsigned int s, unsigned char de, int r, int cr, int ls): DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le):
data((unsigned char*)d), data((unsigned char*)d),
length(l), length(l),
samples(s), samples(s),
@ -43,8 +62,9 @@ struct DivSampleHistory {
rate(r), rate(r),
centerRate(cr), centerRate(cr),
loopStart(ls), loopStart(ls),
loopEnd(le),
hasSample(true) {} hasSample(true) {}
DivSampleHistory(unsigned char de, int r, int cr, int ls): DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le):
data(NULL), data(NULL),
length(0), length(0),
samples(0), samples(0),
@ -52,13 +72,14 @@ struct DivSampleHistory {
rate(r), rate(r),
centerRate(cr), centerRate(cr),
loopStart(ls), loopStart(ls),
loopEnd(le),
hasSample(false) {} hasSample(false) {}
~DivSampleHistory(); ~DivSampleHistory();
}; };
struct DivSample { struct DivSample {
String name; String name;
int rate, centerRate, loopStart, loopOffP; int rate, centerRate, loopStart, loopEnd, loopOffP;
// valid values are: // valid values are:
// - 0: ZX Spectrum overlay drum (1-bit) // - 0: ZX Spectrum overlay drum (1-bit)
// - 1: 1-bit NES DPCM (1-bit) // - 1: 1-bit NES DPCM (1-bit)
@ -70,7 +91,7 @@ struct DivSample {
// - 9: BRR (SNES) // - 9: BRR (SNES)
// - 10: VOX ADPCM // - 10: VOX ADPCM
// - 16: 16-bit PCM // - 16: 16-bit PCM
unsigned char depth; DivSampleDepth depth;
// these are the new data structures. // these are the new data structures.
signed char* data8; // 8 signed char* data8; // 8
@ -93,6 +114,23 @@ struct DivSample {
std::deque<DivSampleHistory*> undoHist; std::deque<DivSampleHistory*> undoHist;
std::deque<DivSampleHistory*> redoHist; std::deque<DivSampleHistory*> redoHist;
/**
* check if sample is loopable.
* @return whether it is loopable.
*/
bool isLoopable();
/**
* get sample end position
* @return the samples end position.
*/
unsigned int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
/**
* @warning DO NOT USE - internal functions
*/
void setSampleCount(unsigned int count);
/** /**
* @warning DO NOT USE - internal functions * @warning DO NOT USE - internal functions
*/ */
@ -116,7 +154,7 @@ struct DivSample {
* @param count number of samples. * @param count number of samples.
* @return whether it was successful. * @return whether it was successful.
*/ */
bool initInternal(unsigned char d, int count); bool initInternal(DivSampleDepth d, int count);
/** /**
* initialize sample data. make sure you have set `depth` before doing so. * initialize sample data. make sure you have set `depth` before doing so.
@ -212,8 +250,9 @@ struct DivSample {
rate(32000), rate(32000),
centerRate(8363), centerRate(8363),
loopStart(-1), loopStart(-1),
loopEnd(-1),
loopOffP(0), loopOffP(0),
depth(16), depth(DIV_SAMPLE_DEPTH_16BIT),
data8(NULL), data8(NULL),
data16(NULL), data16(NULL),
data1(NULL), data1(NULL),
@ -253,3 +292,5 @@ struct DivSample {
samples(0) {} samples(0) {}
~DivSample(); ~DivSample();
}; };
#endif

View File

@ -512,7 +512,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(streamID); w->writeC(streamID);
w->writeS(write.val); // sample number w->writeS(write.val); // sample number
w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags
if (sample->loopStart>0 && !sampleDir[streamID]) { if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8; loopTimer[streamID]=sample->length8;
loopSample[streamID]=write.val; loopSample[streamID]=write.val;
} }
@ -1549,7 +1549,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
size_t memPos=0; size_t memPos=0;
for (int i=0; i<song.sampleLen; i++) { for (int i=0; i<song.sampleLen; i++) {
DivSample* sample=song.sample[i]; DivSample* sample=song.sample[i];
unsigned int alignedSize=(sample->length8+0xff)&(~0xff); unsigned int alignedSize=(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff);
if (alignedSize>65536) alignedSize=65536; if (alignedSize>65536) alignedSize=65536;
if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) { if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) {
memPos=(memPos+0xffff)&0xff0000; memPos=(memPos+0xffff)&0xff0000;
@ -1559,8 +1559,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
sample->offSegaPCM=memPos; sample->offSegaPCM=memPos;
unsigned int readPos=0; unsigned int readPos=0;
for (unsigned int j=0; j<alignedSize; j++) { for (unsigned int j=0; j<alignedSize; j++) {
if (readPos>=sample->length8) { if (readPos>=sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
if (sample->loopStart>=0 && sample->loopStart<(int)sample->length8) { if (sample->isLoopable()) {
readPos=sample->loopStart; readPos=sample->loopStart;
pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80); pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
} else { } else {
@ -1663,7 +1663,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen); memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen);
for (int i=0; i<song.sampleLen; i++) { for (int i=0; i<song.sampleLen; i++) {
DivSample* s=song.sample[i]; DivSample* s=song.sample[i];
if (s->depth==16) { if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
unsigned int pos=s->offYMZ280B; unsigned int pos=s->offYMZ280B;
for (unsigned int j=0; j<s->samples; j++) { for (unsigned int j=0; j<s->samples; j++) {
unsigned char lo=sampleMem[pos+j*2]; unsigned char lo=sampleMem[pos+j*2];
@ -1871,12 +1871,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
if (loopSample[nextToTouch]<song.sampleLen) { if (loopSample[nextToTouch]<song.sampleLen) {
DivSample* sample=song.sample[loopSample[nextToTouch]]; DivSample* sample=song.sample[loopSample[nextToTouch]];
// insert loop // insert loop
if (sample->loopStart<(int)sample->length8) { if (sample->loopStart<(int)sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
w->writeC(0x93); w->writeC(0x93);
w->writeC(nextToTouch); w->writeC(nextToTouch);
w->writeI(sample->off8+sample->loopStart); w->writeI(sample->off8+sample->loopStart);
w->writeC(0x81); w->writeC(0x81);
w->writeI(sample->length8-sample->loopStart); w->writeI(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->loopStart);
} }
} }
loopSample[nextToTouch]=-1; loopSample[nextToTouch]=-1;

View File

@ -18,6 +18,7 @@
*/ */
#include "gui.h" #include "gui.h"
#include "guiConst.h"
#include "debug.h" #include "debug.h"
#include "IconsFontAwesome4.h" #include "IconsFontAwesome4.h"
#include <SDL_timer.h> #include <SDL_timer.h>
@ -154,12 +155,19 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("rate: %d",sample->rate); ImGui::Text("rate: %d",sample->rate);
ImGui::Text("centerRate: %d",sample->centerRate); ImGui::Text("centerRate: %d",sample->centerRate);
ImGui::Text("loopStart: %d",sample->loopStart); ImGui::Text("loopStart: %d",sample->loopStart);
ImGui::Text("loopEnd: %d", sample->loopEnd);
ImGui::Text("loopOffP: %d",sample->loopOffP); ImGui::Text("loopOffP: %d",sample->loopOffP);
ImGui::Text("depth: %d",sample->depth); if (sampleDepths[sample->depth]!=NULL) {
ImGui::Text("depth: %d (%s)",(unsigned char)sample->depth,sampleDepths[sample->depth]);
} else {
ImGui::Text("depth: %d (<NULL!>)",(unsigned char)sample->depth);
}
ImGui::Text("length8: %d",sample->length8); ImGui::Text("length8: %d",sample->length8);
ImGui::Text("length16: %d",sample->length16); ImGui::Text("length16: %d",sample->length16);
ImGui::Text("length1: %d",sample->length1); ImGui::Text("length1: %d",sample->length1);
ImGui::Text("lengthDPCM: %d",sample->lengthDPCM); ImGui::Text("lengthDPCM: %d",sample->lengthDPCM);
ImGui::Text("lengthZ: %d",sample->lengthZ);
ImGui::Text("lengthQSoundA: %d",sample->lengthQSoundA); ImGui::Text("lengthQSoundA: %d",sample->lengthQSoundA);
ImGui::Text("lengthA: %d",sample->lengthA); ImGui::Text("lengthA: %d",sample->lengthA);
ImGui::Text("lengthB: %d",sample->lengthB); ImGui::Text("lengthB: %d",sample->lengthB);
@ -170,6 +178,7 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("off16: %x",sample->off16); ImGui::Text("off16: %x",sample->off16);
ImGui::Text("off1: %x",sample->off1); ImGui::Text("off1: %x",sample->off1);
ImGui::Text("offDPCM: %x",sample->offDPCM); ImGui::Text("offDPCM: %x",sample->offDPCM);
ImGui::Text("offZ: %x",sample->offZ);
ImGui::Text("offQSoundA: %x",sample->offQSoundA); ImGui::Text("offQSoundA: %x",sample->offQSoundA);
ImGui::Text("offA: %x",sample->offA); ImGui::Text("offA: %x",sample->offA);
ImGui::Text("offB: %x",sample->offB); ImGui::Text("offB: %x",sample->offB);
@ -179,6 +188,8 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("offQSound: %x",sample->offQSound); ImGui::Text("offQSound: %x",sample->offQSound);
ImGui::Text("offX1_010: %x",sample->offX1_010); ImGui::Text("offX1_010: %x",sample->offX1_010);
ImGui::Text("offSU: %x",sample->offSU); 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::Text("samples: %d",sample->samples);
ImGui::TreePop(); ImGui::TreePop();

View File

@ -709,6 +709,7 @@ void FurnaceGUI::doAction(int what) {
sample->centerRate=prevSample->centerRate; sample->centerRate=prevSample->centerRate;
sample->name=prevSample->name; sample->name=prevSample->name;
sample->loopStart=prevSample->loopStart; sample->loopStart=prevSample->loopStart;
sample->loopEnd=prevSample->loopEnd;
sample->depth=prevSample->depth; sample->depth=prevSample->depth;
if (sample->init(prevSample->samples)) { if (sample->init(prevSample->samples)) {
if (prevSample->getCurBuf()!=NULL) { if (prevSample->getCurBuf()!=NULL) {
@ -838,7 +839,7 @@ void FurnaceGUI::doAction(int what) {
if (!sample->insert(pos,sampleClipboardLen)) { if (!sample->insert(pos,sampleClipboardLen)) {
showError("couldn't paste! make sure your sample is 8 or 16-bit."); showError("couldn't paste! make sure your sample is 8 or 16-bit.");
} else { } else {
if (sample->depth==8) { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (size_t i=0; i<sampleClipboardLen; i++) { for (size_t i=0; i<sampleClipboardLen; i++) {
sample->data8[pos+i]=sampleClipboard[i]>>8; sample->data8[pos+i]=sampleClipboard[i]>>8;
} }
@ -864,7 +865,7 @@ void FurnaceGUI::doAction(int what) {
if (pos<0) pos=0; if (pos<0) pos=0;
e->lockEngine([this,sample,pos]() { e->lockEngine([this,sample,pos]() {
if (sample->depth==8) { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (size_t i=0; i<sampleClipboardLen; i++) { for (size_t i=0; i<sampleClipboardLen; i++) {
if (pos+i>=sample->samples) break; if (pos+i>=sample->samples) break;
sample->data8[pos+i]=sampleClipboard[i]>>8; sample->data8[pos+i]=sampleClipboard[i]>>8;
@ -894,7 +895,7 @@ void FurnaceGUI::doAction(int what) {
if (pos<0) pos=0; if (pos<0) pos=0;
e->lockEngine([this,sample,pos]() { e->lockEngine([this,sample,pos]() {
if (sample->depth==8) { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (size_t i=0; i<sampleClipboardLen; i++) { for (size_t i=0; i<sampleClipboardLen; i++) {
if (pos+i>=sample->samples) break; if (pos+i>=sample->samples) break;
int val=sample->data8[pos+i]+(sampleClipboard[i]>>8); int val=sample->data8[pos+i]+(sampleClipboard[i]>>8);
@ -948,7 +949,7 @@ void FurnaceGUI::doAction(int what) {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
float maxVal=0.0f; float maxVal=0.0f;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=fabs((float)sample->data16[i]/32767.0f); float val=fabs((float)sample->data16[i]/32767.0f);
if (val>maxVal) maxVal=val; if (val>maxVal) maxVal=val;
@ -963,7 +964,7 @@ void FurnaceGUI::doAction(int what) {
sample->data16[i]=val; sample->data16[i]=val;
} }
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=fabs((float)sample->data8[i]/127.0f); float val=fabs((float)sample->data8[i]/127.0f);
if (val>maxVal) maxVal=val; if (val>maxVal) maxVal=val;
@ -994,14 +995,14 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample]() { e->lockEngine([this,sample]() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data16[i]*float(i-start)/float(end-start); float val=sample->data16[i]*float(i-start)/float(end-start);
if (val<-32768) val=-32768; if (val<-32768) val=-32768;
if (val>32767) val=32767; if (val>32767) val=32767;
sample->data16[i]=val; sample->data16[i]=val;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data8[i]*float(i-start)/float(end-start); float val=sample->data8[i]*float(i-start)/float(end-start);
if (val<-128) val=-128; if (val<-128) val=-128;
@ -1024,14 +1025,14 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample]() { e->lockEngine([this,sample]() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data16[i]*float(end-i)/float(end-start); float val=sample->data16[i]*float(end-i)/float(end-start);
if (val<-32768) val=-32768; if (val<-32768) val=-32768;
if (val>32767) val=32767; if (val>32767) val=32767;
sample->data16[i]=val; sample->data16[i]=val;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data8[i]*float(end-i)/float(end-start); float val=sample->data8[i]*float(end-i)/float(end-start);
if (val<-128) val=-128; if (val<-128) val=-128;
@ -1058,11 +1059,11 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample]() { e->lockEngine([this,sample]() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
sample->data16[i]=0; sample->data16[i]=0;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
sample->data8[i]=0; sample->data8[i]=0;
} }
@ -1116,7 +1117,7 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample]() { e->lockEngine([this,sample]() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
unsigned int ri=end-i-1+start; unsigned int ri=end-i-1+start;
if (ri<=i) break; if (ri<=i) break;
@ -1124,7 +1125,7 @@ void FurnaceGUI::doAction(int what) {
sample->data16[ri]^=sample->data16[i]; sample->data16[ri]^=sample->data16[i];
sample->data16[i]^=sample->data16[ri]; sample->data16[i]^=sample->data16[ri];
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
unsigned int ri=end-i-1+start; unsigned int ri=end-i-1+start;
if (ri<=i) break; if (ri<=i) break;
@ -1148,12 +1149,12 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample]() { e->lockEngine([this,sample]() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
sample->data16[i]=-sample->data16[i]; sample->data16[i]=-sample->data16[i];
if (sample->data16[i]==-32768) sample->data16[i]=32767; if (sample->data16[i]==-32768) sample->data16[i]=32767;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
sample->data8[i]=-sample->data8[i]; sample->data8[i]=-sample->data8[i];
if (sample->data16[i]==-128) sample->data16[i]=127; if (sample->data16[i]==-128) sample->data16[i]=127;
@ -1174,11 +1175,11 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample]() { e->lockEngine([this,sample]() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
sample->data16[i]^=0x8000; sample->data16[i]^=0x8000;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
sample->data8[i]^=0x80; sample->data8[i]^=0x80;
} }
@ -1261,8 +1262,8 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample]() { e->lockEngine([this,sample]() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
sample->trim(0,end);
sample->loopStart=start; sample->loopStart=start;
sample->loopEnd=end;
updateSampleTex=true; updateSampleTex=true;
e->renderSamples(); e->renderSamples();

View File

@ -116,7 +116,7 @@ const char* insTypes[DIV_INS_MAX+1]={
NULL NULL
}; };
const char* sampleDepths[17]={ const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
"1-bit PCM", "1-bit PCM",
"1-bit DPCM", "1-bit DPCM",
NULL, NULL,

View File

@ -40,7 +40,7 @@ extern const char* noteNames[180];
extern const char* noteNamesG[180]; extern const char* noteNamesG[180];
extern const char* pitchLabel[11]; extern const char* pitchLabel[11];
extern const char* insTypes[]; extern const char* insTypes[];
extern const char* sampleDepths[17]; extern const char* sampleDepths[];
extern const char* resampleStrats[]; extern const char* resampleStrats[];
extern const int availableSystems[]; extern const int availableSystems[];
extern const FurnaceGUIActionDef guiActions[]; extern const FurnaceGUIActionDef guiActions[];

View File

@ -41,7 +41,7 @@ void FurnaceGUI::drawSampleEdit() {
} else { } else {
DivSample* sample=e->song.sample[curSample]; DivSample* sample=e->song.sample[curSample];
String sampleType="Invalid"; String sampleType="Invalid";
if (sample->depth<17) { if (sample->depth<DIV_SAMPLE_DEPTH_MAX) {
if (sampleDepths[sample->depth]!=NULL) { if (sampleDepths[sample->depth]!=NULL) {
sampleType=sampleDepths[sample->depth]; sampleType=sampleDepths[sample->depth];
} }
@ -61,11 +61,11 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) { if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) {
for (int i=0; i<17; i++) { for (int i=0; i<DIV_SAMPLE_DEPTH_MAX; i++) {
if (sampleDepths[i]==NULL) continue; if (sampleDepths[i]==NULL) continue;
if (ImGui::Selectable(sampleDepths[i])) { if (ImGui::Selectable(sampleDepths[i])) {
sample->prepareUndo(true); sample->prepareUndo(true);
sample->depth=i; sample->depth=(DivSampleDepth)i;
e->renderSamplesP(); e->renderSamplesP();
updateSampleTex=true; updateSampleTex=true;
MARK_MODIFIED; MARK_MODIFIED;
@ -93,22 +93,43 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::TableNextColumn(); ImGui::TableNextColumn();
bool doLoop=(sample->loopStart>=0); bool doLoop=(sample->isLoopable());
if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED
if (doLoop) { if (doLoop) {
sample->loopStart=0; sample->loopStart=0;
sample->loopEnd=sample->samples;
} else { } else {
sample->loopStart=-1; sample->loopStart=-1;
sample->loopEnd=sample->samples;
} }
updateSampleTex=true; updateSampleTex=true;
} }
if (doLoop) { if (doLoop) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Loop Start");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED if (ImGui::InputInt("##LoopStartPosition",&sample->loopStart,1,10)) { MARK_MODIFIED
if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { if (sample->loopStart<0) {
sample->loopStart=0; sample->loopStart=0;
} }
if (sample->loopStart>sample->loopEnd) {
sample->loopStart=sample->loopEnd;
}
updateSampleTex=true;
}
ImGui::TableNextColumn();
ImGui::Text("Loop End");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##LoopEndPosition",&sample->loopEnd,1,10)) { MARK_MODIFIED
if (sample->loopEnd<sample->loopStart) {
sample->loopEnd=sample->loopStart;
}
if (sample->loopEnd>=(int)sample->samples) {
sample->loopEnd=sample->samples;
}
updateSampleTex=true; updateSampleTex=true;
} }
} }
@ -123,7 +144,7 @@ void FurnaceGUI::drawSampleEdit() {
*/ */
ImGui::Separator(); ImGui::Separator();
ImGui::BeginDisabled(sample->depth!=8 && sample->depth!=16); ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode));
if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) {
@ -275,14 +296,14 @@ void FurnaceGUI::drawSampleEdit() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
float vol=amplifyVol/100.0f; float vol=amplifyVol/100.0f;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data16[i]*vol; float val=sample->data16[i]*vol;
if (val<-32768) val=-32768; if (val<-32768) val=-32768;
if (val>32767) val=32767; if (val>32767) val=32767;
sample->data16[i]=val; sample->data16[i]=val;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data8[i]*vol; float val=sample->data8[i]*vol;
if (val<-128) val=-128; if (val<-128) val=-128;
@ -466,7 +487,7 @@ void FurnaceGUI::drawSampleEdit() {
double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0; double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power); double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
double cut=sin((freq/double(sample->rate))*M_PI); double cut=sin((freq/double(sample->rate))*M_PI);
@ -482,7 +503,7 @@ void FurnaceGUI::drawSampleEdit() {
if (val>32767) val=32767; if (val>32767) val=32767;
sample->data16[i]=val; sample->data16[i]=val;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power); double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
double cut=sin((freq/double(sample->rate))*M_PI); double cut=sin((freq/double(sample->rate))*M_PI);
@ -574,11 +595,11 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) { if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) {
for (int i=0; i<17; i++) { for (int i=0; i<DIV_SAMPLE_DEPTH_MAX; i++) {
if (sampleDepths[i]==NULL) continue; if (sampleDepths[i]==NULL) continue;
if (ImGui::Selectable(sampleDepths[i])) { if (ImGui::Selectable(sampleDepths[i])) {
sample->prepareUndo(true); sample->prepareUndo(true);
sample->depth=i; sample->depth=(DivSampleDepth)i;
e->renderSamplesP(); e->renderSamplesP();
updateSampleTex=true; updateSampleTex=true;
MARK_MODIFIED; MARK_MODIFIED;
@ -607,22 +628,43 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::TableNextColumn(); ImGui::TableNextColumn();
bool doLoop=(sample->loopStart>=0); bool doLoop=(sample->isLoopable());
if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED
if (doLoop) { if (doLoop) {
sample->loopStart=0; sample->loopStart=0;
sample->loopEnd=sample->samples;
} else { } else {
sample->loopStart=-1; sample->loopStart=-1;
sample->loopEnd=sample->samples;
} }
updateSampleTex=true; updateSampleTex=true;
} }
if (doLoop) { if (doLoop) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Loop Start");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED if (ImGui::InputInt("##LoopStartPosition",&sample->loopStart,1,10)) { MARK_MODIFIED
if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { if (sample->loopStart<0) {
sample->loopStart=0; sample->loopStart=0;
} }
if (sample->loopStart>sample->loopEnd) {
sample->loopStart=sample->loopEnd;
}
updateSampleTex=true;
}
ImGui::TableNextColumn();
ImGui::Text("Loop End");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##LoopEndPosition",&sample->loopEnd,1,10)) { MARK_MODIFIED
if (sample->loopEnd<sample->loopStart) {
sample->loopEnd=sample->loopStart;
}
if (sample->loopEnd>=(int)sample->samples) {
sample->loopEnd=sample->samples;
}
updateSampleTex=true; updateSampleTex=true;
} }
} }
@ -637,7 +679,7 @@ void FurnaceGUI::drawSampleEdit() {
*/ */
ImGui::Separator(); ImGui::Separator();
ImGui::BeginDisabled(sample->depth!=8 && sample->depth!=16); ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode));
if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) {
@ -820,7 +862,7 @@ void FurnaceGUI::drawSampleEdit() {
double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0; double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power); double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
double cut=sin((freq/double(sample->rate))*M_PI); double cut=sin((freq/double(sample->rate))*M_PI);
@ -836,7 +878,7 @@ void FurnaceGUI::drawSampleEdit() {
if (val>32767) val=32767; if (val>32767) val=32767;
sample->data16[i]=val; sample->data16[i]=val;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power); double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
double cut=sin((freq/double(sample->rate))*M_PI); double cut=sin((freq/double(sample->rate))*M_PI);
@ -890,14 +932,14 @@ void FurnaceGUI::drawSampleEdit() {
SAMPLE_OP_BEGIN; SAMPLE_OP_BEGIN;
float vol=amplifyVol/100.0f; float vol=amplifyVol/100.0f;
if (sample->depth==16) { if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data16[i]*vol; float val=sample->data16[i]*vol;
if (val<-32768) val=-32768; if (val<-32768) val=-32768;
if (val>32767) val=32767; if (val>32767) val=32767;
sample->data16[i]=val; sample->data16[i]=val;
} }
} else if (sample->depth==8) { } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) { for (unsigned int i=start; i<end; i++) {
float val=sample->data8[i]*vol; float val=sample->data8[i]*vol;
if (val<-128) val=-128; if (val<-128) val=-128;
@ -1138,7 +1180,7 @@ void FurnaceGUI::drawSampleEdit() {
for (int i=0; i<availY; i++) { for (int i=0; i<availY; i++) {
for (int j=0; j<availX; j++) { for (int j=0; j<availX; j++) {
int scaledPos=samplePos+(j*sampleZoom); int scaledPos=samplePos+(j*sampleZoom);
if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples && scaledPos>=sample->loopStart) { if (sample->isLoopable() && (scaledPos>=sample->loopStart && scaledPos<=sample->loopEnd)) {
data[i*availX+j]=bgColorLoop; data[i*availX+j]=bgColorLoop;
} else { } else {
data[i*availX+j]=bgColor; data[i*availX+j]=bgColor;
@ -1158,7 +1200,7 @@ void FurnaceGUI::drawSampleEdit() {
if (xCoarse>=sample->samples) break; if (xCoarse>=sample->samples) break;
int y1, y2; int y1, y2;
int totalAdvance=0; int totalAdvance=0;
if (sample->depth==8) { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
y1=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; y1=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256;
} else { } else {
y1=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; y1=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536;
@ -1171,7 +1213,7 @@ void FurnaceGUI::drawSampleEdit() {
totalAdvance+=xAdvanceCoarse; totalAdvance+=xAdvanceCoarse;
if (xCoarse>=sample->samples) break; if (xCoarse>=sample->samples) break;
do { do {
if (sample->depth==8) { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
y2=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; y2=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256;
} else { } else {
y2=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; y2=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536;
@ -1209,11 +1251,11 @@ void FurnaceGUI::drawSampleEdit() {
sampleSelStart=0; sampleSelStart=0;
sampleSelEnd=sample->samples; sampleSelEnd=sample->samples;
} else { } else {
if (sample->samples>0 && (sample->depth==16 || sample->depth==8)) { if (sample->samples>0 && (sample->depth==DIV_SAMPLE_DEPTH_16BIT || sample->depth==DIV_SAMPLE_DEPTH_8BIT)) {
sampleDragStart=rectMin; sampleDragStart=rectMin;
sampleDragAreaSize=rectSize; sampleDragAreaSize=rectSize;
sampleDrag16=(sample->depth==16); sampleDrag16=(sample->depth==DIV_SAMPLE_DEPTH_16BIT);
sampleDragTarget=(sample->depth==16)?((void*)sample->data16):((void*)sample->data8); sampleDragTarget=(sample->depth==DIV_SAMPLE_DEPTH_16BIT)?((void*)sample->data16):((void*)sample->data8);
sampleDragLen=sample->samples; sampleDragLen=sample->samples;
sampleDragActive=true; sampleDragActive=true;
sampleSelStart=-1; sampleSelStart=-1;
@ -1312,7 +1354,7 @@ void FurnaceGUI::drawSampleEdit() {
posX=samplePos+pos.x*sampleZoom; posX=samplePos+pos.x*sampleZoom;
if (posX>(int)sample->samples) posX=-1; if (posX>(int)sample->samples) posX=-1;
} }
posY=(0.5-pos.y/rectSize.y)*((sample->depth==8)?255:32767); posY=(0.5-pos.y/rectSize.y)*((sample->depth==DIV_SAMPLE_DEPTH_8BIT)?255:32767);
if (posX>=0) { if (posX>=0) {
statusBar+=fmt::sprintf(" | (%d, %d)",posX,posY); statusBar+=fmt::sprintf(" | (%d, %d)",posX,posY);
} }
@ -1362,7 +1404,7 @@ void FurnaceGUI::drawSampleEdit() {
} }
} }
if (sample->depth!=8 && sample->depth!=16) { if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
statusBar="Non-8/16-bit samples cannot be edited without prior conversion."; statusBar="Non-8/16-bit samples cannot be edited without prior conversion.";
} }