I have a Sound object that calls setPitch(id, 1.0f). For some reason, on most devices this seems to work and sound perfect (I realize that 1.0f is normal). But on the galaxy note 3, it makes an ugly deep sound, then the Sound object no longer makes any sounds after calling play method again (I play the Sound object every time player gets point). Setting pitch is necessary because I use the same Sound object for other parts of my game. I will link my code below, but I feel as though this may be a libgdx glitch/hardware problem. Thanks!
if (contact.getFixtureA().getFilterData().categoryBits == Config.CATEGORYBIT_BONUS) {
final BonusFixtureUserData userData = (BonusFixtureUserData) contact.getFixtureA().getUserData();
if (userData.bonus.scorable) {
long id = AudioManager.getAudioManager().playSound(AudioManager.getAudioManager().bonusSound);
AudioManager.getAudioManager().bonusSound.setPitch(id, Config.pointSoundPitch * 2);
}
}
AudioManager class (below)
public class AudioManager {
private static AudioManager audioManager;
public Sound jumpSound, deathSound, pointSound, bonusSound;
public static AudioManager getAudioManager() {
if (audioManager == null) {
audioManager = new AudioManager();
}
return audioManager;
}
private float sound_volume, music_volume;
private AudioManager() {
sound_volume = 1f;
}
public void setAudio() {
deathSound = (Sound) Game.assetManager.get("sound/death.mp3");
jumpSound = (Sound) Game.assetManager.get("sound/tap.mp3");
pointSound = (Sound) Game.assetManager.get("sound/point.mp3");
bonusSound = (Sound) Game.assetManager.get("sound/point.mp3");
}
public long playSound(Sound sound) { //Returns soundID (Sound can play multiple times, soundID refers to which instance is playing)
long id = sound.play();
sound.setLooping(id, false);
sound.setVolume(id, sound_volume);
return id;
}
public static void dispose() {
audioManager = null;
}
}
Config.pointPitchSound is actually equal to between 1.0f and 1.07f throughout the game. When it is 1.0f, then it does the glitch. I haven't tried the other values, but I would asume they'd do the same.
LibGDX audio implementation depends completely on Android. Sound.setPitch actually calls SoundPool.setRate Android documentation of setRate
Try to convert sounds to OGG format, it is known that SoundPool has issues with playing MP3 files on some devices.
Related
As described in documentation, the automatic ducking feature has been introduced in Android 8.0. Ducking means that if your music application has been interrupted by some short sound (like a notification, for ex.), your application will continue playing music, but music volume will be temporary lowered while short sound is playing.
I use a text-to-speech engine to read long articles, and want it to behave similar to music player, i.e. I want it to be automatically ducked by the system in android 8.0
I've got ducking to work fine without any additional code on Android 8.0 for music playing, but not for text-to-speech playing.
Here is a sample code
public class PlayerService extends Service {
//private MediaPlayer mp;
TextToSpeech tts;
#Override
public void onCreate() {
super.onCreate();
//...
//create foreground notification stuff omitted...
//...
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.requestAudioFocus(listener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
/*
mp = MediaPlayer.create(this, R.raw.music);
mp.setLooping(true);
mp.start();
*/
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.setAudioAttributes(
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
);
}
tts.speak("IF you happen to have read another book about Christopher Robin, you may remember that he once had a swan (or the swan had Christopher Robin, I don't know which) and that he used to call this swan Pooh. That was a long time ago, and when we said good-bye, we took the name with us, as we didn't think the swan would want it any more. Well, when Edward Bear said that he would like an exciting name all to himself, Christopher Robin said at once, without stopping to think, that he was Winnie-the-Pooh. And he was. So, as I have explained the Pooh part, I will now explain the rest of it. ",
TextToSpeech.QUEUE_ADD, null);
}
});
}
#Override
public void onDestroy() {
tts.stop();
/*
mp.stop();
mp.release();
*/
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.abandonAudioFocus(listener);
super.onDestroy();
}
private AudioManager.OnAudioFocusChangeListener listener = new AudioManager.OnAudioFocusChangeListener() {
#Override
public void onAudioFocusChange(int focusChange) {
//nothing to do here
}
};
}
If I'd remove text-to-speech stuff and uncomment MediaPlayer lines, ducking will work fine for music playing. But if using text-to-speech as presented, no ducking is happening - during the notification sound text-to-speech continues playing as usually, and no volume change is performed.
I want ducking (volume change) to happen also if I use text-to-speech. What am I doing wrong?
public class AndroidSound implements Sound {
int soundId;
SoundPool soundPool;
public AndroidSound(SoundPool soundPool, int soundId) {
this.soundId = soundId;
this.soundPool = soundPool;
}
#Override
public void play(float volume) {
soundPool.play(soundId, volume, volume, 0, 0, 1);
}
#Override
public void dispose() {
soundPool.unload(soundId);
}}
public class Assets{
public Music theme;
public static Sound sound;
public static void load(Game game) {
theme = game.getAudio().createMusic("theme.mp3");
theme.setLooping(true);
theme.setVolume(0.85f);
theme.play();
sound = game.getAudio().createSound("death.wav");
}
}
Then I play this sound in different class by calling play() on it, but it plays with really huge delay, something around 500ms. Why is that? I tried looking for solution, but there is tons of people with that problem and I haven't found any answer that actually worked. Most of topics was bit old tho, maybe there is a simple solution for this already, counting on your help.
public class AndroidAudio implements Audio {
AssetManager assets;
SoundPool soundPool;
public AndroidAudio(Activity activity) {
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
this.assets = activity.getAssets();
this.soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
}
#Override
public Sound createSound(String filename) {
try {
AssetFileDescriptor assetDescriptor = assets.openFd(filename);
int soundId = soundPool.load(assetDescriptor, 0);
return new AndroidSound(soundPool, soundId);
} catch (IOException e) {
throw new RuntimeException("Couldn't load sound '" + filename + "'");
}
}
}
I don't know if this will be helpful now but also answering.
Use of SoundPool
1)First load your audio as required in the levels in the beginning of application initialization.Suppose you need 5 sound in the level load them in the beginning and keep the soundID's handy.
2) Now on any event just call play with the soundID.
3) This plays with a very less delay while I debugged from SoundPool play till HAL layer.Around 10-15 ms in my device.
For more info on SoundPool implementation follow my github thread:
https://github.com/sauravpradhan/Basic-Audio-Routing
I am having a bit of difficulty with my SoundPool. I have an ArrayList<Integer> of my soundIDs located in my res/raw folder. I'm creating the SoundPool like so in my ViewHolder class for my RecyclerView:
//create the SoundPool
sp = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
//create the AudioManager for managing volume
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
//store the streamVolume in an int
streamVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
//set the load listener for my soundfiles
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
loaded = true;
}
});
I am playing the sound on the click of an ImageView like so:
#Override
public void onClick(View v) {
if (v.equals(cardImg)) {
sp.load(context, cardData.getSoundId(), 1);
if (loaded) {
sp.play(cardData.getSoundId(), streamVolume, streamVolume, 1, 0, 1f);
}
}
}
And every time I click on the cardImg it gives me this error:
W/SoundPool﹕ sample 2130968609 not READY
Where the sample int changes depending on which card I click, like it should.
So I know that it's GETTING the proper soundID from my ArrayList (stored in CardData class), and it definitely sees that it's loaded, because it wouldn't try to play otherwise because loaded would never be true. My question is: Why are my sounds never ready?
My sounds are .m4a format which Android says is supported in the documentation. I've tried on an Android 5.0 device and an Android 4.4 device but nothing changes.
I have tried using a MediaPlayer but I am running into memory errors as I have many short clips that need to be able to be spammed and I read that a SoundPool was a much better way to manage this (?).
Any help would be appreciated! I am super vexxed here.
You're using the wrong id. SoundPool.load returns an id that is suppose to be passed in to SoundPool.play.
I would like to play sound after touching the button. MediaPlayer works fine, but I read somewhere that this library is for long .wav (like music).
Is there any better way to play short .wav(2-3 sec.)?
The SoundPool is the correct class for this. The below code is an example of how to use it. It is also the code I use in several apps of mine to manage the sounds. You can have as may sounds as you like (or as memory permits).
public class SoundPoolPlayer {
private SoundPool mShortPlayer= null;
private HashMap mSounds = new HashMap();
public SoundPoolPlayer(Context pContext)
{
// setup Soundpool
this.mShortPlayer = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
mSounds.put(R.raw.<sound_1_name>, this.mShortPlayer.load(pContext, R.raw.<sound_1_name>, 1));
mSounds.put(R.raw.<sound_2_name>, this.mShortPlayer.load(pContext, R.raw.<sound_2_name>, 1));
}
public void playShortResource(int piResource) {
int iSoundId = (Integer) mSounds.get(piResource);
this.mShortPlayer.play(iSoundId, 0.99f, 0.99f, 0, 0, 1);
}
// Cleanup
public void release() {
// Cleanup
this.mShortPlayer.release();
this.mShortPlayer = null;
}
}
You would use this by calling:
SoundPoolPlayer sound = new SoundPoolPlayer(this);
in your Activity's onCreate() (or anytime after it). After that, to play a sound simple call:
sound.playShortResource(R.raw.<sound_name>);
Finally, once you're done with the sounds, call:
sound.release();
to free up resources.
I'm looking to do a very simple piece of code that plays a sound effect. So far I have this code:
SoundManager snd;
int combo;
private void soundSetup() {
// Create an instance of the sound manger
snd = new SoundManager(getApplicationContext());
// Set volume rocker mode to media volume
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Load the samples from res/raw
combo = snd.load(R.raw.combo);
}
private void playSound() {
soundSetup();
snd.play(combo);
}
However, for some reason when I use the playSound() method, nothing happens. The audio file is in the correct location.
Is there a specific reason you are using SoundManager? I would use MediaPlayer instead, here is a link to the Android Docs
http://developer.android.com/reference/android/media/MediaPlayer.html
then it's as simple as
MediaPlayer mp = MediaPlayer.create(getApplicationContext(), R.raw.combo);
mp.start();
Make a directory called "raw/" under the "res/" directory. Drag wav or mp3 files into the raw/ directory. Play them from anywhere as above.
i have also attempted using the top answer, yet it resulted in NullPointerExceptions from the MediaPlayer when i tried playing a sound many times in a row, so I extended the code a bit.
FXPlayer is my global MediaPlayer.
public void playSound(int _id)
{
if(FXPlayer != null)
{
FXPlayer.stop();
FXPlayer.release();
}
FXPlayer = MediaPlayer.create(this, _id);
if(FXPlayer != null)
FXPlayer.start();
}