Playing sounds simultaneously Android - java

I am creating a game on Android and I have kind of put this problem off for a while, and am now just coming back to it. In my game I have a background beat, gun sounds, explosions... etc. and I need to be able to play them simultaneously. Right now when I call play on the SoundPool class, the currently playing sound gets interrupted and the new one starts to play. My SoundManager class is below as well as the usage. Any help would be much appreciated as this is really my first game where I have needed this many sound effects. Thanks!
public class SoundManager {
private SoundPool mSoundPool;
private HashMap<Integer, Integer> mSoundPoolMap;
private AudioManager mAudioManager;
private Context mContext;
public SoundManager(Context theContext) {
mContext = theContext;
mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
mSoundPoolMap = new HashMap<Integer, Integer>();
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}
public void addSound(int index, int SoundID) {
mSoundPoolMap.put(index, mSoundPool.load(mContext, SoundID, 1));
}
public void playSound(int index) {
float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_RING);
streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
mSoundPool.play((Integer) mSoundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f);
}
public void playLoopedSound(int index) {
float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mSoundPool.play((Integer) mSoundPoolMap.get(index), streamVolume, streamVolume, 1, -1, 1f);
}
}
... and here is an example of how I use the class.
SoundManager sm = new SoundManager(this);
sm.addSound(0, R.raw.explosion);
sm.playSound(0);
... So with this style I add all my sounds to the SoundPool on load and then based on user input I just want to play the sound. Does this look correct? Or should I try and go about this a different way?

Well I did end up figuring this out in case anyone else wants to know. The problem wasn't that it couldn't play more than one sound at a time it was that it was only able to play 4 sounds at a time which gave me the impression that sounds were stopping and starting. In the constructor this line
mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
needed to be changed to allow more streams to play at the same time. So by changing the first argument from a 4 to say, a 20, you could then play 20 sounds at the same time. The game sounds much better now haha. Hope this helps someone.

Related

Drawing and audio not working together in Java Android App

I am currenty doing a small game. But my application does not work properly. Program does not stop with error, but firstly it playes part of track, and after that (around 5-10 seconds) it stops and drawing begins.
Without audio added, code works absolutely fine.
I also tested app on several different devices and emulators, but issue keeps occuring.
Here are some methods from class "Game.java", where I am trying to implement audio.
public class Game {
Plane background;
Plane playfield;
Context context;
List<SingleNote> notes = new ArrayList<SingleNote>();
List<SingleNote> notes_to_compute = new ArrayList<SingleNote>();
Date date = new Date();
long time_initial;
float[] touch_coord = new float[2];
private int mStreamId;
public Game(Context context){
this.context = context;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public void load(){
background = new Plane(context, R.raw.vertex_shader, R.raw.fragment_shader, R.drawable._map1);
playfield = new Plane(context, R.raw.vertex_shader, R.raw.fragment_shader, R.drawable.s_playfield);
InitNotes(R.raw._map1);
time_initial = date.getTime();
MyThread m = new MyThread();
m.context = context;
m.start();
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public void draw(){
background.draw();
playfield.draw();
update();
}
}
class MyThread extends Thread {
Context context;
public void run(){
SoundManagement.playSoundPool(context, R.raw._map1_a);
}
}
And static PlaySondPool method in class
public static void playSoundPool(Context context, int soundID) {
int MAX_STREAMS = 20;
int REPEAT = 0;
SoundPool soundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, REPEAT);
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int soundId, int status) {
int priority = 0;
int repeat = 0;
float rate = 1.f; // Frequency Rate can be from .5 to 2.0
// Set volume
AudioManager mgr = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
float streamVolumeCurrent =
mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
float streamVolumeMax =
mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
float volume = streamVolumeCurrent / streamVolumeMax;
// Play it
soundPool.play(soundId, volume, volume, priority, repeat, rate);
}
});
soundPool.load(context, soundID, 1);
}
I thought using separate thread would help, but same issue occurs.
What should I do in order to avoid this error? Maybe use another library, or play sound from other class?
Whole code here: https://github.com/arthur100500/AndroidProject
Additional debug ingormation from android studio
Logcat: https://pastebin.com/MQSaWw8R
Run: https://pastebin.com/5D4AGuHZ
How it looks: https://youtu.be/X7IBquHs1jA
I think there is every likelihood that the choice of SoundPool for playback is the source of the problem you are experiencing. SoundPool is designed for the handling of audio files that are short (a couple seconds) and can be held in memory. You've indicated that you are trying to use it to play a 5-minute long file. According to the documentation in the API, only the first MB of the 5-minute file is being handled.
Soundpool sounds are expected to be short as they are predecoded into
memory. Each decoded sound is internally limited to one megabyte
storage, which represents approximately 5.6 seconds at 44.1kHz stereo
(the duration is proportionally longer at lower sample rates or a
channel mask of mono). A decoded audio sound will be truncated if it
would exceed the per-sound one megabyte storage space.
Streaming via an AudioTrack should be a more fitting alternative for this sound file.
An AudioTrack instance can operate under two modes: static or
streaming. In Streaming mode, the application writes a continuous
stream of data to the AudioTrack, using one of the write() methods.
These are blocking and return when the data has been transferred from
the Java layer to the native layer and queued for playback. The
streaming mode is most useful when playing blocks of audio data that
for instance are:
too big to fit in memory because of the duration of the sound to play,
too big to fit in memory because of the characteristics of the audio data (high sampling rate, bits per sample ...)
received or generated while previously queued audio is playing.

Music not playing properly on touch-LibGdx

I have array of coins spread in the screen.I want to add sound when I touch a coin.
private Music coinSound;
in show():
coinSound=assetManager.get(Assets.collectCoin);
calling coinSound.play() here:
if (MyInputProcessor.isTouchDown) {
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
game.camera.unproject(touchPos);
for (int i = 0; i < coins.length; i++) {
Rectangle textureBounds = new Rectangle(coins[i].getX(), coins[i].getY(), coins[i].getWidth(),coins[i].getHeight());
if (textureBounds.contains(touchPos.x, touchPos.y) && !coins[i].isBreakBool()) {
coinSound.play();
coins[i].setTapBool(true);
}
}
MyInputProcessor.isTouchDown = false;
}
Now sound is playing but not for all the array elements.for touch on one coin it is playing correctly every time.What do I need to change for making it play for each coins on touch?
Use Sound instead of Music.
Sound effects are small audio samples, usually no longer than a few seconds, that are played back on specific game events such as a character jumping or shooting a gun.
AssetManager manager = new AssetManager();
manager.load("data/mysound.mp3", Sound.class);
manager.finishLoading();
Get sound from AssetManager
Sound sound = manager.get("data/mysound.mp3", Sound.class);
sound.play();
Music instances are heavy, you should usually not have more than one or two at most loaded.

Quality issue when playing sound and fast fade-out in Java

Sorry for my bad english
I write a Java desktop application that plays musical instruments audio files samples.
Each time a note is received by the application, it must stop the current playing note and play the new one. if the user stops playing, the app must do a fade-out to the active note.
By the way, smaller latency is better.
I created a runnable which owns a play and stop method allowing me to play or stop a note(with fade out)
My code works but the sound quality is bad(many click and clipping etc)..
-How to improve my code? Did I make mistake?
-Otherwise it is there any other Java technology than JavaFx media player that is best suited for my need?
public class SamplePlayer implements Runnable{
private boolean fadeOut=false; // true when a fade out is needed
private int soundToFadeOut=0; //the sound number to fade out
private int sound=0; // the sound number to play (nothing if zero)
private int lastSound=0; //the last sound number played that wee need to stop befor playing a new one
MediaPlayer[] sample = new MediaPlayer[42]; //array to store all pre-loaded sounds
public SamplePlayer()
{
for(int i=0;i<42;i++) // load all sounds
{
Media pick = new Media(new File("./src/files/samples/1_"+(i+55)+".wav" ).toURI().toString());
sample[i] = new MediaPlayer(pick);
}
}
/**
* Here i try to play a sound each time the sound variable has changed
* and fade out the sound specified in soundToFadeOut variable if fadeOut variable come to true;
*/
#Override
public void run() {
while(true) // bad, but it's just for testing
{
try {
if(sound!=0) // if a sound need to be played
{
if(lastSound!=0) // if i's not the first sound to played i stop the previous one.
{
sample[lastSound].stop();
}
sample[sound].setVolume(1); //returns the volume to 1 in case we made a fade out
lastSound=sound;
sound=0;//sound = 0 to monitor new other sound
}
if(fadeOut==true) // if wee need to make a fade out
{
fadeOut=false;
fadeOut(sample[soundToFadeOut],50);
}
Thread.sleep(1); // if not the thread keep busy and play, stop method not working properly
} catch (InterruptedException ex) {
Logger.getLogger(SamplePlayer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private void fadeOut(MediaPlayer player,double itteration) // fade out method : run a new thread to itterate on volume
{Runnable task = () -> {
try{
for(int i=0;i<itteration;i++)
{
double value=(itteration-i)/itteration; // set value to 1.0 to near 0.0 each itteration
if(value<0.1)
{
value=0;
}
player.setVolume(value);
Thread.sleep(5);
}
}catch(Exception e){e.printStackTrace();}
};
new Thread(task).start();
}
/*
*
* play and stop method which are called when a sound need to be played or stoped (fade out)
*
*/
public void play(int note)
{
sound=note-55; // -55 just to match with our array range
}
public void stop(int note)
{
soundToFadeOut=note-55;
fadeOut=true;
}
}

Play two sounds with SoundPool

I'm a newie to programming and I'm pretty sure that I'm making a dumb mistake here, but I'm stuck and can't manage to fix it.
The error that appears is the following:
Wrong 1st argument type. Found: 'int[]', required: 'int'
This error appears almost at the end of the code, when trying to play the sounds. More specifically at:
spool.play(soundId, 1, 1, 0, 0, 1f);
I'm pretty sure that this could be really easy to fix but I just couldn't do it. Can anyone help me fix it, please?
I decided to just post here the part where I'm having the issue; if someone would like to check the whole thing, it's right in the revisions.
if (rndm == 0) { //I'm just testing it with the horse sound
//right now, so if the random sound that is
//played equals to zero, that's the horse sound
final int[] soundId = new int[2];
soundId[0] = spool.load(actibida.this, R.raw.el, 1); //"el" is the horse sound ID
soundId[1] = spool.load(actibida.this, R.raw.applause, 1); //this is an applause clip I want to be played simultaneously with the horse sound
ImageButton caballo = (ImageButton) findViewById(R.id.caballo); //this is the horse ImageButton ID
caballo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spool.play(soundId, 1, 1, 0, 0, 1f); //this is
//where I'm
//having the
//issue.
}
});
}

JavaFX Creates Daemon Threads called "Timer-XX"

I just recognized that my program creates a Daemon Thread every time I play a MP3. And they're are Named "Timer-XX" as everybody suggest yes XX is a increasing integer starting with zero.
Ok I can understand that JFX needs them to play a MP3 but actually the MP3 is just 3 sec long and some of them stay Running for a couple of minutes or longer, while others normaly run out (i just suggest it should be like this).
I would like to know why they get created in the first place? Why they stay Running and how I can get ride of them because as far as I know Daemon dose not mean stopped so it still eats Memory and CPU what I can't give away like candy in the current state of my project.
Here is the code that plays the MP3s:
public class EffectPlayer {
private final String MP3_SUFFIX = ".mp3";
private final static int MAX_VOLUME = 100;
private MediaPlayer mediaPlayer;
private int masterVolume = 50;
private int effectVolume = 50;
public EffectPlayer(File f){
if(isMP3(f)){
Media mp3 = new Media(f.toURI().toString());
mediaPlayer = new MediaPlayer(mp3);
effectVolume = Integer.parseInt(GetConfig.getVar("USER_OPTION_VOLUME_EFFECT"));
masterVolume = Integer.parseInt(GetConfig.getVar("USER_OPTION_VOLUME_MASTER"));
if(effectVolume > masterVolume) effectVolume = masterVolume;
mediaPlayer.setVolume(1 - (float)(Math.log(MAX_VOLUME - effectVolume) / Math.log(MAX_VOLUME)));
mediaPlayer.setCycleCount(1);
mediaPlayer.play();
}
}
private boolean isMP3(File f) {
return f.getName().toLowerCase().endsWith(MP3_SUFFIX);
}
}
The JFX Panel gets created in the class that Creates a EffectPlayer Object
#SuppressWarnings("unused")
public static JFXPanel fxPanel = new JFXPanel();

Categories

Resources