mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-29 07:53:01 +00:00
SNES: add an option to not encode BRR with unstable filters
This is useful for seeking to anywhere within the sample using sample offset commands
This commit is contained in:
parent
6a7e7ba571
commit
bdc66ae33e
9 changed files with 40 additions and 16 deletions
|
@ -586,6 +586,7 @@ size | description
|
||||||
| - 0: BRR emphasis
|
| - 0: BRR emphasis
|
||||||
1 | flags 2 (>=159) or reserved
|
1 | flags 2 (>=159) or reserved
|
||||||
| - 0: dither
|
| - 0: dither
|
||||||
|
| - 1: no BRR filters (>=213)
|
||||||
4 | loop start
|
4 | loop start
|
||||||
| - -1 means no loop
|
| - -1 means no loop
|
||||||
4 | loop end
|
4 | loop end
|
||||||
|
|
|
@ -138,7 +138,7 @@ void brrEncodeBlock(const short* buf, unsigned char* out, unsigned char range, u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigned char emphasis) {
|
long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigned char emphasis, unsigned char noFilter) {
|
||||||
if (len==0) return 0;
|
if (len==0) return 0;
|
||||||
|
|
||||||
// encoding process:
|
// encoding process:
|
||||||
|
@ -157,6 +157,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigne
|
||||||
long total=0;
|
long total=0;
|
||||||
unsigned char filter=0;
|
unsigned char filter=0;
|
||||||
unsigned char range=0;
|
unsigned char range=0;
|
||||||
|
unsigned char numFilters=noFilter?2:4;
|
||||||
|
|
||||||
short x0=0;
|
short x0=0;
|
||||||
short x1=0;
|
short x1=0;
|
||||||
|
@ -211,7 +212,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigne
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode
|
// encode
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<numFilters; j++) {
|
||||||
for (int k=0; k<13; k++) {
|
for (int k=0; k<13; k++) {
|
||||||
brrEncodeBlock(in,possibleOut[j][k],k,j,&last1[j][k],&last2[j][k],&avgError[j][k]);
|
brrEncodeBlock(in,possibleOut[j][k],k,j,&last1[j][k],&last2[j][k],&avgError[j][k]);
|
||||||
}
|
}
|
||||||
|
@ -228,7 +229,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigne
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<numFilters; j++) {
|
||||||
for (int k=0; k<13; k++) {
|
for (int k=0; k<13; k++) {
|
||||||
if (avgError[j][k]<candError) {
|
if (avgError[j][k]<candError) {
|
||||||
candError=avgError[j][k];
|
candError=avgError[j][k];
|
||||||
|
@ -245,7 +246,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigne
|
||||||
out[j+1]=possibleOut[filter][range][j];
|
out[j+1]=possibleOut[filter][range][j];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<numFilters; j++) {
|
||||||
for (int k=0; k<13; k++) {
|
for (int k=0; k<13; k++) {
|
||||||
last1[j][k]=last1[filter][range];
|
last1[j][k]=last1[filter][range];
|
||||||
last2[j][k]=last2[filter][range];
|
last2[j][k]=last2[filter][range];
|
||||||
|
|
|
@ -34,9 +34,10 @@ extern "C" {
|
||||||
* @param len input length (should be a multiple of 16. if it isn't, the output will be padded).
|
* @param len input length (should be a multiple of 16. if it isn't, the output will be padded).
|
||||||
* @param loopStart beginning of loop area (may be -1 for no loop). this is used to ensure the respective block has no filter in order to loop properly.
|
* @param loopStart beginning of loop area (may be -1 for no loop). this is used to ensure the respective block has no filter in order to loop properly.
|
||||||
* @param emphasis apply filter to compensate for Gaussian interpolation high frequency loss.
|
* @param emphasis apply filter to compensate for Gaussian interpolation high frequency loss.
|
||||||
|
* @param noFilter do not use filters in any block. this is used to allow seeking to any sample position.
|
||||||
* @return number of written samples.
|
* @return number of written samples.
|
||||||
*/
|
*/
|
||||||
long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigned char emphasis);
|
long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigned char emphasis, unsigned char noFilter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read len bytes from buf, decode BRR and output to out.
|
* read len bytes from buf, decode BRR and output to out.
|
||||||
|
|
|
@ -54,8 +54,8 @@ class DivWorkPool;
|
||||||
|
|
||||||
//#define DIV_UNSTABLE
|
//#define DIV_UNSTABLE
|
||||||
|
|
||||||
#define DIV_VERSION "0.6.4"
|
#define DIV_VERSION "dev213"
|
||||||
#define DIV_ENGINE_VERSION 212
|
#define DIV_ENGINE_VERSION 213
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
#define DIV_VERSION_FC 0xff02
|
#define DIV_VERSION_FC 0xff02
|
||||||
|
|
|
@ -261,6 +261,7 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
||||||
w->writeText(fmt::sprintf(" - mode: %s\n",sampleLoopModes[sample->loopMode&3]));
|
w->writeText(fmt::sprintf(" - mode: %s\n",sampleLoopModes[sample->loopMode&3]));
|
||||||
}
|
}
|
||||||
w->writeText(fmt::sprintf("- BRR emphasis: %s\n",trueFalse[sample->brrEmphasis?1:0]));
|
w->writeText(fmt::sprintf("- BRR emphasis: %s\n",trueFalse[sample->brrEmphasis?1:0]));
|
||||||
|
w->writeText(fmt::sprintf("- no BRR filters: %s\n",trueFalse[sample->brrNoFilter?1:0]));
|
||||||
w->writeText(fmt::sprintf("- dither: %s\n",trueFalse[sample->dither?1:0]));
|
w->writeText(fmt::sprintf("- dither: %s\n",trueFalse[sample->dither?1:0]));
|
||||||
|
|
||||||
// TODO' render matrix
|
// TODO' render matrix
|
||||||
|
|
|
@ -56,7 +56,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(dither);
|
w->writeC((dither?1:0)|(brrNoFilter?2:0));
|
||||||
w->writeI(loop?loopStart:-1);
|
w->writeI(loop?loopStart:-1);
|
||||||
w->writeI(loop?loopEnd:-1);
|
w->writeI(loop?loopEnd:-1);
|
||||||
|
|
||||||
|
@ -134,7 +134,9 @@ DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) {
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
if (version>=159) {
|
if (version>=159) {
|
||||||
dither=reader.readC()&1;
|
signed char c=reader.readC();
|
||||||
|
dither=c&1;
|
||||||
|
if (version>=213) brrNoFilter=c&2;
|
||||||
} else {
|
} else {
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
|
@ -1423,7 +1425,7 @@ void DivSample::render(unsigned int formatMask) {
|
||||||
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR
|
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR
|
||||||
int sampleCount=loop?loopEnd:samples;
|
int sampleCount=loop?loopEnd:samples;
|
||||||
if (!initInternal(DIV_SAMPLE_DEPTH_BRR,sampleCount)) return;
|
if (!initInternal(DIV_SAMPLE_DEPTH_BRR,sampleCount)) return;
|
||||||
brrEncode(data16,dataBRR,sampleCount,loop?loopStart:-1,brrEmphasis);
|
brrEncode(data16,dataBRR,sampleCount,loop?loopStart:-1,brrEmphasis,brrNoFilter);
|
||||||
}
|
}
|
||||||
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_VOX)) { // VOX
|
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_VOX)) { // VOX
|
||||||
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
||||||
|
@ -1564,9 +1566,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,dither,loopMode);
|
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,brrNoFilter,dither,loopMode);
|
||||||
} else {
|
} else {
|
||||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,dither,loopMode);
|
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,brrNoFilter,dither,loopMode);
|
||||||
}
|
}
|
||||||
if (!doNotPush) {
|
if (!doNotPush) {
|
||||||
while (!redoHist.empty()) {
|
while (!redoHist.empty()) {
|
||||||
|
@ -1600,6 +1602,7 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
||||||
loopEnd=h->loopEnd; \
|
loopEnd=h->loopEnd; \
|
||||||
loop=h->loop; \
|
loop=h->loop; \
|
||||||
brrEmphasis=h->brrEmphasis; \
|
brrEmphasis=h->brrEmphasis; \
|
||||||
|
brrNoFilter=h->brrNoFilter; \
|
||||||
dither=h->dither; \
|
dither=h->dither; \
|
||||||
loopMode=h->loopMode;
|
loopMode=h->loopMode;
|
||||||
|
|
||||||
|
|
|
@ -65,10 +65,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, dither;
|
bool loop, brrEmphasis, brrNoFilter, 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, bool di, 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 bf, bool di, DivSampleLoopMode lm):
|
||||||
data((unsigned char*)d),
|
data((unsigned char*)d),
|
||||||
length(l),
|
length(l),
|
||||||
samples(s),
|
samples(s),
|
||||||
|
@ -79,10 +79,11 @@ struct DivSampleHistory {
|
||||||
loopEnd(le),
|
loopEnd(le),
|
||||||
loop(lp),
|
loop(lp),
|
||||||
brrEmphasis(be),
|
brrEmphasis(be),
|
||||||
|
brrNoFilter(bf),
|
||||||
dither(di),
|
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, bool di, DivSampleLoopMode lm):
|
DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, bool bf, bool di, DivSampleLoopMode lm):
|
||||||
data(NULL),
|
data(NULL),
|
||||||
length(0),
|
length(0),
|
||||||
samples(0),
|
samples(0),
|
||||||
|
@ -93,6 +94,7 @@ struct DivSampleHistory {
|
||||||
loopEnd(le),
|
loopEnd(le),
|
||||||
loop(lp),
|
loop(lp),
|
||||||
brrEmphasis(be),
|
brrEmphasis(be),
|
||||||
|
brrNoFilter(bf),
|
||||||
dither(di),
|
dither(di),
|
||||||
loopMode(lm),
|
loopMode(lm),
|
||||||
hasSample(false) {}
|
hasSample(false) {}
|
||||||
|
@ -118,7 +120,7 @@ struct DivSample {
|
||||||
// - 13: IMA ADPCM
|
// - 13: IMA ADPCM
|
||||||
// - 16: 16-bit PCM
|
// - 16: 16-bit PCM
|
||||||
DivSampleDepth depth;
|
DivSampleDepth depth;
|
||||||
bool loop, brrEmphasis, dither;
|
bool loop, brrEmphasis, brrNoFilter, dither;
|
||||||
// valid values are:
|
// valid values are:
|
||||||
// - 0: Forward loop
|
// - 0: Forward loop
|
||||||
// - 1: Backward loop
|
// - 1: Backward loop
|
||||||
|
@ -337,6 +339,7 @@ struct DivSample {
|
||||||
depth(DIV_SAMPLE_DEPTH_16BIT),
|
depth(DIV_SAMPLE_DEPTH_16BIT),
|
||||||
loop(false),
|
loop(false),
|
||||||
brrEmphasis(true),
|
brrEmphasis(true),
|
||||||
|
brrNoFilter(false),
|
||||||
dither(false),
|
dither(false),
|
||||||
loopMode(DIV_SAMPLE_LOOP_FORWARD),
|
loopMode(DIV_SAMPLE_LOOP_FORWARD),
|
||||||
data8(NULL),
|
data8(NULL),
|
||||||
|
|
|
@ -931,6 +931,7 @@ void FurnaceGUI::doAction(int what) {
|
||||||
sample->loop=prevSample->loop;
|
sample->loop=prevSample->loop;
|
||||||
sample->loopMode=prevSample->loopMode;
|
sample->loopMode=prevSample->loopMode;
|
||||||
sample->brrEmphasis=prevSample->brrEmphasis;
|
sample->brrEmphasis=prevSample->brrEmphasis;
|
||||||
|
sample->brrNoFilter=prevSample->brrNoFilter;
|
||||||
sample->dither=prevSample->dither;
|
sample->dither=prevSample->dither;
|
||||||
sample->depth=prevSample->depth;
|
sample->depth=prevSample->depth;
|
||||||
if (sample->init(prevSample->samples)) {
|
if (sample->init(prevSample->samples)) {
|
||||||
|
|
|
@ -541,6 +541,19 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sample->depth!=DIV_SAMPLE_DEPTH_BRR && isThereSNES) {
|
||||||
|
bool bf=sample->brrNoFilter;
|
||||||
|
if (ImGui::Checkbox(_("no BRR filters"),&bf)) {
|
||||||
|
sample->prepareUndo(true);
|
||||||
|
sample->brrNoFilter=bf;
|
||||||
|
e->renderSamplesP(curSample);
|
||||||
|
updateSampleTex=true;
|
||||||
|
MARK_MODIFIED;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(_("enable this option to not use BRR blocks with filters\nand allow sample offset commands to be used safely."));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && e->getSampleFormatMask()&(1L<<DIV_SAMPLE_DEPTH_8BIT)) {
|
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && e->getSampleFormatMask()&(1L<<DIV_SAMPLE_DEPTH_8BIT)) {
|
||||||
bool di=sample->dither;
|
bool di=sample->dither;
|
||||||
if (ImGui::Checkbox(_("8-bit dither"),&di)) {
|
if (ImGui::Checkbox(_("8-bit dither"),&di)) {
|
||||||
|
|
Loading…
Reference in a new issue