• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 204
  • Last Modified:

Best way to add sounds to an application

Hi all,

This is mainly a design question - I've worked out how to create sounds but I'd like to know the best way of adding them to an application.

My application has 5 GUI classes, which will share about 10 different sounds.  Here is my currrent settup, could you please tell me whether there is a better way to do it:

Currently I have an abstract class called "Sounds".  In my main function I call Sounds.initialise()

Here is the sounds class:

public class Sounds {
  public Sounds() {
  }

  public static AudioClip BEEP;
  public static AudioClip CLICK;
  public static AudioClip ERROR;
  .
  .
  . etc

  public static void initialise() {
    try {
      BEEP = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      CLICK = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      .
      .
      . etc

    }
    catch (MalformedURLException ex) {
    }
  }

To make a sound in my GUI classes I use:

Sounds.BEEP.play();

Is this good or is there a better design?
0
agrees
Asked:
agrees
  • 18
  • 12
  • 10
2 Solutions
 
girionisCommented:
Sounds is not an abstract class. I think the design is good, maybe you could make Sounds final and use it as a utrility class.
0
 
girionisCommented:
... or since the methods are already static you might want to leave it as it is.
0
 
zzynxSoftware engineerCommented:
>> In my main function I call Sounds.initialise()
To avoid that (and the danger of forgetting it) you can write:

public class Sounds {
  public Sounds() {
  }

  public static AudioClip BEEP;
  public static AudioClip CLICK;
  public static AudioClip ERROR;

  {
    try {
      BEEP = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      CLICK = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      .
      .
      . etc

    }
    catch (MalformedURLException ex) {
    }
  }

The static initialization is called whenever Sounds is used.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
girionisCommented:
> The static initialization is called

It's not a statci initialization. This is:

static
{
 ...
 ...
}
0
 
girionisCommented:
You could also do that:

public class Sounds {
  public Sounds() {

          try {
      BEEP = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      CLICK = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      .
      .
      . etc

    }
    catch (MalformedURLException ex) {
    }

  }

  public static AudioClip BEEP;
  public static AudioClip CLICK;
  public static AudioClip ERROR;
  .
  .
  . etc

}
0
 
zzynxSoftware engineerCommented:
Of course, I forgot static:


public class Sounds {
  public Sounds() {
  }

  public static AudioClip BEEP;
  public static AudioClip CLICK;
  public static AudioClip ERROR;

  static
  {
    try {
      BEEP = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      CLICK = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
      .
      .
      . etc

    }
    catch (MalformedURLException ex) {
    }
  }
0
 
zzynxSoftware engineerCommented:
>> You could also do that

Is the constructor called when writing

            Sounds.BEEP.play();

?
I think that will lead to a NPE
0
 
girionisCommented:
> >> You could also do that

> Is the constructor called when writing

>             Sounds.BEEP.play();

> ?
> I think that will lead to a NPE

It will if you do not create an instance. This will (hopefully) work:

Sounds s = new Sounds();
Sounds.BEEP.play();
0
 
zzynxSoftware engineerCommented:
>> It will if you do not create an instance

Same as with Sounds.initialise() (which I'd prefer above creating an instance) : you can forget it.
I would go for the static way.
0
 
agreesAuthor Commented:
> I would go for the static way.

Yes that certainly seems easiest.  I have heard people say static blocks are bad practice though?  Is there anything I need to watch out for?
0
 
zzynxSoftware engineerCommented:
>> Is there anything I need to watch out for?
not aware of any pitfalls
0
 
agreesAuthor Commented:
I've added another 20 points for a related question!  It just occured to me I should do the same thing with my Icons.  Currently I create new ImageIcons when I need them, which I guess is wastefull if I need to use the same icon twice.  

Should I create a class called "Graphics" which is something like this:

public abstract class Graphics {

  public static ImageIcon PREVIOUS_ICON;
  public static ImageIcon NEXT_ICON;
  public static ImageIcon RIGHT_ARROW_ICON;
  public static ImageIcon LEFT_ARROW_ICON;
  public static ImageIcon NEW_ICON;
  public static ImageIcon EDIT_ICON;
  public static ImageIcon DELETE_ICON;

  static
  {
    PREVIOUS_ICON = new ImageIcon(Application.IMAGES+"Rewind24.gif");
    NEXT_ICON = new ImageIcon(Application.IMAGES+"FastForward24.gif");
    RIGHT_ARROW_ICON = new ImageIcon(Application.IMAGES+"Forward24.gif");
    LEFT_ARROW_ICON = new ImageIcon(Application.IMAGES + "Back24.gif");
    NEW_ICON = new ImageIcon(Application.IMAGES + "New24.gif");
    EDIT_ICON = new ImageIcon(Application.IMAGES + "Edit24.gif");
    DELETE_ICON = new ImageIcon(Application.IMAGES + "Delete24.gif");
  }

  public Graphics() {
  }  
}
0
 
zzynxSoftware engineerCommented:
That's the way to go indeed!
0
 
zzynxSoftware engineerCommented:
I would call that class MyIcons or something like that.
Graphics sounds so "usual" ;°)
0
 
zzynxSoftware engineerCommented:
>> Currently I create new ImageIcons when I need them, which I guess is wastefull if I need to use the same icon twice.
Indeed, that way you create a new object each time
0
 
girionisCommented:
>Yes that certainly seems easiest.  I have heard people say static blocks are bad practice though?  Is there anything I
>need to watch out for?

I would actually leave it as it is. Static initialization blocks should be used in special cases. I'd keep the initialize() method as it is. Your users should not forget to call it and you should indicate it in java doc. If it were the case (users would forget) then each class should have had an initialization block, which is not the case.
0
 
zzynxSoftware engineerCommented:
>> Static initialization blocks should be used in special cases
1) Why?
2) Define "special cases".
    Like these? ;°)
0
 
girionisCommented:
1) Bacause they are not needed everywhere.
2) Like deffering the instantiation of the fields when they are actually needed.

If static initialization was to be used for everything then all classes should have been using them, which is not the case.


0
 
zzynxSoftware engineerCommented:
>> 1) Bacause they are not needed everywhere.
imo, in these two cases they are very useful (not to say needed)

>>2) Like deffering the instantiation of the fields when they are actually needed
Indeed, like in these cases
0
 
zzynxSoftware engineerCommented:
Now, to be clear: are you trying to tell agrees, (s)he shouldn't use the static initialization block in these cases?
If you do can you explain why?
0
 
girionisCommented:
>>2) Like deffering the instantiation of the fields when they are actually needed
>Indeed, like in these cases

This proves exactly my point. With a static initializer you instantiate them when the class is loaded. You might not use them at all in some cases and so they occupy memory that could be free. With the asker's original approach you only instantiate and use them when you actually need them.

>Now, to be clear: are you trying to tell agrees, (s)he shouldn't use the static initialization block in these cases?

This is a matter of choice and design. I already stated what *I* would do. What the asker will do is up to the project's requirement. My opinion is that there is no need for a static initializer.

>If you do can you explain why?

See above answer.

Maybe you can comment on why is not a good idea to use lazy instantiation.
0
 
agreesAuthor Commented:
> With the asker's original approach you only instantiate and use them when you actually need them.

OK, but if sound is not needed in the project wouldn't you remove the "Sounds" class anyway - and therefore save the memory that way?

One thing I would say is that some of these *individual* sounds might never even be used if the user doesn't go to certain pages of the GUI.  So maybe it would be more efficient to only allocate memory for them the first time they are used, then use a reference from then on?
0
 
agreesAuthor Commented:
Another problem i've found with all these designs is that it means I can't repeat the same sound twice in quick succession. for example:

for (int i=0; i<10; i++) {
  Sounds.BEEP.play();
}

doesn't work, it only plays it once.  But this does work:

AudioClip BEEP= null;
for (int i=0; i<10; i++) {
  try {
    BEEP= Applet.newAudioClip(BEEPURL);
    BEEP.play();
  }
  catch (MalformedURLException ex) {
  }
}

any clever way round this or am I stuck having my application handling sounds in two different ways?

0
 
zzynxSoftware engineerCommented:
>> .... doesn't work, it only plays it once.
That's strange! The doc says:
play()
Starts playing this audio clip. Each time this method is called, the clip is restarted from the beginning.

>> So maybe it would be more efficient to only allocate memory for them the first time they are used, then use a reference from then on?
That's indeed the real lazy instantiation.
0
 
girionisCommented:
>OK, but if sound is not needed in the project wouldn't you remove the "Sounds" class anyway - and therefore save the
>memory that way?

Yes if you do not need it at all there is no need to have the Sound class in your application.

> One thing I would say is that some of these *individual* sounds might never even be used if the user doesn't go to
>certain pages of the GUI.  So maybe it would be more efficient to only allocate memory for them the first time they are
>used, then use a reference from then on?

You could do that too. It depends on how many individual sounds you have in your class. You might as well do something like:

public class Sounds {
  public Sounds() {
  }

  public static AudioClip BEEP;
  public static AudioClip CLICK;
  public static AudioClip ERROR;

  public void initializeBeep()
 {

      BEEP = Applet.newAudioClip(
          new URL("file: BEEPfilename"));
 }
 ...
...
  }

>Another problem i've found with all these designs is that it means I can't repeat the same sound twice in quick
>succession. for example:
>
>for (int i=0; i<10; i++) {
>  Sounds.BEEP.play();
>}

Try:

for (int i=0; i<10; i++) {
  Sounds.BEEP.play();
  Thread.sleep(200);  // sleep for 200 ms
}
0
 
zzynxSoftware engineerCommented:
Instead of having to call initializeBeep() - another one to remember -
wouldn't it be better to have that auto-initialized?

public class Sounds {
  public Sounds() {
  }

  public static AudioClip BEEP;
  public static AudioClip CLICK;
  public static AudioClip ERROR;

  public static AudioClip getBeep() {
      if (BEEP==null) {
         try {
           BEEP = Applet.newAudioClip(new URL("file: BEEPfilename"));
         } catch (...) { }
      }
      return BEEP;
 }
 ...
 ...
}
0
 
zzynxSoftware engineerCommented:
And with the following you can just write

   AudioClip a = Sounds.getInstance().getBeep();
or
   Sounds.getInstance().getBeep().play();

without forgetting anything:

public class Sounds {

   private static AudioClip BEEP;
   private static AudioClip CLICK;
   private static AudioClip ERROR;
   private static Sounds theInstance;

   public Sounds() {  }

   public static Sounds getInstance() {
      if (theInstance==null)
        theInstance = new Sounds();
      return theInstance;
   }

   public AudioClip getBeep() {
      if (BEEP==null) {
         try {
           BEEP = Applet.newAudioClip(new URL("file: BEEPfilename"));
         } catch (MalformedURLException ex) { }
      }
      return BEEP;
   }
     
   ...
 }
0
 
agreesAuthor Commented:
OK you've lost me on that last post :)  Why not just have Sounds as abstract and getBeep() as static?  

So you can just call

Sounds.getBeep().play();
0
 
agreesAuthor Commented:
>> Thread.sleep(200);  // sleep for 200 ms

Doh, yes sorry I was being dumb :)  It does play it twice, just plays the second before the first has finished.
0
 
girionisCommented:
> Doh, yes sorry I was being dumb :)  It does play it twice, just plays the second before the first has finished.

Increment the delay. It needs some time to finish playing and if you do not give it to it then it might crash. It's like you reading out loud a verse and before you finish reading you are requested to read it again from the beginning while you are expected to also finish it.
0
 
agreesAuthor Commented:
> Increment the delay. It needs some time to finish playing and if you do not give it to it then it might crash. It's like you reading out loud a verse and before you finish reading you are requested to read it again from the beginning while you are expected to also finish it.

Presumably it's best to play sounds in their own thread then?  Because otherwise you're going to be holding up your program?

Thanks for your help so far, I'm just waiting for some word on why zzynx suggested using Sounds.getInstance() and then I'll close this question :)
0
 
zzynxSoftware engineerCommented:
>> why zzynx suggested using Sounds.getInstance()
To avoid the obligation to (not to forget to) do

      Sounds s = new Sounds();

to initialize your AudioClips BEEP, CLICK and ERROR.

But girionis remark on that is true. That extra getInstance() isn't really needed.
It's better Sounds having a static getBeepSound(), getClickSound(); and getErrorSound();
0
 
girionisCommented:
> Presumably it's best to play sounds in their own thread then?
>  Because otherwise you're going to be holding up your program?

It depends how big the sound files are. For single beep sounds that shouldn't be a problem but for larger files yes, it is preferable to have a separate thread to play them :)

0
 
agreesAuthor Commented:
ok thanks for the help!  

I'll split the points evenly, but zzynx loses 5 points for criticising my boring name "Graphics" class ;)  

But zzynx was fastest on the buzzer for the 20 bonus points question, so that makes zzynx this weeks winner!
0
 
zzynxSoftware engineerCommented:
;°)

>> I'll split the points evenly
You didn't. Didn't he deserve some for assisting?
0
 
agreesAuthor Commented:
Oh bugger I screwed it up after all that!  The assisted 60 points was supposed to go to girionis!   That's what comes from trying to do too many things at once :)

Sorry girionis I'll give you the points in another question next time I get the chance :/
0
 
zzynxSoftware engineerCommented:
>> Sorry girionis I'll give you the points in another question next time I get the chance :/
You can always ask to reopen this one and then accept again
0
 
agreesAuthor Commented:
Ok that's that sorted :)  I'm a bit disturbed by the amount of code repetition this design requires though, so I've raised a new question to see if anyone can help:

http://www.experts-exchange.com/Programming/Programming_Languages/Java/Q_21143997.html
0
 
girionisCommented:
Thank both of you guys, agrees for accepting, zzynx for being fair :)
0
 
zzynxSoftware engineerCommented:
My pleasure, girionis. I like to be treated fair myself, so...
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 18
  • 12
  • 10
Tackle projects and never again get stuck behind a technical roadblock.
Join Now