基于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语言设计实现在任务栏里提醒你喝水的兔子示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • Gin框架中的路由与请求处理的实现

    Gin框架中的路由与请求处理的实现

    本文主要介绍了Gin框架中的路由与请求处理的实现,包括路径参数、查询参数和路由分组的使用,具有一定的参考价值,感兴趣的可以了解一下
    2025-06-06
  • go开发alertmanger实现钉钉报警

    go开发alertmanger实现钉钉报警

    本文主要介绍了go开发alertmanger实现钉钉报警,通过自己的url实现alertmanager的钉钉报警,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • 完美解决golang go get私有仓库的问题

    完美解决golang go get私有仓库的问题

    这篇文章主要介绍了完美解决golang go get私有仓库的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • 一文带你掌握Golang Interface原理和使用技巧

    一文带你掌握Golang Interface原理和使用技巧

    Golang 中的 interface 是一种非常重要的特性,可以让我们写出更加灵活的代码。在本篇文章中,我们将深入探讨 Golang 中interface 的原理和使用技巧,感兴趣的可以了解一下
    2023-04-04
  • Go strconv包实现字符串与数值转换的深度解析

    Go strconv包实现字符串与数值转换的深度解析

    在 Go 语言开发中,字符串与基本数据类型之间的转换非常常见,Go 标准库中的 strconv 包正是为这些场景设计的,下面小编就和大家详细介绍一下它的具体应用吧
    2026-03-03
  • Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例

    Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例

    这篇文章主要为大家介绍了Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • golang 整合antlr语法校验解析

    golang 整合antlr语法校验解析

    Antlr是一个语法分析器,本身是用java实现的,然是Runtime的库也支持Golang、Java、Python等,本文给大家讲解使用golang整合antlr进行语法解析,感兴趣的朋友一起看看吧
    2023-02-02
  • golang的序列化与反序列化的几种方式

    golang的序列化与反序列化的几种方式

    这篇文章主要介绍了golang的序列化与反序列化的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • Go秒爬博客园100页新闻

    Go秒爬博客园100页新闻

    利用go语言的协程并发优势爬取网页速度相当之快,博客园100页新闻标题只需一秒即可全部爬取,跟着小编一起去看看如何实现的,希望大家可以从中受益
    2018-09-09

最新评论