I am trying to write a simple little thing that stops an audio file from being played when the user "interrupts" it by talking to the phone. I'm using the SoundMeter class that this person wrote to get the maxAmplitude of the microphone. I've set a threshold to 800 and want to test the return of the microphone amplitude against it constantly (every 50ms).
For some reason, it's hit or miss when I get the "interrupt" to show up and when the audio stops. I'd like for the interrupt to be showing the entire time the amplitude is above 800.
handler = new Handler();
final Runnable r = new Runnable() {
#Override
public void run() {
mic_amplitude.setText(""+mSoundMeter.getAmplitude());
if(mSoundMeter.getAmplitude() > threshold) {
Log.d("INTERRUPT", "INTERRUPT");
interrupt.setText("Interrupt");
mBackgroundAudio.pause(mp);
audioButton.setText("Resume Audio");
} else {
interrupt.setText("");
}
handler.postDelayed(this, 50);
}
};
handler.postDelayed(r, 50);
While viewing this, I'm able to see the amplitude at a steady 40-50 while there is no background noise and peaks of 1200-1500 when talking quietly. I'd like the interrupt to show anytime above 800, but it's currently only showing up intermittently.
Ok, I figured it out. I tested what my amplitude was by logging the amp along with the interrupt and I saw I was getting 0. I realized I had been testing on a new amplitude (other than the amp I was showing), so I assigned the amplitude to a variable and used the variable everywhere else.
here's my outcome:
handler = new Handler();
final Runnable r = new Runnable() {
#Override
public void run() {
mAmplitude = mSoundMeter.getAmplitude();
mic_amplitude.setText(""+mAmplitude);
if(mAmplitude > threshold) {
Log.d("INTERRUPT", "INTERRUPT " + mAmplitude);
interrupt.setText("Interrupt");
mBackgroundAudio.pause(mp);
audioButton.setText("Resume Audio");
} else {
interrupt.setText("");
}
handler.postDelayed(this, 100);
}
};
handler.postDelayed(r, 100);
Related
Yes, I did search for the answer before I posted this. :)
Made board game, each piece gets roll of die and then moves step by step on squares. Wanted to follow each step with short beep. Added method "beep();" and placed it in handler that moves position of piece on screen.
When I add beep(); game works couple of moves and then simply stops, without any report or error message. View closes on screen and dialog just says "Unfortunately, BoardLS has stopped [Ok]", and nothing else happens.
When I remove beep(); game works ok.
Please, if anyone knows how beep crashes the game, and how to avoid it, tell me as simple as you can. Thanks.
Here's how I made the beep:
private void beep() {
ToneGenerator beepSound = new ToneGenerator(AudioManager.STREAM_MUSIC, 60);
beepSound.startTone(ToneGenerator.TONE_PROP_BEEP, 75);
} // Short sound
and I call it like this:
private final Handler playMove = new Handler() {
#Override
public void handleMessage(Message playMsg) {
beep();
player.setX(pcX[playPos]);
player.setY(pcY[playPos]);
}
}; // Put Player piece to new coordinates
playPos is square number where the piece is or will be,
pcX and pcY are arrays with on-screen coordinates of squares.
handler is in MainActivity,
and called from AsyncTask with playMove.sendEmptyMessage(0);
AsyncTask works directly with global variables, making no problems here.
Just release created ToneGenerator objects using release() method.
private void beep() {
ToneGenerator beepSound = new ToneGenerator(AudioManager.STREAM_MUSIC, 60);
beepSound.startTone(ToneGenerator.TONE_PROP_BEEP, 75);
beepSound.release();
}
I'm trying to update a label every millisecond in libGDX for a set amount of time.
However, sometimes the label suddenly stops without an error OR I receive a "String index out of range" error which then crashes my program. These are two separate issues.
Code:
Stage stage;
Timer timer = new Timer();
Label countUpLabel;
int countUp;
#Override
public void create () {
stage = new Stage(new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()));
//Setting up time label
BitmapFont font = new BitmapFont(Gdx.files.internal("04b_19__-32.fnt"));
LabelStyle labelStyle = new LabelStyle(font, Color.WHITE);
countUpLabel = new Label("Time:\n00000", labelStyle);
countUpLabel.setPosition(200,200);
countUpLabel.setAlignment(Align.center);
countUpLabel.setFontScale(3);
stage.addActor(countUpLabel);
//Setting up timer
timer.schedule(new TimerTask() {
#Override
public void run() {
if (countUp < 3000) {
countUp++;
countUpLabel.setText(String.format("Time:\n%d", countUp));
}else
timer.cancel();
}
}, 0, 1); //every millisecond run the timer
}
Thanks in advance.
Most of libGDX is not thread safe, unless explicitly stated that it is. Also, updating a label every millisecond, while it is only shown about every 16 milliseconds (the refresh rate of your typical display device), isn't a very good approach. So you might want to remove your timer and instead update the label when it is actually visible: in the render method:
float counter = 0f;
#Override
public void render() {
if (counter < 3) {
counter += Gdx.graphics.getDeltaTime();
countUpLabel.setText(String.format("Time:\n%01.22f", counter));
}
// call glClear, stage.act, stage.draw, etc.
}
Im programming a Music Player with a Seekbar.To manage it im using an Handler with a Runnable which does it update. Somehow it is lagging my UI . How can I stop this lag ?
OnCreate:
mHandler = new Handler();
When Im playing a Song:
public static void updateProgressBar() {
mHandler.postDelayed(mUpdateTimeTask, 100);
}
My Runnable:
private static Runnable mUpdateTimeTask = new Runnable() {
public void run() {
try {
long totalDuration = songService.getTotalDuration();
int currentDuration = songService.getCurrentDuration();
// Displaying Total Duration time
player_time_length.setText(""+utils.milliSecondsToTimer(totalDuration));
// Displaying time completed playing
player_time_current.setText(""+utils.milliSecondsToTimer(currentDuration));
// Updating progress bar
int progress = (int)(utils.getProgressPercentage(currentDuration, totalDuration));
SB_song.setProgress(currentDuration);
// Running this thread after 100 milliseconds
mHandler.postDelayed(this, 100);
}catch(Exception e){}
}
};
How can I prevent this lagg in my App ?
The lag is because the Runnable is executing in the UI Thread. To reduce or remove the lag, you have to reduce the amount of work you do inside the Runnable.
One thing that you can do is to remove long totalDuration = songService.getTotalDuration(); from the Runnable and instead, put it outside, like I do in my music player.
I could add more to this answer if you included the "utils" methods that you're using to convert milliseconds to human readable time.
I would say its because its running on the UI Thread which laggs. But you have to use UI elements so another Thread is not possible .. Im right ?
Make sure the text view is not set to wrap_content. That will trigger a layout pass each time you call setText.
I make this code
Timer.schedule(new Task(){
#Override
public void run() {
flyAway();
}
}, 12);
and when my game paused i do this in draw method (Actor)
Timer.instance().stop();
On resume game i do this:
Timer.instance().start();
It work, but when i pause on 2 sec and resume after 35 sec, function flyAway() executed immediately, not counting the remaining 10 seconds.
How i can paused delaySeconds. Thanks.
Sorry for my bad English.
FlyAvay code
//Муха улетает
public void flyAway(){
flyAway = 1;
targetFlyX = Gdx.graphics.getWidth() / 2;
targetFlyY = Gdx.graphics.getHeight() + 300;
this.setColor(1f, 1f, 1f, 0.2f);
this.addAction(sequence(moveTo(targetFlyX, targetFlyY, flySpeed), desctroyFlyAction));
}
Action desctroyFlyAction = new Action(){
public boolean act( float delta ) {
removeFly();
return true;
}
};
public void removeFly(){
rectBounds.set(1, 1, 0, 0);
this.remove();
}
I had this problem and I know this is late but maybe it'll help someone else. The problem is that when a Timer is created, it is given a time on the system's clock to execute rather than a specified amount of time until it executes. So when you call Timer.stop in your pause method, wait 35 seconds, then call Timer.start in the resume method, the time that task was supposed to be completed had already passed so it was executed right away.
My solution was just to save the current system's time on pause, then subtract it from the current time on resume, and add the difference as a delay to the Timer using Timer.delay() before calling Timer.start() again.
public void pause() {
timerDelay = TimeUtils.nanosToMillis(TimeUtils.nanoTime());
Timer.stop();
}
public void resume() {
Timer.delay(TimeUtils.nanosToMillis(TimeUtils.nanoTime()) - timerDelay);
Timer.start();
}
I was wondering if anyone has any luck with audio recording and playback using libgdx. I'm currently using 0.9.8 and just messing around trying to make a simple voice chat app.
I create my audio device using
int samples = 44100;
int seconds = 5;
boolean isMono = true;
short[] data = new short[samples*seconds];
AudioRecorder recorder = Gdx.audio.newAudioRecorder(samples, isMono);
AudioDevice player = Gdx.audio.newAudioDevice(samples, isMono);
On a button press I kick of a new thread to record the data. (I know this is a messy to kick off a new thread, but i'm only trying to play with audio recording)
new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Record: Start");
recorder.read(data, 0, data.length);
System.out.println("Record: End");
}
}).start();
After the recording I play back the recorded data using
new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Play : Start");
player.writeSamples(data, samples, data.length);
System.out.println("Play : End");
}
}).start();
On my laptop the recording and playback seems to work fine. I can record the data and then playback works great.
The problem happens on Android. I've tried it on three devices (Samsung S3, Samsung Galaxy Mini and a Nexus 10). In all cases, the recording works perfectly, the issue occurs when I attempt the playback it just locks up in the player.writeSamples and nothing is played. I've left it 10 min and never prints "Record : End".
Has anyone ever got audio playback working? Am I missing something?
After a bit of playing around, I found the issue.
Your line, here:
player.writeSamples(data, samples, data.length);
should instead be:
player.writeSamples(data, 0, data.length);
The second argument is the offset, not the sample rate.
So, to sum up, the following works on Android devices:
final int samples = 44100;
boolean isMono = true;
final short[] data = new short[samples * 5];
final AudioRecorder recorder = Gdx.audio.newAudioRecorder(samples, isMono);
final AudioDevice player = Gdx.audio.newAudioDevice(samples, isMono);
new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Record: Start");
recorder.read(data, 0, data.length);
recorder.dispose();
System.out.println("Record: End");
System.out.println("Play : Start");
player.writeSamples(data, 0, data.length);
System.out.println("Play : End");
player.dispose();
}
}).start();