/ sdr.js / sdrjs-footer.js
sdrjs-footer.js
  1  // ========================================================== 
  2  // ========= / THE CODE COMPILED BY EMCC ENDS HERE ==========
  3  // ========================================================== 
  4  
  5  asm$ =
  6  {
  7  	malloc: function(type, size) 
  8  	{
  9  		real_size=size*type.BYTES_PER_ELEMENT;
 10  		pointer = Module._malloc(real_size);
 11  		heap = new Uint8Array(Module.HEAPU8.buffer, pointer, real_size);
 12  		return {
 13  			asm$: true,
 14  			ptr: heap.byteOffset,
 15  			free: function() { Module._free(this.ptr); },
 16  			arr: new type(heap.buffer, heap.byteOffset, size),
 17  			size: size
 18  		};
 19  	},
 20  	cpy: function(dst, dst_offset, src, src_offset, size) 
 21  	{
 22  		if(typeof dst.asm$!='undefined') dst=dst.arr;
 23  		if(typeof src.asm$!='undefined') src=src.arr;
 24  		for(var i=0;i<size;i++) 
 25  			dst[dst_offset+i]=src[src_offset+i];
 26  	}
 27  };
 28  
 29  //                                                  void firdes_lowpass_f(float *output, int length, float cutoff_rate, window_t window)
 30  firdes_lowpass_f = Module.cwrap('firdes_lowpass_f', null,                 ['number',     'number',   'number',          'number']);
 31  
 32  //                                                            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)
 33  rational_resampler_ff = Module.cwrap('rational_resampler_ff', 'struct',                                    ['number',     'number',      'number',       'number',          'number',       'number',    'number',        'number']);
 34  
 35  
 36  rational_resampler_ff=function(pinput,poutput,input_length,interpolation,decimation,ptaps,taps_length,last_taps_delay )
 37  {	stackbase=STACKTOP;
 38  	STACKTOP+=4*3;
 39  	_rational_resampler_ff(stackbase, pinput, poutput, input_length, interpolation, decimation, ptaps, taps_length,last_taps_delay);
 40  	returnstruct={ input_processed: getValue(stackbase,'i32'), output_size: getValue(stackbase+4,'i32'), last_taps_delay: getValue(stackbase+8,'i32') };
 41  	STACKTOP=stackbase;
 42  	return returnstruct;
 43  }
 44  
 45  sdrjs={};
 46  
 47  sdrjs.WINDOW_BOXCAR=0;
 48  sdrjs.WINDOW_BLACKMAN=1;
 49  sdrjs.WINDOW_HAMMING=2;
 50  
 51  //this will be impportant whil converting arrays
 52  //http://stackoverflow.com/questions/25839216/convert-float32array-to-int16array
 53  
 54  /*sdrjs.prototype.FirdesLowpassF=function(taps_length,transition_bw,window)
 55  {
 56  	this.calculate=function(){}
 57  	this.get_output=function(){}
 58  	this.get_output_heap=function(){}
 59  };*/
 60  
 61  
 62  sdrjs.ConvertI16_F=function(i16data)
 63  {
 64  	var f32data=new Float32Array(i16data.length);
 65  	for(var i=0;i<i16data.length;i++) f32data[i]=i16data[i]/32768;
 66  	return f32data;
 67  }
 68  
 69  ima_adpcm_codec=function(encode,pinput,poutput,input_length,state)
 70  {
 71  	myfunc=(encode)?_encode_ima_adpcm_i16_u8:_decode_ima_adpcm_u8_i16;
 72  	stackbase=STACKTOP;
 73  	STACKTOP+=4*2; //sizeof(int)*2
 74  	myfunc(stackbase, pinput, poutput, input_length, state.ptr);
 75  	state.arr[0]=getValue(stackbase+0,'i32');
 76  	state.arr[1]=getValue(stackbase+4,'i32');
 77  	STACKTOP=stackbase;
 78  };
 79  
 80  sdrjs.ImaAdpcm=function()
 81  {
 82  	this.BUFSIZE=1024*64;
 83  	this.ima_adpcm_state=asm$.malloc(Int32Array,2);
 84  	this.i16_buffer=asm$.malloc(Int16Array,this.BUFSIZE*2);
 85  	this.u8_buffer=asm$.malloc(Uint8Array,this.BUFSIZE);
 86  	this.ima_adpcm_state.arr[0]=0;
 87  	this.ima_adpcm_state.arr[1]=0;
 88  
 89  	this.encode=function(data)
 90  	{
 91  		//not_tested_yet
 92  		asm$.cpy(this.i16_buffer.arr,0,data,0,data.length);
 93  		ima_adpcm_codec(true,this.i16_buffer.ptr,this.u8_buffer.ptr,data.length,this.ima_adpcm_state);		
 94  		out=new Uint8Array(data.length/2);
 95  		asm$.cpy(out,0,this.u8_buffer,0,data.length/2);
 96  		return out;	
 97  	};
 98  
 99  	this.decode=function(data)
100  	{
101  		asm$.cpy(this.u8_buffer.arr,0,data,0,data.length);
102  		ima_adpcm_codec(false,this.u8_buffer.ptr,this.i16_buffer.ptr,data.length,this.ima_adpcm_state);
103  		out=new Int16Array(data.length*2);
104  		asm$.cpy(out,0,this.i16_buffer.arr,0,data.length*2);
105  		return out;	
106  	};
107  	this.reset=function() { this.ima_adpcm_state.arr[0]=this.ima_adpcm_state.arr[1]=0|0; }
108  };
109  
110  sdrjs.REBUFFER_FIXED=0; //rebuffer should return arrays of fixed size
111  sdrjs.REBUFFER_MAX=1;	//rebuffer should return arrays with a maximal size of the parameter size
112  
113  sdrjs.Rebuffer=function(size,mode)
114  {
115  	this.mode=mode;
116  	this.size=size;
117  	this.total_size=0;
118  	this.arrays=[];
119  	this.last_arr=[];
120  	this.last_arr_offset=0;
121  	this.push=function(data)
122  	{
123  		this.total_size+=data.length;
124  		this.arrays.push(data);
125  	};
126  	this.remaining=function() 
127  	{ 
128  		var fixed_bufs_num=Math.floor(this.total_size/this.size);
129  		if(!this.mode) return fixed_bufs_num;
130  		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)
131  	};
132  	this.take=function() { var a=this._take(); /*console.log(a);*/ return a; };
133  	this._take=function() 
134  	{
135  		var remain=this.size;
136  		var offset=0;
137  		var obuf=new Float32Array(size);
138  		//console.log("==== get new obuf ====", size);
139  		while(remain)
140  		{
141  			if(this.last_arr_offset==this.last_arr.length)
142  			{
143  				if(this.arrays.length==0)
144  				{ 
145  					//console.log("this should not happen");
146  					if(this.mode) //REBUFFER_MAX
147  					{
148  						this.total_size=0;
149  						return obuf.subarray(0,offset);  
150  					}
151  					else return new Float32Array(0); //REBUFFER_FIXED
152  				}
153  				//console.log("pick new last_arr");
154  				this.last_arr=this.arrays.shift();
155  				this.last_arr_offset=0;
156  			}
157  			var rwithin=this.last_arr.length-this.last_arr_offset;
158  			//console.log("b :: ","remain", remain, "rwithin",rwithin,"last_arr.length",this.last_arr.length,"larroffset",this.last_arr_offset,"offset",offset);
159  			if(remain<rwithin)
160  			{
161  				//console.log("remain < rwithin"); //seems problematic @Andris
162  				for(var i=0;i<remain;i++) obuf[offset++]=this.last_arr[this.last_arr_offset++];
163  				remain=0;
164  			}
165  			else
166  			{
167  				//console.log("remain > rwithin");
168  				for(var i=0;i<rwithin;i++) obuf[offset++]=this.last_arr[this.last_arr_offset++];
169  				remain-=rwithin;
170  			}
171  			//console.log("e :: ","remain", remain, "rwithin",rwithin,"last_arr.length",this.last_arr.length,"larroffset",this.last_arr_offset,"offset",offset);
172  		}
173  			
174  		this.total_size-=obuf.length;
175  		//console.log("return _take");
176  		return obuf;
177  	};
178  };
179  
180  sdrjs.RationalResamplerFF=function(interpolation,decimation,transition_bw,window)
181  {
182  	this.interpolation=interpolation;
183  	this.decimation=decimation;
184  	this.transition_bw = (typeof transition_bw=='undefined')?0.05:transition_bw;
185  	this.window = (typeof window=='undefined')?1:window;
186  	this.buffer_size=1024*512;
187  	this.output_buffer_size=Math.floor((this.buffer_size*interpolation)/decimation);
188  	this.input_buffer = asm$.malloc(Float32Array,this.buffer_size);
189  	this.output_buffer = asm$.malloc(Float32Array,this.output_buffer_size);
190  	//Calculate filter
191  	this.taps_length = Math.floor(4/this.transition_bw);
192  	this.taps = asm$.malloc(Float32Array,this.taps_length);
193  	var cutoff_for_interpolation=1.0/interpolation;
194  	var cutoff_for_decimation=1.0/decimation;
195  	var cutoff = (cutoff_for_interpolation<cutoff_for_decimation)?cutoff_for_interpolation:cutoff_for_decimation; //get the lower
196  	firdes_lowpass_f(this.taps.ptr, this.taps_length, cutoff/2, window);
197  	
198  	this.remain = 0;
199  	this.remain_offset=0;
200  	this.last_taps_delay=0;
201  
202  	this.process=function(input)
203  	{
204  		
205  		if(input.length+this.remain > this.buffer_size)
206  		{
207  			return new Float32Array(0); console.log("sdrjs.RationalResamplerFF: critical audio buffering error"); //This should not happen...
208  		/*	console.log("RationalResamplerFF: splitting..."); //TODO: this branch has not been checked
209  			output_buffers=Array();
210  			new_buffer_size=this.buffer_size/2;
211  			i=0;
212  			//process the input in chunks of new_buffer_size, and add the output product Float32Array-s to output_buffers.
213  			while((i++)*new_buffer_size<=input.length)
214  			{
215  				output_buffers.push(this._process_noheapcheck(input.subarray(i*new_buffer_size,(i+1)*new_buffer_size)));
216  			}
217  			//add up the sizes of the output_buffer-s.
218  			total_output_length=0;
219  			output_buffers.forEach(function(a){total_output_length+=a.length;});
220  			//create one big buffer from concatenating the output_buffer-s
221  			output=new Float32Array(total_output_length);
222  			output_pos=0;
223  			output_buffers.forEach(function(a){
224  				asm$.cpy(output,output_pos,a,0,a.length);
225  				output_pos+=a.length;
226  			});
227  			return output;*/
228  		}
229  		else return this._process_noheapcheck(input);
230  	};
231  	this._process_noheapcheck=function(input) //if we are sure we have enough space in the buffers 
232  	{
233  		asm$.cpy(this.input_buffer.arr,0,this.input_buffer.arr,this.remain_offset,this.remain);
234  		asm$.cpy(this.input_buffer.arr, this.remain, input, 0, input.length);
235  		var total_input_size=input.length+this.remain;
236  		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);
237  		this.last_taps_delay=d.last_taps_delay;
238  		this.remain=total_input_size-d.input_processed;
239  		this.remain_offset=d.input_processed;
240  		var output_copy_arr=new Float32Array(d.output_size);
241  		asm$.cpy(output_copy_arr,0,this.output_buffer.arr,0,d.output_size);
242  		return output_copy_arr;
243  	};
244  };
245  
246  
247  _sdrjs_logb=function(what) { document.body.innerHTML+=what+"<br />"; }
248  
249  
250  function test_firdes_lowpass_f_original()
251  {
252  	//Original method explained over here: 
253  	//http://kapadia.github.io/emscripten/2013/09/13/emscripten-pointers-and-pointers.html
254  	_sdrjs_logb("test_firdes_lowpass_f_original():");
255  	_sdrjs_logb("Now designing FIR filter with firdes_lowpass_f in sdr.js...");
256  	_sdrjs_logb("output should be the same as: <strong>csdr firdes_lowpass_f 0.1 101 HAMMING</strong>");
257  	
258  	var outputSize = 101*4;
259  	var outputPtr = Module._malloc(outputSize);
260  	var outputHeap = new Uint8Array(Module.HEAPU8.buffer, outputPtr, outputSize);
261  	firdes_lowpass_f(outputHeap.byteOffset,101,0.1,2);
262  	var output = new Float32Array(outputHeap.buffer, outputHeap.byteOffset, 101);
263  	outputStr=String();
264  	for(i=0;i<output.length;i++) outputStr+=output[i].toFixed(6)+", ";
265  	Module._free(outputHeap.byteOffset);
266  	_sdrjs_logb(outputStr);
267  }
268  
269  
270  function test_firdes_lowpass_f_new()
271  {
272  	//This is much simpler, using asm$
273  	_sdrjs_logb("test_firdes_lowpass_f_new():");
274  	_sdrjs_logb("Now designing FIR filter with firdes_lowpass_f in sdr.js...");
275  	_sdrjs_logb("output should be the same as: <strong>csdr firdes_lowpass_f 0.1 101 HAMMING</strong>");
276  	
277  	output=asm$.malloc(Float32Array,101);
278  	firdes_lowpass_f(output.ptr,101,0.1,2);
279  	outputStr=String();
280  	for(i=0;i<output.arr.length;i++) outputStr+=(output.arr[i]).toFixed(6)+", ";
281  	output.free();
282  	_sdrjs_logb(outputStr);
283  }
284  
285  function test_struct_return_value()
286  {
287  	v=STACKTOP;
288  	STACKTOP+=4*3;
289  	_shift_addition_init(v,0.2);
290  	console.log( 
291  		"sinval=", getValue(v,'float'), 
292  		"cosval=", getValue(v+4,'float'), 
293  		"rate=", getValue(v+8,'float') 
294  	);
295  	STACKTOP=v;
296  }