Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (731)
Games in Android Showcase (217)
games submitted by our members
Games in WIP (799)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  JavaFX audio not working properly?  (Read 506 times)
0 Members and 1 Guest are viewing this topic.
Offline JoshuaCrotts

Senior Newbie


Exp: 2 years



« Posted 2017-03-19 21:33:17 »

So, I'm currently using a system that implements JavaFX into my game. The problem is: I'm wanting to repeatedly play the same sound effect multiple times. I'm making a Brick Breaker game, and I'm replaying the constant sound effect whenever a brick is hit. And, if you've ever played Brick Breaker, the ball can become stuck at the top and hit a ton of bricks sequentially, thus causing a ton of sound effects. Well, when I try to implement this with one MediaPlayer OR AudioClip JavaFX object, it only plays it once, and unless a slight amount of time goes by between bricks, it doesn't play it again. My only work around is by, every time a brick is hit by the ball, create a NEW Audio object, then immediately play it. This WORKS, though, it is incredibly inefficient and slows my game down tremendously, and I have a powerful PC. Can anyone help me with this endeavor?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
 
package com.joshuacrotts.pt.main;

import java.util.ArrayList;

import com.joshuacrotts.standards.StandardAudio;

public class SongBox {
   
   public static ArrayList<StandardAudio> songs;
   public static ArrayList<StandardAudio> sfx;
   
   public SongBox(){
     
      SongBox.songs = new ArrayList<StandardAudio>();
      SongBox.songs.add(new StandardAudio("Resources/Audio/Music/menu.wav",false)); //Menu music
      SongBox.songs.add(new StandardAudio("Resources/Audio/Music/level1.wav",false));//Level 1 music
      SongBox.songs.add(new StandardAudio("Resources/Audio/Music/level2.wav",false));//Level 2 music
     
      SongBox.sfx = new ArrayList<StandardAudio>();
      SongBox.sfx.add(new StandardAudio("Resources/Audio/SFX/menuselect.wav",true));//Clicking on a button
      SongBox.sfx.add(new StandardAudio("Resources/Audio/SFX/explode_1.wav",true));//Breaking a brick
      SongBox.sfx.add(new StandardAudio("Resources/Audio/SFX/whoosh.wav",true));//Getting an item
     
   //   resetVolumes();
   }
   
   public void resetVolumes(){
      for(int i = 0; i<songs.size(); i++){
         songs.get(i).resetVolume();
      }
     
      for(int i = 0; i<sfx.size(); i++){
         sfx.get(i).resetVolume();
      }
   }
   
   /**
    * This method will add a sound to the arraylists.
    * @param audio
    * @param sfx
    *
    * This is mainly so I can have more than one sound effect playing at once.
         * THIS IS THE METHOD IM REFERENCING IN THE FORUM POST ****************
    */

   public static void addSound(String audio, boolean sfx){
      if(!sfx){
         SongBox.songs.add(new StandardAudio(audio,true));
         SongBox.songs.get(SongBox.songs.size()-1).play();
      }else{
         SongBox.sfx.add(new StandardAudio(audio,true));
         SongBox.sfx.get(SongBox.sfx.size()-1).play();
      }
   }
   public static void clearSFX(){
      for(int i = 1; i<SongBox.sfx.size(); i++){
         SongBox.sfx.remove(i);
         i--;
      }
   }
}

//Below is my Audio (StandardAudio) class:

package com.joshuacrotts.standards;

import java.io.File;

import javafx.scene.media.AudioClip;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
/**
 *
 * Takes an audio source in and plays it.
 *
 */

public class StandardAudio{

   private String fileName;
   //private Media media;
   private AudioClip sound;
   private boolean sfx;
   
   public StandardAudio(String fileName, boolean sfx)
   {
      this.sfx = sfx;
      new javafx.embed.swing.JFXPanel();
     
      try{
         this.sound = new AudioClip(new File(fileName).toURI().toString());
         //this.sound = new MediaPlayer(this.media);
         
      }catch(Exception e)
      {
         e.printStackTrace();
      }
     
      this.sound.setVolume(1);
   }
   
   public void play()
   {
      if(this.sound.isPlaying())
         return;
      else
         this.sound.play();
      if(!sfx)
         this.loop();
   }
   
   
   public void adjustVolume(double val) {
      this.sound.setVolume(this.sound.getVolume() + val);
   }
   
   public double getVolume(){
      return this.sound.getVolume();
   }
   
   public void fadeToBlack() {
     
      double val = -0.05D;
      this.adjustVolume(val);
      if(this.getVolume() <= 0) {
         this.sound.stop();
         this.sound.setVolume(1);
      }
   }
   
   public void stop()
   {
      this.sound.stop();
      //audioClip.close();
   }
   public String getFileName()
   {
      return fileName;
   }
   
   /**
    * @param x determines if the loop is infinite. If it's 1, it is. Else, it's not.
    */

   public void loop(){
      this.sound.setCycleCount(MediaPlayer.INDEFINITE);
   }
   
   public void resetVolume(){
      this.sound.setVolume(1);
   }
}
Offline KaiHH

JGO Kernel


Medals: 416



« Reply #1 - Posted 2017-03-19 22:15:07 »

Well, when I try to implement this with one MediaPlayer OR AudioClip JavaFX object, it only plays it once, and unless a slight amount of time goes by between bricks, it doesn't play it again.
That's true, I am experiencing that, too. Even though the JavaDocs of JavaFX's AudioClip class says that it is capable of being played multiple times simultaneously, that does not seem to be entirely true. Trying to play a single very short AudioClip at intervals of around 100ms gets me a very disturbing "pattern" which also shifts/changes over time.

People usually work around something like this by creating a pre-allocated pool and obtaining ready instances off that pool.
In the case of AudioClip, this could look like so:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
private static final int NUM_BUFFERS = 5;

/**
 * Pool of AudioClips for a specific sound name, each.
 */

private Map<String, List<AudioClip>> clips = new HashMap<String, List<AudioClip>>();

/**
 * Create a pool of a number of AudioClips for the sound with the given name.
 */

private void init(String name) {
   List<AudioClip> cs = new ArrayList<AudioClip>();
   clips.put(name, cs);
   for (int i = 0; i < NUM_BUFFERS; i++) {
      AudioClip clip = new AudioClip(convertNameToUrlSomewhow(name));
      cs.add(clip);
   }
}

/**
 * Obtain a ready AudioClip from the pool for the sound with the given name.
 * @return <code>null</code> if no AudioClip in the pool is ready yet
 */

private AudioClip get(String name) {
   List<AudioClip> cs = clips.get(name);
   for (AudioClip clip : cs) {
      if (!clip.isPlaying()) {
         /* Even though the clip is not playing anymore, we have to stop it
          * otherwise it wouldn't play right from the start. */

         clip.stop();
         return clip;
      }
   }
   /* No AudioClip ready yet! */
   return null;
}


Everytime you want to play a sound with a given name, you just call get(name). This of course only works for very short sounds since in this scheme an AudioClip can only be reused once it is done playing. So the number of pool instances you need depends on the length of the audio track divided by the shortest interval between two successive plays.
Offline philfrei
« Reply #2 - Posted 2017-03-20 01:43:13 »

I've not used AudioClip yet, myself. I'm puzzled about a couple of things.

For starters, the following from the API seems contradictory.
Quote
Playback behavior is fire and forget: once one of the play methods is called the only operable control is stop(). An AudioClip may also be played multiple times simultaneously.

How do you play an AudioClip concurrently if the only operable method after a play is stop()? Maybe the intention was to say each play() is fire and forget?

Secondly, why test for isPlaying() in your code before executing Play()? Do you get an illegal state exception if you call play and it is already playing? There's no illegal state mentioned in the API. Even if the AudioClip does allow concurrent playback, then this test will definitely prevent it. (And if there is silence at the end of the cue, the point where it actually finishes may be beyond the point where the cue goes silent.)

I'd try losing this test before getting into creating a pool of AudioClips. The pool should not be needed if the second line quoted above was written in plain English. (Pools can help if working with javax.audio.sampled.Clip, as they don't allow concurrent playback.)

Another approach is to stop and restart with each play. Then, when the plays are coming faster than the cue can end, the cue will stop without finishing and restart immediately. This can work reasonably well in a lot of circumstances.

In other words:
1  
2  
3  
4  
5  
    public void play()
    {
       this.sound.stop();  // no need to test isPlaying()
       this.sound.play();
    }


Else, if concurrent playback works, seems like simply this should work:
1  
2  
3  
4  
    public void play()
    {
        this.sound.play();
    }


The only hitch here is if the distance between the play calls is only a couple millis, the two playbacks could cause artifacts resulting from comb-filtering.

music and music apps: http://adonax.com
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline nsigma
« Reply #3 - Posted 2017-03-21 19:36:21 »

Well, this comment is amusing - wonder if that's still the up-to-date source?!  Roll Eyes  Good to hear AudioClip in JavaFX is just as broken as the JavaSound one then.

Praxis LIVE - hybrid visual IDE for (live) creative coding
Pages: [1]
  ignore  |  Print  
 
 

 
Archive (343 views)
2017-04-27 17:45:51

buddyBro (540 views)
2017-04-05 03:38:00

CopyableCougar4 (992 views)
2017-03-24 15:39:42

theagentd (1023 views)
2017-03-24 15:32:08

Rule (997 views)
2017-03-19 12:43:22

Rule (980 views)
2017-03-19 12:42:17

Rule (977 views)
2017-03-19 12:36:21

theagentd (1082 views)
2017-03-16 05:07:07

theagentd (1008 views)
2017-03-15 22:37:06

theagentd (779 views)
2017-03-15 22:32:18
List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05

SF/X Libraries
by SkyAphid
2017-03-02 06:38:56

SF/X Libraries
by SkyAphid
2017-03-02 06:38:32

SF/X Libraries
by SkyAphid
2017-03-02 06:38:05

SF/X Libraries
by SkyAphid
2017-03-02 06:37:51
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!