// Decode decodes Ogg/Vorbis data to playable stream. // // Sample rate is automatically adjusted to fit with the audio context. func Decode(context *audio.Context, src audio.ReadSeekCloser) (*Stream, error) { decoded, channelNum, sampleRate, err := decode(src) if err != nil { return nil, err } if channelNum != 1 && channelNum != 2 { return nil, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", channelNum) } var s audio.ReadSeekCloser = decoded size := decoded.Size() if channelNum == 1 { s = convert.NewStereo16(s, true, false) size *= 2 } if sampleRate != context.SampleRate() { s = convert.NewResampling(s, size, sampleRate, context.SampleRate()) size = size * int64(context.SampleRate()) / int64(sampleRate) } return &Stream{s, size}, nil }
// Decode decodes WAV (RIFF) data to playable stream. // // The format must be 1 or 2 channels, 8bit or 16bit little endian PCM. // The format is converted into 2 channels and 16bit. // // Sample rate is automatically adjusted to fit with the audio context. func Decode(context *audio.Context, src audio.ReadSeekCloser) (*Stream, error) { buf := make([]byte, 12) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } if !bytes.Equal(buf[0:4], []byte("RIFF")) { return nil, fmt.Errorf("wav: invalid header: 'RIFF' not found") } if !bytes.Equal(buf[8:12], []byte("WAVE")) { return nil, fmt.Errorf("wav: invalid header: 'WAVE' not found") } // Read chunks dataSize := int64(0) headerSize := int64(0) sampleRateFrom := 0 sampleRateTo := 0 mono := false bitsPerSample := 0 chunks: for { buf := make([]byte, 8) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } headerSize += 8 size := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7])<<24 switch { case bytes.Equal(buf[0:4], []byte("fmt ")): // Size of 'fmt' header is usually 16, but can be more than 16. if size < 16 { return nil, fmt.Errorf("wav: invalid header: maybe non-PCM file?") } buf := make([]byte, size) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } format := int(buf[0]) | int(buf[1])<<8 if format != 1 { return nil, fmt.Errorf("wav: format must be linear PCM") } channelNum := int(buf[2]) | int(buf[3])<<8 switch channelNum { case 1: mono = true case 2: mono = false default: return nil, fmt.Errorf("wav: channel num must be 1 or 2 but was %d", channelNum) } bitsPerSample = int(buf[14]) | int(buf[15])<<8 if bitsPerSample != 8 && bitsPerSample != 16 { return nil, fmt.Errorf("wav: bits per sample must be 8 or 16 but was %d", bitsPerSample) } sampleRate := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7])<<24 if int64(context.SampleRate()) != sampleRate { sampleRateFrom = int(sampleRate) sampleRateTo = context.SampleRate() } headerSize += size case bytes.Equal(buf[0:4], []byte("data")): dataSize = size break chunks default: buf := make([]byte, size) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } headerSize += size } } var s audio.ReadSeekCloser = &stream{ src: src, headerSize: headerSize, dataSize: dataSize, remaining: dataSize, } if mono || bitsPerSample != 16 { s = convert.NewStereo16(s, mono, bitsPerSample != 16) if mono { dataSize *= 2 } if bitsPerSample != 16 { dataSize *= 2 } } if sampleRateFrom != sampleRateTo { s = convert.NewResampling(s, dataSize, sampleRateFrom, sampleRateTo) dataSize = dataSize * int64(sampleRateTo) / int64(sampleRateFrom) } return &Stream{s, dataSize}, nil }
// Decode decodes WAV (RIFF) data to playable stream. // // The format must be 2 channels, 16bit little endian PCM. // The sample rate must be same as that of audio context. func Decode(context *audio.Context, src audio.ReadSeekCloser) (*Stream, error) { buf := make([]byte, 12) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } if !bytes.Equal(buf[0:4], []byte("RIFF")) { return nil, fmt.Errorf("wav: invalid header: 'RIFF' not found") } if !bytes.Equal(buf[8:12], []byte("WAVE")) { return nil, fmt.Errorf("wav: invalid header: 'WAVE' not found") } // Read chunks dataSize := int64(0) headerSize := int64(0) chunks: for { buf := make([]byte, 8) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } headerSize += 8 size := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7])<<24 switch { case bytes.Equal(buf[0:4], []byte("fmt ")): if size != 16 { return nil, fmt.Errorf("wav: invalid header: maybe non-PCM file?") } buf := make([]byte, size) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } format := int(buf[0]) | int(buf[1])<<8 if format != 1 { return nil, fmt.Errorf("wav: format must be linear PCM") } channelNum := int(buf[2]) | int(buf[3])<<8 // TODO: Remove this magic number if channelNum != 2 { return nil, fmt.Errorf("wav: channel num must be 2") } bitsPerSample := int(buf[14]) | int(buf[15])<<8 // TODO: Remove this magic number if bitsPerSample != 16 { return nil, fmt.Errorf("wav: bits per sample must be 16") } sampleRate := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7])<<24 if int64(context.SampleRate()) != sampleRate { return nil, fmt.Errorf("wav: sample rate must be %d but %d", context.SampleRate(), sampleRate) } headerSize += size case bytes.Equal(buf[0:4], []byte("data")): dataSize = size break chunks default: buf := make([]byte, size) n, err := io.ReadFull(src, buf) if n != len(buf) { return nil, fmt.Errorf("wav: invalid header") } if err != nil { return nil, err } headerSize += size } } s := &Stream{ src: src, headerSize: headerSize, dataSize: dataSize, } return s, nil }