Difficulties using TARSOS DSP to extract MFCC from WavFiles JAVA - java

I am attempting to use the TARSOS DSP library to extract the MFCC values from wav files, before using DTW to calculate the distance between them.
Unfortunately I am having trouble undesrtanding how the code from the MFCC class can be used on a wav file.
I am unsure If I need to convert the wav file into some sort of array buffer first.
Please see the code from the library for the MFCC class at this link.
https://github.com/JorenSix/TarsosDSP/blob/master/src/core/be/tarsos/dsp/mfcc/MFCC.java
If I could get advice about how to properly use this code to get MFCC values from a wav file, or perhaps reccomendattions about another method, I would greatly appreciate it.

This is sample code should do the job for small files. It loads the whole .wav file into a byte array so this is not right approach for big files. The final variables should probably be changed according to your use case. I'm still new to java so there's no guarantee that this is the best approach.
public class App {
private final static String pathToFile = "D:\\TarsosWavTest\\wavs\\1000HzTone.wav";
private final static int audioBufferSize = 2048;
private final static int bufferOverlap = 1024;
private final static int amountOfMelFilters = 20;
private final static int amountOfCepstrumCoef = 30;
private final static float lowerFilterFreq = 133.33f;
private final static float upperFilterFreq = 8000f;
public static void main(String[] args) {
File file = new File(pathToFile);
AudioInputStream audioInputStream;
byte[] byteAudioArray;
AudioDispatcher audioDispatcher;
try {
audioInputStream = AudioSystem.getAudioInputStream(file);
byteAudioArray = audioInputStream.readAllBytes();
} catch (Exception e) {
System.out.println("Exception occured");
e.printStackTrace();
return;
}
try {
audioDispatcher = AudioDispatcherFactory.fromByteArray(byteAudioArray, audioInputStream.getFormat(),
audioBufferSize, bufferOverlap);
} catch (Exception e) {
e.printStackTrace();
return;
}
final MFCC mfccProcessor = new MFCC(audioBufferSize, audioInputStream.getFormat().getSampleRate(),
amountOfCepstrumCoef, amountOfMelFilters, lowerFilterFreq, upperFilterFreq);
audioDispatcher.addAudioProcessor(mfccProcessor);
audioDispatcher.addAudioProcessor(new AudioProcessor() {
#Override // gets called on each audio frame
public boolean process(AudioEvent audioEvent) {
float[] mfccs = mfccProcessor.getMFCC();
/* do whatever necessary with the mfcc elements here
e.g print them */
//System.out.println(Arrays.toString(mfccs));
return true;
}
#Override // gets called when end of the audio file was reached
public void processingFinished() {
System.out.println("end of file reached");
}
});
audioDispatcher.run();// starts a new thread
}}
Please note that different libraries(e.g. librosa) are NOT guaranteed to compute the same MFCCs even with the same input parameters.

Related

JavaSoundRecorder TargetDataLine does not close?

I have a JavaSoundRecorder that I have created as shown below. When I create an object of the class and call the finish() function the line does not stop/close and remains active (does not reach null state). Meaning that I can only make a single recording with the recorder. What can I do to fix this issue?
import java.io.*;
import javax.sound.sampled.*;
import java.util.Set;
public class JavaSoundRecorder {
private TargetDataLine line;
private AudioFileFormat.Type fileType;
private File savedWav;
private AudioFormat audioForm;
private DataLine.Info info;
public int errorNum;
public void setFile(File savedWav) {
this.savedWav = savedWav;
}
/*constructs class*/
public JavaSoundRecorder() {
fileType = AudioFileFormat.Type.WAVE;
audioForm = getAudioFormat();
info = new DataLine.Info(TargetDataLine.class, audioForm);
}
/*
* Defines an audio format
*/
AudioFormat getAudioFormat() {
float sampleRate = 16000;
int sampleSizeInBits = 16;
int channels = 1;
boolean signed = true;
boolean BigEndian = true;
AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels , signed, BigEndian);
return format;
}
/*Captures the sound and records in WAV fiLE, creates a new thread for recording*/
protected int startRecording(String path) {
setFile(new File(path));
errorNum = 0;
if(line == null) {
Thread thread2 = new Thread(new Runnable() {
#Override
public void run() {
try {
//check if system supports the data line
if(!AudioSystem.isLineSupported(info)) {
System.out.println("not supported")
}
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(audioForm);
line.start();
AudioInputStream ais = new AudioInputStream(line);
//write recoding to file..
AudioSystem.write(ais, fileType, savedWav);
}
catch(LineUnavailableException e) {
errorNum = 3;
e.printStackTrace();
}
catch(IOException e) {
errorNum = 4;
e.printStackTrace();
}
}
});
thread2.start();
}
return errorNum;
}
/*stops recording*/
public void finish() {
line.stop();
line.close();
}
}
I'd look at using loose coupling pattern. The finish() method should suggest to the recording thread to do the work of closing and cleaning up, not actually do that work itself. Thus have finish() flip a boolean named something like isRunning to false. The boolean can be volatile to help ensure the change in value is immediately read across the different threads.
With this, move the code which closes and cleans up to the end of the run() method, and surround the code that executes the write() with a while(isRunning) block.
Now, I'm not up enough on the details to know off the top of my head the exact changes required, but I think you will also have to refactor a bit so the writing is an action that repeats, that repeatedly gives control back to the enclosing while() after each write operation.

Android Track progress of Azure CloudBlockBlob upload

How can I print the number of bytes that have been uploaded after calling blob.upload(new FileInputStream(imageFile), imageFile.length()); I want to log something like "100/totalBytes bytes have been uploaded, 224/totalBytes bytes have been uploaded..." So I can create a progress bar of the upload progress.
this is the code:
//AzureBlobLoader extends AsyncTask
public class AzureBlobUploader extends AzureBlobLoader {
private Activity act;
private String userName;
private TaggedImageObject img;
private Fragment histFragment;
public AzureBlobUploader(Fragment f, Activity act, String userName, TaggedImageObject img) {
super();
this.act = act;
this.userName = userName;
this.img = img;
this.histFragment = f;
}
#Override
protected Object doInBackground(Object[] params) {
File imageFile = new File(this.img.getImgPath());
try {
// Define the path to a local file.
final String filePath = imageFile.getPath();
// Create or overwrite the blob with contents from the local file.
String[] imagePathArray = filePath.split("/");
String imageName = imagePathArray[imagePathArray.length-1];
System.out.println("Image Name: " + imageName);
String containerName = userName + "/" + imageName;
System.out.println("Container Name: " + containerName);
CloudBlockBlob blob= this.getContainer().getBlockBlobReference(containerName);
//UPLOAD!
blob.upload(new FileInputStream(imageFile), imageFile.length());
//-----DATABASE-----//
//create client
this.setDBClient(
new MobileServiceClient(
"URL",
this.act.getApplicationContext()
)
);
this.setImageTable(this.getDBClient().getTable(Image.class));
this.setIcavTable(this.getDBClient().getTable(ICAV.class));
//IMG TABLE QUERY
String validImageID = containerName.replace("/", "_");
Log.d("Azure", "Valid Image ID: " + validImageID);
Image img = new Image(validImageID, this.img.getUser(), this.img.getLat(), this.img.getLon());
this.getImageTable().insert(img);
for(String context : this.img.getContextAttributeMap().keySet()){
Map<String,String> attributeValueMap = this.img.getContextAttributeMap().get(context);
for(String attribute : attributeValueMap.keySet()){
String value = attributeValueMap.get(attribute);
ICAV icavRow = new ICAV();
icavRow.setImageID(validImageID);
icavRow.setContextID(context);
icavRow.setAttributeID(attribute);
icavRow.setValue(value);
this.getIcavTable().insert(icavRow);
}
}
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
#Override
protected void onProgressUpdate(Object... object) {
super.onProgressUpdate(object);
Log.d("progressUpdate", "progress: "+((Integer)object[0] * 2) + "%");
}
#Override
protected void onPostExecute(Object o) {
// to do
}
}
As you can see the Azure SDK doesn't directly allow for that, but it should be fairly easy to wrap your inputstream in another input stream that can give callbacks for bytes read. Something like that:
public class ListenableInputStream extends InputStream {
private final InputStream wraped;
private final ReadListener listener;
private final long minimumBytesPerCall;
private long bytesRead;
public ListenableInputStream(InputStream wraped, ReadListener listener, int minimumBytesPerCall) {
this.wraped = wraped;
this.listener = listener;
this.minimumBytesPerCall = minimumBytesPerCall;
}
#Override
public int read() throws IOException {
int read = wraped.read();
if (read >= 0) {
bytesRead++;
}
if (bytesRead > minimumBytesPerCall || read == -1) {
listener.onRead(bytesRead);
bytesRead = 0;
}
return read;
}
#Override
public int available() throws IOException {
return wraped.available();
}
#Override
public void close() throws IOException {
wraped.close();
}
#Override
public synchronized void mark(int readlimit) {
wraped.mark(readlimit);
}
#Override
public synchronized void reset() throws IOException {
wraped.reset();
}
#Override
public boolean markSupported() {
return wraped.markSupported();
}
interface ReadListener {
void onRead(long bytes);
}
}
minimumBytesPerCall should be initialised with some sensible number, as you probably don't want to be called on every single byte, maybe every half a megabyte should be good.
And remember that this all gets called on the doInBackground thread, so act accordingly.
edit:
I've edited the class above, there was a small error on computing the bytesRead value.
The official documentation explains your follow-up questions https://developer.android.com/reference/java/io/InputStream.html#read()
Reads the next byte of data from the input stream
So read() reads 1 byte of data (or return -1) if reached the end. So yes, it must be called several several times to read a whole image.
Then the method onRead(long) get's called every time at least minimumBytesPerCall have been read (that's to avoid of calling back for every single byte) and once more at the end of the stream (when it returns -1)
The value passed to onRead(long) is the amount that have been read since the last call. So implementing this on your AsyncTask you would have to accumulate this value and compare with the total size of the file.
Something like the following code inside your asynctask should work fine (assuming the Progress generic parameter is a Long):
private long fileLength;
private long totalBytes;
private final ListenableInputStream.ReadListener readListener = new ListenableInputStream.ReadListener() {
#Override
public void onRead(long bytes) {
totalBytes += bytes;
publishProgress(totalBytes);
}
};
and on inside your upload part you replace with:
FileInputStream fis = new FileInputStream(imageFile);
fileLength = imageFile.length();
ListenableInputStream lis = new ListenableInputStream(fi, readListener, 256 * 1024); // this will call onRead(long) every 256kb
blob.upload(lis, fileLength);
and as a last remark, remember that internally the CloudBlockBlob just caching the file on its own memory for later upload, or doing any other weird stuff that is out of your control. All this code does is check that the complete file was read.
happy coding!
Just another way for your needs, there is a MS blog which introduce about uploading a blob to Azure Storage with progress bar and variable upload block size. That code was written in C#, but it's very simple for reading by Java/Android Developer, I think you can easily rewrite it in Java for Android to compute the uploading processbar ratio to share via some public variables.
Hope it helps.

Thread that terminates after webservice return executed?

My problem is that the web service returns a value of the static variable response in the recognition class before the thread updates its value (not up to date value)
here is my web service :
#GET
#Produces("application/json")
public synchronized String returnTitle() {
String result="init value";
Recognition recognition = new Recognition();
FutureTask<String> future = new FutureTask(recognition);
future.run();
System.out.println("result0 = "+result);
try{
System.out.println("result = "+result);
result = future.get();
System.out.println("result1 = "+result);
}catch (Exception e){e.printStackTrace();}
return "<h1>hello</h1> "+ Recognition.response;
}
This class contains the static variable called response that well be returned by the web service.
import java.io.File;
import java.util.List;
import java.util.concurrent.Callable;
import com.bitsinharmony.recognito.MatchResult;
public class Recognition implements Callable<String>{
public static String response =""; // The variable to return by the web service.
#Override
public String call() throws Exception {
response= "";
if (!Ressources.isInitilalized){ // if the initialization of training data is not done yet.
Ressources.init(); // initialize training data
Ressources.isInitilalized= true; //changing the boolean variable to know that inisialization has been done next execution
}
final JavaSoundRecorder recorder = new JavaSoundRecorder(); // Class used to record voice from microphone and save it to .wav file.
Thread stopper = new Thread(new Runnable() { // Thread that sleeps 5000 ms then stops recording.
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
recorder.finish(); // after timer finished stop recording
try{
File file20 = new File("C:\\RecordAudio.wav");
List<MatchResult<String>> matches = Ressources.recognito.identify(file20);
MatchResult<String> match = matches.get(0);
//file20.delete();
System.out.println(match.getKey() + " " + match.getLikelihoodRatio());
response = match.getKey()+" "+match.getLikelihoodRatio()+"\n";// say for which user the sound recorded belongs with witch probability.
}catch (Exception e){}
}
});
stopper.start(); // start the thread
// start recording
recorder.start(); // start recording
return response;
}
}
This class contains static resources to train the model of speaker identification :
import java.io.File;
import com.bitsinharmony.recognito.Recognito;
public class Ressources {
public static String response = "hello : ";
public final static File file0 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\silence12.wav");
public final static File file00 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\noise12.wav");
public final static File file1 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\dhia12.wav");
public final static File file30 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\dhia30.wav");
public final static File file2 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\dhia2.wav");
public final static File file3 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\obama1.wav");
public final static File file4 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\obama2.wav");
public final static File file5 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\obama3.wav");
public final static File file6 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\reagan1.wav");
public final static File file7 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\reagan2.wav");
public final static File file8 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\reagan3.wav");
public final static File file9 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\georgebush1.wav");
public final static File file10 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\georgebush2.wav");
public final static File file11 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\georgebush3.wav");
public final static File file12 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\georgebush4.wav");
public final static File file13 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\carter1.wav");
public final static File file14 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\carter2.wav");
public final static File file15 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\clinton1.wav");
public final static File file16 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\clinton2.wav");
public final static File file17 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\huyan1.wav");
public final static File file18 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\huyan2.wav");
public final static File file19 = new File("C:\\Users\\dsghaier\\Desktop\\Records\\huyan3.wav");
public static Recognito<String> recognito = new Recognito<String>(16000.0f);
public static boolean isInitilalized = false;
public static void init(){
try{
recognito.createVoicePrint("Dhia", file1);
//recognito.mergeVoiceSample("Dhia", file2);
//recognito.mergeVoiceSample("Dhia", file30);
recognito.createVoicePrint("Obama", file3);
//recognito.mergeVoiceSample("Obama", file4);
//recognito.mergeVoiceSample("Obama", file5);
recognito.createVoicePrint("Reagan", file6);
//recognito.mergeVoiceSample("Reagan", file7);
//recognito.mergeVoiceSample("Reagan", file8);
recognito.createVoicePrint("George Bush", file9);
//recognito.mergeVoiceSample("George Bush", file10);
//recognito.mergeVoiceSample("George Bush", file11);
//recognito.mergeVoiceSample("George Bush", file12);
recognito.createVoicePrint("Carter", file13);
//recognito.mergeVoiceSample("Carter", file14);
//recognito.createVoicePrint("Clinton", file15);
//recognito.mergeVoiceSample("Clinton", file16);
//recognito.createVoicePrint("Huyan", file17);
//recognito.mergeVoiceSample("Huyan", file18);
//recognito.mergeVoiceSample("Huyan", file19);
//recognito.createVoicePrint("Silence", file0);
//recognito.createVoicePrint("Noise", file00);
// ********************************
}catch (Exception e){e.printStackTrace();}
isInitilalized = true;
}
}
And finally this class is used to record sound and save it into a .wav file :
import javax.sound.sampled.*;
import java.io.*;
/**
* A sample program is to demonstrate how to record sound in Java
* author: www.codejava.net
*/
public class JavaSoundRecorder {
// record duration, in milliseconds
static final long RECORD_TIME = 500;
// path of the wav file
File wavFile = new File("C:/RecordAudio.wav");
// format of audio file
AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
// the line from which audio data is captured
TargetDataLine line;
/**
* Defines an audio format
*/
AudioFormat getAudioFormat() {
float sampleRate = 16000;
int sampleSizeInBits = 8;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits,
channels, signed, bigEndian);
return format;
}
/**
* Captures the sound and record into a WAV file
*/
public void start() {
try {
AudioFormat format = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
// checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
System.out.println("Line not supported");
System.exit(0);
}
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start(); // start capturing
// System.out.println("Start capturing...");
AudioInputStream ais = new AudioInputStream(line);
// System.out.println("Start recording...");
// start recording
AudioSystem.write(ais, fileType, wavFile);
} catch (LineUnavailableException ex) {
ex.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Closes the target data line to finish capturing and recording
*/
public void finish() {
line.stop();
line.close();
// System.out.println("Finished");
}
}
Maybe you should just initialize your static variable.
Initializing and declaring a variable is not the same:
Initializing : int a = 0;
Declaring : int a;
If this is not what you are looking for, maybe you might be a bit more specific and show us an error message

How to run the same class in java with multiple different input files automatically

I am wondering how to run a same java class with different command line options without manually change those command line options?
Basically, for inputFile and treeFile, I have more than 100 different combinations of the two files. I can not do "edit configurations" in IntelliJ to get result manually for each combination of treeFile and inputFile.
Could anybody give some suggestions to me such that how to create a loop of those inputFile and treeFile so that I do not need to manually specifying them for each combination.
Your help is highly appreciated!!!!
#Option(gloss="File of provided alignment")
public File inputFile;
#Option(gloss="File of the tree topology")
public File treeFile;
My java class code is below:
public class UniformizationSample implements Runnable
{
#Option(gloss="File of provided alignment")
public File inputFile;
#Option(gloss="File of the tree topology")
public File treeFile;
#Option(gloss="ESS Experiment Number")
public int rep = 1;
#Option(gloss="Rate Matrix Method")
public RateMtxNames selectedRateMtx = RateMtxNames.POLARITYSIZEGTR;
#Option(gloss = "True rate matrix generating data")
public File rateMtxFile;
#Option(gloss="Use cache or not")
public boolean cached=true;
private final PrintWriter detailWriter = BriefIO.output(Results.getFileInResultFolder("experiment.details.txt"));
public void run() {
ObjectMapper mapper = new ObjectMapper();
double[][] array;
EndPointSampler.cached=cached;
try (FileInputStream in = new FileInputStream(rateMtxFile)) {
array = mapper.readValue(in, double[][].class);
long startTime = System.currentTimeMillis();
UnrootedTreeLikelihood<MultiCategorySubstitutionModel<ExpFamMixture>> likelihood1 =
UnrootedTreeLikelihood
.fromFastaFile(inputFile, selectedRateMtx)
.withSingleRateMatrix(array)
.withExpFamMixture(ExpFamMixture.rateMtxModel(selectedRateMtx))
.withTree(treeFile);
Random rand = new Random(1);
likelihood1.evolutionaryModel.samplePosteriorPaths(rand, likelihood1.observations, likelihood1.tree);
logToFile("Total time in seconds: " + ((System.currentTimeMillis() - startTime) / 1000.0));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String [] args)
{
Mains.instrumentedRun(args, new UniformizationSample());
}
public void logToFile(String someline) {
this.detailWriter.println(someline);
this.detailWriter.flush();
}
}
There is no way to do this in IntelliJ IDEA. However, you can modify your UniformizationSample class so that it will take the input data as method parameters, and write another Java class that will loop through your inputs and call your class with the necessary parameters.

AudioRecord not always recording what expected

I am having a problem wit AudioRecord.
I am developing an application that needs to record some an impulse response from the MIC and make some DSP with it.
The audio captured is stored in a WAV file and being plotted afterwards from this file.
I´ve created a class called GrabaAudio which is expected to record a wav file of 3 sec long.
The problem is that I am obtaining ramdonly either wav files of 3 sec and 1,5 sec without a clear reason.
This is what I am supossed to obtain always:
Waveform:
But actually, that result is just obtained sometimes, while most of the time this is what I obtain:
What is really curious about this is that, when I obtain the expected result in the plot, I play the wav file to see what has actually been recorded and I can hear the impulse, but just for 1,5 sec instead of 3. Therefore the samples obtained are half of the expected.
On the other hand, when I obtain the plot with the duplicated impulse, the number of samples is the expected and the wav duration is 3 sec, but I don´t know why the impulse appears twice.
Do you guys know what am I doing wrong?
Here´s the relevant part of the code:
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#SuppressLint("NewApi")
public class GrabaAudio {
private static final int RECORDER_BPP = 16;
private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
public int RECORDER_SAMPLERATE = 8000;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord recorder = null;
private int bufferSize = 0;
private Thread recordingThread = null;
public boolean isRecording = false;
public boolean triggered=false, processed=false;
int bufferTotal=0, read=0, indice=0, indice2=0;
byte[] circBuffer=new byte[8192*3];//AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
//RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING)*3
AutomaticGainControl agc;
File file= new File(getFilename());
CircularArrayList<Byte> circ= new CircularArrayList ((AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING))/2);
int circCapacity=circ.capacity();
Main main;
public GrabaAudio(){
bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING);
if (bufferSize <8192){
bufferSize=8192;
}
//boolean tiene=agc.getEnabled();
}
public void startRecording(){
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE, RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize*6);
agc = AutomaticGainControl.create(recorder.getAudioSessionId());
final boolean agc2=agc.isAvailable();
int i = recorder.getState();
if(i==1)
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
#Override
public void run() {
writeAudioDataToFile();
}
},"AudioRecorder Thread");
recordingThread.start();
}
public void writeAudioDataToFile(){
byte data[] = new byte[6*bufferSize];
byte arrayBytes[]= new byte [3*bufferSize];
String filename = getTempFilename();
FileOutputStream os = null;
try {
os = new FileOutputStream(filename);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null != os){
while(isRecording){
read = recorder.read(data, 0, 6*bufferSize);
//**************************************
arrayBytes=calculateImpulseLevel(data);
if(AudioRecord.ERROR_INVALID_OPERATION != read && indice>=(bufferSize*3-3) ){
try {
os.write(arrayBytes);
processed=true;
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private byte[] calculateImpulseLevel(byte[] array){
double[] arraySamples=new double[array.length/2];
for (int i=0,j=0; i<=array.length-2 ;i+=2){
double sampleAmpl=(double)Math.abs((array[i+1] << 8 | array[i] & 0xff)/32767.0);
if (sampleAmpl<0.3 && !triggered){
int s=circ.size();
if (s<circCapacity){
circ.add(array[i]);
circ.add(array[i+1]);
} else {
circ.remove(0);
circ.add(array[i]);
circ.remove(0);
circ.add(array[i+1]);
}
} else{
if(!triggered){
triggered=true;
} indice=indice2+(bufferSize/2);
if (indice>3*bufferSize-2){
i=array.length;
}else{
circBuffer[indice]=array[i];
circBuffer[indice+1]=array[i+1];
indice2+=2;
arraySamples[j]=sampleAmpl;
}
}}
System.arraycopy(toByteArray(circ),0,circBuffer,0,circ.size());
return circBuffer;
}
I have had problems with AudioRecord returning repeated data in a sequence of reads, resolved by changing the size of the AudioRecord buffer so as not to be an exact multiple of the audiodata buffer size e.g., try:
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE, RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize*9);
Also are you sure that the writes are always able to keep up with the reads? I would insert some log statements to check the timings. You may need to copy the read data in memory and write in another thread.

Categories