go - FLAC和MP3的色印指纹
问题描述
我想使用 Go 中的chromaprint库创建 FLAC 或 MP3 文件的声学指纹。我一直在玩以下两个 Go 库:
使用以下代码,可以创建“原始音频数据流”的指纹(其中reader
类型为io.Reader
):
fpcalc := gochroma.New(gochroma.AlgorithmDefault)
defer fpcalc.Close()
fprint, err := fpcalc.Fingerprint(
fingerprint.RawInfo{
Src: reader,
Channels: 2,
Rate: 44100,
MaxSeconds: 120,
}
)
不幸的是,我无法弄清楚“原始音频数据流”的确切含义(我的猜测:WAVE LPCM 流),但我知道我不能简单地使用打开 FLAC 或 MP3 文件os.Open
并将流传递给fingerprint.RawInfo.Src
. 有一些示例,但这些示例适用于以 . 结尾的文件.raw
。
如何在 Go 中将 FLAC(或辅助 MP3)文件/流转换为原始音频数据流?我的猜测是使用像go-flac这样的 Go FLAC 库,但我不确定从哪里开始。欢迎任何提示!
编辑
通过go-flacGetStreamInfo
应该可以访问 FLAC 文件的原始音频数据,然后可以使用阅读器将其传递给阅读fingerprint.RawInfo.Src
器(我真的不喜欢go-flacGetStreamInfo
不返回的事实io.Reader
;而是返回[]byte
,因此在实际发生进一步处理之前将整个流加载到内存中)。
使用以下代码,可以计算 FLAC 文件的指纹(基本上是做什么fpcalc
的):
package main
import (
"bytes"
"fmt"
"os"
"github.com/go-fingerprint/fingerprint"
"github.com/go-fingerprint/gochroma"
"github.com/go-flac/go-flac"
)
func main() {
f, err := flac.ParseFile(os.Args[1])
if err != nil {
panic(err)
}
si, err := f.GetStreamInfo()
if err != nil {
panic(err)
}
fpcalc := gochroma.New(gochroma.AlgorithmDefault)
defer fpcalc.Close()
fprint, err := fpcalc.Fingerprint(
fingerprint.RawInfo{
Src: bytes.NewReader(f.Frames),
Channels: uint(si.ChannelCount),
Rate: uint(si.SampleRate),
MaxSeconds: 120,
},
)
fmt.Println(fprint)
}
不幸的是,上面的代码没有返回相同的指纹fpcalc
。我究竟做错了什么?
解决方案
我最终得到了以下代码,它使用github.com/eaburns/flac将 FLAC 文件解码为原始音频数据(正如 Steven Penny 指出的那样),然后将数据传递给指纹/ gochroma。
生成的指纹似乎与fpcalc
同一 FLAC 文件报告的指纹不同,但使用生成的指纹查询 AcoustID 数据库时,结果是正确的。
package main
import (
"bytes"
"fmt"
"log"
"os"
"github.com/eaburns/flac"
"github.com/go-fingerprint/fingerprint"
"github.com/go-fingerprint/gochroma"
)
func main() {
if len(os.Args) != 2 {
log.Fatalf("usage: go run fpcalc.go FILE")
}
f, err := os.Open(os.Args[1])
if err != nil {
log.Fatalf("os.Open(%s): %s", os.Args[1], err)
}
defer f.Close()
d, metadata, err := flac.Decode(f)
if err != nil {
log.Fatalf("flac.Decode: %s", err)
}
fpcalc := gochroma.New(gochroma.AlgorithmDefault)
defer fpcalc.Close()
fprint, err := fpcalc.Fingerprint(
fingerprint.RawInfo{
Src: bytes.NewBuffer(d),
Channels: uint(metadata.NChannels),
Rate: uint(metadata.SampleRate),
MaxSeconds: 120,
},
)
if err != nil {
log.Fatalf("fpcalc.Fingerprint: %s", err)
}
fmt.Println(fprint)
}
推荐阅读
- roles - BigCommerce:识别登录用户角色
- node.js - 如何等待带有异步请求的 for 循环在 node.js 中完成?
- c# - PHP 和 C# 不同的 Unicode 输出
- ms-access - 更新/更改 ms 访问字段中文件的路径
- java - Jenkins Sonar 插件如何与 SonarQube 集成?
- ibm-cloud-storage - 更新 COS 中已有的 Object
- javascript - 带有jquery表的Javascript Click函数
- python - 英特尔 Distribution for Python 上的 pipenv 环境
- fpga - 指导 Vivado HLS 指令编辑器利用自定义 IP 实现各种功能
- google-cloud-platform - 我们可以通过使用云发布/订阅为同一主题创建不同的订阅来接收多个用户的 gmail 推送通知吗