use*_*681 0 java audio byte header wav
好的,因此我正在尝试制作一个可处理.wav文件的程序,并且已经看到了此问题/答案,但是我不确定是标题中的每个数据指的是什么。例如,“块”指的是什么?那是特定数量的位/字节吗?
如果有人能至少以本问题中使用的格式告诉我,除了常量String Literals和“数据”数组之外,每个引用到.wav的数据是什么?特别是,我特别想知道什么是“块”,以及所有通道的采样率,字节率,每个采样的字节和每个采样的字节有何关系?(我怀疑字节速率是采样率*每个采样的字节,但是“针对所有渠道”呢?)
任何帮助表示赞赏。
我知道 OP 将问题标记为 Java,但这里有完整的 Kotlin 代码,用于读取可以传递给 Java 的标头。读取 Little Endian 可能很棘手,但幸运的是我们不必这样做。
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]))
}
Run Code Online (Sandbox Code Playgroud)
使用此URL 运行会产生输出:
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)
)
Run Code Online (Sandbox Code Playgroud)
仅发布链接是违反董事会规则的,所以这是我从http://www.topherlee.com/software/pcm-tut-wavformat.html提取的表格
Positions Sample Value Description
1 - 4 "RIFF" Marks the file as a riff file. Characters are each 1. byte long.
5 - 8 File size (integer) Size of the overall file - 8 bytes, in bytes (32-bit integer). Typically, you'd fill this in after creation.
9 -12 "WAVE" File Type Header. For our purposes, it always equals "WAVE".
13-16 "fmt " Format chunk marker. Includes trailing null
17-20 16 Length of format data as listed above
21-22 1 Type of format (1 is PCM) - 2 byte integer
23-24 2 Number of Channels - 2 byte integer
25-28 44100 Sample Rate - 32 bit integer. Common values are 44100 (CD), 48000 (DAT). Sample Rate = Number of Samples per second, or Hertz.
29-32 176400 (Sample Rate * BitsPerSample * Channels) / 8.
33-34 4 (BitsPerSample * Channels) / 8.1 - 8 bit mono2 - 8 bit stereo/16 bit mono4 - 16 bit stereo
35-36 16 Bits per sample
37-40 "data" "data" chunk header. Marks the beginning of the data section.
41-44 File size (data) Size of the data section, i.e. file size - 44 bytes header.
Run Code Online (Sandbox Code Playgroud)
上面给出了16位立体声源的样本值。
更新/提醒
标头整数都是最低有效字节顺序,因此两个字节通道信息0x01 0x00实际上是0x00001,例如单声道。