├── .github └── workflows │ └── go.yml ├── LICENSE ├── README.md ├── bitreader.go ├── codebook.go ├── decode.go ├── decode_test.go ├── doc.go ├── floor0.go ├── floor1.go ├── go.mod ├── header.go ├── huffman.go ├── imdct.go ├── imdct_test.go ├── inversedbtable.go ├── residue.go ├── setup.go ├── testdata ├── test.gob └── test.raw ├── vorbis.go └── window.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.15 20 | 21 | - name: Build 22 | run: go build -v ./... 23 | 24 | - name: Test 25 | run: go test -v ./... 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Johann Freymuth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vorbis 2 | 3 | a native go vorbis decoder 4 | 5 | Note that this package can only decode raw vorbis packets, for reading .ogg files, use [oggvorbis](https://github.com/jfreymuth/oggvorbis) 6 | 7 | [godoc](https://godocs.io/github.com/jfreymuth/vorbis) 8 | 9 | [The vorbis specification](https://xiph.org/vorbis/doc/Vorbis_I_spec.html) 10 | -------------------------------------------------------------------------------- /bitreader.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | type bitReader struct { 4 | data []byte 5 | position int 6 | bitOffset uint 7 | eof bool 8 | } 9 | 10 | func newBitReader(data []byte) *bitReader { 11 | return &bitReader{data, 0, 0, false} 12 | } 13 | 14 | func (r *bitReader) EOF() bool { 15 | return r.eof 16 | } 17 | 18 | func (r *bitReader) Read1() uint32 { 19 | if r.position >= len(r.data) { 20 | r.eof = true 21 | return 0 22 | } 23 | var result uint32 24 | if r.data[r.position]&(1< bits { 38 | panic("invalid argument") 39 | } 40 | var result uint32 41 | var written uint 42 | size := n 43 | for n > 0 { 44 | if r.position >= len(r.data) { 45 | r.eof = true 46 | return 0 47 | } 48 | result |= uint32(r.data[r.position]>>r.bitOffset) << written 49 | written += 8 - r.bitOffset 50 | if n < 8-r.bitOffset { 51 | r.bitOffset += n 52 | break 53 | } 54 | n -= 8 - r.bitOffset 55 | r.bitOffset = 0 56 | r.position++ 57 | } 58 | return result &^ (0xFFFFFFFF << size) 59 | } 60 | 61 | func (r *bitReader) Read8(n uint) uint8 { 62 | return uint8(r.read(n, 8)) 63 | } 64 | 65 | func (r *bitReader) Read16(n uint) uint16 { 66 | return uint16(r.read(n, 16)) 67 | } 68 | 69 | func (r *bitReader) Read32(n uint) uint32 { 70 | return uint32(r.read(n, 32)) 71 | } 72 | 73 | func (r *bitReader) ReadBool() bool { 74 | return r.Read8(1) == 1 75 | } 76 | -------------------------------------------------------------------------------- /codebook.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import ( 4 | "errors" 5 | "math" 6 | ) 7 | 8 | const codebookPattern = 0x564342 //"BCV" 9 | 10 | type codebook struct { 11 | dimensions uint32 12 | entries huffmanCode 13 | values []float32 14 | } 15 | 16 | func (c *codebook) ReadFrom(r *bitReader) error { 17 | if r.Read32(24) != codebookPattern { 18 | return errors.New("vorbis: decoding error") 19 | } 20 | c.dimensions = r.Read32(16) 21 | numEntries := r.Read32(24) 22 | entries := newHuffmanBuilder(numEntries*2 - 2) 23 | ordered := r.ReadBool() 24 | if !ordered { 25 | sparse := r.ReadBool() 26 | for i := uint32(0); i < numEntries; i++ { 27 | if !sparse || r.ReadBool() { 28 | entries.Put(i, r.Read8(5)+1) 29 | } 30 | } 31 | } else { 32 | currentEntry := uint32(0) 33 | currentLength := r.Read8(5) + 1 34 | for currentEntry < numEntries { 35 | num := r.Read32(ilog(int(numEntries - currentEntry))) 36 | for i := currentEntry; i < currentEntry+num; i++ { 37 | entries.Put(i, currentLength) 38 | } 39 | currentEntry += num 40 | currentLength++ 41 | } 42 | } 43 | c.entries = entries.code 44 | 45 | lookupType := r.Read8(4) 46 | if lookupType == 0 { 47 | return nil 48 | } 49 | if lookupType > 2 { 50 | return errors.New("vorbis: decoding error") 51 | } 52 | minimumValue := float32Unpack(r.Read32(32)) 53 | deltaValue := float32Unpack(r.Read32(32)) 54 | valueBits := r.Read8(4) + 1 55 | sequenceP := r.ReadBool() 56 | var multiplicands []uint32 57 | if lookupType == 1 { 58 | multiplicands = make([]uint32, lookup1Values(int(numEntries), c.dimensions)) 59 | } else { 60 | multiplicands = make([]uint32, int(numEntries)*int(c.dimensions)) 61 | } 62 | for i := range multiplicands { 63 | multiplicands[i] = r.Read32(uint(valueBits)) 64 | } 65 | c.values = make([]float32, numEntries*c.dimensions) 66 | for entry := 0; entry < int(numEntries); entry++ { 67 | index := entry * int(c.dimensions) 68 | if lookupType == 1 { 69 | last := float32(0) 70 | indexDivisor := 1 71 | for i := 0; i < int(c.dimensions); i++ { 72 | multiplicandOffset := (entry / indexDivisor) % len(multiplicands) 73 | c.values[index+i] = float32(multiplicands[multiplicandOffset])*deltaValue + minimumValue + last 74 | if sequenceP { 75 | last = c.values[index+i] 76 | } 77 | indexDivisor *= len(multiplicands) 78 | } 79 | } else if lookupType == 2 { 80 | last := float32(0) 81 | for i := 0; i < int(c.dimensions); i++ { 82 | c.values[index+i] = float32(multiplicands[index+i])*deltaValue + minimumValue + last 83 | if sequenceP { 84 | last = c.values[index+i] 85 | } 86 | } 87 | } 88 | } 89 | return nil 90 | } 91 | 92 | func (c *codebook) DecodeScalar(r *bitReader) uint32 { 93 | return c.entries.Lookup(r) 94 | } 95 | 96 | func (c *codebook) DecodeVector(r *bitReader) []float32 { 97 | index := c.entries.Lookup(r) * c.dimensions 98 | return c.values[index : index+c.dimensions] 99 | } 100 | 101 | func ilog(x int) uint { 102 | var r uint 103 | for x > 0 { 104 | r++ 105 | x >>= 1 106 | } 107 | return r 108 | } 109 | 110 | func lookup1Values(entries int, dim uint32) int { 111 | r := int(math.Floor(math.Pow(float64(entries), 1/float64(dim)))) 112 | if math.Pow(float64(r+1), float64(dim)) <= float64(entries) { 113 | return r + 1 114 | } 115 | return r 116 | } 117 | 118 | func float32Unpack(x uint32) float32 { 119 | mantissa := float64(x & 0x1fffff) 120 | if x&0x80000000 != 0 { 121 | mantissa = -mantissa 122 | } 123 | exponent := (x & 0x7fe00000) >> 21 124 | return float32(math.Ldexp(mantissa, int(exponent)-788)) 125 | } 126 | -------------------------------------------------------------------------------- /decode.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import "errors" 4 | 5 | type floorData struct { 6 | floor floor 7 | data interface{} 8 | noResidue bool 9 | } 10 | 11 | func (d *Decoder) decodePacket(r *bitReader, out []float32) ([]float32, error) { 12 | if r.ReadBool() { 13 | return nil, errors.New("vorbis: decoding error") 14 | } 15 | modeNumber := r.Read8(ilog(len(d.modes) - 1)) 16 | mode := d.modes[modeNumber] 17 | // decode window type 18 | blocktype := mode.blockflag 19 | longWindow := mode.blockflag == 1 20 | blocksize := d.blocksize[blocktype] 21 | spectrumSize := uint32(blocksize / 2) 22 | windowPrev, windowNext := false, false 23 | window := windowType{blocksize, blocksize, blocksize} 24 | if longWindow { 25 | windowPrev = r.ReadBool() 26 | windowNext = r.ReadBool() 27 | if !windowPrev { 28 | window.prev = d.blocksize[0] 29 | } 30 | if !windowNext { 31 | window.next = d.blocksize[0] 32 | } 33 | } 34 | 35 | mapping := &d.mappings[mode.mapping] 36 | if d.floorBuffer == nil { 37 | d.floorBuffer = make([]floorData, d.channels) 38 | } 39 | for ch := range d.residueBuffer { 40 | d.residueBuffer[ch] = d.residueBuffer[ch][:spectrumSize] 41 | for i := range d.residueBuffer[ch] { 42 | d.residueBuffer[ch][i] = 0 43 | } 44 | } 45 | 46 | d.decodeFloors(r, d.floorBuffer, mapping, spectrumSize) 47 | d.decodeResidue(r, d.residueBuffer, mapping, d.floorBuffer, spectrumSize) 48 | d.inverseCoupling(mapping, d.residueBuffer) 49 | d.applyFloor(d.floorBuffer, d.residueBuffer) 50 | 51 | // inverse MDCT 52 | for ch := range d.rawBuffer { 53 | d.rawBuffer[ch] = d.rawBuffer[ch][:blocksize] 54 | imdct(&d.lookup[blocktype], d.residueBuffer[ch], d.rawBuffer[ch]) 55 | } 56 | 57 | // apply window and overlap 58 | d.applyWindow(&window, d.rawBuffer) 59 | center := blocksize / 2 60 | offset := d.blocksize[1]/4 - d.blocksize[0]/4 61 | n := 0 62 | if d.hasOverlap { 63 | n = blocksize / 2 64 | if longWindow && !windowPrev { 65 | n -= offset 66 | } 67 | if !longWindow && !d.overlapShort { 68 | n += offset 69 | } 70 | if out == nil { 71 | out = make([]float32, n*d.channels) 72 | } 73 | } 74 | if longWindow { 75 | start := 0 76 | if !windowPrev { 77 | start = offset 78 | } 79 | if d.hasOverlap { 80 | for ch := range d.rawBuffer { 81 | for i := 0; i < center-start; i++ { 82 | out[i*d.channels+ch] = d.rawBuffer[ch][start+i] + d.overlap[(start+i)*d.channels+ch] 83 | } 84 | } 85 | } 86 | d.overlapShort = false 87 | } else /*short window*/ { 88 | if d.hasOverlap { 89 | if d.overlapShort { 90 | for ch := range d.rawBuffer { 91 | for i := 0; i < center; i++ { 92 | out[i*d.channels+ch] = d.rawBuffer[ch][i] + d.overlap[(offset+i)*d.channels+ch] 93 | } 94 | } 95 | } else { 96 | for i := 0; i < offset*d.channels; i++ { 97 | out[i] = d.overlap[i] 98 | } 99 | for ch := range d.rawBuffer { 100 | for i := offset; i < offset+center; i++ { 101 | out[i*d.channels+ch] = d.rawBuffer[ch][i-offset] + d.overlap[i*d.channels+ch] 102 | } 103 | } 104 | } 105 | } 106 | d.overlapShort = true 107 | } 108 | 109 | if !d.hasOverlap { 110 | n = 0 111 | } 112 | overlapCenter := d.blocksize[1] / 4 113 | oStart := overlapCenter - center/2 114 | oEnd := overlapCenter + center/2 115 | for i := 0; i < oStart*d.channels; i++ { 116 | d.overlap[i] = 0 117 | } 118 | for ch := range d.rawBuffer { 119 | for i := oStart; i < oEnd; i++ { 120 | d.overlap[i*d.channels+ch] = d.rawBuffer[ch][center+i-oStart] 121 | } 122 | } 123 | for i := oEnd * d.channels; i < len(d.overlap); i++ { 124 | d.overlap[i] = 0 125 | } 126 | d.hasOverlap = true 127 | 128 | return out[:n*d.channels], nil 129 | } 130 | 131 | func (d *Decoder) decodeFloors(r *bitReader, floors []floorData, mapping *mapping, n uint32) { 132 | for ch := range floors { 133 | floor := d.floors[mapping.submaps[mapping.mux[ch]].floor] 134 | data := floor.Decode(r, d.codebooks, n) 135 | floors[ch] = floorData{floor, data, data == nil} 136 | } 137 | 138 | for i := 0; i < int(mapping.couplingSteps); i++ { 139 | if !floors[mapping.magnitude[i]].noResidue || !floors[mapping.angle[i]].noResidue { 140 | floors[mapping.magnitude[i]].noResidue = false 141 | floors[mapping.angle[i]].noResidue = false 142 | } 143 | } 144 | } 145 | 146 | func (d *Decoder) decodeResidue(r *bitReader, out [][]float32, mapping *mapping, floors []floorData, n uint32) { 147 | for i := range mapping.submaps { 148 | doNotDecode := make([]bool, 0, len(out)) 149 | tmp := make([][]float32, 0, len(out)) 150 | for j := 0; j < d.channels; j++ { 151 | if mapping.mux[j] == uint8(i) { 152 | doNotDecode = append(doNotDecode, floors[j].noResidue) 153 | tmp = append(tmp, out[j]) 154 | } 155 | } 156 | d.residues[mapping.submaps[i].residue].Decode(r, doNotDecode, n, d.codebooks, tmp) 157 | } 158 | } 159 | 160 | func (d *Decoder) inverseCoupling(mapping *mapping, residueVectors [][]float32) { 161 | for i := mapping.couplingSteps; i > 0; i-- { 162 | magnitudeVector := residueVectors[mapping.magnitude[i-1]] 163 | angleVector := residueVectors[mapping.angle[i-1]] 164 | for j := range magnitudeVector { 165 | m := magnitudeVector[j] 166 | a := angleVector[j] 167 | if m > 0 { 168 | if a > 0 { 169 | m, a = m, m-a 170 | } else { 171 | a, m = m, m+a 172 | } 173 | } else { 174 | if a > 0 { 175 | m, a = m, m+a 176 | } else { 177 | a, m = m, m-a 178 | } 179 | } 180 | magnitudeVector[j] = m 181 | angleVector[j] = a 182 | } 183 | } 184 | } 185 | 186 | func (d *Decoder) applyFloor(floors []floorData, residueVectors [][]float32) { 187 | for ch := range residueVectors { 188 | if floors[ch].data != nil { 189 | floors[ch].floor.Apply(residueVectors[ch], floors[ch].data) 190 | } else { 191 | for i := range residueVectors[ch] { 192 | residueVectors[ch][i] = 0 193 | } 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /decode_test.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/gob" 6 | "io" 7 | "os" 8 | "testing" 9 | ) 10 | 11 | type GobVorbis struct { 12 | Headers [3][]byte 13 | Packets [][]byte 14 | } 15 | 16 | func readTestFile() (*GobVorbis, error) { 17 | file, err := os.Open("testdata/test.gob") 18 | if err != nil { 19 | return nil, err 20 | } 21 | defer file.Close() 22 | 23 | data := new(GobVorbis) 24 | err = gob.NewDecoder(file).Decode(data) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return data, nil 29 | } 30 | 31 | func TestDecode(t *testing.T) { 32 | data, err := readTestFile() 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | 37 | var dec Decoder 38 | for _, header := range data.Headers { 39 | err = dec.ReadHeader(header) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | } 44 | 45 | if dec.SampleRate() != 44100 { 46 | t.Errorf("sample rate is %d, expected %d", dec.SampleRate(), 44100) 47 | } 48 | if dec.Channels() != 1 { 49 | t.Errorf("channels is %d, expected %d", dec.Channels(), 1) 50 | } 51 | 52 | refFile, err := os.Open("testdata/test.raw") 53 | if err != nil { 54 | t.Fatal(err) 55 | } 56 | defer refFile.Close() 57 | 58 | rawSize, _ := refFile.Seek(0, io.SeekEnd) 59 | refFile.Seek(0, io.SeekStart) 60 | reference := make([]float32, rawSize/4) 61 | binary.Read(refFile, binary.LittleEndian, reference) 62 | 63 | pos := 0 64 | decode: 65 | for _, packet := range data.Packets { 66 | out, err := dec.Decode(packet) 67 | if err != nil { 68 | t.Fatal(err) 69 | } 70 | n := len(out) 71 | if pos+n > len(reference) { 72 | // it's ok for the decoded data to be longer, since only an integral number of packets can be decoded 73 | n = len(reference) - pos 74 | } 75 | for i := 0; i < n; i++ { 76 | if !equal(out[i], reference[pos+i], .00002) { 77 | t.Errorf("different values at sample %d (%g != %g)", i, out[i], reference[pos+i]) 78 | break decode 79 | } 80 | } 81 | pos += n 82 | } 83 | if pos < len(reference) { 84 | t.Errorf("not enough samples were decoded (%d, expected at least %d)", pos, len(reference)) 85 | } 86 | } 87 | 88 | func equal(a, b, tolerance float32) bool { 89 | return (a > b && a-b < tolerance) || b-a < tolerance 90 | } 91 | 92 | func BenchmarkSetup(b *testing.B) { 93 | data, err := readTestFile() 94 | if err != nil { 95 | b.Fatal(err) 96 | } 97 | 98 | b.ResetTimer() 99 | for i := 0; i < b.N; i++ { 100 | var dec Decoder 101 | for _, header := range data.Headers { 102 | if err = dec.ReadHeader(header); err != nil { 103 | b.Fatal(err) 104 | } 105 | } 106 | } 107 | } 108 | 109 | func BenchmarkDecode(b *testing.B) { 110 | data, err := readTestFile() 111 | if err != nil { 112 | b.Fatal(err) 113 | } 114 | 115 | var dec Decoder 116 | for _, header := range data.Headers { 117 | if err = dec.ReadHeader(header); err != nil { 118 | b.Fatal(err) 119 | } 120 | } 121 | 122 | b.ResetTimer() 123 | for i := 0; i < b.N; i++ { 124 | for _, packet := range data.Packets { 125 | if _, err := dec.Decode(packet); err != nil { 126 | b.Fatal(err) 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package vorbis implements a vorbis decoder. 3 | 4 | Note that this package only decodes raw vorbis packets, these packets are 5 | usually stored in a container format like ogg. 6 | 7 | The vorbis specification is available at: 8 | https://xiph.org/vorbis/doc/Vorbis_I_spec.html 9 | 10 | */ 11 | package vorbis // import "github.com/jfreymuth/vorbis" 12 | -------------------------------------------------------------------------------- /floor0.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | type floor0 struct { 8 | order uint8 9 | rate uint16 10 | barkMapSize uint16 11 | amplitudeBits uint8 12 | amplitudeOffset uint8 13 | bookList []uint8 14 | } 15 | 16 | type floor0Data struct { 17 | amplitude uint32 18 | coefficients []float32 19 | } 20 | 21 | func (f *floor0) ReadFrom(r *bitReader) error { 22 | f.order = r.Read8(8) 23 | f.rate = r.Read16(16) 24 | f.barkMapSize = r.Read16(16) 25 | f.amplitudeBits = r.Read8(6) 26 | f.amplitudeOffset = r.Read8(8) 27 | f.bookList = make([]uint8, r.Read8(4)+1) 28 | for i := range f.bookList { 29 | f.bookList[i] = r.Read8(8) 30 | } 31 | return nil 32 | } 33 | 34 | func (f *floor0) Decode(r *bitReader, books []codebook, n uint32) interface{} { 35 | amplitude := r.Read32(uint(f.amplitudeBits)) 36 | if amplitude == 0 { 37 | return nil 38 | } 39 | bookNumber := r.Read8(ilog(len(f.bookList))) 40 | book := books[f.bookList[bookNumber]] 41 | coefficients := make([]float32, f.order) 42 | i := 0 43 | last := float32(0) 44 | for { 45 | tempVector := book.DecodeVector(r) 46 | for _, c := range tempVector { 47 | coefficients[i] = c + last 48 | i++ 49 | if i >= len(coefficients) { 50 | return floor0Data{amplitude, coefficients} 51 | } 52 | } 53 | last = tempVector[len(tempVector)-1] 54 | } 55 | } 56 | 57 | func (f *floor0) Apply(out []float32, data interface{}) { 58 | d := data.(floor0Data) 59 | n := uint32(len(out)) 60 | i := uint32(0) 61 | for i < n { 62 | mapi := f.mapResult(i, n) 63 | w := math.Pi * float64(mapi) / float64(f.barkMapSize) 64 | cosw := math.Cos(w) 65 | var p, q float64 66 | if f.order%2 == 1 { 67 | p = 1 - cosw*cosw 68 | for j := 0; j <= int(f.order-3)/2; j++ { 69 | tmp := math.Cos(float64(d.coefficients[2*j+1])) - cosw 70 | p *= 4 * tmp * tmp 71 | } 72 | q = 1 / 4 73 | for j := 0; j <= int(f.order-1)/2; j++ { 74 | tmp := math.Cos(float64(d.coefficients[2*j])) - cosw 75 | q *= 4 * tmp * tmp 76 | } 77 | } else { 78 | p = (1 - cosw*cosw) / 2 79 | for j := 0; j <= int(f.order-2)/2; j++ { 80 | tmp := math.Cos(float64(d.coefficients[2*j+1])) - cosw 81 | p *= 4 * tmp * tmp 82 | } 83 | q = (1 + cosw*cosw) / 2 84 | for j := 0; j <= int(f.order-2)/2; j++ { 85 | tmp := math.Cos(float64(d.coefficients[2*j])) - cosw 86 | q *= 4 * tmp * tmp 87 | } 88 | } 89 | linearFloorValue := math.Exp(.11512925 * (float64(d.amplitude)*float64(f.amplitudeOffset)/(float64(uint64(1)<= n { 99 | return -1 100 | } 101 | b := int(math.Floor(bark(float64(f.rate)*float64(i)/2*float64(n)) * float64(f.barkMapSize) / bark(.5*float64(f.rate)))) 102 | if b > int(f.barkMapSize)-1 { 103 | return int(f.barkMapSize) - 1 104 | } 105 | return b 106 | } 107 | 108 | func bark(x float64) float64 { 109 | return 13.1*math.Atan(.00074*x) + 2.24*math.Atan(.0000000185*x*x) + .0001*x 110 | } 111 | -------------------------------------------------------------------------------- /floor1.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import "sort" 4 | 5 | type floor1 struct { 6 | partitionClassList []uint8 7 | classes []floor1Class 8 | multiplier uint8 9 | rangebits uint8 10 | xList []uint32 11 | sort []uint32 12 | 13 | step2 []bool 14 | finalY []uint32 15 | } 16 | 17 | type floor1Class struct { 18 | dimension uint8 19 | subclass uint8 20 | masterbook uint8 21 | subclassBooks []uint8 22 | } 23 | 24 | func (f *floor1) ReadFrom(r *bitReader) error { 25 | f.partitionClassList = make([]uint8, r.Read8(5)) 26 | var maximumClass uint8 27 | for i := range f.partitionClassList { 28 | class := r.Read8(4) 29 | f.partitionClassList[i] = class 30 | if class > maximumClass { 31 | maximumClass = class 32 | } 33 | } 34 | 35 | f.classes = make([]floor1Class, maximumClass+1) 36 | for i := range f.classes { 37 | class := &f.classes[i] 38 | class.dimension = r.Read8(3) + 1 39 | class.subclass = r.Read8(2) 40 | if class.subclass != 0 { 41 | class.masterbook = r.Read8(8) 42 | } 43 | class.subclassBooks = make([]uint8, 1< 0 { 84 | cval = books[class.masterbook].DecodeScalar(r) 85 | } 86 | for j := 0; j < int(cdim); j++ { 87 | book := class.subclassBooks[cval&csub] 88 | cval >>= cbits 89 | if book != 0xFF { 90 | y = append(y, books[book].DecodeScalar(r)) 91 | } else { 92 | y = append(y, 0) 93 | } 94 | } 95 | } 96 | return y 97 | } 98 | 99 | func (f *floor1) Apply(out []float32, data interface{}) { 100 | y := data.([]uint32) 101 | n := uint32(len(out)) 102 | range_ := [4]uint32{256, 128, 86, 64}[f.multiplier-1] 103 | 104 | f.step2[0], f.step2[1] = true, true 105 | f.finalY[0], f.finalY[1] = y[0], y[1] 106 | 107 | for i := 2; i < len(f.xList); i++ { 108 | low := lowNeighbor(f.xList, i) 109 | high := highNeighbor(f.xList, i) 110 | predicted := renderPoint(f.xList[low], f.finalY[low], f.xList[high], f.finalY[high], f.xList[i]) 111 | val := y[i] 112 | 113 | highRoom := range_ - predicted 114 | lowRoom := predicted 115 | var room uint32 116 | if highRoom < lowRoom { 117 | room = highRoom * 2 118 | } else { 119 | room = lowRoom * 2 120 | } 121 | 122 | if val == 0 { 123 | f.step2[i] = false 124 | f.finalY[i] = predicted 125 | } else { 126 | f.step2[low] = true 127 | f.step2[high] = true 128 | f.step2[i] = true 129 | if val >= room { 130 | if highRoom > lowRoom { 131 | f.finalY[i] = val - lowRoom + predicted 132 | } else { 133 | f.finalY[i] = predicted - val + highRoom - 1 134 | } 135 | } else { 136 | if val%2 == 1 { 137 | f.finalY[i] = predicted - (val+1)/2 138 | } else { 139 | f.finalY[i] = predicted + val/2 140 | } 141 | } 142 | } 143 | } 144 | 145 | var hx, lx uint32 146 | ly := f.finalY[0] * uint32(f.multiplier) 147 | 148 | var hy uint32 149 | for j := 1; j < len(f.finalY); j++ { 150 | i := f.sort[j] 151 | if f.step2[i] { 152 | hy = f.finalY[i] * uint32(f.multiplier) 153 | hx = f.xList[i] 154 | renderLine(lx, ly, hx, hy, out) 155 | lx = hx 156 | ly = hy 157 | } 158 | } 159 | 160 | if hx < n { 161 | for i := hx; i < n; i++ { 162 | out[i] *= inverseDBTable[hy] 163 | } 164 | } 165 | } 166 | 167 | func (f *floor1) Len() int { 168 | return len(f.xList) 169 | } 170 | func (f *floor1) Less(i, j int) bool { 171 | return f.xList[f.sort[i]] < f.xList[f.sort[j]] 172 | } 173 | func (f *floor1) Swap(i, j int) { 174 | f.sort[i], f.sort[j] = f.sort[j], f.sort[i] 175 | } 176 | 177 | func lowNeighbor(v []uint32, index int) int { 178 | val := v[index] 179 | best := 0 180 | max := uint32(0) 181 | for i := 1; i < index; i++ { 182 | if v[i] >= val { 183 | continue 184 | } 185 | if v[i] > max { 186 | best = i 187 | max = v[i] 188 | } 189 | } 190 | return best 191 | } 192 | func highNeighbor(v []uint32, index int) int { 193 | val := v[index] 194 | best := 0 195 | min := uint32(0xffffffff) 196 | for i := 1; i < index; i++ { 197 | if v[i] <= val { 198 | continue 199 | } 200 | if v[i] < min { 201 | best = i 202 | min = v[i] 203 | } 204 | } 205 | return best 206 | } 207 | 208 | func renderPoint(x0, y0, x1, y1, x uint32) uint32 { 209 | dy := int(y1) - int(y0) 210 | adx := x1 - x0 211 | ady := y1 - y0 212 | if dy < 0 { 213 | ady = uint32(-dy) 214 | } 215 | err := ady * (x - x0) 216 | off := err / adx 217 | if dy < 0 { 218 | return y0 - off 219 | } 220 | return y0 + off 221 | } 222 | 223 | func renderLine(x0, y0, x1, y1 uint32, v []float32) { 224 | dy := int(y1) - int(y0) 225 | adx := x1 - x0 226 | ady := y1 - y0 227 | if dy < 0 { 228 | ady = uint32(-dy) 229 | } 230 | base := dy / int(adx) 231 | x := x0 232 | y := y0 233 | err := uint32(0) 234 | var sy int 235 | if dy < 0 { 236 | sy = base - 1 237 | } else { 238 | sy = base + 1 239 | } 240 | 241 | absBase := uint32(base) 242 | if base < 0 { 243 | absBase = uint32(-absBase) 244 | } 245 | ady -= absBase * adx 246 | 247 | v[x] *= inverseDBTable[y] 248 | for x := x0 + 1; x < x1; x++ { 249 | err += ady 250 | if err >= adx { 251 | err -= adx 252 | y = uint32(int(y) + sy) 253 | } else { 254 | y = uint32(int(y) + base) 255 | } 256 | v[x] *= inverseDBTable[y] 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jfreymuth/vorbis 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /header.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | ) 7 | 8 | const ( 9 | headerTypeIdentification = 1 10 | headerTypeComment = 3 11 | headerTypeSetup = 5 12 | ) 13 | 14 | func (d *Decoder) readIdentificationHeader(h []byte) error { 15 | if len(h) <= 22 { 16 | return errors.New("vorbis: decoding error") 17 | } 18 | le := binary.LittleEndian 19 | version := le.Uint32(h) 20 | if version != 0 { 21 | return errors.New("vorbis: decoding error") 22 | } 23 | d.channels = int(h[4]) 24 | d.sampleRate = int(le.Uint32(h[5:])) 25 | d.Bitrate.Maximum = int(le.Uint32(h[9:])) 26 | d.Bitrate.Nominal = int(le.Uint32(h[13:])) 27 | d.Bitrate.Minimum = int(le.Uint32(h[17:])) 28 | d.blocksize[0] = 1 << (h[21] & 0x0F) 29 | d.blocksize[1] = 1 << (h[21] >> 4) 30 | if h[22]&1 == 0 { 31 | return errors.New("vorbis: decoding error") 32 | } 33 | return nil 34 | } 35 | 36 | func (d *Decoder) readCommentHeader(h []byte) error { 37 | var err error 38 | defer func() { 39 | if recover() != nil { 40 | err = errors.New("vorbis: decoding error") 41 | } 42 | }() 43 | le := binary.LittleEndian 44 | vendorLen := le.Uint32(h) 45 | h = h[4:] 46 | d.Vendor = string(h[:vendorLen]) 47 | h = h[vendorLen:] 48 | numComments := int(le.Uint32(h)) 49 | d.Comments = make([]string, numComments) 50 | h = h[4:] 51 | for i := 0; i < numComments; i++ { 52 | commentLen := le.Uint32(h) 53 | h = h[4:] 54 | d.Comments[i] = string(h[:commentLen]) 55 | h = h[commentLen:] 56 | } 57 | return err 58 | } 59 | -------------------------------------------------------------------------------- /huffman.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | type huffmanCode []uint32 4 | 5 | func (h huffmanCode) Lookup(r *bitReader) uint32 { 6 | i := uint32(0) 7 | for i&1 == 0 { 8 | i = h[i+r.Read1()] 9 | } 10 | return i >> 1 11 | } 12 | 13 | type huffmanBuilder struct { 14 | code huffmanCode 15 | minLength []uint8 16 | } 17 | 18 | func newHuffmanBuilder(size uint32) *huffmanBuilder { 19 | return &huffmanBuilder{ 20 | code: make(huffmanCode, size), 21 | minLength: make([]uint8, size/2), 22 | } 23 | } 24 | 25 | func (t *huffmanBuilder) Put(entry uint32, length uint8) { 26 | t.put(0, entry, length-1) 27 | } 28 | 29 | func (t *huffmanBuilder) put(index, entry uint32, length uint8) bool { 30 | if length < t.minLength[index/2] { 31 | return false 32 | } 33 | if length == 0 { 34 | if t.code[index] == 0 { 35 | t.code[index] = entry*2 + 1 36 | return true 37 | } 38 | if t.code[index+1] == 0 { 39 | t.code[index+1] = entry*2 + 1 40 | t.minLength[index/2] = 1 41 | return true 42 | } 43 | t.minLength[index/2] = 1 44 | return false 45 | } 46 | if t.code[index]&1 == 0 { 47 | if t.code[index] == 0 { 48 | t.code[index] = t.findEmpty(index + 2) 49 | } 50 | if t.put(t.code[index], entry, length-1) { 51 | return true 52 | } 53 | } 54 | if t.code[index+1]&1 == 0 { 55 | if t.code[index+1] == 0 { 56 | t.code[index+1] = t.findEmpty(index + 2) 57 | } 58 | if t.put(t.code[index+1], entry, length-1) { 59 | return true 60 | } 61 | } 62 | t.minLength[index/2] = length + 1 63 | return false 64 | } 65 | 66 | func (t *huffmanBuilder) findEmpty(index uint32) uint32 { 67 | for t.code[index] != 0 { 68 | index += 2 69 | } 70 | return index 71 | } 72 | -------------------------------------------------------------------------------- /imdct.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import ( 4 | "math" 5 | "math/bits" 6 | ) 7 | 8 | type imdctLookup struct { 9 | A, B, C []float32 10 | } 11 | 12 | func generateIMDCTLookup(n int, l *imdctLookup) { 13 | l.A = make([]float32, n/2) 14 | l.B = make([]float32, n/2) 15 | l.C = make([]float32, n/4) 16 | fn := float64(n) 17 | for k := 0; k < n/4; k++ { 18 | fk := float64(k) 19 | l.A[2*k] = float32(math.Cos(4 * fk * math.Pi / fn)) 20 | l.A[2*k+1] = float32(-math.Sin(4 * fk * math.Pi / fn)) 21 | l.B[2*k] = float32(math.Cos((2*fk + 1) * math.Pi / fn / 2)) 22 | l.B[2*k+1] = float32(math.Sin((2*fk + 1) * math.Pi / fn / 2)) 23 | } 24 | for k := 0; k < n/8; k++ { 25 | fk := float64(k) 26 | l.C[2*k] = float32(math.Cos(2 * (2*fk + 1) * math.Pi / fn)) 27 | l.C[2*k+1] = float32(-math.Sin(2 * (2*fk + 1) * math.Pi / fn)) 28 | } 29 | } 30 | 31 | // "inverse modified discrete cosine transform" 32 | func imdct(t *imdctLookup, in, out []float32) { 33 | n := len(in) * 2 34 | 35 | n2, n4, n8 := n/2, n/4, n/8 36 | n3_4 := n - n4 37 | 38 | // more of these steps could be done in place, but we need two arrays anyway 39 | for j := 0; j < n8; j++ { 40 | a0 := t.A[n2-2*j-1] 41 | a1 := t.A[n2-2*j-2] 42 | a2 := t.A[n4-2*j-1] 43 | a3 := t.A[n4-2*j-2] 44 | a4 := t.A[n2-4-4*j] 45 | a5 := t.A[n2-3-4*j] 46 | v0 := (-in[4*j+3])*a0 + (-in[4*j+1])*a1 47 | v1 := (-in[4*j+3])*a1 - (-in[4*j+1])*a0 48 | v2 := (in[n2-4*j-4])*a2 + (in[n2-4*j-2])*a3 49 | v3 := (in[n2-4*j-4])*a3 - (in[n2-4*j-2])*a2 50 | out[n4+2*j+1] = v3 + v1 51 | out[n4+2*j] = v2 + v0 52 | out[2*j+1] = (v3-v1)*a4 - (v2-v0)*a5 53 | out[2*j] = (v2-v0)*a4 + (v3-v1)*a5 54 | } 55 | ld := int(ilog(n) - 1) 56 | for l := 0; l < ld-3; l++ { 57 | k0 := n >> uint(l+3) 58 | k1 := 1 << uint(l+3) 59 | rlim := n >> uint(l+4) 60 | s2lim := 1 << uint(l+2) 61 | for r := 0; r < rlim; r++ { 62 | a0 := t.A[r*k1] 63 | a1 := t.A[r*k1+1] 64 | i0 := n2 - 1 - 2*r 65 | i1 := n2 - 2 - 2*r 66 | i2 := n2 - 1 - k0 - 2*r 67 | i3 := n2 - 2 - k0 - 2*r 68 | for s2 := 0; s2 < s2lim; s2 += 2 { 69 | v0, v1 := out[i0], out[i1] 70 | v2, v3 := out[i2], out[i3] 71 | out[i0] = v0 + v2 72 | out[i1] = v1 + v3 73 | out[i2] = (v0-v2)*a0 - (v1-v3)*a1 74 | out[i3] = (v1-v3)*a0 + (v0-v2)*a1 75 | i0 -= 2 * k0 76 | i1 -= 2 * k0 77 | i2 -= 2 * k0 78 | i3 -= 2 * k0 79 | } 80 | } 81 | } 82 | for i := 0; i < n8; i++ { 83 | j := int(bits.Reverse32(uint32(i)) >> uint(32-ld+3)) 84 | if i < j { 85 | out[4*j], out[4*i] = out[4*i], out[4*j] 86 | out[4*j+1], out[4*i+1] = out[4*i+1], out[4*j+1] 87 | out[4*j+2], out[4*i+2] = out[4*i+2], out[4*j+2] 88 | out[4*j+3], out[4*i+3] = out[4*i+3], out[4*j+3] 89 | } 90 | } 91 | for k := 0; k < n8; k++ { 92 | in[n2-1-2*k] = out[4*k] 93 | in[n2-2-2*k] = out[4*k+1] 94 | in[n4-1-2*k] = out[4*k+2] 95 | in[n4-2-2*k] = out[4*k+3] 96 | } 97 | i0 := 0 98 | i1 := 1 99 | i2 := n2 - 2 100 | i3 := n2 - 1 101 | for k := 0; k < n8; k++ { 102 | v0, v1 := in[i0], in[i1] 103 | v2, v3 := in[i2], in[i3] 104 | c0 := t.C[i0] 105 | c1 := t.C[i1] 106 | out[i0] = (v0 + v2 + c1*(v0-v2) + c0*(v1+v3)) / 2 107 | out[i2] = (v0 + v2 - c1*(v0-v2) - c0*(v1+v3)) / 2 108 | out[i1] = (v1 - v3 + c1*(v1+v3) - c0*(v0-v2)) / 2 109 | out[i3] = (-v1 + v3 + c1*(v1+v3) - c0*(v0-v2)) / 2 110 | i0 += 2 111 | i1 += 2 112 | i2 -= 2 113 | i3 -= 2 114 | } 115 | for k := 0; k < n4; k++ { 116 | b0 := t.B[2*k] 117 | b1 := t.B[2*k+1] 118 | v0 := out[2*k] 119 | v1 := out[2*k+1] 120 | in[k] = v0*b0 + v1*b1 121 | in[n2-1-k] = v0*b1 - v1*b0 122 | } 123 | for i := 0; i < n4; i++ { 124 | out[i] = in[i+n4] 125 | out[n-i-1] = -in[n-i-n3_4-1] 126 | } 127 | for i := n4; i < n3_4; i++ { 128 | out[i] = -in[n3_4-i-1] 129 | } 130 | } 131 | 132 | // original c code from stb_vorbis 133 | 134 | /* 135 | // this is the original version of the above code, if you want to optimize it from scratch 136 | void inverse_mdct_naive(float *buffer, int n) 137 | { 138 | float s; 139 | float A[1 << 12], B[1 << 12], C[1 << 11]; 140 | int i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; 141 | int n3_4 = n - n4, ld; 142 | // how can they claim this only uses N words?! 143 | // oh, because they're only used sparsely, whoops 144 | float u[1 << 13], X[1 << 13], v[1 << 13], w[1 << 13]; 145 | // set up twiddle factors 146 | 147 | for (k=k2=0; k < n4; ++k,k2+=2) { 148 | A[k2 ] = (float) cos(4*k*M_PI/n); 149 | A[k2+1] = (float) -sin(4*k*M_PI/n); 150 | B[k2 ] = (float) cos((k2+1)*M_PI/n/2); 151 | B[k2+1] = (float) sin((k2+1)*M_PI/n/2); 152 | } 153 | for (k=k2=0; k < n8; ++k,k2+=2) { 154 | C[k2 ] = (float) cos(2*(k2+1)*M_PI/n); 155 | C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n); 156 | } 157 | 158 | // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" 159 | // Note there are bugs in that pseudocode, presumably due to them attempting 160 | // to rename the arrays nicely rather than representing the way their actual 161 | // implementation bounces buffers back and forth. As a result, even in the 162 | // "some formulars corrected" version, a direct implementation fails. These 163 | // are noted below as "paper bug". 164 | 165 | // copy and reflect spectral data 166 | for (k=0; k < n2; ++k) u[k] = buffer[k]; 167 | for ( ; k < n ; ++k) u[k] = -buffer[n - k - 1]; 168 | // kernel from paper 169 | // step 1 170 | for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) { 171 | v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1]; 172 | v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2]; 173 | } 174 | // step 2 175 | for (k=k4=0; k < n8; k+=1, k4+=4) { 176 | w[n2+3+k4] = v[n2+3+k4] + v[k4+3]; 177 | w[n2+1+k4] = v[n2+1+k4] + v[k4+1]; 178 | w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4]; 179 | w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4]; 180 | } 181 | // step 3 182 | ld = ilog(n) - 1; // ilog is off-by-one from normal definitions 183 | for (l=0; l < ld-3; ++l) { 184 | int k0 = n >> (l+2), k1 = 1 << (l+3); 185 | int rlim = n >> (l+4), r4, r; 186 | int s2lim = 1 << (l+2), s2; 187 | for (r=r4=0; r < rlim; r4+=4,++r) { 188 | for (s2=0; s2 < s2lim; s2+=2) { 189 | u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4]; 190 | u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4]; 191 | u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1] 192 | - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1]; 193 | u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1] 194 | + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1]; 195 | } 196 | } 197 | if (l+1 < ld-3) { 198 | // paper bug: ping-ponging of u&w here is omitted 199 | memcpy(w, u, sizeof(u)); 200 | } 201 | } 202 | 203 | // step 4 204 | for (i=0; i < n8; ++i) { 205 | int j = bit_reverse(i) >> (32-ld+3); 206 | assert(j < n8); 207 | if (i == j) { 208 | // paper bug: original code probably swapped in place; if copying, 209 | // need to directly copy in this case 210 | int i8 = i << 3; 211 | v[i8+1] = u[i8+1]; 212 | v[i8+3] = u[i8+3]; 213 | v[i8+5] = u[i8+5]; 214 | v[i8+7] = u[i8+7]; 215 | } else if (i < j) { 216 | int i8 = i << 3, j8 = j << 3; 217 | v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1]; 218 | v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3]; 219 | v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5]; 220 | v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7]; 221 | } 222 | } 223 | // step 5 224 | for (k=0; k < n2; ++k) { 225 | w[k] = v[k*2+1]; 226 | } 227 | // step 6 228 | for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) { 229 | u[n-1-k2] = w[k4]; 230 | u[n-2-k2] = w[k4+1]; 231 | u[n3_4 - 1 - k2] = w[k4+2]; 232 | u[n3_4 - 2 - k2] = w[k4+3]; 233 | } 234 | // step 7 235 | for (k=k2=0; k < n8; ++k, k2 += 2) { 236 | v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2; 237 | v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2; 238 | v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2; 239 | v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2; 240 | } 241 | // step 8 242 | for (k=k2=0; k < n4; ++k,k2 += 2) { 243 | X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1]; 244 | X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ]; 245 | } 246 | 247 | // decode kernel to output 248 | // determined the following value experimentally 249 | // (by first figuring out what made inverse_mdct_slow work); then matching that here 250 | // (probably vorbis encoder premultiplies by n or n/2, to save it on the decoder?) 251 | s = 0.5; // theoretically would be n4 252 | 253 | // [[[ note! the s value of 0.5 is compensated for by the B[] in the current code, 254 | // so it needs to use the "old" B values to behave correctly, or else 255 | // set s to 1.0 ]]] 256 | for (i=0; i < n4 ; ++i) buffer[i] = s * X[i+n4]; 257 | for ( ; i < n3_4; ++i) buffer[i] = -s * X[n3_4 - i - 1]; 258 | for ( ; i < n ; ++i) buffer[i] = -s * X[i - n3_4]; 259 | } 260 | */ 261 | -------------------------------------------------------------------------------- /imdct_test.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func imdctSlow(in []float32) []float32 { 10 | n := len(in) 11 | fn := float32(n) 12 | out := make([]float32, 2*n) 13 | for i := range out { 14 | var sum float32 15 | fi := float32(i) 16 | for k := 0; k < n; k++ { 17 | fk := float32(k) 18 | sum += in[k] * float32(math.Cos(float64((math.Pi/fn)*(fi+.5+fn/2)*(fk+.5)))) 19 | } 20 | out[i] = sum 21 | } 22 | return out 23 | } 24 | 25 | func TestIMDCT(t *testing.T) { 26 | //rand.Seed(0) 27 | const blocksize = 256 28 | data := make([]float32, blocksize/2) 29 | for i := range data { 30 | data[i] = rand.Float32() 31 | } 32 | 33 | reference := imdctSlow(data) 34 | 35 | var lookup imdctLookup 36 | generateIMDCTLookup(blocksize, &lookup) 37 | result := make([]float32, blocksize) 38 | imdct(&lookup, data, result) 39 | 40 | for i := range result { 41 | if !equalAbs(result[i], reference[i], 1.002) { 42 | t.Errorf("different values at index %d (%g != %g)", i, result[i], reference[i]) 43 | break 44 | } 45 | } 46 | } 47 | 48 | func BenchmarkIMDCT(b *testing.B) { 49 | const blocksize = 8192 50 | 51 | data := make([]float32, blocksize/2) 52 | for i := range data { 53 | data[i] = rand.Float32() 54 | } 55 | 56 | var lookup imdctLookup 57 | generateIMDCTLookup(blocksize, &lookup) 58 | out := make([]float32, blocksize) 59 | 60 | in := make([]float32, blocksize/2) 61 | 62 | b.ResetTimer() 63 | for i := 0; i < b.N; i++ { 64 | // the imdct function does not preserve the input, 65 | // reset it, otherwise everything ends up being NaN 66 | copy(in, data) 67 | imdct(&lookup, in, out) 68 | } 69 | } 70 | 71 | func equalRel(a, b, tolerance float32) bool { 72 | return (a > b && a/b < tolerance) || b/a < tolerance 73 | } 74 | 75 | func equalAbs(a, b, tolerance float32) bool { 76 | return a-b < tolerance && b-a < tolerance 77 | } 78 | -------------------------------------------------------------------------------- /inversedbtable.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | var inverseDBTable = [...]float32{ 4 | 1.0649863e-07, 5 | 1.1341951e-07, 6 | 1.2079015e-07, 7 | 1.2863978e-07, 8 | 1.3699951e-07, 9 | 1.4590251e-07, 10 | 1.5538408e-07, 11 | 1.6548181e-07, 12 | 1.7623575e-07, 13 | 1.8768855e-07, 14 | 1.9988561e-07, 15 | 2.1287530e-07, 16 | 2.2670913e-07, 17 | 2.4144197e-07, 18 | 2.5713223e-07, 19 | 2.7384213e-07, 20 | 2.9163793e-07, 21 | 3.1059021e-07, 22 | 3.3077411e-07, 23 | 3.5226968e-07, 24 | 3.7516214e-07, 25 | 3.9954229e-07, 26 | 4.2550680e-07, 27 | 4.5315863e-07, 28 | 4.8260743e-07, 29 | 5.1396998e-07, 30 | 5.4737065e-07, 31 | 5.8294187e-07, 32 | 6.2082472e-07, 33 | 6.6116941e-07, 34 | 7.0413592e-07, 35 | 7.4989464e-07, 36 | 7.9862701e-07, 37 | 8.5052630e-07, 38 | 9.0579828e-07, 39 | 9.6466216e-07, 40 | 1.0273513e-06, 41 | 1.0941144e-06, 42 | 1.1652161e-06, 43 | 1.2409384e-06, 44 | 1.3215816e-06, 45 | 1.4074654e-06, 46 | 1.4989305e-06, 47 | 1.5963394e-06, 48 | 1.7000785e-06, 49 | 1.8105592e-06, 50 | 1.9282195e-06, 51 | 2.0535261e-06, 52 | 2.1869758e-06, 53 | 2.3290978e-06, 54 | 2.4804557e-06, 55 | 2.6416497e-06, 56 | 2.8133190e-06, 57 | 2.9961443e-06, 58 | 3.1908506e-06, 59 | 3.3982101e-06, 60 | 3.6190449e-06, 61 | 3.8542308e-06, 62 | 4.1047004e-06, 63 | 4.3714470e-06, 64 | 4.6555282e-06, 65 | 4.9580707e-06, 66 | 5.2802740e-06, 67 | 5.6234160e-06, 68 | 5.9888572e-06, 69 | 6.3780469e-06, 70 | 6.7925283e-06, 71 | 7.2339451e-06, 72 | 7.7040476e-06, 73 | 8.2047000e-06, 74 | 8.7378876e-06, 75 | 9.3057248e-06, 76 | 9.9104632e-06, 77 | 1.0554501e-05, 78 | 1.1240392e-05, 79 | 1.1970856e-05, 80 | 1.2748789e-05, 81 | 1.3577278e-05, 82 | 1.4459606e-05, 83 | 1.5399272e-05, 84 | 1.6400004e-05, 85 | 1.7465768e-05, 86 | 1.8600792e-05, 87 | 1.9809576e-05, 88 | 2.1096914e-05, 89 | 2.2467911e-05, 90 | 2.3928002e-05, 91 | 2.5482978e-05, 92 | 2.7139006e-05, 93 | 2.8902651e-05, 94 | 3.0780908e-05, 95 | 3.2781225e-05, 96 | 3.4911534e-05, 97 | 3.7180282e-05, 98 | 3.9596466e-05, 99 | 4.2169667e-05, 100 | 4.4910090e-05, 101 | 4.7828601e-05, 102 | 5.0936773e-05, 103 | 5.4246931e-05, 104 | 5.7772202e-05, 105 | 6.1526565e-05, 106 | 6.5524908e-05, 107 | 6.9783085e-05, 108 | 7.4317983e-05, 109 | 7.9147585e-05, 110 | 8.4291040e-05, 111 | 8.9768747e-05, 112 | 9.5602426e-05, 113 | 0.00010181521, 114 | 0.00010843174, 115 | 0.00011547824, 116 | 0.00012298267, 117 | 0.00013097477, 118 | 0.00013948625, 119 | 0.00014855085, 120 | 0.00015820453, 121 | 0.00016848555, 122 | 0.00017943469, 123 | 0.00019109536, 124 | 0.00020351382, 125 | 0.00021673929, 126 | 0.00023082423, 127 | 0.00024582449, 128 | 0.00026179955, 129 | 0.00027881276, 130 | 0.00029693158, 131 | 0.00031622787, 132 | 0.00033677814, 133 | 0.00035866388, 134 | 0.00038197188, 135 | 0.00040679456, 136 | 0.00043323036, 137 | 0.00046138411, 138 | 0.00049136745, 139 | 0.00052329927, 140 | 0.00055730621, 141 | 0.00059352311, 142 | 0.00063209358, 143 | 0.00067317058, 144 | 0.00071691700, 145 | 0.00076350630, 146 | 0.00081312324, 147 | 0.00086596457, 148 | 0.00092223983, 149 | 0.00098217216, 150 | 0.0010459992, 151 | 0.0011139742, 152 | 0.0011863665, 153 | 0.0012634633, 154 | 0.0013455702, 155 | 0.0014330129, 156 | 0.0015261382, 157 | 0.0016253153, 158 | 0.0017309374, 159 | 0.0018434235, 160 | 0.0019632195, 161 | 0.0020908006, 162 | 0.0022266726, 163 | 0.0023713743, 164 | 0.0025254795, 165 | 0.0026895994, 166 | 0.0028643847, 167 | 0.0030505286, 168 | 0.0032487691, 169 | 0.0034598925, 170 | 0.0036847358, 171 | 0.0039241906, 172 | 0.0041792066, 173 | 0.0044507950, 174 | 0.0047400328, 175 | 0.0050480668, 176 | 0.0053761186, 177 | 0.0057254891, 178 | 0.0060975636, 179 | 0.0064938176, 180 | 0.0069158225, 181 | 0.0073652516, 182 | 0.0078438871, 183 | 0.0083536271, 184 | 0.0088964928, 185 | 0.009474637, 186 | 0.010090352, 187 | 0.010746080, 188 | 0.011444421, 189 | 0.012188144, 190 | 0.012980198, 191 | 0.013823725, 192 | 0.014722068, 193 | 0.015678791, 194 | 0.016697687, 195 | 0.017782797, 196 | 0.018938423, 197 | 0.020169149, 198 | 0.021479854, 199 | 0.022875735, 200 | 0.024362330, 201 | 0.025945531, 202 | 0.027631618, 203 | 0.029427276, 204 | 0.031339626, 205 | 0.033376252, 206 | 0.035545228, 207 | 0.037855157, 208 | 0.040315199, 209 | 0.042935108, 210 | 0.045725273, 211 | 0.048696758, 212 | 0.051861348, 213 | 0.055231591, 214 | 0.058820850, 215 | 0.062643361, 216 | 0.066714279, 217 | 0.071049749, 218 | 0.075666962, 219 | 0.080584227, 220 | 0.085821044, 221 | 0.091398179, 222 | 0.097337747, 223 | 0.10366330, 224 | 0.11039993, 225 | 0.11757434, 226 | 0.12521498, 227 | 0.13335215, 228 | 0.14201813, 229 | 0.15124727, 230 | 0.16107617, 231 | 0.17154380, 232 | 0.18269168, 233 | 0.19456402, 234 | 0.20720788, 235 | 0.22067342, 236 | 0.23501402, 237 | 0.25028656, 238 | 0.26655159, 239 | 0.28387361, 240 | 0.30232132, 241 | 0.32196786, 242 | 0.34289114, 243 | 0.36517414, 244 | 0.38890521, 245 | 0.41417847, 246 | 0.44109412, 247 | 0.46975890, 248 | 0.50028648, 249 | 0.53279791, 250 | 0.56742212, 251 | 0.60429640, 252 | 0.64356699, 253 | 0.68538959, 254 | 0.72993007, 255 | 0.77736504, 256 | 0.82788260, 257 | 0.88168307, 258 | 0.9389798, 259 | 1.0, 260 | } 261 | 262 | // gofmt does not like tables :D 263 | -------------------------------------------------------------------------------- /residue.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import "errors" 4 | 5 | type residue struct { 6 | residueType uint16 7 | begin, end uint32 8 | partitionSize uint32 9 | classifications uint8 10 | classbook uint8 11 | cascade []uint8 12 | books [][8]int16 13 | } 14 | 15 | func (x *residue) ReadFrom(r *bitReader) error { 16 | x.residueType = r.Read16(16) 17 | if x.residueType > 2 { 18 | return errors.New("vorbis: decoding error") 19 | } 20 | x.begin = r.Read32(24) 21 | x.end = r.Read32(24) 22 | x.partitionSize = r.Read32(24) + 1 23 | x.classifications = r.Read8(6) + 1 24 | x.classbook = r.Read8(8) 25 | x.cascade = make([]uint8, x.classifications) 26 | for i := range x.cascade { 27 | highBits := uint8(0) 28 | lowBits := r.Read8(3) 29 | if r.ReadBool() { 30 | highBits = r.Read8(5) 31 | } 32 | x.cascade[i] = highBits*8 + lowBits 33 | } 34 | 35 | x.books = make([][8]int16, x.classifications) 36 | for i := range x.books { 37 | for j := 0; j < 8; j++ { 38 | if x.cascade[i]&(1< n { 67 | begin = n 68 | } 69 | if end > n { 70 | end = n 71 | } 72 | classbook := books[x.classbook] 73 | classWordsPerCodeword := classbook.dimensions 74 | nToRead := end - begin 75 | partitionsToRead := nToRead / x.partitionSize 76 | 77 | if nToRead == 0 { 78 | return 79 | } 80 | cs := (partitionsToRead + classWordsPerCodeword) 81 | classifications := make([]uint32, ch*cs) 82 | for pass := 0; pass < 8; pass++ { 83 | partitionCount := uint32(0) 84 | for partitionCount < partitionsToRead { 85 | if pass == 0 { 86 | for j := uint32(0); j < ch; j++ { 87 | if !doNotDecode[j] { 88 | temp := classbook.DecodeScalar(r) 89 | for i := classWordsPerCodeword; i > 0; i-- { 90 | classifications[j*cs+(i-1)+partitionCount] = temp % uint32(x.classifications) 91 | temp /= uint32(x.classifications) 92 | } 93 | } 94 | } 95 | } 96 | for classword := uint32(0); classword < classWordsPerCodeword && partitionCount < partitionsToRead; classword++ { 97 | for j := uint32(0); j < ch; j++ { 98 | if !doNotDecode[j] { 99 | vqclass := classifications[j*cs+partitionCount] 100 | vqbook := x.books[vqclass][pass] 101 | if vqbook != -1 { 102 | book := books[vqbook] 103 | offset := begin + partitionCount*x.partitionSize 104 | switch x.residueType { 105 | case 0: 106 | step := x.partitionSize / book.dimensions 107 | for i := uint32(0); i < step; i++ { 108 | tmp := book.DecodeVector(r) 109 | for k := range tmp { 110 | out[j][offset+i+uint32(k)*step] += tmp[k] 111 | } 112 | } 113 | case 1: 114 | var i uint32 115 | for i < x.partitionSize { 116 | tmp := book.DecodeVector(r) 117 | for k := range tmp { 118 | out[j][offset+i] += tmp[k] 119 | i++ 120 | } 121 | } 122 | case 2: 123 | var i uint32 124 | ch := uint32(len(out)) 125 | for i < x.partitionSize { 126 | tmp := book.DecodeVector(r) 127 | for k := range tmp { 128 | out[(offset+i)%ch][(offset+i)/ch] += tmp[k] 129 | i++ 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | partitionCount++ 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /setup.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import "errors" 4 | 5 | type floor interface { 6 | Decode(*bitReader, []codebook, uint32) interface{} 7 | Apply(out []float32, data interface{}) 8 | } 9 | 10 | type mapping struct { 11 | couplingSteps uint16 12 | angle []uint8 13 | magnitude []uint8 14 | mux []uint8 15 | submaps []mappingSubmap 16 | } 17 | 18 | type mappingSubmap struct { 19 | floor, residue uint8 20 | } 21 | 22 | type mode struct { 23 | blockflag uint8 24 | mapping uint8 25 | } 26 | 27 | func (d *Decoder) readSetupHeader(header []byte) error { 28 | r := newBitReader(header) 29 | 30 | // CODEBOOKS 31 | d.codebooks = make([]codebook, r.Read16(8)+1) 32 | for i := range d.codebooks { 33 | err := d.codebooks[i].ReadFrom(r) 34 | if err != nil { 35 | return err 36 | } 37 | } 38 | 39 | // TIME DOMAIN TRANSFORMS 40 | transformCount := r.Read8(6) + 1 41 | for i := 0; i < int(transformCount); i++ { 42 | if r.Read16(16) != 0 { 43 | return errors.New("vorbis: decoding error") 44 | } 45 | } 46 | 47 | // FLOORS 48 | d.floors = make([]floor, r.Read8(6)+1) 49 | for i := range d.floors { 50 | var err error 51 | switch r.Read16(16) { 52 | case 0: 53 | f := new(floor0) 54 | err = f.ReadFrom(r) 55 | d.floors[i] = f 56 | case 1: 57 | f := new(floor1) 58 | err = f.ReadFrom(r) 59 | d.floors[i] = f 60 | default: 61 | return errors.New("vorbis: decoding error") 62 | } 63 | if err != nil { 64 | return err 65 | } 66 | } 67 | 68 | // RESIDUES 69 | d.residues = make([]residue, r.Read8(6)+1) 70 | for i := range d.residues { 71 | err := d.residues[i].ReadFrom(r) 72 | if err != nil { 73 | return err 74 | } 75 | } 76 | 77 | // MAPPINGS 78 | d.mappings = make([]mapping, r.Read8(6)+1) 79 | for i := range d.mappings { 80 | m := &d.mappings[i] 81 | if r.Read16(16) != 0 { 82 | return errors.New("vorbis: decoding error") 83 | } 84 | if r.ReadBool() { 85 | m.submaps = make([]mappingSubmap, r.Read8(4)+1) 86 | } else { 87 | m.submaps = make([]mappingSubmap, 1) 88 | } 89 | if r.ReadBool() { 90 | m.couplingSteps = r.Read16(8) + 1 91 | m.magnitude = make([]uint8, m.couplingSteps) 92 | m.angle = make([]uint8, m.couplingSteps) 93 | for i := range m.magnitude { 94 | m.magnitude[i] = r.Read8(ilog(d.channels - 1)) 95 | m.angle[i] = r.Read8(ilog(d.channels - 1)) 96 | } 97 | } 98 | if r.Read8(2) != 0 { 99 | return errors.New("vorbis: decoding error") 100 | } 101 | m.mux = make([]uint8, d.channels) 102 | if len(m.submaps) > 1 { 103 | for i := range m.mux { 104 | m.mux[i] = r.Read8(4) 105 | } 106 | } 107 | for i := range m.submaps { 108 | r.Read8(8) 109 | m.submaps[i].floor = r.Read8(8) 110 | m.submaps[i].residue = r.Read8(8) 111 | } 112 | } 113 | 114 | // MODES 115 | d.modes = make([]mode, r.Read8(6)+1) 116 | for i := range d.modes { 117 | m := &d.modes[i] 118 | m.blockflag = r.Read8(1) 119 | if r.Read16(16) != 0 { 120 | return errors.New("vorbis: decoding error") 121 | } 122 | if r.Read16(16) != 0 { 123 | return errors.New("vorbis: decoding error") 124 | } 125 | m.mapping = r.Read8(8) 126 | } 127 | 128 | if !r.ReadBool() { 129 | return errors.New("vorbis: decoding error") 130 | } 131 | d.initLookup() 132 | return nil 133 | } 134 | 135 | func (d *Decoder) initLookup() { 136 | d.windows[0] = makeWindow(d.blocksize[0]) 137 | d.windows[1] = makeWindow(d.blocksize[1]) 138 | generateIMDCTLookup(d.blocksize[0], &d.lookup[0]) 139 | generateIMDCTLookup(d.blocksize[1], &d.lookup[1]) 140 | d.residueBuffer = make([][]float32, d.channels) 141 | for i := range d.residueBuffer { 142 | d.residueBuffer[i] = make([]float32, d.blocksize[1]/2) 143 | } 144 | d.rawBuffer = make([][]float32, d.channels) 145 | for i := range d.rawBuffer { 146 | d.rawBuffer[i] = make([]float32, d.blocksize[1]) 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /testdata/test.gob: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfreymuth/vorbis/bba79ca271fb04261d46a5b2bf2c1be8ea96bfdc/testdata/test.gob -------------------------------------------------------------------------------- /testdata/test.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfreymuth/vorbis/bba79ca271fb04261d46a5b2bf2c1be8ea96bfdc/testdata/test.raw -------------------------------------------------------------------------------- /vorbis.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import "errors" 4 | 5 | // A Decoder stores the information necessary to decode a vorbis steam. 6 | type Decoder struct { 7 | headerRead bool 8 | setupRead bool 9 | 10 | sampleRate int 11 | channels int 12 | Bitrate Bitrate 13 | blocksize [2]int 14 | CommentHeader 15 | 16 | codebooks []codebook 17 | floors []floor 18 | residues []residue 19 | mappings []mapping 20 | modes []mode 21 | 22 | overlap []float32 23 | hasOverlap bool 24 | overlapShort bool 25 | 26 | windows [2][]float32 27 | lookup [2]imdctLookup 28 | residueBuffer [][]float32 29 | floorBuffer []floorData 30 | rawBuffer [][]float32 31 | } 32 | 33 | // The Bitrate of a vorbis stream. 34 | // Some or all of the fields can be zero. 35 | type Bitrate struct { 36 | Nominal int 37 | Minimum int 38 | Maximum int 39 | } 40 | 41 | // The CommentHeader of a vorbis stream. 42 | type CommentHeader struct { 43 | Vendor string 44 | Comments []string 45 | } 46 | 47 | // SampleRate returns the sample rate of the vorbis stream. 48 | // This will be zero if the headers have not been read yet. 49 | func (d *Decoder) SampleRate() int { return d.sampleRate } 50 | 51 | // Channels returns the number of channels of the vorbis stream. 52 | // This will be zero if the headers have not been read yet. 53 | func (d *Decoder) Channels() int { return d.channels } 54 | 55 | // BufferSize returns the highest amount of data that can be decoded from a single packet. 56 | // The result is already multiplied with the number of channels. 57 | // This will be zero if the headers have not been read yet. 58 | func (d *Decoder) BufferSize() int { 59 | return d.blocksize[1] / 2 * d.channels 60 | } 61 | 62 | // IsHeader returns wether the packet is a vorbis header. 63 | func IsHeader(packet []byte) bool { 64 | return len(packet) > 6 && packet[0]&1 == 1 && 65 | packet[1] == 'v' && 66 | packet[2] == 'o' && 67 | packet[3] == 'r' && 68 | packet[4] == 'b' && 69 | packet[5] == 'i' && 70 | packet[6] == 's' 71 | } 72 | 73 | // ReadHeader reads a vorbis header. 74 | // Three headers (identification, comment, and setup) must be read before any samples can be decoded. 75 | func (d *Decoder) ReadHeader(header []byte) error { 76 | if !IsHeader(header) { 77 | return errors.New("vorbis: invalid header") 78 | } 79 | headerType := header[0] 80 | header = header[7:] 81 | switch headerType { 82 | case headerTypeIdentification: 83 | err := d.readIdentificationHeader(header) 84 | if err != nil { 85 | return err 86 | } 87 | d.headerRead = true 88 | case headerTypeComment: 89 | return d.readCommentHeader(header) 90 | case headerTypeSetup: 91 | err := d.readSetupHeader(header) 92 | if err != nil { 93 | return err 94 | } 95 | d.overlap = make([]float32, d.blocksize[1]*d.channels) 96 | d.setupRead = true 97 | default: 98 | return errors.New("vorbis: unknown header type") 99 | } 100 | return nil 101 | } 102 | 103 | // HeadersRead returns wether the headers necessary for decoding have been read. 104 | func (d *Decoder) HeadersRead() bool { 105 | return d.headerRead && d.setupRead 106 | } 107 | 108 | // Decode decodes a packet and returns the result as an interleaved float slice. 109 | // The number of samples decoded varies and can be zero, but will be at most BufferSize() 110 | func (d *Decoder) Decode(in []byte) ([]float32, error) { 111 | if !d.HeadersRead() { 112 | return nil, errors.New("vorbis: missing headers") 113 | } 114 | return d.decodePacket(newBitReader(in), nil) 115 | } 116 | 117 | // DecodeInto decodes a packet and stores the result in the given buffer. 118 | // The size of the buffer must be at least BufferSize(). 119 | // The method will always return a slice of the buffer or nil. 120 | func (d *Decoder) DecodeInto(in []byte, buffer []float32) ([]float32, error) { 121 | if !d.HeadersRead() { 122 | return nil, errors.New("vorbis: missing headers") 123 | } 124 | if len(buffer) < d.BufferSize() { 125 | return nil, errors.New("vorbis: buffer too short") 126 | } 127 | return d.decodePacket(newBitReader(in), buffer) 128 | } 129 | 130 | // Clear must be called between decoding two non-consecutive packets. 131 | func (d *Decoder) Clear() { 132 | d.hasOverlap = false 133 | } 134 | -------------------------------------------------------------------------------- /window.go: -------------------------------------------------------------------------------- 1 | package vorbis 2 | 3 | import "math" 4 | 5 | type windowType struct { 6 | size, prev, next int 7 | } 8 | 9 | func (d *Decoder) applyWindow(t *windowType, samples [][]float32) { 10 | center := t.size / 2 11 | prevOffset := t.size/4 - t.prev/4 12 | nextOffset := t.size/4 - t.next/4 13 | var prevType, nextType int 14 | if t.prev == d.blocksize[1] { 15 | prevType = 1 16 | } 17 | if t.next == d.blocksize[1] { 18 | nextType = 1 19 | } 20 | for ch := range samples { 21 | s := samples[ch][:prevOffset] 22 | for i := range s { 23 | s[i] = 0 24 | } 25 | s = samples[ch][prevOffset : prevOffset+t.prev/2] 26 | w := d.windows[prevType][:len(s)] 27 | for i := range s { 28 | s[i] *= w[i] 29 | } 30 | s = samples[ch][center+nextOffset : center+nextOffset+t.next/2] 31 | w = d.windows[nextType][t.next/2:] 32 | w = w[:len(s)] 33 | for i := range s { 34 | s[i] *= w[i] 35 | } 36 | s = samples[ch][t.size-nextOffset:] 37 | for i := range s { 38 | s[i] = 0 39 | } 40 | } 41 | } 42 | 43 | func makeWindow(size int) []float32 { 44 | window := make([]float32, size) 45 | for i := range window { 46 | window[i] = windowFunc((float32(i) + .5) / float32(size/2) * math.Pi / 2) 47 | } 48 | return window 49 | } 50 | 51 | func windowFunc(x float32) float32 { 52 | sinx := math.Sin(float64(x)) 53 | return float32(math.Sin(math.Pi / 2 * sinx * sinx)) 54 | } 55 | --------------------------------------------------------------------------------