You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用R的readBin读取24位深度的二进制音频数据?

解决R中读取24位二进制音频数据的报错问题

我太懂这个坑了!你碰到的问题本质是:R的readBin()函数里,double()类型对应的字节长度是固定的(通常是8字节),它根本不支持用3字节来解析双精度浮点数,所以指定size=3才会抛出那个“size 3 is unknown”的错误。

要处理24位深度的音频数据,咱们得换个思路:先读取原始的二进制字节,再手动把每3个字节转换成对应的有符号数值,而不是直接用double()类型去读。下面给你两种可行的解决方案:


方案1:循环处理(适合小文件,逻辑清晰)

先把整个文件读成raw类型的字节向量,再逐组处理每3个字节(对应一个24位音频样本):

# 打开文件连接
file1 <- file("filename.w", "rb")
# 读取所有原始二进制字节
raw_data <- readBin(file1, raw(), n = file.info("filename.w")$size)
# 务必关闭文件连接!
close(file1)

# 定义每个音频样本的字节数(24位=3字节)
chunk_size <- 3
# 计算总样本数(忽略最后不足3字节的部分)
num_samples <- length(raw_data) %/% chunk_size
# 初始化存储最终音频数据的向量
audio_samples <- numeric(num_samples)

# 逐组处理每个24位样本(大端模式)
for (i in 1:num_samples) {
  # 取出当前3个字节(大端顺序:第一个是最高位字节)
  chunk <- raw_data[(i-1)*chunk_size + 1:chunk_size]
  
  # 把24位有符号数扩展为32位:判断最高位是否为1(负数),补对应高位字节
  sign_bit <- as.integer(chunk[1]) >= 128
  extended_chunk <- if (sign_bit) c(0xFF, chunk) else c(0x00, chunk)
  
  # 用readBin解析成32位整数
  int_val <- readBin(extended_chunk, integer(), size = 4, endian = "big", n = 1)
  
  # 归一化到音频常用的-1到1范围(24位的最大值是2^23-1,最小值是-2^23)
  audio_samples[i] <- int_val / 2^23
}

方案2:向量化处理(适合大文件,效率更高)

如果你的音频文件很大,循环会很慢,用向量化操作代替循环能大幅提升速度:

file1 <- file("filename.w", "rb")
raw_data <- readBin(file1, raw(), n = file.info("filename.w")$size)
close(file1)

chunk_size <- 3
num_samples <- length(raw_data) %/% chunk_size

# 把raw数据按3字节一组转成矩阵(每行对应一个字节位,每列对应一个样本)
raw_matrix <- matrix(raw_data, nrow = chunk_size, ncol = num_samples)

# 计算每个样本的整数值(大端模式:第1行是2^16位,第2行是2^8位,第3行是2^0位)
byte_vals <- apply(raw_matrix, 2, as.integer)
int_vals <- byte_vals[1] * 2^16 + byte_vals[2] * 2^8 + byte_vals[3]

# 处理24位有符号数的负数:超过2^23-1的数值是负数,需要减去2^24
int_vals[int_vals >= 2^23] <- int_vals[int_vals >= 2^23] - 2^24

# 归一化到-1到1范围
audio_samples <- int_vals / 2^23

额外提醒

如果你的.w文件是标准WAV格式(不是纯原始二进制数据),那它开头会有44字节的RIFF文件头,你需要先跳过这部分再读取数据:

file1 <- file("filename.w", "rb")
# 跳过WAV文件头
readBin(file1, raw(), n = 44)
# 再读取后面的音频数据
raw_data <- readBin(file1, raw(), n = file.info("filename.w")$size - 44)
close(file1)

当然,如果是标准WAV,更省心的方法是直接用tuneR包的readWave()函数,它会自动处理24位深度:

install.packages("tuneR")
library(tuneR)
audio <- readWave("filename.w")
# 提取样本数据
audio_samples <- audio@left # 单声道取left,立体声可以取left/right

内容的提问来源于stack exchange,提问作者springsun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:12:17