- #1
joseche
- 3
- 0
Hi there, I am using a basic java program to identify the frequency of a note captured by the microphone.
The problem is that frequencies don't seem accurate.
The problem is that frequencies don't seem accurate.
Code:
package com.overdrive.FreqFinder;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;
import org.apache.commons.math3.transform.TransformType;
public class AudioInput {
TargetDataLine microphone;
final int audioFrames= 2048; //power ^ 2
final float sampleRate= 8000.0f;
final int bitsPerRecord= 16;
final int channels= 1;
final boolean bigEndian = true;
final boolean signed= true;
byte byteData[]; // length=audioFrames * 2
double doubleData[]; // length=audioFrames only reals needed for apache lib.
AudioFormat format;
FastFourierTransformer transformer;
double frequencyTable[][]= new double[12][8]; //12 notes, 8 octaves
String notes[];
public AudioInput () {
byteData= new byte[audioFrames * 2]; //two bytes per audio frame, 16 bits
//doubleData= new double[audioFrames * 2]; // real & imaginary
doubleData= new double[audioFrames]; // only real for apache
transformer = new FastFourierTransformer(DftNormalization.STANDARD);
System.out.print("Microphone initialization\n");
format = new AudioFormat(sampleRate, bitsPerRecord, channels, signed, bigEndian);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info)) {
System.err.print("isLineSupported failed");
System.exit(1);
}
try {
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
System.out.print("Microphone opened with format: "+format.toString()+"\n");
microphone.start();
}catch(Exception ex){
System.out.println("Microphone failed: "+ex.getMessage());
System.exit(1);
}
notes= new String[12];
notes[0]= "C";
notes[1]= "C#";
notes[2]= "D";
notes[3]= "D#";
notes[4]= "E";
notes[5]= "F";
notes[6]= "F#";
notes[7]= "G";
notes[8]= "G#";
notes[9]= "A";
notes[10]= "A#";
notes[11]= "B";
buildFreqTable();
}
public int readPcm(){
int numBytesRead=
microphone.read(byteData, 0, byteData.length);
if(numBytesRead!=byteData.length){
System.out.println("Warning: read less bytes than buffer size");
System.exit(1);
}
return numBytesRead;
}
public void byteToDouble(){
ByteBuffer buf= ByteBuffer.wrap(byteData);
buf.order(ByteOrder.BIG_ENDIAN);
int i=0;
while(buf.remaining()>2){
short s = buf.getShort();
doubleData[ i ] = (new Short(s)).doubleValue();
++i;
}
}
public void buildFreqTable(){
frequencyTable[0][0]= 32.7032; // C
frequencyTable[1][0]= 34.6478; // C#
frequencyTable[2][0]= 36.7081; // D
frequencyTable[3][0]= 38.8909; // D#
frequencyTable[4][0]= 41.2034; // E
frequencyTable[5][0]= 43.6535; // F
frequencyTable[6][0]= 46.2493; // F#
frequencyTable[7][0]= 48.9994; // G
frequencyTable[8][0]= 51.9131; // G#
frequencyTable[9][0]= 55.0000; // A
frequencyTable[10][0]= 58.2705; // A#
frequencyTable[11][0]= 61.7354; // B
for (int note=0; note<12; note++){
for(int oct=1; oct<8; oct++){
frequencyTable[note][oct]= frequencyTable[note][oct-1]*2;
}
}
}
public int findNearFreq(double freq){
double dMin= Double.MAX_VALUE, dc;
int curNote=0;
for (int note=0; note<12; note++){
for (int oct=0; oct<8; oct++){
//calculate the distance
if( frequencyTable[note][oct] > freq )
dc= frequencyTable[note][oct] - freq;
else dc= freq - frequencyTable[note][oct];
// see if new closer distance
if (dMin > dc){
dMin= dc;
curNote= note;
}
}
}
return curNote;
}
public String noteName(int n){
return notes[n];
}
public void findFrequency(){
double frequency;
Complex[] cmplx= transformer.transform(doubleData, TransformType.FORWARD);
double real;
double im;
double mag[] = new double[cmplx.length];
for(int i = 0; i < cmplx.length; i++){
real = cmplx[i].getReal();
I am = cmplx[i].getImaginary();
mag[i] = Math.sqrt((real * real) + (im*im));
}
double peak = -1.0;
int index=-1;
for(int i = 0; i < cmplx.length; i++){
if(peak < mag[i]){
index=i;
peak= mag[i];
}
}
frequency = (sampleRate * index) / audioFrames;
System.out.print("Index: "+index+", Frequency: "+frequency+", Note: "+ noteName(findNearFreq(frequency)) +"\n");
}
/*
* Print the first frequency bins to know about the resolution we have
*/
public void printFreqs(){
for (int i=0; i<audioFrames/4; i++){
System.out.println("bin "+i+", freq: "+(sampleRate*i)/audioFrames);
}
}
public static void main(String[] args) {
AudioInput ai= new AudioInput();
int turns=10000;
while(turns-- > 0){
ai.readPcm();
ai.byteToDouble();
ai.findFrequency();
}
//ai.printFreqs();
}
}