BRR loop fixes!

This commit is contained in:
tildearrow 2022-12-05 19:13:21 -05:00
parent 2dd8886db1
commit 0f63db2dac
4 changed files with 69 additions and 12 deletions

View File

@ -171,10 +171,24 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
memset(avgError,0,4*13*sizeof(int));
memset(possibleOut,0,4*13*8);
len&=~15;
loopStart&=~15;
for (long i=0; i<len; i+=16) {
memcpy(in,buf,16*sizeof(short));
if (i+16>len) {
long p=i;
for (int j=0; j<16; j++) {
if (p>=len) {
if (loopStart<0 || loopStart>=len) {
in[j]=0;
} else {
p=loopStart;
in[j]=buf[p++];
}
} else {
in[j]=buf[p++];
}
}
} else {
memcpy(in,&buf[i],16*sizeof(short));
}
// encode
for (int j=0; j<4; j++) {
@ -206,7 +220,51 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
}
// write
out[0]=(range<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0);
out[0]=(range<<4)|(filter<<2)|((i+16>=len && loopStart<0)?1:0);
for (int j=0; j<8; j++) {
out[j+1]=possibleOut[filter][range][j];
}
for (int j=0; j<4; j++) {
for (int k=0; k<13; k++) {
last1[j][k]=last1[filter][range];
last2[j][k]=last2[filter][range];
}
}
out+=9;
total+=9;
}
// encode loop block
if (loopStart>=0) {
long p=loopStart;
for (int i=0; i<16; i++) {
if (p>=len) {
p=loopStart;
}
in[i]=buf[p++];
}
// encode (filter 0/1 only)
for (int j=0; j<2; j++) {
for (int k=0; k<13; k++) {
brrEncodeBlock(in,possibleOut[j][k],k,j,&last1[j][k],&last2[j][k],&avgError[j][k]);
}
}
// find best filter/range
int candError=0x7fffffff;
for (int j=0; j<2; j++) {
for (int k=0; k<13; k++) {
if (avgError[j][k]<candError) {
candError=avgError[j][k];
filter=j;
range=k;
}
}
}
// write
out[0]=(range<<4)|(filter<<2)|3;
for (int j=0; j<8; j++) {
out[j+1]=possibleOut[filter][range][j];
}
@ -217,7 +275,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
last2[j][k]=last2[filter][range];
}
}
buf+=16;
out+=9;
total+=9;
}

View File

@ -30,7 +30,7 @@ extern "C" {
/**
* read len samples from buf, encode in BRR and output to out.
* @param buf input data.
* @param out output buffer. shall be at least 9*(len/16) shorts in size.
* @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.
* @return number of written samples.

View File

@ -214,13 +214,13 @@ void DivPlatformSNES::tick(bool sysTick) {
loop=start;
} else if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
start=sampleOff[chan[i].sample];
end=MIN(start+MAX(s->lengthBRR,1),getSampleMemCapacity());
end=MIN(start+MAX(s->lengthBRR+((s->loop && s->depth!=DIV_SAMPLE_DEPTH_BRR)?9:0),1),getSampleMemCapacity());
loop=MAX(start,end-1);
if (chan[i].audPos>0) {
start=start+MIN(chan[i].audPos,s->lengthBRR-1)/16*9;
}
if (s->loopStart>=0) {
loop=start+s->loopStart/16*9;
loop=((s->depth!=DIV_SAMPLE_DEPTH_BRR)?9:0)+start+((s->loopStart/16)*9);
}
} else {
start=0;
@ -817,7 +817,7 @@ void DivPlatformSNES::renderSamples(int sysID) {
continue;
}
int length=s->lengthBRR;
int length=s->lengthBRR+((s->loop && s->depth!=DIV_SAMPLE_DEPTH_BRR)?9:0);
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
if (actualLength>0) {
sampleOff[i]=memPos;

View File

@ -490,8 +490,8 @@ bool DivSample::initInternal(DivSampleDepth d, int count) {
case DIV_SAMPLE_DEPTH_BRR: // BRR
if (dataBRR!=NULL) delete[] dataBRR;
lengthBRR=9*((count+15)/16);
dataBRR=new unsigned char[lengthBRR];
memset(dataBRR,0,lengthBRR);
dataBRR=new unsigned char[lengthBRR+9];
memset(dataBRR,0,lengthBRR+9);
break;
case DIV_SAMPLE_DEPTH_VOX: // VOX
if (dataVOX!=NULL) delete[] dataVOX;
@ -1100,7 +1100,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+15)&(~15),loop?loopStart:-1);
brrEncode(data16,dataBRR,samples,loop?loopStart:-1);
}
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_VOX)) { // VOX
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;