Documentation
¶
Overview ¶
Package wav provides WAV encoding and decoding utilities for Go.
The package supports PCM integer (8/16/24/32-bit), IEEE float (32/64-bit), A-law, mu-law, and GSM 6.10 decode paths. It also parses and encodes common WAV metadata chunks, including LIST/INFO, cue/smpl, bext, and cart.
For chunk-preserving round-trip workflows, Decoder and Encoder expose additive APIs:
- FormatChunk() *FmtChunk
- RawChunks() []RawChunk
- SetRawChunks([]RawChunk)
Existing Decoder/Encoder fields and methods remain supported for backward compatibility.
Index ¶
- Variables
- func DecodeBroadcastChunk(dec *Decoder, chnk *riff.Chunk) error
- func DecodeCartChunk(dec *Decoder, chnk *riff.Chunk) error
- func DecodeCueChunk(d *Decoder, ch *riff.Chunk) error
- func DecodeListChunk(d *Decoder, ch *riff.Chunk) error
- func DecodeSamplerChunk(d *Decoder, ch *riff.Chunk) error
- type BroadcastExtension
- type Cart
- type ChunkHandler
- type ChunkRegistry
- type CuePoint
- type Decoder
- func (d *Decoder) Duration() (time.Duration, error)
- func (d *Decoder) EOF() bool
- func (d *Decoder) Err() error
- func (d *Decoder) Format() *audio.Format
- func (d *Decoder) FormatChunk() *FmtChunk
- func (d *Decoder) FullPCMBuffer() (*audio.Float32Buffer, error)
- func (d *Decoder) FwdToPCM() error
- func (d *Decoder) IsValidFile() bool
- func (d *Decoder) NextChunk() (*riff.Chunk, error)
- func (d *Decoder) PCMBuffer(buf *audio.Float32Buffer) (n int, err error)
- func (d *Decoder) PCMLen() int64
- func (d *Decoder) RawChunks() []RawChunk
- func (d *Decoder) ReadInfo()
- func (d *Decoder) ReadMetadata()
- func (d *Decoder) Rewind() error
- func (d *Decoder) SampleBitDepth() int32
- func (d *Decoder) Seek(offset int64, whence int) (int64, error)
- func (d *Decoder) SetRawChunks(chunks []RawChunk)
- func (d *Decoder) String() string
- func (d *Decoder) WasPCMAccessed() bool
- type Encoder
- func (e *Encoder) AddBE(src any) error
- func (e *Encoder) AddLE(src any) error
- func (e *Encoder) Close() error
- func (e *Encoder) FormatChunk() *FmtChunk
- func (e *Encoder) RawChunks() []RawChunk
- func (e *Encoder) SetRawChunks(chunks []RawChunk)
- func (e *Encoder) Write(buf *audio.Float32Buffer) error
- func (e *Encoder) WriteFrame(value any) error
- type FmtChunk
- type FmtExtensible
- type Metadata
- type RawChunk
- type SampleLoop
- type SamplerInfo
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrCuePointIDNotFound is returned when cue point ID cannot be read. ErrCuePointIDNotFound = errors.New("failed to read the cue point ID") // ErrDataChunkIDNotFound is returned when data chunk ID cannot be read. ErrDataChunkIDNotFound = errors.New("failed to read the data chunk id") )
var ( // CIDList is the chunk ID for a LIST chunk. CIDList = [4]byte{'L', 'I', 'S', 'T'} // CIDSmpl is the chunk ID for a smpl chunk. CIDSmpl = [4]byte{'s', 'm', 'p', 'l'} // CIDINFO is the chunk ID for an INFO chunk. CIDInfo = []byte{'I', 'N', 'F', 'O'} // CIDCue is the chunk ID for the cue chunk. CIDCue = [4]byte{'c', 'u', 'e', 0x20} // CIDFact is the chunk ID for the fact chunk. CIDFact = [4]byte{'f', 'a', 'c', 't'} // CIDBext is the chunk ID for the broadcast extension chunk. CIDBext = [4]byte{'b', 'e', 'x', 't'} // CIDCart is the chunk ID for the cart chunk. CIDCart = [4]byte{'c', 'a', 'r', 't'} // ErrPCMDataNotFound is returned when PCM data chunk is not found. ErrPCMDataNotFound = errors.New("PCM data not found") // ErrDurationNilPointer is returned when calculating duration on a nil decoder. ErrDurationNilPointer = errors.New("can't calculate the duration of a nil pointer") // ErrUnsupportedCompressedFormat is returned when a compressed audio format // (e.g. GSM 6.10, TrueSpeech, Voxware) is encountered that has no decoder // implementation. The WAV file structure is valid but the audio codec is not // supported. ErrUnsupportedCompressedFormat = errors.New("unsupported compressed audio format") )
var ErrPCMChunkNotFound = errors.New("PCM Chunk not found in audio file")
ErrPCMChunkNotFound indicates a bad audio file without data.
Functions ¶
func DecodeBroadcastChunk ¶
DecodeBroadcastChunk decodes a bext chunk into decoder metadata.
func DecodeCartChunk ¶
DecodeCartChunk decodes a cart chunk into decoder metadata.
func DecodeCueChunk ¶
DecodeCueChunk decodes the optional cue chunk and extracts cue points.
func DecodeListChunk ¶
DecodeListChunk decodes a LIST chunk.
Types ¶
type BroadcastExtension ¶
type BroadcastExtension struct {
Description string
Originator string
OriginatorReference string
OriginationDate string
OriginationTime string
TimeReference uint64
Version uint16
UMID [64]byte
Reserved []byte
CodingHistory string
}
BroadcastExtension represents metadata stored in the BWF bext chunk.
type Cart ¶
type Cart struct {
Version string
Title string
Artist string
CutID string
ClientID string
Category string
Classification string
OutCue string
StartDate string
StartTime string
EndDate string
EndTime string
ProducerAppID string
ProducerAppVersion string
UserDef string
LevelReference int32
PostTimer [8]uint32
Reserved []byte
URL string
TagText string
}
Cart represents practical fields from the cart chunk.
type ChunkHandler ¶
type ChunkHandler interface {
CanHandle(chunkID [4]byte, listType [4]byte) bool
Decode(d *Decoder, ch *riff.Chunk) error
Encode(e *Encoder) error
}
ChunkHandler is a typed handler for RIFF/WAV chunks. Encode is optional and may return errChunkEncodeNotSupported.
type ChunkRegistry ¶
type ChunkRegistry struct {
// contains filtered or unexported fields
}
ChunkRegistry resolves chunks to handlers.
func (*ChunkRegistry) Register ¶
func (r *ChunkRegistry) Register(handler ChunkHandler)
Register appends a handler to the registry.
type CuePoint ¶
type CuePoint struct {
// ID is the unique identifier of the cue point
ID [4]byte
// Play position specifies the sample offset associated with the cue point
// in terms of the sample's position in the final stream of samples
// generated by the play list. If a play list chunk is
// specified, the position value is equal to the sample number at which this
// cue point will occur during playback of the entire play list as defined
// by the play list's order. If no play list chunk is specified this value
// should be 0.
Position uint32
// DataChunkID - This value specifies the four byte ID used by the chunk
// containing the sample that corresponds to this cue point. A Wave file
// with no play list is always "data". A Wave file with a play list
// containing both sample data and silence may be either "data" or "slnt".
DataChunkID [4]byte
// ChunkStart specifies the byte offset into the Wave List Chunk of the
// chunk containing the sample that corresponds to this cue point. This is
// the same chunk described by the Data Chunk ID value. If no Wave List
// Chunk exists in the Wave file, this value is 0. If a Wave List Chunk
// exists, this is the offset into the "wavl" chunk. The first chunk in the
// Wave List Chunk would be specified with a value of 0.
ChunkStart uint32
// BlockStart specifies the byte offset into the "data" or "slnt" Chunk to
// the start of the block containing the sample. The start of a block is
// defined as the first byte in uncompressed PCM wave data or the last byte
// in compressed wave data where decompression can begin to find the value
// of the corresponding sample value.
BlockStart uint32
// SampleOffset specifies an offset into the block (specified by Block
// Start) for the sample that corresponds to the cue point. In uncompressed
// PCM waveform data, this is simply the byte offset into the "data" chunk.
// In compressed waveform data, this value is equal to the number of samples
// (may or may not be bytes) from the Block Start to the sample that
// corresponds to the cue point.
SampleOffset uint32
}
CuePoint defines an offset which marks a noteworthy sections of the audio content. For example, the beginning and end of a verse in a song may have cue points to make them easier to find.
type Decoder ¶
type Decoder struct {
NumChans uint16
BitDepth uint16
SampleRate uint32
AvgBytesPerSec uint32
WavAudioFormat uint16
FmtChunk *FmtChunk
PCMSize int
// pcmChunk is available so we can use the LimitReader
PCMChunk *riff.Chunk
// Metadata for the current file
Metadata *Metadata
// UnknownChunks stores non-core chunks for optional round-trip writing.
UnknownChunks []RawChunk
// CompressedSamples stores the sample count from the fact chunk for
// compressed formats (diagnostic/informational only).
CompressedSamples uint32
// contains filtered or unexported fields
}
Decoder handles the decoding of wav files.
func NewDecoder ¶
func NewDecoder(r io.ReadSeeker) *Decoder
NewDecoder creates a decoder for the passed wav reader. Note that the reader doesn't get rewinded as the container is processed.
func (*Decoder) Duration ¶
Duration returns the time duration for the current audio container.
Example ¶
file, err := os.Open("fixtures/kick.wav")
if err != nil {
log.Fatal(err)
}
defer file.Close()
dur, err := NewDecoder(file).Duration()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s duration: %s\n", file.Name(), dur)
Output: fixtures/kick.wav duration: 204.172335ms
func (*Decoder) FormatChunk ¶
FormatChunk returns a copy of the parsed fmt chunk, if available.
func (*Decoder) FullPCMBuffer ¶
func (d *Decoder) FullPCMBuffer() (*audio.Float32Buffer, error)
FullPCMBuffer is an inefficient way to access all the PCM data contained in the audio container. The entire PCM data is held in memory. Consider using PCMBuffer() instead.
func (*Decoder) FwdToPCM ¶
FwdToPCM forwards the underlying reader until the start of the PCM chunk. If the PCM chunk was already read, no data will be found (you need to rewind).
func (*Decoder) IsValidFile ¶
IsValidFile verifies that the file is valid/readable.
Example ¶
file, err := os.Open("fixtures/kick.wav")
if err != nil {
log.Fatal(err)
}
defer file.Close()
fmt.Printf("is this file valid: %t", NewDecoder(file).IsValidFile())
Output: is this file valid: true
func (*Decoder) PCMBuffer ¶
func (d *Decoder) PCMBuffer(buf *audio.Float32Buffer) (n int, err error)
PCMBuffer populates the passed PCM buffer.
func (*Decoder) ReadInfo ¶
func (d *Decoder) ReadInfo()
ReadInfo reads the underlying reader until the comm header is parsed. This method is safe to call multiple times.
func (*Decoder) ReadMetadata ¶
func (d *Decoder) ReadMetadata()
ReadMetadata parses the file for extra metadata such as the INFO list chunk. The entire file will be read and should be rewinded if more data must be accessed.
Example ¶
file, err := os.Open("fixtures/listinfo.wav")
if err != nil {
log.Fatal(err)
}
defer file.Close()
decoder := NewDecoder(file)
decoder.ReadMetadata()
if err := decoder.Err(); err != nil {
log.Fatal(err)
}
if decoder.Metadata == nil {
fmt.Println("No metadata found")
return
}
fmt.Printf("Artist: %s\n", decoder.Metadata.Artist)
fmt.Printf("Title: %s\n", decoder.Metadata.Title)
fmt.Printf("Album: %s\n", decoder.Metadata.Product)
fmt.Printf("Track: %s\n", decoder.Metadata.TrackNbr)
Output: Artist: artist Title: track title Album: album title Track: 42
func (*Decoder) Rewind ¶
Rewind allows the decoder to be rewound to the beginning of the PCM data. This is useful if you want to keep on decoding the same file in a loop.
func (*Decoder) SampleBitDepth ¶
SampleBitDepth returns the bit depth encoding of each sample.
func (*Decoder) SetRawChunks ¶
SetRawChunks replaces preserved non-core chunks with the provided set.
func (*Decoder) WasPCMAccessed ¶
WasPCMAccessed returns positively if the PCM data was previously accessed.
type Encoder ¶
type Encoder struct {
SampleRate int
BitDepth int
NumChans int
// A number indicating the WAVE format category of the file. The content of
// the <format-specific-fields> portion of the ‘fmt’ chunk, and the
// interpretation of the waveform data, depend on this value. PCM = 1 (i.e.
// Linear quantization) Values other than 1 indicate some form of
// compression.
WavAudioFormat int
// FmtChunk optionally controls fmt chunk serialization, including
// WAVE_FORMAT_EXTENSIBLE fields.
FmtChunk *FmtChunk
// Metadata contains metadata to inject in the file.
Metadata *Metadata
// UnknownChunks contains non-core chunks to preserve on write.
UnknownChunks []RawChunk
WrittenBytes int
// contains filtered or unexported fields
}
Encoder encodes LPCM data into a wav containter.
func NewEncoder ¶
func NewEncoder(w io.WriteSeeker, sampleRate, bitDepth, numChans, audioFormat int) *Encoder
NewEncoder creates a new encoder to create a new wav file. Don't forget to add Frames to the encoder before writing.
func NewEncoderFromDecoder ¶
func NewEncoderFromDecoder(w io.WriteSeeker, dec *Decoder) *Encoder
NewEncoderFromDecoder creates an encoder initialized from decoder settings. It carries format details and preserved unknown chunks for round-trip flows.
func (*Encoder) Close ¶
Close flushes the content to disk, make sure the headers are up to date Note that the underlying writer is NOT being closed.
func (*Encoder) FormatChunk ¶
FormatChunk returns a copy of the configured fmt chunk, if available.
func (*Encoder) SetRawChunks ¶
SetRawChunks replaces configured non-core chunks with the provided set.
func (*Encoder) Write ¶
func (e *Encoder) Write(buf *audio.Float32Buffer) error
Write encodes and writes the passed buffer to the underlying writer. Don't forget to Close() the encoder or the file won't be valid.
Example ¶
file, err := os.Open("fixtures/kick.wav")
if err != nil {
panic(fmt.Sprintf("couldn't open audio file - %v", err))
}
// Decode the original audio file
// and collect audio content and information.
decoder := NewDecoder(file)
buf, err := decoder.FullPCMBuffer()
if err != nil {
panic(err)
}
file.Close()
fmt.Println("Old file ->", decoder)
// Destination file
out, err := os.Create("testOutput/kick.wav")
if err != nil {
panic(fmt.Sprintf("couldn't create output file - %v", err))
}
// setup the encoder and write all the frames
encoder := NewEncoder(out,
buf.Format.SampleRate,
int(decoder.BitDepth),
buf.Format.NumChannels,
int(decoder.WavAudioFormat))
if err = encoder.Write(buf); err != nil {
panic(err)
}
// close the encoder to make sure the headers are properly
// set and the data is flushed.
if err = encoder.Close(); err != nil {
panic(err)
}
out.Close()
// reopen to confirm things worked well
out, err = os.Open("testOutput/kick.wav")
if err != nil {
panic(err)
}
d2 := NewDecoder(out)
d2.ReadInfo()
fmt.Println("New file ->", d2)
out.Close()
os.Remove(out.Name())
Output: Old file -> Format: WAVE - 1 channels @ 22050 / 16 bits - Duration: 0.204172 seconds New file -> Format: WAVE - 1 channels @ 22050 / 16 bits - Duration: 0.204172 seconds
func (*Encoder) WriteFrame ¶
WriteFrame writes a single frame of data to the underlying writer.
type FmtChunk ¶
type FmtChunk struct {
FormatTag uint16
NumChannels uint16
SampleRate uint32
AvgBytesPerSec uint32
BlockAlign uint16
BitsPerSample uint16
ExtraData []byte
Extensible *FmtExtensible
}
FmtChunk stores the parsed WAV fmt chunk, including extensible metadata.
func (*FmtChunk) EffectiveFormatTag ¶
type FmtExtensible ¶
type FmtExtensible struct {
ValidBitsPerSample uint16
ChannelMask uint32
SubFormat [16]byte
ExtraData []byte
}
FmtExtensible stores WAVE_FORMAT_EXTENSIBLE extra fields.
type Metadata ¶
type Metadata struct {
SamplerInfo *SamplerInfo
// BroadcastExtension stores BWF bext metadata.
BroadcastExtension *BroadcastExtension
// Cart stores cart chunk metadata used in radio automation workflows.
Cart *Cart
// Artist of the original subject of the file. For example, Michaelangelo.
Artist string
// Comments provides general comments about the file or the subject of the
// file. If the comment is several sentences long, end each sentence with a
// period. Do not include newline characters.
Comments string
// Copyright records the copyright information for the file.
Copyright string
// CreationDate specifies the date the subject of the file was created. List
// dates in year-month-day format, padding one-digit months and days with a
// zero on the left. For example: 1553-05-03 for May 3, 1553. The year
// should always be given using four digits.
CreationDate string
// Engineer stores the name of the engineer who worked on the file. If there
// are multiple engineers, separate the names by a semicolon and a blank.
// For example: Smith, John; Adams, Joe.
Engineer string
// Technician identifies the technician who sampled the subject file. For
// example: Smith, John.
Technician string
// Genre describes the original work, such as jazz, classical, rock, etc.
Genre string
// Keywords provides a list of keywords that refer to the file or subject of
// the file. Separate multiple keywords with a semicolon and a blank. For
// example, Seattle; zoology; The Civil War.
Keywords string
// Medium describes the original subject of the file, such as record, CD and so forth.
Medium string
// Title stores the title of the subject of the file, such as bohemian rhapsody.
Title string
// Product AKA album specifies the name of the title the file was originally
// intended for: A Night at the Opera
Product string
// Subject describes the contents of the file, such as Metadata Management.
Subject string
// Software identifies the name of the software package used to create the
// file, such as go-audio.
Software string
// Source identifies the name of the person or organization who supplied the
// original subject of the file. For example: Splice.
Source string
// Location or Archival Location - Indicates where the subject of the file is archived.
Location string
// TrackNbr is the track number
TrackNbr string
// CuePoints is a list of cue points in the wav file.
CuePoints []*CuePoint
}
Metadata represents optional metadata added to the wav file.
type RawChunk ¶
type RawChunk struct {
ID [4]byte
// Size mirrors len(Data) for preserved chunks.
Size uint32
Data []byte
// Order is the original chunk order index encountered during decode.
Order int
// BeforeData indicates if this chunk appeared before the data chunk.
BeforeData bool
}
RawChunk stores a non-core RIFF/WAV chunk for round-trip preservation.
type SampleLoop ¶
type SampleLoop struct {
// CuePointID - The Cue Point ID specifies the unique ID that corresponds to one of the
// defined cue points in the cue point list. Furthermore, this ID
// corresponds to any labels defined in the associated data list chunk which
// allows text labels to be assigned to the various sample loops.
CuePointID [4]byte
// Type - The type field defines how the waveform samples will be looped.
// 0 Loop forward (normal)
// 1 Alternating loop (forward/backward, also known as Ping Pong)
// 2 Loop backward (reverse)
// 3 Reserved for future standard types
// 32 - 0xFFFFFFFF Sampler specific types (defined by manufacturer)
Type uint32
// Start - The start value specifies the byte offset into the waveform data
// of the first sample to be played in the loop.
Start uint32
// End - The end value specifies the byte offset into the waveform data of
// the last sample to be played in the loop.
End uint32
// Fraction - The fractional value specifies a fraction of a sample at which
// to loop. This allows a loop to be fine tuned at a resolution greater than
// one sample. The value can range from 0x00000000 to 0xFFFFFFFF. A value of
// 0 means no fraction, a value of 0x80000000 means 1/2 of a sample length.
// 0xFFFFFFFF is the smallest fraction of a sample that can be represented.
Fraction uint32
// PlayCount - The play count value determines the number of times to play
// the loop. A value of 0 specifies an infinite sustain loop. An infinite
// sustain loop will continue looping until some external force interrupts
// playback, such as the musician releasing the key that triggered the
// wave's playback. All other values specify an absolute number of times to
// loop.
PlayCount uint32
}
SampleLoop indicates a loop and its properties within the audio file.
type SamplerInfo ¶
type SamplerInfo struct {
// Manufacturer field specifies the MIDI Manufacturer's Association
// (MMA) Manufacturer code for the sampler intended to receive this file's
// waveform. Each manufacturer of a MIDI product is assigned a unique ID
// which identifies the company. If no particular manufacturer is to be
// specified, a value of 0 should be used. The value is stored with some
// extra information to enable translation to the value used in a MIDI
// System Exclusive transmission to the sampler. The high byte indicates the
// number of low order bytes (1 or 3) that are valid for the manufacturer
// code. For example, the value for Digidesign will be 0x01000013 (0x13) and
// the value for Microsoft will be 0x30000041 (0x00, 0x00, 0x41).
Manufacturer [4]byte
// Product field specifies the MIDI model ID defined by the manufacturer
// corresponding to the Manufacturer field. Contact the manufacturer of the
// sampler to get the model ID. If no particular manufacturer's product is
// to be specified, a value of 0 should be used.
Product [4]byte
// SamplePeriod The sample period specifies the duration of time that passes
// during the playback of one sample in nanoseconds (normally equal to 1 /
// Samplers Per Second, where Samples Per Second is the value found in the
// format chunk).
SamplePeriod uint32
// MIDIUnityNote The MIDI unity note value has the same meaning as the instrument chunk's
// MIDI Unshifted Note field which specifies the musical note at which the
// sample will be played at it's original sample rate (the sample rate
// specified in the format chunk).
MIDIUnityNote uint32
// MIDIPitchFraction The MIDI pitch fraction specifies the fraction of a
// semitone up from the specified MIDI unity note field. A value of
// 0x80000000 means 1/2 semitone (50 cents) and a value of 0x00000000 means
// no fine tuning between semitones.
MIDIPitchFraction uint32
// SMPTEFormat The SMPTE format specifies the Society of Motion Pictures and
// Television E time format used in the following SMPTE Offset field. If a
// value of 0 is set, SMPTE Offset should also be set to 0. (0, 24, 25, 29, 30)
SMPTEFormat uint32
// SMPTEOffset The SMPTE Offset value specifies the time offset to be used
// for the synchronization / calibration to the first sample in the
// waveform. This value uses a format of 0xhhmmssff where hh is a signed
// value that specifies the number of hours (-23 to 23), mm is an unsigned
// value that specifies the number of minutes (0 to 59), ss is an unsigned
// value that specifies the number of seconds (0 to 59) and ff is an
// unsigned value that specifies the number of frames (0 to -1).
SMPTEOffset uint32
// NumSampleLoops The sample loops field specifies the number Sample Loop
// definitions in the following list. This value may be set to 0 meaning
// that no sample loops follow.
NumSampleLoops uint32
// Loops A list of sample loops is simply a set of consecutive loop
// descriptions. The sample loops do not have to be in any particular order
// because each sample loop associated cue point position is used to
// determine the play order.
Loops []*SampleLoop
}
SamplerInfo is extra metadata pertinent to a sampler type usage.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
gen-sine
command
|
|
|
metadata
command
This tool reads metadata from the passed wav file if available.
|
This tool reads metadata from the passed wav file if available. |
|
wavtagger
command
This command line tool helps the user tag wav files by injecting metadata in the file in a safe way.
|
This command line tool helps the user tag wav files by injecting metadata in the file in a safe way. |
|
wavtoaiff
command
This tool converts an aiff file into an identical wav file and stores it in the same folder as the source.
|
This tool converts an aiff file into an identical wav file and stores it in the same folder as the source. |