Solved

Best way to add sounds to an application

Posted on 2004-09-23
41
194 Views
Last Modified: 2010-03-31
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
Comment
Question by:agrees
  • 18
  • 12
  • 10
41 Comments
 
LVL 35

Expert Comment

by:girionis
ID: 12132839
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
 
LVL 35

Expert Comment

by:girionis
ID: 12132846
... or since the methods are already static you might want to leave it as it is.
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12132926
>> 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
 
LVL 35

Expert Comment

by:girionis
ID: 12132994
> The static initialization is called

It's not a statci initialization. This is:

static
{
 ...
 ...
}
0
 
LVL 35

Expert Comment

by:girionis
ID: 12133010
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12133019
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12133048
>> You could also do that

Is the constructor called when writing

            Sounds.BEEP.play();

?
I think that will lead to a NPE
0
 
LVL 35

Expert Comment

by:girionis
ID: 12133124
> >> 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
 
LVL 37

Expert Comment

by:zzynx
ID: 12133164
>> 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
 

Author Comment

by:agrees
ID: 12133230
> 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
 
LVL 37

Expert Comment

by:zzynx
ID: 12133319
>> Is there anything I need to watch out for?
not aware of any pitfalls
0
 

Author Comment

by:agrees
ID: 12133396
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12133461
That's the way to go indeed!
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12133482
I would call that class MyIcons or something like that.
Graphics sounds so "usual" ;°)
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12133542
>> 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
 
LVL 35

Expert Comment

by:girionis
ID: 12133973
>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
 
LVL 37

Expert Comment

by:zzynx
ID: 12134050
>> Static initialization blocks should be used in special cases
1) Why?
2) Define "special cases".
    Like these? ;°)
0
 
LVL 35

Expert Comment

by:girionis
ID: 12134337
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12134374
>> 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
 
LVL 37

Expert Comment

by:zzynx
ID: 12134421
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 35

Expert Comment

by:girionis
ID: 12135427
>>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
 

Author Comment

by:agrees
ID: 12135903
> 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
 

Author Comment

by:agrees
ID: 12136671
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12137314
>> .... 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
 
LVL 35

Assisted Solution

by:girionis
girionis earned 65 total points
ID: 12137422
>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
 
LVL 37

Expert Comment

by:zzynx
ID: 12137706
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12137879
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
 

Author Comment

by:agrees
ID: 12138336
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
 

Author Comment

by:agrees
ID: 12138355
>> 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
 
LVL 35

Expert Comment

by:girionis
ID: 12140502
> 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
 

Author Comment

by:agrees
ID: 12141680
> 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
 
LVL 37

Accepted Solution

by:
zzynx earned 80 total points
ID: 12141769
>> 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
 
LVL 35

Expert Comment

by:girionis
ID: 12141818
> 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
 

Author Comment

by:agrees
ID: 12142365
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12142504
;°)

>> I'll split the points evenly
You didn't. Didn't he deserve some for assisting?
0
 

Author Comment

by:agrees
ID: 12142846
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
 
LVL 37

Expert Comment

by:zzynx
ID: 12143072
>> 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
 

Author Comment

by:agrees
ID: 12144688
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
 
LVL 35

Expert Comment

by:girionis
ID: 12158900
Thank both of you guys, agrees for accepting, zzynx for being fair :)
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12158956
My pleasure, girionis. I like to be treated fair myself, so...
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

For customizing the look of your lightweight component and making it look opaque like it was made of plastic.  This tip assumes your component to be of rectangular shape and completely opaque.   (CODE)
Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
Viewers learn about the “while” loop and how to utilize it correctly in Java. Additionally, viewers begin exploring how to include conditional statements within a while loop and avoid an endless loop. Define While Loop: Basic Example: Explanatio…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now