如何从 .mp3 文件中获取平移控制?

How to get panning control forma a .mp3 file?

我正在学习如何在 java 中使用高级控件播放声音。

我发现了一个问题:javax.sound.sampled.AudioInputStream 不支持 Mp3 文件,我 运行 想不出如何解决控制平移。

我设法使用 javazoom.jl.player.advanced.AdvancedPlayer 播放了一个 Mp3 文件,但它没有声像控制,或者我还没有创建它。

我的实际代码打开一个文件,如果格式与 AudioInputStream 兼容,它只播放右声道。如果格式不支持,则使用 AdvancedPlayer.

播放

你知道如何获得 mp3 文件的声像控制吗?

我的代码在这里:

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();
        }


    }
}

平移和音量控制取决于系统,即使它们就位,有时也会有点不稳定。例如,如果您一次更改太多音量或声相设置,不连续会导致咔哒声。

一种解决方案是在 per-frame 的基础上进行修改,然后自己进行更改。例如,参见教程末尾的 "Manipulating the Audio Data Directly" Processing Audio with Controls

例如,查看下一个教程中的代码:Using Files and Format Converters。在标题 "Reading Sound Files" 下查找代码中的注释“\ 在这里,做些有用的事情...”

我邀请您也看看我编写并提供的代码,一个名为 AudioCue 的 class,它具有实时声像以及实时音量和音调播放控制.我添加了平滑(1024 步用于平移更改)以帮助减轻不连续的可能性。

将由您来获取 mp3 文件并将其解码为音频数据数组。我认为在 github 上可用的 javazoom 库应该给你足够的代码访问权限来弄清楚如何做到这一点(我为 ogg/vorbis 解码做了它)。一旦你有了音频数据的浮点数组(立体声,带符号的浮点数,范围从 -1 到 1),就可以直接加载到 AudioCue 中。

首先,感谢 Andrew Thompson 和 Phil Freihofner,我很高兴成为这个社区的一员并有一个值得信任的人。你真的很开心:)

我在这里留下了完全符合我要求的完整代码。

正如 JavaZoom MP3 SPI 文档所说:确保 JLayer、Tritonus 和 MP3SPI 库在您的 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();
}
}