dev159 - add 8-bit dither option
This commit is contained in:
parent
8d07441d2e
commit
5e0eb9aa23
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue