csdr/sdr.js/sdrjs-footer.js

297 lines
10 KiB
JavaScript
Raw Permalink Normal View History

// ==========================================================
// ========= / THE CODE COMPILED BY EMCC ENDS HERE ==========
// ==========================================================
asm$ =
{
malloc: function(type, size)
{
real_size=size*type.BYTES_PER_ELEMENT;
pointer = Module._malloc(real_size);
heap = new Uint8Array(Module.HEAPU8.buffer, pointer, real_size);
return {
asm$: true,
ptr: heap.byteOffset,
free: function() { Module._free(this.ptr); },
arr: new type(heap.buffer, heap.byteOffset, size),
size: size
};
},
cpy: function(dst, dst_offset, src, src_offset, size)
{
if(typeof dst.asm$!='undefined') dst=dst.arr;
if(typeof src.asm$!='undefined') src=src.arr;
for(var i=0;i<size;i++)
dst[dst_offset+i]=src[src_offset+i];
}
};
// void firdes_lowpass_f(float *output, int length, float cutoff_rate, window_t window)
firdes_lowpass_f = Module.cwrap('firdes_lowpass_f', null, ['number', 'number', 'number', 'number']);
// rational_resampler_ff_t rational_resampler_ff(float *input, float *output, int input_size, int interpolation, int decimation, float *taps, int taps_length, int last_taps_delay)
rational_resampler_ff = Module.cwrap('rational_resampler_ff', 'struct', ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);
rational_resampler_ff=function(pinput,poutput,input_length,interpolation,decimation,ptaps,taps_length,last_taps_delay )
{ stackbase=STACKTOP;
STACKTOP+=4*3;
_rational_resampler_ff(stackbase, pinput, poutput, input_length, interpolation, decimation, ptaps, taps_length,last_taps_delay);
returnstruct={ input_processed: getValue(stackbase,'i32'), output_size: getValue(stackbase+4,'i32'), last_taps_delay: getValue(stackbase+8,'i32') };
STACKTOP=stackbase;
return returnstruct;
}
sdrjs={};
sdrjs.WINDOW_BOXCAR=0;
sdrjs.WINDOW_BLACKMAN=1;
sdrjs.WINDOW_HAMMING=2;
//this will be impportant whil converting arrays
//http://stackoverflow.com/questions/25839216/convert-float32array-to-int16array
/*sdrjs.prototype.FirdesLowpassF=function(taps_length,transition_bw,window)
{
this.calculate=function(){}
this.get_output=function(){}
this.get_output_heap=function(){}
};*/
sdrjs.ConvertI16_F=function(i16data)
{
var f32data=new Float32Array(i16data.length);
for(var i=0;i<i16data.length;i++) f32data[i]=i16data[i]/32768;
return f32data;
}
ima_adpcm_codec=function(encode,pinput,poutput,input_length,state)
{
myfunc=(encode)?_encode_ima_adpcm_i16_u8:_decode_ima_adpcm_u8_i16;
stackbase=STACKTOP;
STACKTOP+=4*2; //sizeof(int)*2
myfunc(stackbase, pinput, poutput, input_length, state.ptr);
state.arr[0]=getValue(stackbase+0,'i32');
state.arr[1]=getValue(stackbase+4,'i32');
STACKTOP=stackbase;
};
sdrjs.ImaAdpcm=function()
{
this.BUFSIZE=1024*64;
this.ima_adpcm_state=asm$.malloc(Int32Array,2);
this.i16_buffer=asm$.malloc(Int16Array,this.BUFSIZE*2);
this.u8_buffer=asm$.malloc(Uint8Array,this.BUFSIZE);
this.ima_adpcm_state.arr[0]=0;
this.ima_adpcm_state.arr[1]=0;
this.encode=function(data)
{
//not_tested_yet
asm$.cpy(this.i16_buffer.arr,0,data,0,data.length);
ima_adpcm_codec(true,this.i16_buffer.ptr,this.u8_buffer.ptr,data.length,this.ima_adpcm_state);
out=new Uint8Array(data.length/2);
asm$.cpy(out,0,this.u8_buffer,0,data.length/2);
return out;
};
this.decode=function(data)
{
asm$.cpy(this.u8_buffer.arr,0,data,0,data.length);
ima_adpcm_codec(false,this.u8_buffer.ptr,this.i16_buffer.ptr,data.length,this.ima_adpcm_state);
out=new Int16Array(data.length*2);
asm$.cpy(out,0,this.i16_buffer.arr,0,data.length*2);
return out;
};
this.reset=function() { this.ima_adpcm_state.arr[0]=this.ima_adpcm_state.arr[1]=0|0; }
};
sdrjs.REBUFFER_FIXED=0; //rebuffer should return arrays of fixed size
sdrjs.REBUFFER_MAX=1; //rebuffer should return arrays with a maximal size of the parameter size
sdrjs.Rebuffer=function(size,mode)
{
this.mode=mode;
this.size=size;
this.total_size=0;
this.arrays=[];
this.last_arr=[];
this.last_arr_offset=0;
this.push=function(data)
{
this.total_size+=data.length;
this.arrays.push(data);
};
this.remaining=function()
{
var fixed_bufs_num=Math.floor(this.total_size/this.size);
if(!this.mode) return fixed_bufs_num;
else return fixed_bufs_num+(!!(this.total_size-fixed_bufs_num*this.size)); //if REBUFFER_MAX, add one if we could return one more buffer (smaller than the fixed size)
};
this.take=function() { var a=this._take(); /*console.log(a);*/ return a; };
this._take=function()
{
var remain=this.size;
var offset=0;
var obuf=new Float32Array(size);
//console.log("==== get new obuf ====", size);
while(remain)
{
if(this.last_arr_offset==this.last_arr.length)
{
if(this.arrays.length==0)
{
//console.log("this should not happen");
if(this.mode) //REBUFFER_MAX
{
this.total_size=0;
return obuf.subarray(0,offset);
}
else return new Float32Array(0); //REBUFFER_FIXED
}
//console.log("pick new last_arr");
this.last_arr=this.arrays.shift();
this.last_arr_offset=0;
}
var rwithin=this.last_arr.length-this.last_arr_offset;
//console.log("b :: ","remain", remain, "rwithin",rwithin,"last_arr.length",this.last_arr.length,"larroffset",this.last_arr_offset,"offset",offset);
if(remain<rwithin)
{
//console.log("remain < rwithin"); //seems problematic @Andris
for(var i=0;i<remain;i++) obuf[offset++]=this.last_arr[this.last_arr_offset++];
remain=0;
}
else
{
//console.log("remain > rwithin");
for(var i=0;i<rwithin;i++) obuf[offset++]=this.last_arr[this.last_arr_offset++];
remain-=rwithin;
}
//console.log("e :: ","remain", remain, "rwithin",rwithin,"last_arr.length",this.last_arr.length,"larroffset",this.last_arr_offset,"offset",offset);
}
this.total_size-=obuf.length;
//console.log("return _take");
return obuf;
};
};
sdrjs.RationalResamplerFF=function(interpolation,decimation,transition_bw,window)
{
this.interpolation=interpolation;
this.decimation=decimation;
this.transition_bw = (typeof transition_bw=='undefined')?0.05:transition_bw;
this.window = (typeof window=='undefined')?1:window;
this.buffer_size=1024*512;
this.output_buffer_size=Math.floor((this.buffer_size*interpolation)/decimation);
this.input_buffer = asm$.malloc(Float32Array,this.buffer_size);
this.output_buffer = asm$.malloc(Float32Array,this.output_buffer_size);
//Calculate filter
this.taps_length = Math.floor(4/this.transition_bw);
this.taps = asm$.malloc(Float32Array,this.taps_length);
var cutoff_for_interpolation=1.0/interpolation;
var cutoff_for_decimation=1.0/decimation;
var cutoff = (cutoff_for_interpolation<cutoff_for_decimation)?cutoff_for_interpolation:cutoff_for_decimation; //get the lower
firdes_lowpass_f(this.taps.ptr, this.taps_length, cutoff/2, window);
this.remain = 0;
this.remain_offset=0;
this.last_taps_delay=0;
this.process=function(input)
{
if(input.length+this.remain > this.buffer_size)
{
return new Float32Array(0); console.log("sdrjs.RationalResamplerFF: critical audio buffering error"); //This should not happen...
/* console.log("RationalResamplerFF: splitting..."); //TODO: this branch has not been checked
output_buffers=Array();
new_buffer_size=this.buffer_size/2;
i=0;
//process the input in chunks of new_buffer_size, and add the output product Float32Array-s to output_buffers.
while((i++)*new_buffer_size<=input.length)
{
output_buffers.push(this._process_noheapcheck(input.subarray(i*new_buffer_size,(i+1)*new_buffer_size)));
}
//add up the sizes of the output_buffer-s.
total_output_length=0;
output_buffers.forEach(function(a){total_output_length+=a.length;});
//create one big buffer from concatenating the output_buffer-s
output=new Float32Array(total_output_length);
output_pos=0;
output_buffers.forEach(function(a){
asm$.cpy(output,output_pos,a,0,a.length);
output_pos+=a.length;
});
return output;*/
}
else return this._process_noheapcheck(input);
};
this._process_noheapcheck=function(input) //if we are sure we have enough space in the buffers
{
asm$.cpy(this.input_buffer.arr,0,this.input_buffer.arr,this.remain_offset,this.remain);
asm$.cpy(this.input_buffer.arr, this.remain, input, 0, input.length);
var total_input_size=input.length+this.remain;
d=rational_resampler_ff(this.input_buffer.ptr, this.output_buffer.ptr, total_input_size, this.interpolation, this.decimation, this.taps.ptr, this.taps_length, this.last_taps_delay);
this.last_taps_delay=d.last_taps_delay;
this.remain=total_input_size-d.input_processed;
this.remain_offset=d.input_processed;
var output_copy_arr=new Float32Array(d.output_size);
asm$.cpy(output_copy_arr,0,this.output_buffer.arr,0,d.output_size);
return output_copy_arr;
};
};
_sdrjs_logb=function(what) { document.body.innerHTML+=what+"<br />"; }
function test_firdes_lowpass_f_original()
{
//Original method explained over here:
//http://kapadia.github.io/emscripten/2013/09/13/emscripten-pointers-and-pointers.html
_sdrjs_logb("test_firdes_lowpass_f_original():");
_sdrjs_logb("Now designing FIR filter with firdes_lowpass_f in sdr.js...");
_sdrjs_logb("output should be the same as: <strong>csdr firdes_lowpass_f 0.1 101 HAMMING</strong>");
var outputSize = 101*4;
var outputPtr = Module._malloc(outputSize);
var outputHeap = new Uint8Array(Module.HEAPU8.buffer, outputPtr, outputSize);
firdes_lowpass_f(outputHeap.byteOffset,101,0.1,2);
var output = new Float32Array(outputHeap.buffer, outputHeap.byteOffset, 101);
outputStr=String();
for(i=0;i<output.length;i++) outputStr+=output[i].toFixed(6)+", ";
Module._free(outputHeap.byteOffset);
_sdrjs_logb(outputStr);
}
function test_firdes_lowpass_f_new()
{
//This is much simpler, using asm$
_sdrjs_logb("test_firdes_lowpass_f_new():");
_sdrjs_logb("Now designing FIR filter with firdes_lowpass_f in sdr.js...");
_sdrjs_logb("output should be the same as: <strong>csdr firdes_lowpass_f 0.1 101 HAMMING</strong>");
output=asm$.malloc(Float32Array,101);
firdes_lowpass_f(output.ptr,101,0.1,2);
outputStr=String();
for(i=0;i<output.arr.length;i++) outputStr+=(output.arr[i]).toFixed(6)+", ";
output.free();
_sdrjs_logb(outputStr);
}
function test_struct_return_value()
{
v=STACKTOP;
STACKTOP+=4*3;
_shift_addition_init(v,0.2);
console.log(
"sinval=", getValue(v,'float'),
"cosval=", getValue(v+4,'float'),
"rate=", getValue(v+8,'float')
);
STACKTOP=v;
}