FLAC 和 MP3 的色谱指纹

chromaprint fingerprint of FLAC and 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。有一些 examples,但这些适用于以 .raw.

结尾的文件

如何在 Go 中将 FLAC(或辅助 MP3)file/stream 转换为原始音频数据流?我的猜测是使用像 go-flac 这样的 Go FLAC 库,但我不确定从哪里开始。欢迎任何提示!

编辑

通过 go-flacGetStreamInfo 应该可以访问 FLAC 文件的原始音频数据,然后可以使用 reader (我真的不喜欢 go-flacGetStreamInfo 不是 return 和 io.Reader;而是 return 和 []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)
}

不幸的是,上面的代码没有 return 与 fpcalc 相同的指纹。我做错了什么?

我最终得到了以下代码,它使用 github.com/eaburns/flac (as Steven Penny pointed out) and then passes the data over to fingerprint/gochroma 将 FLAC 文件解码为原始音频数据。

对于同一个 FLAC 文件,生成的指纹似乎与 fpcalc 报告的指纹不一样,但是当使用生成的指纹查询 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)
}