├── wave ├── 48kHz1ch8bit.wav ├── 48kHz1ch16bit.wav ├── 48kHz1ch24bit.wav ├── 48kHz1ch32bit.wav ├── 48kHz2ch16bit.wav ├── 48kHz1ch32bitFloat.wav ├── 48kHz1ch64bitFloat.wav ├── writer_test.go ├── reader.go ├── writer.go ├── reader_test.go └── waveformatex.go ├── README.md ├── saturator └── saturator.go ├── converter ├── converter.go ├── data_test.go ├── uint8.go ├── float64.go ├── float32.go ├── int16.go ├── int24.go ├── int32.go ├── uint8_test.go ├── int24_test.go ├── int16_test.go ├── int32_test.go ├── float64_test.go └── float32_test.go ├── LICENSE ├── resample.go ├── audio.go └── resampler ├── resampler_test.go ├── quality.go └── resampler.go /wave/48kHz1ch8bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/audio/HEAD/wave/48kHz1ch8bit.wav -------------------------------------------------------------------------------- /wave/48kHz1ch16bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/audio/HEAD/wave/48kHz1ch16bit.wav -------------------------------------------------------------------------------- /wave/48kHz1ch24bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/audio/HEAD/wave/48kHz1ch24bit.wav -------------------------------------------------------------------------------- /wave/48kHz1ch32bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/audio/HEAD/wave/48kHz1ch32bit.wav -------------------------------------------------------------------------------- /wave/48kHz2ch16bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/audio/HEAD/wave/48kHz2ch16bit.wav -------------------------------------------------------------------------------- /wave/48kHz1ch32bitFloat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/audio/HEAD/wave/48kHz1ch32bitFloat.wav -------------------------------------------------------------------------------- /wave/48kHz1ch64bitFloat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/audio/HEAD/wave/48kHz1ch64bitFloat.wav -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | audio 2 | ===== 3 | [![GoDoc](https://godoc.org/github.com/oov/audio?status.svg)](https://godoc.org/github.com/oov/audio) 4 | 5 | Audio library for Go programming language. 6 | -------------------------------------------------------------------------------- /saturator/saturator.go: -------------------------------------------------------------------------------- 1 | // Package saturator implements saturator. 2 | package saturator 3 | 4 | func Saturate32(s float32) float32 { 5 | switch { 6 | case s > 1: 7 | return 1 8 | case s < -1: 9 | return -1 10 | } 11 | return s 12 | } 13 | 14 | func Saturate64(s float64) float64 { 15 | switch { 16 | case s > 1: 17 | return 1 18 | case s < -1: 19 | return -1 20 | } 21 | return s 22 | } 23 | 24 | func Saturate32Slice(input, output []float32) { 25 | for i, s := range input { 26 | output[i] = Saturate32(s) 27 | } 28 | } 29 | 30 | func Saturate64Slice(input, output []float64) { 31 | for i, s := range input { 32 | output[i] = Saturate64(s) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /converter/converter.go: -------------------------------------------------------------------------------- 1 | // Package converter implements audio sample format converter. 2 | package converter 3 | 4 | type Converter interface { 5 | SampleSize() int 6 | ToFloat32(input []byte, output []float32) 7 | ToFloat64(input []byte, output []float64) 8 | FromFloat32(input []float32, output []byte) 9 | FromFloat64(input []float64, output []byte) 10 | } 11 | 12 | type InterleavedConverter interface { 13 | SampleSize() int 14 | ToFloat32Interleaved(input []byte, outputs [][]float32) 15 | ToFloat64Interleaved(input []byte, outputs [][]float64) 16 | FromFloat32Interleaved(inputs [][]float32, output []byte) 17 | FromFloat64Interleaved(inputs [][]float64, output []byte) 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Masanobu YOSHIOKA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /converter/data_test.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | dataUint8 = []uint8{0, 64, 128, 192, 255} 10 | dataInt16 = []int16{-32768, -16384, 0, 16383, 32767} 11 | dataInt24 = []int32{-2147483648, -1073741824, 0, 1073741823, 2147483647} 12 | dataInt32 = []int32{-2147483648, -1073741824, 0, 1073741823, 2147483647} 13 | dataFloat32 = []float32{-1, -0.5, 0, 0.5, 1} 14 | dataFloat64 = []float64{-1, -0.5, 0, 0.5, 1} 15 | dataLen = len(dataFloat32) 16 | ) 17 | 18 | func testResultUint8(a []uint8, t *testing.T) { 19 | t.Log("min:", a[0], "low:", a[1], "zero:", a[2], "high:", a[3], "max:", a[4]) 20 | for i, s := range dataUint8 { 21 | if math.Abs(float64(s)-float64(a[i])) > 1 { 22 | t.Fail() 23 | } 24 | } 25 | } 26 | 27 | func testResultInt16(a []int16, t *testing.T) { 28 | t.Log("min:", a[0], "low:", a[1], "zero:", a[2], "high:", a[3], "max:", a[4]) 29 | for i, s := range dataInt16 { 30 | if math.Abs(float64(s)-float64(a[i])) > 1 { 31 | t.Fail() 32 | } 33 | } 34 | } 35 | 36 | func testResultInt24(a []int32, t *testing.T) { 37 | t.Log("min:", a[0], "low:", a[1], "zero:", a[2], "high:", a[3], "max:", a[4]) 38 | for i, s := range dataInt24 { 39 | if math.Abs(float64(s)-float64(a[i])) > 0x100 { 40 | t.Fail() 41 | } 42 | } 43 | } 44 | 45 | func testResultInt32(a []int32, t *testing.T) { 46 | t.Log("min:", a[0], "low:", a[1], "zero:", a[2], "high:", a[3], "max:", a[4]) 47 | for i, s := range dataInt32 { 48 | if math.Abs(float64(s)-float64(a[i])) > 1 { 49 | t.Fail() 50 | } 51 | } 52 | } 53 | 54 | func testResultFloat32(a []float32, t *testing.T) { 55 | t.Log("min:", a[0], "low:", a[1], "zero:", a[2], "high:", a[3], "max:", a[4]) 56 | for i, s := range dataFloat32 { 57 | if math.Abs(float64(s)-float64(a[i])) > 0.01 { 58 | t.Fail() 59 | } 60 | } 61 | } 62 | 63 | func testResultFloat64(a []float64, t *testing.T) { 64 | t.Log("min:", a[0], "low:", a[1], "zero:", a[2], "high:", a[3], "max:", a[4]) 65 | for i, s := range dataFloat64 { 66 | if math.Abs(s-a[i]) > 0.01 { 67 | t.Fail() 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /wave/writer_test.go: -------------------------------------------------------------------------------- 1 | package wave 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | var wfext = &WaveFormatExtensible{ 11 | Format: WaveFormatEx{ 12 | FormatTag: WAVE_FORMAT_PCM, 13 | Channels: 2, 14 | SamplesPerSec: 48000, 15 | AvgBytesPerSec: 96000, 16 | BlockAlign: 4, 17 | BitsPerSample: 16, 18 | ExtSize: 0, 19 | }, 20 | } 21 | var samples = [][]float64{ 22 | []float64{-1, 0, 1}, 23 | []float64{1, 0, -1}, 24 | } 25 | var golden = []byte("RIFF\x38\x00\x00\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00\x80\xbb\x00\x00\x00\x77\x01\x00\x04\x00\x10\x00data\x0c\x00\x00\x00\x01\x80\xff\x7f\x00\x00\x00\x00\xff\x7f\x01\x80") 26 | 27 | func TestDirectWriter(t *testing.T) { 28 | f, err := ioutil.TempFile("", "test") 29 | if err != nil { 30 | t.Error(err) 31 | return 32 | } 33 | 34 | defer f.Close() 35 | defer os.Remove(f.Name()) 36 | 37 | w, err := newDirectWriter(f, wfext) 38 | if err != nil { 39 | t.Error(err) 40 | return 41 | } 42 | 43 | n, err := w.WriteFloat64Interleaved(samples) 44 | if err != nil { 45 | t.Error(err) 46 | return 47 | } 48 | if n != 3 { 49 | t.Log("invalid written size:", n) 50 | t.Fail() 51 | return 52 | } 53 | 54 | err = w.Close() 55 | if err != nil { 56 | t.Error(err) 57 | return 58 | } 59 | 60 | b, err := ioutil.ReadFile(f.Name()) 61 | if err != nil { 62 | t.Error(err) 63 | return 64 | } 65 | if !bytes.Equal(golden, b) { 66 | t.Log("golden:", golden) 67 | t.Log("invalid output:", b) 68 | t.Fail() 69 | return 70 | } 71 | } 72 | 73 | func TestTempFileWriter(t *testing.T) { 74 | buf := bytes.NewBufferString("") 75 | w, err := newTempFileWriter(buf, wfext) 76 | if err != nil { 77 | t.Error(err) 78 | return 79 | } 80 | 81 | n, err := w.WriteFloat64Interleaved(samples) 82 | if err != nil { 83 | t.Error(err) 84 | return 85 | } 86 | 87 | if n != 3 { 88 | t.Log("invalid written size:", n) 89 | t.Fail() 90 | return 91 | } 92 | 93 | err = w.Close() 94 | if err != nil { 95 | t.Error(err) 96 | return 97 | } 98 | b := buf.Bytes() 99 | if !bytes.Equal(golden, b) { 100 | t.Log("golden:", golden) 101 | t.Log("invalid output:", b) 102 | t.Fail() 103 | return 104 | } 105 | } 106 | 107 | func TestTempMemWriter(t *testing.T) { 108 | buf := bytes.NewBufferString("") 109 | w, err := newTempMemWriter(buf, wfext) 110 | if err != nil { 111 | t.Error(err) 112 | return 113 | } 114 | 115 | n, err := w.WriteFloat64Interleaved(samples) 116 | if err != nil { 117 | t.Error(err) 118 | return 119 | } 120 | 121 | if n != 3 { 122 | t.Log("invalid written size:", n) 123 | t.Fail() 124 | return 125 | } 126 | 127 | err = w.Close() 128 | if err != nil { 129 | t.Error(err) 130 | return 131 | } 132 | 133 | b := buf.Bytes() 134 | if !bytes.Equal(golden, b) { 135 | t.Log("golden:", golden) 136 | t.Log("invalid output:", b) 137 | t.Fail() 138 | return 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /wave/reader.go: -------------------------------------------------------------------------------- 1 | // Package wave provides support for reading and wrting RIFF Waveform Audio Format File. 2 | package wave 3 | 4 | import ( 5 | "encoding/binary" 6 | "errors" 7 | "github.com/oov/audio" 8 | "io" 9 | ) 10 | 11 | func min(a, b int) int { 12 | if a < b { 13 | return a 14 | } 15 | return b 16 | } 17 | 18 | // NewLimitedReader returns an *io.LimitedReader which waveform audio data from r. 19 | func NewLimitedReader(r io.Reader) (*io.LimitedReader, *WaveFormatExtensible, error) { 20 | var chunk [4]byte 21 | var err error 22 | if _, err = io.ReadFull(r, chunk[:]); err != nil { 23 | return nil, nil, err 24 | } 25 | if string(chunk[:4]) != "RIFF" { 26 | return nil, nil, errors.New("wave: invalid header") 27 | } 28 | 29 | var ln int32 30 | if err = binary.Read(r, binary.LittleEndian, &ln); err != nil { 31 | return nil, nil, err 32 | } 33 | 34 | lr := io.LimitReader(r, int64(ln)) 35 | 36 | if _, err = io.ReadFull(lr, chunk[:]); err != nil { 37 | return nil, nil, err 38 | } 39 | if string(chunk[:4]) != "WAVE" { 40 | return nil, nil, errors.New("wave: invalid header") 41 | } 42 | 43 | var n int 44 | var ignored [4096]byte 45 | 46 | // find "fmt " chunk 47 | 48 | ln = 0 49 | for string(chunk[:4]) != "fmt " { 50 | n, err = io.ReadFull(lr, ignored[:min(len(ignored), int(ln))]) 51 | if err != nil { 52 | return nil, nil, err 53 | } 54 | ln -= int32(n) 55 | if ln != 0 { 56 | continue 57 | } 58 | 59 | if _, err = io.ReadFull(lr, chunk[:]); err != nil { 60 | return nil, nil, err 61 | } 62 | if err = binary.Read(r, binary.LittleEndian, &ln); err != nil { 63 | return nil, nil, err 64 | } 65 | } 66 | 67 | if ln < 16 { 68 | return nil, nil, errors.New("wave: fmt chunk too small") 69 | } 70 | 71 | // read "fmt " chunk 72 | 73 | var wf WaveFormatExtensible 74 | var rd int64 75 | if rd, err = wf.Format.ReadFrom(lr); err != nil { 76 | return nil, nil, err 77 | } 78 | 79 | // ignore unsupported chunk data 80 | 81 | ln -= int32(rd) 82 | for ln > 0 { 83 | n, err = io.ReadFull(lr, ignored[:min(len(ignored), int(ln))]) 84 | if err != nil { 85 | return nil, nil, err 86 | } 87 | ln -= int32(n) 88 | } 89 | 90 | // find "data" chunk 91 | 92 | ln = 0 93 | for string(chunk[:4]) != "data" { 94 | n, err = io.ReadFull(lr, ignored[:min(len(ignored), int(ln))]) 95 | if err != nil { 96 | return nil, nil, err 97 | } 98 | ln -= int32(n) 99 | if ln != 0 { 100 | continue 101 | } 102 | 103 | if _, err = io.ReadFull(lr, chunk[:]); err != nil { 104 | return nil, nil, err 105 | } 106 | if err = binary.Read(r, binary.LittleEndian, &ln); err != nil { 107 | return nil, nil, err 108 | } 109 | } 110 | 111 | return &io.LimitedReader{r, int64(ln)}, &wf, nil 112 | } 113 | 114 | // NewReader returns an audio.InterleavedReader which waveform audio data from r. 115 | func NewReader(r io.Reader) (audio.InterleavedReader, *WaveFormatExtensible, error) { 116 | lr, wf, err := NewLimitedReader(r) 117 | if err != nil { 118 | return nil, nil, err 119 | } 120 | 121 | conv, err := wf.Format.InterleavedConverter() 122 | if err != nil { 123 | return nil, nil, err 124 | } 125 | return audio.NewInterleavedReader(conv, lr), wf, nil 126 | } 127 | -------------------------------------------------------------------------------- /converter/uint8.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | var ( 4 | Uint8 Uint8Converter 5 | ) 6 | 7 | type Uint8Converter uint8 8 | 9 | func (c Uint8Converter) SampleSize() int { 10 | return 1 11 | } 12 | 13 | func (c Uint8Converter) ToFloat32(input []byte, output []float32) { 14 | for i, s := range input { 15 | output[i] = Uint8ToFloat32(s) 16 | } 17 | } 18 | 19 | func (c Uint8Converter) ToFloat32Interleaved(input []byte, outputs [][]float32) { 20 | chs := len(outputs) 21 | for ch, output := range outputs { 22 | for i, o, ln := ch, 0, len(input); i < ln; i += chs { 23 | output[o] = Uint8ToFloat32(input[i]) 24 | o++ 25 | } 26 | } 27 | } 28 | 29 | func (c Uint8Converter) FromFloat32(input []float32, output []byte) { 30 | for i, s := range input { 31 | output[i] = Float32ToUint8(s) 32 | } 33 | } 34 | 35 | func (c Uint8Converter) FromFloat32Interleaved(inputs [][]float32, output []byte) { 36 | for i, o := 0, 0; o < len(output); i++ { 37 | for _, input := range inputs { 38 | output[o] = Float32ToUint8(input[i]) 39 | o++ 40 | } 41 | } 42 | } 43 | 44 | func (c Uint8Converter) ToFloat64(input []byte, output []float64) { 45 | for i, s := range input { 46 | output[i] = Uint8ToFloat64(s) 47 | } 48 | } 49 | 50 | func (c Uint8Converter) ToFloat64Interleaved(input []byte, outputs [][]float64) { 51 | chs := len(outputs) 52 | for ch, output := range outputs { 53 | for i, o, ln := ch, 0, len(input); i < ln; i += chs { 54 | output[o] = Uint8ToFloat64(input[i]) 55 | o++ 56 | } 57 | } 58 | } 59 | 60 | func (c Uint8Converter) FromFloat64(input []float64, output []byte) { 61 | for i, s := range input { 62 | output[i] = Float64ToUint8(s) 63 | } 64 | } 65 | 66 | func (c Uint8Converter) FromFloat64Interleaved(inputs [][]float64, output []byte) { 67 | for i, o := 0, 0; o < len(output); i++ { 68 | for _, input := range inputs { 69 | output[o] = Float64ToUint8(input[i]) 70 | o++ 71 | } 72 | } 73 | } 74 | 75 | const ( 76 | uint8Half = 127 77 | uint8Shifter = 128 78 | uint8Divider = 1.0 / 128.0 79 | ) 80 | 81 | func Uint8ToFloat32(s uint8) float32 { 82 | return (float32(s) - uint8Shifter) * uint8Divider 83 | } 84 | 85 | func Uint8ToFloat64(s uint8) float64 { 86 | return (float64(s) - uint8Shifter) * uint8Divider 87 | } 88 | 89 | func Float32ToUint8(s float32) uint8 { 90 | return uint8(s*uint8Half + uint8Shifter) 91 | } 92 | 93 | func Float64ToUint8(s float64) uint8 { 94 | return uint8(s*uint8Half + uint8Shifter) 95 | } 96 | 97 | func Uint8ToFloat32Slice(input []uint8, output []float32) { 98 | for i, s := range input { 99 | output[i] = Uint8ToFloat32(s) 100 | } 101 | } 102 | 103 | func Uint8ToFloat64Slice(input []uint8, output []float64) { 104 | for i, s := range input { 105 | output[i] = Uint8ToFloat64(s) 106 | } 107 | } 108 | 109 | func Float32ToUint8Slice(input []float32, output []uint8) { 110 | for i, s := range input { 111 | output[i] = Float32ToUint8(s) 112 | } 113 | } 114 | 115 | func Float64ToUint8Slice(input []float64, output []uint8) { 116 | for i, s := range input { 117 | output[i] = Float64ToUint8(s) 118 | } 119 | } 120 | 121 | func ByteToUint8(a byte) uint8 { 122 | return a 123 | } 124 | 125 | func Uint8ToByte(s uint8) byte { 126 | return s 127 | } 128 | -------------------------------------------------------------------------------- /resample.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | //resample.go is a audio resampler. 4 | // 5 | //Usage: 6 | // 7 | // go run resample.go [options] infile 8 | // 9 | package main 10 | 11 | import ( 12 | "flag" 13 | "fmt" 14 | "github.com/oov/audio/resampler" 15 | "github.com/oov/audio/saturator" 16 | "github.com/oov/audio/wave" 17 | "io" 18 | "os" 19 | ) 20 | 21 | var ( 22 | freq = flag.Float64("f", 0.8, "Frequency ratio") 23 | quality = flag.Int("q", 5, "Resampling quality(0-10)") 24 | ) 25 | 26 | func main() { 27 | flag.Parse() 28 | 29 | if flag.NArg() == 0 { 30 | fmt.Println("resample.go is a audio resampler.") 31 | fmt.Println() 32 | fmt.Println("Usage:") 33 | fmt.Println() 34 | fmt.Println(" go run resample.go [options] infile") 35 | fmt.Println() 36 | fmt.Println("The options are:") 37 | fmt.Println() 38 | flag.PrintDefaults() 39 | return 40 | } 41 | 42 | f, err := os.Open(flag.Arg(0)) 43 | if err != nil { 44 | fmt.Println(err) 45 | return 46 | } 47 | 48 | defer f.Close() 49 | 50 | f2, err := os.Create(flag.Arg(0) + `.out.wav`) 51 | if err != nil { 52 | fmt.Println(err) 53 | return 54 | } 55 | 56 | defer f2.Close() 57 | 58 | ar, wfext, err := wave.NewReader(f) 59 | if err != nil { 60 | fmt.Println(err) 61 | return 62 | } 63 | 64 | aw, err := wave.NewWriter(f2, wfext) 65 | if err != nil { 66 | fmt.Println(err) 67 | return 68 | } 69 | 70 | defer aw.Close() 71 | 72 | fmt.Println("Input file:") 73 | fmt.Println(" Path:", flag.Arg(0)) 74 | fmt.Println(" Samplerate:", wfext.Format.SamplesPerSec) 75 | fmt.Println(" Channels:", wfext.Format.Channels) 76 | fmt.Println(" Bits:", wfext.Format.BitsPerSample) 77 | fmt.Println() 78 | fmt.Println("Output file:") 79 | fmt.Println(" Path:", flag.Arg(0)+`.out.wav`) 80 | fmt.Println(" Samplerate:", wfext.Format.SamplesPerSec) 81 | fmt.Println(" Channels:", wfext.Format.Channels) 82 | fmt.Println(" Bits:", wfext.Format.BitsPerSample) 83 | fmt.Println() 84 | 85 | infreq := int(wfext.Format.SamplesPerSec) 86 | outfreq := int(float64(wfext.Format.SamplesPerSec) * *freq) 87 | fmt.Println("resampling:") 88 | fmt.Printf(" %dHz to %dHz\n", infreq, outfreq) 89 | 90 | inBuf, outBuf := [][]float64{}, [][]float64{} 91 | for i := 0; i < int(wfext.Format.Channels); i++ { 92 | inBuf = append(inBuf, make([]float64, wfext.Format.SamplesPerSec)) 93 | outBuf = append(outBuf, make([]float64, wfext.Format.SamplesPerSec)) 94 | } 95 | in, out := make([][]float64, wfext.Format.Channels), make([][]float64, wfext.Format.Channels) 96 | 97 | rs := resampler.NewWithSkipZeros(int(wfext.Format.Channels), infreq, outfreq, *quality) 98 | var n int 99 | var rerr error 100 | for rerr != io.EOF { 101 | // read 102 | n, rerr = ar.ReadFloat64Interleaved(inBuf) 103 | if rerr != nil && rerr != io.EOF { 104 | fmt.Println(err) 105 | return 106 | } 107 | for i, inbuf := range inBuf { 108 | in[i] = inbuf[:n] 109 | } 110 | 111 | for len(in[0]) > 0 { 112 | // resample 113 | for i, inbuf := range in { 114 | rn, wn := rs.ProcessFloat64(i, inbuf, outBuf[i]) 115 | in[i] = inbuf[rn:] 116 | out[i] = outBuf[i][:wn] 117 | saturator.Saturate64Slice(out[i], out[i]) 118 | } 119 | 120 | // write 121 | _, err = aw.WriteFloat64Interleaved(out) 122 | if err != nil { 123 | fmt.Println(err) 124 | return 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /converter/float64.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | var ( 8 | Float64 Float64Converter 9 | ) 10 | 11 | type Float64Converter float64 12 | 13 | func (c Float64Converter) SampleSize() int { 14 | return 8 15 | } 16 | 17 | func (c Float64Converter) ToFloat32(input []byte, output []float32) { 18 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 19 | output[o] = Float64ToFloat32(ByteToFloat64(input[i], input[i+1], input[i+2], input[i+3], input[i+4], input[i+5], input[i+6], input[i+7])) 20 | o++ 21 | } 22 | } 23 | 24 | func (c Float64Converter) ToFloat64(input []byte, output []float64) { 25 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 26 | output[o] = ByteToFloat64(input[i], input[i+1], input[i+2], input[i+3], input[i+4], input[i+5], input[i+6], input[i+7]) 27 | o++ 28 | } 29 | } 30 | 31 | func (c Float64Converter) FromFloat32(input []float32, output []byte) { 32 | o := 0 33 | for _, s := range input { 34 | output[o], output[o+1], output[o+2], output[o+3], output[o+4], output[o+5], output[o+6], output[o+7] = Float64ToByte(Float32ToFloat64(s)) 35 | o += c.SampleSize() 36 | } 37 | } 38 | 39 | func (c Float64Converter) FromFloat64(input []float64, output []byte) { 40 | o := 0 41 | for _, s := range input { 42 | output[o], output[o+1], output[o+2], output[o+3], output[o+4], output[o+5], output[o+6], output[o+7] = Float64ToByte(s) 43 | o += c.SampleSize() 44 | } 45 | } 46 | 47 | func (c Float64Converter) ToFloat32Interleaved(input []byte, outputs [][]float32) { 48 | chs := len(outputs) 49 | for ch, output := range outputs { 50 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 51 | output[o] = Float64ToFloat32(ByteToFloat64(input[i], input[i+1], input[i+2], input[i+3], input[i+4], input[i+5], input[i+6], input[i+7])) 52 | o++ 53 | } 54 | } 55 | } 56 | 57 | func (c Float64Converter) ToFloat64Interleaved(input []byte, outputs [][]float64) { 58 | chs := len(outputs) 59 | for ch, output := range outputs { 60 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 61 | output[o] = ByteToFloat64(input[i], input[i+1], input[i+2], input[i+3], input[i+4], input[i+5], input[i+6], input[i+7]) 62 | o++ 63 | } 64 | } 65 | } 66 | 67 | func (c Float64Converter) FromFloat32Interleaved(inputs [][]float32, output []byte) { 68 | for i, o := 0, 0; o < len(output); i++ { 69 | for _, input := range inputs { 70 | output[o], output[o+1], output[o+2], output[o+3], output[o+4], output[o+5], output[o+6], output[o+7] = Float64ToByte(Float32ToFloat64(input[i])) 71 | o += c.SampleSize() 72 | } 73 | } 74 | } 75 | 76 | func (c Float64Converter) FromFloat64Interleaved(inputs [][]float64, output []byte) { 77 | for i, o := 0, 0; o < len(output); i++ { 78 | for _, input := range inputs { 79 | output[o], output[o+1], output[o+2], output[o+3], output[o+4], output[o+5], output[o+6], output[o+7] = Float64ToByte(input[i]) 80 | o += c.SampleSize() 81 | } 82 | } 83 | } 84 | 85 | func ByteToFloat64(a, b, c, d, e, f, g, h byte) float64 { 86 | return math.Float64frombits(uint64(a) | (uint64(b) << 8) | (uint64(c) << 16) | (uint64(d) << 24) | (uint64(e) << 32) | (uint64(f) << 40) | (uint64(g) << 48) | (uint64(h) << 56)) 87 | } 88 | 89 | func Float64ToByte(s float64) (byte, byte, byte, byte, byte, byte, byte, byte) { 90 | i := math.Float64bits(s) 91 | return byte(i), byte(i >> 8), byte(i >> 16), byte(i >> 24), byte(i >> 32), byte(i >> 40), byte(i >> 48), byte(i >> 56) 92 | } 93 | -------------------------------------------------------------------------------- /converter/float32.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | var ( 8 | Float32 Float32Converter 9 | ) 10 | 11 | type Float32Converter float32 12 | 13 | func (c Float32Converter) SampleSize() int { 14 | return 4 15 | } 16 | 17 | func (c Float32Converter) ToFloat32(input []byte, output []float32) { 18 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 19 | output[o] = ByteToFloat32(input[i], input[i+1], input[i+2], input[i+3]) 20 | o++ 21 | } 22 | } 23 | 24 | func (c Float32Converter) ToFloat64(input []byte, output []float64) { 25 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 26 | output[o] = Float32ToFloat64(ByteToFloat32(input[i], input[i+1], input[i+2], input[i+3])) 27 | o++ 28 | } 29 | } 30 | 31 | func (c Float32Converter) FromFloat32(input []float32, output []byte) { 32 | o := 0 33 | for _, s := range input { 34 | output[o], output[o+1], output[o+2], output[o+3] = Float32ToByte(s) 35 | o += c.SampleSize() 36 | } 37 | } 38 | 39 | func (c Float32Converter) FromFloat64(input []float64, output []byte) { 40 | o := 0 41 | for _, s := range input { 42 | output[o], output[o+1], output[o+2], output[o+3] = Float32ToByte(Float64ToFloat32(s)) 43 | o += c.SampleSize() 44 | } 45 | } 46 | 47 | func (c Float32Converter) ToFloat32Interleaved(input []byte, outputs [][]float32) { 48 | chs := len(outputs) 49 | for ch, output := range outputs { 50 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 51 | output[o] = ByteToFloat32(input[i], input[i+1], input[i+2], input[i+3]) 52 | o++ 53 | } 54 | } 55 | } 56 | 57 | func (c Float32Converter) ToFloat64Interleaved(input []byte, outputs [][]float64) { 58 | chs := len(outputs) 59 | for ch, output := range outputs { 60 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 61 | output[o] = Float32ToFloat64(ByteToFloat32(input[i], input[i+1], input[i+2], input[i+3])) 62 | o++ 63 | } 64 | } 65 | } 66 | 67 | func (c Float32Converter) FromFloat32Interleaved(inputs [][]float32, output []byte) { 68 | for i, o := 0, 0; o < len(output); i++ { 69 | for _, input := range inputs { 70 | output[o], output[o+1], output[o+2], output[o+3] = Float32ToByte(input[i]) 71 | o += c.SampleSize() 72 | } 73 | } 74 | } 75 | 76 | func (c Float32Converter) FromFloat64Interleaved(inputs [][]float64, output []byte) { 77 | for i, o := 0, 0; o < len(output); i++ { 78 | for _, input := range inputs { 79 | output[o], output[o+1], output[o+2], output[o+3] = Float32ToByte(Float64ToFloat32(input[i])) 80 | o += c.SampleSize() 81 | } 82 | } 83 | } 84 | 85 | func Float32ToFloat64(s float32) float64 { 86 | return float64(s) 87 | } 88 | 89 | func Float64ToFloat32(s float64) float32 { 90 | return float32(s) 91 | } 92 | 93 | func Float32ToFloat64Slice(input []float32, output []float64) { 94 | for i, s := range input { 95 | output[i] = Float32ToFloat64(s) 96 | } 97 | } 98 | 99 | func Float64ToFloat32Slice(input []float64, output []float32) { 100 | for i, s := range input { 101 | output[i] = Float64ToFloat32(s) 102 | } 103 | } 104 | 105 | func ByteToFloat32(a, b, c, d byte) float32 { 106 | return math.Float32frombits(uint32(a) | (uint32(b) << 8) | (uint32(c) << 16) | (uint32(d) << 24)) 107 | } 108 | 109 | func Float32ToByte(s float32) (byte, byte, byte, byte) { 110 | i := math.Float32bits(s) 111 | return byte(i), byte(i >> 8), byte(i >> 16), byte(i >> 24) 112 | } 113 | -------------------------------------------------------------------------------- /converter/int16.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | var ( 4 | Int16 Int16Converter 5 | ) 6 | 7 | type Int16Converter int16 8 | 9 | func (c Int16Converter) SampleSize() int { 10 | return 2 11 | } 12 | 13 | func (c Int16Converter) ToFloat32(input []byte, output []float32) { 14 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 15 | output[o] = Int16ToFloat32(ByteToInt16(input[i], input[i+1])) 16 | o++ 17 | } 18 | } 19 | 20 | func (c Int16Converter) ToFloat32Interleaved(input []byte, outputs [][]float32) { 21 | chs := len(outputs) 22 | for ch, output := range outputs { 23 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 24 | output[o] = Int16ToFloat32(ByteToInt16(input[i], input[i+1])) 25 | o++ 26 | } 27 | } 28 | } 29 | 30 | func (c Int16Converter) FromFloat32(input []float32, output []byte) { 31 | o := 0 32 | for _, s := range input { 33 | output[o], output[o+1] = Int16ToByte(Float32ToInt16(s)) 34 | o += c.SampleSize() 35 | } 36 | } 37 | 38 | func (c Int16Converter) FromFloat32Interleaved(inputs [][]float32, output []byte) { 39 | for i, o := 0, 0; o < len(output); i++ { 40 | for _, input := range inputs { 41 | output[o], output[o+1] = Int16ToByte(Float32ToInt16(input[i])) 42 | o += c.SampleSize() 43 | } 44 | } 45 | } 46 | 47 | func (c Int16Converter) ToFloat64(input []byte, output []float64) { 48 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 49 | output[o] = Int16ToFloat64(ByteToInt16(input[i], input[i+1])) 50 | o++ 51 | } 52 | } 53 | 54 | func (c Int16Converter) ToFloat64Interleaved(input []byte, outputs [][]float64) { 55 | chs := len(outputs) 56 | for ch, output := range outputs { 57 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 58 | output[o] = Int16ToFloat64(ByteToInt16(input[i], input[i+1])) 59 | o++ 60 | } 61 | } 62 | } 63 | 64 | func (c Int16Converter) FromFloat64(input []float64, output []byte) { 65 | o := 0 66 | for _, s := range input { 67 | output[o], output[o+1] = Int16ToByte(Float64ToInt16(s)) 68 | o += c.SampleSize() 69 | } 70 | } 71 | 72 | func (c Int16Converter) FromFloat64Interleaved(inputs [][]float64, output []byte) { 73 | for i, o := 0, 0; o < len(output); i++ { 74 | for _, input := range inputs { 75 | output[o], output[o+1] = Int16ToByte(Float64ToInt16(input[i])) 76 | o += c.SampleSize() 77 | } 78 | } 79 | } 80 | 81 | const ( 82 | int16Max = 32767.0 83 | int16Divider = 1.0 / 32768.0 84 | ) 85 | 86 | func Int16ToFloat32(s int16) float32 { 87 | return float32(s) * int16Divider 88 | } 89 | 90 | func Int16ToFloat64(s int16) float64 { 91 | return float64(s) * int16Divider 92 | } 93 | 94 | func Float32ToInt16(s float32) int16 { 95 | return int16(s * int16Max) 96 | } 97 | 98 | func Float64ToInt16(s float64) int16 { 99 | return int16(s * int16Max) 100 | } 101 | 102 | func Int16ToFloat32Slice(input []int16, output []float32) { 103 | for i, s := range input { 104 | output[i] = Int16ToFloat32(s) 105 | } 106 | } 107 | 108 | func Int16ToFloat64Slice(input []int16, output []float64) { 109 | for i, s := range input { 110 | output[i] = Int16ToFloat64(s) 111 | } 112 | } 113 | 114 | func Float32ToInt16Slice(input []float32, output []int16) { 115 | for i, s := range input { 116 | output[i] = Float32ToInt16(s) 117 | } 118 | } 119 | 120 | func Float64ToInt16Slice(input []float64, output []int16) { 121 | for i, s := range input { 122 | output[i] = Float64ToInt16(s) 123 | } 124 | } 125 | 126 | func ByteToInt16(a, b byte) int16 { 127 | return int16(a) | (int16(b) << 8) 128 | } 129 | 130 | func Int16ToByte(s int16) (byte, byte) { 131 | return byte(s), byte(s >> 8) 132 | } 133 | -------------------------------------------------------------------------------- /converter/int24.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | var ( 4 | Int24 Int24Converter 5 | ) 6 | 7 | type Int24Converter int32 8 | 9 | func (c Int24Converter) SampleSize() int { 10 | return 3 11 | } 12 | 13 | func (c Int24Converter) ToFloat32(input []byte, output []float32) { 14 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 15 | output[o] = Int24ToFloat32(ByteToInt24(input[i], input[i+1], input[i+2])) 16 | o++ 17 | } 18 | } 19 | 20 | func (c Int24Converter) ToFloat32Interleaved(input []byte, outputs [][]float32) { 21 | chs := len(outputs) 22 | for ch, output := range outputs { 23 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 24 | output[o] = Int24ToFloat32(ByteToInt24(input[i], input[i+1], input[i+2])) 25 | o++ 26 | } 27 | } 28 | } 29 | 30 | func (c Int24Converter) FromFloat32(input []float32, output []byte) { 31 | o := 0 32 | for _, s := range input { 33 | output[o], output[o+1], output[o+2] = Int24ToByte(Float32ToInt24(s)) 34 | o += c.SampleSize() 35 | } 36 | } 37 | 38 | func (c Int24Converter) FromFloat32Interleaved(inputs [][]float32, output []byte) { 39 | for i, o := 0, 0; o < len(output); i++ { 40 | for _, input := range inputs { 41 | output[o], output[o+1], output[o+2] = Int24ToByte(Float32ToInt24(input[i])) 42 | o += c.SampleSize() 43 | } 44 | } 45 | } 46 | 47 | func (c Int24Converter) ToFloat64(input []byte, output []float64) { 48 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 49 | output[o] = Int24ToFloat64(ByteToInt24(input[i], input[i+1], input[i+2])) 50 | o++ 51 | } 52 | } 53 | 54 | func (c Int24Converter) ToFloat64Interleaved(input []byte, outputs [][]float64) { 55 | chs := len(outputs) 56 | for ch, output := range outputs { 57 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 58 | output[o] = Int24ToFloat64(ByteToInt24(input[i], input[i+1], input[i+2])) 59 | o++ 60 | } 61 | } 62 | } 63 | 64 | func (c Int24Converter) FromFloat64(input []float64, output []byte) { 65 | o := 0 66 | for _, s := range input { 67 | output[o], output[o+1], output[o+2] = Int24ToByte(Float64ToInt24(s)) 68 | o += c.SampleSize() 69 | } 70 | } 71 | 72 | func (c Int24Converter) FromFloat64Interleaved(inputs [][]float64, output []byte) { 73 | for i, o := 0, 0; o < len(output); i++ { 74 | for _, input := range inputs { 75 | output[o], output[o+1], output[o+2] = Int24ToByte(Float64ToInt24(input[i])) 76 | o += c.SampleSize() 77 | } 78 | } 79 | } 80 | 81 | const ( 82 | int24Divider = 1.0 / (2147483648.0) 83 | int24Max = 2147483648.0 - 256.0 84 | ) 85 | 86 | func Int24ToFloat32(s int32) float32 { 87 | return float32(s) * int24Divider 88 | } 89 | 90 | func Int24ToFloat64(s int32) float64 { 91 | return float64(s) * int24Divider 92 | } 93 | 94 | func Float32ToInt24(s float32) int32 { 95 | return int32(s * int24Max) 96 | } 97 | 98 | func Float64ToInt24(s float64) int32 { 99 | return int32(s * int24Max) 100 | } 101 | 102 | /* 103 | func Int24ToFloat32Slice(input []int32, output []float32) { 104 | for i, s := range input { 105 | output[i] = Int24ToFloat32(s) 106 | } 107 | } 108 | 109 | func Int24ToFloat64Slice(input []int32, output []float64) { 110 | for i, s := range input { 111 | output[i] = Int24ToFloat64(s) 112 | } 113 | } 114 | 115 | func Float32ToInt24Slice(input []float32, output []int32) { 116 | for i, s := range input { 117 | output[i] = Float32ToInt24(s) 118 | } 119 | } 120 | 121 | func Float64ToInt24Slice(input []float64, output []int32) { 122 | for i, s := range input { 123 | output[i] = Float64ToInt24(s) 124 | } 125 | } 126 | */ 127 | 128 | func ByteToInt24(a, b, c byte) int32 { 129 | return (int32(a) << 8) | (int32(b) << 16) | (int32(c) << 24) 130 | } 131 | 132 | func Int24ToByte(s int32) (byte, byte, byte) { 133 | return byte(s >> 8), byte(s >> 16), byte(s >> 24) 134 | } 135 | -------------------------------------------------------------------------------- /converter/int32.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | var ( 4 | Int32 Int32Converter 5 | ) 6 | 7 | type Int32Converter int32 8 | 9 | func (c Int32Converter) SampleSize() int { 10 | return 4 11 | } 12 | 13 | func (c Int32Converter) ToFloat32(input []byte, output []float32) { 14 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 15 | output[o] = Int32ToFloat32(ByteToInt32(input[i], input[i+1], input[i+2], input[i+3])) 16 | o++ 17 | } 18 | } 19 | 20 | func (c Int32Converter) ToFloat32Interleaved(input []byte, outputs [][]float32) { 21 | chs := len(outputs) 22 | for ch, output := range outputs { 23 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 24 | output[o] = Int32ToFloat32(ByteToInt32(input[i], input[i+1], input[i+2], input[i+3])) 25 | o++ 26 | } 27 | } 28 | } 29 | 30 | func (c Int32Converter) FromFloat32(input []float32, output []byte) { 31 | o := 0 32 | for _, s := range input { 33 | output[o], output[o+1], output[o+2], output[o+3] = Int32ToByte(Float32ToInt32(s)) 34 | o += c.SampleSize() 35 | } 36 | } 37 | 38 | func (c Int32Converter) FromFloat32Interleaved(inputs [][]float32, output []byte) { 39 | for i, o := 0, 0; o < len(output); i++ { 40 | for _, input := range inputs { 41 | output[o], output[o+1], output[o+2], output[o+3] = Int32ToByte(Float32ToInt32(input[i])) 42 | o += c.SampleSize() 43 | } 44 | } 45 | } 46 | 47 | func (c Int32Converter) ToFloat64(input []byte, output []float64) { 48 | for i, o, ln := 0, 0, len(input); i < ln; i += c.SampleSize() { 49 | output[o] = Int32ToFloat64(ByteToInt32(input[i], input[i+1], input[i+2], input[i+3])) 50 | o++ 51 | } 52 | } 53 | 54 | func (c Int32Converter) ToFloat64Interleaved(input []byte, outputs [][]float64) { 55 | chs := len(outputs) 56 | for ch, output := range outputs { 57 | for i, o, ln := ch*c.SampleSize(), 0, len(input); i < ln; i += chs * c.SampleSize() { 58 | output[o] = Int32ToFloat64(ByteToInt32(input[i], input[i+1], input[i+2], input[i+3])) 59 | o++ 60 | } 61 | } 62 | } 63 | 64 | func (c Int32Converter) FromFloat64(input []float64, output []byte) { 65 | o := 0 66 | for _, s := range input { 67 | output[o], output[o+1], output[o+2], output[o+3] = Int32ToByte(Float64ToInt32(s)) 68 | o += c.SampleSize() 69 | } 70 | } 71 | 72 | func (c Int32Converter) FromFloat64Interleaved(inputs [][]float64, output []byte) { 73 | for i, o := 0, 0; o < len(output); i++ { 74 | for _, input := range inputs { 75 | output[o], output[o+1], output[o+2], output[o+3] = Int32ToByte(Float64ToInt32(input[i])) 76 | o += c.SampleSize() 77 | } 78 | } 79 | } 80 | 81 | const ( 82 | int32Max = 2147483647 83 | int32Divider = 1.0 / 2147483648.0 84 | ) 85 | 86 | func Int32ToFloat32(s int32) float32 { 87 | return float32(s) * int32Divider 88 | } 89 | 90 | func Int32ToFloat64(s int32) float64 { 91 | return float64(s) * int32Divider 92 | } 93 | 94 | func Float32ToInt32(s float32) int32 { 95 | return int32(float64(s) * int32Max) 96 | } 97 | 98 | func Float64ToInt32(s float64) int32 { 99 | return int32(s * int32Max) 100 | } 101 | 102 | func Int32ToFloat32Slice(input []int32, output []float32) { 103 | for i, s := range input { 104 | output[i] = Int32ToFloat32(s) 105 | } 106 | } 107 | 108 | func Int32ToFloat64Slice(input []int32, output []float64) { 109 | for i, s := range input { 110 | output[i] = Int32ToFloat64(s) 111 | } 112 | } 113 | 114 | func Float32ToInt32Slice(input []float32, output []int32) { 115 | for i, s := range input { 116 | output[i] = Float32ToInt32(s) 117 | } 118 | } 119 | 120 | func Float64ToInt32Slice(input []float64, output []int32) { 121 | for i, s := range input { 122 | output[i] = Float64ToInt32(s) 123 | } 124 | } 125 | 126 | func ByteToInt32(a, b, c, d byte) int32 { 127 | return int32(a) | (int32(b) << 8) | (int32(c) << 16) | (int32(d) << 24) 128 | } 129 | 130 | func Int32ToByte(s int32) (byte, byte, byte, byte) { 131 | return byte(s), byte(s >> 8), byte(s >> 16), byte(s >> 24) 132 | } 133 | -------------------------------------------------------------------------------- /converter/uint8_test.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUint8ToFloat32(t *testing.T) { 8 | o := make([]float32, dataLen) 9 | Uint8ToFloat32Slice(dataUint8, o) 10 | testResultFloat32(o, t) 11 | } 12 | 13 | func TestFloat32ToUint8(t *testing.T) { 14 | o := make([]uint8, dataLen) 15 | Float32ToUint8Slice(dataFloat32, o) 16 | testResultUint8(o, t) 17 | } 18 | 19 | func TestUint8ToFloat64(t *testing.T) { 20 | o := make([]float64, dataLen) 21 | Uint8ToFloat64Slice(dataUint8, o) 22 | testResultFloat64(o, t) 23 | } 24 | 25 | func TestFloat64ToUint8(t *testing.T) { 26 | o := make([]uint8, dataLen) 27 | Float64ToUint8Slice(dataFloat64, o) 28 | testResultUint8(o, t) 29 | } 30 | 31 | func TestUint8ConverterToFloat32(t *testing.T) { 32 | o := make([]float32, dataLen) 33 | input := make([]byte, dataLen*Uint8.SampleSize()) 34 | for i, s := range dataUint8 { 35 | input[i*Uint8.SampleSize()] = s 36 | } 37 | 38 | Uint8.ToFloat32(input, o) 39 | testResultFloat32(o, t) 40 | } 41 | 42 | func TestUint8ConverterToFloat32Interleaved(t *testing.T) { 43 | outputs := make([][]float32, dataLen) 44 | for i := range outputs { 45 | outputs[i] = make([]float32, 2) 46 | } 47 | 48 | input := make([]byte, dataLen*2*Uint8.SampleSize()) 49 | for i, s := range dataUint8 { 50 | input[i*Uint8.SampleSize()] = s 51 | } 52 | for i, s := range dataUint8 { 53 | input[(dataLen+i)*Uint8.SampleSize()] = s 54 | } 55 | 56 | Uint8.ToFloat32Interleaved(input, outputs) 57 | testResultFloat32([]float32{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 58 | testResultFloat32([]float32{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 59 | } 60 | 61 | func TestUint8ConverterFromFloat32(t *testing.T) { 62 | output := make([]byte, dataLen*Uint8.SampleSize()) 63 | Uint8.FromFloat32(dataFloat32, output) 64 | testResultUint8(output[:dataLen], t) 65 | } 66 | 67 | func TestUint8ConverterFromFloat32Interleaved(t *testing.T) { 68 | inputs := make([][]float32, dataLen) 69 | for i := range inputs { 70 | inputs[i] = []float32{dataFloat32[i], dataFloat32[i]} 71 | } 72 | output := make([]byte, dataLen*2*Uint8.SampleSize()) 73 | Uint8.FromFloat32Interleaved(inputs, output) 74 | testResultUint8(output[:dataLen], t) 75 | testResultUint8(output[dataLen:], t) 76 | } 77 | 78 | func TestUint8ConverterToFloat64(t *testing.T) { 79 | o := make([]float64, dataLen) 80 | input := make([]byte, dataLen*Uint8.SampleSize()) 81 | for i, s := range dataUint8 { 82 | input[i*Uint8.SampleSize()] = s 83 | } 84 | 85 | Uint8.ToFloat64(input, o) 86 | testResultFloat64(o, t) 87 | } 88 | 89 | func TestUint8ConverterToFloat64Interleaved(t *testing.T) { 90 | outputs := make([][]float64, dataLen) 91 | for i := range outputs { 92 | outputs[i] = make([]float64, 2) 93 | } 94 | 95 | input := make([]byte, dataLen*2*Uint8.SampleSize()) 96 | for i, s := range dataUint8 { 97 | input[i*Uint8.SampleSize()] = s 98 | } 99 | for i, s := range dataUint8 { 100 | input[(dataLen+i)*Uint8.SampleSize()] = s 101 | } 102 | 103 | Uint8.ToFloat64Interleaved(input, outputs) 104 | testResultFloat64([]float64{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 105 | testResultFloat64([]float64{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 106 | } 107 | 108 | func TestUint8ConverterFromFloat64(t *testing.T) { 109 | output := make([]byte, dataLen*Uint8.SampleSize()) 110 | Uint8.FromFloat64(dataFloat64, output) 111 | testResultUint8(output[:dataLen], t) 112 | } 113 | 114 | func TestUint8ConverterFromFloat64Interleaved(t *testing.T) { 115 | inputs := make([][]float64, dataLen) 116 | for i := range inputs { 117 | inputs[i] = []float64{dataFloat64[i], dataFloat64[i]} 118 | } 119 | output := make([]byte, dataLen*2*Uint8.SampleSize()) 120 | Uint8.FromFloat64Interleaved(inputs, output) 121 | testResultUint8(output[:dataLen], t) 122 | testResultUint8(output[dataLen:], t) 123 | } 124 | -------------------------------------------------------------------------------- /audio.go: -------------------------------------------------------------------------------- 1 | package audio 2 | 3 | import ( 4 | "github.com/oov/audio/converter" 5 | "io" 6 | ) 7 | 8 | type Reader interface { 9 | ReadFloat32(p []float32) (n int, err error) 10 | ReadFloat64(p []float64) (n int, err error) 11 | } 12 | 13 | type Writer interface { 14 | WriteFloat32(p []float32) (n int, err error) 15 | WriteFloat64(p []float64) (n int, err error) 16 | } 17 | 18 | type InterleavedReader interface { 19 | ReadFloat32Interleaved(p [][]float32) (n int, err error) 20 | ReadFloat64Interleaved(p [][]float64) (n int, err error) 21 | } 22 | 23 | type InterleavedWriter interface { 24 | WriteFloat32Interleaved(p [][]float32) (n int, err error) 25 | WriteFloat64Interleaved(p [][]float64) (n int, err error) 26 | } 27 | 28 | type reader struct { 29 | conv converter.Converter 30 | r io.Reader 31 | buf []byte 32 | } 33 | 34 | func NewReader(conv converter.Converter, r io.Reader) Reader { 35 | return &reader{ 36 | conv: conv, 37 | r: r, 38 | } 39 | } 40 | 41 | func (r *reader) ReadFloat32(p []float32) (n int, err error) { 42 | ln := len(p) 43 | if ln > len(r.buf) { 44 | r.buf = make([]byte, ln) 45 | } 46 | 47 | n, err = r.r.Read(r.buf[:ln]) 48 | r.conv.ToFloat32(r.buf[:n], p) 49 | return 50 | } 51 | 52 | func (r *reader) ReadFloat64(p []float64) (n int, err error) { 53 | ln := len(p) 54 | if ln > len(r.buf) { 55 | r.buf = make([]byte, ln) 56 | } 57 | 58 | n, err = r.r.Read(r.buf[:ln]) 59 | r.conv.ToFloat64(r.buf[:n], p) 60 | return 61 | } 62 | 63 | type interleavedReader struct { 64 | conv converter.InterleavedConverter 65 | r io.Reader 66 | buf []byte 67 | } 68 | 69 | func NewInterleavedReader(conv converter.InterleavedConverter, r io.Reader) InterleavedReader { 70 | return &interleavedReader{ 71 | conv: conv, 72 | r: r, 73 | } 74 | } 75 | 76 | func (r *interleavedReader) ReadFloat32Interleaved(p [][]float32) (n int, err error) { 77 | ln := len(p) * len(p[0]) * r.conv.SampleSize() 78 | if ln > len(r.buf) { 79 | r.buf = make([]byte, ln) 80 | } 81 | 82 | n, err = r.r.Read(r.buf[:ln]) 83 | r.conv.ToFloat32Interleaved(r.buf[:n], p) 84 | n /= len(p) * r.conv.SampleSize() 85 | return 86 | } 87 | 88 | func (r *interleavedReader) ReadFloat64Interleaved(p [][]float64) (n int, err error) { 89 | ln := len(p) * len(p[0]) * r.conv.SampleSize() 90 | if ln > len(r.buf) { 91 | r.buf = make([]byte, ln) 92 | } 93 | 94 | n, err = r.r.Read(r.buf[:ln]) 95 | r.conv.ToFloat64Interleaved(r.buf[:n], p) 96 | n /= len(p) * r.conv.SampleSize() 97 | return 98 | } 99 | 100 | type writer struct { 101 | w io.Writer 102 | buf []byte 103 | conv converter.Converter 104 | } 105 | 106 | func NewWriter(conv converter.Converter, w io.Writer) Writer { 107 | return Writer(&writer{w: w, conv: conv}) 108 | } 109 | 110 | func (w *writer) WriteFloat32(p []float32) (n int, err error) { 111 | ln := len(p) 112 | if ln > len(w.buf) { 113 | w.buf = make([]byte, ln) 114 | } 115 | 116 | w.conv.FromFloat32(p, w.buf[:ln]) 117 | n, err = w.w.Write(w.buf[:ln*w.conv.SampleSize()]) 118 | return 119 | } 120 | 121 | func (w *writer) WriteFloat64(p []float64) (n int, err error) { 122 | ln := len(p) 123 | if ln > len(w.buf) { 124 | w.buf = make([]byte, ln) 125 | } 126 | 127 | w.conv.FromFloat64(p, w.buf[:ln]) 128 | n, err = w.w.Write(w.buf[:ln*w.conv.SampleSize()]) 129 | return 130 | } 131 | 132 | type interleavedWriter struct { 133 | w io.Writer 134 | buf []byte 135 | conv converter.InterleavedConverter 136 | } 137 | 138 | func NewInterleavedWriter(conv converter.InterleavedConverter, w io.Writer) InterleavedWriter { 139 | return &interleavedWriter{ 140 | w: w, 141 | conv: conv, 142 | } 143 | } 144 | 145 | func (w *interleavedWriter) WriteFloat32Interleaved(p [][]float32) (n int, err error) { 146 | ln := len(p) * len(p[0]) * w.conv.SampleSize() 147 | if ln > len(w.buf) { 148 | w.buf = make([]byte, ln) 149 | } 150 | 151 | w.conv.FromFloat32Interleaved(p, w.buf[:ln]) 152 | n, err = w.w.Write(w.buf[:ln]) 153 | n /= len(p) * w.conv.SampleSize() 154 | return 155 | } 156 | 157 | func (w *interleavedWriter) WriteFloat64Interleaved(p [][]float64) (n int, err error) { 158 | ln := len(p) * len(p[0]) * w.conv.SampleSize() 159 | if ln > len(w.buf) { 160 | w.buf = make([]byte, ln) 161 | } 162 | 163 | w.conv.FromFloat64Interleaved(p, w.buf[:ln]) 164 | n, err = w.w.Write(w.buf[:ln]) 165 | n /= len(p) * w.conv.SampleSize() 166 | return 167 | } 168 | -------------------------------------------------------------------------------- /wave/writer.go: -------------------------------------------------------------------------------- 1 | package wave 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "github.com/oov/audio" 7 | "io" 8 | "io/ioutil" 9 | "os" 10 | ) 11 | 12 | type Writer struct { 13 | w io.Writer 14 | wfext WaveFormatExtensible 15 | aw audio.InterleavedWriter 16 | body io.Writer 17 | head int64 18 | written int64 19 | } 20 | 21 | func NewWriter(w io.Writer, wfext *WaveFormatExtensible) (*Writer, error) { 22 | if ws, ok := w.(io.WriteSeeker); ok { 23 | return newDirectWriter(ws, wfext) 24 | } 25 | 26 | if wr, err := newTempFileWriter(w, wfext); err == nil { 27 | return wr, err 28 | } 29 | return newTempMemWriter(w, wfext) 30 | } 31 | 32 | func newDirectWriter(ws io.WriteSeeker, wfext *WaveFormatExtensible) (*Writer, error) { 33 | conv, err := wfext.Format.InterleavedConverter() 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | head, err := ws.Seek(0, os.SEEK_CUR) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | // insert header margin 44 | // "RIFF" size "WAVE" "fmt " size body "data" size 45 | _, err = ws.Write(make([]byte, 4+4+4+4+4+wfext.Size()+4+4)) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | return &Writer{ 51 | w: ws, 52 | wfext: *wfext, 53 | aw: audio.NewInterleavedWriter(conv, ws), 54 | head: head, 55 | }, nil 56 | } 57 | 58 | func newTempFileWriter(w io.Writer, wfext *WaveFormatExtensible) (*Writer, error) { 59 | conv, err := wfext.Format.InterleavedConverter() 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | tempfile, err := ioutil.TempFile("", "tempwave") 65 | if err != nil { 66 | return nil, err 67 | } 68 | 69 | return &Writer{ 70 | w: w, 71 | wfext: *wfext, 72 | aw: audio.NewInterleavedWriter(conv, tempfile), 73 | body: tempfile, 74 | }, nil 75 | } 76 | 77 | func newTempMemWriter(w io.Writer, wfext *WaveFormatExtensible) (*Writer, error) { 78 | conv, err := wfext.Format.InterleavedConverter() 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | tempbuf := bytes.NewBufferString("") 84 | return &Writer{ 85 | w: w, 86 | wfext: *wfext, 87 | aw: audio.NewInterleavedWriter(conv, tempbuf), 88 | body: tempbuf, 89 | }, nil 90 | } 91 | 92 | func (w *Writer) WriteFloat32Interleaved(p [][]float32) (n int, err error) { 93 | n, err = w.aw.WriteFloat32Interleaved(p) 94 | w.written += int64(n) 95 | return 96 | } 97 | 98 | func (w *Writer) WriteFloat64Interleaved(p [][]float64) (n int, err error) { 99 | n, err = w.aw.WriteFloat64Interleaved(p) 100 | w.written += int64(n) 101 | return 102 | } 103 | 104 | func (w *Writer) Close() error { 105 | var err error 106 | 107 | ws, isWriteSeeker := w.w.(io.WriteSeeker) 108 | if isWriteSeeker { 109 | if _, err = ws.Seek(w.head, os.SEEK_SET); err != nil { 110 | return err 111 | } 112 | } 113 | 114 | dataSize := w.written * int64(w.wfext.Format.BlockAlign) 115 | // "RIFF" + sz + "WAVE" + "fmt " + sz + fmtbody + "data" + sz + databody 116 | fileSize := 4 + 4 + 4 + 4 + 4 + int64(w.wfext.Size()) + 4 + 4 + dataSize 117 | 118 | _, err = w.w.Write([]byte("RIFF")) 119 | if err != nil { 120 | return err 121 | } 122 | 123 | err = binary.Write(w.w, binary.LittleEndian, int32(fileSize)) 124 | if err != nil { 125 | return err 126 | } 127 | 128 | _, err = w.w.Write([]byte("WAVE")) 129 | if err != nil { 130 | return err 131 | } 132 | 133 | // write "fmt " chunk 134 | 135 | _, err = w.w.Write([]byte("fmt ")) 136 | if err != nil { 137 | return err 138 | } 139 | 140 | err = binary.Write(w.w, binary.LittleEndian, int32(w.wfext.Size())) 141 | if err != nil { 142 | return err 143 | } 144 | 145 | _, err = w.wfext.WriteTo(w.w) 146 | if err != nil { 147 | return err 148 | } 149 | 150 | // write "data" chunk 151 | 152 | _, err = w.w.Write([]byte("data")) 153 | if err != nil { 154 | return err 155 | } 156 | 157 | err = binary.Write(w.w, binary.LittleEndian, int32(dataSize)) 158 | if err != nil { 159 | return err 160 | } 161 | 162 | if isWriteSeeker { 163 | // already written 164 | return nil 165 | } 166 | 167 | switch t := w.body.(type) { 168 | case *os.File: 169 | _, err = t.Seek(0, os.SEEK_SET) 170 | if err != nil { 171 | return err 172 | } 173 | 174 | _, err = io.Copy(w.w, t) 175 | if err != nil { 176 | return err 177 | } 178 | 179 | err = t.Close() 180 | if err != nil { 181 | return err 182 | } 183 | os.Remove(t.Name()) 184 | 185 | case *bytes.Buffer: 186 | _, err = w.w.Write(t.Bytes()) 187 | if err != nil { 188 | return err 189 | } 190 | t.Reset() 191 | } 192 | return nil 193 | } 194 | -------------------------------------------------------------------------------- /resampler/resampler_test.go: -------------------------------------------------------------------------------- 1 | package resampler 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | wave = []float64{ 11 | //-1 to 1 (16 samples) 12 | -1, -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75, 1, 1, 1, 1, 1, 1, 1, 1, 13 | //1 to -1 (16 samples) 14 | 1, 0.75, 0.5, 0.25, 0, -0.25, -0.5, -0.75, -1, -1, -1, -1, -1, -1, -1, -1, 15 | } 16 | ) 17 | 18 | func resample64(t *testing.T, inSamplerate, outSamplerate, q int) []float64 { 19 | r := New(1, inSamplerate, outSamplerate, q) 20 | t.Log("samplerate:", "in:", inSamplerate, "out:", outSamplerate) 21 | t.Log("latency:", "in:", r.InputLatency(), "out:", r.OutputLatency()) 22 | 23 | in := make([]float64, inSamplerate/100) 24 | out := make([]float64, outSamplerate/100) 25 | 26 | copy(in, wave) 27 | read, written := r.ProcessFloat64(0, in, out) 28 | t.Log("read:", read) 29 | t.Log("written:", written) 30 | 31 | s := "" 32 | out = out[r.OutputLatency():][:(32*outSamplerate)/inSamplerate] 33 | for _, v := range out { 34 | s += fmt.Sprintf("%0.3f ", v) 35 | } 36 | t.Log("wave:", s) 37 | return out 38 | } 39 | 40 | func resample32(t *testing.T, inSamplerate, outSamplerate, q int) []float32 { 41 | r := New(1, inSamplerate, outSamplerate, q) 42 | t.Log("samplerate:", "in:", inSamplerate, "out:", outSamplerate) 43 | t.Log("latency:", "in:", r.InputLatency(), "out:", r.OutputLatency()) 44 | 45 | in := make([]float32, inSamplerate/100) 46 | out := make([]float32, outSamplerate/100) 47 | for i, s := range wave { 48 | in[i] = float32(s) 49 | } 50 | 51 | read, written := r.ProcessFloat32(0, in, out) 52 | t.Log("read:", read) 53 | t.Log("written:", written) 54 | 55 | s := "" 56 | out = out[r.OutputLatency():][:(32*outSamplerate)/inSamplerate] 57 | for _, v := range out { 58 | s += fmt.Sprintf("%0.3f ", v) 59 | } 60 | t.Log("wave:", s) 61 | return out 62 | } 63 | 64 | func TestSame64(t *testing.T) { 65 | for q := 0; q < 11; q++ { 66 | out := resample64(t, 48000, 48000, q) 67 | if math.Abs(out[8]-1.0) > 0.1 { 68 | t.Fail() 69 | } 70 | if math.Abs(out[24] - -1.0) > 0.1 { 71 | t.Fail() 72 | } 73 | } 74 | } 75 | 76 | func TestSame32(t *testing.T) { 77 | for q := 0; q < 11; q++ { 78 | out := resample32(t, 48000, 48000, q) 79 | if math.Abs(float64(out[8])-1.0) > 0.1 { 80 | t.Fail() 81 | } 82 | if math.Abs(float64(out[24]) - -1.0) > 0.1 { 83 | t.Fail() 84 | } 85 | } 86 | } 87 | 88 | func TestDirectDownSampling64(t *testing.T) { 89 | for q := 0; q < 11; q++ { 90 | out := resample64(t, 48000, 24000, q) 91 | if math.Abs(out[4]-1.0) > 0.1 { 92 | t.Fail() 93 | } 94 | if math.Abs(out[12] - -1.0) > 0.1 { 95 | t.Fail() 96 | } 97 | } 98 | } 99 | 100 | func TestDirectDownSampling32(t *testing.T) { 101 | for q := 0; q < 11; q++ { 102 | out := resample32(t, 48000, 24000, q) 103 | if math.Abs(float64(out[4])-1.0) > 0.1 { 104 | t.Fail() 105 | } 106 | if math.Abs(float64(out[12]) - -1.0) > 0.1 { 107 | t.Fail() 108 | } 109 | } 110 | } 111 | 112 | func TestDirectUpSampling64(t *testing.T) { 113 | for q := 0; q < 11; q++ { 114 | out := resample64(t, 24000, 48000, q) 115 | if math.Abs(out[16]-1.0) > 0.1 { 116 | t.Fail() 117 | } 118 | if math.Abs(out[48] - -1.0) > 0.1 { 119 | t.Fail() 120 | } 121 | } 122 | } 123 | 124 | func TestDirectUpSampling32(t *testing.T) { 125 | for q := 0; q < 11; q++ { 126 | out := resample32(t, 24000, 48000, q) 127 | if math.Abs(float64(out[16])-1.0) > 0.1 { 128 | t.Fail() 129 | } 130 | if math.Abs(float64(out[48]) - -1.0) > 0.1 { 131 | t.Fail() 132 | } 133 | } 134 | } 135 | 136 | func TestInterpolateDownSampling64(t *testing.T) { 137 | for q := 0; q < 11; q++ { 138 | out := resample64(t, 48000, 23999, q) 139 | if math.Abs(out[4]-1.0) > 0.1 { 140 | t.Fail() 141 | } 142 | if math.Abs(out[12] - -1.0) > 0.1 { 143 | t.Fail() 144 | } 145 | } 146 | } 147 | 148 | func TestInterpolateDownSampling32(t *testing.T) { 149 | for q := 0; q < 11; q++ { 150 | out := resample32(t, 48000, 23999, q) 151 | if math.Abs(float64(out[4])-1.0) > 0.1 { 152 | t.Fail() 153 | } 154 | if math.Abs(float64(out[12]) - -1.0) > 0.1 { 155 | t.Fail() 156 | } 157 | } 158 | } 159 | 160 | func TestInterpolateUpSampling64(t *testing.T) { 161 | for q := 0; q < 11; q++ { 162 | out := resample64(t, 23999, 48000, q) 163 | if math.Abs(out[16]-1.0) > 0.1 { 164 | t.Fail() 165 | } 166 | if math.Abs(out[48] - -1.0) > 0.1 { 167 | t.Fail() 168 | } 169 | } 170 | } 171 | 172 | func TestInterpolateUpSampling32(t *testing.T) { 173 | for q := 0; q < 11; q++ { 174 | out := resample32(t, 23999, 48000, q) 175 | if math.Abs(float64(out[16])-1.0) > 0.1 { 176 | t.Fail() 177 | } 178 | if math.Abs(float64(out[48]) - -1.0) > 0.1 { 179 | t.Fail() 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /wave/reader_test.go: -------------------------------------------------------------------------------- 1 | package wave 2 | 3 | import ( 4 | "math" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | type TestFile struct { 10 | filename string 11 | wf WaveFormatExtensible 12 | } 13 | 14 | var testfiles = []TestFile{ 15 | TestFile{ 16 | filename: "48kHz1ch8bit.wav", 17 | wf: WaveFormatExtensible{ 18 | Format: WaveFormatEx{ 19 | FormatTag: WAVE_FORMAT_PCM, 20 | Channels: 1, 21 | SamplesPerSec: 48000, 22 | AvgBytesPerSec: 48000, 23 | BlockAlign: 1, 24 | BitsPerSample: 8, 25 | }, 26 | }, 27 | }, 28 | TestFile{ 29 | filename: "48kHz1ch16bit.wav", 30 | wf: WaveFormatExtensible{ 31 | Format: WaveFormatEx{ 32 | FormatTag: WAVE_FORMAT_PCM, 33 | Channels: 1, 34 | SamplesPerSec: 48000, 35 | AvgBytesPerSec: 48000 * 2, 36 | BlockAlign: 2, 37 | BitsPerSample: 16, 38 | }, 39 | }, 40 | }, 41 | TestFile{ 42 | filename: "48kHz1ch24bit.wav", 43 | wf: WaveFormatExtensible{ 44 | Format: WaveFormatEx{ 45 | FormatTag: WAVE_FORMAT_PCM, 46 | Channels: 1, 47 | SamplesPerSec: 48000, 48 | AvgBytesPerSec: 48000 * 3, 49 | BlockAlign: 3, 50 | BitsPerSample: 24, 51 | }, 52 | }, 53 | }, 54 | TestFile{ 55 | filename: "48kHz1ch32bit.wav", 56 | wf: WaveFormatExtensible{ 57 | Format: WaveFormatEx{ 58 | FormatTag: WAVE_FORMAT_PCM, 59 | Channels: 1, 60 | SamplesPerSec: 48000, 61 | AvgBytesPerSec: 48000 * 4, 62 | BlockAlign: 4, 63 | BitsPerSample: 32, 64 | }, 65 | }, 66 | }, 67 | TestFile{ 68 | filename: "48kHz1ch32bitFloat.wav", 69 | wf: WaveFormatExtensible{ 70 | Format: WaveFormatEx{ 71 | FormatTag: WAVE_FORMAT_IEEE_FLOAT, 72 | Channels: 1, 73 | SamplesPerSec: 48000, 74 | AvgBytesPerSec: 48000 * 4, 75 | BlockAlign: 4, 76 | BitsPerSample: 32, 77 | }, 78 | }, 79 | }, 80 | TestFile{ 81 | filename: "48kHz1ch64bitFloat.wav", 82 | wf: WaveFormatExtensible{ 83 | Format: WaveFormatEx{ 84 | FormatTag: WAVE_FORMAT_IEEE_FLOAT, 85 | Channels: 1, 86 | SamplesPerSec: 48000, 87 | AvgBytesPerSec: 48000 * 8, 88 | BlockAlign: 8, 89 | BitsPerSample: 64, 90 | }, 91 | }, 92 | }, 93 | TestFile{ 94 | filename: "48kHz2ch16bit.wav", 95 | wf: WaveFormatExtensible{ 96 | Format: WaveFormatEx{ 97 | FormatTag: WAVE_FORMAT_PCM, 98 | Channels: 2, 99 | SamplesPerSec: 48000, 100 | AvgBytesPerSec: 48000 * 2 * 2, 101 | BlockAlign: 4, 102 | BitsPerSample: 16, 103 | }, 104 | }, 105 | }, 106 | } 107 | 108 | func isSameWaveFormatEx(a, b *WaveFormatEx) bool { 109 | if a.FormatTag != b.FormatTag { 110 | return false 111 | } 112 | if a.Channels != b.Channels { 113 | return false 114 | } 115 | if a.SamplesPerSec != b.SamplesPerSec { 116 | return false 117 | } 118 | if a.AvgBytesPerSec != b.AvgBytesPerSec { 119 | return false 120 | } 121 | if a.BlockAlign != b.BlockAlign { 122 | return false 123 | } 124 | if a.BitsPerSample != b.BitsPerSample { 125 | return false 126 | } 127 | if a.ExtSize != b.ExtSize { 128 | return false 129 | } 130 | return true 131 | } 132 | 133 | func isValidSamples(p []float64) bool { 134 | if len(p) != 12 { 135 | return false 136 | } 137 | for _, s := range p[0:4] { 138 | if math.Abs(s-1.0) > 0.01 { 139 | return false 140 | } 141 | } 142 | for _, s := range p[4:8] { 143 | if math.Abs(s) > 0.01 { 144 | return false 145 | } 146 | } 147 | for _, s := range p[8:12] { 148 | if math.Abs(s+1.0) > 0.01 { 149 | return false 150 | } 151 | } 152 | return true 153 | } 154 | 155 | func TestReader(t *testing.T) { 156 | for _, tf := range testfiles { 157 | f, err := os.Open(tf.filename) 158 | if err != nil { 159 | t.Error(err) 160 | return 161 | } 162 | r, wf, err := NewReader(f) 163 | if err != nil { 164 | t.Error(err) 165 | return 166 | } 167 | 168 | if !isSameWaveFormatEx(&wf.Format, &tf.wf.Format) { 169 | t.Fail() 170 | return 171 | } 172 | 173 | var samples [][]float64 174 | for i := 0; i < int(wf.Format.Channels); i++ { 175 | samples = append(samples, make([]float64, 12)) 176 | } 177 | n, err := r.ReadFloat64Interleaved(samples) 178 | if err != nil { 179 | t.Error(err) 180 | return 181 | } 182 | if n != 12 { 183 | t.Fail() 184 | return 185 | } 186 | if !isValidSamples(samples[0]) { 187 | t.Log("invalid samples on ch1", tf.filename, samples[0]) 188 | t.Fail() 189 | return 190 | } 191 | if wf.Format.Channels > 1 { 192 | if !isValidSamples(append(append(samples[1][8:12], samples[1][4:8]...), samples[1][0:4]...)) { 193 | t.Log("invalid samples on ch2", tf.filename, samples[1]) 194 | t.Fail() 195 | return 196 | } 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /converter/int24_test.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "encoding/binary" 5 | "testing" 6 | ) 7 | 8 | func Int24Write(s int32, out []byte) { 9 | buf := make([]byte, 4) 10 | binary.LittleEndian.PutUint32(buf, uint32(s)) 11 | copy(out, buf[1:]) 12 | } 13 | 14 | func Int24Read(s []byte) int32 { 15 | buf := make([]byte, 4) 16 | copy(buf[1:], s) 17 | return int32(binary.LittleEndian.Uint32(buf)) 18 | } 19 | 20 | func TestInt24ConverterToFloat32(t *testing.T) { 21 | o := make([]float32, dataLen) 22 | input := make([]byte, dataLen*Int24.SampleSize()) 23 | for i, s := range dataInt24 { 24 | Int24Write(s, input[i*Int24.SampleSize():]) 25 | } 26 | 27 | Int24.ToFloat32(input, o) 28 | testResultFloat32(o, t) 29 | } 30 | 31 | func TestInt24ConverterToFloat32Interleaved(t *testing.T) { 32 | 33 | outputs := make([][]float32, dataLen) 34 | for i := range outputs { 35 | outputs[i] = make([]float32, 2) 36 | } 37 | 38 | input := make([]byte, dataLen*2*Int24.SampleSize()) 39 | for i, s := range dataInt24 { 40 | Int24Write(s, input[i*Int24.SampleSize():]) 41 | } 42 | for i, s := range dataInt24 { 43 | Int24Write(s, input[(dataLen+i)*Int24.SampleSize():]) 44 | } 45 | 46 | Int24.ToFloat32Interleaved(input, outputs) 47 | testResultFloat32([]float32{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 48 | testResultFloat32([]float32{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 49 | } 50 | 51 | func TestInt24ConverterFromFloat32(t *testing.T) { 52 | output := make([]byte, dataLen*Int24.SampleSize()) 53 | Int24.FromFloat32(dataFloat32, output) 54 | testResultInt24([]int32{ 55 | Int24Read(output[0*Int24.SampleSize():]), 56 | Int24Read(output[1*Int24.SampleSize():]), 57 | Int24Read(output[2*Int24.SampleSize():]), 58 | Int24Read(output[3*Int24.SampleSize():]), 59 | Int24Read(output[4*Int24.SampleSize():]), 60 | }, t) 61 | } 62 | 63 | func TestInt24ConverterFromFloat32Interleaved(t *testing.T) { 64 | inputs := make([][]float32, dataLen) 65 | for i := range inputs { 66 | inputs[i] = []float32{dataFloat32[i], dataFloat32[i]} 67 | } 68 | output := make([]byte, dataLen*2*Int24.SampleSize()) 69 | Int24.FromFloat32Interleaved(inputs, output) 70 | testResultInt24([]int32{ 71 | Int24Read(output[0*Int24.SampleSize():]), 72 | Int24Read(output[1*Int24.SampleSize():]), 73 | Int24Read(output[2*Int24.SampleSize():]), 74 | Int24Read(output[3*Int24.SampleSize():]), 75 | Int24Read(output[4*Int24.SampleSize():]), 76 | }, t) 77 | testResultInt24([]int32{ 78 | Int24Read(output[5*Int24.SampleSize():]), 79 | Int24Read(output[6*Int24.SampleSize():]), 80 | Int24Read(output[7*Int24.SampleSize():]), 81 | Int24Read(output[8*Int24.SampleSize():]), 82 | Int24Read(output[9*Int24.SampleSize():]), 83 | }, t) 84 | } 85 | 86 | func TestInt24ConverterToFloat64(t *testing.T) { 87 | o := make([]float64, dataLen) 88 | input := make([]byte, dataLen*Int24.SampleSize()) 89 | for i, s := range dataInt24 { 90 | Int24Write(s, input[i*Int24.SampleSize():]) 91 | } 92 | 93 | Int24.ToFloat64(input, o) 94 | testResultFloat64(o, t) 95 | } 96 | 97 | func TestInt24ConverterToFloat64Interleaved(t *testing.T) { 98 | outputs := make([][]float64, dataLen) 99 | for i := range outputs { 100 | outputs[i] = make([]float64, 2) 101 | } 102 | 103 | input := make([]byte, dataLen*2*Int24.SampleSize()) 104 | for i, s := range dataInt24 { 105 | Int24Write(s, input[i*Int24.SampleSize():]) 106 | } 107 | for i, s := range dataInt24 { 108 | Int24Write(s, input[(dataLen+i)*Int24.SampleSize():]) 109 | } 110 | 111 | Int24.ToFloat64Interleaved(input, outputs) 112 | testResultFloat64([]float64{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 113 | testResultFloat64([]float64{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 114 | } 115 | 116 | func TestInt24ConverterFromFloat64(t *testing.T) { 117 | output := make([]byte, dataLen*Int24.SampleSize()) 118 | Int24.FromFloat64(dataFloat64, output) 119 | testResultInt24([]int32{ 120 | Int24Read(output[0*Int24.SampleSize():]), 121 | Int24Read(output[1*Int24.SampleSize():]), 122 | Int24Read(output[2*Int24.SampleSize():]), 123 | Int24Read(output[3*Int24.SampleSize():]), 124 | Int24Read(output[4*Int24.SampleSize():]), 125 | }, t) 126 | } 127 | 128 | func TestInt24ConverterFromFloat64Interleaved(t *testing.T) { 129 | inputs := make([][]float64, dataLen) 130 | for i := range inputs { 131 | inputs[i] = []float64{dataFloat64[i], dataFloat64[i]} 132 | } 133 | output := make([]byte, dataLen*2*Int24.SampleSize()) 134 | Int24.FromFloat64Interleaved(inputs, output) 135 | testResultInt24([]int32{ 136 | Int24Read(output[0*Int24.SampleSize():]), 137 | Int24Read(output[1*Int24.SampleSize():]), 138 | Int24Read(output[2*Int24.SampleSize():]), 139 | Int24Read(output[3*Int24.SampleSize():]), 140 | Int24Read(output[4*Int24.SampleSize():]), 141 | }, t) 142 | testResultInt24([]int32{ 143 | Int24Read(output[5*Int24.SampleSize():]), 144 | Int24Read(output[6*Int24.SampleSize():]), 145 | Int24Read(output[7*Int24.SampleSize():]), 146 | Int24Read(output[8*Int24.SampleSize():]), 147 | Int24Read(output[9*Int24.SampleSize():]), 148 | }, t) 149 | } 150 | -------------------------------------------------------------------------------- /converter/int16_test.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "encoding/binary" 5 | "testing" 6 | ) 7 | 8 | func TestInt16ToFloat32(t *testing.T) { 9 | o := make([]float32, dataLen) 10 | Int16ToFloat32Slice(dataInt16, o) 11 | testResultFloat32(o, t) 12 | } 13 | 14 | func TestFloat32ToInt16(t *testing.T) { 15 | o := make([]int16, dataLen) 16 | Float32ToInt16Slice(dataFloat32, o) 17 | testResultInt16(o, t) 18 | } 19 | 20 | func TestInt16ToFloat64(t *testing.T) { 21 | o := make([]float64, dataLen) 22 | Int16ToFloat64Slice(dataInt16, o) 23 | testResultFloat64(o, t) 24 | } 25 | 26 | func TestFloat64ToInt16(t *testing.T) { 27 | o := make([]int16, dataLen) 28 | Float64ToInt16Slice(dataFloat64, o) 29 | testResultInt16(o, t) 30 | } 31 | 32 | func TestInt16ConverterToFloat32(t *testing.T) { 33 | o := make([]float32, dataLen) 34 | input := make([]byte, dataLen*Int16.SampleSize()) 35 | for i, s := range dataInt16 { 36 | binary.LittleEndian.PutUint16(input[i*Int16.SampleSize():], uint16(s)) 37 | } 38 | 39 | Int16.ToFloat32(input, o) 40 | testResultFloat32(o, t) 41 | } 42 | 43 | func TestInt16ConverterToFloat32Interleaved(t *testing.T) { 44 | outputs := make([][]float32, dataLen) 45 | for i := range outputs { 46 | outputs[i] = make([]float32, 2) 47 | } 48 | 49 | input := make([]byte, dataLen*2*Int16.SampleSize()) 50 | for i, s := range dataInt16 { 51 | binary.LittleEndian.PutUint16(input[i*Int16.SampleSize():], uint16(s)) 52 | } 53 | for i, s := range dataInt16 { 54 | binary.LittleEndian.PutUint16(input[(dataLen+i)*Int16.SampleSize():], uint16(s)) 55 | } 56 | 57 | Int16.ToFloat32Interleaved(input, outputs) 58 | testResultFloat32([]float32{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 59 | testResultFloat32([]float32{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 60 | } 61 | 62 | func TestInt16ConverterFromFloat32(t *testing.T) { 63 | output := make([]byte, dataLen*Int16.SampleSize()) 64 | Int16.FromFloat32(dataFloat32, output) 65 | testResultInt16([]int16{ 66 | int16(binary.LittleEndian.Uint16(output[0*Int16.SampleSize():])), 67 | int16(binary.LittleEndian.Uint16(output[1*Int16.SampleSize():])), 68 | int16(binary.LittleEndian.Uint16(output[2*Int16.SampleSize():])), 69 | int16(binary.LittleEndian.Uint16(output[3*Int16.SampleSize():])), 70 | int16(binary.LittleEndian.Uint16(output[4*Int16.SampleSize():])), 71 | }, t) 72 | } 73 | 74 | func TestInt16ConverterFromFloat32Interleaved(t *testing.T) { 75 | inputs := make([][]float32, dataLen) 76 | for i := range inputs { 77 | inputs[i] = []float32{dataFloat32[i], dataFloat32[i]} 78 | } 79 | output := make([]byte, dataLen*2*Int16.SampleSize()) 80 | Int16.FromFloat32Interleaved(inputs, output) 81 | testResultInt16([]int16{ 82 | int16(binary.LittleEndian.Uint16(output[0*Int16.SampleSize():])), 83 | int16(binary.LittleEndian.Uint16(output[1*Int16.SampleSize():])), 84 | int16(binary.LittleEndian.Uint16(output[2*Int16.SampleSize():])), 85 | int16(binary.LittleEndian.Uint16(output[3*Int16.SampleSize():])), 86 | int16(binary.LittleEndian.Uint16(output[4*Int16.SampleSize():])), 87 | }, t) 88 | testResultInt16([]int16{ 89 | int16(binary.LittleEndian.Uint16(output[5*Int16.SampleSize():])), 90 | int16(binary.LittleEndian.Uint16(output[6*Int16.SampleSize():])), 91 | int16(binary.LittleEndian.Uint16(output[7*Int16.SampleSize():])), 92 | int16(binary.LittleEndian.Uint16(output[8*Int16.SampleSize():])), 93 | int16(binary.LittleEndian.Uint16(output[9*Int16.SampleSize():])), 94 | }, t) 95 | } 96 | 97 | func TestInt16ConverterToFloat64(t *testing.T) { 98 | o := make([]float64, dataLen) 99 | input := make([]byte, dataLen*Int16.SampleSize()) 100 | for i, s := range dataInt16 { 101 | binary.LittleEndian.PutUint16(input[i*Int16.SampleSize():], uint16(s)) 102 | } 103 | 104 | Int16.ToFloat64(input, o) 105 | testResultFloat64(o, t) 106 | } 107 | 108 | func TestInt16ConverterToFloat64Interleaved(t *testing.T) { 109 | outputs := make([][]float64, dataLen) 110 | for i := range outputs { 111 | outputs[i] = make([]float64, 2) 112 | } 113 | 114 | input := make([]byte, dataLen*2*Int16.SampleSize()) 115 | for i, s := range dataInt16 { 116 | binary.LittleEndian.PutUint16(input[i*Int16.SampleSize():], uint16(s)) 117 | } 118 | for i, s := range dataInt16 { 119 | binary.LittleEndian.PutUint16(input[(dataLen+i)*Int16.SampleSize():], uint16(s)) 120 | } 121 | 122 | Int16.ToFloat64Interleaved(input, outputs) 123 | testResultFloat64([]float64{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 124 | testResultFloat64([]float64{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 125 | } 126 | 127 | func TestInt16ConverterFromFloat64(t *testing.T) { 128 | output := make([]byte, dataLen*Int16.SampleSize()) 129 | Int16.FromFloat64(dataFloat64, output) 130 | testResultInt16([]int16{ 131 | int16(binary.LittleEndian.Uint16(output[0*Int16.SampleSize():])), 132 | int16(binary.LittleEndian.Uint16(output[1*Int16.SampleSize():])), 133 | int16(binary.LittleEndian.Uint16(output[2*Int16.SampleSize():])), 134 | int16(binary.LittleEndian.Uint16(output[3*Int16.SampleSize():])), 135 | int16(binary.LittleEndian.Uint16(output[4*Int16.SampleSize():])), 136 | }, t) 137 | } 138 | 139 | func TestInt16ConverterFromFloat64Interleaved(t *testing.T) { 140 | inputs := make([][]float64, dataLen) 141 | for i := range inputs { 142 | inputs[i] = []float64{dataFloat64[i], dataFloat64[i]} 143 | } 144 | output := make([]byte, dataLen*2*Int16.SampleSize()) 145 | Int16.FromFloat64Interleaved(inputs, output) 146 | testResultInt16([]int16{ 147 | int16(binary.LittleEndian.Uint16(output[0*Int16.SampleSize():])), 148 | int16(binary.LittleEndian.Uint16(output[1*Int16.SampleSize():])), 149 | int16(binary.LittleEndian.Uint16(output[2*Int16.SampleSize():])), 150 | int16(binary.LittleEndian.Uint16(output[3*Int16.SampleSize():])), 151 | int16(binary.LittleEndian.Uint16(output[4*Int16.SampleSize():])), 152 | }, t) 153 | testResultInt16([]int16{ 154 | int16(binary.LittleEndian.Uint16(output[5*Int16.SampleSize():])), 155 | int16(binary.LittleEndian.Uint16(output[6*Int16.SampleSize():])), 156 | int16(binary.LittleEndian.Uint16(output[7*Int16.SampleSize():])), 157 | int16(binary.LittleEndian.Uint16(output[8*Int16.SampleSize():])), 158 | int16(binary.LittleEndian.Uint16(output[9*Int16.SampleSize():])), 159 | }, t) 160 | } 161 | -------------------------------------------------------------------------------- /converter/int32_test.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "encoding/binary" 5 | "testing" 6 | ) 7 | 8 | func TestInt32ToFloat32(t *testing.T) { 9 | o := make([]float32, dataLen) 10 | Int32ToFloat32Slice(dataInt32, o) 11 | testResultFloat32(o, t) 12 | } 13 | 14 | func TestFloat32ToInt32(t *testing.T) { 15 | o := make([]int32, dataLen) 16 | Float32ToInt32Slice(dataFloat32, o) 17 | testResultInt32(o, t) 18 | } 19 | 20 | func TestInt32ToFloat64(t *testing.T) { 21 | o := make([]float64, dataLen) 22 | Int32ToFloat64Slice(dataInt32, o) 23 | testResultFloat64(o, t) 24 | } 25 | 26 | func TestFloat64ToInt32(t *testing.T) { 27 | o := make([]int32, dataLen) 28 | Float64ToInt32Slice(dataFloat64, o) 29 | testResultInt32(o, t) 30 | } 31 | 32 | func TestInt32ConverterToFloat32(t *testing.T) { 33 | o := make([]float32, dataLen) 34 | input := make([]byte, dataLen*Int32.SampleSize()) 35 | for i, s := range dataInt32 { 36 | binary.LittleEndian.PutUint32(input[i*Int32.SampleSize():], uint32(s)) 37 | } 38 | 39 | Int32.ToFloat32(input, o) 40 | testResultFloat32(o, t) 41 | } 42 | 43 | func TestInt32ConverterToFloat32Interleaved(t *testing.T) { 44 | outputs := make([][]float32, dataLen) 45 | for i := range outputs { 46 | outputs[i] = make([]float32, 2) 47 | } 48 | 49 | input := make([]byte, dataLen*2*Int32.SampleSize()) 50 | for i, s := range dataInt32 { 51 | binary.LittleEndian.PutUint32(input[i*Int32.SampleSize():], uint32(s)) 52 | } 53 | for i, s := range dataInt32 { 54 | binary.LittleEndian.PutUint32(input[(dataLen+i)*Int32.SampleSize():], uint32(s)) 55 | } 56 | 57 | Int32.ToFloat32Interleaved(input, outputs) 58 | testResultFloat32([]float32{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 59 | testResultFloat32([]float32{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 60 | } 61 | 62 | func TestInt32ConverterFromFloat32(t *testing.T) { 63 | output := make([]byte, dataLen*Int32.SampleSize()) 64 | Int32.FromFloat32(dataFloat32, output) 65 | testResultInt32([]int32{ 66 | int32(binary.LittleEndian.Uint32(output[0*Int32.SampleSize():])), 67 | int32(binary.LittleEndian.Uint32(output[1*Int32.SampleSize():])), 68 | int32(binary.LittleEndian.Uint32(output[2*Int32.SampleSize():])), 69 | int32(binary.LittleEndian.Uint32(output[3*Int32.SampleSize():])), 70 | int32(binary.LittleEndian.Uint32(output[4*Int32.SampleSize():])), 71 | }, t) 72 | } 73 | 74 | func TestInt32ConverterFromFloat32Interleaved(t *testing.T) { 75 | inputs := make([][]float32, dataLen) 76 | for i := range inputs { 77 | inputs[i] = []float32{dataFloat32[i], dataFloat32[i]} 78 | } 79 | output := make([]byte, dataLen*2*Int32.SampleSize()) 80 | Int32.FromFloat32Interleaved(inputs, output) 81 | testResultInt32([]int32{ 82 | int32(binary.LittleEndian.Uint32(output[0*Int32.SampleSize():])), 83 | int32(binary.LittleEndian.Uint32(output[1*Int32.SampleSize():])), 84 | int32(binary.LittleEndian.Uint32(output[2*Int32.SampleSize():])), 85 | int32(binary.LittleEndian.Uint32(output[3*Int32.SampleSize():])), 86 | int32(binary.LittleEndian.Uint32(output[4*Int32.SampleSize():])), 87 | }, t) 88 | testResultInt32([]int32{ 89 | int32(binary.LittleEndian.Uint32(output[5*Int32.SampleSize():])), 90 | int32(binary.LittleEndian.Uint32(output[6*Int32.SampleSize():])), 91 | int32(binary.LittleEndian.Uint32(output[7*Int32.SampleSize():])), 92 | int32(binary.LittleEndian.Uint32(output[8*Int32.SampleSize():])), 93 | int32(binary.LittleEndian.Uint32(output[9*Int32.SampleSize():])), 94 | }, t) 95 | } 96 | 97 | func TestInt32ConverterToFloat64(t *testing.T) { 98 | o := make([]float64, dataLen) 99 | input := make([]byte, dataLen*Int32.SampleSize()) 100 | for i, s := range dataInt32 { 101 | binary.LittleEndian.PutUint32(input[i*Int32.SampleSize():], uint32(s)) 102 | } 103 | 104 | Int32.ToFloat64(input, o) 105 | testResultFloat64(o, t) 106 | } 107 | 108 | func TestInt32ConverterToFloat64Interleaved(t *testing.T) { 109 | outputs := make([][]float64, dataLen) 110 | for i := range outputs { 111 | outputs[i] = make([]float64, 2) 112 | } 113 | 114 | input := make([]byte, dataLen*2*Int32.SampleSize()) 115 | for i, s := range dataInt32 { 116 | binary.LittleEndian.PutUint32(input[i*Int32.SampleSize():], uint32(s)) 117 | } 118 | for i, s := range dataInt32 { 119 | binary.LittleEndian.PutUint32(input[(dataLen+i)*Int32.SampleSize():], uint32(s)) 120 | } 121 | 122 | Int32.ToFloat64Interleaved(input, outputs) 123 | testResultFloat64([]float64{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 124 | testResultFloat64([]float64{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 125 | } 126 | 127 | func TestInt32ConverterFromFloat64(t *testing.T) { 128 | output := make([]byte, dataLen*Int32.SampleSize()) 129 | Int32.FromFloat64(dataFloat64, output) 130 | testResultInt32([]int32{ 131 | int32(binary.LittleEndian.Uint32(output[0*Int32.SampleSize():])), 132 | int32(binary.LittleEndian.Uint32(output[1*Int32.SampleSize():])), 133 | int32(binary.LittleEndian.Uint32(output[2*Int32.SampleSize():])), 134 | int32(binary.LittleEndian.Uint32(output[3*Int32.SampleSize():])), 135 | int32(binary.LittleEndian.Uint32(output[4*Int32.SampleSize():])), 136 | }, t) 137 | } 138 | 139 | func TestInt32ConverterFromFloat64Interleaved(t *testing.T) { 140 | inputs := make([][]float64, dataLen) 141 | for i := range inputs { 142 | inputs[i] = []float64{dataFloat64[i], dataFloat64[i]} 143 | } 144 | output := make([]byte, dataLen*2*Int32.SampleSize()) 145 | Int32.FromFloat64Interleaved(inputs, output) 146 | testResultInt32([]int32{ 147 | int32(binary.LittleEndian.Uint32(output[0*Int32.SampleSize():])), 148 | int32(binary.LittleEndian.Uint32(output[1*Int32.SampleSize():])), 149 | int32(binary.LittleEndian.Uint32(output[2*Int32.SampleSize():])), 150 | int32(binary.LittleEndian.Uint32(output[3*Int32.SampleSize():])), 151 | int32(binary.LittleEndian.Uint32(output[4*Int32.SampleSize():])), 152 | }, t) 153 | testResultInt32([]int32{ 154 | int32(binary.LittleEndian.Uint32(output[5*Int32.SampleSize():])), 155 | int32(binary.LittleEndian.Uint32(output[6*Int32.SampleSize():])), 156 | int32(binary.LittleEndian.Uint32(output[7*Int32.SampleSize():])), 157 | int32(binary.LittleEndian.Uint32(output[8*Int32.SampleSize():])), 158 | int32(binary.LittleEndian.Uint32(output[9*Int32.SampleSize():])), 159 | }, t) 160 | } 161 | -------------------------------------------------------------------------------- /converter/float64_test.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "encoding/binary" 5 | "math" 6 | "testing" 7 | ) 8 | 9 | func TestFloat64ConverterToFloat32(t *testing.T) { 10 | o := make([]float32, dataLen) 11 | input := make([]byte, dataLen*Float64.SampleSize()) 12 | for i, s := range dataFloat64 { 13 | binary.LittleEndian.PutUint64(input[i*Float64.SampleSize():], uint64(math.Float64bits(s))) 14 | } 15 | 16 | Float64.ToFloat32(input, o) 17 | testResultFloat32(o, t) 18 | } 19 | 20 | func TestFloat64ConverterToFloat32Interleaved(t *testing.T) { 21 | outputs := make([][]float32, dataLen) 22 | for i := range outputs { 23 | outputs[i] = make([]float32, 2) 24 | } 25 | 26 | input := make([]byte, dataLen*2*Float64.SampleSize()) 27 | for i, s := range dataFloat64 { 28 | binary.LittleEndian.PutUint64(input[i*Float64.SampleSize():], uint64(math.Float64bits(s))) 29 | } 30 | for i, s := range dataFloat64 { 31 | binary.LittleEndian.PutUint64(input[(dataLen+i)*Float64.SampleSize():], uint64(math.Float64bits(s))) 32 | } 33 | 34 | Float64.ToFloat32Interleaved(input, outputs) 35 | testResultFloat32([]float32{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 36 | testResultFloat32([]float32{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 37 | } 38 | 39 | func TestFloat64ConverterFromFloat32(t *testing.T) { 40 | output := make([]byte, dataLen*Float64.SampleSize()) 41 | Float64.FromFloat64(dataFloat64, output) 42 | testResultFloat64([]float64{ 43 | math.Float64frombits(binary.LittleEndian.Uint64(output[0*Float64.SampleSize():])), 44 | math.Float64frombits(binary.LittleEndian.Uint64(output[1*Float64.SampleSize():])), 45 | math.Float64frombits(binary.LittleEndian.Uint64(output[2*Float64.SampleSize():])), 46 | math.Float64frombits(binary.LittleEndian.Uint64(output[3*Float64.SampleSize():])), 47 | math.Float64frombits(binary.LittleEndian.Uint64(output[4*Float64.SampleSize():])), 48 | }, t) 49 | } 50 | 51 | func TestFloat64ConverterFromFloat32Interleaved(t *testing.T) { 52 | inputs := make([][]float32, dataLen) 53 | for i := range inputs { 54 | inputs[i] = []float32{dataFloat32[i], dataFloat32[i]} 55 | } 56 | output := make([]byte, dataLen*2*Float64.SampleSize()) 57 | Float64.FromFloat32Interleaved(inputs, output) 58 | testResultFloat64([]float64{ 59 | math.Float64frombits(binary.LittleEndian.Uint64(output[0*Float64.SampleSize():])), 60 | math.Float64frombits(binary.LittleEndian.Uint64(output[1*Float64.SampleSize():])), 61 | math.Float64frombits(binary.LittleEndian.Uint64(output[2*Float64.SampleSize():])), 62 | math.Float64frombits(binary.LittleEndian.Uint64(output[3*Float64.SampleSize():])), 63 | math.Float64frombits(binary.LittleEndian.Uint64(output[4*Float64.SampleSize():])), 64 | }, t) 65 | testResultFloat64([]float64{ 66 | math.Float64frombits(binary.LittleEndian.Uint64(output[5*Float64.SampleSize():])), 67 | math.Float64frombits(binary.LittleEndian.Uint64(output[6*Float64.SampleSize():])), 68 | math.Float64frombits(binary.LittleEndian.Uint64(output[7*Float64.SampleSize():])), 69 | math.Float64frombits(binary.LittleEndian.Uint64(output[8*Float64.SampleSize():])), 70 | math.Float64frombits(binary.LittleEndian.Uint64(output[9*Float64.SampleSize():])), 71 | }, t) 72 | } 73 | 74 | func TestFloat64ConverterToFloat64(t *testing.T) { 75 | o := make([]float64, dataLen) 76 | input := make([]byte, dataLen*Float64.SampleSize()) 77 | for i, s := range dataFloat64 { 78 | binary.LittleEndian.PutUint64(input[i*Float64.SampleSize():], uint64(math.Float64bits(s))) 79 | } 80 | 81 | Float64.ToFloat64(input, o) 82 | testResultFloat64(o, t) 83 | } 84 | 85 | func TestFloat64ConverterToFloat64Interleaved(t *testing.T) { 86 | outputs := make([][]float64, dataLen) 87 | for i := range outputs { 88 | outputs[i] = make([]float64, 2) 89 | } 90 | 91 | input := make([]byte, dataLen*2*Float64.SampleSize()) 92 | for i, s := range dataFloat64 { 93 | binary.LittleEndian.PutUint64(input[i*Float64.SampleSize():], uint64(math.Float64bits(s))) 94 | } 95 | for i, s := range dataFloat64 { 96 | binary.LittleEndian.PutUint64(input[(dataLen+i)*Float64.SampleSize():], uint64(math.Float64bits(s))) 97 | } 98 | 99 | Float64.ToFloat64Interleaved(input, outputs) 100 | testResultFloat64([]float64{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 101 | testResultFloat64([]float64{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 102 | } 103 | 104 | func TestFloat64ConverterFromFloat64(t *testing.T) { 105 | output := make([]byte, dataLen*Float64.SampleSize()) 106 | Float64.FromFloat64(dataFloat64, output) 107 | testResultFloat64([]float64{ 108 | math.Float64frombits(binary.LittleEndian.Uint64(output[0*Float64.SampleSize():])), 109 | math.Float64frombits(binary.LittleEndian.Uint64(output[1*Float64.SampleSize():])), 110 | math.Float64frombits(binary.LittleEndian.Uint64(output[2*Float64.SampleSize():])), 111 | math.Float64frombits(binary.LittleEndian.Uint64(output[3*Float64.SampleSize():])), 112 | math.Float64frombits(binary.LittleEndian.Uint64(output[4*Float64.SampleSize():])), 113 | }, t) 114 | } 115 | 116 | func TestFloat64ConverterFromFloat64Interleaved(t *testing.T) { 117 | inputs := make([][]float64, dataLen) 118 | for i := range inputs { 119 | inputs[i] = []float64{dataFloat64[i], dataFloat64[i]} 120 | } 121 | output := make([]byte, dataLen*2*Float64.SampleSize()) 122 | Float64.FromFloat64Interleaved(inputs, output) 123 | testResultFloat64([]float64{ 124 | math.Float64frombits(binary.LittleEndian.Uint64(output[0*Float64.SampleSize():])), 125 | math.Float64frombits(binary.LittleEndian.Uint64(output[1*Float64.SampleSize():])), 126 | math.Float64frombits(binary.LittleEndian.Uint64(output[2*Float64.SampleSize():])), 127 | math.Float64frombits(binary.LittleEndian.Uint64(output[3*Float64.SampleSize():])), 128 | math.Float64frombits(binary.LittleEndian.Uint64(output[4*Float64.SampleSize():])), 129 | }, t) 130 | testResultFloat64([]float64{ 131 | math.Float64frombits(binary.LittleEndian.Uint64(output[5*Float64.SampleSize():])), 132 | math.Float64frombits(binary.LittleEndian.Uint64(output[6*Float64.SampleSize():])), 133 | math.Float64frombits(binary.LittleEndian.Uint64(output[7*Float64.SampleSize():])), 134 | math.Float64frombits(binary.LittleEndian.Uint64(output[8*Float64.SampleSize():])), 135 | math.Float64frombits(binary.LittleEndian.Uint64(output[9*Float64.SampleSize():])), 136 | }, t) 137 | } 138 | -------------------------------------------------------------------------------- /converter/float32_test.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "encoding/binary" 5 | "math" 6 | "testing" 7 | ) 8 | 9 | func TestFloat32ToFloat64(t *testing.T) { 10 | o := make([]float64, dataLen) 11 | Float32ToFloat64Slice(dataFloat32, o) 12 | testResultFloat64(o, t) 13 | } 14 | 15 | func TestFloat64ToFloat32(t *testing.T) { 16 | o := make([]float32, dataLen) 17 | Float64ToFloat32Slice(dataFloat64, o) 18 | testResultFloat32(o, t) 19 | } 20 | 21 | func TestFloat32ConverterToFloat32(t *testing.T) { 22 | o := make([]float32, dataLen) 23 | input := make([]byte, dataLen*Float32.SampleSize()) 24 | for i, s := range dataFloat32 { 25 | binary.LittleEndian.PutUint32(input[i*Float32.SampleSize():], uint32(math.Float32bits(s))) 26 | } 27 | 28 | Float32.ToFloat32(input, o) 29 | testResultFloat32(o, t) 30 | } 31 | 32 | func TestFloat32ConverterToFloat32Interleaved(t *testing.T) { 33 | outputs := make([][]float32, dataLen) 34 | for i := range outputs { 35 | outputs[i] = make([]float32, 2) 36 | } 37 | 38 | input := make([]byte, dataLen*2*Float32.SampleSize()) 39 | for i, s := range dataFloat32 { 40 | binary.LittleEndian.PutUint32(input[i*Float32.SampleSize():], uint32(math.Float32bits(s))) 41 | } 42 | for i, s := range dataFloat32 { 43 | binary.LittleEndian.PutUint32(input[(dataLen+i)*Float32.SampleSize():], uint32(math.Float32bits(s))) 44 | } 45 | 46 | Float32.ToFloat32Interleaved(input, outputs) 47 | testResultFloat32([]float32{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 48 | testResultFloat32([]float32{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 49 | } 50 | 51 | func TestFloat32ConverterFromFloat32(t *testing.T) { 52 | output := make([]byte, dataLen*Float32.SampleSize()) 53 | Float32.FromFloat32(dataFloat32, output) 54 | testResultFloat32([]float32{ 55 | math.Float32frombits(binary.LittleEndian.Uint32(output[0*Float32.SampleSize():])), 56 | math.Float32frombits(binary.LittleEndian.Uint32(output[1*Float32.SampleSize():])), 57 | math.Float32frombits(binary.LittleEndian.Uint32(output[2*Float32.SampleSize():])), 58 | math.Float32frombits(binary.LittleEndian.Uint32(output[3*Float32.SampleSize():])), 59 | math.Float32frombits(binary.LittleEndian.Uint32(output[4*Float32.SampleSize():])), 60 | }, t) 61 | } 62 | 63 | func TestFloat32ConverterFromFloat32Interleaved(t *testing.T) { 64 | inputs := make([][]float32, dataLen) 65 | for i := range inputs { 66 | inputs[i] = []float32{dataFloat32[i], dataFloat32[i]} 67 | } 68 | output := make([]byte, dataLen*2*Float32.SampleSize()) 69 | Float32.FromFloat32Interleaved(inputs, output) 70 | testResultFloat32([]float32{ 71 | math.Float32frombits(binary.LittleEndian.Uint32(output[0*Float32.SampleSize():])), 72 | math.Float32frombits(binary.LittleEndian.Uint32(output[1*Float32.SampleSize():])), 73 | math.Float32frombits(binary.LittleEndian.Uint32(output[2*Float32.SampleSize():])), 74 | math.Float32frombits(binary.LittleEndian.Uint32(output[3*Float32.SampleSize():])), 75 | math.Float32frombits(binary.LittleEndian.Uint32(output[4*Float32.SampleSize():])), 76 | }, t) 77 | testResultFloat32([]float32{ 78 | math.Float32frombits(binary.LittleEndian.Uint32(output[5*Float32.SampleSize():])), 79 | math.Float32frombits(binary.LittleEndian.Uint32(output[6*Float32.SampleSize():])), 80 | math.Float32frombits(binary.LittleEndian.Uint32(output[7*Float32.SampleSize():])), 81 | math.Float32frombits(binary.LittleEndian.Uint32(output[8*Float32.SampleSize():])), 82 | math.Float32frombits(binary.LittleEndian.Uint32(output[9*Float32.SampleSize():])), 83 | }, t) 84 | } 85 | 86 | func TestFloat32ConverterToFloat64(t *testing.T) { 87 | o := make([]float64, dataLen) 88 | input := make([]byte, dataLen*Float32.SampleSize()) 89 | for i, s := range dataFloat32 { 90 | binary.LittleEndian.PutUint32(input[i*Float32.SampleSize():], uint32(math.Float32bits(s))) 91 | } 92 | 93 | Float32.ToFloat64(input, o) 94 | testResultFloat64(o, t) 95 | } 96 | 97 | func TestFloat32ConverterToFloat64Interleaved(t *testing.T) { 98 | outputs := make([][]float64, dataLen) 99 | for i := range outputs { 100 | outputs[i] = make([]float64, 2) 101 | } 102 | 103 | input := make([]byte, dataLen*2*Float32.SampleSize()) 104 | for i, s := range dataFloat32 { 105 | binary.LittleEndian.PutUint32(input[i*Float32.SampleSize():], uint32(math.Float32bits(s))) 106 | } 107 | for i, s := range dataFloat32 { 108 | binary.LittleEndian.PutUint32(input[(dataLen+i)*Float32.SampleSize():], uint32(math.Float32bits(s))) 109 | } 110 | 111 | Float32.ToFloat64Interleaved(input, outputs) 112 | testResultFloat64([]float64{outputs[0][0], outputs[1][0], outputs[2][0], outputs[3][0], outputs[4][0]}, t) 113 | testResultFloat64([]float64{outputs[0][1], outputs[1][1], outputs[2][1], outputs[3][1], outputs[4][1]}, t) 114 | } 115 | 116 | func TestFloat32ConverterFromFloat64(t *testing.T) { 117 | output := make([]byte, dataLen*Float32.SampleSize()) 118 | Float32.FromFloat64(dataFloat64, output) 119 | testResultFloat32([]float32{ 120 | math.Float32frombits(binary.LittleEndian.Uint32(output[0*Float32.SampleSize():])), 121 | math.Float32frombits(binary.LittleEndian.Uint32(output[1*Float32.SampleSize():])), 122 | math.Float32frombits(binary.LittleEndian.Uint32(output[2*Float32.SampleSize():])), 123 | math.Float32frombits(binary.LittleEndian.Uint32(output[3*Float32.SampleSize():])), 124 | math.Float32frombits(binary.LittleEndian.Uint32(output[4*Float32.SampleSize():])), 125 | }, t) 126 | } 127 | 128 | func TestFloat32ConverterFromFloat64Interleaved(t *testing.T) { 129 | inputs := make([][]float64, dataLen) 130 | for i := range inputs { 131 | inputs[i] = []float64{dataFloat64[i], dataFloat64[i]} 132 | } 133 | output := make([]byte, dataLen*2*Float32.SampleSize()) 134 | Float32.FromFloat64Interleaved(inputs, output) 135 | testResultFloat32([]float32{ 136 | math.Float32frombits(binary.LittleEndian.Uint32(output[0*Float32.SampleSize():])), 137 | math.Float32frombits(binary.LittleEndian.Uint32(output[1*Float32.SampleSize():])), 138 | math.Float32frombits(binary.LittleEndian.Uint32(output[2*Float32.SampleSize():])), 139 | math.Float32frombits(binary.LittleEndian.Uint32(output[3*Float32.SampleSize():])), 140 | math.Float32frombits(binary.LittleEndian.Uint32(output[4*Float32.SampleSize():])), 141 | }, t) 142 | testResultFloat32([]float32{ 143 | math.Float32frombits(binary.LittleEndian.Uint32(output[5*Float32.SampleSize():])), 144 | math.Float32frombits(binary.LittleEndian.Uint32(output[6*Float32.SampleSize():])), 145 | math.Float32frombits(binary.LittleEndian.Uint32(output[7*Float32.SampleSize():])), 146 | math.Float32frombits(binary.LittleEndian.Uint32(output[8*Float32.SampleSize():])), 147 | math.Float32frombits(binary.LittleEndian.Uint32(output[9*Float32.SampleSize():])), 148 | }, t) 149 | } 150 | -------------------------------------------------------------------------------- /resampler/quality.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2007-2008 Jean-Marc Valin 2 | // Copyright (C) 2008 Thorvald Natvig 3 | // Copyright (C) 2013 Oov 4 | // 5 | // Arbitrary resampling code 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are 9 | // met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // 18 | // 3. The name of the author may not be used to endorse or promote products 19 | // derived from this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | // POSSIBILITY OF SUCH DAMAGE. 32 | 33 | package resampler 34 | 35 | type kaiserTable struct { 36 | table []float64 37 | oversample int 38 | } 39 | 40 | type quality struct { 41 | baseLength int 42 | oversample int 43 | downsampleBandwidth float64 44 | upsampleBandwidth float64 45 | table *kaiserTable 46 | } 47 | 48 | var ( 49 | kaiser12 = kaiserTable{ 50 | table: []float64{ 51 | 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, 52 | 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, 53 | 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, 54 | 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, 55 | 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, 56 | 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, 57 | 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, 58 | 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, 59 | 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, 60 | 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, 61 | 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, 62 | 0.00001000, 0.00000000}, 63 | oversample: 64, 64 | } 65 | 66 | kaiser10 = kaiserTable{ 67 | table: []float64{ 68 | 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, 69 | 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, 70 | 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, 71 | 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, 72 | 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, 73 | 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}, 74 | oversample: 32, 75 | } 76 | 77 | kaiser8 = kaiserTable{ 78 | table: []float64{ 79 | 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, 80 | 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, 81 | 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, 82 | 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, 83 | 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, 84 | 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}, 85 | oversample: 32, 86 | } 87 | 88 | kaiser6 = kaiserTable{ 89 | table: []float64{ 90 | 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, 91 | 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, 92 | 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, 93 | 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, 94 | 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, 95 | 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}, 96 | oversample: 32, 97 | } 98 | 99 | qualityMap = []quality{ 100 | // Q0 101 | quality{ 102 | baseLength: 8, 103 | oversample: 4, 104 | downsampleBandwidth: 0.830, 105 | upsampleBandwidth: 0.860, 106 | table: &kaiser6, 107 | }, 108 | // Q1 109 | quality{ 110 | baseLength: 16, 111 | oversample: 4, 112 | downsampleBandwidth: 0.850, 113 | upsampleBandwidth: 0.880, 114 | table: &kaiser6, 115 | }, 116 | // Q2 117 | quality{ 118 | baseLength: 32, 119 | oversample: 4, 120 | downsampleBandwidth: 0.882, 121 | upsampleBandwidth: 0.910, 122 | table: &kaiser6, 123 | }, 124 | // Q3 125 | quality{ 126 | baseLength: 48, 127 | oversample: 8, 128 | downsampleBandwidth: 0.895, 129 | upsampleBandwidth: 0.917, 130 | table: &kaiser8, 131 | }, 132 | // Q4 133 | quality{ 134 | baseLength: 64, 135 | oversample: 8, 136 | downsampleBandwidth: 0.921, 137 | upsampleBandwidth: 0.940, 138 | table: &kaiser8, 139 | }, 140 | // Q5 141 | quality{ 142 | baseLength: 80, 143 | oversample: 16, 144 | downsampleBandwidth: 0.922, 145 | upsampleBandwidth: 0.940, 146 | table: &kaiser10, 147 | }, 148 | // Q6 149 | quality{ 150 | baseLength: 96, 151 | oversample: 16, 152 | downsampleBandwidth: 0.940, 153 | upsampleBandwidth: 0.945, 154 | table: &kaiser10, 155 | }, 156 | // Q7 157 | quality{ 158 | baseLength: 128, 159 | oversample: 16, 160 | downsampleBandwidth: 0.950, 161 | upsampleBandwidth: 0.950, 162 | table: &kaiser10, 163 | }, 164 | // Q8 165 | quality{ 166 | baseLength: 160, 167 | oversample: 16, 168 | downsampleBandwidth: 0.960, 169 | upsampleBandwidth: 0.960, 170 | table: &kaiser10, 171 | }, 172 | // Q9 173 | quality{ 174 | baseLength: 192, 175 | oversample: 32, 176 | downsampleBandwidth: 0.968, 177 | upsampleBandwidth: 0.968, 178 | table: &kaiser12, 179 | }, 180 | // Q10 181 | quality{ 182 | baseLength: 256, 183 | oversample: 32, 184 | downsampleBandwidth: 0.975, 185 | upsampleBandwidth: 0.975, 186 | table: &kaiser12, 187 | }, 188 | } 189 | ) 190 | -------------------------------------------------------------------------------- /wave/waveformatex.go: -------------------------------------------------------------------------------- 1 | package wave 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "github.com/oov/audio/converter" 7 | "io" 8 | ) 9 | 10 | type GUID struct { 11 | Data1 uint32 12 | Data2 uint16 13 | Data3 uint16 14 | Data4 [8]byte 15 | } 16 | 17 | func (guid *GUID) Size() int { 18 | return 16 19 | } 20 | 21 | func (guid *GUID) ReadFrom(r io.Reader) (n int64, err error) { 22 | if err = binary.Read(r, binary.LittleEndian, &guid.Data1); err != nil { 23 | return 24 | } 25 | n += 4 26 | 27 | if err = binary.Read(r, binary.LittleEndian, &guid.Data2); err != nil { 28 | return 29 | } 30 | n += 2 31 | 32 | if err = binary.Read(r, binary.LittleEndian, &guid.Data3); err != nil { 33 | return 34 | } 35 | n += 2 36 | 37 | var rd int 38 | rd, err = r.Read(guid.Data4[:]) 39 | n += int64(rd) 40 | return 41 | } 42 | 43 | func (guid *GUID) WriteTo(w io.Writer) (n int64, err error) { 44 | if err = binary.Write(w, binary.LittleEndian, guid.Data1); err != nil { 45 | return 46 | } 47 | n += 4 48 | 49 | if err = binary.Write(w, binary.LittleEndian, guid.Data2); err != nil { 50 | return 51 | } 52 | n += 2 53 | 54 | if err = binary.Write(w, binary.LittleEndian, guid.Data3); err != nil { 55 | return 56 | } 57 | n += 2 58 | 59 | var wt int 60 | wt, err = w.Write(guid.Data4[:]) 61 | n += int64(wt) 62 | return 63 | } 64 | 65 | type WaveFormatEx struct { 66 | FormatTag WaveFormatTag 67 | Channels uint16 68 | SamplesPerSec uint32 69 | AvgBytesPerSec uint32 70 | BlockAlign uint16 71 | BitsPerSample uint16 72 | ExtSize uint16 73 | } 74 | 75 | func (wfex *WaveFormatEx) Size() int { 76 | return 16 77 | } 78 | 79 | func (wfex *WaveFormatEx) ReadFrom(r io.Reader) (n int64, err error) { 80 | if err = binary.Read(r, binary.LittleEndian, &wfex.FormatTag); err != nil { 81 | return 82 | } 83 | n += 2 84 | 85 | if err = binary.Read(r, binary.LittleEndian, &wfex.Channels); err != nil { 86 | return 87 | } 88 | n += 2 89 | 90 | if err = binary.Read(r, binary.LittleEndian, &wfex.SamplesPerSec); err != nil { 91 | return 92 | } 93 | n += 4 94 | 95 | if err = binary.Read(r, binary.LittleEndian, &wfex.AvgBytesPerSec); err != nil { 96 | return 97 | } 98 | n += 4 99 | 100 | if err = binary.Read(r, binary.LittleEndian, &wfex.BlockAlign); err != nil { 101 | return 102 | } 103 | n += 2 104 | 105 | if err = binary.Read(r, binary.LittleEndian, &wfex.BitsPerSample); err != nil { 106 | return 107 | } 108 | n += 2 109 | return 110 | } 111 | 112 | func (wfex *WaveFormatEx) WriteTo(w io.Writer) (n int64, err error) { 113 | if err = binary.Write(w, binary.LittleEndian, wfex.FormatTag); err != nil { 114 | return 115 | } 116 | n += 2 117 | 118 | if err = binary.Write(w, binary.LittleEndian, wfex.Channels); err != nil { 119 | return 120 | } 121 | n += 2 122 | 123 | if err = binary.Write(w, binary.LittleEndian, wfex.SamplesPerSec); err != nil { 124 | return 125 | } 126 | n += 4 127 | 128 | if err = binary.Write(w, binary.LittleEndian, wfex.AvgBytesPerSec); err != nil { 129 | return 130 | } 131 | n += 4 132 | 133 | if err = binary.Write(w, binary.LittleEndian, wfex.BlockAlign); err != nil { 134 | return 135 | } 136 | n += 2 137 | 138 | if err = binary.Write(w, binary.LittleEndian, wfex.BitsPerSample); err != nil { 139 | return 140 | } 141 | n += 2 142 | return 143 | } 144 | 145 | func (wfex *WaveFormatEx) Converter() (converter.Converter, error) { 146 | var conv converter.Converter 147 | switch wfex.FormatTag { 148 | case WAVE_FORMAT_PCM: 149 | switch wfex.BitsPerSample { 150 | case 8: 151 | conv = converter.Uint8 152 | case 16: 153 | conv = converter.Int16 154 | case 24: 155 | conv = converter.Int24 156 | case 32: 157 | conv = converter.Int32 158 | } 159 | case WAVE_FORMAT_IEEE_FLOAT: 160 | switch wfex.BitsPerSample { 161 | case 32: 162 | conv = converter.Float32 163 | case 64: 164 | conv = converter.Float64 165 | } 166 | } 167 | if conv == nil { 168 | return nil, errors.New("wave: unsupported wave file format") 169 | } 170 | return conv, nil 171 | } 172 | 173 | func (wfex *WaveFormatEx) InterleavedConverter() (converter.InterleavedConverter, error) { 174 | var conv converter.InterleavedConverter 175 | switch wfex.FormatTag { 176 | case WAVE_FORMAT_PCM: 177 | switch wfex.BitsPerSample { 178 | case 8: 179 | conv = converter.Uint8 180 | case 16: 181 | conv = converter.Int16 182 | case 24: 183 | conv = converter.Int24 184 | case 32: 185 | conv = converter.Int32 186 | } 187 | case WAVE_FORMAT_IEEE_FLOAT: 188 | switch wfex.BitsPerSample { 189 | case 32: 190 | conv = converter.Float32 191 | case 64: 192 | conv = converter.Float64 193 | } 194 | } 195 | if conv == nil { 196 | return nil, errors.New("wave: unsupported wave file format") 197 | } 198 | return conv, nil 199 | } 200 | 201 | type WaveFormatExtensible struct { 202 | Format WaveFormatEx 203 | Samples uint16 // union { ValidBitsPerSample or SamplesPerBlock or Reserved } 204 | ChannelMask WFESpeaker 205 | SubFormat GUID 206 | } 207 | 208 | func (wfext *WaveFormatExtensible) Size() int { 209 | return wfext.Format.Size() + int(wfext.Format.ExtSize) 210 | } 211 | 212 | func (wfext *WaveFormatExtensible) ReadFrom(r io.Reader) (n int64, err error) { 213 | if n, err = wfext.Format.ReadFrom(r); err != nil { 214 | return 215 | } 216 | 217 | if wfext.Format.FormatTag != WAVE_FORMAT_EXTENSIBLE { 218 | return 219 | } 220 | 221 | if err = binary.Read(r, binary.LittleEndian, &wfext.Format.ExtSize); err != nil { 222 | return 223 | } 224 | n += 2 225 | 226 | if wfext.Format.FormatTag == WAVE_FORMAT_EXTENSIBLE && wfext.Format.ExtSize != 22 { 227 | return n, errors.New("wave: unsupported wave file format") 228 | } 229 | 230 | if err = binary.Read(r, binary.LittleEndian, &wfext.Format.ExtSize); err != nil { 231 | return 232 | } 233 | n += 2 234 | 235 | if err = binary.Read(r, binary.LittleEndian, &wfext.Samples); err != nil { 236 | return 237 | } 238 | n += 2 239 | 240 | if err = binary.Read(r, binary.LittleEndian, &wfext.ChannelMask); err != nil { 241 | return 242 | } 243 | n += 4 244 | 245 | var rd int64 246 | rd, err = wfext.SubFormat.ReadFrom(r) 247 | n += rd 248 | return 249 | } 250 | 251 | func (wfext *WaveFormatExtensible) WriteTo(w io.Writer) (n int64, err error) { 252 | if (wfext.Format.FormatTag != WAVE_FORMAT_EXTENSIBLE && wfext.Format.ExtSize != 0) || 253 | (wfext.Format.FormatTag == WAVE_FORMAT_EXTENSIBLE && wfext.Format.ExtSize != 22) { 254 | return 0, errors.New("wave: unsupported wave file format") 255 | } 256 | 257 | if n, err = wfext.Format.WriteTo(w); err != nil { 258 | return 259 | } 260 | 261 | if wfext.Format.FormatTag != WAVE_FORMAT_EXTENSIBLE { 262 | return 263 | } 264 | 265 | if err = binary.Write(w, binary.LittleEndian, wfext.Format.ExtSize); err != nil { 266 | return 267 | } 268 | n += 2 269 | 270 | if err = binary.Write(w, binary.LittleEndian, wfext.Samples); err != nil { 271 | return 272 | } 273 | n += 2 274 | 275 | if err = binary.Write(w, binary.LittleEndian, wfext.ChannelMask); err != nil { 276 | return 277 | } 278 | n += 4 279 | 280 | var wt int64 281 | wt, err = wfext.SubFormat.WriteTo(w) 282 | n += wt 283 | return 284 | } 285 | 286 | type WaveFormatTag uint16 287 | 288 | const ( 289 | WAVE_FORMAT_UNKNOWN = WaveFormatTag(0x0000) // Microsoft Corporation 290 | WAVE_FORMAT_PCM = WaveFormatTag(0x0001) // Microsoft PCM format 291 | WAVE_FORMAT_MS_ADPCM = WaveFormatTag(0x0002) // Microsoft ADPCM 292 | WAVE_FORMAT_IEEE_FLOAT = WaveFormatTag(0x0003) // Micrososft 32 bit float format 293 | WAVE_FORMAT_VSELP = WaveFormatTag(0x0004) // Compaq Computer Corporation 294 | WAVE_FORMAT_IBM_CVSD = WaveFormatTag(0x0005) // IBM Corporation 295 | WAVE_FORMAT_ALAW = WaveFormatTag(0x0006) // Microsoft Corporation 296 | WAVE_FORMAT_MULAW = WaveFormatTag(0x0007) // Microsoft Corporation 297 | WAVE_FORMAT_OKI_ADPCM = WaveFormatTag(0x0010) // OKI 298 | WAVE_FORMAT_IMA_ADPCM = WaveFormatTag(0x0011) // Intel Corporation 299 | WAVE_FORMAT_MEDIASPACE_ADPCM = WaveFormatTag(0x0012) // Videologic 300 | WAVE_FORMAT_SIERRA_ADPCM = WaveFormatTag(0x0013) // Sierra Semiconductor Corp 301 | WAVE_FORMAT_G723_ADPCM = WaveFormatTag(0x0014) // Antex Electronics Corporation 302 | WAVE_FORMAT_DIGISTD = WaveFormatTag(0x0015) // DSP Solutions, Inc. 303 | WAVE_FORMAT_DIGIFIX = WaveFormatTag(0x0016) // DSP Solutions, Inc. 304 | WAVE_FORMAT_DIALOGIC_OKI_ADPCM = WaveFormatTag(0x0017) // Dialogic Corporation 305 | WAVE_FORMAT_MEDIAVISION_ADPCM = WaveFormatTag(0x0018) // Media Vision, Inc. 306 | WAVE_FORMAT_CU_CODEC = WaveFormatTag(0x0019) // Hewlett-Packard Company 307 | WAVE_FORMAT_YAMAHA_ADPCM = WaveFormatTag(0x0020) // Yamaha Corporation of America 308 | WAVE_FORMAT_SONARC = WaveFormatTag(0x0021) // Speech Compression 309 | WAVE_FORMAT_DSPGROUP_TRUESPEECH = WaveFormatTag(0x0022) // DSP Group, Inc 310 | WAVE_FORMAT_ECHOSC1 = WaveFormatTag(0x0023) // Echo Speech Corporation 311 | WAVE_FORMAT_AUDIOFILE_AF36 = WaveFormatTag(0x0024) // Audiofile, Inc. 312 | WAVE_FORMAT_APTX = WaveFormatTag(0x0025) // Audio Processing Technology 313 | WAVE_FORMAT_AUDIOFILE_AF10 = WaveFormatTag(0x0026) // Audiofile, Inc. 314 | WAVE_FORMAT_PROSODY_1612 = WaveFormatTag(0x0027) // Aculab plc 315 | WAVE_FORMAT_LRC = WaveFormatTag(0x0028) // Merging Technologies S.A. 316 | WAVE_FORMAT_DOLBY_AC2 = WaveFormatTag(0x0030) // Dolby Laboratories 317 | WAVE_FORMAT_GSM610 = WaveFormatTag(0x0031) // Microsoft Corporation 318 | WAVE_FORMAT_MSNAUDIO = WaveFormatTag(0x0032) // Microsoft Corporation 319 | WAVE_FORMAT_ANTEX_ADPCME = WaveFormatTag(0x0033) // Antex Electronics Corporation 320 | WAVE_FORMAT_CONTROL_RES_VQLPC = WaveFormatTag(0x0034) // Control Resources Limited 321 | WAVE_FORMAT_DIGIREAL = WaveFormatTag(0x0035) // DSP Solutions, Inc. 322 | WAVE_FORMAT_DIGIADPCM = WaveFormatTag(0x0036) // DSP Solutions, Inc. 323 | WAVE_FORMAT_CONTROL_RES_CR10 = WaveFormatTag(0x0037) // Control Resources Limited 324 | WAVE_FORMAT_NMS_VBXADPCM = WaveFormatTag(0x0038) // Natural MicroSystems 325 | WAVE_FORMAT_ROLAND_RDAC = WaveFormatTag(0x0039) // Roland 326 | WAVE_FORMAT_ECHOSC3 = WaveFormatTag(0x003A) // Echo Speech Corporation 327 | WAVE_FORMAT_ROCKWELL_ADPCM = WaveFormatTag(0x003B) // Rockwell International 328 | WAVE_FORMAT_ROCKWELL_DIGITALK = WaveFormatTag(0x003C) // Rockwell International 329 | WAVE_FORMAT_XEBEC = WaveFormatTag(0x003D) // Xebec Multimedia Solutions Limited 330 | WAVE_FORMAT_G721_ADPCM = WaveFormatTag(0x0040) // Antex Electronics Corporation 331 | WAVE_FORMAT_G728_CELP = WaveFormatTag(0x0041) // Antex Electronics Corporation 332 | WAVE_FORMAT_MSG723 = WaveFormatTag(0x0042) // Microsoft Corporation 333 | WAVE_FORMAT_MPEG = WaveFormatTag(0x0050) // Microsoft Corporation 334 | WAVE_FORMAT_RT24 = WaveFormatTag(0x0052) // InSoft Inc. 335 | WAVE_FORMAT_PAC = WaveFormatTag(0x0053) // InSoft Inc. 336 | WAVE_FORMAT_MPEGLAYER3 = WaveFormatTag(0x0055) // MPEG 3 Layer 1 337 | WAVE_FORMAT_LUCENT_G723 = WaveFormatTag(0x0059) // Lucent Technologies 338 | WAVE_FORMAT_CIRRUS = WaveFormatTag(0x0060) // Cirrus Logic 339 | WAVE_FORMAT_ESPCM = WaveFormatTag(0x0061) // ESS Technology 340 | WAVE_FORMAT_VOXWARE = WaveFormatTag(0x0062) // Voxware Inc 341 | WAVE_FORMAT_CANOPUS_ATRAC = WaveFormatTag(0x0063) // Canopus, Co., Ltd. 342 | WAVE_FORMAT_G726_ADPCM = WaveFormatTag(0x0064) // APICOM 343 | WAVE_FORMAT_G722_ADPCM = WaveFormatTag(0x0065) // APICOM 344 | WAVE_FORMAT_DSAT = WaveFormatTag(0x0066) // Microsoft Corporation 345 | WAVE_FORMAT_DSAT_DISPLAY = WaveFormatTag(0x0067) // Microsoft Corporation 346 | WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = WaveFormatTag(0x0069) // Voxware Inc. 347 | WAVE_FORMAT_VOXWARE_AC8 = WaveFormatTag(0x0070) // Voxware Inc. 348 | WAVE_FORMAT_VOXWARE_AC10 = WaveFormatTag(0x0071) // Voxware Inc. 349 | WAVE_FORMAT_VOXWARE_AC16 = WaveFormatTag(0x0072) // Voxware Inc. 350 | WAVE_FORMAT_VOXWARE_AC20 = WaveFormatTag(0x0073) // Voxware Inc. 351 | WAVE_FORMAT_VOXWARE_RT24 = WaveFormatTag(0x0074) // Voxware Inc. 352 | WAVE_FORMAT_VOXWARE_RT29 = WaveFormatTag(0x0075) // Voxware Inc. 353 | WAVE_FORMAT_VOXWARE_RT29HW = WaveFormatTag(0x0076) // Voxware Inc. 354 | WAVE_FORMAT_VOXWARE_VR12 = WaveFormatTag(0x0077) // Voxware Inc. 355 | WAVE_FORMAT_VOXWARE_VR18 = WaveFormatTag(0x0078) // Voxware Inc. 356 | WAVE_FORMAT_VOXWARE_TQ40 = WaveFormatTag(0x0079) // Voxware Inc. 357 | WAVE_FORMAT_SOFTSOUND = WaveFormatTag(0x0080) // Softsound, Ltd. 358 | WAVE_FORMAT_VOXARE_TQ60 = WaveFormatTag(0x0081) // Voxware Inc. 359 | WAVE_FORMAT_MSRT24 = WaveFormatTag(0x0082) // Microsoft Corporation 360 | WAVE_FORMAT_G729A = WaveFormatTag(0x0083) // AT&T Laboratories 361 | WAVE_FORMAT_MVI_MV12 = WaveFormatTag(0x0084) // Motion Pixels 362 | WAVE_FORMAT_DF_G726 = WaveFormatTag(0x0085) // DataFusion Systems (Pty) (Ltd) 363 | WAVE_FORMAT_DF_GSM610 = WaveFormatTag(0x0086) // DataFusion Systems (Pty) (Ltd) 364 | WAVE_FORMAT_ONLIVE = WaveFormatTag(0x0089) // OnLive! Technologies, Inc. 365 | WAVE_FORMAT_SBC24 = WaveFormatTag(0x0091) // Siemens Business Communications Systems 366 | WAVE_FORMAT_DOLBY_AC3_SPDIF = WaveFormatTag(0x0092) // Sonic Foundry 367 | WAVE_FORMAT_ZYXEL_ADPCM = WaveFormatTag(0x0097) // ZyXEL Communications, Inc. 368 | WAVE_FORMAT_PHILIPS_LPCBB = WaveFormatTag(0x0098) // Philips Speech Processing 369 | WAVE_FORMAT_PACKED = WaveFormatTag(0x0099) // Studer Professional Audio AG 370 | WAVE_FORMAT_RHETOREX_ADPCM = WaveFormatTag(0x0100) // Rhetorex, Inc. 371 | IBM_FORMAT_MULAW = WaveFormatTag(0x0101) // IBM mu-law format 372 | IBM_FORMAT_ALAW = WaveFormatTag(0x0102) // IBM a-law format 373 | IBM_FORMAT_ADPCM = WaveFormatTag(0x0103) // IBM AVC Adaptive Differential PCM format 374 | WAVE_FORMAT_VIVO_G723 = WaveFormatTag(0x0111) // Vivo Software 375 | WAVE_FORMAT_VIVO_SIREN = WaveFormatTag(0x0112) // Vivo Software 376 | WAVE_FORMAT_DIGITAL_G723 = WaveFormatTag(0x0123) // Digital Equipment Corporation 377 | WAVE_FORMAT_CREATIVE_ADPCM = WaveFormatTag(0x0200) // Creative Labs, Inc 378 | WAVE_FORMAT_CREATIVE_FASTSPEECH8 = WaveFormatTag(0x0202) // Creative Labs, Inc 379 | WAVE_FORMAT_CREATIVE_FASTSPEECH10 = WaveFormatTag(0x0203) // Creative Labs, Inc 380 | WAVE_FORMAT_QUARTERDECK = WaveFormatTag(0x0220) // Quarterdeck Corporation 381 | WAVE_FORMAT_FM_TOWNS_SND = WaveFormatTag(0x0300) // Fujitsu Corporation 382 | WAVE_FORMAT_BZV_DIGITAL = WaveFormatTag(0x0400) // Brooktree Corporation 383 | WAVE_FORMAT_VME_VMPCM = WaveFormatTag(0x0680) // AT&T Labs, Inc. 384 | WAVE_FORMAT_OLIGSM = WaveFormatTag(0x1000) // Ing C. Olivetti & C., S.p.A. 385 | WAVE_FORMAT_OLIADPCM = WaveFormatTag(0x1001) // Ing C. Olivetti & C., S.p.A. 386 | WAVE_FORMAT_OLICELP = WaveFormatTag(0x1002) // Ing C. Olivetti & C., S.p.A. 387 | WAVE_FORMAT_OLISBC = WaveFormatTag(0x1003) // Ing C. Olivetti & C., S.p.A. 388 | WAVE_FORMAT_OLIOPR = WaveFormatTag(0x1004) // Ing C. Olivetti & C., S.p.A. 389 | WAVE_FORMAT_LH_CODEC = WaveFormatTag(0x1100) // Lernout & Hauspie 390 | WAVE_FORMAT_NORRIS = WaveFormatTag(0x1400) // Norris Communications, Inc. 391 | WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = WaveFormatTag(0x1500) // AT&T Labs, Inc. 392 | WAVE_FORMAT_DVM = WaveFormatTag(0x2000) // FAST Multimedia AG 393 | WAVE_FORMAT_INTERWAV_VSC112 = WaveFormatTag(0x7150) // ????? 394 | WAVE_FORMAT_EXTENSIBLE = WaveFormatTag(0xFFFE) // 395 | ) 396 | 397 | type WFESpeaker uint32 398 | 399 | const ( 400 | SPEAKER_FRONT_LEFT = WFESpeaker(0x00000001) 401 | SPEAKER_FRONT_RIGHT = WFESpeaker(0x00000002) 402 | SPEAKER_FRONT_CENTER = WFESpeaker(0x00000004) 403 | SPEAKER_LOW_FREQUENCY = WFESpeaker(0x00000008) 404 | SPEAKER_BACK_LEFT = WFESpeaker(0x00000010) 405 | SPEAKER_BACK_RIGHT = WFESpeaker(0x00000020) 406 | SPEAKER_FRONT_LEFT_OF_CENTER = WFESpeaker(0x00000040) 407 | SPEAKER_FRONT_RIGHT_OF_CENTER = WFESpeaker(0x00000080) 408 | SPEAKER_BACK_CENTER = WFESpeaker(0x00000100) 409 | SPEAKER_SIDE_LEFT = WFESpeaker(0x00000200) 410 | SPEAKER_SIDE_RIGHT = WFESpeaker(0x00000400) 411 | SPEAKER_TOP_CENTER = WFESpeaker(0x00000800) 412 | SPEAKER_TOP_FRONT_LEFT = WFESpeaker(0x00001000) 413 | SPEAKER_TOP_FRONT_CENTER = WFESpeaker(0x00002000) 414 | SPEAKER_TOP_FRONT_RIGHT = WFESpeaker(0x00004000) 415 | SPEAKER_TOP_BACK_LEFT = WFESpeaker(0x00008000) 416 | SPEAKER_TOP_BACK_CENTER = WFESpeaker(0x00010000) 417 | SPEAKER_TOP_BACK_RIGHT = WFESpeaker(0x00020000) 418 | ) 419 | -------------------------------------------------------------------------------- /resampler/resampler.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2007-2008 Jean-Marc Valin 2 | // Copyright (C) 2008 Thorvald Natvig 3 | // Copyright (C) 2013 Oov 4 | // 5 | // Arbitrary resampling code 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are 9 | // met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // 18 | // 3. The name of the author may not be used to endorse or promote products 19 | // derived from this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | // POSSIBILITY OF SUCH DAMAGE. 32 | 33 | // Package resampler implements audio resampler. 34 | // 35 | // This is a port of the Opus-tools( http://git.xiph.org/?p=opus-tools.git ) audio resampler to the pure Go. 36 | package resampler 37 | 38 | import ( 39 | "math" 40 | ) 41 | 42 | const bufferSize = 160 43 | 44 | type channelState struct { 45 | lastSample int 46 | sampFracNum int 47 | magicSamples int 48 | mem []float64 49 | } 50 | 51 | type Resampler struct { 52 | numRate int 53 | denRate int 54 | 55 | quality *quality 56 | filtLen int 57 | intAdvance int 58 | fracAdvance int 59 | cutoff float64 60 | oversample int 61 | 62 | initialised bool 63 | started bool 64 | skipZeros bool 65 | 66 | channels []channelState 67 | sincTable []float64 68 | resampler func(channelIndex int, in []float64, out []float64) int 69 | } 70 | 71 | func Resample64(in []float64, inSampleRate int, out []float64, outSampleRate int, quality int) (read int, written int) { 72 | return NewWithSkipZeros(1, inSampleRate, outSampleRate, quality).ProcessFloat64(0, in, out) 73 | } 74 | 75 | func Resample32(in []float32, inSampleRate int, out []float32, outSampleRate int, quality int) (read int, written int) { 76 | return NewWithSkipZeros(1, inSampleRate, outSampleRate, quality).ProcessFloat32(0, in, out) 77 | } 78 | 79 | func New(channels int, inSampleRate, outSampleRate int, quality int) *Resampler { 80 | if channels < 1 { 81 | panic("you must have at least one channel") 82 | } 83 | r := &Resampler{ 84 | cutoff: 1.0, 85 | channels: make([]channelState, channels), 86 | } 87 | 88 | r.setQuality(quality) 89 | r.setSampleRate(inSampleRate, outSampleRate) 90 | r.updateFilter() 91 | r.initialised = true 92 | return r 93 | } 94 | 95 | func NewWithSkipZeros(channels int, inSampleRate, outSampleRate int, quality int) *Resampler { 96 | r := New(channels, inSampleRate, outSampleRate, quality) 97 | r.skipZeros = true 98 | return r 99 | } 100 | 101 | // cannot change quality on running in now implementation. 102 | func (r *Resampler) setQuality(q int) { 103 | if q < 0 || q > 10 { 104 | panic("invalid quality value") 105 | } 106 | 107 | if r.quality == &qualityMap[q] { 108 | return 109 | } 110 | r.quality = &qualityMap[q] 111 | if r.initialised { 112 | r.updateFilter() 113 | } 114 | } 115 | 116 | func imin(a, b int) int { 117 | if a < b { 118 | return a 119 | } else { 120 | return b 121 | } 122 | } 123 | 124 | // cannot change sample on running in now implementation. 125 | func (r *Resampler) setSampleRate(in int, out int) { 126 | ratioNum := in 127 | ratioDen := out 128 | 129 | // FIXME: This is terribly inefficient, but who cares (at least for now)? 130 | for fact := 2; fact <= imin(ratioNum, ratioDen); fact++ { 131 | for (ratioNum%fact == 0) && (ratioDen%fact == 0) { 132 | ratioNum /= fact 133 | ratioDen /= fact 134 | } 135 | } 136 | 137 | if r.numRate == ratioNum && r.denRate == ratioDen { 138 | return 139 | } 140 | 141 | if r.denRate > 0 { 142 | for i := range r.channels { 143 | ch := &r.channels[i] 144 | ch.sampFracNum = ch.sampFracNum * ratioDen / r.denRate 145 | // Safety net 146 | if ch.sampFracNum >= ratioDen { 147 | ch.sampFracNum = ratioDen - 1 148 | } 149 | } 150 | } 151 | 152 | r.numRate = ratioNum 153 | r.denRate = ratioDen 154 | 155 | if r.initialised { 156 | r.updateFilter() 157 | } 158 | } 159 | 160 | func (r *Resampler) ProcessFloat64(channelIndex int, in []float64, out []float64) (read int, written int) { 161 | if r.skipZeros { 162 | for i := range r.channels { 163 | r.channels[i].lastSample = r.InputLatency() 164 | } 165 | r.skipZeros = false 166 | } 167 | 168 | ch := &r.channels[channelIndex] 169 | x := ch.mem 170 | filtOffs := r.filtLen - 1 171 | iLen, oLen, xLen := len(in), len(out), len(x)-filtOffs 172 | read, written = iLen, oLen 173 | 174 | if ch.magicSamples != 0 { 175 | oLen -= r.magic(channelIndex, out) 176 | } 177 | 178 | if ch.magicSamples == 0 { 179 | for iLen != 0 && oLen != 0 { 180 | ichunk, ochunk := imin(xLen, iLen), 0 181 | if in != nil { 182 | copy(x[filtOffs:], in[:ichunk]) 183 | } else { 184 | for j := filtOffs; j < ichunk+filtOffs; j++ { 185 | x[j] = 0 186 | } 187 | } 188 | ichunk, ochunk = r.processNative(channelIndex, ichunk, out) 189 | iLen -= ichunk 190 | oLen -= ochunk 191 | out = out[ochunk:] 192 | if in != nil { 193 | in = in[ichunk:] 194 | } 195 | } 196 | } 197 | read -= iLen 198 | written -= oLen 199 | return 200 | } 201 | 202 | func (r *Resampler) ProcessFloat32(channelIndex int, in []float32, out []float32) (read int, written int) { 203 | const stackSize = 1024 204 | var stack [stackSize]float64 205 | 206 | if r.skipZeros { 207 | for i := range r.channels { 208 | r.channels[i].lastSample = r.InputLatency() 209 | } 210 | r.skipZeros = false 211 | } 212 | 213 | ch := &r.channels[channelIndex] 214 | x := ch.mem 215 | filtOffs := r.filtLen - 1 216 | iLen, oLen := len(in), len(out) 217 | xLen, yLen := len(x)-filtOffs, stackSize 218 | read, written = iLen, oLen 219 | 220 | if ch.magicSamples != 0 { 221 | m := r.magic(channelIndex, stack[:imin(yLen, oLen)]) 222 | oLen -= m 223 | for i, s := range stack[:m] { 224 | out[i] = float32(s) 225 | } 226 | out = out[m:] 227 | } 228 | 229 | if ch.magicSamples == 0 { 230 | for iLen != 0 && oLen != 0 { 231 | ichunk, ochunk := imin(xLen, iLen), imin(yLen, oLen) 232 | if in != nil { 233 | for i, s := range in[:ichunk] { 234 | x[filtOffs+i] = float64(s) 235 | } 236 | } else { 237 | for j := filtOffs; j < ichunk+filtOffs; j++ { 238 | x[j] = 0 239 | } 240 | } 241 | ichunk, ochunk = r.processNative(channelIndex, ichunk, stack[:ochunk]) 242 | iLen -= ichunk 243 | oLen -= ochunk 244 | for i, s := range stack[:ochunk] { 245 | out[i] = float32(s) 246 | } 247 | out = out[ochunk:] 248 | if in != nil { 249 | in = in[ichunk:] 250 | } 251 | } 252 | } 253 | read -= iLen 254 | written -= oLen 255 | return 256 | } 257 | 258 | func (r *Resampler) processNative(channelIndex int, inLen int, out []float64) (inLenRet int, outLenRet int) { 259 | ch := &r.channels[channelIndex] 260 | r.started = true 261 | 262 | outLenRet = r.resampler(channelIndex, ch.mem[:inLen], out) 263 | if ch.lastSample < inLen { 264 | inLenRet = ch.lastSample 265 | } else { 266 | inLenRet = inLen 267 | } 268 | ch.lastSample -= inLenRet 269 | copy(ch.mem, ch.mem[inLenRet:inLenRet+r.filtLen-1]) 270 | return 271 | } 272 | 273 | func (r *Resampler) magic(channelIndex int, out []float64) (outWritten int) { 274 | ch := &r.channels[channelIndex] 275 | n := r.filtLen - 1 276 | 277 | inLen, outLen := r.processNative(channelIndex, ch.magicSamples, out) 278 | 279 | ch.magicSamples -= inLen 280 | 281 | // If we couldn't process all "magic" input samples, save the rest for next time 282 | if ch.magicSamples != 0 { 283 | copy(ch.mem[n:n+ch.magicSamples], ch.mem[n+inLen:]) 284 | } 285 | return outLen 286 | } 287 | 288 | func computeFunc(x float64, windowFunc *kaiserTable) float64 { 289 | y := x * float64(windowFunc.oversample) 290 | ind := int(math.Floor(y)) 291 | frac := y - float64(ind) 292 | fracx2 := frac * frac 293 | fracx3 := fracx2 * frac 294 | fracx2mul0_5 := 0.5 * fracx2 295 | fracx3mul0_16 := 0.1666666667 * fracx3 296 | // Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation but I know it's MMSE-optimal on a sinc 297 | i3 := -0.1666666667*frac + fracx3mul0_16 298 | i2 := frac + fracx2mul0_5 - 0.5*fracx3 299 | // interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac; 300 | i0 := -0.3333333333*frac + fracx2mul0_5 - fracx3mul0_16 301 | // Just to make sure we don't have rounding problems 302 | i1 := 1.0 - i3 - i2 - i0 303 | return i0*windowFunc.table[ind] + i1*windowFunc.table[ind+1] + i2*windowFunc.table[ind+2] + i3*windowFunc.table[ind+3] 304 | } 305 | 306 | // The slow way of computing a sinc for the table. Should improve that some day 307 | func sinc(cutoff float64, x float64, n float64, windowFunc *kaiserTable) float64 { 308 | xabs := math.Abs(x) 309 | if xabs < 1e-6 { 310 | return cutoff 311 | } else if xabs > 0.5*n { 312 | return 0 313 | } 314 | // FIXME: Can it really be any slower than this? 315 | xx := x * cutoff * math.Pi 316 | return cutoff * math.Sin(xx) / xx * computeFunc(2.0*xabs/n, windowFunc) 317 | } 318 | 319 | func (r *Resampler) resamplerBasicDirect(channelIndex int, in []float64, out []float64) int { 320 | ch := &r.channels[channelIndex] 321 | n := r.filtLen 322 | outSample := 0 323 | lastSample := ch.lastSample 324 | sampFracNum := ch.sampFracNum 325 | sincTable := r.sincTable 326 | intAdvance := r.intAdvance 327 | fracAdvance := r.fracAdvance 328 | denRate := r.denRate 329 | 330 | for lastSample < len(in) && outSample < len(out) { 331 | sinct := sincTable[sampFracNum*n : sampFracNum*n+n] 332 | var sum float64 333 | for j, s := range in[lastSample : lastSample+n] { 334 | sum += sinct[j] * s 335 | } 336 | 337 | out[outSample] = sum 338 | outSample++ 339 | lastSample += intAdvance 340 | sampFracNum += fracAdvance 341 | if sampFracNum >= denRate { 342 | sampFracNum -= denRate 343 | lastSample++ 344 | } 345 | } 346 | ch.lastSample = lastSample 347 | ch.sampFracNum = sampFracNum 348 | return outSample 349 | } 350 | 351 | func cubicCoef(frac float64) (float64, float64, float64, float64) { 352 | fracx2 := frac * frac 353 | fracx3 := fracx2 * frac 354 | fracx2mul0_5 := 0.5 * fracx2 355 | fracx3mul0_16 := 0.1666666667 * fracx3 356 | // Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation but I know it's MMSE-optimal on a sinc 357 | i0 := -0.1666666667*frac + fracx3mul0_16 358 | i1 := frac + fracx2mul0_5 - 0.5*fracx3 359 | // interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac; 360 | i3 := -0.3333333333*frac + fracx2mul0_5 - fracx3mul0_16 361 | // Just to make sure we don't have rounding problems 362 | i2 := 1.0 - i0 - i1 - i3 363 | return i0, i1, i2, i3 364 | } 365 | 366 | func (r *Resampler) resamplerBasicInterpolate(channelIndex int, in []float64, out []float64) int { 367 | ch := &r.channels[channelIndex] 368 | n := r.filtLen 369 | outSample := 0 370 | lastSample := ch.lastSample 371 | sampFracNum := ch.sampFracNum 372 | intAdvance := r.intAdvance 373 | fracAdvance := r.fracAdvance 374 | denRate := r.denRate 375 | 376 | for lastSample < len(in) && outSample < len(out) { 377 | offset := sampFracNum * r.oversample / r.denRate 378 | frac := float64((sampFracNum*r.oversample)%r.denRate) / float64(r.denRate) 379 | var accum0, accum1, accum2, accum3 float64 380 | for j, s := range in[lastSample : lastSample+n] { 381 | t := 4 + (j+1)*r.oversample - offset 382 | accum0 += s * r.sincTable[t-2] 383 | accum1 += s * r.sincTable[t-1] 384 | accum2 += s * r.sincTable[t] 385 | accum3 += s * r.sincTable[t+1] 386 | } 387 | i0, i1, i2, i3 := cubicCoef(frac) 388 | out[outSample] = i0*accum0 + i1*accum1 + i2*accum2 + i3*accum3 389 | outSample++ 390 | lastSample += intAdvance 391 | sampFracNum += fracAdvance 392 | if sampFracNum >= denRate { 393 | sampFracNum -= denRate 394 | lastSample++ 395 | } 396 | } 397 | ch.lastSample = lastSample 398 | ch.sampFracNum = sampFracNum 399 | return outSample 400 | } 401 | 402 | func (r *Resampler) updateFilter() { 403 | oldLength := r.filtLen 404 | r.oversample = r.quality.oversample 405 | r.filtLen = r.quality.baseLength 406 | 407 | if r.numRate > r.denRate { 408 | // down-sampling 409 | r.cutoff = r.quality.downsampleBandwidth * float64(r.denRate) / float64(r.numRate) 410 | // FIXME: divide the numerator and denominator by a certain amount if they're too large 411 | r.filtLen = r.filtLen * r.numRate / r.denRate 412 | // Round up to make sure we have a multiple of 8 413 | r.filtLen = ((r.filtLen - 1) & (^int(0x7))) + 8 414 | if r.denRate<<1 < r.numRate { 415 | r.oversample >>= 1 416 | } 417 | if r.denRate<<2 < r.numRate { 418 | r.oversample >>= 1 419 | } 420 | if r.denRate<<3 < r.numRate { 421 | r.oversample >>= 1 422 | } 423 | if r.denRate<<4 < r.numRate { 424 | r.oversample >>= 1 425 | } 426 | if r.oversample < 1 { 427 | r.oversample = 1 428 | } 429 | } else { 430 | // up-sampling 431 | r.cutoff = r.quality.upsampleBandwidth 432 | } 433 | 434 | // Choose the resampling type that requires the least amount of memory 435 | if r.denRate <= 16*(r.oversample+8) { 436 | if r.sincTable == nil || len(r.sincTable) < r.filtLen*r.denRate { 437 | r.sincTable = make([]float64, r.filtLen*r.denRate) 438 | } 439 | for i := 0; i < r.denRate; i++ { 440 | for j := 0; j < r.filtLen; j++ { 441 | r.sincTable[i*r.filtLen+j] = sinc( 442 | r.cutoff, 443 | float64(j-(r.filtLen>>1)+1)-float64(i)/float64(r.denRate), 444 | float64(r.filtLen), 445 | r.quality.table, 446 | ) 447 | } 448 | } 449 | r.resampler = r.resamplerBasicDirect 450 | } else { 451 | if r.sincTable == nil || len(r.sincTable) < r.filtLen*r.oversample+8 { 452 | r.sincTable = make([]float64, r.filtLen*r.oversample+8) 453 | } 454 | for i := -4; i < r.oversample*r.filtLen+4; i++ { 455 | r.sincTable[i+4] = sinc( 456 | r.cutoff, 457 | float64(i)/float64(r.oversample)-float64(r.filtLen>>1), 458 | float64(r.filtLen), 459 | r.quality.table, 460 | ) 461 | } 462 | r.resampler = r.resamplerBasicInterpolate 463 | } 464 | 465 | r.intAdvance = r.numRate / r.denRate 466 | r.fracAdvance = r.numRate % r.denRate 467 | 468 | // Here's the place where we update the filter memory to take into account 469 | // the change in filter length. It's probably the messiest part of the code 470 | // due to handling of lots of corner cases. 471 | switch { 472 | case r.channels[0].mem == nil || !r.started: 473 | size := r.filtLen - 1 + bufferSize 474 | for i := range r.channels { 475 | r.channels[i].mem = make([]float64, size) 476 | } 477 | case r.filtLen > oldLength: 478 | panic("not implemented") 479 | // Increase the filter length 480 | // oldAllocSize := len(r.mem) / len(r.channels) 481 | // if r.filtLen-1+r.bufferSize > oldAllocSize { 482 | // m := make([]float64, (r.filtLen-1+r.bufferSize)*len(r.channels)) 483 | // copy(m, r.mem) 484 | // r.mem = m 485 | // } 486 | for i := len(r.channels) - 1; i >= 0; i-- { 487 | // spx_int32_t j; 488 | // spx_uint32_t olen = old_length; 489 | // /*if (st->magic_samples[i])*/ 490 | // { 491 | // /* Try and remove the magic samples as if nothing had happened */ 492 | // 493 | // /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ 494 | // olen = old_length + 2*st->magic_samples[i]; 495 | // for (j=old_length-2+st->magic_samples[i];j>=0;j--) 496 | // st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; 497 | // for (j=0;jmagic_samples[i];j++) 498 | // st->mem[i*st->mem_alloc_size+j] = 0; 499 | // st->magic_samples[i] = 0; 500 | // } 501 | // if (st->filt_len > olen) 502 | // { 503 | // /* If the new filter length is still bigger than the "augmented" length */ 504 | // /* Copy data going backward */ 505 | // for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; 507 | // /* Then put zeros for lack of anything better */ 508 | // for (;jfilt_len-1;j++) 509 | // st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; 510 | // /* Adjust last_sample */ 511 | // st->last_sample[i] += (st->filt_len - olen)/2; 512 | // } else { 513 | // /* Put back some of the magic! */ 514 | // st->magic_samples[i] = (olen - st->filt_len)/2; 515 | // for (j=0;jfilt_len-1+st->magic_samples[i];j++) 516 | // st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; 517 | // } 518 | } 519 | case r.filtLen < oldLength: 520 | panic("not implemented") 521 | // spx_uint32_t i; 522 | // /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" 523 | // samples so they can be used directly as input the next time(s) */ 524 | // for (i=0;inb_channels;i++) 525 | // { 526 | // spx_uint32_t j; 527 | // spx_uint32_t old_magic = st->magic_samples[i]; 528 | // st->magic_samples[i] = (old_length - st->filt_len)/2; 529 | // /* We must copy some of the memory that's no longer used */ 530 | // /* Copy data going backward */ 531 | // for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) 532 | // st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; 533 | // st->magic_samples[i] += old_magic; 534 | // } 535 | } 536 | } 537 | 538 | func (r *Resampler) InputLatency() int { 539 | return r.filtLen >> 1 540 | } 541 | 542 | func (r *Resampler) OutputLatency() int { 543 | return ((r.filtLen>>1)*r.denRate + (r.numRate >> 1)) / r.numRate 544 | } 545 | --------------------------------------------------------------------------------