0

I´m learning how to play sound in java but with advanced controls.

I´ve found one problem: The javax.sound.sampled.AudioInputStream doesn´t support Mp3 files, and i´m running out of ideas to find how to get control of panning.

I managed to play an Mp3 file using javazoom.jl.player.advanced.AdvancedPlayer, but it doesn´t have a panning control, or i haven´t founded it.

My actual code opens a file, if the format is compatible with AudioInputStream, it plays only the right channel. If the format doesn´t, it plays using AdvancedPlayer.

Do you know a way to get panning control of mp3 files?

My code here:

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.advanced.AdvancedPlayer;

import javax.sound.sampled.*;
import javax.swing.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class AudioPlayerExample2 {
    private static final int BUFFER_SIZE = 4096;

    public static void main(String[] args) throws IOException, LineUnavailableException, JavaLayerException {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.showOpenDialog(null);

        new AudioPlayerExample2().play(fileChooser.getSelectedFile());
    }


    void play(File file) throws IOException, LineUnavailableException, JavaLayerException {


        AudioInputStream audioStream;

        try {
            audioStream = AudioSystem.getAudioInputStream(file);

            AudioFormat format = audioStream.getFormat();
            System.err.println(format.toString());

            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

            SourceDataLine audioLine = (SourceDataLine) AudioSystem.getLine(info);

            audioLine.open(format);

            audioLine.start();

            FloatControl pan = (FloatControl) audioLine.getControl(FloatControl.Type.PAN);

            byte[] bytesBuffer = new byte[BUFFER_SIZE];
            int bytesRead = -1;


            while ((bytesRead = audioStream.read(bytesBuffer)) != -1) {
                pan.setValue((float) (1));
                audioLine.write(bytesBuffer, 0, bytesRead);
            }

            audioLine.drain();
            audioLine.close();
            audioStream.close();
        } catch (UnsupportedAudioFileException e) {
            FileInputStream fis = new FileInputStream(file);
            AdvancedPlayer player = new AdvancedPlayer(fis);

            player.play();
        }


    }
}
Radiodef
  • 37,180
  • 14
  • 90
  • 125
Mango
  • 3
  • 1
  • You could also try using the JavaFX media player. (See also https://stackoverflow.com/q/6045384/2891664.) – Radiodef Jul 15 '18 at 17:54
  • *"doesn´t support Mp3 files"* See the [Java Sound info. page](https://stackoverflow.com/tags/javasound/info) under 'Service Provider Interface'. – Andrew Thompson Jul 17 '18 at 21:57

2 Answers2

1

Panning and volume controls are system dependent and can sometimes be a bit flaky even if they are in place. For example, if you change the volume or pan setting too much at once, the discontinuity causes a click.

One solution is to go in there on a per-frame basis and make the changes yourself. For example, see "Manipulating the Audio Data Directly" at the end of the tutorial Processing Audio with Controls.

For an example, check out the code from the next tutorial on the trail: Using Files and Format Converters. Look under the heading "Reading Sound Files" and look for the comment in the code "\ Here, do something useful..."

I invite you to also take a look at the code I wrote and have made available, a class called AudioCue that has real time panning as well as real time volume and pitch playback controls. I've added smoothing (1024 steps for panning changes) to help mitigate the possibility of discontinuities.

It will be up to you to take the mp3 file and decode it into an array of audio data. I think that the javazoom libraries made available on github should give you enough code access to figure out how to do this (I did it for ogg/vorbis decoding). Once you have a float array of audio data (stereo, signed floats ranging from -1 to 1), this can be directly loaded into AudioCue.

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
0

First of all, thanks to Andrew Thompson and Phil Freihofner, I feel very good about being part of this community and having someone to trust. You really make feel happy :)

I leave here the full code that does exactly what I wanted.

As the JavaZoom MP3 SPI Documentation says: Make sure that JLayer, Tritonus and MP3SPI librairies are available in your CLASSPATH.

import javax.sound.sampled.*;
import javax.swing.*;
import java.io.File;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException, 
UnsupportedAudioFileException, LineUnavailableException {
    JFileChooser chooser = new JFileChooser();
    chooser.showOpenDialog(null);
    String path = chooser.getSelectedFile().getAbsolutePath();

    System.err.println(path);
    File file = new File(path);

    AudioInputStream baseStream = AudioSystem.getAudioInputStream(file);

    AudioFormat baseFormat = baseStream.getFormat();

    System.err.println(baseFormat.toString());
    AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 
baseFormat.getSampleRate(),
            16, baseFormat.getChannels(), baseFormat.getChannels() * 2, 
baseFormat.getSampleRate(), true);

    DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

    AudioInputStream stream = AudioSystem.getAudioInputStream(format, baseStream);

    SourceDataLine audioLine = (SourceDataLine) AudioSystem.getLine(info);


    audioLine.open(format);
    audioLine.start();

    FloatControl pan = (FloatControl) audioLine.getControl(FloatControl.Type.PAN);

    pan.setValue(1);

    int BUFFER_SIZE = 4096;

    byte[] buffer = new byte[BUFFER_SIZE];

    int read = -1;

    while((read = stream.read(buffer)) != -1){
        audioLine.write(buffer, 0, read);
    }

    audioLine.drain();
    audioLine.close();
}
}
Mango
  • 3
  • 1