streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

wav.go (4040B)


      1 // Package wav implements access to WAV (or WAVE) files.
      2 // WAVE is a file format for storing digitised audio,
      3 // most commonly as raw PCM signals.
      4 //
      5 // See also https://en.wikipedia.org/wiki/WAV
      6 package wav
      7 
      8 import (
      9 	"bytes"
     10 	"encoding/binary"
     11 	"fmt"
     12 	"io"
     13 )
     14 
     15 type File struct {
     16 	Header    Header
     17 	Bitstream io.Reader
     18 }
     19 
     20 const (
     21 	headerLength    = 44
     22 	extensionLength = 24
     23 )
     24 
     25 const (
     26 	AudioFormatPCMInteger uint16 = 1
     27 	AudioFormatFloat      uint16 = 3
     28 	AudioFormatExtensible uint16 = 0xfffe
     29 )
     30 
     31 var (
     32 	riffID = [4]byte{'R', 'I', 'F', 'F'}
     33 	waveID = [4]byte{'W', 'A', 'V', 'E'}
     34 )
     35 
     36 var formatChunkID = [4]byte{'f', 'm', 't', ' '}
     37 
     38 var dataChunkID = [4]byte{'d', 'a', 't', 'a'}
     39 
     40 type Header struct {
     41 	FileSize uint32
     42 
     43 	AudioFormat    uint16
     44 	ChannelCount   uint16
     45 	Frequency      uint32
     46 	BytesPerSecond uint32
     47 	BytesPerBloc   uint16
     48 	BitsPerSample  uint16
     49 	Extension      *FormatExtension
     50 
     51 	DataSize uint32
     52 }
     53 
     54 func ReadFile(r io.Reader) (*File, error) {
     55 	h, err := readHeader(r)
     56 	if err != nil {
     57 		return nil, fmt.Errorf("read header: %w", err)
     58 	}
     59 	return &File{
     60 		Header: Header{
     61 			h.File.Length,
     62 			h.Format.AudioFormat,
     63 			h.Format.ChannelCount,
     64 			h.Format.Frequency,
     65 			h.Format.BytesPerSecond,
     66 			h.Format.BytesPerBloc,
     67 			h.Format.BitsPerSample,
     68 			h.FormatExtension,
     69 			h.Data.Length,
     70 		},
     71 		Bitstream: r,
     72 	}, nil
     73 }
     74 
     75 func EncodeHeader(hdr Header) []byte {
     76 	h := header{
     77 		File: fileChunk{riffID, hdr.FileSize, waveID},
     78 		Format: formatChunk{
     79 			formatChunkID,
     80 			formatChunkLength,
     81 			hdr.AudioFormat,
     82 			hdr.ChannelCount,
     83 			hdr.Frequency,
     84 			hdr.BytesPerSecond,
     85 			hdr.BytesPerBloc,
     86 			hdr.BitsPerSample,
     87 		},
     88 		FormatExtension: hdr.Extension,
     89 		Data:            dataChunk{dataChunkID, hdr.DataSize},
     90 	}
     91 	if h.Format.AudioFormat == AudioFormatExtensible {
     92 		h.Format.Length = extendedFormatChunkLength
     93 	}
     94 
     95 	bcap := headerLength
     96 	if h.Format.AudioFormat == AudioFormatExtensible {
     97 		bcap += extensionLength
     98 	}
     99 	buf := bytes.NewBuffer(make([]byte, 0, bcap))
    100 	binary.Write(buf, binary.LittleEndian, h.File)
    101 	binary.Write(buf, binary.LittleEndian, h.Format)
    102 	if h.FormatExtension != nil {
    103 		binary.Write(buf, binary.LittleEndian, h.FormatExtension)
    104 	}
    105 	binary.Write(buf, binary.LittleEndian, h.Data)
    106 	return buf.Bytes()
    107 }
    108 
    109 type header struct {
    110 	File   fileChunk
    111 	Format formatChunk
    112 	// Extension holds optional extra audio format information for
    113 	FormatExtension *FormatExtension
    114 	Data            dataChunk
    115 }
    116 
    117 type fileChunk struct {
    118 	ID       [4]byte
    119 	Length   uint32
    120 	FormatID [4]byte
    121 }
    122 
    123 const (
    124 	formatChunkLength         = 16
    125 	extendedFormatChunkLength = formatChunkLength + extensionLength
    126 )
    127 
    128 type formatChunk struct {
    129 	ID             [4]byte
    130 	Length         uint32
    131 	AudioFormat    uint16
    132 	ChannelCount   uint16
    133 	Frequency      uint32
    134 	BytesPerSecond uint32
    135 	BytesPerBloc   uint16
    136 	BitsPerSample  uint16
    137 }
    138 
    139 type dataChunk struct {
    140 	ID     [4]byte
    141 	Length uint32
    142 }
    143 
    144 type FormatExtension struct {
    145 	Length      uint16
    146 	ValidBits   uint16
    147 	ChannelMask uint32
    148 	SubFormat   [16]byte
    149 }
    150 
    151 func readHeader(rd io.Reader) (*header, error) {
    152 	var head header
    153 	if err := binary.Read(rd, binary.LittleEndian, &head.File); err != nil {
    154 		return nil, fmt.Errorf("read file chunk: %w", err)
    155 	}
    156 	if head.File.ID != riffID {
    157 		return nil, fmt.Errorf("bad RIFF id %x", head.File.ID)
    158 	} else if head.File.FormatID != waveID {
    159 		return nil, fmt.Errorf("bad WAVE file format id %x", head.File.FormatID)
    160 	}
    161 
    162 	if err := binary.Read(rd, binary.LittleEndian, &head.Format); err != nil {
    163 		return nil, fmt.Errorf("read file chunk: %w", err)
    164 	}
    165 	if head.Format.ID != formatChunkID {
    166 		return nil, fmt.Errorf("bad format chunk id %x", head.Format.ID)
    167 	}
    168 
    169 	if head.Format.AudioFormat == AudioFormatExtensible {
    170 		var ext FormatExtension
    171 		if err := binary.Read(rd, binary.LittleEndian, &ext); err != nil {
    172 			return nil, fmt.Errorf("read format chunk extension: %w", err)
    173 		}
    174 		head.FormatExtension = &ext
    175 	}
    176 
    177 	if err := binary.Read(rd, binary.LittleEndian, &head.Data); err != nil {
    178 		return nil, fmt.Errorf("read data chunk: %w", err)
    179 	}
    180 	return &head, nil
    181 }