A sound handler I have developed for my game handles playing musing and sound effects. In theory there should be one voice for each sfx and music, and each should only be able to play one track at a time.
However, whilst monitoring the resources used the RAM used exponentially increases when skipping through tracks, all the way to the argument limit of 8Gb - meaning that it loads tracks into memory again each time it is played and is never dumped.
Whilst debugging this, I placed an unhealthy amount of .Drains and .Flushes on the Clips in my class, and resetting the AudioInputStream to null, experimenting with no effect.
On a side note, when skipping through tracks quickly, an occasional phantom voices will appear, continuing to play in the background uncontrollably of the controlled Music voice - I feel this are likely closely related.
Below is the entire class, including all positions which .Drain etc were used during debugging. Song skipping starts from NextTrack() or PrevTrack(), both give the same result.
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class SoundHandler {
private static Clip sfx = null, Music = null;
public static boolean MusicEnabled = true;
private static int STIndex = 0;
private static final int TrackCount = 41;
private static AudioInputStream audioInputStream;
//Channel true = sfx, else music
private static void PlayFile(String filename, boolean Chanel){
try {
audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(filename)));
if (Chanel) {
try {sfx.stop(); sfx.drain();}catch (Exception e) {}
sfx = AudioSystem.getClip();
sfx.open(audioInputStream);
sfx.start();
} else {
if (!MusicEnabled) {return;}
try {Music.stop(); Music.drain();}catch (Exception e) {}
Music = AudioSystem.getClip();
Music.open(audioInputStream);
Music.start();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
//Music Handler for external
private static void PlayTrack() {
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/ST" + STIndex + ".wav");
PlayFile(Location, false);
}
public static void SFX(String Effect) {
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/" + Effect + ".wav");
PlayFile(Location, true);
}
public static void NextTrack() {
if (STIndex >= TrackCount) {STIndex = 0;} else {STIndex++;}
Music.stop();
Music.drain();
Music.flush();
try {audioInputStream.close();} catch (IOException e) {}
audioInputStream = null;
PlayTrack();
}
public static void PrevTrack() {
if (STIndex <= 0) {STIndex = TrackCount;} else {STIndex--;}
Music.stop();
Music.drain();
Music.flush();
try {audioInputStream.close();} catch (IOException e) {}
audioInputStream = null;
PlayTrack();
}
public static void StartMusic () {
MusicEnabled = true;
STIndex = 0;
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/ST" + STIndex + ".wav");
PlayFile(Location, false);
}
public static void PlayIndex(int index) {
MusicEnabled = true;
STIndex = 0;
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/ST" + index + ".wav");
PlayFile(Location, false);
}
public static void PlayStop() {
MusicEnabled = !MusicEnabled;
if (MusicEnabled) {
StartMusic();
} else {
try {Music.stop(); Music.drain(); Music.flush();}catch (Exception e) {}
}}
public static void Tick() {
try {if ((!Music.isActive()) && MusicEnabled){NextTrack();}} catch (Exception e) {}
if (!MusicEnabled) {
try {if (!Music.isActive()){Music.stop(); Music.drain();}} catch (Exception e) {}
}}
public static int getST() {
return STIndex;
}
}
Related
I try to get correct AVI video player to play AVI file since my current AVI Player class looks like not work really good anymore.
Some AVI files can play correctly, but the others can not.
People who know which AVI Video player class play all avi files exactly,
Please help me,
Thank you,
p/s :
I don't want intent to 3rd application to play AVI file.
Below codes is current I used to play AVI files:
AVI Player.java
package runnable;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import iterface.IVideoSink;
public class VideoPlayer implements Runnable {
private final int FPS = 24;
/**
* String section
*/
private boolean IS_ALIVE = true;
private long LAST_FRAME_TIME;
/**
* Data section
*/
private ArrayList<IVideoSink> mAlVideoSinks;
/**
* Others section
*/
private BufferedInputStream mBufferedInputStream;
public VideoPlayer(String filename) {
mAlVideoSinks = new ArrayList<IVideoSink>();
try {
mBufferedInputStream = new BufferedInputStream(new FileInputStream(filename));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void addVideoSink(IVideoSink videoSink) {
synchronized (mAlVideoSinks) {
mAlVideoSinks.add(videoSink);
}
}
public void removeVideoSink(IVideoSink videoSink) {
synchronized (mAlVideoSinks) {
if (mAlVideoSinks.contains(videoSink))
mAlVideoSinks.remove(videoSink);
}
}
#Override
public void run() {
int count = 0;
while (IS_ALIVE) {
if (LAST_FRAME_TIME == 0) {
LAST_FRAME_TIME = System.currentTimeMillis();
}
try {
long currentTime = System.currentTimeMillis();
if (currentTime - LAST_FRAME_TIME < 1000 / FPS) {
Thread.sleep(1000 / FPS - (currentTime - LAST_FRAME_TIME));
}
LAST_FRAME_TIME = System.currentTimeMillis();
int b0 = mBufferedInputStream.read();
if (b0 == -1) break;
int b1 = mBufferedInputStream.read();
int b2 = mBufferedInputStream.read();
int b3 = mBufferedInputStream.read();
count = b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
byte[] buffer = new byte[count];
int readCount = mBufferedInputStream.read(buffer, 0, count);
for (IVideoSink videoSink : mAlVideoSinks) {
videoSink.onFrame(buffer, null);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
mBufferedInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (IVideoSink videoSink : mAlVideoSinks) {
videoSink.onVideoEnd();
}
}
public void stop() {
IS_ALIVE = false;
}
}
PCM Player.java
package runnable;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import java.util.ArrayList;
public class PCMPlayer implements Runnable {
/**
* String section
*/
private boolean IS_ALIVE = true;
/**
* Data section
*/
private ArrayList<byte[]> mAlBuffers = new ArrayList<byte[]>();
/**
* Other section
*/
private AudioTrack mAudioTrack;
public PCMPlayer() {
}
#Override
public void run() {
int bufSize = AudioTrack.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufSize,
AudioTrack.MODE_STREAM);
mAudioTrack.play();
while (IS_ALIVE) {
byte[] buffer = null;
boolean dataFlag = true;
while (dataFlag) {
synchronized (mAlBuffers) {
if (mAlBuffers.size() > 0) {
buffer = mAlBuffers.remove(0);
} else {
dataFlag = false;
break;
}
}
mAudioTrack.write(buffer, 0, buffer.length);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mAudioTrack.stop();
mAudioTrack.release();
}
public void writePCM(byte[] pcm) {
synchronized (mAlBuffers) {
byte[] buffer = new byte[pcm.length];
System.arraycopy(pcm, 0, buffer, 0, buffer.length);
mAlBuffers.add(buffer);
}
}
public void stop() {
IS_ALIVE = false;
}
}
I don't know your intentions. But in your place, I would use a library for that. For examlpe jVLC .
The problem is that AVI is just a container for sound and video data, that can be encoded by any codecs. The sound can be mp3, ogg, or whatever and the video can be mpeg, divx, xvid of several versions.
You can not count on that the all AVIs will contain the same sound/video formats. That is why some of your AVIs can not be played by you current program.
How to stop MP3 in jlayer? (the stop() is no longer used)
My code as follows:
//main class mp3_main
private AdvancedPlayer player;
public static void main(String[] args) {
String file="C:\\cd.mp3";
mp3PlayerSample mp3 = new mp3PlayerSample(file);
mp3.play();
mp3.stop();
}
//class mp3PlayerSample
private String filename;
private BufferedInputStream buffer;
private AdvancedPlayer player;
//constructor
public mp3PlayerSample(String filename)
{
this.filename = filename;
}
//start method
public void play()
{
FileInputStream fis;
try {
fis = new FileInputStream(this.filename);
buffer = new BufferedInputStream(fis);
try {
this.player=new AdvancedPlayer(buffer);
player.play();
} catch (JavaLayerException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
//stop method
public void stop()
{
if(player != null){
player.close();
}
}
You need to run the player in its own thread, right now your main method blocks after calling play() until playback has completed.
Note, the classes Player/AdvancedPlayer included with jlayer are meant as example code to demonstrate how the decoding and output of decoded audio has to be wired up. They are not fully fledged players (e.g. there isn't even volume control).
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import java.util.Scanner;
class Music extends Thread{
public void run(){
try {
FileInputStream fileInputStream = new FileInputStream("Freedom.mp3");
Player player = new Player(fileInputStream);
player.play();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(JavaLayerException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main (String[]args){
Scanner keyboard = new Scanner(System.in);
Music music = new Music();
music.start();
System.out.println("Stop music: ");
int off = keyboard.nextInt();
if(off == 0) {
music.stop();
}
}
}
I have been trying to write a basic 'Jeopardy' game in java, and right now I'm trying to add sound to play when the player get's an answer right or wrong. I have tried to add the sound (placing the sound file in the bin folder and using the code below), but when I try to play the file there is no sound. There is no null pointer exception.
public class Overview{
static AudioClip right, wrong;
//start the game
public static void guiApp(){
right = Applet.newAudioClip(Jeopardy.class.getResource("correct.wav"));
wrong = Applet.newAudioClip(Jeopardy.class.getResource("wrong.wav"));
right.play();
intro = new Intro();
intro.start();
}
public static void main (String[ ] args)
{
javax.swing.SwingUtilities.invokeLater (new Runnable ( )
{
public void run ( )
{
guiApp();
}
}
);
}
}
The following is essentially what is happening in the method called:
public class Intro{
public Intro(){
}
public void start(){
JFrame frame = new JFrame();
frame.setSize(100, 100);
frame.setVisible(true);
}
}
This is something that i use to play sound.
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class SoundPlayer extends Thread
{
private static final int BUFFER_SIZE = 128000;
private static File soundFile;
private static AudioInputStream audioStream;
private static AudioFormat audioFormat;
private static SourceDataLine sourceLine;
private String file;
public static String turn = "data/bell.wav"; //bell sound for black jack when it is your turn (played once each turn)
/**
* Plays the sound of the sent file name
* #param file Audio File's path
*/
public SoundPlayer(String file)
{
super("SoundPlayer");
this.file = file;
start();
}
public void run()
{
String strFilename = file;
try {
soundFile = new File(strFilename);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
this.stop();
}
public static void main(String[] args)
{
}
}
I am creating a metronome program and the for loop is executing +1 times than it should.
public class Tempo {
String file;
int bpm;
public Tempo(int bpm, String file){
this.bpm=bpm;
this.file=file;
}
public void tempoPlay () throws InterruptedException{
new Play(file).start();
Thread.sleep(60000/bpm);
}
public static void main(String[] args) throws InterruptedException {
Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");
for(int i=0;i<20;i++){
t.tempoPlay();
}
}
}
The first beat is rapidly followed by the second one but later as it goes it is sounding compliant. I've counted it plays 21 beats but it should play 20.
Here's the Play class:
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
class Play extends Thread {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
enum Position {
LEFT, RIGHT, NORMAL
};
public Play(String wavfile) {
filename = wavfile;
curPosition = Position.NORMAL;
}
public Play(String wavfile, Position p) {
filename = wavfile;
curPosition = p;
}
#Override
public void run() {
File soundFile = new File(filename);
if (!soundFile.exists()) {
System.err.println("Wave file not found: " + filename);
return;
}
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline
.getControl(FloatControl.Type.PAN);
if (curPosition == Position.RIGHT) {
pan.setValue(1.0f);
} else if (curPosition == Position.LEFT) {
pan.setValue(-1.0f);
}
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0) {
auline.write(abData, 0, nBytesRead);
}
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
Shot in the dark: It might be worthwhile to read the file into memory completely for testing purposes. A guess as to what might be happening is that the I/O from reading the file is interfering with the timing of the playback.
You might be able to get away with this to test.
Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");
t.tempoPlay() // ignore this
Thread.sleep(10);
for(int i=0;i<20;i++){
t.tempoPlay();
}
Or better yet, have Tempo cache the read in before playing the sound.
First of all, I love you guys! This is THE best site for finding answers to weird and difficult programming questions. This is the first problem I have not been able to find a solution for on this site, so thanks for that.
So, I have a runnable Game.class and a runnable OggStreamer.class, to allow the music to run in its own separate thread, which I send as a parameter for the Game-class to use. When I run the game from my IDE the OggStreamer always works, but when I've exported it to a .jar-file, it only works 1/3 of the times I start it up. And it's not like the first piece of music doesn't start, and then the next piece of music started will play..it doesn't work at all, until I've started the game a few times.
Has any of you good people had a similar problem? I could understand it if it didn't work at all, which could indicate there was something wrong with the file-references to the music inside the jar-file...but it DOES work, just not consistently.
NOTE: This is my first attempt at Game-programming, and I know it's not very pretty and that I am a total newbie :) There are many things I'd change about the general design, but I'm using this as a project to help me understand the problems I'll encounter when I sit down to design a real framework for my next game.
Start.class
public static void main(String[] args) throws InterruptedException{
ExecutorService threadExecutor = Executors.newCachedThreadPool();
Game game = new Game(musicStreamer);
game.init(); // loads stuff
threadExecutor.execute( musicStreamer ); // start task1
threadExecutor.execute( game ); // start task2
threadExecutor.shutdown();
}
OggStreamer.class
public class OggStreamer implements Runnable{
private URL url;
private AudioInputStream stream;
private AudioInputStream decodedStream;
private AudioFormat format;
private AudioFormat decodedFormat;
private boolean stop, running;
String filename = "";
SourceDataLine line = null;
public OggStreamer() {
this.stop = true;
this.running = true;
this.url = null;
}
public void run() {
while(running){
while (!this.stop) {
System.out.println("Playing Loop");
try {
// Get AudioInputStream from given file.
this.stream = AudioSystem.getAudioInputStream(this.url);
this.decodedStream = null;
if (this.stream != null) {
this.format = this.stream.getFormat();
this.decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
this.format.getSampleRate(), 16,
this.format.getChannels(),
this.format.getChannels() * 2,
this.format.getSampleRate(), false);
// Get AudioInputStream that will be decoded by underlying
// VorbisSPI
this.decodedStream = AudioSystem.getAudioInputStream(
this.decodedFormat, this.stream);
}else{
JOptionPane.showMessageDialog(null, "Stream = null!");
}
} catch (Exception e) {
// Do nothing
System.out.println("Could not get or decode audiostream");
}
line = null;
try {
line = this.getSourceDataLine(this.decodedFormat);
FloatControl volume = (FloatControl)line.getControl(FloatControl.Type.MASTER_GAIN);
volume.setValue(1);
} catch (LineUnavailableException lue) {
// Do nothing
JOptionPane.showMessageDialog(null, "Line is unavailable!");
}
if (line != null) {
try {
byte[] data = new byte[4096];
// Start
line.start();
int nBytesRead = 0;
while (nBytesRead != -1) {
nBytesRead = this.decodedStream.read(data, 0,
data.length);
if (nBytesRead != -1) {
line.write(data, 0, nBytesRead);
}
if (this.stop) {
break;
}
}
// Stop
line.drain();
line.stop();
line.close();
} catch (IOException io) {
// Do nothing
JOptionPane.showMessageDialog(null, "Line cannot start!");
}
}
}
}
}
private SourceDataLine getSourceDataLine(AudioFormat audioFormat)
throws LineUnavailableException {
SourceDataLine res = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
audioFormat);
res = (SourceDataLine) AudioSystem.getLine(info);
res.open(audioFormat);
return res;
}
public void startLoop(String filenameString) {
this.filename = filenameString;
System.out.println("Starting loop with: "+filenameString);
this.url = this.getClass().getResource(filenameString);
this.stop = false;
}
public void stopLoop() {
System.out.println("Stopping loop");
try {
if(this.decodedStream!=null)this.decodedStream.close();
if(this.stream!=null)this.stream.close();
} catch (IOException e) {
}
this.stop = true;
this.url = null;
}
public boolean isStop() {
return stop;
}
public void setStop(boolean stop) {
this.stop = stop;
}
public URL getUrl() {
return url;
}
public void setUrl(String string) {
this.filename = string;
this.url = this.getClass().getResource(string);
}
public String getFilename() {
return filename;
}
}
Game.class uses the OggStreamer-class as such:
if(musicStreamer!=null && !musicStreamer.getFilename().equals("/snm/sound/oggs/Prelude.ogg")){
if(!musicStreamer.isStop())musicStreamer.stopLoop();
musicStreamer.startLoop("/snm/sound/oggs/Prelude.ogg");
}