dev159 - add 8-bit dither option

This commit is contained in:
tildearrow 2023-06-05 04:28:07 -05:00
parent 8d07441d2e
commit 5e0eb9aa23
6 changed files with 54 additions and 14 deletions

View file

@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
the format versions are: the format versions are:
- 159: Furnace dev159
- 158: Furnace 0.6pre5 - 158: Furnace 0.6pre5
- 157: Furnace dev157 - 157: Furnace dev157
- 156: Furnace dev156 - 156: Furnace dev156
@ -1232,7 +1233,8 @@ size | description
| - 2: ping-pong | - 2: ping-pong
1 | flags (>=129) or reserved 1 | flags (>=129) or reserved
| - 0: BRR emphasis | - 0: BRR emphasis
1 | reserved 1 | flags 2 (>=159) or reserved
| - 0: dither
4 | loop start 4 | loop start
| - -1 means no loop | - -1 means no loop
4 | loop end 4 | loop end

View file

@ -54,8 +54,8 @@
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock(); #define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; #define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
#define DIV_VERSION "0.6pre5" #define DIV_VERSION "dev159"
#define DIV_ENGINE_VERSION 158 #define DIV_ENGINE_VERSION 159
// for imports // for imports
#define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02 #define DIV_VERSION_FC 0xff02

View file

@ -54,7 +54,7 @@ void DivSample::putSampleData(SafeWriter* w) {
w->writeC(depth); w->writeC(depth);
w->writeC(loopMode); w->writeC(loopMode);
w->writeC(brrEmphasis); w->writeC(brrEmphasis);
w->writeC(0); // reserved w->writeC(dither);
w->writeI(loop?loopStart:-1); w->writeI(loop?loopStart:-1);
w->writeI(loop?loopEnd:-1); w->writeI(loop?loopEnd:-1);
@ -131,8 +131,11 @@ DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) {
} else { } else {
reader.readC(); reader.readC();
} }
// reserved if (version>=159) {
reader.readC(); dither=reader.readC()&1;
} else {
reader.readC();
}
loopStart=reader.readI(); loopStart=reader.readI();
loopEnd=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 (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_8BIT)) { // 8-bit PCM
if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return; if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return;
for (unsigned int i=0; i<samples; i++) { if (dither) {
data8[i]=data16[i]>>8; unsigned short lfsr=0x6438;
unsigned short lfsr1=0x1283;
signed char errorLast=0;
signed char errorCur=0;
for (unsigned int i=0; i<samples; i++) {
signed char val=CLAMP(data16[i]+128,-32768,32767)>>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<samples; i++) {
data8[i]=data16[i]>>8;
}
} }
} }
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR 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()]; duplicate=new unsigned char[getCurBufLen()];
memcpy(duplicate,getCurBuf(),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 { } 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) { if (!doNotPush) {
while (!redoHist.empty()) { while (!redoHist.empty()) {
@ -1312,6 +1330,8 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
loopStart=h->loopStart; \ loopStart=h->loopStart; \
loopEnd=h->loopEnd; \ loopEnd=h->loopEnd; \
loop=h->loop; \ loop=h->loop; \
brrEmphasis=h->brrEmphasis; \
dither=h->dither; \
loopMode=h->loopMode; loopMode=h->loopMode;

View file

@ -61,10 +61,10 @@ struct DivSampleHistory {
unsigned int length, samples; unsigned int length, samples;
DivSampleDepth depth; DivSampleDepth depth;
int rate, centerRate, loopStart, loopEnd; int rate, centerRate, loopStart, loopEnd;
bool loop, brrEmphasis; bool loop, brrEmphasis, dither;
DivSampleLoopMode loopMode; DivSampleLoopMode loopMode;
bool hasSample; 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), data((unsigned char*)d),
length(l), length(l),
samples(s), samples(s),
@ -75,9 +75,10 @@ struct DivSampleHistory {
loopEnd(le), loopEnd(le),
loop(lp), loop(lp),
brrEmphasis(be), brrEmphasis(be),
dither(di),
loopMode(lm), loopMode(lm),
hasSample(true) {} 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), data(NULL),
length(0), length(0),
samples(0), samples(0),
@ -88,6 +89,7 @@ struct DivSampleHistory {
loopEnd(le), loopEnd(le),
loop(lp), loop(lp),
brrEmphasis(be), brrEmphasis(be),
dither(di),
loopMode(lm), loopMode(lm),
hasSample(false) {} hasSample(false) {}
~DivSampleHistory(); ~DivSampleHistory();
@ -108,7 +110,7 @@ struct DivSample {
// - 10: VOX ADPCM // - 10: VOX ADPCM
// - 16: 16-bit PCM // - 16: 16-bit PCM
DivSampleDepth depth; DivSampleDepth depth;
bool loop, brrEmphasis; bool loop, brrEmphasis, dither;
// valid values are: // valid values are:
// - 0: Forward loop // - 0: Forward loop
// - 1: Backward loop // - 1: Backward loop
@ -323,6 +325,7 @@ struct DivSample {
depth(DIV_SAMPLE_DEPTH_16BIT), depth(DIV_SAMPLE_DEPTH_16BIT),
loop(false), loop(false),
brrEmphasis(true), brrEmphasis(true),
dither(false),
loopMode(DIV_SAMPLE_LOOP_FORWARD), loopMode(DIV_SAMPLE_LOOP_FORWARD),
data8(NULL), data8(NULL),
data16(NULL), data16(NULL),

View file

@ -791,6 +791,8 @@ void FurnaceGUI::doAction(int what) {
sample->loopEnd=prevSample->loopEnd; sample->loopEnd=prevSample->loopEnd;
sample->loop=prevSample->loop; sample->loop=prevSample->loop;
sample->loopMode=prevSample->loopMode; sample->loopMode=prevSample->loopMode;
sample->brrEmphasis=prevSample->brrEmphasis;
sample->dither=prevSample->dither;
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) {

View file

@ -291,6 +291,19 @@ void FurnaceGUI::drawSampleEdit() {
} }
} }
} }
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && e->getSampleFormatMask()&(1L<<DIV_SAMPLE_DEPTH_8BIT)) {
bool di=sample->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 sampleNote=round(64.0+(128.0*12.0*log((double)targetRate/8363.0)/log(2.0)));
int sampleNoteCoarse=60+(sampleNote>>7); int sampleNoteCoarse=60+(sampleNote>>7);