content: package device.airspy;
  
  /*******************************************************************************
   *     SDR Trunk 
   *     Copyright (C) 2015 Dennis Sheirer
   * 
   *     This program is free software: you can redistribute it and/or modify
   *     it under the terms of the GNU General Public License as published by
   *     the Free Software Foundation, either version 3 of the License, or
   *     (at your option) any later version.
   * 
   *     This program is distributed in the hope that it will be useful,
   *     but WITHOUT ANY WARRANTY; without even the implied warranty of
   *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *     GNU General Public License for more details.
   * 
   *     You should have received a copy of the GNU General Public License
   *     along with this program.  If not, see <http://www.gnu.org/licenses/>
   ******************************************************************************/
  
  
  public class AirspySampleAdapter 
  {
  	private static final float SCALE_SIGNED_12_BIT_TO_FLOAT = 1.0f / 2048.0f;
  	
  	private boolean mSamplePacking = false;
  
  	/**
  	 * Adapter to translate byte buffers received from the airspy tuner into 
  	 * float buffers for processing.
  	 */
  	public AirspySampleAdapter()
  	{
  	}
  
  	/**
  	 * Sample packing places two 12-bit samples into 3 bytes when enabled or 
  	 * places two 12-bit samples into 4 bytes when disabled.
  	 * 
  	 * @param enabled 
  	 */
  	public void setSamplePacking( boolean enabled )
  	{
  		mSamplePacking = enabled;
  	}
  	
  	public float[] convert( byte[] samples )
  	{
  		if( mSamplePacking )
  		{
  			return convertPacked( samples );
  		}
  		else
  		{
  			return convertUnpacked( samples );
  		}
  	}
  
  	/**
  	 * Converts the byte array containing unsigned 12-bit short values into
  	 * signed float values in the range -1 to 1;
  	 * 
  	 * @param data - byte array of unsigned 16-bit values
  	 * @return converted float values
  	 */
  	private float[] convertUnpacked( byte[] data )
  	{
  		float[] samples = new float[ data.length / 2 ];
  
  		int pointer = 0;
  		
  		for( int x = 0; x < data.length; x += 2 )
  		{
  			samples[ pointer++ ] = scale( ( data[ x ] & 0xFF ) | 
  										  ( data[ x + 1 ] << 8 ) );
  		}
  		
  		return samples;
  	}
  	
  	/**
  	 * Converts every 3 bytes containing a pair of 12-bit unsigned values into
  	 * a pair of float values in the range -1 to 1;
  	 * 
  	 * @param data - byte array of unsigned 12-bit values
  	 * @return converted float values
  	 */
  	private float[] convertPacked( byte[] data1 )
  	{
  		byte[] data = new byte[ data1.length ];
  
  		//Convert big-endian to little-endian
  		for( int x = 0; x < data1.length; x += 4 )
  		{
  			data[ x ] = data1[ x + 3 ];
  			data[ x + 1 ] = data1[ x + 2 ];
  			data[ x + 2 ] = data1[ x + 1 ];
  			data[ x + 3 ] = data1[ x ];
  		}
  		
  		int count = (int)( (float)data.length / 1.5f );
  
  		/* Ensure we have an even number of samples */
  		if( count % 2 == 1 )
  		{
  			count--;
  		}
  
  		int bytes = (int)((float)count * 1.5f);
  
  		float[] samples = new float[ count ];
  		
  		int pointer = 0;
  		
  		int first;
  		int second;
  		
  		for( int x = 0; x < bytes; x += 3 )
  		{
  			first = ( ( data[ x ] << 4 ) & 0xFF0 ) | 
  					( ( data[ x + 1 ] >> 4 ) & 0xF );
  
  			samples[ pointer++ ] = scale( first );
  
  			second = ( ( data[ x + 1 ] << 8 ) & 0xF00 ) |
  					   ( data[ x + 2 ] & 0xFF );
  			
  			samples[ pointer++ ] = scale( second );
  		}
  		
  		return samples;
  	}
  
  	/**
  	 * Converts unsigned 12-bit values to signed 12-bit values and then scales
  	 * the signed value to a signed float value in range: -1.0 : +1.0
  	 */
  	public static float scale( int value )
  	{
  		return (float)(( value & 0xFFF ) - 2048 ) * SCALE_SIGNED_12_BIT_TO_FLOAT;
  	}
  }
  