I'm trying to downsample a .wav audio from 22050 to 8000 using AudioInputStream but the conversion returns me 0 data bytes. Here is the code:
AudioInputStream ais;
AudioInputStream eightKhzInputStream = null;
ais = AudioSystem.getAudioInputStream(file);
if (ais.getFormat().getSampleRate() == 22050f) {
AudioFileFormat sourceFileFormat = AudioSystem.getAudioFileFormat(file);
AudioFileFormat.Type targetFileType = sourceFileFormat.getType();
AudioFormat sourceFormat = ais.getFormat();
AudioFormat targetFormat = new AudioFormat(
sourceFormat.getEncoding(),
8000f,
sourceFormat.getSampleSizeInBits(),
sourceFormat.getChannels(),
sourceFormat.getFrameSize(),
8000f,
sourceFormat.isBigEndian());
eightKhzInputStream = AudioSystem.getAudioInputStream(targetFormat, ais);
int nWrittenBytes = 0;
nWrittenBytes = AudioSystem.write(eightKhzInputStream, targetFileType, file);
I already checked AudioSystem.isConversionSupported(targetFormat, sourceFormat) and it returns true. Any idea?
I have just tested your code with different audio files and everything seems to work just fine. I can only guess, that you are either testing your code with an empty audio file (bytes == 0) or, that the file you try to convert is not supported by the Java Audio System.
Try using another input file and/or convert your input file to a compatible file, and it should work.
Here is the main method, that worked for me:
public static void main(String[] args) throws InterruptedException, UnsupportedAudioFileException, IOException {
File file = ...;
File output = ...;
AudioInputStream ais;
AudioInputStream eightKhzInputStream = null;
ais = AudioSystem.getAudioInputStream(file);
AudioFormat sourceFormat = ais.getFormat();
if (ais.getFormat().getSampleRate() == 22050f) {
AudioFileFormat sourceFileFormat = AudioSystem.getAudioFileFormat(file);
AudioFileFormat.Type targetFileType = sourceFileFormat.getType();
AudioFormat targetFormat = new AudioFormat(
sourceFormat.getEncoding(),
8000f,
sourceFormat.getSampleSizeInBits(),
sourceFormat.getChannels(),
sourceFormat.getFrameSize(),
8000f,
sourceFormat.isBigEndian());
if (!AudioSystem.isFileTypeSupported(targetFileType) || ! AudioSystem.isConversionSupported(targetFormat, sourceFormat)) {
throw new IllegalStateException("Conversion not supported!");
}
eightKhzInputStream = AudioSystem.getAudioInputStream(targetFormat, ais);
int nWrittenBytes = 0;
nWrittenBytes = AudioSystem.write(eightKhzInputStream, targetFileType, output);
System.out.println("nWrittenBytes: " + nWrittenBytes);
}
}
Related
I am working on a simple application which needs the facility to read in all the .wav files in a specified directory (/audiofiles), and then concatenate them. I have working code which gets the names of all the files in the directory and prints them to the console, and code which concatenates a list of specified files, but I cannot seem to combine the two functions. Any suggestions?
So far:-
import java.util.*;
import java.io.*;
import javax.sound.sampled.*;
public class getconc_1 {
public static void main(String[] args) {
// get list of file names from audio directory
File audDir = new File("/audiofiles");
//define a list to contain the audio files names and path
File[] filesList = audDir.listFiles();
// assign contents of each wav file from filesList to a string
String wavFile1 = filesList.get(0);
String wavFile2 = filesList.get(1);
// read the string from the audio file into an AudioInputStream, and concatenate
try {
AudioInputStream clip1 = AudioSystem.getAudioInputStream(new File(wavFile1));
AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(wavFile2));
AudioInputStream appendedFiles =
new AudioInputStream(
new SequenceInputStream(clip1, clip2),
clip1.getFormat(),
clip1.getFrameLength() + clip2.getFrameLength());
AudioSystem.write(appendedFiles,
AudioFileFormat.Type.WAVE,
new File("wavAppended.wav"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
First of all you have error in your codes
String wavFile1 = filesList.get(0);
String wavFile2 = filesList.get(1);
Should be replaced by
String wavFile1 = filesList[0].getPath();
String wavFile2 = filesList[1].getPath();
Secondly use
new SequenceInputStream(Collections.enumeration(list)) to join multiple streams into one.
I have not added few checks in the program like checking the size and null check for clip object.
import java.util.*;
import java.io.*;
import javax.sound.sampled.*;
public class getconc_1 {
public static void main(String[] args) {
// get list of file names from audio directory
File audDir = new File("/audiofiles");
//define a list to contain the audio files names and path
File[] filesList = audDir.listFiles();
// assign contents of each wav file from filesList to a string
// read the string from the audio file into an AudioInputStream, and concatenate
try {
long length = 0;
AudioInputStream clip = null;
List<AudioInputStream> list = new ArrayList<AudioInputStream>();
for (File file:filesList ) {
clip = AudioSystem.getAudioInputStream(new File(file.getPath()));
list.add(clip);
length += clip.getFrameLength();
}
if(length>0 && list.size()>0 && clip!=null) {
AudioInputStream appendedFiles =
new AudioInputStream(
new SequenceInputStream(Collections.enumeration(list)),
clip.getFormat(),
length);
AudioSystem.write(appendedFiles,
AudioFileFormat.Type.WAVE,
new File("wavAppended12.wav"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
i have tow audio files and
i want to join that two audio files using java codding or any java Audio-Sound API.
String wavFile1 = "D://SampleAudio_0.4mb.mp3";
String wavFile2 = "D://wSampleAudio_0.7mb.mp3";
AudioInputStream clip1 = AudioSystem.getAudioInputStream(new File(wavFile1));
AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(wavFile2));
AudioInputStream appendedFiles =
new AudioInputStream(
new SequenceInputStream(clip1, clip2),
clip1.getFormat(),
clip1.getFrameLength() + clip2.getFrameLength());
AudioSystem.write(appendedFiles,
AudioFileFormat.Type.WAVE,
new File("D://merge1.mp3"));
I get the following exception:
javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
Got the Solution and It's Working for me.
String wavFile1 = "C:\\1.mp3";
String wavFile2 = "C:\\2.mp3";
FileInputStream fistream1 = new FileInputStream(wavFile1); // first source file
FileInputStream fistream2 = new FileInputStream(wavFile2);//second source file
SequenceInputStream sistream = new SequenceInputStream(fistream1, fistream2);
FileOutputStream fostream = new FileOutputStream("D://merge1.mp3");//destinationfile
int temp;
while( ( temp = sistream.read() ) != -1)
{
// System.out.print( (char) temp ); // to print at DOS prompt
fostream.write(temp); // to write to file
}
fostream.close();
sistream.close();
fistream1.close();
fistream2.close();
I think .7mb.mp3 is recognised as a .7mb extension. Make sure that's not causing problems. Try to rename your files this way:
From:
String wavFile1 = "D://SampleAudio_0.4mb.mp3";
String wavFile2 = "D://wSampleAudio_0.7mb.mp3";
To:
String wavFile1 = "D://SampleAudio_01.mp3";
String wavFile2 = "D://wSampleAudio_02.mp3";
Update
I didn't see that you have answered the question already, but I think it's worth keeping on eye on the extensions in the future.
In my game I've have got a very long ogg files(about 8 to 20 mb) and some other machines aren't able to read it direct into memory. So I read that some games uses stream and play method. Is there any lib/code example to load and play ogg files(with LWJGL) in real time?
Thanks for help :)
Do you specifically need to play OGG files? If not, there are plenty of online converters than can convert it to MP3, WAV, etc.
Also, do you specifically need to play it with LWJGL? This is very possible with default java, like so:
static String randomName = "TreasureQuest";
public static Clip clip = null;
public static void playSound(String name) throws Exception{
if (clip != null && clip.isOpen()) clip.close();
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("music/" + name + ".wav").getAbsoluteFile());
clip = AudioSystem.getClip();
clip.open(audioInputStream);
FloatControl gainControl =
(FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(0f);
System.out.println(clip.getFrameLength() + " | " + clip.getFramePosition());
clip.start();
}
Personally, I use this for my LWJGL game, and it works perfectly fine.
If you must play an OGG file, and you specifically must play it with LWJGL, I suggest you use OpenAL. You can find the documentation for playing OGG files here.
#Joehot200
So I have two music engines - java clip and lwjgl, so it doesn't metter which one i will be using :)
I have a very similar code to yours(but it includes ogg decompression) and it time loading is still very long - I want to read my sound file and play what I read at the same time(like YOUTUBE). Here is my piece of code:
public static Clip DecodeOgg(String filename)
{
try
{
File file = new File(filename);
// Get AudioInputStream from given file.
AudioInputStream in= AudioSystem.getAudioInputStream(file);
AudioInputStream din = null;
if (in != null)
{
AudioFormat baseFormat = in.getFormat();
AudioFormat decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false);
// Get AudioInputStream that will be decoded by underlying VorbisSPI
din = AudioSystem.getAudioInputStream(decodedFormat, in);
Clip clip = AudioSystem.getClip();
clip.open(din);
return clip;
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
I have been wondering how to change this method so i don't have to download the song from the internet, instead i want to play the song from a directory on my computer. Can somebody please give me an example of how i would do this?
URL url = new URL("myUrlToSong.wav"); //How I make this a directory?
//I get an error if i change it to a string
Clip clip = AudioSystem.getClip();
AudioInputStream ais = AudioSystem.getAudioInputStream(url); //error is here id I
//change url to a string
clip.open(ais);
clip.loop(Clip.LOOP_CONTINUOUSLY);
Use any ofAudioSystem.getAudioInputStream(File) or AudioSystem.getAudioInputStream(InputStream).
File f = new File("mySong.wav");
AudioInputStream ais = AudioSystem.getAudioInputStream(f);
Or
InpuStream is = new FileInputStream(new File("mySong.wav"));
AudioInputStream ais = AudioSystem.getAudioInputStream(is);
The answers provided in How do I get a sound file’s total time in Java? work well for wav files, but not for mp3 files.
They are (given a file):
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
AudioFormat format = audioInputStream.getFormat();
long frames = audioInputStream.getFrameLength();
double durationInSeconds = (frames+0.0) / format.getFrameRate();
and:
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
AudioFormat format = audioInputStream.getFormat();
long audioFileLength = file.length();
int frameSize = format.getFrameSize();
float frameRate = format.getFrameRate();
float durationInSeconds = (audioFileLength / (frameSize * frameRate));
They give the same correct result for wav files, but wrong and different results for mp3 files.
Any idea what do I have to do to get the mp3 file's duration?
Using MP3SPI:
private static void getDurationWithMp3Spi(File file) throws UnsupportedAudioFileException, IOException {
AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(file);
if (fileFormat instanceof TAudioFileFormat) {
Map<?, ?> properties = ((TAudioFileFormat) fileFormat).properties();
String key = "duration";
Long microseconds = (Long) properties.get(key);
int mili = (int) (microseconds / 1000);
int sec = (mili / 1000) % 60;
int min = (mili / 1000) / 60;
System.out.println("time = " + min + ":" + sec);
} else {
throw new UnsupportedAudioFileException();
}
}
Here is the way I get the total time of a file .mp3, I'm using the library is Jlayer 1.0.1
Header h = null;
FileInputStream file = null;
try {
file = new FileInputStream(filename);
} catch (FileNotFoundException ex) {
Logger.getLogger(MP3.class.getName()).log(Level.SEVERE, null, ex);
}
bitstream = new Bitstream(file);
try {
h = bitstream.readFrame();
} catch (BitstreamException ex) {
Logger.getLogger(MP3.class.getName()).log(Level.SEVERE, null, ex);
}
int size = h.calculate_framesize();
float ms_per_frame = h.ms_per_frame();
int maxSize = h.max_number_of_frames(10000);
float t = h.total_ms(size);
long tn = 0;
try {
tn = file.getChannel().size();
} catch (IOException ex) {
Logger.getLogger(MP3.class.getName()).log(Level.SEVERE, null, ex);
}
//System.out.println("Chanel: " + file.getChannel().size());
int min = h.min_number_of_frames(500);
return h.total_ms((int) tn)/1000;
Here is a detailed explanation of the MP3 File structure
http://www.autohotkey.com/forum/topic29420.html
Use jave-1.0.1.jar library.
It passed my test on wave file formats such as: wav-pcm8/16,
wav-alaw, wav-ulaw, wav-gsm, wav-adpcm;
It passed my test on some MP3 file formats: cbr vs vbr, stereo vs
SingleChannel;
It can support video formats, which I haven't tested on.
Code sample:
File source = new File("C:\\22.mp3");
Encoder encoder = new Encoder();
try {
MultimediaInfo mi = encoder.getInfo(source);
long ls = mi.getDuration();
System.out.println("duration(sec) = "+ ls/1000);
} catch (Exception e) {
e.printStackTrace();
}
I've tried Jlayer 1.0.1, but it failed for some MP3 format. As for another libaray jaudiotagger-2.0.3.jar, it works fine for MP3 formats, but it can only support wav-pcm8/16.
I'm old-fashioned in this, but I always simply get the specs for MP3, write a function that searches the right bits, and find it out.
If Winamp can determine this by reading the bitstream of an MP3 file, then so can I right?
And so can you, I believe in you mate!