299 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			299 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package kha.audio2.ogg.vorbis.data; | ||
|  | import haxe.ds.Vector; | ||
|  | import haxe.io.Input; | ||
|  | import kha.audio2.ogg.vorbis.VorbisDecodeState; | ||
|  | 
 | ||
|  | /** | ||
|  |  * ... | ||
|  |  * @author shohei909 | ||
|  |  */ | ||
|  | class Residue | ||
|  | { | ||
|  |     public var begin(default, null):UInt; // uint32 | ||
|  |     public var end(default, null):UInt; // uint32 | ||
|  |     public var partSize(default, null):UInt; // uint32 | ||
|  |     public var classifications(default, null):Int; // uint8 | ||
|  |     public var classbook(default, null):Int; // uint8 | ||
|  |     public var classdata(default, null):Vector<Vector<Int>>; //uint8 ** | ||
|  |     public var residueBooks(default, null):Vector<Vector<Int>>; //int16 (*)[8] | ||
|  |     public var type(default, null):Int; | ||
|  | 
 | ||
|  |     public function new() { | ||
|  |     } | ||
|  | 
 | ||
|  |     public static function read(decodeState:VorbisDecodeState, codebooks:Vector<Codebook>):Residue | ||
|  |     { | ||
|  |         var r = new Residue(); | ||
|  |         r.type = decodeState.readBits(16); | ||
|  |         if (r.type > 2) { | ||
|  |             throw new ReaderError(INVALID_SETUP); | ||
|  |         } | ||
|  | 
 | ||
|  |         var residueCascade = new Vector<Int>(64); | ||
|  |         r.begin = decodeState.readBits(24); | ||
|  |         r.end = decodeState.readBits(24); | ||
|  |         r.partSize = decodeState.readBits(24)+1; | ||
|  |         var classifications = r.classifications = decodeState.readBits(6)+1; | ||
|  |         r.classbook = decodeState.readBits(8); | ||
|  | 
 | ||
|  |         for (j in 0...r.classifications) { | ||
|  |             var highBits = 0; | ||
|  |             var lowBits = decodeState.readBits(3); | ||
|  |             if (decodeState.readBits(1) != 0){ | ||
|  |                 highBits = decodeState.readBits(5); | ||
|  |             } | ||
|  |             residueCascade[j] = highBits * 8 + lowBits; | ||
|  |         } | ||
|  | 
 | ||
|  |         r.residueBooks = new Vector(r.classifications); | ||
|  |         for (j in 0...r.classifications) { | ||
|  |             r.residueBooks[j] = new Vector(8); | ||
|  |             for (k in 0...8) { | ||
|  |                 if (residueCascade[j] & (1 << k) != 0) { | ||
|  |                     r.residueBooks[j][k] = decodeState.readBits(8); | ||
|  |                     if (r.residueBooks[j][k] >= codebooks.length) { | ||
|  |                         throw new ReaderError(INVALID_SETUP); | ||
|  |                     } | ||
|  |                 } else { | ||
|  |                     r.residueBooks[j][k] = -1; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // precompute the classifications[] array to avoid inner-loop mod/divide | ||
|  |         // call it 'classdata' since we already have classifications | ||
|  |         var el = codebooks[r.classbook].entries; | ||
|  |         var classwords = codebooks[r.classbook].dimensions; | ||
|  |         r.classdata = new Vector(el); | ||
|  | 
 | ||
|  |         for (j in 0...el) { | ||
|  |             var temp = j; | ||
|  |             var k = classwords; | ||
|  |             var cd = r.classdata[j] = new Vector(classwords); | ||
|  |             while (--k >= 0) { | ||
|  |                 cd[k] = temp % classifications; | ||
|  |                 temp = Std.int(temp / classifications); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return r; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     public function decode(decodeState:VorbisDecodeState, header:Header, residueBuffers:Vector<Vector<Float>>, ch:Int, n:Int,  doNotDecode:Vector<Bool>, channelBuffers:Vector<Vector<Float>>) | ||
|  |     { | ||
|  |         // STB_VORBIS_DIVIDES_IN_RESIDUE = true | ||
|  |         var codebooks = header.codebooks; | ||
|  |         var classwords = codebooks[classbook].dimensions; | ||
|  |         var nRead = end - begin; | ||
|  |         var partSize = this.partSize; | ||
|  |         var partRead = Std.int(nRead / partSize); | ||
|  |         var classifications = new Vector<Int>(header.channel * partRead + 1); // + 1 is a hack for a possible crash in line 268 with some ogg files | ||
|  | 
 | ||
|  |         VorbisTools.stbProf(2); | ||
|  |         for (i in 0...ch) { | ||
|  |             if (!doNotDecode[i]) { | ||
|  |                 var buffer = residueBuffers[i]; | ||
|  |                 for (j in 0...buffer.length) { | ||
|  |                     buffer[j] = 0; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if (type == 2 && ch != 1) { | ||
|  |             for (j in 0...ch) { | ||
|  |                 if (!doNotDecode[j]) { | ||
|  |                     break; | ||
|  |                 } else if (j == ch - 1) { | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             VorbisTools.stbProf(3); | ||
|  |             for (pass in 0...8) { | ||
|  |                 var pcount = 0, classSet = 0; | ||
|  |                 if (ch == 2) { | ||
|  |                     VorbisTools.stbProf(13); | ||
|  |                     while (pcount < partRead) { | ||
|  |                         var z = begin + pcount * partSize; | ||
|  |                         var cInter = (z & 1); | ||
|  |                         var pInter = z >> 1; | ||
|  |                         if (pass == 0) { | ||
|  |                             var c:Codebook = codebooks[classbook]; | ||
|  |                             var q = decodeState.decode(c); | ||
|  |                             if (q == VorbisTools.EOP) { | ||
|  |                                 return; | ||
|  |                             } | ||
|  |                             var i = classwords; | ||
|  |                             while (--i >= 0) { | ||
|  |                                 classifications[i + pcount] = q % this.classifications; | ||
|  |                                 q = Std.int(q / this.classifications); | ||
|  |                             } | ||
|  |                         } | ||
|  |                         VorbisTools.stbProf(5); | ||
|  |                         for (i in 0...classwords) { | ||
|  |                             if (pcount >= partRead) { | ||
|  |                                 break; | ||
|  |                             } | ||
|  |                             var z = begin + pcount*partSize; | ||
|  |                             var c = classifications[pcount]; | ||
|  |                             var b = residueBooks[c][pass]; | ||
|  |                             if (b >= 0) { | ||
|  |                                 var book = codebooks[b]; | ||
|  |                                 VorbisTools.stbProf(20);  // accounts for X time | ||
|  |                                 var result = book.decodeDeinterleaveRepeat(decodeState, residueBuffers, ch, cInter, pInter, n, partSize); | ||
|  |                                 if (result == null) { | ||
|  |                                     return; | ||
|  |                                 } else { | ||
|  |                                     cInter = result.cInter; | ||
|  |                                     pInter = result.pInter; | ||
|  |                                 } | ||
|  |                                 VorbisTools.stbProf(7); | ||
|  |                             } else { | ||
|  |                                 z += partSize; | ||
|  |                                 cInter = z & 1; | ||
|  |                                 pInter = z >> 1; | ||
|  |                             } | ||
|  |                             ++pcount; | ||
|  |                         } | ||
|  |                         VorbisTools.stbProf(8); | ||
|  |                     } | ||
|  |                 } else if (ch == 1) { | ||
|  |                     while (pcount < partRead) { | ||
|  |                         var z = begin + pcount*partSize; | ||
|  |                         var cInter = 0; | ||
|  |                         var pInter = z; | ||
|  |                         if (pass == 0) { | ||
|  |                             var c:Codebook = codebooks[classbook]; | ||
|  |                             var q = decodeState.decode(c); | ||
|  |                             if (q == VorbisTools.EOP) return; | ||
|  | 
 | ||
|  |                             var i = classwords; | ||
|  |                             while (--i >= 0) { | ||
|  |                                 classifications[i + pcount] = q % this.classifications; | ||
|  |                                 q = Std.int(q / this.classifications); | ||
|  |                             } | ||
|  |                         } | ||
|  | 
 | ||
|  |                         for (i in 0...classwords) { | ||
|  |                             if (pcount >= partRead) { | ||
|  |                                 break; | ||
|  |                             } | ||
|  |                             var z = begin + pcount * partSize; | ||
|  |                             var b = residueBooks[classifications[pcount]][pass]; | ||
|  |                             if (b >= 0) { | ||
|  |                                 var book:Codebook = codebooks[b]; | ||
|  |                                 VorbisTools.stbProf(22); | ||
|  |                                 var result = book.decodeDeinterleaveRepeat(decodeState, residueBuffers, ch, cInter, pInter, n, partSize); | ||
|  |                                 if (result == null) { | ||
|  |                                     return; | ||
|  |                                 } else { | ||
|  |                                     cInter = result.cInter; | ||
|  |                                     pInter = result.pInter; | ||
|  |                                 } | ||
|  |                                 VorbisTools.stbProf(3); | ||
|  |                             } else { | ||
|  |                                 z += partSize; | ||
|  |                                 cInter = 0; | ||
|  |                                 pInter = z; | ||
|  |                             } | ||
|  |                             ++pcount; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } else { | ||
|  |                     while (pcount < partRead) { | ||
|  |                         var z = begin + pcount * partSize; | ||
|  |                         var cInter = z % ch; | ||
|  |                         var pInter = Std.int(z / ch); | ||
|  | 
 | ||
|  |                         if (pass == 0) { | ||
|  |                             var c:Codebook = codebooks[classbook]; | ||
|  |                             var q = decodeState.decode(c); | ||
|  |                             if (q == VorbisTools.EOP) { | ||
|  |                                 return; | ||
|  |                             } | ||
|  | 
 | ||
|  |                             var i = classwords; | ||
|  |                             while (--i >= 0) { | ||
|  |                                 classifications[i+pcount] = q % this.classifications; | ||
|  |                                 q = Std.int(q / this.classifications); | ||
|  |                             } | ||
|  |                         } | ||
|  | 
 | ||
|  |                         for (i in 0...classwords) { | ||
|  |                             if (pcount >= partRead) { | ||
|  |                                 break; | ||
|  |                             } | ||
|  |                             var z = begin + pcount * partSize; | ||
|  |                             var b = residueBooks[classifications[pcount]][pass]; | ||
|  |                             if (b >= 0) { | ||
|  |                                 var book = codebooks[b]; | ||
|  |                                 VorbisTools.stbProf(22); | ||
|  |                                 var result = book.decodeDeinterleaveRepeat(decodeState, residueBuffers, ch, cInter, pInter, n, partSize); | ||
|  |                                 if (result == null) { | ||
|  |                                     return; | ||
|  |                                 } else { | ||
|  |                                     cInter = result.cInter; | ||
|  |                                     pInter = result.pInter; | ||
|  |                                 } | ||
|  |                                 VorbisTools.stbProf(3); | ||
|  |                             } else { | ||
|  |                                 z += partSize; | ||
|  |                                 cInter = z % ch; | ||
|  |                                 pInter = Std.int(z / ch); | ||
|  |                             } | ||
|  |                             ++pcount; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             return; | ||
|  |         } | ||
|  |         VorbisTools.stbProf(9); | ||
|  | 
 | ||
|  |         for (pass in 0...8) { | ||
|  |             var pcount = 0; | ||
|  |             var classSet = 0; | ||
|  |             while (pcount < partRead) { | ||
|  |                 if (pass == 0) { | ||
|  |                     for (j in 0...ch) { | ||
|  |                         if (!doNotDecode[j]) { | ||
|  |                             var c:Codebook = codebooks[classbook]; | ||
|  |                             var temp = decodeState.decode(c); | ||
|  |                             if (temp == VorbisTools.EOP) { | ||
|  |                                 return; | ||
|  |                             } | ||
|  |                             var i = classwords; | ||
|  |                             while (--i >= 0) { | ||
|  |                                 classifications[j * partRead + i + pcount] = temp % this.classifications; | ||
|  |                                 temp = Std.int(temp / this.classifications); | ||
|  |                             } | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |                 for (i in 0...classwords) { | ||
|  |                     if (pcount >= partRead) { | ||
|  |                         break; | ||
|  |                     } | ||
|  |                     for (j in 0...ch) { | ||
|  |                         if (!doNotDecode[j]) { | ||
|  |                             var c = classifications[j  * partRead + pcount]; | ||
|  |                             var b = residueBooks[c][pass]; | ||
|  |                             if (b >= 0) { | ||
|  |                                 var target = residueBuffers[j]; | ||
|  |                                 var offset = begin + pcount * partSize; | ||
|  |                                 var n = partSize; | ||
|  |                                 var book = codebooks[b]; | ||
|  |                                 if (!book.residueDecode(decodeState, target, offset, n, type)) { | ||
|  |                                     return; | ||
|  |                                 } | ||
|  |                             } | ||
|  |                         } | ||
|  |                     } | ||
|  |                     ++pcount; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |