/* NAME decode.go DESCRIPTION decode.go provides functionality for the decoding of FLAC compressed audio AUTHOR Saxon Nelson-Milton LICENSE decode.go is Copyright (C) 2017-2019 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. */ package flac import ( "bytes" "errors" "io" "github.com/go-audio/audio" "github.com/go-audio/wav" "github.com/mewkiz/flac" ) const wavFormat = 1 // writeSeeker implements a memory based io.WriteSeeker. type writeSeeker struct { buf []byte pos int } // Bytes returns the bytes contained in the writeSeekers buffer. func (ws *writeSeeker) Bytes() []byte { return ws.buf } // Write writes len(p) bytes from p to the writeSeeker's buf and returns the number // of bytes written. If less than len(p) bytes are written, an error is returned. func (ws *writeSeeker) Write(p []byte) (n int, err error) { minCap := ws.pos + len(p) if minCap > cap(ws.buf) { // Make sure buf has enough capacity: buf2 := make([]byte, len(ws.buf), minCap+len(p)) // add some extra copy(buf2, ws.buf) ws.buf = buf2 } if minCap > len(ws.buf) { ws.buf = ws.buf[:minCap] } copy(ws.buf[ws.pos:], p) ws.pos += len(p) return len(p), nil } // Seek sets the offset for the next Read or Write to offset, interpreted according // to whence: SeekStart means relative to the start of the file, SeekCurrent means // relative to the current offset, and SeekEnd means relative to the end. Seek returns // the new offset relative to the start of the file and an error, if any. func (ws *writeSeeker) Seek(offset int64, whence int) (int64, error) { newPos, offs := 0, int(offset) switch whence { case io.SeekStart: newPos = offs case io.SeekCurrent: newPos = ws.pos + offs case io.SeekEnd: newPos = len(ws.buf) + offs } if newPos < 0 { return 0, errors.New("negative result pos") } ws.pos = newPos return int64(newPos), nil } // Decode takes buf, a slice of FLAC, and decodes to WAV. If complete decoding // fails, an error is returned. func Decode(buf []byte) ([]byte, error) { // Lex and decode the FLAC into a stream to hold audio and properties. r := bytes.NewReader(buf) stream, err := flac.Parse(r) if err != nil { return nil, errors.New("Could not parse FLAC") } // Create WAV encoder and pass writeSeeker that will store output WAV. ws := &writeSeeker{} enc := wav.NewEncoder(ws, int(stream.Info.SampleRate), int(stream.Info.BitsPerSample), int(stream.Info.NChannels), wavFormat) defer enc.Close() var data []int for { // Decode FLAC audio samples. frame, err := stream.ParseNext() if err != nil { if err == io.EOF { break } return nil, err } // Encode WAV audio samples. data = data[:0] for i := 0; i < frame.Subframes[0].NSamples; i++ { for _, subframe := range frame.Subframes { data = append(data, int(subframe.Samples[i])) } } buf := &audio.IntBuffer{ Format: &audio.Format{ NumChannels: int(stream.Info.NChannels), SampleRate: int(stream.Info.SampleRate), }, Data: data, SourceBitDepth: int(stream.Info.BitsPerSample), } if err := enc.Write(buf); err != nil { return nil, err } } return ws.Bytes(), nil }