Created
September 12, 2011 12:06
-
-
Save cosinusoidally/1211111 to your computer and use it in GitHub Desktop.
vorbis esq public
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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