Java音频在定制的Sound类中不断发展

时间:2017-04-29 01:12:23

标签: java multithreading audio

为了保持简洁,我使用Java的自定义Sound类,但是我使用它的方式,出于某种原因,为某些声音产生了很多噼啪声。如果上传音频可能会有所帮助,请告知我们。

这是我正在使用的Sound类的代码:

package brad.classes;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;

import sun.audio.AudioData;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
import sun.audio.ContinuousAudioDataStream;

/*
 * Custom class for playing audio (audio file must be in src)
 */
public class Sound {
    private ContinuousAudioDataStream loop = null; //Puts music data into loop
    private InputStream in = null; //Takes in music file as input
    private AudioStream audioStreamMusic = null; //Takes in InputStream of music file as input
    private AudioData audioData = null; //Changes AudioStream to data
    private boolean loopable; //Whether the music input is meant to be looped or not
    private String music; //The name of the music file
    private double length; //The duration of the audio snippet in seconds
    private static boolean isStopped = false;

    /*
     * Takes in music file name and whether or not the file is loopable
     */
    public Sound(String music, boolean loopable) throws IOException, UnsupportedAudioFileException {
        if(music.length() < 4 || !music.substring(music.length() - 4, music.length()).equals(".wav"))
            throw new IOException(music + " (Given file must be .wav)");
        else if(new File(music).length() > 1000000)
            throw new IOException(music + " (Given file must not be over 1 megabyte)");
        this.music = System.getProperty("user.dir") + "/" + music;
        this.loopable = loopable;
        in = new FileInputStream(music);
        audioStreamMusic = new AudioStream(in);
        if(loopable) {
            audioData = audioStreamMusic.getData();
            loop = new ContinuousAudioDataStream(audioData);
        }
        AudioInputStream stream = AudioSystem.getAudioInputStream(new File(music));
        AudioFormat format = stream.getFormat();
        long frames = stream.getFrameLength();
        length = (double) frames/format.getFrameRate();
    }

    /*
     * Also takes in whether the file size limit should be ignored
     */
    public Sound(String music, boolean loopable, boolean override) throws IOException {
        if(music.length() < 4 || !music.substring(music.length() - 4, music.length()).equals(".wav"))
            throw new IOException(music + " (Given file must be .wav)");
        if(!override) {
            if(new File(music).length() > 1000000)
                throw new IOException(music + " (Given file must not be over 1 megabyte)");
        }
        this.music = System.getProperty("user.dir") + "/" + music;
        this.loopable = loopable;
        in = new FileInputStream(music);
        audioStreamMusic = new AudioStream(in);
        if(loopable) {
            audioData = audioStreamMusic.getData();
            loop = new ContinuousAudioDataStream(audioData);
        }
    }

    /*
     * Plays audio file
     */
    public void play() {
        if(loopable)
            AudioPlayer.player.start(loop);
        else {
            try {
                in = new FileInputStream(music);
                audioStreamMusic = new AudioStream(in);
                AudioPlayer.player.start(audioStreamMusic);
            }
            catch(IOException error) {
                System.out.println(error);
            }
        }
    }

    /*
     * Stops audio file if playing
     */
    public void stop() {
        if(loopable)
            AudioPlayer.player.stop(loop);
        else
            AudioPlayer.player.stop(audioStreamMusic);
    }

    /*
     * Returns a string representation of the sound, including
     * the given name of the audio file as well as whether or
     * not it is loopable
     */
    @Override
    public String toString() {
        return String.format("Sound[music = %s, loopable = %b]", music, loopable);
    }

    public boolean equals(Sound other) {
        if(music.equals(other.music))
            return true;
        return false;
    }

    /*
     * Returns value of music
     */
    public String getMusic() {
        return music;
    }

    /*
     * Returns value of loopable
     */
    public boolean getLoopable() {
        return loopable;
    }

    /*
     * Returns value of length
     */
    public double getLength() {
        return length;
    }

    /*
     * Plays group of Sounds
     */
    public static Thread playGroup(Sound[] sounds, boolean loopable) throws InterruptedException {
        return playGroup(new ArrayList<Sound>(Arrays.asList(sounds)), loopable);
    }

    /*
     * Plays group of Sounds
     */
    public static Thread playGroup(ArrayList<Sound> sounds, boolean loopable) throws InterruptedException {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                do {
                    int i = 0;
                    try {
                        sounds.get(0).play();
                        Thread.sleep((long) (sounds.get(0).getLength() * 1000));
                        for(i = 1; i < sounds.size(); ++i) {
                            sounds.get(i).play();
                            sounds.get(i - 1).stop();
                            Thread.sleep((long) (sounds.get(i).getLength() * 1000));
                        }
                    }
                    catch(Exception e) {
                        sounds.get(i).stop();
                        break;
                    }
                } while(loopable && !isStopped);
            }
        };
        Thread t = new Thread(r);
        t.start();
        return t;
    }

    public static void stopGroup(Thread t) {
        while(t != null && !t.isInterrupted()) {
            t.interrupt();
            isStopped = true;
        }
    }
}

我删除了很多代码。所以,我希望这有点简洁,以获得基本的想法。

package defense;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import javax.imageio.ImageIO;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import brad.classes.Sound;

public class Runner extends JPanel implements ActionListener, KeyListener {
    private static final long serialVersionUID = 1L;

    static char dir = 'u';

    static int delay = 10;
    static int angle = 0;
    static int breakCount = 0;
    static int breakFrame = 0;
    static int count = 0;
    static int gifCount = 0;
    static int currentDirection = 0;
    static int gameOverCount = 0;
    static int gameOverFrame = 0;

    static boolean isHard = true;
    static boolean runsGif = false;
    static boolean heartDone = false;
    static boolean gameOverDone = false;
    static boolean firstEnd = true;
    static boolean secondEnd = true;

    protected Timer timer;

    BufferedImage gif;
    BufferedImage heart;
    BufferedImage heartBreak;
    BufferedImage gameOver;

    static Thread mainSound;

    Attack a1 = new Attack(new LinkedList<Arrow>(), 2);
    Player p = new Player();

    public Runner(String s) {
        JFrame frame = new JFrame(s);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Runner bp = new Runner();
        frame.add(bp);
        frame.addKeyListener(this);
        frame.setSize(600, 600);
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setSize(600, 600);
        frame.setLocation(dim.width/2 - frame.getSize().width/2, dim.height/2 - frame.getSize().height/2);
        frame.setResizable(false);
        frame.setVisible(true); 
    }

    public static void main(String args[]) throws IOException, UnsupportedAudioFileException, InterruptedException {
        @SuppressWarnings("unused")
        Runner a = new Runner("Game");
        ArrayList<Sound> mainTheme = new ArrayList<Sound>();
        int max;
        String base;
        if(isHard) {
            max = 16;
            base = "BATH";
        }
        else {
            max = 12;
            base = "SOJ";
        }
        for(int i = 1; i <= max; ++i) {
            mainTheme.add(new Sound("audio/" + base + i + ".wav", false));
        }
        mainSound = Sound.playGroup(mainTheme, true);
    }

    public Runner() {
        timer = new Timer(delay, this);
        timer.start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(p.getHealth() != 0) {
            drawBG(g);
            drawSqu(g);
            drawCircle(g);
            drawHeart(g);
            p.shield(g, dir);
            gif(g);
            try {
                a1.spawnArrows(g, p);
                p.drawHealth(g);
            }
            catch (FontFormatException | IOException e) {
                e.printStackTrace();
            }
        }
        else {
            drawBG(g);
            if(firstEnd) {
                Sound.stopGroup(mainSound);
                firstEnd = false;
            }
            if(!heartDone)
                breakHeart(g);
            else if(secondEnd){
                secondEnd = false;
                ArrayList<Sound> determination = new ArrayList<Sound>();
                try {
                    for(int i = 1; i <= 6; ++i) {
                        determination.add(new Sound("audio/DT" + i + ".wav", false));
                    }
                    Sound.playGroup(determination, true);
                }
                catch(Exception e) {
                    e.printStackTrace();
                }
            }
            else if(!gameOverDone){
                gameOver(g);
            }
        }
    }

    public boolean breakHeartException(int breakFrame) {
        int[] exceptions = {2, 6, 8, 12, 14, 18, 20, 22, 23};
        for(int exception : exceptions) {
            if(breakFrame == exception)
                return true;
        }
        return false;
    }

    public void makeBreakHeart(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        int width = heartBreak.getWidth();
        int height = heartBreak.getHeight();
        g2d.drawImage(heartBreak, getWidth() / 2 - (width / 2) + 11, getHeight() / 2 - height / 2 + 78, null);
        g2d.dispose();
    }

    public void breakHeart(Graphics g) {
        ++breakCount;
        boolean exception = breakHeartException(breakFrame);
        try {
            heartBreak = ImageIO.read(new File("images/gif/heartBreak" + breakFrame + ".png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(breakCount % 4 == 0 && breakCount != 0 && !exception) {
            ++breakFrame;
            if(breakFrame == 25) {
                try {
                    Sound split = new Sound("audio/split.wav", false);
                    split.play();
                } catch (IOException | UnsupportedAudioFileException e) {
                    e.printStackTrace();
                }
            }
            if(breakFrame == 48)
                heartDone = true;
            breakCount = 0;
        }
        else if(exception) {
            switch(breakFrame) {
                case 2:
                case 12:
                    if(breakCount % 24 == 0) {
                        ++breakFrame;
                        breakCount = 0;
                    }
                    break;
                case 14:
                    if(breakCount % 28 == 0) {
                        ++breakFrame;
                        breakCount = 0;
                    }
                    break;
                default:
                    if(breakCount % 8 == 0) {
                        ++breakFrame;
                        if(breakFrame == 9) {
                            try {
                                Sound broke = new Sound("audio/heartBreak.wav", false);
                                broke.play();
                            } catch (IOException | UnsupportedAudioFileException e) {
                                e.printStackTrace();
                            }
                        }
                        breakCount = 0;
                    }
            }
        }
        makeBreakHeart(g);
    }

    public void gameOver(Graphics g) {
        ++gameOverCount;
        try {
            gameOver = ImageIO.read(new File("images/gif/gameOver" + gameOverFrame + ".png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(gameOverCount % 4 == 0 && gameOverCount != 0) {
            ++gameOverFrame;
            switch(gameOverFrame) {
                case 68:
                case 70:
                case 73:
                case 75:
                case 76:
                case 78:
                case 80:
                case 81:
                case 85:
                case 86:
                case 88:
                case 93:
                case 95:
                case 96:
                case 98:
                    try {
                        Sound asgore = new Sound("audio/asgore.wav", false);
                        asgore.play();
                    }
                    catch(Exception e) {
                        e.printStackTrace();
                    }
                    break;
            }
            if(gameOverFrame == 225)
                gameOverDone = true;
            gameOverCount = 0;
        }
        Graphics2D g2d = (Graphics2D) g.create();
        int width = gameOver.getWidth();
        int height = gameOver.getHeight();
        g2d.drawImage(gameOver, getWidth() / 2 - (width / 2) + 1, getHeight() / 2 - height / 2, null);
        g2d.dispose();
    }

    @Override
    public void actionPerformed(ActionEvent e) { 
        repaint();
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
        case KeyEvent.VK_UP:
            dir = 'u';
            break;
        case KeyEvent.VK_DOWN:
            dir = 'd';
            break;
        case KeyEvent.VK_RIGHT:
            dir = 'r';
            break;
        case KeyEvent.VK_LEFT:
            dir = 'l';
            break;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
}

如果需要进一步的详细信息,请与我们联系。谢谢!

更新1:

我刚才意识到我遗漏了一些相当重要的信息。对于我的目的,playGroup()听起来似乎工作正常(或至少足够好)。主要问题是同时在这些声音上播放小音效。

因此,放入ArrayList并放入playGroup()和stopGroup()方法的声音似乎运行得很好。当我创建一个单独的声音并在主循环声音上播放时,会出现主要问题。

1 个答案:

答案 0 :(得分:0)

几乎每次与多线程有关时都会发出噼啪声。 我编写了一个有效的音频库。使用它:https://github.com/RalleYTN/SimpleAudio