Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
9ce00f18e6
|
@ -126,7 +126,7 @@ void k007232_core::voice_t::write(u8 address, u8 data)
|
||||||
m_start = (m_start & ~0x0ff00) | (u32(data) << 8);
|
m_start = (m_start & ~0x0ff00) | (u32(data) << 8);
|
||||||
break;
|
break;
|
||||||
case 4: // start address bit 16
|
case 4: // start address bit 16
|
||||||
m_start = (m_start & ~0x10000) | (u32(bitfield(data, 16)) << 16);
|
m_start = (m_start & ~0x10000) | (u32(bitfield(data, 0)) << 16);
|
||||||
break;
|
break;
|
||||||
case 5: // keyon trigger
|
case 5: // keyon trigger
|
||||||
keyon();
|
keyon();
|
||||||
|
|
|
@ -106,6 +106,13 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
|
||||||
audioSysStarted=true;
|
audioSysStarted=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* audioDriver=SDL_GetCurrentAudioDriver();
|
||||||
|
if (audioDriver==NULL) {
|
||||||
|
logD("SDL audio driver: NULL!");
|
||||||
|
} else {
|
||||||
|
logD("SDL audio driver: %s",audioDriver);
|
||||||
|
}
|
||||||
|
|
||||||
desc=request;
|
desc=request;
|
||||||
desc.outFormat=TA_AUDIO_FORMAT_F32;
|
desc.outFormat=TA_AUDIO_FORMAT_F32;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "brrUtils.h"
|
#include "brrUtils.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define NEXT_SAMPLE buf[j]-(buf[j]>>3)
|
#define NEXT_SAMPLE buf[j]-(buf[j]>>3)
|
||||||
|
|
||||||
|
@ -56,6 +58,86 @@
|
||||||
last2=last1; \
|
last2=last1; \
|
||||||
last1=nextDec; \
|
last1=nextDec; \
|
||||||
|
|
||||||
|
void brrEncodeBlock(const short* buf, unsigned char* out, unsigned char range, unsigned char filter, short* last1, short* last2, int* errorSum) {
|
||||||
|
// encode one block using BRR
|
||||||
|
unsigned char nibble=0;
|
||||||
|
int preOut=0;
|
||||||
|
int pred=0;
|
||||||
|
int nextDec=0;
|
||||||
|
int nextError=0;
|
||||||
|
*errorSum=0;
|
||||||
|
for (int j=0; j<16; j++) {
|
||||||
|
short s=NEXT_SAMPLE;
|
||||||
|
switch (filter) {
|
||||||
|
case 0: // no filter
|
||||||
|
pred=s;
|
||||||
|
break;
|
||||||
|
case 1: // simple
|
||||||
|
pred=s-(((int)(*last1*2)*15)>>4);
|
||||||
|
break;
|
||||||
|
case 2: // complex
|
||||||
|
pred=s+(((int)(*last2*2)*15)>>4)-(((int)(*last1*2)*61)>>5);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pred=s+(((int)(*last2*2)*13)>>4)-(((int)(*last1*2)*115)>>6);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pred<-32768) pred=-32768;
|
||||||
|
if (pred>32767) pred=32767;
|
||||||
|
|
||||||
|
preOut=pred>>range;
|
||||||
|
if (range) {
|
||||||
|
if (pred&(1<<(range>>1))) preOut++;
|
||||||
|
if (filter==0 && range>=12) if (preOut<-7) preOut=-7;
|
||||||
|
}
|
||||||
|
if (preOut>7) preOut=7;
|
||||||
|
if (preOut<-8) preOut=-8;
|
||||||
|
|
||||||
|
nibble=preOut&15;
|
||||||
|
if (j&1) {
|
||||||
|
out[j>>1]|=nibble;
|
||||||
|
} else {
|
||||||
|
out[j>>1]=nibble<<4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// roll last1/last2
|
||||||
|
nextDec=nibble;
|
||||||
|
if (nextDec&8) nextDec|=0xfffffff0;
|
||||||
|
|
||||||
|
if (range>=13) { /* invalid shift */
|
||||||
|
nextDec=(nextDec<0)?0xfffff800:0;
|
||||||
|
} else {
|
||||||
|
nextDec<<=range; /* range */
|
||||||
|
nextDec>>=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (filter) { /* filter */
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
nextDec+=(*last1)+((-(*last1))>>4);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
nextDec+=(*last1)*2+((-(*last1)*3)>>5)-(*last2)+((*last2)>>4);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
nextDec+=(*last1)*2+((-(*last1)*13)>>6)-(*last2)+(((*last2)*3)>>4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextDec&=0x7fff;
|
||||||
|
if (nextDec&0x4000) nextDec|=0xffff8000;
|
||||||
|
|
||||||
|
nextError=s-(nextDec<<1);
|
||||||
|
if (nextError<0) nextError=-nextError;
|
||||||
|
*errorSum+=nextError;
|
||||||
|
|
||||||
|
*last2=*last1;
|
||||||
|
*last1=nextDec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
||||||
if (len==0) return 0;
|
if (len==0) return 0;
|
||||||
|
|
||||||
|
@ -63,377 +145,136 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
||||||
// 1. read next group of 16 samples
|
// 1. read next group of 16 samples
|
||||||
// 2. is this the first block?
|
// 2. is this the first block?
|
||||||
// - if yes, don't filter. output and then go to 1
|
// - if yes, don't filter. output and then go to 1
|
||||||
// 3. is this the loop block?
|
// 4. try encoding using 3 filters and 12 ranges (besides no filter)
|
||||||
// - if yes, don't filter. output and then go to 1
|
|
||||||
// 4. try encoding using 4 filters
|
|
||||||
// - perform linear prediction
|
|
||||||
// - calculate range
|
|
||||||
// - decode and apply correction to achieve low error
|
|
||||||
// 5. which one of these yields the least amount of error?
|
// 5. which one of these yields the least amount of error?
|
||||||
// 6. output the one which does
|
// 6. output the one which does
|
||||||
// 7. is this the last block?
|
// 7. do we still have more to encode?
|
||||||
// - if yes, mark end and finish
|
// - if so, go to 1
|
||||||
// 8. go to 1
|
// 8. is loop point set?
|
||||||
|
// - if not, end process here
|
||||||
|
// 9. is transition between last block and loop block smooth?
|
||||||
|
// - if not, encode the loop block again and output it
|
||||||
long total=0;
|
long total=0;
|
||||||
unsigned char next0[8];
|
|
||||||
unsigned char next1[8];
|
|
||||||
unsigned char next2[8];
|
|
||||||
unsigned char next3[8];
|
|
||||||
unsigned char filter=0;
|
unsigned char filter=0;
|
||||||
unsigned char range0=0;
|
unsigned char range=0;
|
||||||
unsigned char range1=0;
|
|
||||||
unsigned char range2=0;
|
|
||||||
unsigned char range3=0;
|
|
||||||
unsigned char o=0;
|
|
||||||
int pred1[16];
|
|
||||||
int pred2[16];
|
|
||||||
int pred3[16];
|
|
||||||
short o1=0;
|
|
||||||
short o2=0;
|
|
||||||
short o0=0;
|
|
||||||
short o1f1=0;
|
|
||||||
short o1f2=0;
|
|
||||||
short o1f3=0;
|
|
||||||
//short o2f1=0;
|
|
||||||
short o2f2=0;
|
|
||||||
short o2f3=0;
|
|
||||||
|
|
||||||
int last1=0;
|
short in[16];
|
||||||
int last2=0;
|
|
||||||
int nextDec=0;
|
short last1[4][13];
|
||||||
int maxError[4];
|
short last2[4][13];
|
||||||
int avgError[4];
|
int avgError[4][13];
|
||||||
|
unsigned char possibleOut[4][13][8];
|
||||||
|
|
||||||
|
memset(in,0,16*sizeof(short));
|
||||||
|
memset(last1,0,4*13*sizeof(short));
|
||||||
|
memset(last2,0,4*13*sizeof(short));
|
||||||
|
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) {
|
for (long i=0; i<len; i+=16) {
|
||||||
range0=0;
|
if (i+16>len) {
|
||||||
// encode with no filter
|
long p=i;
|
||||||
for (int j=0; j<16; j++) {
|
for (int j=0; j<16; j++) {
|
||||||
short s=NEXT_SAMPLE;
|
if (p>=len) {
|
||||||
if (s<0) s=-s;
|
if (loopStart<0 || loopStart>=len) {
|
||||||
while (range0<12 && s>((8<<range0)-1)) range0++;
|
in[j]=0;
|
||||||
}
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
short s=NEXT_SAMPLE;
|
|
||||||
o0=s>>range0;
|
|
||||||
if (range0) if (s&(1<<(range1>>1))) o0++;
|
|
||||||
if (o0>7) o0=7;
|
|
||||||
if (o0<-8) o0=-8;
|
|
||||||
if (range0>=12) if (o0<-7) o0=-7;
|
|
||||||
o=o0&15;
|
|
||||||
if (j&1) {
|
|
||||||
next0[j>>1]|=o;
|
|
||||||
} else {
|
} else {
|
||||||
next0[j>>1]=o<<4;
|
p=loopStart;
|
||||||
|
in[j]=buf[p++];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// encode with filter
|
|
||||||
if (i /*&& i!=loopStart*/) {
|
|
||||||
// 1: x = o0 - o1 * 15/16
|
|
||||||
// 2: x = o0 + o2 * 15/16 - o1 * 61/32
|
|
||||||
// 3: x = o0 + o2 * 13/16 - o1 * 115/64
|
|
||||||
range1=0;
|
|
||||||
range2=0;
|
|
||||||
range3=0;
|
|
||||||
//o2f1=o2;
|
|
||||||
o2f2=o2;
|
|
||||||
o2f3=o2;
|
|
||||||
o1f1=o1;
|
|
||||||
o1f2=o1;
|
|
||||||
o1f3=o1;
|
|
||||||
// first pass
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
|
|
||||||
pred1[j]=s-(((int)o1*15)>>4);
|
|
||||||
if (pred1[j]<-32768) pred1[j]=-32768;
|
|
||||||
if (pred1[j]>32767) pred1[j]=32767;
|
|
||||||
|
|
||||||
pred2[j]=s+(((int)o2*15)>>4)-(((int)o1*61)>>5);
|
|
||||||
if (pred2[j]<-32768) pred2[j]=-32768;
|
|
||||||
if (pred2[j]>32767) pred2[j]=32767;
|
|
||||||
|
|
||||||
pred3[j]=s+(((int)o2*13)>>4)-(((int)o1*115)>>6);
|
|
||||||
if (pred3[j]<-32768) pred3[j]=-32768;
|
|
||||||
if (pred3[j]>32767) pred3[j]=32767;
|
|
||||||
|
|
||||||
o2=o1;
|
|
||||||
o1=s;
|
|
||||||
}
|
|
||||||
// calculate range of values
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
short s=pred1[j];
|
|
||||||
if (s<0) s=-s;
|
|
||||||
while (range1<12 && s>((8<<range1)-1)) range1++;
|
|
||||||
|
|
||||||
s=pred2[j];
|
|
||||||
if (s<0) s=-s;
|
|
||||||
while (range2<12 && s>((8<<range2)-1)) range2++;
|
|
||||||
|
|
||||||
s=pred3[j];
|
|
||||||
if (s<0) s=-s;
|
|
||||||
while (range3<12 && s>((8<<range3)-1)) range3++;
|
|
||||||
}
|
|
||||||
// second pass
|
|
||||||
int prevLast1=last1;
|
|
||||||
int prevLast2=last2;
|
|
||||||
filter=1;
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
|
|
||||||
pred1[j]=s-(((int)o1f1*15)>>4);
|
|
||||||
if (pred1[j]<-32768) pred1[j]=-32768;
|
|
||||||
if (pred1[j]>32767) pred1[j]=32767;
|
|
||||||
|
|
||||||
o0=pred1[j]>>range1;
|
|
||||||
if (range1) if (pred1[j]&(1<<(range1>>1))) o0++;
|
|
||||||
if (o0>7) o0=7;
|
|
||||||
if (o0<-8) o0=-8;
|
|
||||||
o=o0&15;
|
|
||||||
if (j&1) {
|
|
||||||
next1[j>>1]|=o;
|
|
||||||
} else {
|
} else {
|
||||||
next1[j>>1]=o<<4;
|
in[j]=buf[p++];
|
||||||
}
|
}
|
||||||
|
|
||||||
nextDec=o;
|
|
||||||
DO_ONE_DEC(range1);
|
|
||||||
//o2f1=last2<<1;
|
|
||||||
o1f1=last1<<1;
|
|
||||||
}
|
}
|
||||||
last1=prevLast1;
|
|
||||||
last2=prevLast2;
|
|
||||||
filter=2;
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
pred2[j]=s+(((int)o2f2*15)>>4)-(((int)o1f2*61)>>5);
|
|
||||||
if (pred2[j]<-32768) pred2[j]=-32768;
|
|
||||||
if (pred2[j]>32767) pred2[j]=32767;
|
|
||||||
|
|
||||||
o0=pred2[j]>>range2;
|
|
||||||
if (range2) if (pred2[j]&(1<<(range2>>1))) o0++;
|
|
||||||
if (o0>7) o0=7;
|
|
||||||
if (o0<-8) o0=-8;
|
|
||||||
o=o0&15;
|
|
||||||
if (j&1) {
|
|
||||||
next2[j>>1]|=o;
|
|
||||||
} else {
|
} else {
|
||||||
next2[j>>1]=o<<4;
|
memcpy(in,&buf[i],16*sizeof(short));
|
||||||
}
|
}
|
||||||
|
|
||||||
nextDec=o;
|
// encode
|
||||||
DO_ONE_DEC(range2);
|
|
||||||
o2f2=last2<<1;
|
|
||||||
o1f2=last1<<1;
|
|
||||||
}
|
|
||||||
last1=prevLast1;
|
|
||||||
last2=prevLast2;
|
|
||||||
filter=3;
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
pred3[j]=s+(((int)o2f3*13)>>4)-(((int)o1f3*115)>>6);
|
|
||||||
if (pred3[j]<-32768) pred3[j]=-32768;
|
|
||||||
if (pred3[j]>32767) pred3[j]=32767;
|
|
||||||
|
|
||||||
o0=pred3[j]>>range3;
|
|
||||||
if (range3) if (pred3[j]&(1<<(range3>>1))) o0++;
|
|
||||||
if (o0>7) o0=7;
|
|
||||||
if (o0<-8) o0=-8;
|
|
||||||
o=o0&15;
|
|
||||||
if (j&1) {
|
|
||||||
next3[j>>1]|=o;
|
|
||||||
} else {
|
|
||||||
next3[j>>1]=o<<4;
|
|
||||||
}
|
|
||||||
|
|
||||||
nextDec=o;
|
|
||||||
DO_ONE_DEC(range3);
|
|
||||||
o2f3=last2<<1;
|
|
||||||
o1f3=last1<<1;
|
|
||||||
}
|
|
||||||
last1=prevLast1;
|
|
||||||
last2=prevLast2;
|
|
||||||
|
|
||||||
// find best filter
|
|
||||||
int error=0;
|
|
||||||
|
|
||||||
maxError[0]=0;
|
|
||||||
maxError[1]=0;
|
|
||||||
maxError[2]=0;
|
|
||||||
maxError[3]=0;
|
|
||||||
avgError[0]=0;
|
|
||||||
avgError[1]=0;
|
|
||||||
avgError[2]=0;
|
|
||||||
avgError[3]=0;
|
|
||||||
|
|
||||||
// test filter 0
|
|
||||||
filter=0;
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
if (j&1) {
|
|
||||||
nextDec=next0[j>>1]&15;
|
|
||||||
} else {
|
|
||||||
nextDec=next0[j>>1]>>4;
|
|
||||||
}
|
|
||||||
DO_ONE_DEC(range0);
|
|
||||||
error=s-(nextDec<<1);
|
|
||||||
if (error<0) error=-error;
|
|
||||||
avgError[0]+=error;
|
|
||||||
if (error>maxError[0]) maxError[0]=error;
|
|
||||||
}
|
|
||||||
last1=prevLast1;
|
|
||||||
last2=prevLast2;
|
|
||||||
|
|
||||||
// test filter 1
|
|
||||||
filter=1;
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
if (j&1) {
|
|
||||||
nextDec=next1[j>>1]&15;
|
|
||||||
} else {
|
|
||||||
nextDec=next1[j>>1]>>4;
|
|
||||||
}
|
|
||||||
DO_ONE_DEC(range1);
|
|
||||||
error=s-(nextDec<<1);
|
|
||||||
if (error<0) error=-error;
|
|
||||||
avgError[1]+=error;
|
|
||||||
if (error>maxError[1]) maxError[1]=error;
|
|
||||||
}
|
|
||||||
last1=prevLast1;
|
|
||||||
last2=prevLast2;
|
|
||||||
|
|
||||||
// test filter 2
|
|
||||||
filter=2;
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
if (j&1) {
|
|
||||||
nextDec=next2[j>>1]&15;
|
|
||||||
} else {
|
|
||||||
nextDec=next2[j>>1]>>4;
|
|
||||||
}
|
|
||||||
DO_ONE_DEC(range2);
|
|
||||||
error=s-(nextDec<<1);
|
|
||||||
if (error<0) error=-error;
|
|
||||||
avgError[2]+=error;
|
|
||||||
if (error>maxError[2]) maxError[2]=error;
|
|
||||||
}
|
|
||||||
last1=prevLast1;
|
|
||||||
last2=prevLast2;
|
|
||||||
|
|
||||||
// test filter 3
|
|
||||||
filter=3;
|
|
||||||
for (int j=0; j<16; j++) {
|
|
||||||
int s=NEXT_SAMPLE;
|
|
||||||
if (j&1) {
|
|
||||||
nextDec=next3[j>>1]&15;
|
|
||||||
} else {
|
|
||||||
nextDec=next3[j>>1]>>4;
|
|
||||||
}
|
|
||||||
DO_ONE_DEC(range3);
|
|
||||||
error=s-(nextDec<<1);
|
|
||||||
if (error<0) error=-error;
|
|
||||||
avgError[3]+=error;
|
|
||||||
if (error>maxError[3]) maxError[3]=error;
|
|
||||||
}
|
|
||||||
last1=prevLast1;
|
|
||||||
last2=prevLast2;
|
|
||||||
|
|
||||||
// pick best filter
|
|
||||||
int candError=0x7fffffff;
|
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<4; j++) {
|
||||||
if (avgError[j]<candError) {
|
for (int k=0; k<13; k++) {
|
||||||
candError=avgError[j];
|
brrEncodeBlock(in,possibleOut[j][k],k,j,&last1[j][k],&last2[j][k],&avgError[j][k]);
|
||||||
filter=j;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//printf("block %ld: %8d %8d %8d %8d -> %d\n",i>>4,avgError[0],avgError[1],avgError[2],avgError[3],filter);
|
|
||||||
} else {
|
// find best filter/range
|
||||||
// don't filter on the first or loop block
|
int candError=0x7fffffff;
|
||||||
|
if (i==0) {
|
||||||
filter=0;
|
filter=0;
|
||||||
|
for (int k=0; k<13; k++) {
|
||||||
|
if (avgError[0][k]<candError) {
|
||||||
|
candError=avgError[0][k];
|
||||||
|
range=k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int j=0; j<4; j++) {
|
||||||
|
for (int k=0; k<13; k++) {
|
||||||
|
if (avgError[j][k]<candError) {
|
||||||
|
candError=avgError[j][k];
|
||||||
|
filter=j;
|
||||||
|
range=k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (filter) {
|
// write
|
||||||
case 0:
|
out[0]=(range<<4)|(filter<<2)|((i+16>=len && loopStart<0)?1:0);
|
||||||
for (int j=0; j<8; j++) {
|
for (int j=0; j<8; j++) {
|
||||||
nextDec=next0[j]>>4;
|
out[j+1]=possibleOut[filter][range][j];
|
||||||
DO_ONE_DEC(range0);
|
|
||||||
nextDec=next0[j]&15;
|
|
||||||
DO_ONE_DEC(range0);
|
|
||||||
}
|
}
|
||||||
o2=last2<<1;
|
|
||||||
o1=last1<<1;
|
|
||||||
|
|
||||||
out[0]=(range0<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0);
|
for (int j=0; j<4; j++) {
|
||||||
out[1]=next0[0];
|
for (int k=0; k<13; k++) {
|
||||||
out[2]=next0[1];
|
last1[j][k]=last1[filter][range];
|
||||||
out[3]=next0[2];
|
last2[j][k]=last2[filter][range];
|
||||||
out[4]=next0[3];
|
}
|
||||||
out[5]=next0[4];
|
}
|
||||||
out[6]=next0[5];
|
out+=9;
|
||||||
out[7]=next0[6];
|
total+=9;
|
||||||
out[8]=next0[7];
|
}
|
||||||
break;
|
// encode loop block
|
||||||
case 1:
|
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++) {
|
for (int j=0; j<8; j++) {
|
||||||
nextDec=next1[j]>>4;
|
out[j+1]=possibleOut[filter][range][j];
|
||||||
DO_ONE_DEC(range1);
|
|
||||||
nextDec=next1[j]&15;
|
|
||||||
DO_ONE_DEC(range1);
|
|
||||||
}
|
}
|
||||||
o2=last2<<1;
|
|
||||||
o1=last1<<1;
|
for (int j=0; j<4; j++) {
|
||||||
out[0]=(range1<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0);
|
for (int k=0; k<13; k++) {
|
||||||
out[1]=next1[0];
|
last1[j][k]=last1[filter][range];
|
||||||
out[2]=next1[1];
|
last2[j][k]=last2[filter][range];
|
||||||
out[3]=next1[2];
|
|
||||||
out[4]=next1[3];
|
|
||||||
out[5]=next1[4];
|
|
||||||
out[6]=next1[5];
|
|
||||||
out[7]=next1[6];
|
|
||||||
out[8]=next1[7];
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
for (int j=0; j<8; j++) {
|
|
||||||
nextDec=next2[j]>>4;
|
|
||||||
DO_ONE_DEC(range2);
|
|
||||||
nextDec=next2[j]&15;
|
|
||||||
DO_ONE_DEC(range2);
|
|
||||||
}
|
}
|
||||||
o2=last2<<1;
|
|
||||||
o1=last1<<1;
|
|
||||||
out[0]=(range2<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0);
|
|
||||||
out[1]=next2[0];
|
|
||||||
out[2]=next2[1];
|
|
||||||
out[3]=next2[2];
|
|
||||||
out[4]=next2[3];
|
|
||||||
out[5]=next2[4];
|
|
||||||
out[6]=next2[5];
|
|
||||||
out[7]=next2[6];
|
|
||||||
out[8]=next2[7];
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
for (int j=0; j<8; j++) {
|
|
||||||
nextDec=next3[j]>>4;
|
|
||||||
DO_ONE_DEC(range3);
|
|
||||||
nextDec=next3[j]&15;
|
|
||||||
DO_ONE_DEC(range3);
|
|
||||||
}
|
}
|
||||||
o2=last2<<1;
|
|
||||||
o1=last1<<1;
|
|
||||||
out[0]=(range3<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0);
|
|
||||||
out[1]=next3[0];
|
|
||||||
out[2]=next3[1];
|
|
||||||
out[3]=next3[2];
|
|
||||||
out[4]=next3[3];
|
|
||||||
out[5]=next3[4];
|
|
||||||
out[6]=next3[5];
|
|
||||||
out[7]=next3[6];
|
|
||||||
out[8]=next3[7];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf+=16;
|
|
||||||
out+=9;
|
out+=9;
|
||||||
total+=9;
|
total+=9;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ extern "C" {
|
||||||
/**
|
/**
|
||||||
* read len samples from buf, encode in BRR and output to out.
|
* read len samples from buf, encode in BRR and output to out.
|
||||||
* @param buf input data.
|
* @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 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.
|
||||||
* @return number of written samples.
|
* @return number of written samples.
|
||||||
|
|
|
@ -498,6 +498,7 @@ void DivPlatformSMS::setFlags(const DivConfig& flags) {
|
||||||
easyStartingPeriod=13;
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
CHECK_CUSTOM_CLOCK;
|
||||||
resetPhase=!flags.getBool("noPhaseReset",false);
|
resetPhase=!flags.getBool("noPhaseReset",false);
|
||||||
easyNoise=!flags.getBool("noEasyNoise",false);
|
easyNoise=!flags.getBool("noEasyNoise",false);
|
||||||
divider=16;
|
divider=16;
|
||||||
|
@ -568,7 +569,6 @@ void DivPlatformSMS::setFlags(const DivConfig& flags) {
|
||||||
stereo=false;
|
stereo=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CHECK_CUSTOM_CLOCK;
|
|
||||||
rate=chipClock/divider;
|
rate=chipClock/divider;
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
oscBuf[i]->rate=rate;
|
oscBuf[i]->rate=rate;
|
||||||
|
|
|
@ -214,13 +214,13 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
loop=start;
|
loop=start;
|
||||||
} else if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
} else if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||||
start=sampleOff[chan[i].sample];
|
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);
|
loop=MAX(start,end-1);
|
||||||
if (chan[i].audPos>0) {
|
if (chan[i].audPos>0) {
|
||||||
start=start+MIN(chan[i].audPos,s->lengthBRR-1)/16*9;
|
start=start+MIN(chan[i].audPos,s->lengthBRR-1)/16*9;
|
||||||
}
|
}
|
||||||
if (s->loopStart>=0) {
|
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 {
|
} else {
|
||||||
start=0;
|
start=0;
|
||||||
|
@ -817,7 +817,7 @@ void DivPlatformSNES::renderSamples(int sysID) {
|
||||||
continue;
|
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);
|
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
|
||||||
if (actualLength>0) {
|
if (actualLength>0) {
|
||||||
sampleOff[i]=memPos;
|
sampleOff[i]=memPos;
|
||||||
|
|
|
@ -490,8 +490,8 @@ bool DivSample::initInternal(DivSampleDepth d, int count) {
|
||||||
case DIV_SAMPLE_DEPTH_BRR: // BRR
|
case DIV_SAMPLE_DEPTH_BRR: // BRR
|
||||||
if (dataBRR!=NULL) delete[] dataBRR;
|
if (dataBRR!=NULL) delete[] dataBRR;
|
||||||
lengthBRR=9*((count+15)/16);
|
lengthBRR=9*((count+15)/16);
|
||||||
dataBRR=new unsigned char[lengthBRR];
|
dataBRR=new unsigned char[lengthBRR+9];
|
||||||
memset(dataBRR,0,lengthBRR);
|
memset(dataBRR,0,lengthBRR+9);
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
||||||
if (dataVOX!=NULL) delete[] dataVOX;
|
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 (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR
|
||||||
if (!initInternal(DIV_SAMPLE_DEPTH_BRR,samples)) return;
|
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 (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_VOX)) { // VOX
|
||||||
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
||||||
|
|
|
@ -23,6 +23,15 @@
|
||||||
|
|
||||||
void FurnaceGUI::drawMobileControls() {
|
void FurnaceGUI::drawMobileControls() {
|
||||||
float timeScale=1.0f/(60.0f*ImGui::GetIO().DeltaTime);
|
float timeScale=1.0f/(60.0f*ImGui::GetIO().DeltaTime);
|
||||||
|
if (dragMobileMenu) {
|
||||||
|
if (portrait) {
|
||||||
|
mobileMenuPos=(dragMobileMenuOrigin.y-ImGui::GetMousePos().y)/(canvasH*0.65);
|
||||||
|
} else {
|
||||||
|
mobileMenuPos=(ImGui::GetMousePos().x-dragMobileMenuOrigin.x)/(canvasW*0.65);
|
||||||
|
}
|
||||||
|
if (mobileMenuPos<0.0f) mobileMenuPos=0.0f;
|
||||||
|
if (mobileMenuPos>1.0f) mobileMenuPos=1.0f;
|
||||||
|
} else {
|
||||||
if (mobileMenuOpen) {
|
if (mobileMenuOpen) {
|
||||||
if (mobileMenuPos<0.999f) {
|
if (mobileMenuPos<0.999f) {
|
||||||
WAKE_UP;
|
WAKE_UP;
|
||||||
|
@ -38,6 +47,7 @@ void FurnaceGUI::drawMobileControls() {
|
||||||
mobileMenuPos=0.0f;
|
mobileMenuPos=0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ImGui::SetNextWindowPos(portrait?ImVec2(0.0f,((1.0-mobileMenuPos*0.65)*canvasH)-(0.16*canvasW)):ImVec2(0.5*canvasW*mobileMenuPos,0.0f));
|
ImGui::SetNextWindowPos(portrait?ImVec2(0.0f,((1.0-mobileMenuPos*0.65)*canvasH)-(0.16*canvasW)):ImVec2(0.5*canvasW*mobileMenuPos,0.0f));
|
||||||
ImGui::SetNextWindowSize(portrait?ImVec2(canvasW,0.16*canvasW):ImVec2(0.16*canvasH,canvasH));
|
ImGui::SetNextWindowSize(portrait?ImVec2(canvasW,0.16*canvasW):ImVec2(0.16*canvasH,canvasH));
|
||||||
if (ImGui::Begin("Mobile Controls",NULL,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) {
|
if (ImGui::Begin("Mobile Controls",NULL,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) {
|
||||||
|
@ -54,8 +64,21 @@ void FurnaceGUI::drawMobileControls() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::Button(mobButtonName,buttonSize)) {
|
if (ImGui::Button(mobButtonName,buttonSize)) {
|
||||||
|
if (!dragMobileMenu) {
|
||||||
mobileMenuOpen=!mobileMenuOpen;
|
mobileMenuOpen=!mobileMenuOpen;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemActive() && ImGui::GetIO().MouseDragMaxDistanceSqr[ImGuiMouseButton_Left]>ImGui::GetIO().ConfigInertialScrollToleranceSqr*2.0f) {
|
||||||
|
if (!dragMobileMenu) {
|
||||||
|
dragMobileMenu=true;
|
||||||
|
dragMobileMenuOrigin=ImGui::GetMousePos();
|
||||||
|
if (portrait) {
|
||||||
|
dragMobileMenuOrigin.y+=mobileMenuPos*canvasH*0.65f;
|
||||||
|
} else {
|
||||||
|
dragMobileMenuOrigin.x-=mobileMenuPos*canvasW*0.65f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!portrait) ImGui::Separator();
|
if (!portrait) ImGui::Separator();
|
||||||
|
|
||||||
|
|
|
@ -2931,6 +2931,14 @@ void FurnaceGUI::pointUp(int x, int y, int button) {
|
||||||
}
|
}
|
||||||
orderScrollLocked=false;
|
orderScrollLocked=false;
|
||||||
orderScrollTolerance=false;
|
orderScrollTolerance=false;
|
||||||
|
if (dragMobileMenu) {
|
||||||
|
dragMobileMenu=false;
|
||||||
|
if (mobileMenuOpen) {
|
||||||
|
mobileMenuOpen=(mobileMenuPos>=0.85f);
|
||||||
|
} else {
|
||||||
|
mobileMenuOpen=(mobileMenuPos>=0.15f);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (selecting) {
|
if (selecting) {
|
||||||
if (!selectingFull) cursor=selEnd;
|
if (!selectingFull) cursor=selEnd;
|
||||||
finishSelection();
|
finishSelection();
|
||||||
|
@ -5785,6 +5793,7 @@ FurnaceGUI::FurnaceGUI():
|
||||||
keepLoopAlive(false),
|
keepLoopAlive(false),
|
||||||
orderScrollLocked(false),
|
orderScrollLocked(false),
|
||||||
orderScrollTolerance(false),
|
orderScrollTolerance(false),
|
||||||
|
dragMobileMenu(false),
|
||||||
curWindow(GUI_WINDOW_NOTHING),
|
curWindow(GUI_WINDOW_NOTHING),
|
||||||
nextWindow(GUI_WINDOW_NOTHING),
|
nextWindow(GUI_WINDOW_NOTHING),
|
||||||
curWindowLast(GUI_WINDOW_NOTHING),
|
curWindowLast(GUI_WINDOW_NOTHING),
|
||||||
|
@ -5877,6 +5886,7 @@ FurnaceGUI::FurnaceGUI():
|
||||||
orderScroll(0.0f),
|
orderScroll(0.0f),
|
||||||
orderScrollSlideOrigin(0.0f),
|
orderScrollSlideOrigin(0.0f),
|
||||||
orderScrollRealOrigin(0.0f,0.0f),
|
orderScrollRealOrigin(0.0f,0.0f),
|
||||||
|
dragMobileMenuOrigin(0.0f,0.0f),
|
||||||
layoutTimeBegin(0),
|
layoutTimeBegin(0),
|
||||||
layoutTimeEnd(0),
|
layoutTimeEnd(0),
|
||||||
layoutTimeDelta(0),
|
layoutTimeDelta(0),
|
||||||
|
|
|
@ -1435,7 +1435,7 @@ class FurnaceGUI {
|
||||||
SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd;
|
SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd;
|
||||||
bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI;
|
bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI;
|
||||||
bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, waveSigned, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble;
|
bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, waveSigned, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble;
|
||||||
bool keepLoopAlive, orderScrollLocked, orderScrollTolerance;
|
bool keepLoopAlive, orderScrollLocked, orderScrollTolerance, dragMobileMenu;
|
||||||
FurnaceGUIWindows curWindow, nextWindow, curWindowLast;
|
FurnaceGUIWindows curWindow, nextWindow, curWindowLast;
|
||||||
std::atomic<FurnaceGUIWindows> curWindowThreadSafe;
|
std::atomic<FurnaceGUIWindows> curWindowThreadSafe;
|
||||||
float peak[2];
|
float peak[2];
|
||||||
|
@ -1581,6 +1581,7 @@ class FurnaceGUI {
|
||||||
float nextScroll, nextAddScroll, orderScroll, orderScrollSlideOrigin;
|
float nextScroll, nextAddScroll, orderScroll, orderScrollSlideOrigin;
|
||||||
|
|
||||||
ImVec2 orderScrollRealOrigin;
|
ImVec2 orderScrollRealOrigin;
|
||||||
|
ImVec2 dragMobileMenuOrigin;
|
||||||
|
|
||||||
int layoutTimeBegin, layoutTimeEnd, layoutTimeDelta;
|
int layoutTimeBegin, layoutTimeEnd, layoutTimeDelta;
|
||||||
int renderTimeBegin, renderTimeEnd, renderTimeDelta;
|
int renderTimeBegin, renderTimeEnd, renderTimeDelta;
|
||||||
|
|
Loading…
Reference in New Issue