Asked  7 Months ago    Answers:  5   Viewed   34 times

How can I play an .mp3 and a .wav file in my Java application? I am using Swing. I tried looking on the internet, for something like this example:

public void playSound() {
    try {
        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("D:/MusicPlayer/fml.mp3").getAbsoluteFile());
        Clip clip = AudioSystem.getClip();
        clip.open(audioInputStream);
        clip.start();
    } catch(Exception ex) {
        System.out.println("Error with playing sound.");
        ex.printStackTrace();
    }
}

But, this will only play .wav files.

The same with:

http://www.javaworld.com/javaworld/javatips/jw-javatip24.html

I want to be able to play both .mp3 files and .wav files with the same method.

 Answers

62

Java FX has Media and MediaPlayer classes which will play mp3 files.

Example code:

String bip = "bip.mp3";
Media hit = new Media(new File(bip).toURI().toString());
MediaPlayer mediaPlayer = new MediaPlayer(hit);
mediaPlayer.play();

You will need the following import statements:

import java.io.File;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
Tuesday, June 1, 2021
 
maniclorn
answered 7 Months ago
28

As far as I know, there are only two kinds of functions, destructive and constructive.

While constructive function, as the name implies, constructs something, a destructive one destroys something, but not in the way you may think now.

For example, the function

Function<Integer,Integer> f = (x,y) -> x + y  

is a constructive one. As you need to construct something. In the example you constructed the tuple (x,y). Constructive functions have the problem, of being not able to handle infinite arguments. But the worst thing is, you can't just leave an argument open. You can't just say "well, let x := 1" and try out every y you may like to try. You have to construct every time the whole tuple with x := 1. So if you like to see what the functions return for y := 1, y := 2, y := 3 you have to write f(1,1) , f(1,2) , f(1,3).

In Java 8, constructive functions should be handled (most of the time) by using method references because there's not much advantage of using a constructive lambda function. They are a bit like static methods. You can use them, but they have no real state.

The other type is the destructive one, it takes something and dismantles it as far as needed. For example, the destructive function

Function<Integer, Function<Integer, Integer>> g = x -> (y -> x + y) 

does the same as the function f which was constructive. The benefits of a destructive function are, you can handle now infinite arguments, which is especially convenient for streams, and you can just leave arguments open. So if you again want to see what would the result be like if x := 1 and y := 1 , y := 2 , y := 3 , you can say h = g(1) and h(1) is the result for y := 1, h(2) for y := 2 and h(3) for y := 3.

So here you have a fixed state! That's quite dynamic and that's most of the time that what we want from a lambda.

Patterns like Factory are a lot easier if you can just put in a function which does the work for you.

Destructive ones are easily combined with each other. If the type is right you can just compose them as you like. Using that, you can easily define morphisms which make (with immutable values) testing a lot easier!

You can do that too with a constructive one, but destructive composition looks nicer and more like a list or a decorator, and the constructive one looks a lot like a tree. And things like backtracking with constructive functions are just not nice. You can just save the partial functions of a destructive one (dynamic programming), and on "backtrack" just use the old destructive function. That makes code a lot smaller and better readable. With constructive functions you have more or less to remember all arguments, which can be a lot.

So why is there a need for BiFunction should be more of question than why there is no TriFunction?

First of all, a lot of time you just have a few values (less than 3) and need just a result, so a normal destructive function would not be needed at all, a constructive one would do fine. And there are things like monads which really needs a constructive function. But aside from that, there are not really a lot of good reasons why there is a BiFunction at all. Which doesn't mean it should be removed! I fight for my Monads until I die!

So if you have a lot of arguments, which you can't combine into a logical container class, and if you need the function to be constructive, use a method reference. Otherwise try to use the new gained ability of destructive functions, you may find yourself doing a lot of things with a lot less code lines.

Thursday, June 3, 2021
 
Gregosaurus
answered 6 Months ago
38
public static byte [] getAudioDataBytes(byte [] sourceBytes, AudioFormat audioFormat) throws UnsupportedAudioFileException, IllegalArgumentException, Exception{
        if(sourceBytes == null || sourceBytes.length == 0 || audioFormat == null){
            throw new IllegalArgumentException("Illegal Argument passed to this method");
        }

        ByteArrayInputStream bais = null;
        ByteArrayOutputStream baos = null;
        AudioInputStream sourceAIS = null;
        AudioInputStream convert1AIS = null;
        AudioInputStream convert2AIS = null;

        try{
            bais = new ByteArrayInputStream(sourceBytes);
            sourceAIS = AudioSystem.getAudioInputStream(bais);
            AudioFormat sourceFormat = sourceAIS.getFormat();
            AudioFormat convertFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), 16, sourceFormat.getChannels(), sourceFormat.getChannels()*2, sourceFormat.getSampleRate(), false);
            convert1AIS = AudioSystem.getAudioInputStream(convertFormat, sourceAIS);
            convert2AIS = AudioSystem.getAudioInputStream(audioFormat, convert1AIS);

            baos = new ByteArrayOutputStream();

            byte [] buffer = new byte[8192];
            while(true){
                int readCount = convert2AIS.read(buffer, 0, buffer.length);
                if(readCount == -1){
                    break;
                }
                baos.write(buffer, 0, readCount);
            }
            return baos.toByteArray();
        } catch(UnsupportedAudioFileException uafe){
            //uafe.printStackTrace();
            throw uafe;
        } catch(IOException ioe){
            //ioe.printStackTrace();
            throw ioe;
        } catch(IllegalArgumentException iae){
            //iae.printStackTrace();
            throw iae;
        } catch (Exception e) {
            //e.printStackTrace();
            throw e;
        }finally{
            if(baos != null){
                try{
                    baos.close();
                }catch(Exception e){
                }
            }
            if(convert2AIS != null){
                try{
                    convert2AIS.close();
                }catch(Exception e){
                }
            }
            if(convert1AIS != null){
                try{
                    convert1AIS.close();
                }catch(Exception e){
                }
            }
            if(sourceAIS != null){
                try{
                    sourceAIS.close();
                }catch(Exception e){
                }
            }
            if(bais != null){
                try{
                    bais.close();
                }catch(Exception e){
                }
            }
        }
    }

Here sourceBytes represents MP3 file or WAV file. audioFormat is PCM format in which you want conversion. Also we need to put mp3spi.jar, tritonus_mp3.jar, jl*.jar, tritonus_share.jar from javazoom.com in classpath. Hope this may help to other.

Java 7 version:

public static byte [] getAudioDataBytes(byte [] sourceBytes, AudioFormat audioFormat) throws UnsupportedAudioFileException, IllegalArgumentException, Exception {
    if(sourceBytes == null || sourceBytes.length == 0 || audioFormat == null){
        throw new IllegalArgumentException("Illegal Argument passed to this method");
    }

    try (final ByteArrayInputStream bais = new ByteArrayInputStream(sourceBytes);
         final AudioInputStream sourceAIS = AudioSystem.getAudioInputStream(bais)) {
        AudioFormat sourceFormat = sourceAIS.getFormat();
        AudioFormat convertFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), 16, sourceFormat.getChannels(), sourceFormat.getChannels()*2, sourceFormat.getSampleRate(), false);
        try (final AudioInputStream convert1AIS = AudioSystem.getAudioInputStream(convertFormat, sourceAIS);
             final AudioInputStream convert2AIS = AudioSystem.getAudioInputStream(audioFormat, convert1AIS);
             final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte [] buffer = new byte[8192];
            while(true){
                int readCount = convert2AIS.read(buffer, 0, buffer.length);
                if(readCount == -1){
                    break;
                }
                baos.write(buffer, 0, readCount);
            }
            return baos.toByteArray();
        }
    }
}

Maven:

<dependency>
    <groupId>com.googlecode.soundlibs</groupId>
    <artifactId>mp3spi</artifactId>
    <version>1.9.5-1</version>
</dependency>
<dependency>
    <groupId>com.googlecode.soundlibs</groupId>
    <artifactId>jlayer</artifactId>
    <version>1.0.1-1</version>
    <exclusions>
        <exclusion>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </exclusion>
    </exclusions>
</dependency>
Thursday, July 29, 2021
 
Nickool
answered 4 Months ago
44

Read your wave file @ http://java.sun.com/javase/technologies/desktop/media/jmf/ and encode to mp3 @ http://openinnowhere.sourceforge.net/lameonj/

As pointed out, lameonj is not a pure java solution. For that the options don't seem so many, but see the other SO question: MP3 Encoding in Java

Wednesday, August 11, 2021
 
iceduck
answered 4 Months ago
66

It might be because the input streams cannot be read more than once. Once you read an input stream, it will be at its end and attempt to read further will read no more bytes from that stream.

This should work with a slight modification, keep creating new audio input streams in your loop:

File sample1 = new File("f1.wav");
File sample2 = new File("f2.wav");

File fileOut = new File("combined.wav");

AudioInputStream audio1 = AudioSystem.getAudioInputStream(sample1);
AudioInputStream audio2 = AudioSystem.getAudioInputStream(sample2);

AudioInputStream audioBuild = new AudioInputStream(new SequenceInputStream(audio1, audio2), audio1.getFormat(), audio1.getFrameLength() + audio2.getFrameLength());

for(int i = 0; i < 5; i++)
{
    audioBuild = new AudioInputStream(new SequenceInputStream(audioBuild, /* keep creating new input streams */ AudioSystem.getAudioInputStream(sample2)), audioBuild.getFormat(), audioBuild.getFrameLength() + audio2.getFrameLength());
}

AudioSystem.write(audioBuild, AudioFileFormat.Type.WAVE, fileOut);

Also, ensure your audio formats for the files are exactly the same. That is, same sample rate, same channel count, same bits per sample. Otherwise you'll need additional code to do sample conversion.

Monday, November 22, 2021
 
Bob
answered 1 Week ago
Bob
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share