This is my first time posting, and hopefully I'm posting correctly.
I'm currently playing a background song for my project, and I'm trying to play a sound effect, when a button is pressed, on top of the background song. However, the sound doesn't play and the bgm just continues. See below for my Audio class (ignore the bad commenting), and thanks in advance for the help.
package pro;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Audio
{
private boolean loop = false;
private AudioInputStream ais = null;
private static Clip clip = null;
//declaration of variables
public Audio (String fileName, boolean loop)
//Constructor for the class which fileName and accepts whether the clip needs to loop or not
{
this.loop = loop;
//sets the variable within the class as constructor
try {
clip = AudioSystem.getClip();
ais = AudioSystem.getAudioInputStream(Audio.class.getResource(fileName));
clip.open(ais);
} catch (IOException | UnsupportedAudioFileException | LineUnavailableException e) {
e.printStackTrace();
}
//tries to load file into java's built in audio player, else prints the error to console
}
public void musicStart ()
//starts music
{
if (loop)
{
clip.loop(Clip.LOOP_CONTINUOUSLY);
//starts music on loop if loop is requested
}
else
{
clip.start();
//starts music as not on loop
}
}
public void musicStop ()
//stops the music
{
clip.stop();
}
}
EDIT: I found a solution to the problem thanks to MadProgrammer by simply removing static from clip.
Get rid of the static declaration of the Clip. Each instance of Audio should be self contained and point to it's own instance of Clip
Basically, the static will make Clip ALWAYS point to the last sound file loaded, this isn't really what you want, because when you call stopMusic, you won't know which clip you're really stopping or if you're actually stopping anything at all
Related
I've seen and tried several things with AudioCLip, MediaPlayer and more, but nothing really worked. Also, I have no idea how the URL or URI system works. There again I've seen many things but don't know which are actually right.
This is the Code I used in my last try:
public void start (Stage primaryStage) throws Exception {
// TODO Auto-generated method stub
//Initialising path of the media file, replace this with your file path
//File is in the same project with the following path:
String path = "file:src/SoundTest/Megalovania.mp3";
File file = new File(path);
//Instantiating Media class
if(file.exists()) {
Media media = new Media(file.getPath());
MediaPlayer mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
} else{
System.out.println("file not found");
}
//Instantiating MediaPlayer class
//by setting this property to true, the audio will be played
primaryStage.setTitle("Playing Audio");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
Can someone tell me if this worked if the URL was right? And if not, what else is wrong?
This code works, but only if you have something else like a Scene, otherwise the code will stop early. Not sure if an empty stage works.
import javafx.application.Application;
import javafx.scene.image.Image;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.File;
import java.net.URISyntaxException;
public class AudioTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
String musicFile = "Megalovania.mp3"; // For example
Media sound = null;
try {
sound = new Media(getClass().getResource(musicFile).toURI().toString());
} catch (URISyntaxException e) {
e.printStackTrace();
}
MediaPlayer mediaPlayer = new MediaPlayer(sound);
mediaPlayer.play();
}
}
It was the path/resource all along. I figured it out thanks to my teacher now.
I want to have a ****seperate Class**** to have the sounds and i want to call upon that class to play the sounds, but if there is a better way, pls tell me.
Story (can be skipped):
First i used AudioClips that were stored in final statics that i called everytime i needed the sound to play. For single stuff like the background music, this was perfect, but if i wanted to use the sound more than once at a time, like my turrets that shoot, they sometimes play the sound perfectly and sometimes it gets restarted or it is canceled completely.
Then i switched to Clips after reading trhough some posts and that some guy found a solution by doin Clips, after using a tutorial.
Sound Class:
package Game.main;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Mixer;
public class Sound {
public static final Sound backgroundMusic4 = new Sound("/backgroundMusic4.wav");
public static final Sound blockDestroy = new Sound("/blockDestroy.wav");
public static final Sound bulletHit = new Sound("/bulletHit.wav");
public static final Sound button = new Sound("/button.wav");
public static final Sound camera = new Sound("/camera.wav");
public static final Sound teleporter = new Sound("/teleporter.wav");
public static final Sound turretShot = new Sound("/turretShot.wav");
public static final Sound walking = new Sound("/walking.wav");
public static Clip clip;
public Sound(String fileLocation){
Mixer.Info[] mixInfos = AudioSystem.getMixerInfo();
Mixer mixer = AudioSystem.getMixer(mixInfos[0]);
DataLine.Info dataInfo = new DataLine.Info(Clip.class, null);
try{
clip =(Clip) mixer.getLine(dataInfo);
}catch(Exception e){
e.printStackTrace();
}
try{
URL soundURL = getClass().getResource(fileLocation);
AudioInputStream audioStream = AudioSystem.getAudioInputStream(soundURL);
clip.open(audioStream);
}catch(Exception e){
e.printStackTrace();
}
}
public void play(){
clip.loop(clip.LOOP_CONTINUOUSLY);
}
public void playOnce(){
clip.start();
}
public void stop(){
clip.stop();
}
}
Turret Class (As example) [Only the last method "shoot()" matters]:
package Game.main.IngameObjects;
import java.applet.AudioClip;
import java.awt.Graphics;
import java.awt.Rectangle;
import Game.main.Controller;
import Game.main.Game;
import Game.main.GameObject;
import Game.main.Sound;
import Game.main.Textures;
import Game.main.classes.EntityC;
public class Turret extends GameObject implements EntityC{
private boolean activated;
private String direction;
private Game game;
private Textures tex;
private Camera activationCam;
private Controller c;
private long lastShot=0;
public Turret (double x, double y, Textures tex, Game game, Controller c, String direction){
super(x,y);
this.game=game;
this.tex=tex;
this.c=c;
if(!direction.equalsIgnoreCase("up") && !direction.equalsIgnoreCase("down") && !direction.equalsIgnoreCase("left") && !direction.equalsIgnoreCase("right")){
System.err.println("ERROR 1: Wrong Direction in Constructor in Class \"java.Game.main.IngameObjects.Camera\"");
System.exit(1);
}else{
this.direction=direction;
}
}
public Turret (double x, double y, Textures tex, Game game, Controller c , Camera cam, String direction){
super(x,y);
this.game=game;
this.tex=tex;
this.c=c;
if(!direction.equalsIgnoreCase("up") && !direction.equalsIgnoreCase("down") && !direction.equalsIgnoreCase("left") && !direction.equalsIgnoreCase("right")){
System.err.println("ERROR 1: Wrong Direction in Constructor in Class \"java.Game.main.IngameObjects.Camera\"");
System.exit(1);
}else{
this.direction=direction;
}
this.activationCam=cam;
}
public void tick() {
if(activationCam==null){
shoot();
}else if(activationCam.getActivated()){
shoot();
}
}
public void render(Graphics g) {
if(activated){
if(direction.equalsIgnoreCase("up")){
g.drawImage(tex.turretActi.get(0), (int)x, (int)y, null);
}else if(direction.equalsIgnoreCase("down")){
g.drawImage(tex.turretActi.get(1), (int)x, (int)y, null);
}else if(direction.equalsIgnoreCase("left")){
g.drawImage(tex.turretActi.get(2), (int)x, (int)y, null);
}else if(direction.equalsIgnoreCase("right")){
g.drawImage(tex.turretActi.get(3), (int)x, (int)y, null);
}
}else{
if(direction.equalsIgnoreCase("up")){
g.drawImage(tex.turretDeac.get(0), (int)x, (int)y, null);
}else if(direction.equalsIgnoreCase("down")){
g.drawImage(tex.turretDeac.get(1), (int)x, (int)y, null);
}else if(direction.equalsIgnoreCase("left")){
g.drawImage(tex.turretDeac.get(2), (int)x, (int)y, null);
}else if(direction.equalsIgnoreCase("right")){
g.drawImage(tex.turretDeac.get(3), (int)x, (int)y, null);
}
}
}
public Rectangle getBounds() {
return new Rectangle((int)x, (int)y, 32, 32);
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void activate() {
activated=true;
}
public void deactivate() {
activated=false;
}
public boolean getActivated() {
return activated;
}
public void setX(double x) {
this.x=x;
}
public void setY(double y) {
this.y=y;
}
public void shoot(){
if(System.currentTimeMillis() - lastShot >= 1000){
Sound.turretShot.playOnce();
lastShot = System.currentTimeMillis();
c.addEntity(new Bullet(x,y,game,tex,c,direction));
}
}
}
Now i have the problem that the turret Shoots once and the sound plays and then its gone (example video: https://youtu.be/q8TR2nR8hUI ). I tried to give every object his own Sound Clip but that very wastefull and last time it reduced my ticks and fps to 1 every 5 seconds or so.
Thats why i wanted to ask for a solution or some heplfull ideas and code.
I red something about and Byte array and dataStreamOutput, or that i could clone the clips but i cant get either one to work.
I am sorry for my somehow bad english, i am german so pls overlook any mistake (unless you can't read it)
Java Clips are not set up for concurrent playback. At best, and this is often done, you can take a playing Clip and reset it back to the start and restart it (i.e., interrupting it before it completes). The next logical alternative is to instantiate multiple copies of the Clip (as suggested in the comment by VGR) and write a layer of code to manage these instances.
There are a couple libraries that allow concurrent playback of clip-equivalents. TinySound is publicly available via github. There is a major thread about it by the dev at java-gaming.org. Several members there have made successful use of this library.
I've been working on my own sound library, and it includes concurrent playback of clip-equivalents. I haven't opened my sources, yet, though. But if you wish to explore writing your own code to do this, I'm happy to reply on a thread either here or at java-gaming.org. The basic plan is to store the data in an array (can be either as bytes or as PCM normals or whatever) and play it back via a SourceDataLine (SDL) that is set to read from this data file. There is also the option of either running several of these through a single SDL output line (mixing them together before outputting) or giving each its own SDL. It is a bit of work to set this all up, hence many prefer to find a library.
So I'm using VLCJ and the VLC player for java to play a video when I run my program. Problem is, the video player only closes when the user clicks the "x" button. Is there a way to close it automatically when the video ends?
Thanks!
If it helps, here's my code:
//////Main class:
package switchAndAnim;
import java.io.File;
import javax.swing.JFileChooser;
public class Start {
public static void main(String[] args)
{
//location of vlc files, media file
new MediaPlayer("vlc-2.0.2", "ryankilp2.wmv").run();
}
}
///////MediaPlayer class:
package switchAndAnim;
import javax.swing.JFrame;
import com.sun.jna.NativeLibrary;
import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;
public class MediaPlayer {
private JFrame ourFrame = new JFrame();
private EmbeddedMediaPlayerComponent ourMediaPlayer;
private String mediaPath = "";
MediaPlayer(String vlcPath,String mediaURL)
{
this.mediaPath = mediaURL;
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), vlcPath);
ourMediaPlayer = new EmbeddedMediaPlayerComponent();
ourFrame.setContentPane(ourMediaPlayer);
ourFrame.setSize(640,480);
ourFrame.setVisible(true);
ourFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void run()
{
ourMediaPlayer.getMediaPlayer().playMedia(mediaPath);
}
}
The media player has all sorts of events you can listen for, one of them being the "finished" event that fires when the end of the video is reached.
ourMediaPlayer = new EmbeddedMediaPlayerComponent() {
public void finished(MediaPlayer mediaPlayer) {
ourMediaPlayer.release(); // In practice, this line is optional
System.exit(0);
}
}
I used System.exit() since your question set EXIT_ON_CLOSE, but equally you could hide or dispose the frame instead depending on your use case.
I'm trying to get background music to play in a text adventure I am making. However, I cant get the sound class to work.
import sun.audio.*;
import java.io.*;
public class Sound {
public static void music()
{
AudioPlayer MGP = AudioPlayer.player;
AudioStream BGM;
AudioData MD;
ContinuousAudioDataStream loop = null;
try
{
InputStream test = new FileInputStream(new File "TrainerRedMusic.wav");
BGM = new AudioStream(test);
AudioPlayer.player.start(BGM);
}
catch(FileNotFoundException e){
System.out.print(e.toString());
}
catch(IOException error)
{
System.out.print(error.toString());
}
MGP.start(loop);
}
}
I have scoured the internet looking for a simple guide, but nothing works for what I am doing. I am just trying to run a .wav file in the background of my text adventure. Any help?
I watched a great tutorial of Mattew on how to implement audio sounds in Java games.
The problem is that even after I decreased the volume of the wav file when I run the game the volume of the wav sound file is still very high in Java, I mean you can't even play the game because of the background music that is too loud.
Why the volume of the wav file is not maintaining in Java?
It is probably better to use the Java Sound based Clip than the applet based AudioClip. The Clip interface supports controls, one of which should be a MASTER_GAIN.
E.G.
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.event.*;
import javax.sound.sampled.*;
class ClipVolume {
public static void main(String[] args) throws Exception {
URL url = new URL(
"http://pscode.org/media/leftright.wav");
final Clip clip = AudioSystem.getClip();
// getAudioInputStream() also accepts a File or InputStream
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
clip.open(ais);
clip.loop(Clip.LOOP_CONTINUOUSLY);
Runnable r = new Runnable() {
#Override
public void run() {
final FloatControl control = (FloatControl)
clip.getControl(FloatControl.Type.MASTER_GAIN);
final JSlider volume = new JSlider(
JSlider.HORIZONTAL,
(int) control.getMinimum(),
(int) control.getMaximum(),
(int) control.getValue());
volume.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent ce) {
control.setValue(volume.getValue());
}
});
JOptionPane.showMessageDialog(null, volume);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
So, this is the code that i'm using, is working and hope that will help others as well.
happy coding and once again thanks to Andrew Thompson
package com.stefanbanu;
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
// To play sound using Clip, the process need to be alive.
// Hence, we use a Swing application.
public class SoundClipTest extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
// Constructor
public SoundClipTest() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Test Sound Clip");
this.setSize(300, 200);
this.setVisible(true);
try {
// Open an audio input stream.
URL url = this.getClass().getClassLoader().getResource("bgsong.wav");
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
// Get a sound clip resource.
Clip clip = AudioSystem.getClip();
// Open audio clip and load samples from the audio input stream.
clip.open(audioIn);
clip.start();
final FloatControl control = (FloatControl)
clip.getControl(FloatControl.Type.MASTER_GAIN);
control.setValue(-30.0f);
// final JSlider volume = new JSlider(
// JSlider.HORIZONTAL,
// (int) control.getMinimum(),
// (int) control.getMaximum(),
// (int) control.getValue());
// volume.addChangeListener(new ChangeListener() {
//
// public void stateChanged(ChangeEvent ce) {
// control.setValue(volume.getValue());
// }
// });
//
// JOptionPane.showMessageDialog(null, volume);
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new SoundClipTest();
}
}