I am using this FFT library to perform the FFT on the sound caught by device microphone. I am using following code:
int bufferSize = AudioRecord.getMinBufferSize(frequency,
channelConfiguration, audioEncoding);
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT,
frequency, channelConfiguration, audioEncoding, bufferSize);
int bufferReadResult;
try {
audioRecord.startRecording();
} catch (IllegalStateException e) {
e.printStackTrace();
Log.e("Recording failed", e.toString());
}
while (true) {
bufferReadResult = audioRecord.read(buffer, 0, blockSize);
if (isCancelled())
break;
boolean bln = false;
for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
toTransform[i] = (double) buffer[i] / 32768.0;
if (buffer[i] != 0) {
bln = true;
}
}
if (bln) {
transformer.ft(toTransform);
doStuff(toTransform);
} else {
try {
audioRecord = new AudioRecord(
MediaRecorder.AudioSource.DEFAULT, frequency,
channelConfiguration, audioEncoding, bufferSize);
audioRecord.startRecording();
} catch (IllegalStateException e) {
e.printStackTrace();
Log.e("Recording failed", e.toString());
}
}
if (isCancelled())
break;
}
try {
audioRecord.stop();
} catch (IllegalStateException e) {
e.printStackTrace();
Log.e("Stop failed", e.toString());
}
It works fine for microphone. But I want to do this transformation on sound file(in raw folder). I tried using InputStreamReader to read the sound file content, but how to use this file data to apply transformation on file? I tried using a buffer using following code:
InputStream ins;
ByteArrayOutputStream outputStream;
int size = 0;
byte[] buffer = new byte[1024];
ins = getResources().openRawResource(R.raw.fire);
outputStream = new ByteArrayOutputStream();
transformer = new RealDoubleFFT(blockSize);
while ((size = ins.read(buffer, 0, 1024)) >= 0) {
outputStream.write(buffer, 0, size);
if (isCancelled())
break;
boolean bln = false;
for (int i = 0; i < buffer.length; i++) {
toTransform[i] = (double) buffer[i] / 32768.0;
if (buffer[i] != 0) {
bln = true;
}
}
if (bln) {
transformer.ft(toTransform);
doStuff(toTransform);
}
}
ins.close();
But it is not returning the correct data. Maybe the data received from file is not what the library wants. Any ideas how to apply FFT on sound file?
You appear to be converting single bytes, but the format of a .wav/RIFF file, after the header (often 44 bytes), is usually 16-bit or 2-byte little-endian samples.
Related
I want to get the data from mic and store it in a byte array for some processing.
I have tried the code given below but it gives errors on recorder.record function.
I have tried a lot of stuff but it was not worth it. Please do help me.
public class AudioRecordThread implements Runnable {
#Override
public void run() {
int bufferLength = 0;
int bufferSize;
short[] audioData;
int bufferReadResult;
MediaRecorder recorder=new MediaRecorder();
recorder.start();
try {
int sampleAudioBitRate=44100;
bufferSize = AudioRecord.getMinBufferSize(sampleAudioBitRate,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
if (bufferSize <= 2048) {
bufferLength = 2048;
} else if (bufferSize <= 4096) {
bufferLength = 4096;
}
AudioRecord audioRecord;
/* set audio recorder parameters, and start recording */
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleAudioBitRate,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferLength);
audioData = new short[bufferLength];
audioRecord.startRecording();
Log.d("My Activity", "audioRecord.startRecording()");
boolean isAudioRecording = true;
boolean isRecorderStart=true;
/* ffmpeg_audio encoding loop */
while (isAudioRecording) {
bufferReadResult = audioRecord.read(audioData, 0, audioData.length);
if (bufferReadResult == 1024 && isRecorderStart) {
Buffer realAudioData1024 = ShortBuffer.wrap(audioData, 0, 1024);
***********************************
recorder.record(realAudioData1024);
***********************************
} else if (bufferReadResult == 2048 && isRecorderStart) {
Buffer realAudioData2048_1=ShortBuffer.wrap(audioData, 0, 1024);
Buffer realAudioData2048_2=ShortBuffer.wrap(audioData, 1024, 1024);
for (int i = 0; i < 2; i++) {
if (i == 0) {
***********************************
recorder.record(realAudioData2048_1);
***********************************
} else if (i == 1) {
***********************************
recorder.record(realAudioData2048_2);
***********************************
}
}
}
}
/* encoding finish, release recorder */
if (audioRecord != null) {
try {
audioRecord.stop();
audioRecord.release();
} catch (Exception e) {
e.printStackTrace();
}
audioRecord = null;
}
if (recorder != null && isRecorderStart) {
try {
recorder.stop();
recorder.release();
} catch (Exception e) {
e.printStackTrace();
}
recorder = null;
}
} catch (Exception e) {
Log.e("My Activity", "get audio data failed:"+e.getMessage()+e.getCause()+e.toString());
}
}
}
I am trying to play a PCM file which was created while recording audio from the microphone.
I am using AudioRecord because I want to analyse the frequency of the sound which is recorded by the microphone.
The snippet of code which plays the PCM file is as below. But when I tried to play the file, there is a heavy noise which is being played.
FileInputStream fis=null;
File l=null;
l=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Notate/f1.pcm");
byte[] buffer=new byte[(int)l.length()];
try {
fis = new FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Notate/f1.pcm");
fis.read(buffer);
}
catch(Exception e)
{
}
int intSize = android.media.AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, intSize, AudioTrack.MODE_STREAM);
if (at!=null) {
at.play();
at.write(buffer, 0, buffer.length);
at.stop();
at.release();
}
The code which is used to store the PCM file is below.
private class RecordAudio extends AsyncTask<Void, Double, Void> {
FileOutputStream os = null;
BufferedOutputStream bos =null;
DataOutputStream dos = null;
#Override
protected Void doInBackground(Void... params) {
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioEncoding); // Gets the minimum buffer needed
AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioEncoding, bufferSize); // The RAW PCM sample recording
File f=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Notate/");
if(!f.isDirectory()) {
File newDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Notate/");
newDirectory.mkdirs();
}
String filepath=Environment.getExternalStorageDirectory().getAbsolutePath()+"/Notate/f1.pcm";
short[] buffer = new short[blockSize]; // Save the raw PCM samples as short bytes
try{
os=new FileOutputStream(filepath);
}
catch(FileNotFoundException e)
{
}
bos = new BufferedOutputStream(os);
dos = new DataOutputStream(bos);
try {
audioRecord.startRecording(); //Start
} catch (Throwable t) {
}
while (started) {
int length=audioRecord.read(buffer, 0, blockSize);
Yin alpha = new Yin(44100, 1024, 0.2);
float[] floaters = new float[buffer.length];
for (int i = 0; i < buffer.length; i++) {
floaters[i] = buffer[i];
}
for(int k=0;k<length;k++) {
try {
dos.writeShort(buffer[k]);
} catch (IOException e) {
}
}
float result = alpha.getPitch(floaters);
publishProgress((double) result);
}
try{
dos.close();
}
catch(IOException e){
e.printStackTrace();
}
return null;
}
writeShort writes the values in a big-endian layout, i.e. the most significant byte first, while AudioTrack probably expects the samples to be little-endian (least significant byte first).
You'd make things simpler for yourself if you used a byte[] instead of a short[] when recording. Then you can simply write to your DataOutputStream with dos.write(buffer, 0, length);. Your conversion to floating-point values would have to be modified a bit in that case:
for (int i = 0; i < length; i += 2) {
floaters[i] = (short)(buffer[i] | (buffer[i+1] << 8));
}
I have recorded user's voice successfully using mediaplayer and the file is stored in sd card.
now i want to play that voice using audio track. But when I do it is making noise.
Y so.?
Here is the code to play sound..
private void PlayAudioFileViaAudioTrack(String filePath) throws IOException
{
// We keep temporarily filePath globally as we have only two sample sounds now..
if (filePath==null)
return;
int intSize = android.media.AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT, intSize, AudioTrack.MODE_STREAM);
if (at==null){
Log.d("TCAudio", "audio track is not initialised ");
return;
}
int count = 512 * 1024; // 512 kb
//Reading the file..
byte[] byteData = null;
File file = null;
file = new File(filePath);
byteData = new byte[(int)count];
FileInputStream in = null;
try {
in = new FileInputStream( file );
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int bytesread = 0, ret = 0;
int size = (int) file.length();
at.play();
while (bytesread < size) { ret = in.read( byteData,0, count); if (ret != -1) { // Write the byte array to the track
at.write(byteData,0, ret); bytesread += ret; } else break; } in.close(); at.stop(); at.release(); }
Noise could be due to a small buffer.
Try:
int intSize = android.media.AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
init *= 2;
If you work with exactly the minimum buffer size, it might result in noisy sound. Having twice the minimum size is a good practice (in my experience).
I have just resolve this by adding buffer size and check this code this will resolve your problem.
void playRecord(int position) {
if (position==0){
m=8000;
String folder_main = "MyVoiceChanger";
File filee = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + folder_main + "/Recording.mp3");
int shortSizeInBytes = Short.SIZE / Byte.SIZE;
int bufferSizeInBytes = (int) (filee.length() / shortSizeInBytes);
short[] audioData = new short[bufferSizeInBytes];
try {
InputStream inputStream = new FileInputStream(filee);
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
int i = 0;
while (dataInputStream.available() > 0) {
try {
audioData[i] = dataInputStream.readShort();
i++;
}catch (EOFException e){
e.printStackTrace();
}
}
dataInputStream.close();
try {
bufferSizeInBytes = AudioTrack.getMinBufferSize(
m,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING
);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,44100, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);
Log.i("Buffer", "playRecord: "+bufferSizeInBytes);
final int finalBufferSizeInBytes = bufferSizeInBytes;
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
audioTrack = new AudioTrack(3, m, 2, 2, finalBufferSizeInBytes, 1);
try {
audioTrack.play();
Log.i("Usman", "Audio "+audioTrack);
}catch (Exception e){
e.printStackTrace();
}
}
});
}catch (Exception e){
e.printStackTrace();
}
mediaPlayer.prepareAsync();
audioTrack.write(audioData, 0, bufferSizeInBytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Sorry for my bad english :(
I start my project for android application, this app record microphone, if I click to start record button the app get microphone and write it on a file and when I click to stop , a file saved into SD card.
project code :
The output file
OUTPUT_FILE = Environment.getExternalStorageState() + "/myaudio.3gp";
Start recording
public void startRecord() throws IOException{
if (recorder != null)
{
recorder.release();
}
File outFile = new File(OUTPUT_FILE);
if (outFile.exists())
{
outFile.delete();
}
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFormat(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(OUTPUT_FILE);
recorder.prepare();
recorder.start();
}
Stop recording
public void stopRec(){
recorder.stop();
}
PlaySound recorded file
public void playRecFile() throws IOException{
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(OUTPUT_FILE);
mediaPlayer.prepare();
mediaPlayer.start();
}
I want to get recorded voice and put it into a variable ByteArray and play it whitout saving the audio file to SD card
I have a project like what I want but it is written in actionscript 3
import flash.media.*;
import flash.events.*;
import flash.utils.ByteArray;
var ch:SoundChannel
var mic:Microphone = Microphone.getMicrophone();
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);
mic.addEventListener(ActivityEvent.ACTIVITY,onAct);
function onAct(evt:ActivityEvent):void
{
trace(evt.activating,mic.activityLevel);
if (!evt.activating)
{
if (soundBytes.length)
{
timerHandler();
}
}
}
var soundBytes:ByteArray = new ByteArray();
var soundO:ByteArray = new ByteArray();
function micSampleDataHandler(event:SampleDataEvent):void
{
trace(event.data.length,event.data.bytesAvailable, soundBytes.length);
while (event.data.bytesAvailable)
{
var sample:Number = event.data.readFloat();
soundBytes.writeFloat(sample);
}
}
function timerHandler():void
{
mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);
soundBytes.position = 0;
soundO.writeBytes(soundBytes);
soundO.position = 0;
soundBytes.position = 0;
soundBytes.length=0;
var sound:Sound= new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler);
ch=sound.play();
ch.addEventListener(Event.SOUND_COMPLETE,onSC)
trace("OUTPUT",soundO.bytesAvailable);
}
function onSC(evt:Event):void
{
trace("SOUND_COMPLETE");
}
function playbackSampleHandler(event:SampleDataEvent):void
{
trace("SAMPLE_DATA: ",soundO.bytesAvailable)
for (var i:int = 0; i < 8192; i++)
{
if (soundO.bytesAvailable < 4)
{
break;
}
var sample:Number = soundO.readFloat();
event.data.writeFloat(sample);
event.data.writeFloat(sample);
}
if (soundO.bytesAvailable < 4 && soundO.position!==0)
{
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);
soundO.position=0
soundO.length = 0;
trace("END
}
}
Check Out this answer! It works exactly with MediaRecorder not AudioRecord
Try to use the following solution to record audio to byte array using MediaRecorder:
// Byte array for audio record
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ParcelFileDescriptor[] descriptors = ParcelFileDescriptor.createPipe();
ParcelFileDescriptor parcelRead = new ParcelFileDescriptor(descriptors[0]);
ParcelFileDescriptor parcelWrite = new ParcelFileDescriptor(descriptors[1]);
InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(parcelRead);
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(parcelWrite.getFileDescriptor());
recorder.prepare();
recorder.start();
int read;
byte[] data = new byte[16384];
while ((read = inputStream.read(data, 0, data.length)) != -1) {
byteArrayOutputStream.write(data, 0, read);
}
byteArrayOutputStream.flush();
I wrap this code in AsyncTask for start execution.
Also, don't forgot to run the following code to stop recording:
recorder.stop();
recorder.reset();
recorder.release();
To convert byteArrayOutputStream to byte[] use byteArrayOutputStream.toByteArray()
Use the following class to get the Recorded Mic data As the Byte Array. You will get the data as buffer.. try to use that.. hope this will helps you ..
class AudioRecordThread implements Runnable {
#Override
public void run() {
int bufferLength = 0;
int bufferSize;
short[] audioData;
int bufferReadResult;
try {
bufferSize = AudioRecord.getMinBufferSize(sampleAudioBitRate,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
if (bufferSize <= 2048) {
bufferLength = 2048;
} else if (bufferSize <= 4096) {
bufferLength = 4096;
}
/* set audio recorder parameters, and start recording */
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleAudioBitRate,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferLength);
audioData = new short[bufferLength];
audioRecord.startRecording();
Log.d(LOG_TAG, "audioRecord.startRecording()");
isAudioRecording = true;
/* ffmpeg_audio encoding loop */
while (isAudioRecording) {
bufferReadResult = audioRecord.read(audioData, 0, audioData.length);
if (bufferReadResult == 1024 && isRecorderStart) {
Buffer realAudioData1024 = ShortBuffer.wrap(audioData,0,1024);
***********************************
recorder.record(realAudioData1024);
***********************************
} else if (bufferReadResult == 2048 && isRecorderStart) {
Buffer realAudioData2048_1=ShortBuffer.wrap(audioData, 0, 1024);
Buffer realAudioData2048_2=ShortBuffer.wrap(audioData, 1024, 1024);
for (int i = 0; i < 2; i++) {
if (i == 0) {
***********************************
recorder.record(realAudioData2048_1);
***********************************
} else if (i == 1) {
***********************************
recorder.record(realAudioData2048_2);
***********************************
}
}
}
}
/* encoding finish, release recorder */
if (audioRecord != null) {
try {
audioRecord.stop();
audioRecord.release();
} catch (Exception e) {
e.printStackTrace();
}
audioRecord = null;
}
if (recorder != null && isRecorderStart) {
try {
recorder.stop();
recorder.release();
} catch (Exception e) {
e.printStackTrace();
}
recorder = null;
}
} catch (Exception e) {
Log.e(LOG_TAG, "get audio data failed:"+e.getMessage()+e.getCause()+e.toString());
}
}
}
I want to get recorded voice and put it into a variable ByteArray and play it whitout saving the audio file to SD card
Use the AudioRecord class to grab audio from the mic into an array and then feed it into an AudioTrack.
i try and play an mp3 file in my SDCard for my Android emulator but all that comes out is some weird buzzing noise. I made sure the sample rate is 44.1k hz i don't know what else could be wrong
if(AudioTrack.MODE_STATIC != mode && AudioTrack.MODE_STREAM != mode)
throw new InvalidParameterException();
String audioFilePath = "/sdcard/test.mp3";
long fileSize = 0;
long bytesWritten = 0;
int bytesRead = 0;
int bufferSize = 0;
byte[] buffer;
AudioTrack track;
File audioFile = new File(audioFilePath);
fileSize = audioFile.length();
if(AudioTrack.MODE_STREAM == mode)
{
bufferSize = 8000;
}
else
{// AudioTrack.MODE_STATIC
bufferSize = (int)fileSize;
}
buffer = new byte[bufferSize];
track = new AudioTrack(AudioManager.STREAM_MUSIC,/* this is for pcm*/ /*22050*/ /*this is for mp3*/ 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_DEFAULT/*AudioFormat.ENCODING_PCM_16BIT*/,
bufferSize, mode);
// in stream mode,
// 1. start track playback
// 2. write data to track
if(AudioTrack.MODE_STREAM == mode)
track.play();
FileInputStream audioStream = null;
try {
audioStream = new FileInputStream(audioFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while(bytesWritten < fileSize)
{
try {
bytesRead = audioStream.read(buffer, 0, bufferSize);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bytesWritten += track.write(buffer, 0, bytesRead);
}
// in static mode,
// 1. write data to track
// 2. start track playback
if(AudioTrack.MODE_STATIC == mode)
track.play();
It's correct that you hear strange noise, since you need to decode the MP3 first before
you feed it to an AudioTrack! AudioTrack only plays raw PCM audio.
You should use android.media.MediaPlayer to play mp3 audio file