I want to implement a VU meter in my recording app when recording AND playing. I know how to do it when recording, but the problem appears when playing. How can I grab the max amplitude at a given point in time from android MediaPlayer? I know there is a way because I saw some widget that do the same when playing some music on my device. I don't want to use android Visualizer for rendering, I want to make my own VU meter to work for devices with OS 2.3+. Basically, I need getMaxAmplitude for MediaPlayer.
//first of all import this library
import android.media.MediaRecorder;
private MediaRecorder mRecorder = null;
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude()/2700.0);
else
return 0;
}
//if you need further detail here is my class which is doing same thing
package com.spaidevelopers.noisealert;
import java.io.IOException;
import android.media.MediaRecorder;
public class SoundMeter {
// This file is used to record voice
static final private double EMA_FILTER = 0.6;
private MediaRecorder mRecorder = null;
private double mEMA = 0.0;
public void start() {
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
try {
mRecorder.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mRecorder.start();
mEMA = 0.0;
}
}
public void stop() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude()/2700.0);
else
return 0;
}
public double getAmplitudeEMA() {
double amp = getAmplitude();
mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
return mEMA;
}
}
Related
I was referring to a code that I found previously and tried it myself. It works perfectly however the decibel measured from the code is extremely high even in a quiet room. The value ranged from 0 to 30000. I was expecting the decibel be around 30 ~ 40 when I am in a quiet room. Can someone please tell me what's wrong with the code? Maybe the algorithm in the code is wrong because "soundDB()" is not used. The decibel shown is the app is from "getAmplitudeEMA()" instead.
import android.app.Activity;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.TextView;
public class Noise extends Activity {
TextView mStatusView;
MediaRecorder mRecorder;
Thread runner;
private static double mEMA = 0.0;
static final private double EMA_FILTER = 0.6;
final Runnable updater = new Runnable(){
public void run(){
updateTv();
};
};
final Handler mHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.noiselevel);
mStatusView = (TextView) findViewById(R.id.status);
if (runner == null)
{
runner = new Thread(){
public void run()
{
while (runner != null)
{
try
{
Thread.sleep(1000);
Log.i("Noise", "Tock");
} catch (InterruptedException e) { };
mHandler.post(updater);
}
}
};
runner.start();
Log.d("Noise", "start runner()");
}
}
public void onResume()
{
super.onResume();
startRecorder();
}
public void onPause()
{
super.onPause();
stopRecorder();
}
public void startRecorder(){
if (mRecorder == null){
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
try {
mRecorder.prepare();
}catch (java.io.IOException ioe) {
android.util.Log.e("[Monkey]", "IOException: " +
android.util.Log.getStackTraceString(ioe));
}catch (java.lang.SecurityException e) {
android.util.Log.e("[Monkey]", "SecurityException: " +
android.util.Log.getStackTraceString(e));
}
try{
mRecorder.start();
}catch (java.lang.SecurityException e) {
android.util.Log.e("[Monkey]", "SecurityException: " +
android.util.Log.getStackTraceString(e));
}
//mEMA = 0.0;
}
}
public void stopRecorder() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
public void updateTv(){
mStatusView.setText(Double.toString((getAmplitudeEMA())) + " dB");
}
public double soundDb(double ampl){
return 20 * Math.log10(getAmplitudeEMA() / ampl);
}
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude());
else
return 0;
}
public double getAmplitudeEMA() {
double amp = getAmplitude();
mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
return mEMA;
}
}
The problem is the following line:
mStatusView.setText(Double.toString((getAmplitudeEMA())) + " dB");
You are setting as text the value returned from getAmplitudeEMA() but this is not a dB value, it's the amplitude returned by mRecorder.getMaxAmplitude() which is then modified by getAmplitudeEMA().
To "convert" amplitude to dB you need to include your soundDb(double ampl) method in this way:
public void updateTv(){
mStatusView.setText(Double.toString(soundDb(getAmplitudeEMA()))+ "dB");
}
You have to call the function soundDb, which transforms the amplitude into dB FS.
mStatusView.setText(soundDb(32767.0) + " dB");
I am very new to android development and I don't have enough experience. So the question I am asking might be very simple. I want to detect if there is noise in the environment using microphone. Now if there is no mic on the cellphone I will toast a relevant.
I found the code from here: android: Detect sound level
On main activity I have a button. Pressing the button will toast some result. But I only get 0.0 even though there is a noise in the room. Could some one give me some hint on this please.
public class MainActivity extends AppCompatActivity implements SensorEventListener {
double soundLevel;
protected void onCreate(Bundle savedInstanceState) {
noiseButton = findViewById(R.id.noiseCheck);
PackageManager PM= this.getPackageManager();
final boolean microphone = PM.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
noiseButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (microphone){
double soundLevel = detectEnvironmentalNoise();
Toast.makeText(mContext, "Environmental noise level is " + soundLevel , Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(mContext, "This device is not equipped to microphone to detect environmental noise", Toast.LENGTH_LONG).show();
}
}
});
}
public double detectEnvironmentalNoise() {
AudioRecord audio = null;
int sampleRate = 8000;
double lastLevel = 0;
try {
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
audio = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize);
} catch (Exception e) {
android.util.Log.e("TrackingFlow", "Exception", e);
}
audio.startRecording();
short[] buffer = new short[100];
int bufferReadResult = 1;
if (audio != null) {
// Sense the voice...
bufferReadResult = audio.read(buffer, 0, 10000);
double sumLevel = 0;
for (int i = 0; i < bufferReadResult; i++) {
sumLevel += buffer[i];
}
lastLevel = Math.abs((sumLevel / bufferReadResult));
}
return lastLevel;
}
}
You need to implement getMaxAmplitude() for AudioRecord as described in below post:
Implement getMaxAmplitude for audioRecord
Or you can use MediaRecorder as below:
public class SoundMeter {
private MediaRecorder mRecorder = null;
public void start() {
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
mRecorder.prepare();
mRecorder.start();
}
}
public void stop() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
public double getAmplitude() {
if (mRecorder != null)
return mRecorder.getMaxAmplitude();
else
return 0;
}
}
My goal is to be able to get a callback/hook when a user speaks into the mic during a phone call. I cant use RecognizerIntent.ACTION_RECOGNIZE_SPEECH because during a phone call this gets queued until the call ends then the prompt appears. I need something that while the user is on the phone i can determine if they speak into the mic. If there is no native way to do this, can you recommend a 3rd party ?
Right now im using android noiseAlert sample code and it looks like this:
public class SoundMeter {
static final private double EMA_FILTER = 0.6;
private MediaRecorder mRecorder = null;
private double mEMA = 0.0;
public void start() {
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
try {
mRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mRecorder.start();
mEMA = 0.0;
}
}
public void stop() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude()/2700.0);
else
return 0;
}
public double getAmplitudeEMA() {
double amp = getAmplitude();
mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
return mEMA;
}
}
What is a good measurement i can use to know that the user is speaking into the mic using this approach ? for Example can i do the following:
SoundMeter soundMeter = new SoundMeter();
soundMeter.start();
if(soundMeter.getAmplitude>1.0)
//users is talking into the mic
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
How to detect amplitude from user's voice?
Just detect if user speak or not.
What is the different between AudioRecorder, MediaRecorder, Audio Capture?
Please give me a full explanation and code please
i tried this class from tutorial but it has error in "mRecorder.prepare():"
import android.media.MediaRecorder;
public class SoundMeter {
static final private double EMA_FILTER = 0.6;
private MediaRecorder mRecorder = null;
private double mEMA = 0.0;
public void start() {
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.prepare();
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
mRecorder.start();
mEMA = 0.0;
}
}
public void stop() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude()/2700.0);
else
return 0;
}
public double getAmplitudeEMA() {
double amp = getAmplitude();
mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
return mEMA;
}
}
update my second try
public class MainActivity extends Activity {
static final private double EMA_FILTER = 0.6;
private MediaRecorder mRecorder = null;
private double mEMA = 0.0;
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.start();
mEMA = 0.0;
tv = (TextView) findViewById(R.id.textView1);
double a = getAmplitude();
tv.setText(String.valueOf(a));
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
down();
}
}, 500, 10);
}
public void down() {
this.runOnUiThread(Update);
}
private Runnable Update=new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
double a = getAmplitude();
tv.setText(String.valueOf(a));
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude());
else
return 0;
}
}
A couple of things:
You need to set Output Format before the prepare() statement. From the documentation for prepare(): Throws IllegalStateException if it is called after start() or before setOutputFormat()
MediaRecorder.prepare() also throws IOException. You may want to surround the prepare() with a try/catch construct.
try:
if (mRecorder == null) {
try {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
mRecorder.prepare();
mRecorder.start();
mEMA = 0.0;
}
catch (IOException e) {
//do something with e
}
}
Im trying to get the sound level by getting live-input from the microphone.
As apps such as ,Sound meter and deciBel. I found this sample code from the link:
http://code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/src/com/google/android/noisealert/SoundMeter.java
I'm also pasting it here.
package com.google.android.noisealert;
import android.media.MediaRecorder;
public class SoundMeter {
static final private double EMA_FILTER = 0.6;
private MediaRecorder mRecorder = null;
private double mEMA = 0.0;
public void start() {
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
mRecorder.prepare();
mRecorder.start();
mEMA = 0.0;
}
}
public void stop() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude()/2700.0);
else
return 0;
}
public double getAmplitudeEMA() {
double amp = getAmplitude();
mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
return mEMA;
}
}
Does this code do what im trying to do?
Thanks!
it will once you:
instantiate the class
call its start() method
poll its getAmplitude() function from your main class (just as they did it in that sample code). Be aware that you need to do the polling in a Runnable() so that the UI is not affected. (Call the getAmplitude function every 100ms to detect a change in the input volume)
I have used it for that too and the code does the job.