如何用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
相关产品推荐
相关产品推荐

