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

Golang从串口流转换单声道PCM至WAV文件遇异常音频问题求助

串口PCM转WAV杂音问题的解决方法

核心问题分析

  • 编码器被提前关闭:循环内部每次调用e.Close(),会直接终止WAV文件的写入流程,第一次循环后文件就被写入结束标记,后续写入无效,重复的头信息还会破坏文件结构。
  • 16位PCM样本解析错误:你设置的是16位采样深度,但代码把每个字节单独当作一个样本处理。16位PCM每个样本占2字节,需要将两个字节合并成一个16位整数(通常为小端字节序),而非拆分单个字节。
  • 忽略串口实际读取字节数:s.Read(buf)返回的读取长度被丢弃,可能导致缓冲区残留旧数据,引入杂音。

修正后的代码

func readAudio() {
    flag.Parse()

    // Output file.
    out, err := os.Create("output.wav")
    if err != nil {
        log.Fatal(err)
    }
    defer out.Close()

    // 8 kHz, 16 bit, 1 channel, WAV.
    e := wav.NewEncoder(out, 8000, 16, 1, 1)
    defer func() {
        // 仅在程序结束时关闭编码器,保证文件结构完整
        if err := e.Close(); err != nil {
            log.Fatal(err)
        }
    }()

    // Program Info
    log.Printf("Starting with port %s at baud rate %d", com, baud)

    // Setup Serial Port
    c := &serial.Config{Name: com, Baud: 115200}
    s, err := serial.OpenPort(c)
    if err != nil {
        log.Fatal(err)
    }
    defer s.Close()

    for {
        log.Print("Reading Bytes in...")

        buf := make([]byte, 320)
        // 记录实际读取的字节数
        n, err := s.Read(buf)
        if err != nil {
            log.Fatal(err)
        }
        // 仅处理实际读取到的数据
        buf = buf[:n]

        // Print Bytes Read
        log.Println(buf)

        audioBuf, err := newAudioIntBuf(buf)
        if err != nil {
            log.Fatal(err)
        }

        // 写入缓冲区到WAV文件
        if err := e.Write(audioBuf); err != nil {
            log.Fatal(err)
        }
    }
}

func newAudioIntBuf(byteBuf []byte) (*audio.IntBuffer, error) {
    buf := audio.IntBuffer{
        Format: &audio.Format{
            NumChannels: 1,
            SampleRate:  8000,
        },
    }

    // 16位PCM每个样本占2字节,按小端序解析
    for i := 0; i < len(byteBuf); i += 2 {
        if i+1 >= len(byteBuf) {
            break // 避免越界,跳过不完整的样本
        }
        // 合并两个字节为16位整数(小端)
        sample := int(int16(byteBuf[i]) | int16(byteBuf[i+1])<<8)
        buf.Data = append(buf.Data, sample)
    }
    return &buf, nil
}

额外说明

  • 串口每次发送320字节是合理的:8kHz采样率、16位单声道下,每秒产生16000字节(8000*2),320字节对应20ms音频数据,属于标准小数据块传输,不会影响结果。
  • 需确保串口发送的PCM数据格式为8kHz、16位、单声道、小端字节序,若发送端格式与接收端解析不一致,仍会出现杂音。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 06:24:03