0

When I am playing the audio on my Java desktop application, the sound begins to crackle and fuzz out. I don't know why, any suggestions? I am working on a Pokemon fan game.

static AudioInputStream audio = null;
public static boolean change = false;
static Clip clip = null;

public static void music() {
    try {
        change = false;
         
        if(!Main.choosegame) {
            if(!Main.startup) {
                if(Movement.POKEMONBATTLE) {
                    audio = AudioSystem.getAudioInputStream(new File("Res/music/pokemon battle.wav"));
                } else {
                    audio = AudioSystem.getAudioInputStream(new File("Res/music/route.wav"));
                }
            } else {
                audio = AudioSystem.getAudioInputStream(new File("Res/music/Oak's Speech.wav"));
            }
        } else {
            audio = AudioSystem.getAudioInputStream(new File("Res/music/Title Screen.wav"));
        }
        clip = AudioSystem.getClip();   
        clip.open(audio);
        clip.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while(clip.isActive() && Main.Running && !change){
            
        }
        clip.stop();
        
        audio.close();
        Thread.sleep(100);
    } catch(UnsupportedAudioFileException uae) {
        System.out.println(uae);
    } catch(IOException ioe) {
        System.out.println(ioe);
    } catch(LineUnavailableException lua) {
        System.out.println(lua);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch(OutOfMemoryError e12) {
        clip.stop();
        change = true;
        try {
            audio.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        System.out.println("OUT OF MEMORY IN MUSIC");
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
@Override                                                                                                    
public void run() {
    while(Main.Running) {
        music();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
  • Please indent your code properly. I'd also consider a different mechanism than deeply-nested `if`s and redundant code, e.g., the only thing that's changing is the filename. – Dave Newton Jan 03 '16 at 18:24
  • This could help : http://stackoverflow.com/a/9630897/2223027 – pyb Jan 03 '16 at 18:26
  • 2
    Please consider making a MVE http://stackoverflow.com/help/mcve –  Jan 03 '16 at 18:37

2 Answers2

1

Curious stuff. Given that you have found a solution, maybe I shouldn't be adding my two cents. But a few things seem puzzling and not quite matching the audio world as I know it.

Usually crackle and distortion are the result of PCM data points exceeding their bounds. For example, if you have wav files with data that ranges from -32768 to 32767 (16-bit encoding represented via signed shorts), and the values go outside of that range, then distortion of various sorts can occur.

This might occur in your case if more than one wav file is played at a time, and the wavs are already at a very high volume. When their data is summed together for simultaneous playback, the 16-bit range could be exceeded.

If the addition of pauses has the main effect of preventing the wavs from playing at the same time, this could thus also lessen the amount of distortion.

There are some situations where it takes an audio thread a bit of time to finish and respond to a state change. But I can't think of any where crackle or fuzz would be the result. (But that doesn't mean there are no such situations.)

Simply bypassing a number of samples, via skip(), should (theoretically) only help if the same crackle and fuzz are on the original wav files, and you are skipping past the distorted section. However this should result in a click if starting from an already audible volume level.

By the way, you would probably do better to run the files as SourceDataLines than as Clips. Clips are only meant for situations where you are going to replay the sounds many times and can afford to hold the data in memory. As coded, every time you play a sound, you are first loading the entire sound into memory, and then playing it. A Clip does not play until all the data has been loaded into memory. With a SourceDataLine, the playback code reads data as it plays, consuming much less memory.

If you can afford the memory, load the Clip only once into its own variable. After playing a Clip, one can set its cursor back to the start of the Clip and later replay the data without having to reload from the file (as you are continually doing).

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
-2

Is the crackling always at the beginning? If so, I found some code that skips the first bytes to avoid that:

// Skip some bytes at the beginning to prevent crackling noise.
audio.skip(30);

Source: http://veritas.eecs.berkeley.edu/apcsa-ret/program/projects/lesson13/Sound/SampleRateConverter.java

pyb
  • 4,813
  • 2
  • 27
  • 45
  • The only reason this concerns me is that you're using a magic number to determine how many bytes to skip. It's not guaranteed that this will always work for *all* media types, and there are no tests at your source to verify that this technique is applicable. I won't deny that it may work, but just saying "skip 30 bytes" without anything to really back it up is a dangerous precedent. – Makoto Jan 03 '16 at 19:02
  • 1
    `30` is just an example, if you call `skip()` without argument it will not compile. I don't have access to the files that cause the issue, so obviously there is no guarantee that `30` is the right number. However, OP is designing a video game, not a media player so (s)he has control of the files (s)he wants to play. Finally, this solution has been effective in the past as my source suggests. – pyb Jan 03 '16 at 19:10
  • *"`30` is just an example.."* ..what magic number were you thinking of using in production? A random number? Agree with @Makoto that this is a 'dangerous' approach. – Andrew Thompson Jan 04 '16 at 05:41
  • @AndrewThompson: OP seems to be coding his/her own video game, it's possible that all audio files have been recorded with the same audio source and that they all have the same issue. As I said, I don't have access to the crackling audio files so your mileage may vary. I don't get why this gets downvoted more than the question itself when it's the only available answer and it's been used in the past. If you think the question is of low quality because you cannot answer it with a bullet proof solution, go ahead and downvote it as well. Please be consistent. – pyb Jan 04 '16 at 14:59