java - 无法从 AudioInputStream 读取单个字节

标签 java audio

我尝试使用 javax.sound library. 更改 wav 文件的采样率

实现我想要的方法后,我尝试了一下,它成功了! 但创建的 .wav 文件只有几个字节大。确切地说,它只有 2.090 字节,原来约为 50 MB

问题是,Java 无法从我打开的 AudioInputStream 中读取单个字节。

仅供引用,使用的文件是用JLayer转换mp3文件的产物。它工作正常,JLayer 没有问题,但我想如果我发布我的整个源代码会更好。注意:我使用了许多 System.out.printlns 来记录日志。

所以首先我导入了所有需要的库,正如你所看到的,我还导入了 JLayer。

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

import javax.sound.sampled.*;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JOptionPane;

import javazoom.jl.converter.Converter;
import javazoom.jl.decoder.JavaLayerException;

public class MyConverter {

    private static AudioInputStream lowResAis = null;
    private static AudioInputStream audioInputStream = null;

设置这些全局常量后,我正在编写主文件并预先选择了一个演示文件用于测试目的。

    public static void main(String[] args) {
        MyConverter converterdemo = new MyConverter();
        String wavfilepath = "C:\\Users\\JohnDoe\\Desktop\\Second Nature.wav";
        File f = new File(wavfilepath);
        converterdemo.convertMp3toWav("C:\\Users\\JohnDoe\\Desktop\\Second Nature.mp3", "C:\\Users\\JohnDoe\\Desktop\\Second Nature.wav");
        converterdemo.compressWavFile(wavfilepath);
        converterdemo.writeToSoundFile(f);
        System.out.println("Everything worked!");
    }

这是我的转换方法

public void convertMp3toWav(String sourcefilename, String targetfilename){
        Converter con = new Converter();
        try {
            con.convert(sourcefilename, targetfilename);
            System.out.println("Wav File converted!");
        } catch (JavaLayerException e) {
            this.showOptionPane("Could not convert by using JLayer!");
        }
    }

转换方法没问题(相信我,音频文件没有问题),但这是我有点担心的方法

添加此行后:System.out.println(AudioSystem.getAudioFileFormat(audioInputStream).getByteLength());

我收到以下错误:java.io.IOException:如果帧大小 > 1,则无法读取单个字节

我无法从自己的流中读取内容。

public void compressWavFile(String sourcefilename){
        try {
            InputStream musicfile = new BufferedInputStream(new FileInputStream(sourcefilename));
        audioInputStream = AudioSystem.getAudioInputStream(musicfile);
            AudioFormat format = audioInputStream.getFormat();
            AudioFormat outDataFormat = new AudioFormat((float) 22000.0,
                    (int) 16, (int) 1, true, false);
            if(AudioSystem.isConversionSupported(outDataFormat, format)){
                System.out.println("Conversion Supported!");
                lowResAis = AudioSystem.getAudioInputStream(outDataFormat, audioInputStream);
            }
            System.out.println("low res created!");
        } catch (UnsupportedAudioFileException e) {
            this.showOptionPane("Audio File not Supported!"); e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

我故意没有对资源使用 try ,因为某些魔法,新创建的 AudioInputStream 在关闭原始 audioInputStream (现在是一个静态变量)后也会关闭。

public void writeToSoundFile(File out){
        if(AudioSystem.isFileTypeSupported( AudioFileFormat.Type.WAVE, lowResAis)){
            try {
                AudioSystem.write(lowResAis,  AudioFileFormat.Type.WAVE, out);
                System.out.println("New wav file written!");
            } catch (IOException e) {
                e.printStackTrace();
                this.showOptionPane("Could not write to new Audio File!");
            }
        }
        try {
            System.out.println("closing stream!");
            lowResAis.close();
            audioInputStream.close();

        } catch (IOException e) {
            this.showOptionPane("Could not close Audio Stream!");
            e.printStackTrace();
        }
    }

最后一位仅用于将新创建的 AudioInputStream 写入给定的File。我也不认为这里会出现任何问题。

我确实认为我的 AudioInputStreams 有问题,因为这是唯一可能出错的地方。

编辑:

我添加了一个新的“showOptionPane”方法来始终保持线程安全

private void showOptionPane(String msg){
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                JOptionPane.showMessageDialog(null, msg, "Error",
                        JOptionPane.ERROR_MESSAGE);
            }

        });
    }

最佳答案

我不是音频专业人士,但环顾四周后,错误消息似乎更有意义。

音频并不完全是字节流,而是帧流;其中整个帧旨在加载到播放系统中,因为它代表某一时刻的输出或输入值。

这个框架似乎针对读取帧进行了优化。因此,它可能会让您使用 getBytes(...) 方法读取一个或多个帧,在该方法中您指定一个相当大的字节缓冲区来写入多个帧。显然它不跟踪子帧加载,因为从音频角度来看使用帧的一部分没有意义。

如果您可以将帧大小调整为 1,您可能会读取单个字节;但是,你无法压缩它。压缩例程将整个帧相互压缩。因此,我建议您最少读出整个帧,除非重点是遍历帧中的每个字节。

如果重点是遍历字节,那么我会避免将其视为音频,而会将其视为字节流。

因此,您的方法可能必须更改为以帧为中心的方法,因为这是大多数音频框架处理的最小音频单元。

关于java - 无法从 AudioInputStream 读取单个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32487959/

相关文章:

java - 不要更改对具有级联 ="all-delete-orphan"的集合的引用

java - JPA 仅选择每个项目的最近日期

javascript - HTML5在手机中的应用

audio - 如何使用 ffmpeg 在视频中添加新音频(不混合)?

javascript - javascript音频方法的文档?

java - 从枚举常量内部运行Runnable以播放声音

java - 服务器不响应使用 Java 的 HTTP/1.1 客户端中的并发请求

java - 如何在TreeMap中使用部分键搜索值

audio - Web Audio API 注意事项

java - 比较耶拿的两个 OntModel