为了保持简洁,我使用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()方法的声音似乎运行得很好。当我创建一个单独的声音并在主循环声音上播放时,会出现主要问题。