214 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			214 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package kha.audio2.ogg.vorbis.data; | ||
|  | import haxe.ds.Vector; | ||
|  | import haxe.io.BytesInput; | ||
|  | import haxe.io.BytesOutput; | ||
|  | import haxe.io.Input; | ||
|  | import haxe.io.Output; | ||
|  | import kha.audio2.ogg.vorbis.data.Comment; | ||
|  | import kha.audio2.ogg.vorbis.data.Page.PageFlag; | ||
|  | import kha.audio2.ogg.vorbis.data.ReaderError.ReaderErrorType; | ||
|  | import kha.audio2.ogg.vorbis.VorbisDecodeState; | ||
|  | 
 | ||
|  | /** | ||
|  |  * ... | ||
|  |  * @author shohei909 | ||
|  |  */ | ||
|  | class Header { | ||
|  | 
 | ||
|  |     static public inline var PACKET_ID = 1; | ||
|  |     static public inline var PACKET_COMMENT = 3; | ||
|  |     static public inline var PACKET_SETUP = 5; | ||
|  | 
 | ||
|  |     public var maximumBitRate(default, null):UInt; | ||
|  |     public var nominalBitRate(default, null):UInt; | ||
|  |     public var minimumBitRate(default, null):UInt; | ||
|  |     public var sampleRate(default, null):UInt; | ||
|  |     public var channel(default, null):Int; | ||
|  |     public var blocksize0(default, null):Int; | ||
|  |     public var blocksize1(default, null):Int; | ||
|  |     public var codebooks(default, null):Vector<Codebook>; | ||
|  |     public var floorConfig(default, null):Vector<Floor>; | ||
|  |     public var residueConfig(default, null):Vector<Residue>; | ||
|  |     public var mapping(default, null):Vector<Mapping>; | ||
|  |     public var modes(default, null):Vector<Mode>; // [64] varies | ||
|  |     public var comment(default, null):Comment; | ||
|  |     public var vendor(default, null):String; | ||
|  | 
 | ||
|  |     function new() { | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     static public function read(decodeState:VorbisDecodeState):Header { | ||
|  |         var page = decodeState.page; | ||
|  |         page.start(decodeState); | ||
|  | 
 | ||
|  |         if ((page.flag & PageFlag.FIRST_PAGE) == 0) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE, "not firstPage"); | ||
|  |         } | ||
|  |         if ((page.flag & PageFlag.LAST_PAGE) != 0) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE, "lastPage"); | ||
|  |         } | ||
|  |         if ((page.flag & PageFlag.CONTINUED_PACKET) != 0) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE, "continuedPacket"); | ||
|  |         } | ||
|  | 
 | ||
|  |         decodeState.firstPageValidate(); | ||
|  |         if (decodeState.readByte() != PACKET_ID) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE, "decodeState head"); | ||
|  |         } | ||
|  | 
 | ||
|  |         // vorbis header | ||
|  |         decodeState.vorbisValidate(); | ||
|  | 
 | ||
|  |         // vorbisVersion | ||
|  |         var version = decodeState.readInt32(); | ||
|  |         if (version != 0) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE, "vorbis version : " + version); | ||
|  |         } | ||
|  | 
 | ||
|  |         var header = new Header(); | ||
|  | 
 | ||
|  |         header.channel = decodeState.readByte(); | ||
|  |         if (header.channel == 0) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE, "no channel"); | ||
|  |         } else if (header.channel > Setting.MAX_CHANNELS) { | ||
|  |             throw new ReaderError(TOO_MANY_CHANNELS, "too many channels"); | ||
|  |         } | ||
|  | 
 | ||
|  |         header.sampleRate = decodeState.readInt32(); | ||
|  |         if (header.sampleRate == 0) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE, "no sampling rate"); | ||
|  |         } | ||
|  | 
 | ||
|  |         header.maximumBitRate = decodeState.readInt32(); | ||
|  |         header.nominalBitRate = decodeState.readInt32(); | ||
|  |         header.minimumBitRate = decodeState.readInt32(); | ||
|  | 
 | ||
|  |         var x = decodeState.readByte(); | ||
|  |         var log0 = x & 15; | ||
|  |         var log1 = x >> 4; | ||
|  |         header.blocksize0 = 1 << log0; | ||
|  |         header.blocksize1 = 1 << log1; | ||
|  |         if (log0 < 6 || log0 > 13) { | ||
|  |             throw new ReaderError(INVALID_SETUP); | ||
|  |         } | ||
|  |         if (log1 < 6 || log1 > 13) { | ||
|  |             throw new ReaderError(INVALID_SETUP); | ||
|  |         } | ||
|  |         if (log0 > log1) { | ||
|  |             throw new ReaderError(INVALID_SETUP); | ||
|  |         } | ||
|  | 
 | ||
|  |         // framingFlag | ||
|  |         var x = decodeState.readByte(); | ||
|  |         if (x & 1 == 0) { | ||
|  |             throw new ReaderError(INVALID_FIRST_PAGE); | ||
|  |         } | ||
|  | 
 | ||
|  |         // comment fields | ||
|  |         decodeState.page.start(decodeState); | ||
|  |         decodeState.startPacket(); | ||
|  | 
 | ||
|  |         var len = 0; | ||
|  |         var output = new BytesOutput(); | ||
|  |         while((len = decodeState.next()) != 0) { | ||
|  |             output.write(decodeState.readBytes(len)); | ||
|  |             decodeState.bytesInSeg = 0; | ||
|  |         } | ||
|  | 
 | ||
|  |         { | ||
|  |             var packetInput = new BytesInput(output.getBytes()); | ||
|  |             packetInput.readByte(); | ||
|  |             packetInput.read(6); | ||
|  | 
 | ||
|  |             var vendorLength:UInt = packetInput.readInt32(); | ||
|  |             header.vendor = packetInput.readString(vendorLength); | ||
|  |             header.comment = new Comment(); | ||
|  | 
 | ||
|  |             var commentCount = packetInput.readInt32(); | ||
|  | 
 | ||
|  |             for (i in 0...commentCount) { | ||
|  |                 var n = packetInput.readInt32(); | ||
|  |                 var str = packetInput.readString(n); | ||
|  |                 var splitter = str.indexOf("="); | ||
|  |                 if (splitter != -1) { | ||
|  |                     header.comment.add(str.substring(0, splitter), str.substring(splitter + 1)); | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             var x = packetInput.readByte(); | ||
|  |             if (x & 1 == 0) { | ||
|  |                 throw new ReaderError(ReaderErrorType.INVALID_SETUP); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // third packet! | ||
|  |         decodeState.startPacket(); | ||
|  | 
 | ||
|  |         if (decodeState.readPacket() != PACKET_SETUP) { | ||
|  |             throw new ReaderError(ReaderErrorType.INVALID_SETUP, "setup packet"); | ||
|  |         } | ||
|  | 
 | ||
|  |         decodeState.vorbisValidate(); | ||
|  | 
 | ||
|  |         // codebooks | ||
|  |         var codebookCount = decodeState.readBits(8) + 1; | ||
|  |         header.codebooks = new Vector(codebookCount); | ||
|  |         for (i in 0...codebookCount) { | ||
|  |             header.codebooks[i] = Codebook.read(decodeState); | ||
|  |         } | ||
|  | 
 | ||
|  |         // time domain transfers (notused) | ||
|  |         x = decodeState.readBits(6) + 1; | ||
|  |         for (i in 0...x) { | ||
|  |             if (decodeState.readBits(16) != 0) { | ||
|  |                 throw new ReaderError(INVALID_SETUP); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // Floors | ||
|  |         var floorCount = decodeState.readBits(6) + 1; | ||
|  |         header.floorConfig = new Vector(floorCount); | ||
|  |         for (i in 0...floorCount) { | ||
|  |             header.floorConfig[i] = Floor.read(decodeState, header.codebooks); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Residue | ||
|  |         var residueCount = decodeState.readBits(6) + 1; | ||
|  |         header.residueConfig = new Vector(residueCount); | ||
|  |         for (i in 0...residueCount) { | ||
|  |             header.residueConfig[i] = Residue.read(decodeState, header.codebooks); | ||
|  |         } | ||
|  | 
 | ||
|  |         //Mapping | ||
|  |         var mappingCount = decodeState.readBits(6) + 1; | ||
|  |         header.mapping = new Vector(mappingCount); | ||
|  |         for (i in 0...mappingCount) { | ||
|  |             var map = Mapping.read(decodeState, header.channel); | ||
|  |             header.mapping[i] = map; | ||
|  |             for (j in 0...map.submaps) { | ||
|  |                 if (map.submapFloor[j] >= header.floorConfig.length) { | ||
|  |                     throw new ReaderError(INVALID_SETUP); | ||
|  |                 } | ||
|  |                 if (map.submapResidue[j] >= header.residueConfig.length) { | ||
|  |                     throw new ReaderError(INVALID_SETUP); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         var modeCount = decodeState.readBits(6) + 1; | ||
|  |         header.modes = new Vector(modeCount); | ||
|  |         for (i in 0...modeCount) { | ||
|  |             var mode = Mode.read(decodeState); | ||
|  |             header.modes[i] = mode; | ||
|  |             if (mode.mapping >= header.mapping.length) { | ||
|  |                 throw new ReaderError(INVALID_SETUP); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         decodeState.flushPacket(); | ||
|  | 
 | ||
|  |         return header; | ||
|  |     } | ||
|  | } |