Package com.talixa.specan.demod.ook

Source Code of com.talixa.specan.demod.ook.CwDemod

package com.talixa.specan.demod.ook;

import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Queue;

import com.talixa.audio.riff.exceptions.RiffFormatException;
import com.talixa.audio.wav.WaveFile;
import com.talixa.audio.wav.WaveReader;
import com.talixa.specan.SpectrumAnalyzer;
import com.talixa.specan.dsp.SharedDSPFunctions;

public class CwDemod {
 
 
  /*
   * How to decode CW?
   * count on/off periods
   * convert to morse
   */
     
  private static boolean debug = false;        // true for logging
  private static boolean gui = true
 
  private short[] data;                // pcm samples
  private int wpm;
 
  public CwDemod(String inputFile) throws IOException, RiffFormatException {
    WaveFile waveFile;
    if (gui) {
      waveFile = SpectrumAnalyzer.readWaveFile(inputFile);
    } else {
      waveFile = WaveReader.readFromFile(inputFile);
   
   
    data = SharedDSPFunctions.extractWaveFileData(waveFile);
  }
 
  public CwDemod(short[] data) {
    this.data = data;
  }
 
  public String demodulate() {
    int sampleSize = 11;
    int sampleLowHigh = (sampleSize - 1) / 2;
   
    // count of high/low waves
    int onCount = 0;
    int offCount = 0;
    int shortestTransition = 9999;
   
    Queue<Integer> countLengths = new ArrayDeque<Integer>()
   
    for(int i = sampleLowHigh; i < data.length - sampleLowHigh; ++i) {
      double avg = getAverage(data, i, sampleLowHigh);
      if (avg > 10000) {       
        if (offCount > 10) {
          //System.out.println("OFFCOUNT: " + offCount);
          if (countLengths.size() != 0) {
            // always want array to start with mark condition
            countLengths.add(offCount);
          }
          offCount = 0;
        }
        ++onCount;
      } else {           
        if (onCount > 10) {
          //System.out.println("ONCOUNT: " + onCount);
          countLengths.add(onCount);
          if (onCount < shortestTransition) {
            shortestTransition = onCount;
          }   
          onCount = 0;
        }
        ++offCount;
      }
    }
   
    double shortTransitionLength = shortestTransition / 8000f;
    wpm = (int)Math.pow((shortTransitionLength * 1000) / 1200, -1);
    debug("WPM: " + wpm);
   
    // now we have the transition states in countLengths and the short transition length
    // go through and figure out dots/dashes
    boolean isMark = true;
    StringBuilder morseString = new StringBuilder();
    while (!countLengths.isEmpty()) {
      int currentLength = countLengths.poll();
      double duration = currentLength / shortestTransition;
      if (isMark) {       
        if (duration > 2.5 && duration < 3.5) {
          morseString.append("-");
        } else if (duration > .8 && duration < 1.2) {
          morseString.append(".");
        }
      } else {
        if (duration > 2.5 && duration < 3.5) {
          morseString.append(" ");
        } else if (duration > .8 && duration < 1.2){
          morseString.append("");
        } else if (duration > 9.5 && duration < 10.5){
          morseString.append("\n");
        }
      }
      isMark = !isMark;
    }
    return MorseCodeDecoder.decodeMorse(morseString.toString());
  }
 
  public int getWpm() {
    return wpm;
  }
 
  // instead of ever using a single point, average 5 points together to determine high/low
  private double getAverage(short[] samples, int averagePoint, int sampleLowHigh) {
    double sum = 0;
    for(int sampleId = sampleLowHigh * -1; sampleId < sampleLowHigh; ++sampleId) {
      sum += Math.abs(samples[averagePoint + sampleId]);       
    }
    return sum/ (sampleLowHigh*2+1)
  }
 
  private void debug(String msg) {
    if (debug) {     
      System.out.println(msg);
    }
  } 
   
  private static final String PATH_LINUX = "/home/thomas/git/specan/SpecAn/res/";
  private static final String PATH_WIN = "C:\\users\\tgerlach\\git\\specan\\SpecAn\\res\\";
  private static final String[] TEST_FILES = {"cw-5wpm.wav"};
 
  public static void main(String[] args) {
    debug = true;
    testDemod();             
  }   
 
  public static void testDemod() {
    boolean usingWindows = System.getProperty("os.name").toLowerCase().contains("windows");
    String path;
    if (usingWindows) {
      path = PATH_WIN;
    } else {
      path = PATH_LINUX;
    }
   
    gui = false;
    for(int i = 0; i < TEST_FILES.length; ++i) {
      System.out.print("***********************");
      System.out.print(TEST_FILES[i]);
      System.out.println("***********************");
      String inputFile = path + TEST_FILES[i]
      try {
        CwDemod demod = new CwDemod(inputFile);
        String data = demod.demodulate();       
        System.out.println(data);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
TOP

Related Classes of com.talixa.specan.demod.ook.CwDemod

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.