wav

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 22, 2022 License: Apache-2.0 Imports: 11 Imported by: 231

README

wav codec

GoDoc Go Report Card Coverage Status Build Status

Wav audio file encoder and decoder. See GoDoc for more details.

Documentation

Overview

Package wav is a package allowing developers to decode and encode audio PCM data using the Waveform Audio File Format https://en.wikipedia.org/wiki/WAV

Index

Examples

Constants

This section is empty.

Variables

View Source
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}
)
View Source
var (
	// ErrPCMChunkNotFound indicates a bad audio file without data
	ErrPCMChunkNotFound = errors.New("PCM Chunk not found in audio file")
)

Functions

func DecodeCueChunk

func DecodeCueChunk(d *Decoder, ch *riff.Chunk) error

DecodeCueChunk decodes the optional cue chunk and extracts cue points.

func DecodeListChunk

func DecodeListChunk(d *Decoder, ch *riff.Chunk) error

DecodeListChunk decodes a LIST chunk

func DecodeSamplerChunk

func DecodeSamplerChunk(d *Decoder, ch *riff.Chunk) error

DecodeSamplerChunk decodes a smpl chunk and put the data in Decoder.Metadata.SamplerInfo

Types

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

	PCMSize int

	// pcmChunk is available so we can use the LimitReader
	PCMChunk *riff.Chunk
	// Metadata for the current file
	Metadata *Metadata
	// 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

func (d *Decoder) Duration() (time.Duration, error)

Duration returns the time duration for the current audio container

Example
f, err := os.Open("fixtures/kick.wav")
if err != nil {
	log.Fatal(err)
}
defer f.Close()
dur, err := NewDecoder(f).Duration()
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s duration: %s\n", f.Name(), dur)
Output:

fixtures/kick.wav duration: 204.172335ms

func (*Decoder) EOF

func (d *Decoder) EOF() bool

EOF returns positively if the underlying reader reached the end of file.

func (*Decoder) Err

func (d *Decoder) Err() error

Err returns the first non-EOF error that was encountered by the Decoder.

func (*Decoder) Format

func (d *Decoder) Format() *audio.Format

Format returns the audio format of the decoded content.

func (*Decoder) FullPCMBuffer

func (d *Decoder) FullPCMBuffer() (*audio.IntBuffer, 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

func (d *Decoder) FwdToPCM() error

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

func (d *Decoder) IsValidFile() bool

IsValidFile verifies that the file is valid/readable.

Example
f, err := os.Open("fixtures/kick.wav")
if err != nil {
	log.Fatal(err)
}
defer f.Close()
fmt.Printf("is this file valid: %t", NewDecoder(f).IsValidFile())
Output:

is this file valid: true

func (*Decoder) NextChunk

func (d *Decoder) NextChunk() (*riff.Chunk, error)

NextChunk returns the next available chunk

func (*Decoder) PCMBuffer

func (d *Decoder) PCMBuffer(buf *audio.IntBuffer) (n int, err error)

PCMBuffer populates the passed PCM buffer

func (*Decoder) PCMLen

func (d *Decoder) PCMLen() int64

PCMLen returns the total number of bytes in the PCM data chunk

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
f, err := os.Open("fixtures/listinfo.wav")
if err != nil {
	log.Fatal(err)
}
defer f.Close()
d := NewDecoder(f)
d.ReadMetadata()
if d.Err() != nil {
	log.Fatal(err)
}
fmt.Printf("%#v\n", d.Metadata)
Output:

&wav.Metadata{SamplerInfo:(*wav.SamplerInfo)(nil), Artist:"artist", Comments:"my comment", Copyright:"", CreationDate:"2017", Engineer:"", Technician:"", Genre:"genre", Keywords:"", Medium:"", Title:"track title", Product:"album title", Subject:"", Software:"", Source:"", Location:"", TrackNbr:"42", CuePoints:[]*wav.CuePoint(nil)}

func (*Decoder) Rewind added in v1.1.0

func (d *Decoder) Rewind() error

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

func (d *Decoder) SampleBitDepth() int32

SampleBitDepth returns the bit depth encoding of each sample.

func (*Decoder) Seek

func (d *Decoder) Seek(offset int64, whence int) (int64, error)

Seek provides access to the cursor position in the PCM data

func (*Decoder) String

func (d *Decoder) String() string

String implements the Stringer interface.

func (*Decoder) WasPCMAccessed

func (d *Decoder) WasPCMAccessed() bool

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

	// Metadata contains metadata to inject in the file.
	Metadata *Metadata

	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 (*Encoder) AddBE

func (e *Encoder) AddBE(src interface{}) error

AddBE serializes and adds the passed value using big endian

func (*Encoder) AddLE

func (e *Encoder) AddLE(src interface{}) error

AddLE serializes and adds the passed value using little endian

func (*Encoder) Close

func (e *Encoder) Close() error

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) Write

func (e *Encoder) Write(buf *audio.IntBuffer) 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
f, 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.
d := NewDecoder(f)
buf, err := d.FullPCMBuffer()
if err != nil {
	panic(err)
}
f.Close()
fmt.Println("Old file ->", d)

// 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
e := NewEncoder(out,
	buf.Format.SampleRate,
	int(d.BitDepth),
	buf.Format.NumChannels,
	int(d.WavAudioFormat))
if err = e.Write(buf); err != nil {
	panic(err)
}
// close the encoder to make sure the headers are properly
// set and the data is flushed.
if err = e.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

func (e *Encoder) WriteFrame(value interface{}) error

WriteFrame writes a single frame of data to the underlying writer.

type Metadata

type Metadata struct {
	SamplerInfo *SamplerInfo
	// 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 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.

Directories

Path Synopsis
cmd
metadata
This tool reads metadata from the passed wav file if available.
This tool reads metadata from the passed wav file if available.
wavtagger
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
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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL