Whistle detection with devices having ICS Android? - android

I am using musicg library for Whistle Detection in my app.
So far, the library works great when I test it on devices having Froyo, GingerBread or even JellyBean, but when testing on ICS it does not detect the whistles properly.
In the library for Whistle detection, it has a class named, WhistleApi.java having boundary values for frequency, intensity, standard deviation etc:
protected void init(){
// settings for detecting a whistle
minFrequency = 600.0f;
maxFrequency = Double.MAX_VALUE;
minIntensity = 100.0f;
maxIntensity = 100000.0f;
minStandardDeviation = 0.1f;
maxStandardDeviation = 1.0f;
highPass = 100;
lowPass = 10000;
minNumZeroCross = 50;
maxNumZeroCross = 200;
numRobust = 10;
}
So far, I know by analyzing logs that the whistle is not being recognized in the isPassedStandardDeviation(double[][] spectrogramData) of the class DetectionApi.java.
The AudioRecord is being initialized like this:
private int channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
private int sampleRate = 44100;
private int frameByteSize = 2048;
int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
int recBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfiguration, audioEncoding); // need to be larger than size of a frame
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfiguration, audioEncoding, recBufSize);
I have tried different workarounds by changing the boundary value in WhistleApi.java class to no results. Can anyone guide me, where am I overlooking or where can I find the mistake in the library ?
Thanks in advance :)

I faces similar problem. For me whistleDemo was detecting whistle on micromax funbook pro tablet with ICS but was not detecting whistle in micromax A110 phone with ICS.
In whistleApi I changed minNumZeroCross from 50 to 20 and it resolved the problem.

Related

How to generate a tone of specified frequncy for a fixed duration

I am new to android.
Can someone help me with a non-deprecated code to generate a tone of F frequency and S second duration
I found this but it uses deprecated methods.
Here is a rendition of the linked code, adapted for API level 23+, with a parameter added for tone duration:
short generatedSnd[];
int sampleRate = 44100;
float freqOfTone = 1000; //Hz
float amplitude = 10000; //0..32767 (0x7FFF)
float lengthSeconds = 1.0f;
private void genTone(){
int numSamples = (int) (sampleRate * lengthSeconds);
generatedSnd = new short[numSamples];
// fill out the array
for (int i = 0; i < numSamples; ++i) {
generatedSnd[i] = (short) (Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone)) * amplitude);
}
}
private void playSound(){
AudioTrack audioTrack = new AudioTrack.Builder()
.setAudioFormat(
new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(sampleRate)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build()
)
.setTransferMode(AudioTrack.MODE_STATIC)
.setBufferSizeInBytes(generatedSnd.length * 2) //2 bytes-per-sample
.build();
audioTrack.write(generatedSnd, 0, generatedSnd.length);
audioTrack.play();
}
This code has been tested up to 50s in the emulator, but it may crash at higher play times, due to the size being passed to setBufferSize(). Note it does not include other advanced features to help you handle arbitrarily long play times, such as 1.) streaming playback, or 2.) phase correction due to float quantization errors at values far from 0.
It should work fine for durations less than about 10 seconds, however.
Also omitted is the AudioTrack cleanup code (stop()/release()).

AudioRecord produces choppy audio

I am using AudioRecord to capture audio packets and stream them to a voice recognition server.
In my Galaxy Note 4, Android M device, it works perfectly fine.
However, when I use other devices (Nexus 7/Android L and HTC combo/android ICS) the resulting audio is choppy, with glitchy noises in the sound every half a second that spoil the speech recognition process at the server.
I know this is a complicated topic, does somebody know how to deal with this audio capture irregularities in android?
This is my code setup:
private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
private static final int SAMPLING_RATE = 16000; //44100,
private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
private static final int BIT_RATE = AudioFormat.ENCODING_PCM_16BIT;
bufferSize = AudioRecord.getMinBufferSize(SAMPLING_RATE,
CHANNEL_CONFIG,
BIT_RATE;
audioBuffer = new byte[bufferSize];
AudioRecord recorder = new AudioRecord(AUDIO_SOURCE,
SAMPLING_RATE,
CHANNEL_CONFIG,
BIT_RATE,
bufferSize);
recorder.startRecording();
while (isRecording) {
short[] buffer = new short[bufferSize];
int shorts_recorded = recorder.read(buffer, 0, buffer.length);
byte[] audioBytes = new byte[bufferSize*2]; //bufferSize*2
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(buffer);//runningBuffer.get(0));
Integer.toString(audioBytes.length)+","+audioBuffer.length);
handler.onAudioDataCapture(audioBytes); //expose audio data to upload callback interface
proceed();
}

How to compute FFT point from sampling rate in audio recording

I have a sample code that fixed sampling rate, fft point in audio recording. This code is
private static final String FILE_NAME = "audiorecordtest.raw";
private static final int SAMPLING_RATE = 44100;
private static final int FFT_POINTS = 1024;
private static final int MAGIC_SCALE = 10;
private void proceed() {
double temp;
Complex[] y;
Complex[] complexSignal = new Complex[FFT_POINTS];
for (int i=0; i<FFT_POINTS; i++) {
temp = (double)((audioBuffer[2*i] & 0xFF) | (audioBuffer[2*i+1] << 8)) / 32768.0F;
complexSignal[i] = new Complex(temp * MAGIC_SCALE, 0d);
}
y = FFT.fft(complexSignal);
/*
* See http://developer.android.com/reference/android/media/audiofx/Visualizer.html#getFft(byte[]) for format explanation
*/
final byte[] y_byte = new byte[y.length*2];
y_byte[0] = (byte) y[0].re();
y_byte[1] = (byte) y[y.length - 1].re();
for (int i = 1; i < y.length - 1; i++) {
y_byte[i*2] = (byte) y[i].re();
y_byte[i*2+1] = (byte) y[i].im();
}
if (handler != null) {
handler.onFftDataCapture(y_byte);
}
}
That code is used to record raw file from audio recording. However, I want to change SAMPLING_RATE to 16000. Could I used same FFT_POINTS is 1024? If not, Please suggest to me how to compute it and MAGIC_SCALE. I tried to used that values but the sound appear noise. Thanks.
The reference link is here
The FFT algorithm doesn't care about the sampling rate. I know that sounds somewhat non-intuitive, but each sample of the output (referred to as a bin) represents the magnitude of the content that is (SAMPLING_FREQUENCY / FFT_POINTS) Hz wide.
MAGIC_SCALE is just a value to scale the data and doesn't have a real impact when you're dealing with doubles. If it were a DFFT using 16 bit integers, you'd have a scaling factor to ensure your input doesn't saturate/overflow during it's calculations.
Notice that the FFT function is never told what SAMPLING_FREQUENCY or MAGIC_SCALE is.
In the case of 44100, and 1024, each bin is the spectral content of ~43 Hz. In the case of 16000, it's ~15Hz.
If 44100 works and 16000 doesn't, the problem is probably in the code that manages your audioBuffer[] variable.

Improve performance of musical note synthesis using AudioTrack

I am trying to build an android app which synthesizes and plays musical notes. I am using AudioTrack. It seems that my program is unable to fill the track buffer fast enough due to the latency in generating the audio information. I am generating the audio info from the fourier coefficients of the note. Hence before each write, the program has to create and sample 2048 sine waves each with a sample size of 2400 and sample rate of 44100!
So instead of a continuous sound I hear intermittent beeps. The Logcat gives the following warning in between beeps:
W/AudioTrack﹕ obtainBuffer() track 0x177ff80 disabled, restarting
My code is given below. Can anyone identify ways in which I could optimize the code?
package com.alantaar.alantaar;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import java.util.Arrays;
public class AudioGenerator {
private AudioTrack audio;
private double[] coefficients;
private int bufferSize;
private int sampleRate;
private double[] phases;
private double frequency;
public AudioGenerator(double[] coefficients, double frequency, int sampleRate, int bufferSize){
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
this.bufferSize = bufferSize > minBufferSize ? bufferSize : minBufferSize;
audio = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, this.bufferSize, AudioTrack.MODE_STREAM);
this.coefficients = coefficients;
this.sampleRate = sampleRate;
this.frequency = frequency;
this.phases = new double[coefficients.length];
Arrays.fill(this.phases, 0.0);
Log.i("length", Integer.toString(coefficients.length));
audio.play();
}
public void playNote(){
while(true){
short[] waveSample = sampleWave();
audio.write(waveSample, 0, waveSample.length);
}
}
private short[] sampleWave(){
short [] waveSample = new short[bufferSize];
Arrays.fill(waveSample, (short)0);
for(int i = 0; i < coefficients.length; i++){
double coefficient = coefficients[i];
short[] sineSamples = sampleSineWave(coefficient, i);
for(int j = 0; j < waveSample.length; j++){
waveSample[j] += sineSamples[j];
}
}
return waveSample;
}
private short [] sampleSineWave(double coefficient, int index){
double freq = frequency * index;
short [] samples = new short[bufferSize];
for(int i = 0; i < bufferSize; i++){
samples[i] = (short) (coefficient * Short.MAX_VALUE * Math.cos(phases[index]));
phases[index] += 2 * Math.PI * freq/sampleRate;
}
return samples;
}
public void pauseNote(){
audio.stop();
}
public void stopNote(){
audio.release();
}
}
Here are a few things that pop out at me:
Move computations out of the inner loop. For example, the 2*pi*freq/sampleRate could be done right before the for. Same with coefficient * Short.MAX_VALUE.
I'd bet that your note doesn't actually contain 2048 different meaningful sine components.One option would be to NOT generate tones when the coefficient falls below a certain threshold.
Use FFT! You are implementing a DFT which is O(n^2). FFT runs in O(n log n).
Use the time while audio.write is blocking to generate more samples. I don't know the behavior of AudioTrack's streaming mode but there is a good chance that your program is spending most of its time in a blocking call.

Detecting the current volume on Android

I'm building an application that is always recording audio from the microphone, whenever the audio reaches a certain threshold I perform a certain action.
However how should I calc the appropriate volume for the threshold ? I've a static volume coded which works well across some devices but not all devices (in somes cases it is too sensitive or vice versa).
I'm using AudioRecord, here's part of the code:
int bufferSize = AudioRecord.getMinBufferSize(Constants.RECORDING_FREQUENCY,Constants.channelConfiguration,Constants.audioEncoding);
AudioRecord audioRecord = new AudioRecord( MediaRecorder.AudioSource.MIC,Constants.RECORDING_FREQUENCY,Constants.channelConfiguration,Constants.audioEncoding, bufferSize);
short[] buffer = new short[bufferSize];
while(true) {
int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
for (int i = 0; i < bufferReadResult; i++) {
currentVolume = java.lang.Math.abs(buffer[i]);
if (currentVolume > Constants.NO_VOLUME_AMPLITUDE)
// ALRIGHT ! This is what I'm looking for :D
}
}
So, my question is: how do I calculate Constants.NO_VOLUME_AMPLITUDE instead of having it hard coded ?
Thanks so much in advance,
Ze

Categories

Resources