Implement sample loop end position, enum-ise sample depth (#557)
TODO: new sample format
This commit is contained in:
parent
a137eefd20
commit
5127d5ef18
|
@ -2226,7 +2226,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
|
||||
sample->rate=33144;
|
||||
sample->centerRate=33144;
|
||||
sample->depth=1;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM;
|
||||
sample->init(len*8);
|
||||
|
||||
if (fread(sample->dataDPCM,1,len,f)==0) {
|
||||
|
@ -2301,9 +2301,9 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
|
||||
int index=0;
|
||||
if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) {
|
||||
sample->depth=8;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_8BIT;
|
||||
} else {
|
||||
sample->depth=16;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
}
|
||||
sample->init(si.frames);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -799,17 +799,17 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
sample->rate=ymuSampleRate*400;
|
||||
}
|
||||
if (ds.version>0x15) {
|
||||
sample->depth=reader.readC();
|
||||
if (sample->depth!=8 && sample->depth!=16) {
|
||||
sample->depth=(DivSampleDepth)reader.readC();
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
logW("%d: sample depth is wrong! (%d)",i,sample->depth);
|
||||
sample->depth=16;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
}
|
||||
} else {
|
||||
if (ds.version>0x08) {
|
||||
sample->depth=16;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
} else {
|
||||
// it appears samples were stored as ADPCM back then
|
||||
sample->depth=3;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_YMZ_ADPCM;
|
||||
}
|
||||
}
|
||||
if (length>0) {
|
||||
|
@ -838,7 +838,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
if (k>=sample->samples) {
|
||||
break;
|
||||
}
|
||||
if (sample->depth==8) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
float next=(float)(data[(unsigned int)j]-0x80)*mult;
|
||||
sample->data8[k++]=fmin(fmax(next,-128),127);
|
||||
} else {
|
||||
|
@ -1631,7 +1631,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
logD("reading sample %d at %x...",i,samplePtr[i]);
|
||||
|
||||
sample->name=reader.readString();
|
||||
sample->samples=reader.readI();
|
||||
sample->samples=sample->loopEnd=reader.readI();
|
||||
sample->rate=reader.readI();
|
||||
if (ds.version<58) {
|
||||
vol=reader.readS();
|
||||
|
@ -1639,7 +1639,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
sample->depth=reader.readC();
|
||||
sample->depth=(DivSampleDepth)reader.readC();
|
||||
|
||||
// reserved
|
||||
reader.readC();
|
||||
|
@ -1657,6 +1657,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
reader.readI();
|
||||
}
|
||||
|
||||
/*
|
||||
if (ds.version>=100) {
|
||||
sample->loopEnd=reader.readI();
|
||||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
*/
|
||||
if (ds.version>=58) { // modern sample
|
||||
sample->init(sample->samples);
|
||||
reader.read(sample->getCurBuf(),sample->getCurBufLen());
|
||||
|
@ -1670,9 +1677,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
// 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);
|
||||
sample->depth=16;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
}
|
||||
sample->samples=(double)sample->samples/samplePitches[pitch];
|
||||
sample->init(sample->samples);
|
||||
|
@ -1683,7 +1690,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (k>=sample->samples) {
|
||||
break;
|
||||
}
|
||||
if (sample->depth==8) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
float next=(float)(data[(unsigned int)j]-0x80)*mult;
|
||||
sample->data8[k++]=fmin(fmax(next,-128),127);
|
||||
} else {
|
||||
|
@ -1877,7 +1884,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
logD("reading samples... (%d)",insCount);
|
||||
for (int i=0; i<insCount; i++) {
|
||||
DivSample* sample=new DivSample;
|
||||
sample->depth=8;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_8BIT;
|
||||
sample->name=reader.readString(22);
|
||||
logD("%d: %s",i+1,sample->name);
|
||||
int slen=((unsigned short)reader.readS_BE())*2;
|
||||
|
@ -1897,8 +1904,8 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
loopLen=0;
|
||||
}
|
||||
if (loopLen>=2) {
|
||||
if (loopEnd<slen) slen=loopEnd;
|
||||
sample->loopStart=loopStart;
|
||||
sample->loopEnd=loopEnd;
|
||||
}
|
||||
sample->init(slen);
|
||||
ds.sample.push_back(sample);
|
||||
|
@ -3043,6 +3050,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(0);
|
||||
w->writeS(sample->centerRate);
|
||||
w->writeI(sample->loopStart);
|
||||
//w->writeI(sample->loopEnd);
|
||||
|
||||
w->write(sample->getCurBuf(),sample->getCurBufLen());
|
||||
|
||||
|
|
|
@ -114,12 +114,10 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
|
|||
if (chan[i].audPos<s->samples) {
|
||||
writeAudDat(s->data8[chan[i].audPos++]);
|
||||
}
|
||||
if (chan[i].audPos>=s->samples || chan[i].audPos>=131071) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].audPos=s->loopStart;
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
if (s->isLoopable() && chan[i].audPos>=MIN(131071,s->getEndPosition())) {
|
||||
chan[i].audPos=s->loopStart;
|
||||
} else if (chan[i].audPos>=MIN(131071,s->samples)) {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
|
|
|
@ -153,14 +153,13 @@ void DivPlatformGenesis::processDAC() {
|
|||
if (chan[i].dacPeriod>=(chipClock/576)) {
|
||||
if (s->samples>0) {
|
||||
while (chan[i].dacPeriod>=(chipClock/576)) {
|
||||
if (++chan[i].dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples && !chan[i].dacDirection) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else {
|
||||
chan[i].dacSample=-1;
|
||||
chan[i].dacPeriod=0;
|
||||
break;
|
||||
}
|
||||
++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) {
|
||||
chan[i].dacSample=-1;
|
||||
chan[i].dacPeriod=0;
|
||||
break;
|
||||
}
|
||||
chan[i].dacPeriod-=(chipClock/576);
|
||||
}
|
||||
|
@ -200,14 +199,13 @@ void DivPlatformGenesis::processDAC() {
|
|||
chan[5].dacReady=false;
|
||||
}
|
||||
}
|
||||
if (++chan[5].dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples && !chan[5].dacDirection) {
|
||||
chan[5].dacPos=s->loopStart;
|
||||
} else {
|
||||
chan[5].dacSample=-1;
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
}
|
||||
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) {
|
||||
chan[5].dacSample=-1;
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
}
|
||||
}
|
||||
while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
if (chan[i].samplePos>=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].samplePos=s->loopStart;
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
if (s->isLoopable() && chan[i].samplePos>=(int)s->getEndPosition()) {
|
||||
chan[i].samplePos=s->loopStart;
|
||||
} else if (chan[i].samplePos>=(int)s->samples) {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,12 +62,11 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
if (!isMuted[2]) {
|
||||
rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80));
|
||||
}
|
||||
if (++dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
}
|
||||
dacPos++;
|
||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) {
|
||||
dacPos=s->loopStart;
|
||||
} else if (dacPos>=s->samples) {
|
||||
dacSample=-1;
|
||||
}
|
||||
dacPeriod-=rate;
|
||||
} else {
|
||||
|
|
|
@ -108,12 +108,11 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
|||
rWrite(0x4011,next); \
|
||||
} \
|
||||
} \
|
||||
if (++dacPos>=s->samples) { \
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) { \
|
||||
dacPos=s->loopStart; \
|
||||
} else { \
|
||||
dacSample=-1; \
|
||||
} \
|
||||
dacPos++; \
|
||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) { \
|
||||
dacPos=s->loopStart; \
|
||||
} else if (dacPos>=s->samples) { \
|
||||
dacSample=-1; \
|
||||
} \
|
||||
dacPeriod-=rate; \
|
||||
} else { \
|
||||
|
|
|
@ -771,7 +771,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(11,(end>>2)&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) {
|
||||
chan[c.chan].note=c.value;
|
||||
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;
|
||||
immWrite(11,(end>>2)&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;
|
||||
immWrite(16,freq&0xff);
|
||||
immWrite(17,(freq>>8)&0xff);
|
||||
|
|
|
@ -90,12 +90,10 @@ 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 (chan[i].dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else {
|
||||
chan[i].dacSample=-1;
|
||||
}
|
||||
if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else if (chan[i].dacPos>=s->samples) {
|
||||
chan[i].dacSample=-1;
|
||||
}
|
||||
chan[i].dacPeriod-=rate;
|
||||
}
|
||||
|
|
|
@ -301,7 +301,7 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
qsound_bank = 0x8000 | (s->offQSound >> 16);
|
||||
qsound_addr = s->offQSound & 0xffff;
|
||||
|
||||
int length = s->samples;
|
||||
int length = s->getEndPosition();
|
||||
if (length > 65536 - 16) {
|
||||
length = 65536 - 16;
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
|||
if (chan[i].audPos>0) {
|
||||
start=start+MIN(chan[i].audPos,s->length8);
|
||||
}
|
||||
if (s->loopStart>=0) {
|
||||
if (s->isLoopable()) {
|
||||
loop=start+s->loopStart;
|
||||
}
|
||||
start=MIN(start,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->length8;
|
||||
int length=s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
||||
if (actualLength>0) {
|
||||
s->offRF5C68=memPos;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
chan[i].pcm.pos+=chan[i].pcm.freq;
|
||||
if (chan[i].pcm.pos>=(s->samples<<8)) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].pcm.pos=s->loopStart<<8;
|
||||
} else {
|
||||
chan[i].pcm.sample=-1;
|
||||
}
|
||||
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)) {
|
||||
chan[i].pcm.sample=-1;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=0;
|
||||
|
@ -202,7 +200,7 @@ 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->length8;
|
||||
int actualLength=(int)(s->getEndPosition(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);
|
||||
|
@ -235,7 +233,7 @@ 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->length8;
|
||||
int actualLength=(int)(s->getEndPosition(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);
|
||||
|
|
|
@ -213,7 +213,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->samples;
|
||||
unsigned int sampleEnd=sample->offSU+(sample->getEndPosition());
|
||||
unsigned int off=sample->offSU+chan[i].hasOffset;
|
||||
chan[i].hasOffset=0;
|
||||
if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1;
|
||||
|
@ -221,7 +221,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
|||
chWrite(i,0x0b,off>>8);
|
||||
chWrite(i,0x0c,sampleEnd&0xff);
|
||||
chWrite(i,0x0d,sampleEnd>>8);
|
||||
if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples) {
|
||||
if (sample->isLoopable()) {
|
||||
unsigned int sampleLoop=sample->offSU+sample->loopStart;
|
||||
if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1;
|
||||
chWrite(i,0x0e,sampleLoop&0xff);
|
||||
|
|
|
@ -83,12 +83,10 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
continue;
|
||||
}
|
||||
rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80);
|
||||
if (dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
}
|
||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) {
|
||||
dacPos=s->loopStart;
|
||||
} else if (dacPos>=s->samples) {
|
||||
dacSample=-1;
|
||||
}
|
||||
dacPeriod-=rate;
|
||||
}
|
||||
|
|
|
@ -96,13 +96,11 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
rWritePCMData(tmp_r&0xff);
|
||||
}
|
||||
chan[16].pcm.pos++;
|
||||
if (chan[16].pcm.pos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[16].pcm.pos=s->loopStart;
|
||||
} else {
|
||||
chan[16].pcm.sample=-1;
|
||||
break;
|
||||
}
|
||||
if (s->isLoopable() && chan[16].pcm.pos>=s->getEndPosition()) {
|
||||
chan[16].pcm.pos=s->loopStart;
|
||||
} else if (chan[16].pcm.pos>=s->samples) {
|
||||
chan[16].pcm.sample=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -267,12 +265,12 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
chan[16].pcm.pos=0;
|
||||
DivSample* s=parent->getSample(chan[16].pcm.sample);
|
||||
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;
|
||||
ctrl|=0x20;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -77,13 +77,11 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
chWrite(i,0,0x80|chan[i].dacOut);
|
||||
}
|
||||
chan[i].dacPos++;
|
||||
if (chan[i].dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else {
|
||||
chan[i].dacSample=-1;
|
||||
chWrite(i,0,0);
|
||||
}
|
||||
if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else if (chan[i].dacPos>=s->samples) {
|
||||
chan[i].dacSample=-1;
|
||||
chWrite(i,0,0);
|
||||
}
|
||||
chan[i].dacPeriod-=rate;
|
||||
}
|
||||
|
|
|
@ -761,7 +761,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
immWrite(0x104,(end>>5)&0xff);
|
||||
immWrite(0x105,(end>>13)&0xff);
|
||||
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) {
|
||||
chan[c.chan].note=c.value;
|
||||
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(0x105,(end>>13)&0xff);
|
||||
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);
|
||||
immWrite(0x109,freq&0xff);
|
||||
immWrite(0x10a,(freq>>8)&0xff);
|
||||
|
|
|
@ -793,7 +793,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
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) {
|
||||
chan[c.chan].note=c.value;
|
||||
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(0x15,end>>16);
|
||||
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);
|
||||
immWrite(0x19,freq&0xff);
|
||||
immWrite(0x1a,(freq>>8)&0xff);
|
||||
|
|
|
@ -775,7 +775,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
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) {
|
||||
chan[c.chan].note=c.value;
|
||||
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(0x15,end>>16);
|
||||
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);
|
||||
immWrite(0x19,freq&0xff);
|
||||
immWrite(0x1a,(freq>>8)&0xff);
|
||||
|
|
|
@ -136,9 +136,9 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
|
|||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
unsigned char ctrl;
|
||||
switch (s->depth) {
|
||||
case 3: ctrl=0x20; break;
|
||||
case 8: ctrl=0x40; break;
|
||||
case 16: ctrl=0x60; break;
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM: ctrl=0x20; break;
|
||||
case DIV_SAMPLE_DEPTH_8BIT: ctrl=0x40; break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT: ctrl=0x60; break;
|
||||
default: ctrl=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>511) chan[i].freq=511;
|
||||
// ADPCM has half the range
|
||||
if (s->depth==3 && chan[i].freq>255) chan[i].freq=255;
|
||||
ctrl|=(chan[i].active?0x80:0)|((s->loopStart>=0)?0x10:0)|(chan[i].freq>>8);
|
||||
if (s->depth==DIV_SAMPLE_DEPTH_YMZ_ADPCM && chan[i].freq>255) chan[i].freq=255;
|
||||
ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|(chan[i].freq>>8);
|
||||
if (chan[i].keyOn) {
|
||||
unsigned int start=s->offYMZ280B;
|
||||
unsigned int loop=0;
|
||||
unsigned int loopStart=0;
|
||||
unsigned int loopEnd=0;
|
||||
unsigned int end=MIN(start+s->getCurBufLen(),getSampleMemCapacity()-1);
|
||||
if (chan[i].audPos>0) {
|
||||
switch (s->depth) {
|
||||
case 3: start+=chan[i].audPos/2; break;
|
||||
case 8: start+=chan[i].audPos; break;
|
||||
case 16: start+=chan[i].audPos*2; break;
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM: start+=chan[i].audPos/2; break;
|
||||
case DIV_SAMPLE_DEPTH_8BIT: start+=chan[i].audPos; break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT: start+=chan[i].audPos*2; break;
|
||||
default: break;
|
||||
}
|
||||
start=MIN(start,end);
|
||||
}
|
||||
if (s->loopStart>=0) {
|
||||
if (s->isLoopable()) {
|
||||
switch (s->depth) {
|
||||
case 3: loop=start+s->loopStart/2; break;
|
||||
case 8: loop=start+s->loopStart; break;
|
||||
case 16: loop=start+s->loopStart*2; break;
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM: loopStart=start+s->loopStart/2; loopEnd=start+s->loopEnd/2; break;
|
||||
case DIV_SAMPLE_DEPTH_8BIT: loopStart=start+s->loopStart; loopEnd=start+s->loopEnd; 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(0x20+i*4,(start>>16)&0xff);
|
||||
rWrite(0x21+i*4,(loop>>16)&0xff);
|
||||
rWrite(0x22+i*4,(end>>16)&0xff);
|
||||
rWrite(0x21+i*4,(loopStart>>16)&0xff);
|
||||
rWrite(0x22+i*4,(loopEnd>>16)&0xff);
|
||||
rWrite(0x23+i*4,(end>>16)&0xff);
|
||||
rWrite(0x40+i*4,(start>>8)&0xff);
|
||||
rWrite(0x41+i*4,(loop>>8)&0xff);
|
||||
rWrite(0x42+i*4,(end>>8)&0xff);
|
||||
rWrite(0x41+i*4,(loopStart>>8)&0xff);
|
||||
rWrite(0x42+i*4,(loopEnd>>8)&0xff);
|
||||
rWrite(0x43+i*4,(end>>8)&0xff);
|
||||
rWrite(0x60+i*4,start&0xff);
|
||||
rWrite(0x61+i*4,loop&0xff);
|
||||
rWrite(0x62+i*4,end&0xff);
|
||||
rWrite(0x61+i*4,loopStart&0xff);
|
||||
rWrite(0x62+i*4,loopEnd&0xff);
|
||||
rWrite(0x63+i*4,end&0xff);
|
||||
if (!chan[i].std.vol.had) {
|
||||
chan[i].outVol=chan[i].vol;
|
||||
|
|
|
@ -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);
|
||||
samp_prevSample=samp_temp;
|
||||
|
||||
if (sPreview.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples && (int)sPreview.pos>=s->loopStart) {
|
||||
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.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples && (int)sPreview.pos>=s->loopStart) {
|
||||
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 {
|
||||
} else if (sPreview.pos>=s->samples) {
|
||||
sPreview.sample=-1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,65 @@ DivSampleHistory::~DivSampleHistory() {
|
|||
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) {
|
||||
#ifndef HAVE_SNDFILE
|
||||
logE("Furnace was not compiled with libsndfile!");
|
||||
|
@ -53,7 +112,7 @@ bool DivSample::save(const char* path) {
|
|||
si.channels=1;
|
||||
si.samplerate=rate;
|
||||
switch (depth) {
|
||||
case 8: // 8-bit
|
||||
case DIV_SAMPLE_DEPTH_8BIT: // 8-bit
|
||||
si.format=SF_FORMAT_PCM_U8|SF_FORMAT_WAV;
|
||||
break;
|
||||
default: // 16-bit
|
||||
|
@ -76,17 +135,17 @@ bool DivSample::save(const char* path) {
|
|||
inst.detune = 50 - (pitch % 100);
|
||||
inst.velocity_hi = 0x7f;
|
||||
inst.key_hi = 0x7f;
|
||||
if(loopStart != -1)
|
||||
if(isLoopable())
|
||||
{
|
||||
inst.loop_count = 1;
|
||||
inst.loops[0].mode = SF_LOOP_FORWARD;
|
||||
inst.loops[0].start = loopStart;
|
||||
inst.loops[0].end = samples;
|
||||
inst.loops[0].end = loopEnd;
|
||||
}
|
||||
sf_command(f, SFC_SET_INSTRUMENT, &inst, sizeof(inst));
|
||||
|
||||
switch (depth) {
|
||||
case 8: {
|
||||
case DIV_SAMPLE_DEPTH_8BIT: {
|
||||
// convert from signed to unsigned
|
||||
unsigned char* buf=new unsigned char[length8];
|
||||
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.
|
||||
bool DivSample::initInternal(unsigned char d, int count) {
|
||||
bool DivSample::initInternal(DivSampleDepth d, int count) {
|
||||
switch (d) {
|
||||
case 0: // 1-bit
|
||||
case DIV_SAMPLE_DEPTH_1BIT: // 1-bit
|
||||
if (data1!=NULL) delete[] data1;
|
||||
length1=(count+7)/8;
|
||||
data1=new unsigned char[length1];
|
||||
memset(data1,0,length1);
|
||||
break;
|
||||
case 1: // DPCM
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM: // DPCM
|
||||
if (dataDPCM!=NULL) delete[] dataDPCM;
|
||||
lengthDPCM=(count+7)/8;
|
||||
dataDPCM=new unsigned char[lengthDPCM];
|
||||
memset(dataDPCM,0,lengthDPCM);
|
||||
break;
|
||||
case 3: // YMZ ADPCM
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM: // YMZ ADPCM
|
||||
if (dataZ!=NULL) delete[] dataZ;
|
||||
lengthZ=(count+1)/2;
|
||||
// for padding AICA sample
|
||||
dataZ=new unsigned char[(lengthZ+3)&(~0x03)];
|
||||
memset(dataZ,0,(lengthZ+3)&(~0x03));
|
||||
break;
|
||||
case 4: // QSound ADPCM
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: // QSound ADPCM
|
||||
if (dataQSoundA!=NULL) delete[] dataQSoundA;
|
||||
lengthQSoundA=(count+1)/2;
|
||||
dataQSoundA=new unsigned char[lengthQSoundA];
|
||||
memset(dataQSoundA,0,lengthQSoundA);
|
||||
break;
|
||||
case 5: // ADPCM-A
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A: // ADPCM-A
|
||||
if (dataA!=NULL) delete[] dataA;
|
||||
lengthA=(count+1)/2;
|
||||
dataA=new unsigned char[(lengthA+255)&(~0xff)];
|
||||
memset(dataA,0,(lengthA+255)&(~0xff));
|
||||
break;
|
||||
case 6: // ADPCM-B
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B: // ADPCM-B
|
||||
if (dataB!=NULL) delete[] dataB;
|
||||
lengthB=(count+1)/2;
|
||||
dataB=new unsigned char[(lengthB+255)&(~0xff)];
|
||||
memset(dataB,0,(lengthB+255)&(~0xff));
|
||||
break;
|
||||
case 8: // 8-bit
|
||||
case DIV_SAMPLE_DEPTH_8BIT: // 8-bit
|
||||
if (data8!=NULL) delete[] data8;
|
||||
length8=count;
|
||||
// for padding X1-010 sample
|
||||
data8=new signed char[(count+4095)&(~0xfff)];
|
||||
memset(data8,0,(count+4095)&(~0xfff));
|
||||
break;
|
||||
case 9: // BRR
|
||||
case DIV_SAMPLE_DEPTH_BRR: // BRR
|
||||
if (dataBRR!=NULL) delete[] dataBRR;
|
||||
lengthBRR=9*((count+15)/16);
|
||||
dataBRR=new unsigned char[lengthBRR];
|
||||
memset(dataBRR,0,lengthBRR);
|
||||
break;
|
||||
case 10: // VOX
|
||||
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
||||
if (dataVOX!=NULL) delete[] dataVOX;
|
||||
lengthVOX=(count+1)/2;
|
||||
dataVOX=new unsigned char[lengthVOX];
|
||||
memset(dataVOX,0,lengthVOX);
|
||||
break;
|
||||
case 16: // 16-bit
|
||||
case DIV_SAMPLE_DEPTH_16BIT: // 16-bit
|
||||
if (data16!=NULL) delete[] data16;
|
||||
length16=count*2;
|
||||
data16=new short[(count+511)&(~0x1ff)];
|
||||
|
@ -180,34 +239,34 @@ bool DivSample::initInternal(unsigned char d, int count) {
|
|||
|
||||
bool DivSample::init(unsigned int count) {
|
||||
if (!initInternal(depth,count)) return false;
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DivSample::resize(unsigned int count) {
|
||||
if (depth==8) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
|
||||
memcpy(data8,oldData8,MIN(count,samples));
|
||||
delete[] oldData8;
|
||||
} else {
|
||||
initInternal(8,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
|
||||
memcpy(data16,oldData16,sizeof(short)*MIN(count,samples));
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
initInternal(16,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -218,11 +277,11 @@ bool DivSample::strip(unsigned int begin, unsigned int end) {
|
|||
if (end>samples) end=samples;
|
||||
int count=samples-(end-begin);
|
||||
if (count<=0) return resize(0);
|
||||
if (depth==8) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
|
||||
if (begin>0) {
|
||||
memcpy(data8,oldData8,begin);
|
||||
}
|
||||
|
@ -234,13 +293,13 @@ bool DivSample::strip(unsigned int begin, unsigned int end) {
|
|||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
|
||||
if (begin>0) {
|
||||
memcpy(data16,oldData16,sizeof(short)*begin);
|
||||
}
|
||||
|
@ -252,7 +311,7 @@ bool DivSample::strip(unsigned int begin, unsigned int end) {
|
|||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -262,31 +321,31 @@ bool DivSample::trim(unsigned int begin, unsigned int end) {
|
|||
int count=end-begin;
|
||||
if (count==0) return true;
|
||||
if (begin==0 && end==samples) return true;
|
||||
if (depth==8) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
|
||||
memcpy(data8,oldData8+begin,count);
|
||||
delete[] oldData8;
|
||||
} else {
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
|
||||
memcpy(data16,&(oldData16[begin]),sizeof(short)*count);
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -294,11 +353,11 @@ bool DivSample::trim(unsigned int begin, unsigned int end) {
|
|||
|
||||
bool DivSample::insert(unsigned int pos, unsigned int length) {
|
||||
unsigned int count=samples+length;
|
||||
if (depth==8) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
|
||||
if (pos>0) {
|
||||
memcpy(data8,oldData8,pos);
|
||||
}
|
||||
|
@ -307,15 +366,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
|
|||
}
|
||||
delete[] oldData8;
|
||||
} else {
|
||||
initInternal(8,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_8BIT,count);
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
|
||||
if (pos>0) {
|
||||
memcpy(data16,oldData16,sizeof(short)*pos);
|
||||
}
|
||||
|
@ -324,9 +383,9 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
|
|||
}
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
initInternal(16,count);
|
||||
initInternal(DIV_SAMPLE_DEPTH_16BIT,count);
|
||||
}
|
||||
samples=count;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -337,15 +396,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
|
|||
int finalCount=(double)samples*(r/(double)rate); \
|
||||
signed char* oldData8=data8; \
|
||||
short* oldData16=data16; \
|
||||
if (depth==16) { \
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) { \
|
||||
if (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) { \
|
||||
data8=NULL; \
|
||||
initInternal(8,finalCount); \
|
||||
initInternal(DIV_SAMPLE_DEPTH_8BIT,finalCount); \
|
||||
} \
|
||||
} else { \
|
||||
return false; \
|
||||
|
@ -353,19 +412,20 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
|
|||
|
||||
#define RESAMPLE_END \
|
||||
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)); \
|
||||
rate=r; \
|
||||
samples=finalCount; \
|
||||
if (depth==16) { \
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) { \
|
||||
delete[] oldData16; \
|
||||
} else if (depth==8) { \
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \
|
||||
delete[] oldData8; \
|
||||
}
|
||||
|
||||
bool DivSample::resampleNone(double r) {
|
||||
RESAMPLE_BEGIN;
|
||||
|
||||
if (depth==16) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
unsigned int pos=(unsigned int)((double)i*((double)rate/r));
|
||||
if (pos>=samples) {
|
||||
|
@ -374,7 +434,7 @@ bool DivSample::resampleNone(double r) {
|
|||
data16[i]=oldData16[pos];
|
||||
}
|
||||
}
|
||||
} else if (depth==8) {
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
unsigned int pos=(unsigned int)((double)i*((double)rate/r));
|
||||
if (pos>=samples) {
|
||||
|
@ -396,7 +456,7 @@ bool DivSample::resampleLinear(double r) {
|
|||
unsigned int posInt=0;
|
||||
double factor=(double)rate/r;
|
||||
|
||||
if (depth==16) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
short s1=(posInt>=samples)?0:oldData16[posInt];
|
||||
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++;
|
||||
}
|
||||
}
|
||||
} else if (depth==8) {
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
short s1=(posInt>=samples)?0:oldData8[posInt];
|
||||
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;
|
||||
float* cubicTable=DivFilterTables::getCubicTable();
|
||||
|
||||
if (depth==16) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
unsigned int n=((unsigned int)(posFrac*1024.0))&1023;
|
||||
float* t=&cubicTable[n<<2];
|
||||
|
@ -456,7 +516,7 @@ bool DivSample::resampleCubic(double r) {
|
|||
posInt++;
|
||||
}
|
||||
}
|
||||
} else if (depth==8) {
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
unsigned int n=((unsigned int)(posFrac*1024.0))&1023;
|
||||
float* t=&cubicTable[n<<2];
|
||||
|
@ -493,7 +553,7 @@ bool DivSample::resampleBlep(double r) {
|
|||
|
||||
memset(s,0,16*sizeof(float));
|
||||
|
||||
if (depth==16) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
memset(data16,0,finalCount*sizeof(short));
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
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);
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
if (posInt<samples) {
|
||||
|
@ -582,7 +642,7 @@ bool DivSample::resampleSinc(double r) {
|
|||
|
||||
memset(s,0,16*sizeof(float));
|
||||
|
||||
if (depth==16) {
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (int i=0; i<finalCount+8; i++) {
|
||||
unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
|
||||
float result=0;
|
||||
|
@ -607,7 +667,7 @@ bool DivSample::resampleSinc(double r) {
|
|||
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++) {
|
||||
unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
|
||||
float result=0;
|
||||
|
@ -639,7 +699,7 @@ bool DivSample::resampleSinc(double r) {
|
|||
}
|
||||
|
||||
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) {
|
||||
case DIV_RESAMPLE_NONE:
|
||||
return resampleNone(r);
|
||||
|
@ -669,15 +729,15 @@ bool DivSample::resample(double r, int filter) {
|
|||
|
||||
void DivSample::render() {
|
||||
// step 1: convert to 16-bit if needed
|
||||
if (depth!=16) {
|
||||
if (!initInternal(16,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_16BIT,samples)) return;
|
||||
switch (depth) {
|
||||
case 0: // 1-bit
|
||||
case DIV_SAMPLE_DEPTH_1BIT: // 1-bit
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
data16[i]=((data1[i>>3]>>(i&7))&1)?0x7fff:-0x7fff;
|
||||
}
|
||||
break;
|
||||
case 1: { // DPCM
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM: { // DPCM
|
||||
int accum=0;
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
accum+=((dataDPCM[i>>3]>>(i&7))&1)?1:-1;
|
||||
|
@ -687,27 +747,27 @@ void DivSample::render() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 3: // YMZ ADPCM
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM: // YMZ ADPCM
|
||||
ymz_decode(dataZ,data16,samples);
|
||||
break;
|
||||
case 4: // QSound ADPCM
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: // QSound ADPCM
|
||||
bs_decode(dataQSoundA,data16,samples);
|
||||
break;
|
||||
case 5: // ADPCM-A
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A: // ADPCM-A
|
||||
yma_decode(dataA,data16,samples);
|
||||
break;
|
||||
case 6: // ADPCM-B
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B: // ADPCM-B
|
||||
ymb_decode(dataB,data16,samples);
|
||||
break;
|
||||
case 8: // 8-bit PCM
|
||||
case DIV_SAMPLE_DEPTH_8BIT: // 8-bit PCM
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
data16[i]=data8[i]<<8;
|
||||
}
|
||||
break;
|
||||
case 9: // BRR
|
||||
case DIV_SAMPLE_DEPTH_BRR: // BRR
|
||||
// TODO!
|
||||
break;
|
||||
case 10: // VOX
|
||||
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
||||
oki_decode(dataVOX,data16,samples);
|
||||
break;
|
||||
default:
|
||||
|
@ -716,16 +776,16 @@ void DivSample::render() {
|
|||
}
|
||||
|
||||
// step 2: render to other formats
|
||||
if (depth!=0) { // 1-bit
|
||||
if (!initInternal(0,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_1BIT) { // 1-bit
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_1BIT,samples)) return;
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
if (data16[i]>0) {
|
||||
data1[i>>3]|=1<<(i&7);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (depth!=1) { // DPCM
|
||||
if (!initInternal(1,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_1BIT_DPCM) { // DPCM
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_1BIT_DPCM,samples)) return;
|
||||
int accum=63;
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
int next=((unsigned short)(data16[i]^0x8000))>>9;
|
||||
|
@ -739,84 +799,88 @@ void DivSample::render() {
|
|||
if (accum>127) accum=127;
|
||||
}
|
||||
}
|
||||
if (depth!=3) { // YMZ ADPCM
|
||||
if (!initInternal(3,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_YMZ_ADPCM) { // YMZ ADPCM
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_YMZ_ADPCM,samples)) return;
|
||||
ymz_encode(data16,dataZ,(samples+7)&(~0x7));
|
||||
}
|
||||
if (depth!=4) { // QSound ADPCM
|
||||
if (!initInternal(4,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_QSOUND_ADPCM) { // QSound ADPCM
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_QSOUND_ADPCM,samples)) return;
|
||||
bs_encode(data16,dataQSoundA,samples);
|
||||
}
|
||||
// TODO: pad to 256.
|
||||
if (depth!=5) { // ADPCM-A
|
||||
if (!initInternal(5,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_ADPCM_A) { // ADPCM-A
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_A,samples)) return;
|
||||
yma_encode(data16,dataA,(samples+511)&(~0x1ff));
|
||||
}
|
||||
if (depth!=6) { // ADPCM-B
|
||||
if (!initInternal(6,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_ADPCM_B) { // ADPCM-B
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_B,samples)) return;
|
||||
ymb_encode(data16,dataB,(samples+511)&(~0x1ff));
|
||||
}
|
||||
if (depth!=8) { // 8-bit PCM
|
||||
if (!initInternal(8,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_8BIT) { // 8-bit PCM
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return;
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
data8[i]=data16[i]>>8;
|
||||
}
|
||||
}
|
||||
// TODO: BRR!
|
||||
if (depth!=10) { // VOX
|
||||
if (!initInternal(10,samples)) return;
|
||||
if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
||||
oki_encode(data16,dataVOX,samples);
|
||||
}
|
||||
}
|
||||
|
||||
void* DivSample::getCurBuf() {
|
||||
switch (depth) {
|
||||
case 0:
|
||||
case DIV_SAMPLE_DEPTH_1BIT:
|
||||
return data1;
|
||||
case 1:
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||
return dataDPCM;
|
||||
case 3:
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||
return dataZ;
|
||||
case 4:
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||
return dataQSoundA;
|
||||
case 5:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||
return dataA;
|
||||
case 6:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
return dataB;
|
||||
case 8:
|
||||
case DIV_SAMPLE_DEPTH_8BIT:
|
||||
return data8;
|
||||
case 9:
|
||||
case DIV_SAMPLE_DEPTH_BRR:
|
||||
return dataBRR;
|
||||
case 10:
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
return dataVOX;
|
||||
case 16:
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
return data16;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int DivSample::getCurBufLen() {
|
||||
switch (depth) {
|
||||
case 0:
|
||||
case DIV_SAMPLE_DEPTH_1BIT:
|
||||
return length1;
|
||||
case 1:
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||
return lengthDPCM;
|
||||
case 3:
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||
return lengthZ;
|
||||
case 4:
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||
return lengthQSoundA;
|
||||
case 5:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||
return lengthA;
|
||||
case 6:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
return lengthB;
|
||||
case 8:
|
||||
case DIV_SAMPLE_DEPTH_8BIT:
|
||||
return length8;
|
||||
case 9:
|
||||
case DIV_SAMPLE_DEPTH_BRR:
|
||||
return lengthBRR;
|
||||
case 10:
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
return lengthVOX;
|
||||
case 16:
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
return length16;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -831,9 +895,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);
|
||||
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd);
|
||||
} else {
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart);
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd);
|
||||
}
|
||||
if (!doNotPush) {
|
||||
while (!redoHist.empty()) {
|
||||
|
@ -863,7 +927,8 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
|||
} \
|
||||
rate=h->rate; \
|
||||
centerRate=h->centerRate; \
|
||||
loopStart=h->loopStart;
|
||||
loopStart=h->loopStart; \
|
||||
loopEnd=h->loopEnd;
|
||||
|
||||
|
||||
int DivSample::undo() {
|
||||
|
|
|
@ -17,9 +17,28 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _SAMPLE_H
|
||||
#define _SAMPLE_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../ta-utils.h"
|
||||
#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 {
|
||||
DIV_RESAMPLE_NONE=0,
|
||||
DIV_RESAMPLE_LINEAR,
|
||||
|
@ -32,10 +51,10 @@ enum DivResampleFilters {
|
|||
struct DivSampleHistory {
|
||||
unsigned char* data;
|
||||
unsigned int length, samples;
|
||||
unsigned char depth;
|
||||
int rate, centerRate, loopStart;
|
||||
DivSampleDepth depth;
|
||||
int rate, centerRate, loopStart, loopEnd;
|
||||
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),
|
||||
length(l),
|
||||
samples(s),
|
||||
|
@ -43,8 +62,9 @@ struct DivSampleHistory {
|
|||
rate(r),
|
||||
centerRate(cr),
|
||||
loopStart(ls),
|
||||
loopEnd(le),
|
||||
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),
|
||||
length(0),
|
||||
samples(0),
|
||||
|
@ -52,13 +72,14 @@ struct DivSampleHistory {
|
|||
rate(r),
|
||||
centerRate(cr),
|
||||
loopStart(ls),
|
||||
loopEnd(le),
|
||||
hasSample(false) {}
|
||||
~DivSampleHistory();
|
||||
};
|
||||
|
||||
struct DivSample {
|
||||
String name;
|
||||
int rate, centerRate, loopStart, loopOffP;
|
||||
int rate, centerRate, loopStart, loopEnd, loopOffP;
|
||||
// valid values are:
|
||||
// - 0: ZX Spectrum overlay drum (1-bit)
|
||||
// - 1: 1-bit NES DPCM (1-bit)
|
||||
|
@ -70,7 +91,7 @@ struct DivSample {
|
|||
// - 9: BRR (SNES)
|
||||
// - 10: VOX ADPCM
|
||||
// - 16: 16-bit PCM
|
||||
unsigned char depth;
|
||||
DivSampleDepth depth;
|
||||
|
||||
// these are the new data structures.
|
||||
signed char* data8; // 8
|
||||
|
@ -93,6 +114,23 @@ struct DivSample {
|
|||
std::deque<DivSampleHistory*> undoHist;
|
||||
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
|
||||
*/
|
||||
|
@ -116,7 +154,7 @@ struct DivSample {
|
|||
* @param count number of samples.
|
||||
* @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.
|
||||
|
@ -212,8 +250,9 @@ struct DivSample {
|
|||
rate(32000),
|
||||
centerRate(8363),
|
||||
loopStart(-1),
|
||||
loopEnd(-1),
|
||||
loopOffP(0),
|
||||
depth(16),
|
||||
depth(DIV_SAMPLE_DEPTH_16BIT),
|
||||
data8(NULL),
|
||||
data16(NULL),
|
||||
data1(NULL),
|
||||
|
@ -253,3 +292,5 @@ struct DivSample {
|
|||
samples(0) {}
|
||||
~DivSample();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -512,7 +512,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(streamID);
|
||||
w->writeS(write.val); // sample number
|
||||
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;
|
||||
loopSample[streamID]=write.val;
|
||||
}
|
||||
|
@ -1549,7 +1549,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
size_t memPos=0;
|
||||
for (int i=0; i<song.sampleLen; 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 ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) {
|
||||
memPos=(memPos+0xffff)&0xff0000;
|
||||
|
@ -1559,8 +1559,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
sample->offSegaPCM=memPos;
|
||||
unsigned int readPos=0;
|
||||
for (unsigned int j=0; j<alignedSize; j++) {
|
||||
if (readPos>=sample->length8) {
|
||||
if (sample->loopStart>=0 && sample->loopStart<(int)sample->length8) {
|
||||
if (readPos>=sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||
if (sample->isLoopable()) {
|
||||
readPos=sample->loopStart;
|
||||
pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
|
||||
} else {
|
||||
|
@ -1663,7 +1663,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen);
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
DivSample* s=song.sample[i];
|
||||
if (s->depth==16) {
|
||||
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
unsigned int pos=s->offYMZ280B;
|
||||
for (unsigned int j=0; j<s->samples; j++) {
|
||||
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) {
|
||||
DivSample* sample=song.sample[loopSample[nextToTouch]];
|
||||
// insert loop
|
||||
if (sample->loopStart<(int)sample->length8) {
|
||||
if (sample->loopStart<(int)sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||
w->writeC(0x93);
|
||||
w->writeC(nextToTouch);
|
||||
w->writeI(sample->off8+sample->loopStart);
|
||||
w->writeC(0x81);
|
||||
w->writeI(sample->length8-sample->loopStart);
|
||||
w->writeI(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->loopStart);
|
||||
}
|
||||
}
|
||||
loopSample[nextToTouch]=-1;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "gui.h"
|
||||
#include "guiConst.h"
|
||||
#include "debug.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include <SDL_timer.h>
|
||||
|
@ -154,12 +155,19 @@ void FurnaceGUI::drawDebug() {
|
|||
ImGui::Text("rate: %d",sample->rate);
|
||||
ImGui::Text("centerRate: %d",sample->centerRate);
|
||||
ImGui::Text("loopStart: %d",sample->loopStart);
|
||||
ImGui::Text("loopEnd: %d", sample->loopEnd);
|
||||
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("length16: %d",sample->length16);
|
||||
ImGui::Text("length1: %d",sample->length1);
|
||||
ImGui::Text("lengthDPCM: %d",sample->lengthDPCM);
|
||||
ImGui::Text("lengthZ: %d",sample->lengthZ);
|
||||
ImGui::Text("lengthQSoundA: %d",sample->lengthQSoundA);
|
||||
ImGui::Text("lengthA: %d",sample->lengthA);
|
||||
ImGui::Text("lengthB: %d",sample->lengthB);
|
||||
|
@ -170,6 +178,7 @@ void FurnaceGUI::drawDebug() {
|
|||
ImGui::Text("off16: %x",sample->off16);
|
||||
ImGui::Text("off1: %x",sample->off1);
|
||||
ImGui::Text("offDPCM: %x",sample->offDPCM);
|
||||
ImGui::Text("offZ: %x",sample->offZ);
|
||||
ImGui::Text("offQSoundA: %x",sample->offQSoundA);
|
||||
ImGui::Text("offA: %x",sample->offA);
|
||||
ImGui::Text("offB: %x",sample->offB);
|
||||
|
@ -179,6 +188,8 @@ void FurnaceGUI::drawDebug() {
|
|||
ImGui::Text("offQSound: %x",sample->offQSound);
|
||||
ImGui::Text("offX1_010: %x",sample->offX1_010);
|
||||
ImGui::Text("offSU: %x",sample->offSU);
|
||||
ImGui::Text("offYMZ280B: %x",sample->offYMZ280B);
|
||||
ImGui::Text("offRF5C68: %x",sample->offRF5C68);
|
||||
|
||||
ImGui::Text("samples: %d",sample->samples);
|
||||
ImGui::TreePop();
|
||||
|
|
|
@ -709,6 +709,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
sample->centerRate=prevSample->centerRate;
|
||||
sample->name=prevSample->name;
|
||||
sample->loopStart=prevSample->loopStart;
|
||||
sample->loopEnd=prevSample->loopEnd;
|
||||
sample->depth=prevSample->depth;
|
||||
if (sample->init(prevSample->samples)) {
|
||||
if (prevSample->getCurBuf()!=NULL) {
|
||||
|
@ -838,7 +839,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (!sample->insert(pos,sampleClipboardLen)) {
|
||||
showError("couldn't paste! make sure your sample is 8 or 16-bit.");
|
||||
} else {
|
||||
if (sample->depth==8) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
for (size_t i=0; i<sampleClipboardLen; i++) {
|
||||
sample->data8[pos+i]=sampleClipboard[i]>>8;
|
||||
}
|
||||
|
@ -864,7 +865,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (pos<0) pos=0;
|
||||
|
||||
e->lockEngine([this,sample,pos]() {
|
||||
if (sample->depth==8) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
for (size_t i=0; i<sampleClipboardLen; i++) {
|
||||
if (pos+i>=sample->samples) break;
|
||||
sample->data8[pos+i]=sampleClipboard[i]>>8;
|
||||
|
@ -894,7 +895,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (pos<0) pos=0;
|
||||
|
||||
e->lockEngine([this,sample,pos]() {
|
||||
if (sample->depth==8) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
for (size_t i=0; i<sampleClipboardLen; i++) {
|
||||
if (pos+i>=sample->samples) break;
|
||||
int val=sample->data8[pos+i]+(sampleClipboard[i]>>8);
|
||||
|
@ -948,7 +949,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
SAMPLE_OP_BEGIN;
|
||||
float maxVal=0.0f;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
float val=fabs((float)sample->data16[i]/32767.0f);
|
||||
if (val>maxVal) maxVal=val;
|
||||
|
@ -963,7 +964,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
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++) {
|
||||
float val=fabs((float)sample->data8[i]/127.0f);
|
||||
if (val>maxVal) maxVal=val;
|
||||
|
@ -994,14 +995,14 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
float val=sample->data16[i]*float(i-start)/float(end-start);
|
||||
if (val<-32768) val=-32768;
|
||||
if (val>32767) val=32767;
|
||||
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++) {
|
||||
float val=sample->data8[i]*float(i-start)/float(end-start);
|
||||
if (val<-128) val=-128;
|
||||
|
@ -1024,14 +1025,14 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
float val=sample->data16[i]*float(end-i)/float(end-start);
|
||||
if (val<-32768) val=-32768;
|
||||
if (val>32767) val=32767;
|
||||
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++) {
|
||||
float val=sample->data8[i]*float(end-i)/float(end-start);
|
||||
if (val<-128) val=-128;
|
||||
|
@ -1058,11 +1059,11 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
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++) {
|
||||
sample->data8[i]=0;
|
||||
}
|
||||
|
@ -1116,7 +1117,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
unsigned int ri=end-i-1+start;
|
||||
if (ri<=i) break;
|
||||
|
@ -1124,7 +1125,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
sample->data16[ri]^=sample->data16[i];
|
||||
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++) {
|
||||
unsigned int ri=end-i-1+start;
|
||||
if (ri<=i) break;
|
||||
|
@ -1148,12 +1149,12 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
sample->data16[i]=-sample->data16[i];
|
||||
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++) {
|
||||
sample->data8[i]=-sample->data8[i];
|
||||
if (sample->data16[i]==-128) sample->data16[i]=127;
|
||||
|
@ -1174,11 +1175,11 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
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++) {
|
||||
sample->data8[i]^=0x80;
|
||||
}
|
||||
|
@ -1261,8 +1262,8 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
sample->trim(0,end);
|
||||
sample->loopStart=start;
|
||||
sample->loopEnd=end;
|
||||
updateSampleTex=true;
|
||||
|
||||
e->renderSamples();
|
||||
|
|
|
@ -116,7 +116,7 @@ const char* insTypes[DIV_INS_MAX+1]={
|
|||
NULL
|
||||
};
|
||||
|
||||
const char* sampleDepths[17]={
|
||||
const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
|
||||
"1-bit PCM",
|
||||
"1-bit DPCM",
|
||||
NULL,
|
||||
|
|
|
@ -40,7 +40,7 @@ extern const char* noteNames[180];
|
|||
extern const char* noteNamesG[180];
|
||||
extern const char* pitchLabel[11];
|
||||
extern const char* insTypes[];
|
||||
extern const char* sampleDepths[17];
|
||||
extern const char* sampleDepths[];
|
||||
extern const char* resampleStrats[];
|
||||
extern const int availableSystems[];
|
||||
extern const FurnaceGUIActionDef guiActions[];
|
||||
|
|
|
@ -41,7 +41,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
} else {
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
String sampleType="Invalid";
|
||||
if (sample->depth<17) {
|
||||
if (sample->depth<DIV_SAMPLE_DEPTH_MAX) {
|
||||
if (sampleDepths[sample->depth]!=NULL) {
|
||||
sampleType=sampleDepths[sample->depth];
|
||||
}
|
||||
|
@ -61,11 +61,11 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
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 (ImGui::Selectable(sampleDepths[i])) {
|
||||
sample->prepareUndo(true);
|
||||
sample->depth=i;
|
||||
sample->depth=(DivSampleDepth)i;
|
||||
e->renderSamplesP();
|
||||
updateSampleTex=true;
|
||||
MARK_MODIFIED;
|
||||
|
@ -93,22 +93,43 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
bool doLoop=(sample->loopStart>=0);
|
||||
bool doLoop=(sample->isLoopable());
|
||||
if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED
|
||||
if (doLoop) {
|
||||
sample->loopStart=0;
|
||||
sample->loopEnd=sample->samples;
|
||||
} else {
|
||||
sample->loopStart=-1;
|
||||
sample->loopEnd=sample->samples;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (doLoop) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Start");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED
|
||||
if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) {
|
||||
if (ImGui::InputInt("##LoopStartPosition",&sample->loopStart,1,10)) { MARK_MODIFIED
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +144,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
*/
|
||||
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));
|
||||
if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) {
|
||||
|
@ -275,14 +296,14 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
SAMPLE_OP_BEGIN;
|
||||
float vol=amplifyVol/100.0f;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
float val=sample->data16[i]*vol;
|
||||
if (val<-32768) val=-32768;
|
||||
if (val>32767) val=32767;
|
||||
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++) {
|
||||
float val=sample->data8[i]*vol;
|
||||
if (val<-128) val=-128;
|
||||
|
@ -466,7 +487,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
|
||||
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++) {
|
||||
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
|
||||
double cut=sin((freq/double(sample->rate))*M_PI);
|
||||
|
@ -482,7 +503,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (val>32767) val=32767;
|
||||
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++) {
|
||||
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
|
||||
double cut=sin((freq/double(sample->rate))*M_PI);
|
||||
|
@ -574,11 +595,11 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
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 (ImGui::Selectable(sampleDepths[i])) {
|
||||
sample->prepareUndo(true);
|
||||
sample->depth=i;
|
||||
sample->depth=(DivSampleDepth)i;
|
||||
e->renderSamplesP();
|
||||
updateSampleTex=true;
|
||||
MARK_MODIFIED;
|
||||
|
@ -607,22 +628,43 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
bool doLoop=(sample->loopStart>=0);
|
||||
bool doLoop=(sample->isLoopable());
|
||||
if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED
|
||||
if (doLoop) {
|
||||
sample->loopStart=0;
|
||||
sample->loopEnd=sample->samples;
|
||||
} else {
|
||||
sample->loopStart=-1;
|
||||
sample->loopEnd=sample->samples;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (doLoop) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Start");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED
|
||||
if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) {
|
||||
if (ImGui::InputInt("##LoopStartPosition",&sample->loopStart,1,10)) { MARK_MODIFIED
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
|
@ -637,7 +679,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
*/
|
||||
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));
|
||||
if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) {
|
||||
|
@ -820,7 +862,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
|
||||
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++) {
|
||||
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
|
||||
double cut=sin((freq/double(sample->rate))*M_PI);
|
||||
|
@ -836,7 +878,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (val>32767) val=32767;
|
||||
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++) {
|
||||
double freq=sampleFilterCutStart+(sampleFilterCutEnd-sampleFilterCutStart)*pow(double(i-start)/double(end-start),power);
|
||||
double cut=sin((freq/double(sample->rate))*M_PI);
|
||||
|
@ -890,14 +932,14 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
SAMPLE_OP_BEGIN;
|
||||
float vol=amplifyVol/100.0f;
|
||||
|
||||
if (sample->depth==16) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=start; i<end; i++) {
|
||||
float val=sample->data16[i]*vol;
|
||||
if (val<-32768) val=-32768;
|
||||
if (val>32767) val=32767;
|
||||
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++) {
|
||||
float val=sample->data8[i]*vol;
|
||||
if (val<-128) val=-128;
|
||||
|
@ -1138,7 +1180,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
for (int i=0; i<availY; i++) {
|
||||
for (int j=0; j<availX; j++) {
|
||||
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;
|
||||
} else {
|
||||
data[i*availX+j]=bgColor;
|
||||
|
@ -1158,7 +1200,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (xCoarse>=sample->samples) break;
|
||||
int y1, y2;
|
||||
int totalAdvance=0;
|
||||
if (sample->depth==8) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
y1=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256;
|
||||
} else {
|
||||
y1=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536;
|
||||
|
@ -1171,7 +1213,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
totalAdvance+=xAdvanceCoarse;
|
||||
if (xCoarse>=sample->samples) break;
|
||||
do {
|
||||
if (sample->depth==8) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
y2=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256;
|
||||
} else {
|
||||
y2=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536;
|
||||
|
@ -1209,11 +1251,11 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sampleSelStart=0;
|
||||
sampleSelEnd=sample->samples;
|
||||
} 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;
|
||||
sampleDragAreaSize=rectSize;
|
||||
sampleDrag16=(sample->depth==16);
|
||||
sampleDragTarget=(sample->depth==16)?((void*)sample->data16):((void*)sample->data8);
|
||||
sampleDrag16=(sample->depth==DIV_SAMPLE_DEPTH_16BIT);
|
||||
sampleDragTarget=(sample->depth==DIV_SAMPLE_DEPTH_16BIT)?((void*)sample->data16):((void*)sample->data8);
|
||||
sampleDragLen=sample->samples;
|
||||
sampleDragActive=true;
|
||||
sampleSelStart=-1;
|
||||
|
@ -1312,7 +1354,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
posX=samplePos+pos.x*sampleZoom;
|
||||
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) {
|
||||
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.";
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue