2024-01-28 01:36:16 +08:00

108 lines
2.3 KiB
Go

package audio
import (
"encoding/binary"
"io"
)
type Encoder struct {
Output io.WriteSeeker
SampleRate int
BitDepth int
totalBytes uint32
isHeaderWritten bool
}
func (e *Encoder) WriteHeader() error {
if err := writeLe(e.Output, []byte("RIFF")); err != nil {
return err
}
if err := writeLe(e.Output, uint32(0)); err != nil { // Placeholder for file size
return err
}
if err := writeLe(e.Output, []byte("WAVE")); err != nil {
return err
}
if err := writeLe(e.Output, []byte("fmt ")); err != nil {
return err
}
if err := writeLe(e.Output, uint32(16)); err != nil {
return err
}
if err := writeLe(e.Output, uint16(1)); err != nil { // Audio format: PCM
return err
}
if err := writeLe(e.Output, uint16(1)); err != nil { // Number of channels: 1 (mono)
return err
}
if err := writeLe(e.Output, uint32(e.SampleRate)); err != nil {
return err
}
if err := writeLe(e.Output, uint32(e.SampleRate*e.BitDepth/8)); err != nil {
return err
}
if err := writeLe(e.Output, uint16(e.BitDepth/8)); err != nil {
return err
}
if err := writeLe(e.Output, uint16(e.BitDepth)); err != nil {
return err
}
if err := writeLe(e.Output, []byte("data")); err != nil {
return err
}
if err := writeLe(e.Output, uint32(0)); err != nil { //Placeholder for data size
return err
}
e.isHeaderWritten = true
return nil
}
func writeLe[T []byte | uint32 | uint16 | uint8](w io.Writer, data T) error {
return binary.Write(w, binary.LittleEndian, data)
}
func (e *Encoder) Write(data []byte) error {
if !e.isHeaderWritten {
e.WriteHeader()
}
n, err := e.Output.Write(data)
if err != nil {
return err
}
e.totalBytes += uint32(n)
return nil
}
func (e *Encoder) Close() error {
if _, err := e.Output.Seek(4, io.SeekStart); err != nil {
return err
}
if err := binary.Write(e.Output, binary.LittleEndian, uint32(36+e.totalBytes)); err != nil {
return err
}
if _, err := e.Output.Seek(40, io.SeekStart); err != nil {
return err
}
if err := binary.Write(e.Output, binary.LittleEndian, e.totalBytes); err != nil {
return err
}
return nil
}
func NewEncoder(w io.WriteSeeker, sampleRate int, bitDepth int) *Encoder {
return &Encoder{
SampleRate: sampleRate,
Output: w,
BitDepth: bitDepth,
isHeaderWritten: false,
}
}