dev129 - SNES: add option to toggle BRR emphasis
This commit is contained in:
parent
b149d1b92e
commit
056e67b228
|
@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 129: Furnace dev129
|
||||
- 128: Furnace dev128
|
||||
- 127: Furnace dev127
|
||||
- 126: Furnace dev126
|
||||
- 125: Furnace dev125
|
||||
|
@ -1120,9 +1122,11 @@ size | description
|
|||
| - 16: 16-bit PCM
|
||||
1 | loop direction (>=123) or reserved
|
||||
| - 0: forward
|
||||
| - 0: backward
|
||||
| - 0: ping-pong
|
||||
2 | reserved
|
||||
| - 1: backward
|
||||
| - 2: ping-pong
|
||||
1 | flags (>=129) or reserved
|
||||
| - 0: BRR emphasis
|
||||
1 | reserved
|
||||
4 | loop start
|
||||
| - -1 means no loop
|
||||
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) {
|
||||
long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigned char emphasis) {
|
||||
if (len==0) return 0;
|
||||
|
||||
// encoding process:
|
||||
|
@ -158,7 +158,12 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
|||
unsigned char filter=0;
|
||||
unsigned char range=0;
|
||||
|
||||
short in[16];
|
||||
short x0=0;
|
||||
short x1=0;
|
||||
short x2=0;
|
||||
int emphOut=0;
|
||||
|
||||
short in[17];
|
||||
|
||||
short last1[4][13];
|
||||
short last2[4][13];
|
||||
|
@ -172,9 +177,9 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
|||
memset(possibleOut,0,4*13*8);
|
||||
|
||||
for (long i=0; i<len; i+=16) {
|
||||
if (i+16>len) {
|
||||
if (i+17>len) {
|
||||
long p=i;
|
||||
for (int j=0; j<16; j++) {
|
||||
for (int j=0; j<17; j++) {
|
||||
if (p>=len) {
|
||||
if (loopStart<0 || loopStart>=len) {
|
||||
in[j]=0;
|
||||
|
@ -187,7 +192,22 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
memcpy(in,&buf[i],16*sizeof(short));
|
||||
memcpy(in,&buf[i],17*sizeof(short));
|
||||
}
|
||||
|
||||
// emphasis
|
||||
if (emphasis) {
|
||||
for (int j=0; j<17; j++) {
|
||||
x0=x1;
|
||||
x1=x2;
|
||||
x2=in[j];
|
||||
|
||||
if (j==0) continue;
|
||||
emphOut=((x1<<11)-x0*370-in[j]*374)/1305;
|
||||
if (emphOut<-32768) emphOut=-32768;
|
||||
if (emphOut>32767) emphOut=32767;
|
||||
in[j-1]=emphOut;
|
||||
}
|
||||
}
|
||||
|
||||
// encode
|
||||
|
@ -237,13 +257,27 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
|||
// encode loop block
|
||||
if (loopStart>=0) {
|
||||
long p=loopStart;
|
||||
for (int i=0; i<16; i++) {
|
||||
for (int i=0; i<17; i++) {
|
||||
if (p>=len) {
|
||||
p=loopStart;
|
||||
}
|
||||
in[i]=buf[p++];
|
||||
}
|
||||
|
||||
if (emphasis) {
|
||||
for (int j=0; j<17; j++) {
|
||||
x0=x1;
|
||||
x1=x2;
|
||||
x2=in[j];
|
||||
|
||||
if (j==0) continue;
|
||||
emphOut=((x1<<11)-x0*370-in[j]*374)/1305;
|
||||
if (emphOut<-32768) emphOut=-32768;
|
||||
if (emphOut>32767) emphOut=32767;
|
||||
in[j-1]=emphOut;
|
||||
}
|
||||
}
|
||||
|
||||
// encode (filter 0/1 only)
|
||||
for (int j=0; j<2; j++) {
|
||||
for (int k=0; k<13; k++) {
|
||||
|
@ -315,9 +349,11 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
|||
*out=next<<1; \
|
||||
out++;
|
||||
|
||||
long brrDecode(unsigned char* buf, short* out, long len) {
|
||||
long brrDecode(unsigned char* buf, short* out, long len, unsigned char emphasis) {
|
||||
if (len==0) return 0;
|
||||
|
||||
short* outOrig=out;
|
||||
|
||||
long total=0;
|
||||
|
||||
int last1=0;
|
||||
|
@ -344,5 +380,20 @@ long brrDecode(unsigned char* buf, short* out, long len) {
|
|||
buf+=9;
|
||||
}
|
||||
|
||||
if (emphasis) {
|
||||
short x0=0;
|
||||
short x1=0;
|
||||
short x2=0;
|
||||
for (long i=0; i<=total; i++) {
|
||||
x0=x1;
|
||||
x1=x2;
|
||||
x2=(i>=total)?0:outOrig[i];
|
||||
|
||||
if (i==0) continue;
|
||||
|
||||
outOrig[i-1]=(x0*370+x1*1305+x2*374)>>11;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
|
|
@ -33,18 +33,20 @@ extern "C" {
|
|||
* @param out output buffer. shall be at least 9*((15+len)/16) shorts in size (9 more if loopStart is not -1!)
|
||||
* @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 emphasis apply filter to compensate for Gaussian interpolation high frequency loss.
|
||||
* @return number of written samples.
|
||||
*/
|
||||
long brrEncode(short* buf, unsigned char* out, long len, long loopStart);
|
||||
long brrEncode(short* buf, unsigned char* out, long len, long loopStart, unsigned char emphasis);
|
||||
|
||||
/**
|
||||
* read len bytes from buf, decode BRR and output to out.
|
||||
* @param buf input data.
|
||||
* @param out output buffer. shall be at least 16*(len/9) shorts in size.
|
||||
* @param len input length (shall be a multiple of 9).
|
||||
* @param emphasis apply filter to simulate Gaussian interpolation high frequency loss.
|
||||
* @return number of written bytes.
|
||||
*/
|
||||
long brrDecode(unsigned char* buf, short* out, long len);
|
||||
long brrDecode(unsigned char* buf, short* out, long len, unsigned char emphasis);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -47,8 +47,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev128"
|
||||
#define DIV_ENGINE_VERSION 128
|
||||
#define DIV_VERSION "dev129"
|
||||
#define DIV_ENGINE_VERSION 129
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
|
@ -52,8 +52,8 @@ void DivSample::putSampleData(SafeWriter* w) {
|
|||
w->writeI(centerRate);
|
||||
w->writeC(depth);
|
||||
w->writeC(loopMode);
|
||||
w->writeC(brrEmphasis);
|
||||
w->writeC(0); // reserved
|
||||
w->writeC(0);
|
||||
w->writeI(loop?loopStart:-1);
|
||||
w->writeI(loop?loopEnd:-1);
|
||||
|
||||
|
@ -125,9 +125,13 @@ DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) {
|
|||
reader.readC();
|
||||
}
|
||||
|
||||
if (version>=129) {
|
||||
brrEmphasis=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
// reserved
|
||||
reader.readC();
|
||||
reader.readC();
|
||||
|
||||
loopStart=reader.readI();
|
||||
loopEnd=reader.readI();
|
||||
|
@ -1041,7 +1045,7 @@ void DivSample::render(unsigned int formatMask) {
|
|||
}
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_BRR: // BRR
|
||||
brrDecode(dataBRR,data16,lengthBRR);
|
||||
brrDecode(dataBRR,data16,lengthBRR,brrEmphasis);
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
||||
oki_decode(dataVOX,data16,samples);
|
||||
|
@ -1100,7 +1104,7 @@ void DivSample::render(unsigned int formatMask) {
|
|||
}
|
||||
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_BRR,samples)) return;
|
||||
brrEncode(data16,dataBRR,samples,loop?loopStart:-1);
|
||||
brrEncode(data16,dataBRR,samples,loop?loopStart:-1,brrEmphasis);
|
||||
}
|
||||
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_VOX)) { // VOX
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
||||
|
@ -1174,9 +1178,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,loopMode);
|
||||
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,loopMode);
|
||||
} else {
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,loopMode);
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,loopMode);
|
||||
}
|
||||
if (!doNotPush) {
|
||||
while (!redoHist.empty()) {
|
||||
|
|
|
@ -60,10 +60,10 @@ struct DivSampleHistory {
|
|||
unsigned int length, samples;
|
||||
DivSampleDepth depth;
|
||||
int rate, centerRate, loopStart, loopEnd;
|
||||
bool loop;
|
||||
bool loop, brrEmphasis;
|
||||
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, 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, DivSampleLoopMode lm):
|
||||
data((unsigned char*)d),
|
||||
length(l),
|
||||
samples(s),
|
||||
|
@ -73,9 +73,10 @@ struct DivSampleHistory {
|
|||
loopStart(ls),
|
||||
loopEnd(le),
|
||||
loop(lp),
|
||||
brrEmphasis(be),
|
||||
loopMode(lm),
|
||||
hasSample(true) {}
|
||||
DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm):
|
||||
DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, DivSampleLoopMode lm):
|
||||
data(NULL),
|
||||
length(0),
|
||||
samples(0),
|
||||
|
@ -85,6 +86,7 @@ struct DivSampleHistory {
|
|||
loopStart(ls),
|
||||
loopEnd(le),
|
||||
loop(lp),
|
||||
brrEmphasis(be),
|
||||
loopMode(lm),
|
||||
hasSample(false) {}
|
||||
~DivSampleHistory();
|
||||
|
@ -106,7 +108,7 @@ struct DivSample {
|
|||
// - 10: VOX ADPCM
|
||||
// - 16: 16-bit PCM
|
||||
DivSampleDepth depth;
|
||||
bool loop;
|
||||
bool loop, brrEmphasis;
|
||||
// valid values are:
|
||||
// - 0: Forward loop
|
||||
// - 1: Backward loop
|
||||
|
@ -306,6 +308,7 @@ struct DivSample {
|
|||
loopOffP(0),
|
||||
depth(DIV_SAMPLE_DEPTH_16BIT),
|
||||
loop(false),
|
||||
brrEmphasis(true),
|
||||
loopMode(DIV_SAMPLE_LOOP_FORWARD),
|
||||
data8(NULL),
|
||||
data16(NULL),
|
||||
|
|
|
@ -190,6 +190,31 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
bool isThereSNES=false;
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
if (e->song.system[i]==DIV_SYSTEM_SNES) {
|
||||
isThereSNES=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_BRR || isThereSNES) {
|
||||
bool be=sample->brrEmphasis;
|
||||
if (ImGui::Checkbox("BRR emphasis",&be)) {
|
||||
sample->prepareUndo(true);
|
||||
sample->brrEmphasis=be;
|
||||
e->renderSamplesP();
|
||||
updateSampleTex=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_BRR) {
|
||||
ImGui::SetTooltip("this is a BRR sample.\nenabling this option will muffle it (only affects non-SNES chips).");
|
||||
} else {
|
||||
ImGui::SetTooltip("enable this option to slightly boost high frequencies\nto compensate for the SNES' Gaussian filter's muffle.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("C-4 (Hz)");
|
||||
ImGui::SameLine();
|
||||
|
|
Loading…
Reference in New Issue