getAudioInputStream cannot read mp3 java - java

AudioInputStream in = AudioSystem.getAudioInputStream(fileAudio);
AudioFormat audFormat = in.getFormat();
audFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
audFormat.getSampleRate(),
16,
audFormat.getChannels(),
audFormat.getChannels() * 2,
audFormat.getSampleRate(),
false);
din = AudioSystem.getAudioInputStream(audFormat, in);
thats the code for me trying to get the raw data, however it is throwing the error: could not get audio input stream from input file. This seems to be the case for mp3s only (only tested on wavs and mp3's). ive added mp3plugin and mp3spi, as others have suggested. Also it seems to work on when getting a file from a JFileChooser, however when hard coding the file it falls over.
code for me creating the file:
private final String sFolderPath = "C:\\Users\\michael\\Music\\MUSIC\\Bushido.mp3";
File fileAudio = new File(sFolderPath);

Related

AudioInputStream from file conversion gives "frameLength=-1"

I am trying to obtain an AudioInputStream from a file in a specific format. When I open the file in fileStream I get a positive frameLength meaning the file can be read and the AudioInputStream effectively has data. Now I want to convert it with AudioSystem with AudioSystem.getAudioInputStream(format, fileStream); and the obtained stream audioStream has a frameLength of -1. I even made sure the conversion is supported and it sure is.
public void openFile() throws IOException, UnsupportedAudioFileException, LineUnavailableException {
AudioInputStream fileStream = AudioSystem.getAudioInputStream(audioFile);
AudioFormat format = new AudioFormat(sampleRate, 8, 1, true, true);
boolean supported = AudioSystem.isConversionSupported(format, fileStream.getFormat());
if(supported) {
audioStream = AudioSystem.getAudioInputStream(format, fileStream);
System.out.println("Opened file: " + audioFile.getName());
}else{
System.out.println("Couldn't open file: " + audioFile.getName());
throw new IOException();
}
}
I am completely stuck and I haven't found anyone with the same exact problem. I welcome any suggestions of different libraries but I would prefer to keep using this one as I'm used to it.
Okay figured it out, I'm dumb.
A frameLength of -1 is, according to the AudioSystem constants, NOT_SPECIFIED which means that, when converting audio, you lose that information.
I was thinking that was the problem because of another unrelated problem.

TarsosDSP Android applying lowpass filter and saving to wav gives choppy results

I am using TarsosDSP library to apply a low pass filter on a wav file. Here is the code.
private void eq2(File file) throws FileNotFoundException {
new AndroidFFMPEGLocator(this);
InputStream inputStream = new FileInputStream(file);
TarsosDSPAudioFormat format = new TarsosDSPAudioFormat(16000,16,2,true,false);
AudioDispatcher adp = new AudioDispatcher(new UniversalAudioInputStream(inputStream,format),2048,0);
adp.addAudioProcessor(new LowPassFS(100,16000));
RandomAccessFile raf = null;
raf = new RandomAccessFile(Environment.getExternalStorageDirectory()+ "/cibiodLogs/audioFiltered1.wav", "rw");
adp.addAudioProcessor(new WriterProcessor(format,raf));
adp.run();
Thread audioThread = new Thread(adp, "Audio Thread");
audioThread.start();
}
It gives output but the output is choppy and not even filtered.
Here take a look at the original wav file and the output wav file.
Original
Filtered
I have tried different buffer sizes from 2 - 4096 but every time either the output is choppy or the audio is not filtered. Can someone point me what might be going wrong here.
This issue is solved now! The TarsosDSP does not support dual-channel audio processing so the algorithm was getting confused with two channels of audio and thus giving the choppy results.

PDFBox creating Sound object with link/reference to external mp3 or wav file

I am writing a utility application using open source java based PDFBox to convert PDF file containing 'Hyperlink to open an mp3 file' to replace it with sound object.
I used PDFBox API since it appears to be mature enough to work with Sound object. I could read the PDF file and find the hyperlink with reference to mp3. But I am not able to replace it with sound object. I created the Sound Object and associate with action but it does not work. I think I am missing some important part how to create Sound object using PDActionSound object. Is it possible to refer to external wav file using PDFBox API?
for (PDPage pdPage : pages) {
List<PDAnnotation> annotations = pdPage.getAnnotations();
for (PDAnnotation pdAnnotation : annotations) {
if (pdAnnotation instanceof PDAnnotationLink) {
PDAnnotationLink link = ((PDAnnotationLink) pdAnnotation);
PDAction action = link.getAction();
if (action instanceof PDActionLaunch) {
PDActionLaunch launch = ((PDActionLaunch) action);
String fileInfo = launch.getFile().getFile();
if (fileInfo.contains(".mp3")) {
/* create Sound object referring to external mp3*/
//something like
PDActionSound actionSound = new PDActionSound(
soundStream);
//set the ActionSound to the link.
link.setAction(actionSound);
}
}
}
}
}
How to create sound object (PDActionSound) and add to link successfully?
Speaking of mature, that part has never been used, and now that I had a closer look at the code, I think some work remains to be done... Please try this, I created this with PDFBox 2.0 after reading the PDF specification:
PDSimpleFileSpecification fileSpec = new PDSimpleFileSpecification(new COSString("/C/dir1/dir2/blah.mp3")); // see "File Specification Strings" in PDF spec
COSStream soundStream = new COSStream();
soundStream.createOutputStream().close();
soundStream.setItem(COSName.F, fileSpec);
soundStream.setInt(COSName.R, 44100); // put actual sample rate here
PDActionSound actionSound = new PDActionSound();
actionSound.getCOSObject().setItem(COSName.getPDFName("Sound"), soundStream));
link.setAction(actionSound); // reassign the new action to the link annotation
edit: as the above didn't work, here's an alternative solution as requested in the comments. The file is embedded. It works only with .WAV files, and you have to know details of them. About 1/2 seconds are lost at the beginning. The sound you should hear is "I am Al Bundy". I tried with MP3 and didn't succeed. While googling, I found some texts saying that only "old" formats (wav, aif etc) are supported. I did find another way to play sounds ("Renditions") that even worked with embedded mp3 in another product, but the generated structure in the PDF is even more complex.
COSStream soundStream = new COSStream();
OutputStream os = soundStream.createOutputStream(COSName.FLATE_DECODE);
URL url = new URL("http://cd.textfiles.com/hackchronii/WAV/ALBUNDY1.WAV");
InputStream is = url.openStream();
// FileInputStream is = new FileInputStream(".....WAV");
IOUtils.copy(is, os);
is.close();
os.close();
// See p. 506 in PDF spec, Table 294
soundStream.setInt(COSName.C, 1); // channels
soundStream.setInt(COSName.R, 22050); // sampling rate
//soundStream.setString(COSName.E, "Signed"); // The encoding format for the sample data
soundStream.setInt(COSName.B, 8); // The number of bits per sample value per channel. Default value: 8
// soundStream.setName(COSName.CO, "MP3"); // doesn't work
PDActionSound actionSound = new PDActionSound();
actionSound.getCOSObject().setItem(COSName.getPDFName("Sound"), soundStream);
link.setAction(actionSound);
Update 9.7.2016:
We discussed this on the PDFBox mailing list, and thanks to Gilad Denneboom we know two more things:
1) in Adobe Acrobat it only lets you select either WAV or AIF files
2) code by Gilad Denneboom with MP3SPI to convert MP3 to raw:
private static InputStream getAudioStream(String filename) throws Exception {
File file = new File(filename);
AudioInputStream in = AudioSystem.getAudioInputStream(file);
AudioFormat baseFormat = in.getFormat();
AudioFormat decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_UNSIGNED,
baseFormat.getSampleRate(),
baseFormat.getSampleSizeInBits(),
baseFormat.getChannels(),
baseFormat.getChannels(),
baseFormat.getSampleRate(),
false);
return AudioSystem.getAudioInputStream(decodedFormat, in);
}

java.io.IOException: mark/reset not supported

try {
//String location = dir1.getCanonicalPath()+"\\app_yamb_test1\\mySound.au";
//displayMessage(location);
AudioInputStream audio2 = AudioSystem.getAudioInputStream(getClass().getResourceAsStream("mySound.au"));
Clip clip2 = AudioSystem.getClip();
clip2.open(audio2);
clip2.start();
} catch (UnsupportedAudioFileException uae) {
System.out.println(uae);
JOptionPane.showMessageDialog(null, uae.toString());
} catch (IOException ioe) {
System.out.println("Couldn't find it");
JOptionPane.showMessageDialog(null, ioe.toString());
} catch (LineUnavailableException lua) {
System.out.println(lua);
JOptionPane.showMessageDialog(null, lua.toString());
}
This code works fine when I run the application from netbeans. The sound plays and there are no exceptions. However, when I run it from the dist folder, the sound does not play and I get the java.io.IOException: mark/reset not supported in my message dialog.
How can I fix this?
The documentation for AudioSystem.getAudioInputStream(InputStream) says:
The implementation of this method may
require multiple parsers to examine
the stream to determine whether they
support it. These parsers must be able
to mark the stream, read enough data
to determine whether they support the
stream, and, if not, reset the
stream's read pointer to its original
position. If the input stream does not
support these operation, this method
may fail with an IOException.
Therefore, the stream you provide to this method must support the optional mark/reset functionality. Decorate your resource stream with a BufferedInputStream.
//read audio data from whatever source (file/classloader/etc.)
InputStream audioSrc = getClass().getResourceAsStream("mySound.au");
//add buffer for mark/reset support
InputStream bufferedIn = new BufferedInputStream(audioSrc);
AudioInputStream audioStream = AudioSystem.getAudioInputStream(bufferedIn);
After floundering about for a while and referencing this page many times, I stumbled across this which helped me with my problem. I was initially able to load a wav file, but subsequently only could play it once, because it could not rewind it due to the "mark/reset not supported" error. It was maddening.
The linked code reads an AudioInputStream from a file, then puts the AudioInputStream into a BufferedInputStream, then puts that back into the AudioInputStream like so:
audioInputStream = AudioSystem.getAudioInputStream(new File(filename));
BufferedInputStream bufferedInputStream = new BufferedInputStream(audioInputStream);
audioInputStream = new AudioInputStream(bufferedInputStream, audioInputStream.getFormat(), audioInputStream.getFrameLength());
And then finally it converts the read data to a PCM encoding:
audioInputStream = convertToPCM(audioInputStream);
With convertToPCM defined as:
private static AudioInputStream convertToPCM(AudioInputStream audioInputStream)
{
AudioFormat m_format = audioInputStream.getFormat();
if ((m_format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) &&
(m_format.getEncoding() != AudioFormat.Encoding.PCM_UNSIGNED))
{
AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
m_format.getSampleRate(), 16,
m_format.getChannels(), m_format.getChannels() * 2,
m_format.getSampleRate(), m_format.isBigEndian());
audioInputStream = AudioSystem.getAudioInputStream(targetFormat, audioInputStream);
}
return audioInputStream;
}
I believe they do this because BufferedInputStream handles mark/reset better than audioInputStream. Hope this helps somebody out there.
Just came across this question from someone else with the same problem who referenced it. Looks like this issue arose with Java 7.
Oracle Bug database, #7095006
A test, executed when InputStream is the argument to the getAudioInputStream() method, is triggering the error. The existence of Mark/Reset capabilities in the audio resource file have no bearing on whether the Clip will load and play. Given that, there is no reason to prefer an InputStream as the argument, when a URL or File suffice.
If we substitute a URL as the argument, this needless test is not executed. Revising the OP code:
AudioInputStream ais = AudioSystem.getAudioInputStream(getClass().getResource(fileName));
Details can be seen in the API, in the description text for the two forms.
AudioSystem.getAudioInputStream(InputStream)
AudioSystem.getAudioInputStream(URL)
The problem is that you're input stream has to support the methods mark and reset. At least if mark is supported you can test with: AudioInputStream#markSupported.
So you should maybe use a different InputStream.

Specifying start/stop time in millisecs when playing MP3 using JLayer

I need to play a part of an MP3 file in my java code. I wish to do this via a function which accepts the start and stop time in millisecs.
JLayer contains a class called AdvancedPlayer which has a method that accepts the start and stop position in frames:
/**
* Plays a range of MPEG audio frames
* #param start The first frame to play
* #param end The last frame to play
* #return true if the last frame was played, or false if there are more frames.
*/
public boolean play(final int start, final int end) throws JavaLayerException
{
boolean ret = true;
int offset = start;
while (offset-- > 0 && ret) ret = skipFrame();
return play(end - start);
}
According to this, a frame lasts 26millisecs. However I need a finer degree of control than this, i.e. I may wish to play from 40millisecs to 50millisecs.
How can I do this? Do I need to convert the MP3 to .wav first?
The solution I used in the end was to first write the code to play a part of a wave file (i.e. from xxx ms to xxx ms) as I also need support for this file format. Here's the code for that:
File soundFile = new File(this.audioFilePath);
AudioInputStream originalAudioInputStream = AudioSystem.getAudioInputStream(soundFile);
AudioFormat audioFormat = originalAudioInputStream.getFormat();
float startInBytes = (startTimeinMs / 1000 * audioFormat.getSampleRate() * audioFormat.getFrameSize());
float lengthInFrames = ((endTimeinMs - startTimeinMs) / 1000 * audioFormat.getSampleRate());
originalAudioInputStream.skip((long) startInBytes);
AudioInputStream partAudioInputStream = new AudioInputStream(originalAudioInputStream,
originalAudioInputStream.getFormat(), (long) lengthInFrames);
// code to actually play the audio input stream here
Once this was working I wrote this code to convert an MP3 to a temporary wave file (which I can then use with the above code) - this is using JLayer and MP3SPI. I did try simply performing the above directly on the converted audio stream without first writing out to a file but couldn't get it to work. I'm only using small MP3 files that convert/write out instantly so I'm happy with this solution.
File soundFile = new File(this.inputFilePath);
AudioInputStream mp3InputStream = AudioSystem.getAudioInputStream(soundFile);
AudioFormat baseFormat = mp3InputStream.getFormat();
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16, baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
AudioInputStream convertedAudioInputStream = AudioSystem.getAudioInputStream(decodedFormat, mp3InputStream);
File outputFile = new File(this.outputFilePath);
AudioSystem.write(convertedAudioInputStream, AudioFileFormat.Type.WAVE, outputFile);
If 26 milliseconds is the finest resolution you can achieve in an MP3 file, then you're out of luck. Converting it to WAV might work, but the source data (i.e. the MP3) stil has that basic resolution limit.
Out of curiosity, why do you want to play 10 milliseconds worth of audio?

Categories