595 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			595 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package kha.audio2.ogg.vorbis.data; | ||
|  | import haxe.ds.Vector; | ||
|  | import haxe.io.Bytes; | ||
|  | import haxe.io.Input; | ||
|  | import kha.audio2.ogg.tools.MathTools; | ||
|  | import kha.audio2.ogg.vorbis.data.ReaderError.ReaderErrorType; | ||
|  | import kha.audio2.ogg.vorbis.VorbisDecodeState; | ||
|  | 
 | ||
|  | /** | ||
|  |  * ... | ||
|  |  * @author shohei909 | ||
|  |  */ | ||
|  | class Codebook | ||
|  | { | ||
|  |     static public inline var NO_CODE = 255; | ||
|  | 
 | ||
|  |     public var dimensions:Int; | ||
|  |     public var entries:Int; | ||
|  |     public var codewordLengths:Vector<Int>; //uint8* | ||
|  |     public var minimumValue:Float; | ||
|  |     public var deltaValue:Float; | ||
|  |     public var valueBits:Int; //uint8 | ||
|  |     public var lookupType:Int; //uint8 | ||
|  |     public var sequenceP:Bool; //uint8 | ||
|  |     public var sparse:Bool; //uint8 | ||
|  |     public var lookupValues:UInt; //uint32 | ||
|  |     public var multiplicands:Vector<Float>; // codetype * | ||
|  |     public var codewords:Vector<UInt>; //uint32* | ||
|  |     public var fastHuffman:Vector<Int>; //[FAST_HUFFMAN_TABLE_SIZE]; | ||
|  |     public var sortedCodewords:Array<UInt>; //uint32* | ||
|  |     public var sortedValues:Vector<Int>; | ||
|  |     public var sortedEntries:Int; | ||
|  | 
 | ||
|  |     public function new () { | ||
|  |     } | ||
|  | 
 | ||
|  |     static public function read(decodeState:VorbisDecodeState):Codebook { | ||
|  |         var c = new Codebook(); | ||
|  |         if (decodeState.readBits(8) != 0x42 || decodeState.readBits(8) != 0x43 || decodeState.readBits(8) != 0x56) { | ||
|  |             throw new ReaderError(ReaderErrorType.INVALID_SETUP); | ||
|  |         } | ||
|  | 
 | ||
|  |         var x = decodeState.readBits(8); | ||
|  |         c.dimensions = (decodeState.readBits(8) << 8) + x; | ||
|  | 
 | ||
|  |         var x = decodeState.readBits(8); | ||
|  |         var y = decodeState.readBits(8); | ||
|  |         c.entries = (decodeState.readBits(8) << 16) + (y << 8) + x; | ||
|  |         var ordered = decodeState.readBits(1); | ||
|  |         c.sparse = (ordered != 0) ? false : (decodeState.readBits(1) != 0); | ||
|  | 
 | ||
|  |         var lengths = new Vector(c.entries); | ||
|  |         if (!c.sparse) { | ||
|  |             c.codewordLengths = lengths; | ||
|  |         } | ||
|  | 
 | ||
|  |         var total = 0; | ||
|  | 
 | ||
|  |         if (ordered != 0) { | ||
|  |             var currentEntry = 0; | ||
|  |             var currentLength = decodeState.readBits(5) + 1; | ||
|  | 
 | ||
|  |             while (currentEntry < c.entries) { | ||
|  |                 var limit = c.entries - currentEntry; | ||
|  |                 var n = decodeState.readBits(MathTools.ilog(limit)); | ||
|  |                 if (currentEntry + n > c.entries) { | ||
|  |                     throw new ReaderError(ReaderErrorType.INVALID_SETUP, "codebook entrys"); | ||
|  |                 } | ||
|  |                 for (i in 0...n) { | ||
|  |                     lengths.set(currentEntry + i, currentLength); | ||
|  |                 } | ||
|  |                 currentEntry += n; | ||
|  |                 currentLength++; | ||
|  |             } | ||
|  |         } else { | ||
|  |             for (j in 0...c.entries) { | ||
|  |                 var present = (c.sparse) ? decodeState.readBits(1) : 1; | ||
|  |                 if (present != 0) { | ||
|  |                     lengths.set(j, decodeState.readBits(5) + 1); | ||
|  |                     total++; | ||
|  |                 } else { | ||
|  |                     lengths.set(j, NO_CODE); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if (c.sparse && total >= (c.entries >> 2)) { | ||
|  |             c.codewordLengths = lengths; | ||
|  |             c.sparse = false; | ||
|  |         } | ||
|  | 
 | ||
|  |         c.sortedEntries = if (c.sparse) { | ||
|  |             total; | ||
|  |         } else { | ||
|  |             var sortedCount = 0; | ||
|  |             for (j in 0...c.entries) { | ||
|  |                 var l = lengths.get(j); | ||
|  |                 if (l > Setting.FAST_HUFFMAN_LENGTH && l != NO_CODE) { | ||
|  |                     ++sortedCount; | ||
|  |                 } | ||
|  |             } | ||
|  |             sortedCount; | ||
|  |         } | ||
|  | 
 | ||
|  |         var values:Vector<UInt> = null; | ||
|  | 
 | ||
|  |         if (!c.sparse) { | ||
|  |             c.codewords = new Vector<UInt>(c.entries); | ||
|  |         } else { | ||
|  |             if (c.sortedEntries != 0) { | ||
|  |                 c.codewordLengths = new Vector(c.sortedEntries); | ||
|  |                 c.codewords = new Vector<UInt>(c.entries); | ||
|  |                 values = new Vector<UInt>(c.entries); | ||
|  |             } | ||
|  | 
 | ||
|  |             var size:Int = c.entries + (32 + 32) * c.sortedEntries; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (!c.computeCodewords(lengths, c.entries, values)) { | ||
|  |             throw new ReaderError(ReaderErrorType.INVALID_SETUP, "compute codewords"); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (c.sortedEntries != 0) { | ||
|  |             // allocate an extra slot for sentinels | ||
|  |             c.sortedCodewords = []; | ||
|  | 
 | ||
|  |             // allocate an extra slot at the front so that sortedValues[-1] is defined | ||
|  |             // so that we can catch that case without an extra if | ||
|  |             c.sortedValues = new Vector<Int>(c.sortedEntries); | ||
|  |             c.computeSortedHuffman(lengths, values); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (c.sparse) { | ||
|  |             values = null; | ||
|  |             c.codewords = null; | ||
|  |             lengths = null; | ||
|  |         } | ||
|  | 
 | ||
|  |         c.computeAcceleratedHuffman(); | ||
|  | 
 | ||
|  |         c.lookupType = decodeState.readBits(4); | ||
|  |         if (c.lookupType > 2) { | ||
|  |             throw new ReaderError(ReaderErrorType.INVALID_SETUP, "codebook lookup type"); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (c.lookupType > 0) { | ||
|  |             c.minimumValue = VorbisTools.floatUnpack(decodeState.readBits(32)); | ||
|  |             c.deltaValue = VorbisTools.floatUnpack(decodeState.readBits(32)); | ||
|  |             c.valueBits = decodeState.readBits(4) + 1; | ||
|  |             c.sequenceP = (decodeState.readBits(1) != 0); | ||
|  | 
 | ||
|  |             if (c.lookupType == 1) { | ||
|  |                 c.lookupValues = VorbisTools.lookup1Values(c.entries, c.dimensions); | ||
|  |             } else { | ||
|  |                 c.lookupValues = c.entries * c.dimensions; | ||
|  |             } | ||
|  |             var mults = new Vector<Int>(c.lookupValues); | ||
|  |             for (j in 0...c.lookupValues) { | ||
|  |                 var q = decodeState.readBits(c.valueBits); | ||
|  |                 if (q == VorbisTools.EOP) { | ||
|  |                     throw new ReaderError(ReaderErrorType.INVALID_SETUP, "fail lookup"); | ||
|  |                 } | ||
|  |                 mults[j] = q; | ||
|  |             } | ||
|  | 
 | ||
|  |             { | ||
|  |                 c.multiplicands = new Vector(c.lookupValues); | ||
|  | 
 | ||
|  |                 //STB_VORBIS_CODEBOOK_FLOATS = true | ||
|  |                 for (j in 0...c.lookupValues) { | ||
|  |                     c.multiplicands[j] = mults[j] * c.deltaValue + c.minimumValue; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             //STB_VORBIS_CODEBOOK_FLOATS = true | ||
|  |             if (c.lookupType == 2 && c.sequenceP) { | ||
|  |                 for (j in 1...c.lookupValues) { | ||
|  |                     c.multiplicands[j] = c.multiplicands[j - 1]; | ||
|  |                 } | ||
|  |                 c.sequenceP = false; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return c; | ||
|  |     } | ||
|  | 
 | ||
|  |     inline function addEntry(huffCode:UInt, symbol:Int, count:Int, len:Int, values:Vector<UInt>) | ||
|  |     { | ||
|  |         if (!sparse) { | ||
|  |             codewords[symbol] = huffCode; | ||
|  |         } else { | ||
|  |             codewords[count] = huffCode; | ||
|  |             codewordLengths.set(count, len); | ||
|  |             values[count] = symbol; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     inline function includeInSort(len:Int) | ||
|  |     { | ||
|  |         return if (sparse) { | ||
|  |             VorbisTools.assert(len != NO_CODE); | ||
|  |             true; | ||
|  |         } else if (len == NO_CODE) { | ||
|  |             false; | ||
|  |         } else if (len > Setting.FAST_HUFFMAN_LENGTH) { | ||
|  |             true; | ||
|  |         } else { | ||
|  |             false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function computeCodewords(len:Vector<Int>, n:Int, values:Vector<UInt>) | ||
|  |     { | ||
|  |         var available = new Vector<UInt>(32); | ||
|  |         for (x in 0...32) available[x] = 0; | ||
|  | 
 | ||
|  |         // find the first entry | ||
|  |         var k = 0; | ||
|  |         while (k < n) { | ||
|  |             if (len.get(k) < NO_CODE) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             k++; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (k == n) { | ||
|  |             VorbisTools.assert(sortedEntries == 0); | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         var m = 0; | ||
|  | 
 | ||
|  |         // add to the list | ||
|  |         addEntry(0, k, m++, len.get(k), values); | ||
|  | 
 | ||
|  |         // add all available leaves | ||
|  |         var i = 0; | ||
|  | 
 | ||
|  |         while (++i <= len.get(k)) { | ||
|  |             available[i] = (1:UInt) << ((32 - i):UInt); | ||
|  |         } | ||
|  | 
 | ||
|  |         // note that the above code treats the first case specially, | ||
|  |         // but it's really the same as the following code, so they | ||
|  |         // could probably be combined (except the initial code is 0, | ||
|  |         // and I use 0 in available[] to mean 'empty') | ||
|  |         i = k; | ||
|  |         while (++i < n) { | ||
|  |             var z = len.get(i); | ||
|  |             if (z == NO_CODE) continue; | ||
|  | 
 | ||
|  |             // find lowest available leaf (should always be earliest, | ||
|  |             // which is what the specification calls for) | ||
|  |             // note that this property, and the fact we can never have | ||
|  |             // more than one free leaf at a given level, isn't totally | ||
|  |             // trivial to prove, but it seems true and the assert never | ||
|  |             // fires, so! | ||
|  |             while (z > 0 && available[z] == 0) --z; | ||
|  |             if (z == 0) { | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             var res:UInt = available[z]; | ||
|  |             available[z] = 0; | ||
|  |             addEntry(VorbisTools.bitReverse(res), i, m++, len.get(i), values); | ||
|  | 
 | ||
|  |             // propogate availability up the tree | ||
|  |             if (z != len.get(i)) { | ||
|  |                 var y = len.get(i); | ||
|  |                 while (y > z) { | ||
|  |                     VorbisTools.assert(available[y] == 0); | ||
|  |                     available[y] = res + (1 << (32 - y)); | ||
|  |                     y--; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     function computeSortedHuffman(lengths:Vector<Int>, values:Vector<UInt>) | ||
|  |     { | ||
|  |         // build a list of all the entries | ||
|  |         // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN. | ||
|  |         // this is kind of a frivolous optimization--I don't see any performance improvement, | ||
|  |         // but it's like 4 extra lines of code, so. | ||
|  |         if (!sparse) { | ||
|  |             var k = 0; | ||
|  |             for (i in 0...entries) { | ||
|  |                 if (includeInSort(lengths.get(i))) { | ||
|  |                     sortedCodewords[k++] = VorbisTools.bitReverse(codewords[i]); | ||
|  |                 } | ||
|  |             } | ||
|  |             VorbisTools.assert(k == sortedEntries); | ||
|  |         } else { | ||
|  |             for (i in 0...sortedEntries) { | ||
|  |                 sortedCodewords[i] = VorbisTools.bitReverse(codewords[i]); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         sortedCodewords[sortedEntries] = 0xffffffff; | ||
|  |         sortedCodewords.sort(VorbisTools.uintAsc); | ||
|  | 
 | ||
|  |         var len = sparse ? sortedEntries : entries; | ||
|  |         // now we need to indicate how they correspond; we could either | ||
|  |         //    #1: sort a different data structure that says who they correspond to | ||
|  |         //    #2: for each sorted entry, search the original list to find who corresponds | ||
|  |         //    #3: for each original entry, find the sorted entry | ||
|  |         // #1 requires extra storage, #2 is slow, #3 can use binary search! | ||
|  |         for (i in 0...len) { | ||
|  |             var huffLen = sparse ? lengths.get(values[i]) : lengths.get(i); | ||
|  |             if (includeInSort(huffLen)) { | ||
|  |                 var code = VorbisTools.bitReverse(codewords[i]); | ||
|  |                 var x = 0; | ||
|  |                 var n = sortedEntries; | ||
|  |                 while (n > 1) { | ||
|  |                     // invariant: sc[x] <= code < sc[x+n] | ||
|  |                     var m = x + (n >> 1); | ||
|  |                     if (sortedCodewords[m] <= code) { | ||
|  |                         x = m; | ||
|  |                         n -= (n>>1); | ||
|  |                     } else { | ||
|  |                         n >>= 1; | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 //VorbisTools.assert(sortedCodewords[x] == code); | ||
|  |                 if (sparse) { | ||
|  |                     sortedValues[x] = values[i]; | ||
|  |                     codewordLengths.set(x, huffLen); | ||
|  |                 } else { | ||
|  |                     sortedValues[x] = i; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     function computeAcceleratedHuffman() | ||
|  |     { | ||
|  |         fastHuffman = new Vector(Setting.FAST_HUFFMAN_TABLE_SIZE); | ||
|  |         fastHuffman[0] = -1; | ||
|  |         for (i in 0...(Setting.FAST_HUFFMAN_TABLE_SIZE)) { | ||
|  |             fastHuffman[i] =  -1; | ||
|  |         } | ||
|  | 
 | ||
|  |         var len = (sparse) ? sortedEntries : entries; | ||
|  | 
 | ||
|  |         //STB_VORBIS_FAST_HUFFMAN_SHORT | ||
|  |         //if (len > 32767) len = 32767; // largest possible value we can encode! | ||
|  | 
 | ||
|  |         for (i in 0...len) { | ||
|  |             if (codewordLengths[i] <= Setting.FAST_HUFFMAN_LENGTH) { | ||
|  |                 var z:Int = (sparse) ? VorbisTools.bitReverse(sortedCodewords[i]) : codewords[i]; | ||
|  |                 // set table entries for all bit combinations in the higher bits | ||
|  |                 while (z < Setting.FAST_HUFFMAN_TABLE_SIZE) { | ||
|  |                     fastHuffman[z] = i; | ||
|  |                     z += 1 << codewordLengths[i]; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     function codebookDecode(decodeState:VorbisDecodeState, output:Vector<Float>, offset:Int, len:Int) | ||
|  |     { | ||
|  |         var z = decodeStart(decodeState); | ||
|  |         var lookupValues = this.lookupValues; | ||
|  |         var sequenceP = this.sequenceP; | ||
|  |         var multiplicands = this.multiplicands; | ||
|  |         var minimumValue = this.minimumValue; | ||
|  | 
 | ||
|  |         if (z < 0) { | ||
|  |             return false; | ||
|  |         } | ||
|  |         if (len > dimensions) { | ||
|  |             len = dimensions; | ||
|  |         } | ||
|  | 
 | ||
|  |         // STB_VORBIS_DIVIDES_IN_CODEBOOK = true | ||
|  |         if (lookupType == 1) { | ||
|  |             var div = 1; | ||
|  |             var last = 0.0; | ||
|  |             for (i in 0...len) { | ||
|  |                 var off = Std.int(z / div) % lookupValues; | ||
|  |                 var val = multiplicands[off] + last; | ||
|  |                 output[offset + i] += val; | ||
|  |                 if (sequenceP) { | ||
|  |                     last = val + minimumValue; | ||
|  |                 } | ||
|  |                 div *= lookupValues; | ||
|  |             } | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         z *= dimensions; | ||
|  |         if (sequenceP) { | ||
|  |             var last = 0.0; | ||
|  |             for (i in 0...len) { | ||
|  |                 var val = multiplicands[z + i] + last; | ||
|  |                 output[offset + i] += val; | ||
|  |                 last = val + minimumValue; | ||
|  |             } | ||
|  |         } else { | ||
|  |             var last = 0.0; | ||
|  |             for (i in 0...len) { | ||
|  |                 output[offset + i] += multiplicands[z + i] + last; | ||
|  |             } | ||
|  |         } | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     function codebookDecodeStep(decodeState:VorbisDecodeState, output:Vector<Float>, offset:Int, len:Int, step:Int) | ||
|  |     { | ||
|  |         var z = decodeStart(decodeState); | ||
|  |         var last = 0.0; | ||
|  |         if (z < 0) { | ||
|  |             return false; | ||
|  |         } | ||
|  |         if (len > dimensions) { | ||
|  |             len = dimensions; | ||
|  |         } | ||
|  | 
 | ||
|  |         var lookupValues = this.lookupValues; | ||
|  |         var sequenceP = this.sequenceP; | ||
|  |         var multiplicands = this.multiplicands; | ||
|  | 
 | ||
|  |         // STB_VORBIS_DIVIDES_IN_CODEBOOK = true | ||
|  | 
 | ||
|  |         if (lookupType == 1) { | ||
|  |             var div = 1; | ||
|  |             for (i in 0...len) { | ||
|  |                 var off = Std.int(z / div) % lookupValues; | ||
|  |                 var val = multiplicands[off] + last; | ||
|  |                 output[offset + i * step] += val; | ||
|  |                 if (sequenceP) { | ||
|  |                     last = val; | ||
|  |                 } | ||
|  |                 div *= lookupValues; | ||
|  |             } | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         z *= dimensions; | ||
|  |         for (i in 0...len) { | ||
|  |             var val = multiplicands[z + i] + last; | ||
|  |             output[offset + i * step] += val; | ||
|  |             if (sequenceP) { | ||
|  |                 last = val; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     inline function decodeStart(decodeState:VorbisDecodeState) | ||
|  |     { | ||
|  |         return decodeState.decode(this); | ||
|  | 
 | ||
|  |         //var z = -1; | ||
|  |         //// type 0 is only legal in a scalar context | ||
|  |         //if (lookupType == 0) { | ||
|  |         //    throw new ReaderError(INVALID_STREAM); | ||
|  |         //} else { | ||
|  |         //    z = decodeState.decode(this); | ||
|  |         //    //if (sparse) VorbisTools.assert(z < sortedEntries); | ||
|  |         //    if (z < 0) {  // check for VorbisTools.EOP | ||
|  |         //        if (decodeState.isLastByte()) { | ||
|  |         //            return z; | ||
|  |         //        } else { | ||
|  |         //            throw new ReaderError(INVALID_STREAM); | ||
|  |         //        } | ||
|  |         //    } else { | ||
|  |         //        return z; | ||
|  |         //    } | ||
|  |         //} | ||
|  |     } | ||
|  | 
 | ||
|  |     static var delay = 0; | ||
|  | 
 | ||
|  |     public function decodeDeinterleaveRepeat(decodeState:VorbisDecodeState, residueBuffers:Vector<Vector<Float>>, ch:Int, cInter:Int, pInter:Int, len:Int, totalDecode:Int) | ||
|  |     { | ||
|  |         var effective = dimensions; | ||
|  | 
 | ||
|  |         // type 0 is only legal in a scalar context | ||
|  |         if (lookupType == 0) { | ||
|  |             throw new ReaderError(INVALID_STREAM); | ||
|  |         } | ||
|  | 
 | ||
|  |         var multiplicands = this.multiplicands; | ||
|  |         var sequenceP = this.sequenceP; | ||
|  |         var lookupValues = this.lookupValues; | ||
|  | 
 | ||
|  |         while (totalDecode > 0) { | ||
|  |             var last = 0.0; | ||
|  |             var z = decodeState.decode(this); | ||
|  | 
 | ||
|  |             if (z < 0) { | ||
|  |                 if (decodeState.isLastByte()) { | ||
|  |                     return null; | ||
|  |                 } | ||
|  |                 throw new ReaderError(INVALID_STREAM); | ||
|  |             } | ||
|  | 
 | ||
|  |             // if this will take us off the end of the buffers, stop short! | ||
|  |             // we check by computing the length of the virtual interleaved | ||
|  |             // buffer (len*ch), our current offset within it (pInter*ch)+(cInter), | ||
|  |             // and the length we'll be using (effective) | ||
|  |             if (cInter + pInter * ch + effective > len * ch) { | ||
|  |                 effective = len * ch - (pInter * ch - cInter); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (lookupType == 1) { | ||
|  |                 var div = 1; | ||
|  |                 if (sequenceP) { | ||
|  |                     for (i in 0...effective) { | ||
|  |                         var off = Std.int(z / div) % lookupValues; | ||
|  |                         var val = multiplicands[off] + last; | ||
|  |                         residueBuffers[cInter][pInter] += val; | ||
|  |                         if (++cInter == ch) { | ||
|  |                             cInter = 0; | ||
|  |                             ++pInter; | ||
|  |                         } | ||
|  |                         last = val; | ||
|  |                         div *= lookupValues; | ||
|  |                     } | ||
|  |                 } else { | ||
|  |                     for (i in 0...effective) { | ||
|  |                         var off = Std.int(z / div) % lookupValues; | ||
|  |                         var val = multiplicands[off] + last; | ||
|  |                         residueBuffers[cInter][pInter] += val; | ||
|  |                         if (++cInter == ch) { | ||
|  |                             cInter = 0; | ||
|  |                             ++pInter; | ||
|  |                         } | ||
|  |                         div *= lookupValues; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } else { | ||
|  |                 z *= dimensions; | ||
|  |                 if (sequenceP) { | ||
|  |                     for (i in 0...effective) { | ||
|  |                         var val = multiplicands[z + i] + last; | ||
|  |                         residueBuffers[cInter][pInter] += val; | ||
|  |                         if (++cInter == ch) { | ||
|  |                             cInter = 0; | ||
|  |                             ++pInter; | ||
|  |                         } | ||
|  |                         last = val; | ||
|  |                     } | ||
|  |                 } else { | ||
|  |                     for (i in 0...effective) { | ||
|  |                         var val = multiplicands[z + i] + last; | ||
|  |                         residueBuffers[cInter][pInter] += val; | ||
|  |                         if (++cInter == ch) { | ||
|  |                             cInter = 0; | ||
|  |                             ++pInter; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             totalDecode -= effective; | ||
|  |         } | ||
|  | 
 | ||
|  |         return { | ||
|  |             cInter : cInter, | ||
|  |             pInter : pInter | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     public function residueDecode(decodeState:VorbisDecodeState, target:Vector<Float>, offset:Int, n:Int, rtype:Int) | ||
|  |     { | ||
|  |         if (rtype == 0) { | ||
|  |             var step = Std.int(n / dimensions); | ||
|  |             for (k in 0...step) { | ||
|  |                 if (!codebookDecodeStep(decodeState, target, offset + k, n-offset-k, step)) { | ||
|  |                     return false; | ||
|  |                 } | ||
|  |             } | ||
|  |         } else { | ||
|  |             var k = 0; | ||
|  |             while(k < n) { | ||
|  |                 if (!codebookDecode(decodeState, target, offset, n-k)) { | ||
|  |                     return false; | ||
|  |                 } | ||
|  |                 k += dimensions; | ||
|  |                 offset += dimensions; | ||
|  |             } | ||
|  |         } | ||
|  |         return true; | ||
|  |     } | ||
|  | } |