How to play sounds and music in java without lag - java

I wrote this audio class that is used by my soundplayer class it works correctly with no errors but causes my game to hiccup or jerk when the sound is used in quick succession (i.e. rapid jumping). I thought that by loading it in once and rewinding it each time(with the mark and reset methods) the sound would stay in RAM but it doesn't seem to be doing that.I am open to any changes or a total rewrite. i just need it to work I've been stuck on audio for months.
package com.bigdirty1985.squaresthatmove.sound;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
public class Sound {
#SuppressWarnings("restriction")
private AudioStream audioStream;
private File file;
#SuppressWarnings("restriction")
public Sound(File file) {
this.file = file;
try {
this.audioStream = new AudioStream(new FileInputStream(this.file));
this.audioStream.mark(100000000);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#SuppressWarnings("restriction")
public void play() {
AudioPlayer.player.stop(this.audioStream);
AudioPlayer.player.start(this.audioStream);
try {
this.audioStream.reset();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#SuppressWarnings("restriction")
public void stop() {
AudioPlayer.player.stop(this.audioStream);
}
}

Related

UnsupportedAudioFileException with a .wav file

I'm trying to load a .wav file in my EnviromentAudio object, but I received only an UnsupportedAudioFileException and I don't know why. Because the file is a wav and I've tried to encode it as an unsigned 8 bit, as a signed 16 bit, with a 44100 bit rate, as a GSM, as a A-law... long story short I've tried a lot of encoding, as many people suggested, but no one worked. Probably I'm not getting something, so, I want to ask what I'm doing wrong.
EDIT:
As pointed out I should have specified some things: first of all, to set some context, I am using Java 8 to create a little pc game for a project, which must uses the basics components of java. Said that, I'm using the ClassLoader
, because I have a mess in the project folder. It does not follow the convention and I have to keep like that. It's structured like this:
-src
-app
-audio
EnviromentAudio.java // Class that need to load soundtrack.wav
-res
-audio
Soundtrack.wav // Audio to be loaded
And I know that a getResource.. should start always with a /, but if I add that slash, then every attempt to get a resource results in a NPE. Probably that's caused by the folders disposition and, by the way, the resources folder is set as source folder, so I'm not even quite sure about that, cause, also, I've already used the getResource to get other files without problems.
In this case The getResource works fine, that is it retrieves the file, but the AudioSystem generates an error. I've tried to isolate the parties involved, but the only problem seems to be here. I'm adding the AudioManager class, the Audio class inherited by EnviromentAudio, and the whole EnviromentAudio, with the hope that it will be of help for a better understanding. I also provided a main in the AudioManager class, which should be enough to replicate the error.
Audio class:
package application.core.audio;
import java.util.ArrayList;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.JOptionPane;
public abstract class Audio
{
protected static final String AUDIOERROR="Error in loading audio. "
+ "Execution Failed, please, restart the game. "
protected static final String AUDIOERRORTITLE="Audio loading error";
protected ArrayList<Clip> multimedia;
protected Clip currentAudio;
protected FloatControl gainControl;
public Audio() {
multimedia=new ArrayList<Clip>();
currentAudio=null;
}
protected abstract void getResources();
public void playAudio(int index) {
try
{
currentAudio=multimedia.get(index);
gainControl=(FloatControl) currentAudio.getControl(
FloatControl.Type.MASTER_GAIN);
currentAudio.open();
} catch (LineUnavailableException e)
{
e.printStackTrace();
JOptionPane.showMessageDialog(null, AUDIOERROR,
AUDIOERRORTITLE, JOptionPane.ERROR_MESSAGE);
}
currentAudio.start();
}
public void loopAudio(int index) {
currentAudio=multimedia.get(index);
// gainControl=(FloatControl) currentAudio.getControl(
// FloatControl.Type.MASTER_GAIN);
// currentAudio.open();
// currentAudio.start();
currentAudio.loop(Clip.LOOP_CONTINUOUSLY);
}
public void repeatAudio(int index, int times) {
try
{
currentAudio=multimedia.get(index);
gainControl=(FloatControl) currentAudio.getControl(
FloatControl.Type.MASTER_GAIN);
currentAudio.open();
} catch (LineUnavailableException e)
{
e.printStackTrace();
JOptionPane.showMessageDialog(null, AUDIOERROR,
AUDIOERRORTITLE, JOptionPane.ERROR_MESSAGE);
}
currentAudio.loop(times);
}
public void stopAudio(int index) {
multimedia.get(index).stop();
multimedia.get(index).close();
}
public void setVolume(float volume) {
float range=gainControl.getMaximum()-gainControl.getMinimum();
float gain=(range-volume)+gainControl.getMinimum();
gainControl.setValue(gain);
}
public boolean currentAudioIsOpen() {return currentAudio.isOpen();}
public void openCurrentAudio() {
if (!currentAudio.isOpen())
try
{
currentAudio.open();
} catch (LineUnavailableException e)
{
e.printStackTrace();
JOptionPane.showMessageDialog(null, AUDIOERROR,
AUDIOERRORTITLE, JOptionPane.ERROR_MESSAGE);
}
}
public void openAndPlayCurrentAudio() {
if (!currentAudio.isOpen())
openCurrentAudio();
currentAudio.start();
}
public void playCurrentAudio() {currentAudio.start();}
public void loopCurrentAudio() {currentAudio.loop(Clip.LOOP_CONTINUOUSLY);}
public void repeatCurrentAudio(int times) {currentAudio.loop(times);}
public void stopCurrentAudio() {currentAudio.stop();}
public void stopAndCloseCurrentAudio() {
currentAudio.stop();
currentAudio.close();
}
}
This is my EnviromentAudio class that produce the exception:
package application.core.audio;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class EnviromentAudio extends Audio
{
public static final int SOUNDTRACK=0;
public EnviromentAudio()
{
super();
getResources();
this.gainControl=(FloatControl) currentAudio.getControl(FloatControl.Type.MASTER_GAIN);
}
#Override
protected void getResources()
{
try
{
ClassLoader loader=EnviromentAudio.class.getClassLoader();
multimedia.add(AudioSystem.getClip());
multimedia.get(SOUNDTRACK).open(AudioSystem.getAudioInputStream( // here the exception is thrown (on getAudioInputStream)
loader.getResourceAsStream("resources"+File.separator+"audio"+File.separator+
"soundtrack"+File.separator+"igpeSoundtrack.wav")));
currentAudio=multimedia.get(SOUNDTRACK);
} catch (LineUnavailableException e)
{
e.printStackTrace();
} catch (IOException | UnsupportedAudioFileException e1)
{
e1.printStackTrace();
}
}
}
AudioManager class:
package application.core.audio;
public class AudioManager
{
private static AudioManager instance=null;
private EnviromentAudio soundtrack;
private PlayerAudio playerAudio;
private AudioManager() {
soundtrack=new EnviromentAudio();
// playerAudio=new PlayerAudio();
soundtrack.loopAudio(EnviromentAudio.SOUNDTRACK);
}
public static AudioManager getInstance() {
if (instance==null)
instance=new AudioManager();
return instance;
}
public Audio getSoundtrack() {return soundtrack;}
public Audio getPlayerSounds() {return playerAudio;}
public void setVolume(float volume) {
soundtrack.setVolume(volume);
playerAudio.setVolume(volume);
}
public float getVolume() {return soundtrack.gainControl.getValue();}
public static void main(String[] args)
{
AudioManager a=AudioManager.getInstance();
}
}
And here is the error:
javax.sound.sampled.UnsupportedAudioFileException: Stream of unsupported format
at java.desktop/javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1020)
at application.core.audio.EnviromentAudio.getResources(EnviromentAudio.java:29)
at application.core.audio.EnviromentAudio.<init>(EnviromentAudio.java:18)
at application.core.audio.AudioManager.<init>(AudioManager.java:11)
at application.core.audio.AudioManager.getInstance(AudioManager.java:19)
at application.MainApplication.audioInitialize(MainApplication.java:44)
at application.MainApplication.main(MainApplication.java:25)
This is more to help with troubleshooting than a solution (expanding on Andrew Thompson's suggestion of making an MRE. Are you using a particular framework? Or is it something of your own making? For a second I though it might be Android (due to presence of AudioManager).
Following is a more minimal example for play testing your .wav file. Put the wav file in the same folder as this class. Does your .wav file play when using this?
import java.io.IOException;
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.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class BasicClipExample {
public static void main(String[] args) {
try {
BasicClipExample.run();
} catch (UnsupportedAudioFileException | IOException
| LineUnavailableException | InterruptedException e) {
e.printStackTrace();
}
}
private static void run() throws UnsupportedAudioFileException,
IOException, LineUnavailableException, InterruptedException
{
String filename = "yourSound.wav";
URL url = BasicClipExample.class.getResource(filename);
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(ais);
clip.start();
Thread.sleep(6000); // plays up to 6 seconds of sound before exiting
clip.close();
}
}
If it works, then something is odd about your framing code. From here you can progressively check if things like the file separator logic are working. You can also add some lines to print out the AudioFormat if the file loads.
Another way I sometimes inspect files is to load them into Audacity, which is free. Info about the file format is pretty easy to inspect with that tool. If I had to wager, and the issue IS the .wav format, I'm guessing that the file is recorded at a higher quality level than Java is set to work with, e.g., 48000 (maybe Java supports?) or 96000 fps or 24- or 32-bit encoding rather than 16-bit.

Loading assets in libgdx for JUnit tests

I am currently developing a game using libgdx and java. I am wanting to run some JUnit tests on some of the features of my game, however I am having difficulties loading in my assets. I have tried to implement Mockito so that I can make headless JUnit tests to see if this helped solved the problem but this has not helped. Here is the test class that I am trying to load an asset in (the asset is being loaded on line 17)
import com.kroy.game.FireEngine;
import com.kroy.game.Fortress;
import com.kroy.game.Tile;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
#RunWith(GdxTestRunner.class)
public class FireEngineTests {
Tile testTile = new Tile();
FireEngine testFireEngine = new FireEngine(100, 10, 10, testTile, 10, 100, "fireEngineSprite.png");
Class ReflectionClass = FireEngine.class;
#Test
public void testRefillAmount() {
testFireEngine.refillAmount(50);
assertEquals(50, testFireEngine.getWaterAmount());
testFireEngine.refillAmount(5000);
assertEquals(100, testFireEngine.getWaterAmount());
}
#Test
public void testCanShoot() {
}
#Test
public void testDeath() {
testFireEngine.setHealth(0);
assertTrue(testFireEngine.isDisabled());
}
#Test
public void testTakeDamage() {
try {
testFireEngine.setHealth(100);
Method takeDamageReflection = ReflectionClass.getDeclaredMethod("takeDamage");
takeDamageReflection.setAccessible(true);
takeDamageReflection.invoke(50, takeDamageReflection);
assertEquals(50, testFireEngine.getHealth());
takeDamageReflection.invoke(5000, takeDamageReflection);
assertEquals(0, testFireEngine.getHealth());
} catch (NoSuchMethodException e) {
} catch (InvocationTargetException e) {
} catch (IllegalAccessException e) {
}
}
#Test
public void testTransferTo() {
Tile newLocation = new Tile(2,2);
try {
Method transferToReflection = ReflectionClass.getDeclaredMethod("transferTo");
transferToReflection.setAccessible(true);
transferToReflection.invoke(newLocation, transferToReflection);
assertEquals(testTile.getInhabitant(),null);
assertEquals(newLocation.getInhabitant(), testFireEngine);
} catch (NoSuchMethodException e) {
} catch (InvocationTargetException e) {
} catch (IllegalAccessException e) {
}
}
#Test
public void testShootTarget() {
Fortress testFortress = new Fortress(1000, 10,2,testTile, "fortress1", "lavaTile.png");
testFireEngine.shootTarget(testFortress);
assertEquals(testFortress.getHealth(), (testFortress.getMaxHealth() - testFireEngine.getDamage()));
assertEquals(99, testFireEngine.getWaterAmount());
}
}
Here is the error message that I get for each of the tests that I try to run:
com.badlogic.gdx.utils.GdxRuntimeException: Asset not loaded: /Users/michaelShepherd/Documents/University Work/Year 2/SEPR/Assessment 3/Septagon3/tests/assets/fireEngineSprite.png
The searched for file is definitely in that location specified and I have also made the assets folder the resouces root for this module, yet still the file does not load.
Any suggestions?
I am not sure how you work with textures in FireEngine class but you probably need to load and access textures through AssetManager as you usually do in game.

RandomAccessFile doesn't work with Minecraft Forge

I'm working at the moment on a Mod for Minecraft with a dedicated Gui system written in C++ and Qt5. I let my GUI and Minecraft communicate through a named pipe, but I have there a small problem. I can read and write with a simple Java and C++(Qt) program into the pipe. But when I create a new instance of my Pipeendpoint class in post init of Minecraft Forge it can't read anything from the Pipe. In a standalone system, it can read stuff.
Not working Forge Implementation:
package de.CoderDE.CodersAnimationEditor;
import java.io.FileNotFoundException;
import de.CoderDE.CodersAnimationEditor.Pipe.PipeEndpoint;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
#SideOnly(Side.CLIENT)
public class ClientProxy extends CommonProxy {
static PipeEndpoint pendpoint;
#Override
public void preInit(FMLPreInitializationEvent e) {
super.preInit(e);
}
#Override
public void init(FMLInitializationEvent e) {
super.init(e);
}
#Override
public void postInit(FMLPostInitializationEvent e) {
super.postInit(e);
try {
pendpoint = new PipeEndpoint();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
Working standalone implementation:
import java.io.FileNotFoundException;
import de.CoderDE.CodersAnimationEditor.Pipe.PipeEndpoint;
public class Main {
static PipeEndpoint pipe;
public static void main(String[] args) {
try {
pipe = new PipeEndpoint();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And the important PipeEndpoint class:
package de.CoderDE.CodersAnimationEditor.Pipe;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class PipeEndpoint {
private Thread reciever;
private RandomAccessFile pipe;
public PipeEndpoint() throws FileNotFoundException {
pipe = new RandomAccessFile("\\\\.\\pipe\\CodersAnimationEditor", "rw");
reciever = new Thread(new PipeEndpointReciever());
reciever.start();
}
private class PipeEndpointReciever implements Runnable {
#Override
public void run() {
try {
while (true) {
System.out.print((char)pipe.read());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
And with "can't read anything" I mean that it never returns from pipe.read().
Oh, and the Java application starts after the C++(Qt) LocalServer started listening and waits for a new connection.

Extend filelock even the program is not running

Im having trouble with the files that I want to lock permanently. My program can lock the files but when I exit the program (the program is not running) the lock will be release. I want to lock files even the program is not running, is it possible? here's my code. Please help me
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import javax.swing.JOptionPane;
import static com.sun.nio.file.ExtendedOpenOption.NOSHARE_DELETE;
import static com.sun.nio.file.ExtendedOpenOption.NOSHARE_READ;
import static com.sun.nio.file.ExtendedOpenOption.NOSHARE_WRITE;
import java.nio.channels.FileLock;
public class LockFile {
public static void ProcessPackageFiles2(File Path) {
try {
File[] files = Path.listFiles();
for (File file : files) {
if (!file.isDirectory()) {
LockDown(file.getCanonicalPath());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void LockDown(String FilePath) {
try {
Path path = FileSystems.getDefault().getPath(FilePath);
FileChannel locks = FileChannel.open(path, NOSHARE_WRITE, NOSHARE_DELETE, NOSHARE_READ);
FileLock fileLock = locks.tryLock();
if (fileLock != null) {
System.out.println("Locked");
} else {
JOptionPane.showMessageDialog(null, "FAILED");
}
} catch (Exception ex) {
System.out.println(ex);
}
}
public static void main(String[] args) {
ProcessPackageFiles2(new File(path);
}
this is the result when I run the program. The file will be unreadable and
cannot be shared and deleted. But I want to extend it even the program is not
running. But the question is HOW

error trying to attach to virtual machine

I'm trying to attach to a running JVM to debug it using the Virtual Machine class in java. I'm currently have java 8, with jdk1.8.0_11. I have tried to add a manifest to it, with but to no avail. I'm also importing the tools.jar file from my JDK\libs folder.
My code:
import java.io.IOException;
import java.util.List;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
public class loadVM {
public static void main(String[] args) {
String name = "replaceAfterNameFound";
List <VirtualMachineDescriptor> vms = VirtualMachine.list();
for (VirtualMachineDescriptor vmd: vms) {
System.out.println(vmd.displayName());
if (vmd.displayName().equals(name)) {
try {
VirtualMachine vm = VirtualMachine.attach(vmd.id());
String agent = "";
vm.loadAgent(agent);
} catch(AttachNotSupportedException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
} catch(AgentLoadException e) {
e.printStackTrace();
} catch(AgentInitializationException e) {
e.printStackTrace();
}
}
}
}
}
Here is a copy of the error I get when running it:
java.util.ServiceConfigurationError:com.sun.tools.attach.spi.AttachProvider:
Provider sun.tools.attach.WindowsAttachProvider could not be
instantiated
Thank you guys for all your help!

Categories