Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 有人能解释一下.wav(WAVE)文件头吗?_Java_Audio_Header_Byte_Wav - Fatal编程技术网

Java 有人能解释一下.wav(WAVE)文件头吗?

Java 有人能解释一下.wav(WAVE)文件头吗?,java,audio,header,byte,wav,Java,Audio,Header,Byte,Wav,好的,我正在尝试制作一个可以处理.wav文件的程序,我已经看到了,但是我不能完全确定头中的每一条数据是指什么。例如,“块”指的是什么?这是一个特定的位/字节数吗 如果有人能告诉我,至少在这个问题中使用的格式中,除了常量字符串文本和“数据”数组之外,每个写入.wav的数据是指什么?特别是,我想知道什么是“块”,以及所有通道的采样率、字节率、每个采样的字节数和每个采样的字节数之间的关系?(我怀疑字节率是采样率*每个采样的字节数,但“所有通道”的情况如何?) 非常感谢您的帮助。仅发布链接是违反董事会规

好的,我正在尝试制作一个可以处理.wav文件的程序,我已经看到了,但是我不能完全确定头中的每一条数据是指什么。例如,“块”指的是什么?这是一个特定的位/字节数吗

如果有人能告诉我,至少在这个问题中使用的格式中,除了常量字符串文本和“数据”数组之外,每个写入.wav的数据是指什么?特别是,我想知道什么是“块”,以及所有通道的采样率、字节率、每个采样的字节数和每个采样的字节数之间的关系?(我怀疑字节率是采样率*每个采样的字节数,但“所有通道”的情况如何?)


非常感谢您的帮助。

仅发布链接是违反董事会规则的,因此这是我从中获取的表格

定位样本值描述
1-4“RIFF”将文件标记为RIFF文件。每个字符都是1。字节长。
5-8文件大小(整数)整个文件的大小-8字节,以字节为单位(32位整数)。通常,您会在创建后填写此信息。
9-12“WAVE”文件类型标题。就我们而言,它总是等于“波”。
13-16“fmt”格式块标记。包括尾随null
17-20 16上述格式数据的长度
21-22 1种格式(1为PCM)-2字节整数
23-24 2个通道数-2字节整数
25-28 44100采样率-32位整数。常用值为44100(CD)和48000(DAT)。采样率=每秒采样数,或赫兹。
29-32 176400(采样率*比特采样*通道)/8。
33-34 4(位采样*通道)/8.1-8位单声道2-8位立体声/16位单声道4-16位立体声
35-36每个样本16位
37-40“数据”“数据”块头。标记数据节的开头。
41-44数据段的文件大小(数据),即文件大小-44字节头。
上面给出了16位立体声源的样本值

更新/提醒

标头整数都是最低有效字节顺序, 因此,双字节通道信息0x01 0x00实际上是0x00001,例如单声道。

我知道OP将这个问题标记为Java,但下面是完整的Kotlin代码,用于读取可以传递给Java的头。阅读《小恩迪安》可能很棘手,但谢天谢地,我们不必这么做

class WaveHeader(bytes: ByteArray) {
    init {
        require(bytes.size >= SIZE) { "Input size is must be at least $SIZE bytes" }
    }

    private var start = 0
    private val riff = RiffChunk(
        String(bytes.copyOfRange(start, start + 4))
            .also {
                require(it == "RIFF") { "$it must be 'RIFF'" }
                start += it.length
            },
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 4)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.int,
        String(bytes.copyOfRange(start, start + 4))
            .also {
                require(it == "WAVE") { "$it must be 'WAVE'" }
                start += it.length
            }
    )
    private val format = FormatChunk(
        // null terminated
        String(bytes.copyOfRange(start, start + 3))
            .also {
                require(it == "fmt") { "$it must be 'fmt'" }
                start += 4
            },
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 4)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.int,
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 2)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }
            .let { if (it.short == 1.toShort()) "PCM" else "OTHER (${it.short})" },
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 2)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.short,
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 4)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.int,
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 4)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.int,
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 2)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.short,
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 2)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.short
    )
    private val `data` = DataChunk(
        String(bytes.copyOfRange(start, start + 4))
             // remove all null chars
            .replace("\u0000", "")
            .also { start += it.length },
        ByteBuffer.wrap(bytes.copyOfRange(start, start + 4)).order(ByteOrder.LITTLE_ENDIAN)
            .also { start += it.capacity() }.int
    )

    init {
        assert(start == 44) { "Illegal state" }
    }

    data class RiffChunk(val id: String, val size: Int, val format: String)
    data class FormatChunk(
        val id: String, val size: Int, val format: String, val numChannels: Short,
        val sampleRate: Int, val byteRate: Int, val blockAlign: Short, val bitsPerSample: Short
    )

    data class DataChunk(val id: String, val size: Int)

    override fun toString(): String {
        val ls = System.lineSeparator()
        return "WaveHeader($ls\t$riff}$ls\t$format$ls\t$`data`$ls)"
    }

    companion object {
        const val SIZE = 44

        fun fromPath(path: String): WaveHeader  = fromInputStream(WaveHeader::class.java.getResourceAsStream(path))

        fun fromUrl(url: String): WaveHeader  = fromInputStream(URL(url).openStream())

        private fun fromInputStream(input: InputStream): WaveHeader {
            val bytes = input.use {
                it.readNBytes(SIZE)
            }
            return WaveHeader(bytes)
        }
    }
}

fun main(args: Array<String>) {
    if (args.isEmpty()) {
        System.err.println("Argument is missing")
    }
    println(WaveHeader.fromUrl(args[0]))
}

那么
文件大小
值是
32位整数
,分别包含整个文件和数据部分中
8位字节的数量
?是采样率
32位
32字节
,因为如果我没有弄错的话,后者在128位时比需要的大得多。32位采样就是答案。精确地说是4字节的头空间。你可能会找到一些库来为你处理所有的头内容,你所需要做的就是找到它们。如果你使用这些库,你所要担心的就是如何实际操作音频,而不仅仅是如何编码或解码它们。
WaveHeader(
    RiffChunk(id=RIFF, size=168050, format=WAVE)}
    FormatChunk(id=fmt, size=18, format=PCM, numChannels=1, sampleRate=16000, byteRate=32000, blockAlign=2, bitsPerSample=16)
    DataChunk(id=fa, size=1952670054)
)