Music not playing properly on touch-LibGdx - java

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.

Related

Controlling volume of different sound files independent from each other using sliders

I've been working on this project with a peer for comp sci class, and I can't figure out how to make SFX and music have their own independent volume controls. Both the music and the SFX both play just fine when they need to (hovering/clicking on buttons, menu music, etc), and I made sliders for both of them (music volume and SFX volume), but for some reason only music can be controlled. I have sat here for hours trying to figure out why it doesn't work. The FloatControl gain does update with the slider (I printed out it's value and it was working just fine, just not updating the actual volume of the sound effects). I also got rid of everything to do with the music by commenting out everything regarding it's slider controls, audio input stream, gain control, etc; it was as if SFX was the only audio related thing in the program, but it still didn't work. I don't understand why since the code is identical to the music's code (just that "music" is now "sound").
The below code is not meant to be functional on it's own since the actual code is 605 lines so far and that's too long to post on here. It does contain the core components, so if you want to set it up to work you have to make the JFrame and all the buttons, or have me post the full code and sound files.
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.sound.sampled.*;
import java.awt.event.*;
import javax.swing.border.Border;
import javax.swing.BorderFactory;
import java.io.*;
import java.io.File.*;
import java.io.IOException;
public class AudioTesting {
// Declare Global Objects
static final String[] SFXName = {"menuHover", "buttonEnter", "buttonLeave", "gameStart"};
static final String[] TrackName = {"Bossfight_Incomplete"};
static final String userName = System.getProperty("user.name");
static Clip sound;
static Clip music;
static JSlider musicVolumeSlider;
static JSlider soundVolumeSlider;
public static void main(String []args){
GameSetting();
}
public static void GameSetting(){
musicVolumeSlider = new JSlider(-45,6,6);
soundVolumeSlider = new JSlider(-45,6,6);
musicVolumeSlider.setMajorTickSpacing(5);
musicVolumeSlider.setMinorTickSpacing(1);
musicVolumeSlider.setPaintTicks(true);
//musicVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
// musicVolumeSlider.setBackground(menuColor);
musicVolumeSlider.addChangeListener(new SliderListener());
soundVolumeSlider.setMajorTickSpacing(5);
soundVolumeSlider.setMinorTickSpacing(1);
soundVolumeSlider.setPaintTicks(true);
// soundVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
// soundVolumeSlider.setBackground(menuColor);
soundVolumeSlider.addChangeListener(new SliderListener());
}
//manages the loading and playing of sfx
public static void SFXManager(int sfx){
try{
sound = AudioSystem.getClip();
File sfxFile = new File("C:\\Users\\" + userName + "\\Documents\\" + SFXName[sfx] + ".wav");
sound.open(AudioSystem.getAudioInputStream(sfxFile));
}catch (Exception ex){}
sound.flush();
sound.start();
}
// manages the loading and playing of music tracks
public static void MusicManager(int track){
try{
music = AudioSystem.getClip();
File musicFile = new File("C:\\Users\\" + userName + "\\Documents\\" + TrackName[track] + ".wav");
music.open(AudioSystem.getAudioInputStream(musicFile));
}catch (Exception ex){}
music.start();
music.loop(Clip.LOOP_CONTINUOUSLY);
}
static class SliderListener implements ChangeListener {
public void stateChanged(ChangeEvent e) throws IllegalArgumentException {
float currentMusicVolume = 0;
float currentSoundVolume = 0;
FloatControl musicGainControl = (FloatControl) music.getControl(FloatControl.Type.MASTER_GAIN);
FloatControl soundGainControl = (FloatControl) sound.getControl(FloatControl.Type.MASTER_GAIN);
//-------------------------------------------------------------PROBLEM AREA v v v
//For changing the volume of the music (this works just fine)
if (e.getSource() == musicVolumeSlider){
currentMusicVolume = musicVolumeSlider.getValue();
//if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
if (currentMusicVolume == -45){
currentMusicVolume = -80;
}
musicGainControl.setValue(currentMusicVolume); // Reduce volume by slider value
}
//for changing the volume of the sfx
if (e.getSource() == soundVolumeSlider){
currentSoundVolume = soundVolumeSlider.getValue();
//if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
if (currentSoundVolume == -45){
currentSoundVolume = -80;
}
soundGainControl.setValue(currentSoundVolume); // Reduce volume by slider value
}
}
}
//-------------------------------------------------------------PROBLEM AREA ^ ^ ^
// I didn't implement it in here, but here is where all the mouse and event listeners go for the different buttons
// If a button is hovered over or pressed, it plays a sound from the index that corresponds with that sound
// I.e. if you hover over a button, call SFXManager(0); which plays the first sound in the array (buttonHover.wav) etc.
}
I've found these float controls to be kind of hit-or-miss, in part because they depend on the local PC and its OS. It's often the case that only the master gain works, if you want to change volumes in real time. The master gain changes will affect ALL the playing sounds.
You could follow the suggestion from the last paragraphs of the Oracle sound tutorial on audio controls and write your own volume controls. To do so requires intercepting the audio input stream, compiling the bytes into PCM, multiplying the PCM by a volume factor, converting the PCM back to bytes, and finally, shipping the bytes out via a SourceDataLine.
This is basically the plan I followed when I wrote AudioCue. You are welcome to use that code base as an example for rolling your own, or to import and directly make use of the files within your project. I tried to follow the Clip API as closely as I could, while adding real time volume controls for each playing audio instance. One limitation is that it only works with wav files. But if you can work with that, feel free to use the library. I'm happy to answer any questions if you have any trouble setting it up.
I'm currently learning how to make the program available as a Maven resource. I'm not clear on how the Gradle instructions work--another contributor did that part. It is pretty easy to just copy the five files into your project and use them with just a little tinkering to the import/package lines.

AudioManager is introducing delay in the setMode(MODE_IN_COMMUNICATION)

I am trying to play sound on speaker even if headphones are on, BUT if there is music playing in background, I want the music to be played on headphones until the sound is played.
So I am taking the next steps:
Before I play sound, I gain audioFocus so all the background music is
stopped
After audioFocus is gained, I set MODE_COMMUNICATION to the
AudioManager, so the sound can be played on the speaker.
After the sound ends, I abandonAudioFocus and set back MODE_NORMAL to
AudioManager, so the background music can continue playing on the headphones.
The strange thing is that it depends from the device, on some device this is OK, but on Nexus 6P (Huawei) devices after setting the MODE_COMMUNICATION there is delay 3-4 seconds before the sound can be played. If I play the sound without the delay, it is not played neither to speaker nor to headphones.
THE QUESTION
How can I know how much delay to set before the sound is played? Is there any listener that I can attach, so can notify me that after setting MODE_COMMUNICATION the sound is ready to be played?
I don't want to set delay even if it is not necessary!
The solution is not setting the mode into the constructor of the class(to skip the delay), because I need the sound to be played on speaker in the specific moment!
P.S: I am playing the sound with AudioTrack, but I tried with MediaPlayer as well (setting setAudioStreamType(MODE_IN_COMMUNICATION)), but no success, the delay is still there!
So any suggestions?
In case anyone stumbles upon this post, what worked for me was calling AudioManager.setMode() and then recreating my MediaPlayer (via constructor, not create()) and using setAudioAttributes() to change the output source.
Kotlin snippet:
fun switchOutput(inCommunication: Boolean) {
//STEP 1: Change the AudioManager's audio mode
if(inCommunication) {
audioManager.mode = AudioManager.MODE_IN_CALL
audioManager.isSpeakerphoneOn = false
} else {
audioManager.mode = AudioManager.MODE_NORMAL
audioManager.isSpeakerphoneOn = true
}
//STEP 2: Recreate the MediaPlayer
if (player != null) {
try {
player?.stop()
} catch (e: RuntimeException) {
} finally {
player?.reset()
player?.release()
player = null
}
}
player = MediaPlayer()
try {
val streamType =
if (inCommunication) AudioManager.STREAM_VOICE_CALL
else AudioManager.STREAM_MUSIC
player?.setDataSource(dataSource)
player?.setAudioAttributes(AudioAttributes.Builder()
.setLegacyStreamType(streamType)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build())
player?.prepare()
player?.start()
} catch (e: java.lang.Exception) {}
}
Hope this helps :)
P.S. Notice I've used MODE_IN_CALL instead of MODE_IN_COMMUNICATION

how to display the "Game over" image in android for a fixed amount of time and restart the game when user taps the screen after a specified interval?

I made clone of ""Flappy bird" game by watching video tutorials.i programmed it so that when the bird falls or collides with the tubes a game over message appears on the screen and the game restarts when the player taps on the screen.
The problem is that when the user fails to tap the bird in time and it collides with the tube,the game over screen appears immediately and the user happens to tap on the game over screen which results in restarting of the game.
This makes the user unable to see the score.I have already tried using Thread.sleep().Following is the code
(gameState == 2)
{
batch.draw(gameOver,Gdx.graphics.getWidth()/2-gameOver.getWidth()/2,Gdx.graphics.getHeight()/2-gameOver.getHeight()/2);
try
{
Thread.sleep(2000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
if (Gdx.input.justTouched()) {
gameState = 1;
startGame();
score =0;
scoringTube = 0;
velocity = 0;
}
}
With this code the problem is that even the gameover image is being delayed and the previous problem is still occuring but now with a delay.I basically need a way so that justTouched method becomes inactive for a while when the game over screen is there.Please help.
I really wouldn't recommend using Thread.sleep; instead, you could try to use a boolean that is changed once the game ended, and prevent the method from executing in that case. Combine that with e.g a Timer that resets it after a fixed delay, and you should have the solution to your problem.
Example Usage for the timer:
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
//execute code here (change boolean state)
}
},
yourDelayHere
);

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;
}
}

Playing sounds simultaneously Android

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.

Categories

Resources