Package com.talixa.specan.dsp

Source Code of com.talixa.specan.dsp.FrequencyTranslator

package com.talixa.specan.dsp;

import java.io.IOException;

import com.talixa.audio.riff.exceptions.RiffFormatException;
import com.talixa.audio.wav.WaveFile;
import com.talixa.audio.wav.WaveGenerator;
import com.talixa.audio.wav.WaveReader;
import com.talixa.specan.fft.Complex;
import com.talixa.specan.fft.FFT;

// TODO What effect would dropping every other value have? How about adding new values between existing ones?
public class FrequencyTranslator {

  /*
   * To make a band pass filter:
   * 1) Run FFT on input data
   * 2) Zero all data above & below the pass range
   * 3) DeFFT the data
   * 4) Output
   */
 
  private static final int FFT_LEN = 8192*8;
  private static final int SHIFT_VALUE = FFT_LEN;  
 
  private static short[] shift(short[] data, int shift) {               
    int numberSamples = data.length;
    short[] shiftedData = new short[numberSamples];
    Complex[] amplitudeData = new Complex[FFT_LEN];
    Complex[] frequencyData = new Complex[FFT_LEN]
   
    for(int baseAddress = 0; (baseAddress)+FFT_LEN < numberSamples; baseAddress+=SHIFT_VALUE) {     
      // fill the data array
      for (int offset = 0; offset < FFT_LEN; offset++) {
        int desiredSampleIndex = (baseAddress)+offset;         
        short signedSample = data[desiredSampleIndex];                 
        double sample = ((double) signedSample) / (Short.MAX_VALUE);
        amplitudeData[offset] = new Complex(sample,0);
      }                             

      // run fft
      frequencyData = FFT.fft(amplitudeData);
                 
      if (shift < 0) {
        // downshift
       
        // calculate new 0
        int newZero = SharedDSPFunctions.getSampleNumberByFrequency(FFT_LEN, shift*-1);
       
        // shift new zero to zero
        for(int i = 0; i < FFT_LEN/2; ++i) {
          Complex value;
          if (i + newZero < FFT_LEN/2) {
            value = frequencyData[i+newZero];
          } else {
            value = new Complex(0,0);
          }
       
          frequencyData[i] = value;
          frequencyData[FFT_LEN-i-1] = value;
       
      } else {
        // calculate where to put the old 0
        int oldZero = SharedDSPFunctions.getSampleNumberByFrequency(FFT_LEN, shift);
       
        // upshift
        for(int i = FFT_LEN/2-1; i > 0 ; --i) {
          Complex value;
          if (i - oldZero > 0) {
            value = frequencyData[i-oldZero];
          } else {
            value = new Complex(0,0);
          }
       
          frequencyData[i] = value;
          frequencyData[FFT_LEN-i-1] = value;
       
      }
     
      // undo fft
      Complex[] filterFft = FFT.ifft(frequencyData);
     
      // create new data array
      for(int i = 0; i < FFT_LEN; ++i) {         
        shiftedData[baseAddress+i] = (short)(filterFft[i].re() * Short.MAX_VALUE);       
      }           
    }
                   
    return shiftedData;
  }
   
  public static short[] doDoubleShift(short[] data, int frequency) {           
    // single pass causes amplitude variations on constant carrier
    // two passes, shifted 50% and averaged together works well
   
    // first shift
    short[] shifted1 = shift(data, frequency);
   
    // offset 50% and shift again
    short[] data2 = new short[data.length - FFT_LEN/2];
    for(int i = 0; i+FFT_LEN/2 < data.length; ++i) {
      data2[i] = data[i+FFT_LEN/2];
    }
    short[] shifted2 = shift(data2, frequency);
   
    // line up data, and average values
    short[] outputData = new short[shifted2.length];
    for(int i = 0; i < outputData.length; ++i) {
      outputData[i] = (short)((shifted1[i+FFT_LEN/2] + shifted2[i]) / 2);
    }
   
    // return shifted data
    return outputData;
  }
 
  public static short[] shiftDown(short[] data, int frequency) {
    return doDoubleShift(data, frequency * -1);
  }
 
  public static void shiftDown(short[] data, int frequency, String outputFile) throws IOException {
    short[] shifted = shiftDown(data, frequency);         
    byte[] byteData = SharedDSPFunctions.shortArrayToByteArray(shifted);                   
    WaveFile out = WaveGenerator.generateWaveFromRaw16bitPcm(byteData);
    out.outputToFile(outputFile);   
  }
 
  public static short[] shiftUp(short[] data, int frequency) {
    return doDoubleShift(data, frequency);
  }
 
  public static void shiftUp(short[] data, int frequency, String outputFile) throws IOException {
    short[] shifted = shiftUp(data, frequency);         
    byte[] byteData = SharedDSPFunctions.shortArrayToByteArray(shifted);                   
    WaveFile out = WaveGenerator.generateWaveFromRaw16bitPcm(byteData);
    out.outputToFile(outputFile);   
  }
 
  public static void main(String args[]) {
    String testFile = "/home/thomas/audio/1000Hz.wav";
    String downFile  = "/home/thomas/audio/900Hz.wav";
    String upFile  = "/home/thomas/audio/1100Hz.wav";
    try {               
      WaveFile waveFile = WaveReader.readFromFile(testFile);
      short[] data = SharedDSPFunctions.extractWaveFileData(waveFile)
      shiftDown(data, 100, downFile);
      shiftUp(data, 100, upFile);
     
    } catch (IOException e) {     
      e.printStackTrace();
    } catch (RiffFormatException e) {
      e.printStackTrace();
   
  } 
}
TOP

Related Classes of com.talixa.specan.dsp.FrequencyTranslator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.