Skip to content
Snippets Groups Projects
decoder.go 1.26 KiB
package prober

import (
	"encoding/binary"
	"io"
	"os"
	"os/exec"
)

const (
	analysisSampleRate = "44100"
	analysisChannels   = "1"
)

// The decoder uses sox(1) to decode the audio data to mono float64
// samples at a fixed sample rate (in the same format expected by the
// floatReader). We shell out to sox due to the lack of simple audio
// libraries for Go that would do the job...
type decoder struct {
	io.ReadCloser
	cmd *exec.Cmd
}

func newDecoder(r io.Reader, ext string) (*decoder, error) {
	var args []string
	if ext == ".mp3" {
		args = append(args, "-t", "mp3")
	}
	args = append(args, "-", "-r", analysisSampleRate, "-c", analysisChannels, "-b", "64", "-e", "float", "--endian", "little", "-t", "raw", "-")
	cmd := exec.Command("sox", args...)
	cmd.Stdin = r
	cmd.Stderr = os.Stderr
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	return &decoder{
		ReadCloser: stdout,
		cmd:        cmd,
	}, nil
}

func (d *decoder) Close() error {
	d.ReadCloser.Close()
	return d.cmd.Wait()
}

// The floatReader reads float64 arrays from an io.Reader.
type floatReader struct {
	io.Reader
}

func (r floatReader) ReadFloats(buf []float64) error {
	return binary.Read(r.Reader, binary.LittleEndian, buf)
}