I made a small signal processing application. It processes the audio signal (Morse code) at a specific frequency using the Goerztel algorithm. The application saves the temporary file to the file system and, after recording is complete, begins to detect signals. Now I got a result with many quantities.
I do not know what to read from these quantities. How can I decipher the morse code from these values? How can I read them? I tried to find links, but nowhere is it explained what is the result and how to read it.
EDIT:
My morse code application runs with Delphi and uses the Windows Beep function to send signals at a specific frequency. I use 1200 Hz for signals. Also, pauses between signals and words and Morse sounds are similar to Wikipedia descriptions. All right.
Goertzel.java:
public class Goertzel { private float samplingRate; private float targetFrequency; private int n; private double coeff, Q1, Q2; private double sine, cosine; public Goertzel(float samplingRate, float targetFrequency, int inN) { this.samplingRate = samplingRate; this.targetFrequency = targetFrequency; n = inN; sine = Math.sin(2 * Math.PI * (targetFrequency / samplingRate)); cosine = Math.cos(2 * Math.PI * (targetFrequency / samplingRate)); coeff = 2 * cosine; } public void resetGoertzel() { Q1 = 0; Q2 = 0; } public void initGoertzel() { int k; float floatN; double omega; floatN = (float) n; k = (int) (0.5 + ((floatN * targetFrequency) / samplingRate)); omega = (2.0 * Math.PI * k) / floatN; sine = Math.sin(omega); cosine = Math.cos(omega); coeff = 2.0 * cosine; resetGoertzel(); } public void processSample(double sample) { double Q0; Q0 = coeff * Q1 - Q2 + sample; Q2 = Q1; Q1 = Q0; } public double[] getRealImag(double[] parts) { parts[0] = (Q1 - Q2 * cosine); parts[1] = (Q2 * sine); return parts; } public double getMagnitudeSquared() { return (Q1 * Q1 + Q2 * Q2 - Q1 * Q2 * coeff); } }
SoundCompareActivity.java
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.app.Activity; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class SoundCompareActivity extends Activity { private static final int RECORDER_SAMPLE_RATE = 8000; // at least 2 times // higher than sound // frequency, private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_CONFIGURATION_MONO; private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT; private AudioRecord recorder = null; private int bufferSize = 0; private Thread recordingThread = null; private boolean isRecording = false; private Button startRecBtn; private Button stopRecBtn; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); startRecBtn = (Button) findViewById(R.id.button1); stopRecBtn = (Button) findViewById(R.id.button2); startRecBtn.setEnabled(true); stopRecBtn.setEnabled(false); bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLE_RATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING); startRecBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.d("SOUNDCOMPARE", "Start Recording"); startRecBtn.setEnabled(false); stopRecBtn.setEnabled(true); stopRecBtn.requestFocus(); startRecording(); } }); stopRecBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.d("SOUNDCOMPARE", "Stop recording"); startRecBtn.setEnabled(true); stopRecBtn.setEnabled(false); startRecBtn.requestFocus(); stopRecording(); } }); } private void startRecording() { recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLE_RATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize); recorder.startRecording(); isRecording = true; recordingThread = new Thread(new Runnable() { @Override public void run() { writeAudioDataToTempFile(); } }, "AudioRecorder Thread"); recordingThread.start(); } private String getTempFilename() { File file = new File(getFilesDir(), "tempaudio"); if (!file.exists()) { file.mkdirs(); } File tempFile = new File(getFilesDir(), "signal.raw"); if (tempFile.exists()) tempFile.delete(); return (file.getAbsolutePath() + "/" + "signal.raw"); } private void writeAudioDataToTempFile() { byte data[] = new byte[bufferSize]; String filename = getTempFilename(); FileOutputStream os = null; try { os = new FileOutputStream(filename); } catch (FileNotFoundException e) { e.printStackTrace(); } int read = 0; if (os != null) { while (isRecording) { read = recorder.read(data, 0, bufferSize); if (read != AudioRecord.ERROR_INVALID_OPERATION) { try { os.write(data); } catch (IOException e) { e.printStackTrace(); } } } try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } private void deleteTempFile() { File file = new File(getTempFilename()); file.delete(); } private void stopRecording() { if (recorder != null) { isRecording = false; recorder.stop(); recorder.release(); recorder = null; recordingThread = null; } new MorseDecoder().execute(new File(getTempFilename())); } }
MorseDecoder.java:
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ShortBuffer; import android.media.AudioFormat; import android.media.AudioRecord; import android.os.AsyncTask; import android.util.Log; public class MorseDecoder extends AsyncTask<File, Void, Void> { private FileInputStream is = null; @Override protected Void doInBackground(File... files) { int index;
EDIT2:
Notifications of errors in sample processing. Changed the code in the while loop.
while(is.read(data) != -1) { ShortBuffer sbuf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); short[] audioShorts = new short[sbuf.capacity()]; sbuf.get(audioShorts); float[] audioFloats = new float[audioShorts.length]; for (int j = 0; j < audioShorts.length; j++) { audioFloats[j] = ((float)audioShorts[j]) / 0x8000; } for (index = 0; index < audioFloats.length; index++) { g.processSample(audioFloats[index]); magnitude = Math.sqrt(g.getMagnitudeSquared()); Log.d("SoundCompare", "Relative magnitude = " + magnitude); }
Regards, evilone