Reputation: 47
I am making a simple android application where I record something from a smartphone mic, save it in a file and then play that file.
Now I want to apply a high pass filter to that audio file, but to do so, I need to first convert the audio file into a float array. Can someone please help me out with it.
Thanks
package abc.com.please;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static MediaRecorder mediaRecorder = new MediaRecorder();
private static MediaPlayer mediaPlayer;
private static String audioFilePath;
private static Button stopButton;
private static Button playButton;
private static Button recordButton;
private boolean isRecording = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recordButton = (Button) findViewById(R.id.recordButton);
playButton = (Button) findViewById(R.id.playButton);
stopButton = (Button) findViewById(R.id.stopButton);
if (!hasMicrophone())
{
stopButton.setEnabled(false);
playButton.setEnabled(false);
recordButton.setEnabled(false);
} else {
playButton.setEnabled(false);
stopButton.setEnabled(false);
}
audioFilePath =
Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/myaudio.3gp";
recordButton.setOnClickListener(new View.OnClickListener(){
public void onClick (View v)
{
isRecording = true;
stopButton.setEnabled(true);
playButton.setEnabled(false);
recordButton.setEnabled(false);
try {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setOutputFile(audioFilePath);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.prepare();
mediaRecorder.start();
}catch (Exception e) {
e.printStackTrace();
}
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
public void onClick (View view)
{
stopButton.setEnabled(false);
playButton.setEnabled(true);
if (isRecording)
{
recordButton.setEnabled(false);
isRecording = false;
mediaRecorder.stop();
mediaRecorder.release();
recordButton.setEnabled(true);
}
else
{
Toast.makeText(getApplicationContext(),"No recording going on",Toast.LENGTH_SHORT).show();
}
}});
playButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view)
{
playButton.setEnabled(false);
recordButton.setEnabled(false);
stopButton.setEnabled(true);
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(audioFilePath);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
protected boolean hasMicrophone() {
PackageManager pmanager = this.getPackageManager();
return pmanager.hasSystemFeature(
PackageManager.FEATURE_MICROPHONE);
}
}
Upvotes: 1
Views: 2764
Reputation: 7910
The details of the bytes-to-float conversion are going to depend on the file format that you use for your audio file. I cannot tell what that format is from your code. If your file is WAV, 44100 fps, 16-bit, little-endian, stereo (this is a standard Java, "CD quality" format) you can try making use of the following code I wrote. The key conversion point is when two bytes are concatenated and converted to a single numeral (where "buffer" contains data being read in from the audio file:
float audioVal = ( buffer[bufferIdx++] & 0xff )
| ( buffer[bufferIdx++] << 8 );
If it is big endian, reverse the order of the shifts. If 24 or 32 bit, then you would OR in shifts of << 16 and << 24, respectively. With 16-bit, the result will make use of the range of a short, so division by 32767 is needed to normalize the result to [-1..1].
I've been using the following in the Java context for a while without problems, but I don't know if Android supports javax.sound.sampled.AudioInputStream, etc. Maybe it is still useful to see the conversion in context of a file read? The code assumes that we have the "CD Quality" audio format and that the audio file is not longer than Integer.MAX number of frames.
public float[] loadSoundFileURL(URL url) throws UnsupportedAudioFileException,
IOException
{
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
int framesCount = (int)ais.getFrameLength();
// assuming stereo format, so two entries per frame
float[] temp = new float[framesCount * 2];
long tempCountdown = temp.length;
int bytesRead = 0;
int bufferIdx;
int clipIdx = 0;
byte[] buffer = new byte[1024];
while((bytesRead = ais.read(buffer, 0, 1024)) != -1)
{
bufferIdx = 0;
for (int i = 0, n = (bytesRead >> 1); i < n; i ++)
{
if ( tempCountdown-- >= 0)
{
temp[clipIdx++] =
( buffer[bufferIdx++] & 0xff )
| ( buffer[bufferIdx++] << 8 ) ;
}
}
}
// QUESTION: better to do following in above loop?
for (int i = 0; i < temp.length; i++)
{
temp[i] = temp[i] / 32767f;
}
return temp;
}
Upvotes: 2