Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
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  
  How do I handle sound?  (Read 4793 times)
0 Members and 1 Guest are viewing this topic.
Offline Regenuluz
« Posted 2012-10-05 08:49:26 »

Right,

So I want to learn how to make a simple sound engine in Java. Any one got any good links for sites that holds a good tutorial for learning it?

I know there's tons of libraries out there for doing it, like paulscode that's posted in this forum, but I really want to learn how to do it myself, I just want something that can play sound effects and continuous music.

Cheers! Smiley
Online Phased
« Reply #1 - Posted 2012-10-05 08:52:42 »

Using Java's inbuilt audio clips:
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  
import java.applet.Applet;
import java.applet.AudioClip;

public class Sound {
   private AudioClip clip;
   public Sound(String name){
      try
      {
         clip = Applet.newAudioClip(Game.class.getResource(name));
      }catch (Throwable e){
         e.printStackTrace();
      }
   }
   public void play(){
      try{
         new Thread(){
            public void run(){
               clip.play();
            }
         }.start();
      }catch(Throwable e){
         e.printStackTrace();
      }
   }
}


to set a sound you can go
1  
Sound mySoundFile = new Sound("sound/music.wav");

then
1  
mySoundFile.play();
Offline philfrei
« Reply #2 - Posted 2012-10-05 19:05:27 »

I was perhaps where you were about two years ago.

I don't know that this is what I'd call a "good" site for learning sound in Java. I've had to read through it many times.

http://docs.oracle.com/javase/tutorial/sound/TOC.html

It needs more concrete examples, earlier in the tutorial, imho. (There are some in the section on working with various format conversions, about five sections in.) In any event, I think that is a place to start and come back to repeatedly, and I'll be happy to answer questions that come up.

I never really got into the Applet AudioClip--it seemed to be a bit too limited for the sorts of things I want to do. With javax.sound.sampled, I've been able to build a couple little audio systems, e.g., http://www.hexara.com/VSL/JTheremin.htm & http://www.hexara.com/VSL/AudioMixerDemoWarOfWorlds.htm

I've occasionally found useful info here: http://jsresources.org/
I'm guessing you already know about them.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Regenuluz
« Reply #3 - Posted 2012-10-06 13:17:04 »

Hm, thanks guys! Smiley

I'll have to look into it more. I'll come back to ask what I did wrong when I manage to do something that sets my comp on fire. xD
Offline LunaticEdit

Senior Member


Medals: 8
Projects: 1



« Reply #4 - Posted 2012-12-26 23:52:14 »

Please be VERY careful playing sound in java. A lot of examples around the interwebs involving play() look good in THEORY, but I've found that they start generating a lot of hanging threads stuck in "ready" state for no particularly good reason. Assuming that you'd like to play WAV sound effects, In my game I created the following function:

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  
    private void playSfx(final InputStream fileStream) {
        ActivityManager.getInstance().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    BufferedInputStream bufferedStream = new BufferedInputStream(fileStream);
                    AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(bufferedStream);

                    final int BUFFER_SIZE = 128000;
                    SourceDataLine sourceLine = null;

                    AudioFormat audioFormat = audioInputStream.getFormat();
                    DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);

                    sourceLine = (SourceDataLine) AudioSystem.getLine(info);
                    sourceLine.open(audioFormat);

                    if (sourceLine == null) {
                        return;
                    }

                    sourceLine.start();
                    int nBytesRead = 0;
                    byte[] abData = new byte[BUFFER_SIZE];
                    while (nBytesRead != -1) {
                        try {
                            nBytesRead = bufferedStream.read(abData, 0, abData.length);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        if (nBytesRead >= 0) {
                            sourceLine.write(abData, 0, nBytesRead);
                        }
                    }

                    sourceLine.drain();
                    sourceLine.close();
                    bufferedStream.close();
                    audioInputStream.close();

                } catch (IOException e) {
                    e.printStackTrace();
                } catch (UnsupportedAudioFileException e) {
                    e.printStackTrace();
                } catch (LineUnavailableException e) {
                    e.printStackTrace();
                    System.exit(1);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        });
    }


In my case I use a custom class called AcitivityManager to deal with threads (as the play function will otherwise lock until the sound is done). The code for it is below:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
public final class ActivityManager {
    private static ActivityManager _activityManager = null;

    private final ExecutorService _executorService;

    public static ActivityManager getInstance() {
        if (_activityManager == null) {
            _activityManager = new ActivityManager();
        }
        return _activityManager;
    }

    private ActivityManager() {
        _executorService = Executors.newCachedThreadPool();
    }

    public void submit(final Runnable task) {
        _executorService.submit(task);
    }
}


This is a bit lower level, but the high level classes seem to have thread issues in some OSs, whereas this logic appears to be stable and run fine in all environments. Basically all I'm doing here is manually spoon-feeding audio data to the audio device. Works well playing multiple sounds in rapid succession with no issues.

Below is an example of how I call my sound logic:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
    public static void playSound(final SoundEffect soundEffect) {
        switch (soundEffect) {
            case BoxHit:
                getInstance().playSfx(getInstance().getClass().getResourceAsStream("boxhit.wav"));
                break;
            case CannonShot:
                getInstance().playSfx(getInstance().getClass().getResourceAsStream("cannonshot.wav"));
                break;
            case Coin:
                getInstance().playSfx(getInstance().getClass().getResourceAsStream("coin.wav"));
                break;
            case Jump:
                getInstance().playSfx(getInstance().getClass().getResourceAsStream("jump.wav"));
                break;
        }
    }


I've tried many different ways and this seems to be the only workable java-only solution that was stable.

Offline 65K
« Reply #5 - Posted 2012-12-27 09:36:48 »

This null check is a little late:
1  
2  
3  
4  
5  
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
if (sourceLine == null) {
   return;
}

Resources should rather be closed in a finally block.
playSfx would be more flexible to use if it was just a Runnable and leaving the concrete thread handling to the caller.
I would the inner while loop break after the first read failure.

Offline SHC
« Reply #6 - Posted 2012-12-27 09:45:19 »

See my implementation here.

Offline 65K
« Reply #7 - Posted 2012-12-27 10:30:58 »

See my implementation here.
Please do yourself a favor and add exception handling. Exceptions are thrown for a reason. Wink

Offline SHC
« Reply #8 - Posted 2012-12-27 10:39:08 »

See my implementation here.
Please do yourself a favor and add exception handling. Exceptions are thrown for a reason. Wink
I'll add that when my exams are completed. (Daily Tests till MAY). Also see my article here

Offline nsigma
« Reply #9 - Posted 2012-12-27 17:08:40 »

Using a Thread and a SourceDataLine per sound is terrible advice, unresponsive and liable to fail on some systems.  Check out a software mixing library such as TinySound instead.

Using the same Thread to read from disk as write to the audio line is also not a great idea, and liable to cause problems.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline philfrei
« Reply #10 - Posted 2012-12-27 21:06:41 »

Have you tested this with Java 7?

I'd expect to get Mark/Reset errors when dealing with InputStreams. Java7 is much more rigorous about making sure InputStreams are markable & resetable than Java 6 was, and more than a few audio programs broke as a result of the upgrade. wav files generally aren't markable/resetable.

Thus, I'd consider passing in URL's rather than InputStreams, and creating the AudioInputStream directly from the URL rather than the InputStream.

It's beyond my experience to know whether anything is gained by the way you handle the threads. It seems interesting, but I don't understand what you are trying to fix. I've never had problems with lingering audio threads. Other problems, but not that!

Does TinySound do mixing down to a single SDL? I didn't know I was duplicating his wheel. I've also started using a simple mixing algorithm, consolidating down to a single SourceDataLine. It's posted on a neighbor thread with source code.

@nsigma -- One fellow at StackOverflow was suggesting it's better to let the sound mixing occur in hardware, rather than do it up front (as I do). In that case, running multiple SourceDataLines would probably be part of the process. Of course, we've run into systems that only allow one output at a time, so I don't know what this fellow is thinking...maybe thinking in terms of some ideal, or future with sound cards that provide this service. (He also thinks mixing *requires* more complicated math than summation, e.g., an equation such as A + B - AB (where A & B are two volumes between 0 and 1). I'm thinking efforts like this may have their place but aren't strictly necessary.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline LunaticEdit

Senior Member


Medals: 8
Projects: 1



« Reply #11 - Posted 2012-12-27 23:56:33 »

I haven't ran into anyone having issues with my implementation yet.; I use java 7 yes. The thread hangs any other way I do it -- whatever the reason. And yes, that null check is 1 line too late; I have no idea how it got there :p

Offline nsigma
« Reply #12 - Posted 2012-12-28 19:44:09 »

Does TinySound do mixing down to a single SDL? I didn't know I was duplicating his wheel. I've also started using a simple mixing algorithm, consolidating down to a single SourceDataLine. It's posted on a neighbor thread with source code.

AFAIK that's what it does - I still haven't actually tried it out  persecutioncomplex  I assumed you realised that, as software mixing is mentioned a number of times in the TinySound thread, and you have posted in it ..  Wink

@nsigma -- One fellow at StackOverflow was suggesting it's better to let the sound mixing occur in hardware, rather than do it up front (as I do). In that case, running multiple SourceDataLines would probably be part of the process. Of course, we've run into systems that only allow one output at a time, so I don't know what this fellow is thinking...maybe thinking in terms of some ideal, or future with sound cards that provide this service.

Then one fellow at StackOverflow is a muppet!  Smiley  Few cards support hardware mixing, and it's an older feature not a future one.  That's why every OS now has a sound server that does mixing in software.  If you have a system that supports multiple SDL's then it's almost certainly mixing in software, just outside Java.  This is an inefficient way of outputting multiple sounds from a single application - it's primarily designed for allowing multiple applications to output audio at the same time.

(He also thinks mixing *requires* more complicated math than summation, e.g., an equation such as A + B - AB (where A & B are two volumes between 0 and 1). I'm thinking efforts like this may have their place but aren't strictly necessary.

The guy seems to be proving he's an idiot.  Roll Eyes  Be interesting to see the link exactly - found that equation linked to in an article that talks about combining sounds without clipping.  It presumably acts like a limiter to stop the sound peaking, but it must cause some distortion at higher levels.  A better approach is something like the automatic gain control used in JASS (http://www.cs.ubc.ca/~kvdoel/jass/) that tracks the highest output and reduces all values (not a sample at a time) to keep within range.  I adapted that in some old code using JASS so that the maximum value reduced slightly over time (a few seconds) so that a short peak wouldn't cause everything to become quiet permanently - closer to the behaviour of a proper limiter.  It's a better approach to avoiding clipping.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline philfrei
« Reply #13 - Posted 2012-12-28 21:22:54 »

Does TinySound do mixing down to a single SDL? I didn't know I was duplicating his wheel. I've also started using a simple mixing algorithm, consolidating down to a single SourceDataLine. It's posted on a neighbor thread with source code.

AFAIK that's what it does - I still haven't actually tried it out  persecutioncomplex  I assumed you realised that, as software mixing is mentioned a number of times in the TinySound thread, and you have posted in it ..  Wink

I assumed that the TinySound library was creating wrappers, using multiple output lines. PaulsCode does the same, doesn't it? Why else did he start out on a separate project to make a mixer (yet uncompleted afaik)?

In any event, I really do need to find the time to look at the code behind TinySound, and set it up an run it.

***********

Thanks for the explanations about hardware/software mixing stages.

Here's the link to the StackOverflow question:
http://stackoverflow.com/questions/14007885/reliable-sound-api-in-java-for-simple-digital-samples-playback/14009624#comment19414936_14009624

You probably have some good advice and recommendations for the fellow's main question (the system you wrote or coauthored, I'm thinking).

This article was cited as a way to prevent peak overflow.
http://www.vttoth.com/CMS/index.php/technical-notes/68
It seems dubious to me, especially with the exponential growth in the number of calculations required with multiple lines.


"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #14 - Posted 2012-12-28 21:26:18 »

I'd just forget all that crap and figure out OpenAL using LWJGL or JogAmp.

(See also discussions on Java2D vs OpenGL)

Cas Smiley

Offline nsigma
« Reply #15 - Posted 2012-12-29 13:46:40 »

I assumed that the TinySound library was creating wrappers, using multiple output lines. PaulsCode does the same, doesn't it? Why else did he start out on a separate project to make a mixer (yet uncompleted afaik)?

TinySound and PaulsCode have a completely different architecture. 

Here's the link to the StackOverflow question:
...
You probably have some good advice and recommendations for the fellow's main question (the system you wrote or coauthored, I'm thinking).

The guy's quite amusing - suggesting using FFT to mix audio.  Shocked  And the idea that Java isn't fast enough to mix a few sounds together is hilarious.  I've been using Java for DSP for almost 10 years now.  People have written entire sequencers and softsynths in pure Java - http://youtu.be/9sYGcziGtHI

I'd just forget all that crap and figure out OpenAL using LWJGL or JogAmp.

(See also discussions on Java2D vs OpenGL)

Not really a correct comparison, though.  OpenGL is direct access to a hardware accelerated (and programmable) graphics pipeline.  OpenAL is a fairly limited API, and presumably in most cases running on top of the platform's primary audio system?  The low-level bits of JavaSound also give direct access to the native audio system, so it's possible to achieve far more scope and flexibility using it (or alternative bindings like PortAudio) and programming audio code in Java itself.  Most people on here should take the advice to use a library, be it OpenAL, TinySound, etc.  It really depends what features you require now and in the future, but I'd tend to prefer things written in Java as it's easier (possible) to get in and fiddle with the code if you ever need to.  Just ignore Clip and all the code posted above!  Wink



Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline philfrei
« Reply #16 - Posted 2012-12-30 06:45:27 »

I totally forgot about this thread (which I posted on, too Clueless ):
http://www.java-gaming.org/topics/selecting-non-default-mixer/26342/view.html
Probably had something to do with barely understanding the discussion at the time. I'm doing a little better now.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline Regenuluz
« Reply #17 - Posted 2012-12-30 12:24:33 »

Heh, and here I thought that this thread was dead. Tongue

And seems like there's almost as much dispute over how to handle sound as to j2d vs opengl. Though I'm slowly coming to terms with a thought that keeps creeping up in my mind... "Just use LWJGL/LibGDX/OpenAL and be done with it!".... Tongue
Offline davedes
« Reply #18 - Posted 2012-12-30 18:04:11 »

Quote
PaulsCode does the same, doesn't it? Why else did he start out on a separate project to make a mixer (yet uncompleted afaik)?
PaulsCode does not include a software mixer last I checked. Instead, it's just an abstraction of different sound libraries -- LWJGL, JOGL and Java2D. TinySound, on the other hand, mixes all channels in software into a single JavaSound clip (if I remember correctly).

Regarding Paul's 3D sound library -- IMO it's not the best.

OpenAL just sounds different than Java2D. This is obvious when you run the same audio file through the two different libraries. Java2D has crackles, pops, and glitches -- especially when stopping a cilp -- and often leads to slightly different volumes. So you might have fine-tuned your game to the LWJGL backend, but then testing it with the Java2D backend everything might sound a little off. And then you begin to question why you have a Java2D backend in the first place...

The reason Paul went lengths to abstract sound is for "maximum compatibility" -- but realistically if your user doesn't support OpenAL, they probably won't be able to run your game!

So why bother with the Java2D backend at all? Then you are left with only two: JOGL or LWJGL. Obviously if your game is based on LWJGL, it makes no sense to use a JOGL backend, and vice versa. So really you just have a huge, clunky, multi-threaded and IMHO poorly designed API that wraps LWJGL.

With that said, Paul has written some fantastic decoders that are not very dependent on the rest of the library. Smiley

Quote
"Just use LWJGL/LibGDX/OpenAL and be done with it!"...
For a beginner, it's easier to just use a wrapper: TinySound, Pauls Sound System, LibGDX, or even SlickUtil if you must.

Offline Regenuluz
« Reply #19 - Posted 2012-12-30 20:48:01 »

Arh, but I want to use OpenGL for my game, so I might as well use the stuff that libraries like LJWGL offers. Smiley (I started making my game in pure java2d, but it started dropping frames when placing more than 100 towers xD)
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Riven (14 views)
2014-07-29 18:09:19

Riven (10 views)
2014-07-29 18:08:52

Dwinin (10 views)
2014-07-29 10:59:34

E.R. Fleming (28 views)
2014-07-29 03:07:13

E.R. Fleming (10 views)
2014-07-29 03:06:25

pw (40 views)
2014-07-24 01:59:36

Riven (39 views)
2014-07-23 21:16:32

Riven (27 views)
2014-07-23 21:07:15

Riven (28 views)
2014-07-23 20:56:16

ctomni231 (59 views)
2014-07-18 06:55:21
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
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!