基于Go语言编写一个能在Windows上录音的小程序

 更新时间:2026年03月03日 09:55:07   作者:Mgx  
这篇文章主要为大家详细介绍了如何基于Go语言编写一个能在Windows上录音的小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

大家好!今天我要带大家用 Go 语言写一个能在 Windows 上录音的小程序。别紧张,这不是什么黑客工具(虽然听起来有点像),而是一个正经的、能生成 output.wav 文件的"声音捕捉器"——比如录下你早上对着电脑喊"为什么又报错了!"的珍贵瞬间 。

使用的Go库

这个项目用到了两个非常酷的 Go 库:

  • github.com/Onelio/winmm:让你在 Windows 上调用经典的 winmm.dll 多媒体 API(没错,就是那个 Win95 时代就存在的老古董,但它依然好用!)
  • github.com/go-audio/wav:帮你把原始音频数据打包成标准的 WAV 文件。

话不多说,咱们直接上"操作"!

第一步:看看你的电脑有哪些"耳朵"和"嘴巴"

程序启动后,它会先列出你电脑上所有的输入设备(麦克风)和输出设备(扬声器):

输入设备: 0 麦克风 (Realtek Audio)
输入设备: 1 立体声混音 (Realtek Audio)
输出设备: 0 扬声器 (Realtek Audio)
输出设备: 1 耳机 (Bluetooth Device)

然后它会坏笑着等你按回车——仿佛在说:"准备好了吗?我要开始偷听你了哦~"

第二步:开始录音

程序会以 8kHz 采样率、16位深度、立体声 的格式录音。虽然音质比不上 Hi-Res,但录个语音备忘、猫叫、或者你模仿 Siri 的声音绰绰有余。

录音过程中,你随时按回车就能停止。程序会把录到的所有声音,乖乖写进一个叫 output.wav 的文件里。

小知识:8kHz 是电话音质,但对语音识别或简单录音完全够用,而且文件小!

第三步:播放你的"高光时刻"

录完后,双击 output.wav,Windows 自带的播放器就会打开。

  • 如果你录的是"啊——测试测试",那恭喜你,成功了!
  • 如果你录的是"老板根本不懂技术",建议立刻删除文件并装作无事发生 。

为什么这个代码有点"复古"?

因为底层用的是 Windows 的 WaveIn API,这可是上世纪 90 年代的产物!但它稳定、简单、无需管理员权限,特别适合做小型录音工具。Go 语言通过 cgo 或 syscall 封装后,用起来居然还挺顺手。

不过要注意:这段代码只能在 Windows 上跑。Mac 和 Linux 用户请绕道,或者考虑用 PortAudio 之类的跨平台库。

完整源码

下面就是我们精心整理、注释全中文、风格清爽的录音小工具源码:

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/Onelio/winmm"
	"github.com/go-audio/audio"
	"github.com/go-audio/wav"
)

func main() {
	// 列出所有输入设备
	inputDevices, _ := winmm.EnumInDevices()
	for _, dev := range inputDevices {
		fmt.Println("输入设备:", dev.Id(), dev.Name())
	}

	// 列出所有输出设备
	outputDevices, _ := winmm.EnumOutDevices()
	for _, dev := range outputDevices {
		fmt.Println("输出设备:", dev.Id(), dev.Name())
	}

	// 等待用户按回车继续
	fmt.Println("按回车键开始录音...")
	_, _ = fmt.Scanln()

	// 1. 创建录音所需的音频格式:立体声(2通道)、8kHz 采样率、16位深度
	waveFormat := winmm.NewWaveFormat(winmm.ChStereo, winmm.SpS08kHz, winmm.BpS16)

	// 创建用于录音的缓冲区,时长为 2 秒
	recordBuffer := winmm.NewWaveHeader(waveFormat, 2)

	// 创建录音对象并打开默认录音设备(WaveMapper)
	recorder := winmm.NewWaveIn()
	_ = recorder.Open(winmm.WaveMapper, waveFormat)

	// 准备缓冲区,并获取其唯一标识 key(用于后续操作)
	bufferKey, _ := recorder.PrepareBuffer(recordBuffer)

	fmt.Println("正在录音...(按回车键停止)")

	// 将缓冲区添加到录音设备,并开始录音
	_ = recorder.AddBuffer(bufferKey)
	_ = recorder.Start()

	// 稍微延迟,确保录音已开始
	time.Sleep(200 * time.Millisecond)

	// 启动一个 goroutine,监听用户是否按下回车键以停止录音
	shouldStop := false
	go func() {
		_, _ = fmt.Scanln()
		shouldStop = true
	}()

	// 创建输出 WAV 文件
	outFile, err := os.Create("output.wav")
	if err != nil {
		log.Fatal("无法创建输出文件:", err)
	}
	defer outFile.Close()

	// 创建 WAV 编码器:8kHz、16位、2通道(立体声)、1 块(通常为 1)
	encoder := wav.NewEncoder(outFile, 8000, 16, 2, 1)

	// 初始化用于写入的音频缓冲区
	writeBuffer := audio.IntBuffer{
		Format: &audio.Format{
			NumChannels: 2,   // 立体声
			SampleRate:  8000, // 8kHz 采样率
		},
	}

	// 持续监听录音数据,直到用户停止
	for !shouldStop {
		select {
		case data := <-recorder.Channel:
			// 将接收到的原始字节数据转换为 int16 样本,并追加到 writeBuffer
			copyDataToBuffer(data.GetBufferSlice(), &writeBuffer)
			// 重新将缓冲区加入录音队列(循环使用)
			_ = recorder.AddBuffer(bufferKey)
			_ = recorder.Start()
		default:
			// 短暂休眠,避免忙等待
			time.Sleep(10 * time.Millisecond)
		}
	}

	// 停止录音后,释放缓冲区
	_ = recorder.UnPrepareBuffer(bufferKey)
	// 关闭录音设备
	_ = recorder.Close()

	// 将录制的音频数据写入 WAV 文件(包含 RIFF 头和 PCM 数据)
	if err := encoder.Write(&writeBuffer); err != nil {
		log.Fatal("写入 WAV 文件失败:", err)
	}
	if err := encoder.Close(); err != nil {
		log.Fatal("关闭 WAV 编码器失败:", err)
	}

	fmt.Println("录音已保存为 output.wav")
}

// copyDataToBuffer 将原始字节数据(小端序 int16)转换为 audio.IntBuffer 所需的 int 切片
func copyDataToBuffer(data []byte, buffer *audio.IntBuffer) {
	reader := bytes.NewReader(data)
	for {
		var sample int16
		err := binary.Read(reader, binary.LittleEndian, &sample)
		switch {
		case err == io.EOF:
			return // 读取完毕
		case err != nil:
			log.Println("读取音频样本时出错:", err)
			return
		}
		// 将 int16 转为 int 并追加到缓冲区
		buffer.Data = append(buffer.Data, int(sample))
	}
}

小提醒(认真脸)

  • 代码中为了简洁,忽略了大部分错误处理。实际项目中请务必加上!
  • 录音需要麦克风权限,Windows 可能会弹出隐私提示。
  • 如果你录下了什么不可描述的内容……后果自负,本人概不负责

结语

用 Go 在 Windows 上录音,听起来是不是有点"跨界"?但正是这种混搭,才让编程充满乐趣。下次你可以在这个基础上加个 GUI、自动上传到云盘,甚至做个"语音日记"小工具。

好了,我去试试录下我家母老虎打呼的声音了。你呢?打算录点啥?

你的声音,值得被保存——哪怕是吐槽代码的那一刻。

到此这篇关于基于Go语言编写一个能在Windows上录音的小程序的文章就介绍到这了,更多相关Go语言实现录音内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go实现凯撒密码加密解密

    Go实现凯撒密码加密解密

    这篇文章主要为大家介绍了Go实现凯撒密码加密解密示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Go语言语法基础之算术符示例详解

    Go语言语法基础之算术符示例详解

    这篇文章主要介绍了Go语言语法基础之算术符示例详解,详细讲解算术、关系、逻辑、位、赋值及其他运算符的用法与示例,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-06-06
  • go打印%v %+v %#v的区别及说明

    go打印%v %+v %#v的区别及说明

    文章总结了Go语言中fmt包中%v、%+v和%#v格式化动词的用法:%v只输出值,%+v输出字段名和值,%#v输出结构体名和字段信息
    2025-12-12
  • go语言中strings包的用法汇总

    go语言中strings包的用法汇总

    Golang语言 strings标准库包主要涉及字符串的基本操作,下面我们来详细分析下吧
    2018-10-10
  • 深入理解Go语言实现多态 

    深入理解Go语言实现多态 

    本文主要介绍了Go语言实现多态,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • golang中的net/rpc包使用概述(小结)

    golang中的net/rpc包使用概述(小结)

    本篇文章主要介绍了golang中的net/rpc包使用概述(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Go语言中多字节字符的处理方法详解

    Go语言中多字节字符的处理方法详解

    这篇文章主要给大家介绍了关于Go语言中多字节字符的处理方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-10-10
  • 详解Go语言中配置文件使用与日志配置

    详解Go语言中配置文件使用与日志配置

    这篇文章主要为大家详细讲解一下Go语言中调整项目目录结构、增加配置文件使用和增加日志配置的方法,文中示例代码讲解详细,需要的可以参考一下
    2022-06-06
  • 浅谈Golang的方法传递值应该注意的地方

    浅谈Golang的方法传递值应该注意的地方

    这篇文章主要介绍了浅谈Golang的方法传递值应该注意的地方,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go实现将任何网页转化为PDF

    Go实现将任何网页转化为PDF

    在许多应用场景中,可能需要将网页内容转化为 PDF 格式,使用Go编程语言,结合一些现有的库,可以非常方便地实现这一功能,下面我们就来看看具体实现方法吧
    2024-11-11

最新评论