Loop a sound file from a certain point? - java

Suppose I have a sound file that I wish to play in this manner:
Start from the 0:00 mark.
When the sound file ends, replay from the 0:30.00 mark.
Essentially, I wish for the song to play from 0:00 to 0:30, then loop from 0:30 to the end.
How do you do this?
Usually, when playing Audio Files, I use AudioClip.
AudioClip audio = Applet.newAudioClip( this.getClass().getResource( "..." ) );
audio.loop();
It's because of bad experiences with loading the audio file when the project is packed into a .jar file. If the method you recommend uses another class, I would still be more than happy to listen. However, if you've encountered the same problem as I have and know how to fix it, please do tell me.

You might use a Clip for this, or if the clip is too large, feed the bytes directly to a SourceDataLine.

Related

Cache a sound and create instaces of it

I am currently programming a game and now I also want to add sound. My current method works fine but I am not happy with it.
new Sound(new Resource().readAndGetStream("small_click.wav")).play();
This line of code reads the file small_click.wav whenever it is getting executed. But I think it is not very efficient to always read the resource file when it's needed.
So what I want to do now is caching a sound in a variable or something to not have to load the sound from file again. But I also want to create a new object from the sound, so I can play it mutiple times and it overlaps in the speakers.
I can't find a way to do this. I already tried to use Threads but.. this code works without any threads.
If you want to know, here is the code of the Sound class:
public Sound(InputStream audioSrc) {
try {
InputStream bufferedIn = new BufferedInputStream(audioSrc);
AudioInputStream audioStream = AudioSystem.getAudioInputStream(bufferedIn);
clip = AudioSystem.getClip();
clip.open(audioStream);
} catch {
...exception handling...
}
}
public void play() {
clip.setFramePosition(0);
clip.start();
}
And If you want to know what the "new Resource().readAndGetStream()" does:
It basically loads a resource and returns an InputStream of that resource with getResourceAsStream().
With the Sound class that you have, you can easily create a "cache". For example, create an array of type Sound[] soundCache and execute the first part of the code line you gave in your example.
soundCache[0] = new Sound(new Resource().readAndGetStream("small_click.wav"));
You could even consider making constants to correspond to each sound.
final int SMALL_CLICK = 0;
Then, when it is time to play the sound, execute your play function.
soundCache[SMALL_CLICK].play();
Going from here to having concurrent playbacks of a given sound is quite a bit more involved. If continuing to work with Clip as your basis, I don't know of any way to get overlapping playbacks of the same sound resource except by making and managing as many copies of the Clip as you might want to allow to be heard at once.
When faced with this coding challenge, I ended up writing my own library, AudioCue. It is available on Github, and has a very permissive license.
The basic concept is to store the audio data in an array of signed PCM floats, and manage the concurrent playback by having multiple "cursors" that can independently iterate through the PCM data and feed it to a SourceDataLine.
These cursors can be managed in real time. You can change the rate at which they travel through the data and scale the volume level of the data, allowing frequency and volume changes.
I did my best to keep the API as similar to a Clip as practical, so that the class would be easy to use for coders familiar with Java's Clip.
Feel free to examine the code for ideas/examples or make use of this library in your project.

JAVA: Controlling volume of an audioinputstream

I use in a java code a wav file that I load into an AudioInputStream using AudioInputStream ais = AudioSystem.getAudioInputStream("file.wav")
Once I have done that, I wish to basically pick up the n amount of seconds at the end (let's say the 5 last seconds) and "fade out" the volume (FloatControl.Type.MASTER_GAIN??).
Once done I could transfert my audiostreaminput back into a wav file using: AudioSystem.write(ais, Type.WAVE, file_output);
the result is a same wav file but with the last 5 seconds fading out (volume decreasing).
Any idea on how to do this? I tried changing the ais into bytes[], or a sourcedataline... but didn't find what I wanted, as most examples are about changing volume of an audio "in-play" (I also saw things around using Clip which also seems to be dealing an audio file in-play)
Many thanks everyone
Start by turning the sound into a byte array. Then turn the bytes into samples: you'll need to find a tutorial specifically for this, it's a little involved in Java (http://www.jsresources.org/ is a good resource). Samples are the direct representation of the sound wave.
To decrease the volume, multiply all the samples by something less than 1, and then save them back to a byte array. To fade out you'll need to multiply the last n samples by a decreasing function. Then write out the file with the proper WAV headers.
These are just a few pointers for a complex process, hopefully they will send you in the right direction.

Using the java.sound API

I was looking into the Java sound API and noticed that it allows us to play audio files. I have two questions. Given an audio file, how can we use javax.sound to play the audio file at any random location. Moreover, does javax.sound convert audio files to text files containing their lyrics?
"to play the audio file at any random location":
When you are creating an AudioInputStream object you can just give it the bytestream starting at the position at which you want to start like so:
audioInputStream = new AudioInputStream( byteArrayInputStream, audioFormat,
audioData.length/audioFormat.getFrameSize());
This is from the complete example-code at:
http://www.developer.com/java/other/article.php/1565671/Java-Sound-An-Introduction.htm
To your second question: There exist several speech-recognition packages but as far as i know they do a poor job at parsing music because there is too much "noise".
Given an audio file, how can we use javax.sound to play the audio file ..
If you'd read the JavaSound info page you'd have seen source that can play a sound.
..at any random location?
Clip also provides setMicrosecondPosition(long) & setFramePosition(int). Feed a random number to either, and you're set to go.

Why audio files sound different?

I recorded some audio files that must be played from java. I did it about half-year ago. Now, when I add files, they sound as if being sped-up with higher pitch. Old files sound normally, new ones don't. I suppose there is something that has to be changed in audio parameters. What could it be?
That's the code I'm using to play .wav files:
AudioInputStream result1 = AudioSystem.getAudioInputStream(new File("/home/nikkka/Desktop/alphabet/result.wav"));
DataLine.Info info = new DataLine.Info(Clip.class, result1.getFormat());
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(result1);
clip.start();
At the risk of stating the obvious ...
If the old file still play fine and the new ones don't, then it must be something different about the way that you recorded the new files.
It doesn't sound like the real problem is anything to do with programming, let alone Java.
of course. but the thing is, i recorded the old files with settings i don't actually remember.
My suggestion is to fiddle with the settings until you can once again record files that play properly.

Audio playing too fast

If any of my fellow Xuggler users can tell me what I'm doing wrong, that would be awesome! I am doing the following:
Reading from ogv (ogg video)
Queueing the audio and video
Writing back to ogv
sounds simple right? The problem I am experiencing in my QueueMixer class is that the output file plays the audio 2x too fast, and no matter what I check or change with regards to pts it doesnt improve.
The eclipse project and all files being used are at this link:
http://dl.dropbox.com/u/7316897/paul-xuggled.zip
To run a test, compile and execute the StreamManager class; a test ogv file is included. Before anyone asks, yes I have to queue the data as it will be mixed with other data in a future version.
Audio has a sample rate. Make sure that you copy the sample rate from the input to the output, otherwise the system might use a default (like 44KHz while the original data was sampled at 22KHz which would create such an effect).
The fix is to multiply the sample count by two when extracting them from the ShortBuffer.
samples = new short[(int) audioSamples.getNumSamples() * 2];
audioSamples.getByteBuffer().asShortBuffer().get(samples);
Having half the samples causes the audio to play twice as fast.

Categories

Resources