/******************************************************************************* * sdrtrunk * Copyright (C) 2014-2017 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/> * ******************************************************************************/ package source.tuner.airspy; import dsp.filter.dc.DCRemovalFilter_RB; import dsp.filter.hilbert.HilbertTransform; import sample.adapter.ISampleAdapter; public class AirspySampleAdapter implements ISampleAdapter { private static final float SCALE_SIGNED_12_BIT_TO_FLOAT = 1.0f / 2048.0f; private DCRemovalFilter_RB mDCFilter = new DCRemovalFilter_RB(0.01f); private HilbertTransform mHilbertTransform = new HilbertTransform(); 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; } @Override public float[] convert(byte[] samples) { float[] realSamples; if(mSamplePacking) { realSamples = convertPacked(samples); } else { realSamples = convertUnpacked(samples); } mDCFilter.filter(realSamples); return mHilbertTransform.filter(realSamples); } /** * 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 data1 - 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; } }