Skip to content

Instantly share code, notes, and snippets.

@cosinusoidally
Created September 12, 2011 12:06
Show Gist options
  • Save cosinusoidally/1211111 to your computer and use it in GitHub Desktop.
Save cosinusoidally/1211111 to your computer and use it in GitHub Desktop.
vorbis esq public
fs=require("fs");
a=fs.openSync("a.raw","r");
var b=fs.openSync("c.raw","w");
off=0;
var sizeof=function(a){return a.length};
var assert=function(){};
var bit_reverse=function(n){
n = ((n & 0xAAAAAAAA) >>> 1) | ((n & 0x55555555) << 1);
n = ((n & 0xCCCCCCCC) >>> 2) | ((n & 0x33333333) << 2);
n = ((n & 0xF0F0F0F0) >>> 4) | ((n & 0x0F0F0F0F) << 4);
n = ((n & 0xFF00FF00) >>> 8) | ((n & 0x00FF00FF) << 8);
return (n >>> 16) | (n << 16);
}
var ilog=function(n){
// static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
log2_4= [ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 ];
// 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29)
if (n < (1 << 14))
if (n < (1 << 4)) return 0 + log2_4[n ];
else if (n < (1 << 9)) return 5 + log2_4[n >> 5];
else return 10 + log2_4[n >> 10];
else if (n < (1 << 24))
if (n < (1 << 19)) return 15 + log2_4[n >> 15];
else return 20 + log2_4[n >> 20];
else if (n < (1 << 29)) return 25 + log2_4[n >> 25];
else if (n < (1 << 31)) return 30 + log2_4[n >> 30];
else return 0; // signed n returns 0
}
var memcpy=function(s1,s2,n){
for(var i=0;i<n;i++){
s1[i]=s2[i];
};
};
//void inverse_mdct_naive(float *buffer, int n)
// {
var inverse_mdct=function(buffer,n){
// float s;
var s;
// float A[1 << 12], B[1 << 12], C[1 << 11];
var A=[], B=[], C=[];
// int i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
var i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
// int n3_4 = n - n4, ld;
var n3_4 = n - n4, ld;
// how can they claim this only uses N words?!
// oh, because they're only used sparsely, whoops
// float u[1 << 13], X[1 << 13], v[1 << 13], w[1 << 13];
var u=[], X=[], v=[], w=[];
u.length= 1 << 13;
// set up twiddle factors
// for (k=k2=0; k < n4; ++k,k2+=2) {
// A[k2 ] = (float) cos(4*k*M_PI/n);
// A[k2+1] = (float) -sin(4*k*M_PI/n);
// B[k2 ] = (float) cos((k2+1)*M_PI/n/2);
// B[k2+1] = (float) sin((k2+1)*M_PI/n/2);
// }
var M_PI=Math.PI;
var cos=Math.cos;
var sin=Math.sin;
for (k=k2=0; k < n4; ++k,k2+=2) {
A[k2 ] = cos(4*k*M_PI/n);
A[k2+1] = -sin(4*k*M_PI/n);
B[k2 ] = cos((k2+1)*M_PI/n/2);
B[k2+1] = sin((k2+1)*M_PI/n/2);
}
// for (k=k2=0; k < n8; ++k,k2+=2) {
// C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);
// C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);
// }
for (k=k2=0; k < n8; ++k,k2+=2) {
C[k2 ] = cos(2*(k2+1)*M_PI/n);
C[k2+1] = -sin(2*(k2+1)*M_PI/n);
}
// IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio"
// Note there are bugs in that pseudocode, presumably due to them attempting
// to rename the arrays nicely rather than representing the way their actual
// implementation bounces buffers back and forth. As a result, even in the
// "some formulars corrected" version, a direct implementation fails. These
// are noted below as "paper bug".
// copy and reflect spectral data
// for (k=0; k < n2; ++k) u[k] = buffer[k];
for (k=0; k < n2; ++k) {u[k] = buffer[k];};
// for ( ; k < n ; ++k) u[k] = -buffer[n - k - 1];
for ( ; k < n ; ++k){ u[k] = -buffer[n - k - 1];};
// kernel from paper
// step 1
// for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) {
// v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1];
// v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2];
// }
for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) {
v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1];
v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2];
}
// step 2
// for (k=k4=0; k < n8; k+=1, k4+=4) {
// w[n2+3+k4] = v[n2+3+k4] + v[k4+3];
// w[n2+1+k4] = v[n2+1+k4] + v[k4+1];
// w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4];
// w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4];
// }
for (k=k4=0; k < n8; k+=1, k4+=4) {
w[n2+3+k4] = v[n2+3+k4] + v[k4+3];
w[n2+1+k4] = v[n2+1+k4] + v[k4+1];
w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4];
w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4];
}
// step 3
// ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
// for (l=0; l < ld-3; ++l) {
// int k0 = n >> (l+2), k1 = 1 << (l+3);
// int rlim = n >> (l+4), r4, r;
// int s2lim = 1 << (l+2), s2;
// for (r=r4=0; r < rlim; r4+=4,++r) {
// for (s2=0; s2 < s2lim; s2+=2) {
// u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4];
// u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4];
// u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1]
// - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1];
// u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1]
// + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1];
// }
// }
// if (l+1 < ld-3) {
// // paper bug: ping-ponging of u&w here is omitted
// memcpy(w, u, sizeof(u));
// }
// }
ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
for (l=0; l < ld-3; ++l) {
var k0 = n >> (l+2), k1 = 1 << (l+3);
var rlim = n >> (l+4), r4, r;
var s2lim = 1 << (l+2), s2;
for (r=r4=0; r < rlim; r4+=4,++r) {
for (s2=0; s2 < s2lim; s2+=2) {
u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4];
u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4];
u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1] - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1];
u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1] + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1];
}
}
if (l+1 < ld-3) {
// paper bug: ping-ponging of u&w here is omitted
// memcpy massive bottleneck in js, replaced:
w=u;
u=[];
// memcpy(w, u, sizeof(u));
}
}
// step 4
// for (i=0; i < n8; ++i) {
// int j = bit_reverse(i) >> (32-ld+3);
// assert(j < n8);
// if (i == j) {
// // paper bug: original code probably swapped in place; if copying,
// // need to directly copy in this case
// int i8 = i << 3;
// v[i8+1] = u[i8+1];
// v[i8+3] = u[i8+3];
// v[i8+5] = u[i8+5];
// v[i8+7] = u[i8+7];
// } else if (i < j) {
// int i8 = i << 3, j8 = j << 3;
// v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1];
// v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3];
// v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5];
// v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7];
// }
// }
for (i=0; i < n8; ++i) {
var j = bit_reverse(i) >>> (32-ld+3);
assert(j < n8);
if (i === j) {
// paper bug: original code probably swapped in place; if copying,
// need to directly copy in this case
var i8 = i << 3;
v[i8+1] = u[i8+1];
v[i8+3] = u[i8+3];
v[i8+5] = u[i8+5];
v[i8+7] = u[i8+7];
} else if (i < j) {
var i8 = i << 3, j8 = j << 3;
v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1];
v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3];
v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5];
v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7];
}
}
// step 5
// for (k=0; k < n2; ++k) {
// w[k] = v[k*2+1];
// }
for (k=0; k < n2; ++k) {
w[k] = v[k*2+1];
}
// step 6
// for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) {
// u[n-1-k2] = w[k4];
// u[n-2-k2] = w[k4+1];
// u[n3_4 - 1 - k2] = w[k4+2];
// u[n3_4 - 2 - k2] = w[k4+3];
// }
for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) {
u[n-1-k2] = w[k4];
u[n-2-k2] = w[k4+1];
u[n3_4 - 1 - k2] = w[k4+2];
u[n3_4 - 2 - k2] = w[k4+3];
}
// step 7
// for (k=k2=0; k < n8; ++k, k2 += 2) {
// v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
// v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
// v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
// v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
// }
for (k=k2=0; k < n8; ++k, k2 += 2) {
v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
}
// step 8
// for (k=k2=0; k < n4; ++k,k2 += 2) {
// X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1];
// X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ];
// }
for (k=k2=0; k < n4; ++k,k2 += 2) {
X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1];
X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ];
}
// decode kernel to output
// determined the following value experimentally
// (by first figuring out what made inverse_mdct_slow work); then matching that here
// (probably vorbis encoder premultiplies by n or n/2, to save it on the decoder?)
// s = 0.5; // theoretically would be n4
s = 0.5; // theoretically would be n4
// [[[ note! the s value of 0.5 is compensated for by the B[] in the current code,
// so it needs to use the "old" B values to behave correctly, or else
// set s to 1.0 ]]]
// for (i=0; i < n4 ; ++i) buffer[i] = s * X[i+n4];
// for ( ; i < n3_4; ++i) buffer[i] = -s * X[n3_4 - i - 1];
// for ( ; i < n ; ++i) buffer[i] = -s * X[i - n3_4];
var outp=[]; // I'm not overwriting the input
for (i=0; i < n4 ; ++i) {outp[i] = s * X[i+n4];};
for ( ; i < n3_4; ++i) {outp[i] = -s * X[n3_4 - i - 1];};
for ( ; i < n ; ++i) {outp[i] = -s * X[i - n3_4];};
return outp;
}
x=0;
var buf=new Buffer(2048*4);
var prev=[];
var lap_add=function(prev,next){
var out=[];
var winfn=function(x,n){
var square=function(a){return a*a};
return Math.sin((Math.PI/2)*square(Math.sin((x+(1/2))*Math.PI/n)))
};
var lhs_short=function(x){
return winfn(x,256);
};
var rhs_short=function(x){
return winfn(x+128,256);
};
var lhs_long=function(x){
return winfn(x,2048);
};
var rhs_long=function(x){
return winfn(x+1024,2048);
};
var block_map={256:0,2048:1};
var b=[[],[]];
out=[];
b[0][0]=function(){
out=[];
for(var i=0;i<128;i++){
out[i]=rhs_short(i)*prev[i]+lhs_short(i)*next[i];
}
// show("prev short, next short");
};
b[0][1]=function(){
out=[];
var long_start=1024-576;
for(var i=0;i<128;i++){
out.push(rhs_short(i)*prev[i]+lhs_short(i)*next[i+long_start]);
};
for(;i<576;i++){
out.push(next[i+long_start]);
}
// show("prev short, next long");
};
b[1][0]=function(){
out=[];
for(var i=0;i<576-128;i++){
out.push(prev[i]);
};
for(var k=0;k<128;k++){
out.push(rhs_short(k)*prev[i+k]+lhs_short(k)*next[k]);
}
// show( "prev long, next short");
};
b[1][1]=function(){
out=[];
for(var i=0;i<1024;i++){
out[i]=rhs_long(i)*prev[i]+lhs_long(i)*next[i];
};
// show("prev long, next long");
};
b[block_map[prev.length*2]][block_map[next.length*2]]();
return out;
};
var next=[];
for(var i=0;i<128;i++){next[i]=0};
var nextr=[];
for(var i=0;i<128;i++){nextr[i]=0};
while(true){
if(fs.readSync(a,buf,0,3)<1){break};
var chan=buf[0];
var high=buf[1];
var low=buf[2];
len=(high*256+low)/2;
off=off+3;
fs.readSync(a,buf,0,len*4);
off=off+len*4;
var pcm=[];
for(var i=0;i<len;i++){
var l=i*4;
pcm[i]=((buf[l+3]<<24) | (buf[l+2] << 16) | (buf[l+1] << 8) | buf[l])/(256*256*256);
};
var split=function(a){
return [a.slice(0,a.length/2),a.slice(a.length/2)];
}
pcm=inverse_mdct(pcm,len*2);
var z=split(pcm);
if(chan===0){
prev=next;
next=z[0];
oup=lap_add(prev,next);
next=z[1];
buff=new Buffer(oup.length*2);
for(var i=0;i<oup.length;i++){
var val=oup[i];
if(val>1){val=0.999};
if(val<-1){val=-1};
val=val*256*256*256*128>>>16;
buff[i*2]=val & 255;
buff[i*2+1]=val >>> 8 & 255;
};
// fs.writeSync(b,buff,0,buff.length);
}
if(chan===1){
prevr=nextr;
nextr=z[0];
oup=lap_add(prevr,nextr);
nextr=z[1];
buffr=new Buffer(oup.length*2);
for(var i=0;i<oup.length;i++){
var val=oup[i];
if(val>1){val=0.999};
if(val<-1){val=-1};
val=val*256*256*256*128>>>16;
buffr[i*2]=val & 255;
buffr[i*2+1]=val >>> 8 & 255;
};
var buffout=new Buffer(oup.length*4);
for(var i=0;i<oup.length;i++){
buffout[i*4]=buff[i*2];
buffout[i*4+1]=buff[i*2+1];
buffout[i*4+2]=buffr[i*2];
buffout[i*4+3]=buffr[i*2+1];
}
fs.writeSync(b,buffout,0,buffout.length);
}
pcm=pcm.map(function(a){return Math.round(a*256*256*256)});
for(var i=0;i<len*2;i++){
l=i*4;
buf[l]=pcm[i] & 255;
buf[l+1]=(pcm[i] >>> 8) & 255;
buf[l+2]=(pcm[i] >>> 16) & 255;
buf[l+3]=(pcm[i] >>> 24) & 255;
};
var out=buf.slice(0,len*8);
var out=buf.slice(0,len*8);
var short=new Buffer([chan,high,low]);
// fs.writeSync(b,short,0,short.length);
// fs.writeSync(b,out,0,out.length);
//process.stdout.write(short);
//process.stdout.write(out);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment