diff --git a/papers/format.md b/papers/format.md index 248a98d05..bf0b929eb 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 159: Furnace dev159 - 158: Furnace 0.6pre5 - 157: Furnace dev157 - 156: Furnace dev156 @@ -1232,7 +1233,8 @@ size | description | - 2: ping-pong 1 | flags (>=129) or reserved | - 0: BRR emphasis - 1 | reserved + 1 | flags 2 (>=159) or reserved + | - 0: dither 4 | loop start | - -1 means no loop 4 | loop end diff --git a/src/engine/engine.h b/src/engine/engine.h index bf842aaeb..2b9f59920 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -54,8 +54,8 @@ #define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock(); #define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; -#define DIV_VERSION "0.6pre5" -#define DIV_ENGINE_VERSION 158 +#define DIV_VERSION "dev159" +#define DIV_ENGINE_VERSION 159 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 57bf7e09b..5f9b25545 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -54,7 +54,7 @@ void DivSample::putSampleData(SafeWriter* w) { w->writeC(depth); w->writeC(loopMode); w->writeC(brrEmphasis); - w->writeC(0); // reserved + w->writeC(dither); w->writeI(loop?loopStart:-1); w->writeI(loop?loopEnd:-1); @@ -131,8 +131,11 @@ DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) { } else { reader.readC(); } - // reserved - reader.readC(); + if (version>=159) { + dither=reader.readC()&1; + } else { + reader.readC(); + } loopStart=reader.readI(); loopEnd=reader.readI(); @@ -1196,8 +1199,23 @@ void DivSample::render(unsigned int formatMask) { } if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_8BIT)) { // 8-bit PCM if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return; - for (unsigned int i=0; i>8; + if (dither) { + unsigned short lfsr=0x6438; + unsigned short lfsr1=0x1283; + signed char errorLast=0; + signed char errorCur=0; + for (unsigned int i=0; i>8; + errorLast=errorCur; + errorCur=(val<<8)-data16[i]; + data8[i]=CLAMP(val-((((errorLast+errorCur)>>1)+(lfsr&0xff))>>8),-128,127); + lfsr=(lfsr<<1)|(((lfsr>>1)^(lfsr>>2)^(lfsr>>4)^(lfsr>>15))&1); + lfsr1=(lfsr1<<1)|(((lfsr1>>1)^(lfsr1>>2)^(lfsr1>>4)^(lfsr1>>15))&1); + } + } else { + for (unsigned int i=0; i>8; + } } } if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR @@ -1277,9 +1295,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { duplicate=new unsigned char[getCurBufLen()]; memcpy(duplicate,getCurBuf(),getCurBufLen()); } - h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,loopMode); + h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,dither,loopMode); } else { - h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,loopMode); + h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,dither,loopMode); } if (!doNotPush) { while (!redoHist.empty()) { @@ -1312,6 +1330,8 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { loopStart=h->loopStart; \ loopEnd=h->loopEnd; \ loop=h->loop; \ + brrEmphasis=h->brrEmphasis; \ + dither=h->dither; \ loopMode=h->loopMode; diff --git a/src/engine/sample.h b/src/engine/sample.h index c2f08ced6..ce1bf1fa2 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -61,10 +61,10 @@ struct DivSampleHistory { unsigned int length, samples; DivSampleDepth depth; int rate, centerRate, loopStart, loopEnd; - bool loop, brrEmphasis; + bool loop, brrEmphasis, dither; DivSampleLoopMode loopMode; bool hasSample; - DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, DivSampleLoopMode lm): + DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, bool di, DivSampleLoopMode lm): data((unsigned char*)d), length(l), samples(s), @@ -75,9 +75,10 @@ struct DivSampleHistory { loopEnd(le), loop(lp), brrEmphasis(be), + dither(di), loopMode(lm), hasSample(true) {} - DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, DivSampleLoopMode lm): + DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, bool di, DivSampleLoopMode lm): data(NULL), length(0), samples(0), @@ -88,6 +89,7 @@ struct DivSampleHistory { loopEnd(le), loop(lp), brrEmphasis(be), + dither(di), loopMode(lm), hasSample(false) {} ~DivSampleHistory(); @@ -108,7 +110,7 @@ struct DivSample { // - 10: VOX ADPCM // - 16: 16-bit PCM DivSampleDepth depth; - bool loop, brrEmphasis; + bool loop, brrEmphasis, dither; // valid values are: // - 0: Forward loop // - 1: Backward loop @@ -323,6 +325,7 @@ struct DivSample { depth(DIV_SAMPLE_DEPTH_16BIT), loop(false), brrEmphasis(true), + dither(false), loopMode(DIV_SAMPLE_LOOP_FORWARD), data8(NULL), data16(NULL), diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 7520162f7..87d74e6cf 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -791,6 +791,8 @@ void FurnaceGUI::doAction(int what) { sample->loopEnd=prevSample->loopEnd; sample->loop=prevSample->loop; sample->loopMode=prevSample->loopMode; + sample->brrEmphasis=prevSample->brrEmphasis; + sample->dither=prevSample->dither; sample->depth=prevSample->depth; if (sample->init(prevSample->samples)) { if (prevSample->getCurBuf()!=NULL) { diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index c0691f7de..238f37e88 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -291,6 +291,19 @@ void FurnaceGUI::drawSampleEdit() { } } } + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && e->getSampleFormatMask()&(1L<dither; + if (ImGui::Checkbox("8-bit dither",&di)) { + sample->prepareUndo(true); + sample->dither=di; + e->renderSamplesP(); + updateSampleTex=true; + MARK_MODIFIED; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("dither the sample when used on a chip that only supports 8-bit samples."); + } + } int sampleNote=round(64.0+(128.0*12.0*log((double)targetRate/8363.0)/log(2.0))); int sampleNoteCoarse=60+(sampleNote>>7);