12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587 |
- (** AUTHOR "Christian Wassmer, chwassme@student.ethz.ch";
- PURPOSE "an audio-player for Ogg/Vorbis-radiostations and -files";
- DATE "Avril 2004" *)
- MODULE OGGVorbisPlayer;
- IMPORT
- SYSTEM, Strings, KernelLog, Streams, Files, Commands, SoundDevices, BIT, Math,
- OGGUtilities, Modules, Kernel,
- TCP, WebHTTP, WebHTTPClient;
- CONST
- (* Debugging Set *)
- Trace = 1;
- Error = 2;
- Codec = 3;
- Debug = {Error};
- (* oggstream-types, are also recognition-pattern for calling the correct decoder *)
- Vorbis = "vorbis";
- CodebookSynchPattern = 564342H;
- (* return codes *)
- Ok = 0;
- ErrorIdentification = 1;
- ErrorSetup = 2;
- ErrorDataPacket = 3;
- PacketTooBig = 4;
- InvalidSerialNumber = 5;
- UnexpectedEOS = 6;
- OggStreamNotFound = 7;
- NoDecoderFound = 8;
- LogicalOggStreamFinished = 8;
- ErrorCapturePattern = 9;
- TooManyLogicalOggStreams = 10;
- NoDataPacket = 11;
- InvalidCodebookNumber = 12;
- ChannelNotUsed = 13;
- PacketUndecodable = 14;
- ErrorWindowDecode = 15;
- (* maximum ogg-page-size, as defined in the specs *)
- MaxPageSize = 65307;
- (* length of all header field of an Ogg-page *)
- BaseHeaderLength = 27;
- (* 'vorbis' as example, others seems to be also of the same length*)
- OggStreamTypeLength = 6;
- (* constants for sound output *)
- MaxChannels* = 6;
- DefaultSamplingResolution = 16;
- (* data structure constants *)
- MaxNrOfSegments = 255;
- MaxLogicalStreams = 8;
- MaxVendorLength = 64;
- MaxCommentLength = 256;
- MaxNumberOfCodebooks = 256;
- MaxNumberOfMultiplicands = 65536;
- MaxNumberOfFloors = 64;
- MaxNumberOfResidues = 64;
- MaxNumberOfMappings = 64;
- MaxNumberOfModes = 64;
- Floor0BookListSize = 16;
- Floor1PartitionClassListSize = 32;
- Floor1ClassSize = 16;
- Floor1SubclassSize = 16;
- Floor1XListSize = 256; (* >= 32 * 7 + 7 *)
- ResidueCascadeSize = 64;
- ResidueBookSize = 64;
- MappingMagnitudeSize = 256;
- MappingMuxSize = 256;
- MappingSubmapFloorSize = 16;
- (* floor1Y: 0..288 = 32 * (3 bit "+ 1") *)
- Floor1Final = 288;
- (* used for partword01, partword2 and decodemap (residues) *)
- PartwordSize = 8;
- NrOfBlocksizes = 8;
- InverseDBLookupSize = 256;
- (* some marker constants *)
- ResidueBookUnused = -1;
- UnusedCodebookEntry = -2;
- (* returned by AbstractFloorType::DecodePacket() if the floor is unused *)
- SerialNumberUnset = -4;
- VAR
- frameCnt: LONGINT;
- OggS: ARRAY 4 OF CHAR;
- nrOfPages: LONGINT;
- FloorRanges: ARRAY 4 OF LONGINT;
- InverseDBLookup: ARRAY InverseDBLookupSize OF LONGINT;
- (** state of the player *);
- stopped*, playing*: BOOLEAN;
- TYPE
- BitReader = OBJECT
- VAR
- r: Streams.Reader;
- bsBuff, bsLive: LONGINT;
- bytesRead: LONGINT;
- PROCEDURE &Init*(r: Streams.Reader);
- BEGIN
- SELF.r := r;
- bsLive := 0
- END Init;
- (* is stream still available *)
- PROCEDURE IsOk() : BOOLEAN;
- BEGIN
- RETURN r.res = Streams.Ok
- END IsOk;
- (* get the number of bytes read *)
- PROCEDURE GetBytesRead(): LONGINT;
- BEGIN
- RETURN SELF.bytesRead
- END GetBytesRead;
- (* read a number of bits (lsb first) from the reader (max: 32)
- note: if n is 32 (bigger is not allowed) then the last bit will be interpreted as the sign
- and may give wrong results, otherwise the sign-bit of the returned longint will not be affected anyway *)
- PROCEDURE GetBits(n: LONGINT): LONGINT;
- VAR r, factor: LONGINT;
- BEGIN
- r := 0; factor := 1;
- WHILE (n > 0) DO
- r := r + factor * GetBit();
- factor := factor * 2;
- DEC(n)
- END;
- RETURN r
- END GetBits;
- (* get the next bit from the stream (lsb first) *)
- PROCEDURE GetBit(): LONGINT;
- VAR res: LONGINT;
- BEGIN
- IF (bsLive = 0) THEN
- bsBuff := ORD(r.Get());
- IF (r.res = Streams.Ok) THEN bsLive := 8
- ELSE StreamEOF()
- END;
- INC(bytesRead)
- END;
- DEC(bsLive);
- res := bsBuff MOD 2;
- bsBuff := bsBuff DIV 2;
- RETURN res;
- END GetBit;
- (* get a hugeint *)
- PROCEDURE GetHugeInt(): HUGEINT;
- VAR
- huge: HUGEINT;
- BEGIN
- huge := GetBits(16);
- huge := huge + 10000H * GetBits(16);
- huge := huge + 10000H * GetBits(16);
- huge := huge + 10000H * GetBits(16);
- RETURN huge
- END GetHugeInt;
- (* get a char *)
- PROCEDURE GetChar(): CHAR;
- BEGIN
- RETURN CHR(GetBits(8))
- END GetChar;
- PROCEDURE StreamEOF;
- BEGIN
- KernelLog.String("unexpected end of stream"); KernelLog.Ln;
- RETURN
- END StreamEOF;
- END BitReader;
- (* read from a buffer, returning various sized integers *)
- BufferReader = OBJECT
- VAR
- bsBuff, bsLive, pos, len: LONGINT;
- PROCEDURE &Init*;
- BEGIN
- bsLive := 0; pos := 0; len := 0
- END Init;
- (* print the state of it *)
- PROCEDURE Print;
- BEGIN
- OGGUtilities.String("*** state of BufferReader ***");
- OGGUtilities.Var("bsLive", bsLive);
- OGGUtilities.Var("len", len);
- OGGUtilities.Var("pos", pos);
- OGGUtilities.String("*** --- ***")
- END Print;
- PROCEDURE SetLen(len: LONGINT);
- BEGIN
- SELF.len := len
- END SetLen;
- PROCEDURE GetLen(): LONGINT;
- BEGIN
- RETURN SELF.len
- END GetLen;
- (* is buffer still available *)
- PROCEDURE IsOk(VAR buf: ARRAY OF CHAR) : BOOLEAN;
- BEGIN
- RETURN ((LEN(buf) # pos) & (len # pos));
- END IsOk;
- (* get the current position in the buffer *)
- PROCEDURE GetPos(): LONGINT;
- BEGIN
- RETURN pos
- END GetPos;
- PROCEDURE GetBitCount(): LONGINT;
- BEGIN
- RETURN (pos - 1) * 8 + (8 - bsLive)
- END GetBitCount;
- (* get the current byte from the buffer as a longint *)
- PROCEDURE GetCurByte(VAR buf: ARRAY OF CHAR): LONGINT;
- BEGIN
- RETURN ORD(buf[pos])
- END GetCurByte;
- (* get the next bit from the buffer (lsb first) *)
- PROCEDURE GetBit(VAR buf: ARRAY OF CHAR): LONGINT;
- VAR res: LONGINT;
- BEGIN
- IF ((LEN(buf) # pos) & (len # pos) & (bsLive = 0)) THEN
- bsBuff := ORD(buf[pos]);
- bsLive := 8;
- INC(pos)
- END;
- DEC(bsLive);
- res := bsBuff MOD 2;
- bsBuff := bsBuff DIV 2;
- RETURN res
- END GetBit;
- (* read a number of bits (lsb first) from the buffer (max: 32)
- note: if n is 32 (bigger is not allowed) then the last bit will be interpreted as the sign (by the processor)
- and may give wrong results, otherwise the sign-bit of the returned longint will not be affected anyway *)
- PROCEDURE GetBits(VAR buf: ARRAY OF CHAR; n: LONGINT): LONGINT;
- VAR r, factor: LONGINT;
- BEGIN
- r := 0;
- factor := 1;
- WHILE (n > 0) DO
- r := r + factor * GetBit(buf);
- factor := factor * 2;
- DEC(n)
- END;
- RETURN r
- END GetBits;
- (* get a hugeint *)
- PROCEDURE GetHugeInt(VAR buf: ARRAY OF CHAR): HUGEINT;
- VAR
- huge: HUGEINT;
- BEGIN
- huge := GetBits(buf, 16);
- huge := huge + 10000H * GetBits(buf, 16);
- huge := huge + 10000H * GetBits(buf, 16);
- huge := huge + 10000H * GetBits(buf, 16);
- RETURN huge
- END GetHugeInt;
- (* get a 32 bit unsigned integer *)
- PROCEDURE Get32UnsignedBits (VAR buf: ARRAY OF CHAR): HUGEINT;
- VAR
- res: HUGEINT;
- tmp: LONGINT;
- BEGIN
- tmp := 1;
- res := GetBits(buf, 31) + GetBit(buf) * LSH(tmp, 31);
- RETURN res;
- END Get32UnsignedBits;
- (* get the next char *)
- PROCEDURE GetChar (VAR buf: ARRAY OF CHAR): CHAR;
- BEGIN
- RETURN CHR(GetBits(buf, 8))
- END GetChar;
- END BufferReader;
- OggPageHeader = RECORD
- headerTypeFlag, pageSegments,pageSize,headerLength, streamSerialNo: LONGINT;
- pageNo, checksum, absGranulePos: HUGEINT;
- segTable: ARRAY MaxNrOfSegments OF LONGINT
- END;
- OggPage = RECORD
- buf: ARRAY MaxPageSize OF CHAR;
- header: OggPageHeader
- END;
- (* not really a stream, more a structure to keep stream-serialnumber, decoder and it's type together *)
- LogicalOggStream = OBJECT
- VAR
- serialNumber*: LONGINT;
- decoder*: Decoder;
- soundOutput: SoundOutput;
- type*: ARRAY OggStreamTypeLength OF CHAR;
- finished*: BOOLEAN;
- (* init a new LogicalOggStream, type must have a length of 6 *)
- PROCEDURE &Init*(dec: Decoder; soundOutput: SoundOutput; type: ARRAY OF CHAR);
- VAR i: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ LogicalOggStream::Init()")
- END;
- serialNumber := SerialNumberUnset;
- SELF.decoder := dec;
- SELF.soundOutput := soundOutput;
- IF (LEN(type)- 1 # OggStreamTypeLength) THEN
- KernelLog.String("ASSERTION failed - type-string isn't 0X terminated"); KernelLog.Ln
- END;
- ASSERT(LEN(type) - 1= OggStreamTypeLength); (* -1: string is 0X terminated *)
- FOR i:=0 TO OggStreamTypeLength-1 DO SELF.type[i] := type[i] END;
- finished := FALSE
- END Init;
- END LogicalOggStream;
- OggStreamReader* = OBJECT
- VAR
- bitReader: BitReader;
- page: OggPage;
- streams: ARRAY MaxLogicalStreams OF LogicalOggStream;
- nrOfStreams*: LONGINT;
- (* init the OggStreamReader *)
- PROCEDURE &Init*(reader: Streams.Reader);
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ Init()");
- END;
- NEW(SELF.bitReader, reader);
- nrOfStreams := 0;
- stopped := FALSE;
- playing := FALSE;
- END Init;
- (** register an ogg-stream decoder of a given oggstream-type, type must have a length of 6*)
- PROCEDURE RegisterDecoder*(dec: Decoder; soundOutput: SoundOutput; type: ARRAY OF CHAR): LONGINT;
- VAR
- logOggStream: LogicalOggStream;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ RegisterDecoder()");
- END;
- IF nrOfStreams < MaxLogicalStreams THEN
- NEW(logOggStream, dec, soundOutput, type);
- streams[nrOfStreams] := logOggStream;
- INC(nrOfStreams);
- RETURN Ok
- ELSE
- IF (Error IN Debug) THEN
- OGGUtilities.Var("no more logical streams allowed, maximum", MaxLogicalStreams);
- END;
- RETURN TooManyLogicalOggStreams
- END
- END RegisterDecoder;
- (** unregister an logical ogg-stream , usually used when it's finished *)
- PROCEDURE UnregisterLogicalOggStream*(stream: LogicalOggStream);
- VAR
- i: LONGINT;
- found: BOOLEAN;
- BEGIN
- i := 0; found := FALSE;
- WHILE ((i # nrOfStreams) & (~found)) DO
- IF streams[i] = stream THEN
- found := TRUE;
- streams[i] := NIL
- ELSE
- INC(i)
- END;
- END;
- (* shift the remaining streams into the generated gap *)
- IF found THEN
- DEC(nrOfStreams);
- WHILE (i # nrOfStreams) DO
- streams[i] := streams[i+1]; INC(i)
- END
- END
- END UnregisterLogicalOggStream;
- (* dispatches a whole ogg-page to the correspondant Decoder by calling DecodePage() *)
- PROCEDURE Dispatch(VAR oggStream: LogicalOggStream);
- VAR
- type: ARRAY OggStreamTypeLength OF CHAR;
- firstPage: BOOLEAN;
- pos, i: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ Dispatch()")
- END;
- firstPage := (((page.header.headerTypeFlag DIV 2) MOD 2) = 1);
- (* determine packet type and get correct LogicalOggStream *)
- pos := page.header.headerLength + 1; (* set current position to start packet identification string *)
- IF firstPage THEN
- i := 0;
- pos := 1(* page.header.headerLength + 1 *); (* set current position to start packet identification string *)
- WHILE (i # OggStreamTypeLength) DO (* get type-string *)
- type[i] := page.buf[pos + i];
- INC(i)
- END;
- oggStream := GetLogicalOggStreamByType(type); (* find it's LogicalOggStream *)
- (* and update it's serial-number *)
- IF oggStream # NIL THEN oggStream.serialNumber := page.header.streamSerialNo END
- ELSE oggStream := GetLogicalOggStreamBySerialNr(page.header.streamSerialNo)
- END;
- END Dispatch;
- PROCEDURE DecodePage(VAR oggStream: LogicalOggStream): LONGINT;
- VAR
- res, seg, pos, len, i: LONGINT;
- decodingSuccess: BOOLEAN;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ DecodePage()");
- END;
- decodingSuccess := TRUE;
- len := 0; i := 0; pos := 1 + OggStreamTypeLength;
- (* while there are more lacing-values *)
- WHILE (i # page.header.pageSegments) DO
- seg := page.header.segTable[i];
- INC(len,seg);
- (* new packets are indicated by a number unequal to 255 *)
- IF (seg # 255) THEN
- res := oggStream.decoder(page.buf, pos, len, FALSE, oggStream.soundOutput);
- INC(pos,len);
- len := 0
- END;
- IF res # Ok THEN RETURN res END;
- INC(i)
- END;
- IF (seg = 255) THEN
- res := oggStream.decoder(page.buf, pos, len, TRUE, oggStream.soundOutput)
- END;
- RETURN res
- END DecodePage;
- (* get a LogicalOggStream by serial-number *)
- PROCEDURE GetLogicalOggStreamBySerialNr(serialNr: LONGINT): LogicalOggStream;
- VAR
- i: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ GetLogicalOggStreamBySerialNr()")
- END;
- i := 0;
- WHILE (i # nrOfStreams) DO
- IF streams[i].serialNumber = serialNr THEN RETURN streams[i] END;
- INC(i);
- END;
- IF (Error IN Debug) THEN
- OGGUtilities.String("no oggStream (by serialnr) found !!!")
- END;
- RETURN NIL
- END GetLogicalOggStreamBySerialNr;
- (* get a LogicalOggStream by type-string *)
- PROCEDURE GetLogicalOggStreamByType(type: ARRAY OF CHAR): LogicalOggStream;
- VAR
- i, j: LONGINT;
- oggStream: LogicalOggStream;
- found: BOOLEAN;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ GetLogicalOggStreamBySerialType()")
- END;
- found := FALSE; i := 0;
- WHILE (~found) & (i # nrOfStreams) DO
- oggStream := streams[i]; j := 0;
- WHILE (j # OggStreamTypeLength) & (oggStream.type[j] = type[j]) DO INC(j) END;
- found := (j = OggStreamTypeLength);
- INC(i)
- END;
- IF ~found THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("no oggStream (by type) found !!!")
- END;
- RETURN NIL
- ELSE
- RETURN oggStream
- END
- END GetLogicalOggStreamByType;
- PROCEDURE Stop*;
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO LEN(streams) - 1 DO
- IF streams[i] # NIL THEN
- streams[i].soundOutput.CloseSoundChannel()
- END
- END
- END Stop;
- (** start playing an ogg-stream *)
- PROCEDURE Start*(): LONGINT;
- VAR
- retCode: LONGINT;
- lastPage: BOOLEAN;
- oggStream: LogicalOggStream;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ Start()");
- END;
- (* start a loop for all logical ogg-stream header packets *)
- LOOP
- (* if playback is stopped from outside ... *)
- IF stopped THEN
- KernelLog.String("playback stopped"); KernelLog.Ln;
- stopped := FALSE;
- playing := FALSE;
- RETURN retCode;
- END;
- retCode := NextPage(); (* (try to) read the next ogg-page *)
- IF retCode = Ok THEN
- (* get the right LogicalOggStream *)
- Dispatch(oggStream);
- (* if a LogicalOggStream found, call it's Decode()-procedure *)
- IF (oggStream # NIL) & (~oggStream.finished) THEN
- lastPage := (((page.header.headerTypeFlag DIV 4) MOD 2) = 1);
- IF lastPage THEN oggStream.finished := TRUE END;
- (* try to decode it *)
- retCode := DecodePage(oggStream);
- (* if it is finished then unregister it *)
- IF oggStream.finished THEN
- UnregisterLogicalOggStream(oggStream);
- oggStream.soundOutput.CloseSoundChannel();
- retCode := LogicalOggStreamFinished
- ELSE
- retCode := Ok
- END
- ELSIF oggStream = NIL THEN retCode := NoDecoderFound
- END;
- IF retCode # Ok THEN
- (* if no logical ogg-stream is left, the physical ogg-stream is finished correctly *)
- IF nrOfStreams = 0 THEN RETURN Ok ELSE RETURN retCode END
- END
- ELSE
- RETURN retCode
- END;
- IF ~bitReader.IsOk() THEN
- RETURN UnexpectedEOS
- END
- END; (* LOOP *)
- RETURN Ok
- END Start;
- (* reads the next page of the stream buffering its content *)
- PROCEDURE NextPage(): LONGINT;
- VAR
- res, i: LONGINT;
- ch: CHAR;
- BEGIN
- (* look for the capture pattern *)
- i := 0;
- ch := bitReader.GetChar();
- WHILE (i # 4) & (ch = OggS[i]) DO
- ch := bitReader.GetChar();
- INC(i)
- END;
- IF (i#4) THEN RETURN ErrorCapturePattern ELSE res := Ok END;
- (* continue with the header, step-by-step *)
- (* stream structure version already done (read one step ahead in previous loop *)
- page.header.headerTypeFlag := bitReader.GetBits(8);
- page.header.absGranulePos := bitReader.GetHugeInt();
- page.header.streamSerialNo := bitReader.GetBits(32);
- page.header.pageNo := bitReader.GetBits(32);
- page.header.checksum := bitReader.GetBits(32);
- page.header.pageSegments := bitReader.GetBits(8);
- page.header.headerLength := page.header.pageSegments + BaseHeaderLength;
- (* calculate page size and save segment sizes *)
- page.header.pageSize := 0;
- FOR i := 0 TO page.header.pageSegments-1 DO
- page.header.segTable[i] := (bitReader.GetBits(8)); (* SHORT(.) removed *)
- page.header.pageSize := page.header.pageSize + page.header.segTable[i];
- END;
- (* buffer whole page *)
- FOR i:=0 TO page.header.pageSize-1 DO
- ch := bitReader.GetChar();
- page.buf[i] := ch;
- END;
- INC(nrOfPages);
- RETURN res
- END NextPage;
- END OggStreamReader;
- (* simple data-container for decoding *)
- DecoderState = OBJECT
- VAR
- (* internal state *)
- bufferAllocated: BOOLEAN;
- (* some single information *)
- resSize, n, residueType, cacheSize, lastWindowFlag, nrOfSamples: LONGINT;
- preCached: BOOLEAN;
- (* information needed during decoding process *)
- codec: CodecSetup;
- mode: Mode;
- mapping: Mapping;
- win: Window;
- info: Info;
- resInfo: ResidueInfo;
- (* buffers for temporary and final (floor) data *)
- floor, rightCache, residues: ARRAY MaxChannels OF OGGUtilities.PCMBuffer;
- (* Residue *)
- residuePartitionProc: ARRAY 3 OF ResiduePartitionProc;
- doNotDecode, noResidue: ARRAY MaxChannels OF BOOLEAN;
- residueNumbers: ARRAY MaxChannels OF LONGINT; (* stores info of residue vector of each channel *)
- (* FloorType1 *)
- floor1Y: ARRAY Floor1Final OF LONGINT;
- floor1Step2Flag: ARRAY Floor1Final OF BOOLEAN;
- PROCEDURE &Init*(channels: LONGINT);
- BEGIN
- bufferAllocated := FALSE;
- NEW(codec);
- NEW(resInfo);
- residuePartitionProc[0] := ResiduePartitionProc0;
- residuePartitionProc[1] := ResiduePartitionProc1;
- residuePartitionProc[2] := ResiduePartitionProc2
- END Init;
- PROCEDURE AllocateBuffers(channels: LONGINT);
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO channels - 1 DO
- NEW(residues[i]);
- NEW(floor[i]);
- NEW(rightCache[i])
- END;
- bufferAllocated := TRUE
- END AllocateBuffers;
- END DecoderState;
- (** contains information about current window sizes during decode process *)
- Window = OBJECT
- VAR
- small, long: LONGINT;
- center*, leftStart*, leftEnd*, leftSize*, rightStart*, rightEnd*, rightSize*: LONGINT;
- lookupsLeft*, lookupsRight*: ARRAY 2 OF Slope;
- PROCEDURE &Init*(small, long: LONGINT);
- BEGIN
- SELF.small := small DIV 2;
- SELF.long := long DIV 2;
- NEW(lookupsLeft[0], SELF.small, SlopeLeft);
- NEW(lookupsLeft[1], SELF.long, SlopeLeft);
- NEW(lookupsRight[0], SELF.small, SlopeRight);
- NEW(lookupsRight[1], SELF.long, SlopeRight)
- END Init;
- (* return the correct lookup-table index for blocksize n *)
- PROCEDURE GetLookupTable(n: LONGINT): LONGINT;
- BEGIN
- IF n = small THEN
- RETURN 0
- ELSIF n = long THEN
- RETURN 1
- END
- END GetLookupTable;
- PROCEDURE ApplyWindow(VAR data: ARRAY OF HUGEINT; VAR decState: DecoderState);
- VAR i, rIdx, lIdx, n: LONGINT;
- BEGIN
- lIdx := GetLookupTable(leftSize);
- rIdx := GetLookupTable(rightSize);
- n := decState.n;
- IF (decState.mode.windowType = 0) THEN
- FOR i := 0 TO leftStart - 1 DO
- (* no data from this area *)
- data[i] := 0
- END;
- FOR i := leftStart TO leftEnd - 1 DO
- (* increasing window *)
- data[i] := OGGUtilities.MultHugeFP(data[i], lookupsLeft[lIdx].data[i - leftStart])
- END;
- (* in between window is equal 1 => do nothing *)
- FOR i := rightStart TO rightEnd - 1 DO
- (* descending window *)
- data[i] := OGGUtilities.MultHugeFP(data[i], lookupsRight[rIdx].data[i - rightStart])
- END;
- FOR i := rightEnd TO n - 1 DO
- (* no data from this area *)
- data[i] := 0
- END
- ELSE
- IF (Error IN Debug) THEN
- KernelLog.String("ERROR @ VorbisCodec::Window::ApplyWindows() - undefined windowType");
- KernelLog.Ln
- END
- END;
- END ApplyWindow;
- PROCEDURE Print;
- BEGIN
- OGGUtilities.String("### Window ###");
- OGGUtilities.Var("center", center);
- OGGUtilities.Var("leftStart", leftStart);
- OGGUtilities.Var("leftEnd", leftEnd);
- OGGUtilities.Var("leftSize", leftSize);
- OGGUtilities.Var("rightStart", rightStart);
- OGGUtilities.Var("rightEnd", rightEnd);
- OGGUtilities.Var("rightSize", rightSize);
- OGGUtilities.String("### END ")
- END Print;
- END Window;
- Slope = OBJECT
- VAR data: ARRAY OGGUtilities.MaxBlocksize OF LONGINT;
- length: LONGINT;
- PROCEDURE &Init*(length: LONGINT; slope: SlopeFunction);
- VAR i: LONGINT;
- tmp: REAL;
- BEGIN
- SELF.length := length;
- FOR i := 0 TO length - 1 DO
- tmp := slope(i, length);
- data[i] := OGGUtilities.ScaleUp(tmp);
- END
- END Init;
- PROCEDURE Print;
- BEGIN
- PrintLen(length);
- END Print;
- PROCEDURE PrintLen(len: LONGINT);
- BEGIN
- OGGUtilities.String("### SLOPE ###");
- OGGUtilities.Var("length", length);
- OGGUtilities.ArrayLen("data", data, len);
- OGGUtilities.String("### END (slope) ###");
- END PrintLen;
- END Slope;
- AbstractFloorType = OBJECT
- (** no common fields yet *)
- (** abstract method *)
- PROCEDURE DecodeHeader(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR info: Info; VAR codec: CodecSetup): BOOLEAN;
- BEGIN
- HALT(301)
- END DecodeHeader;
- (** abstract method *)
- PROCEDURE DecodePacket(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR; VAR decState: DecoderState): LONGINT;
- BEGIN
- HALT(301)
- END DecodePacket;
- (** abstract method *)
- PROCEDURE ComputeCurve(VAR decState: DecoderState; ch: LONGINT);
- BEGIN
- HALT(301)
- END ComputeCurve;
- (** abstract method *)
- PROCEDURE Print;
- BEGIN
- HALT(301)
- END Print;
- END AbstractFloorType;
- (*
- (* FloorType0 is no longer supported by Xiph.Org and therefore nearly deprecated *)
- FloorType0 = OBJECT(AbstractFloorType)
- VAR
- order, rate, barkMapSize, amplitudeBits, amplitudeOffset, numberOfBooks: LONGINT;
- bookList: ARRAY Floor0BookListSize OF LONGINT;
- (** print to the logfile *)
- PROCEDURE Print;
- BEGIN
- (*
- OGGUtilities.String("### FloorType0 ###");
- OGGUtilities.Var("order", order);
- OGGUtilities.Var("rate", rate);
- OGGUtilities.Var("barkMapSize", barkMapSize);
- OGGUtilities.Var("amplitudeBits", amplitudeBits);
- OGGUtilities.Var("amplitudeOffset", amplitudeOffset);
- OGGUtilities.Var("numberOfBooks", numberOfBooks);
- OGGUtilities.Array("bookList", bookList);
- OGGUtilities.String("### END (FloorType0) ###"); OGGUtilities.String("")
- *)
- END Print;
- (** decode floor0-description from codec setup header*)
- PROCEDURE DecodeHeader(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR info: Info; VAR codec: CodecSetup): BOOLEAN;
- BEGIN
- (*
- order := bufReader.GetBits(buf, 8);
- rate := bufReader.GetBits(buf, 16);
- barkMapSize := bufReader.GetBits(buf, 16);
- amplitudeBits := bufReader.GetBits(buf, 6);
- amplitudeOffset := bufReader.GetBits(buf, 8);
- numberOfBooks := bufReader.GetBits(buf, 4) + 1;
- FOR i := 0 TO numberOfBooks - 1 DO
- bookList[i] := bufReader.GetBits(buf, 8);
- IF (bookList[i] > info.codec.codebookCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Floor0::DecodeHeader() - invalid codebook number (too big)")
- END;
- RETURN FALSE
- END
- END;
- *)
- RETURN TRUE
- END DecodeHeader;
- PROCEDURE DecodePacket(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR; VAR decState: DecoderState): LONGINT;
- (* VAR
- amplitude, booknumber, lookupOffset: LONGINT;
- lastFP: HUGEINT;
- codebook: Codebook; *)
- BEGIN
- (*
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@VorbisCodec::FloorType0::DecodePacket()")
- END;
- amplitude := bufReader.GetBits(buf, amplitudeBits);
- IF (amplitude > 0) THEN
- booknumber := bufReader.GetBits(buf, OGGUtilities.ILog(numberOfBooks));
- codebook := decState.codec.codebooks[booknumber];
- decState.coeffVectorFP.Init;
- IF (booknumber >= decState.codec.codebookCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Floor0::DecodePacket() - invalid codebook number")
- END;
- RETURN InvalidCodebookNumber
- END;
- lastFP := 0; (* lastval from docu [8] eliminated (seems strange) *)
- REPEAT
- lookupOffset := codebook.GetCodeword(bufReader, buf);
- codebook.GetVectorVQ(decState.tempVectorFP, lookupOffset);
- decState.tempVectorFP.Increase(lastFP);
- lastFP := decState.tempVectorFP.GetLast();
- decState.coeffVectorFP.Concatenate(decState.tempVectorFP);
- decState.tempVectorFP.Init;
- UNTIL (decState.coeffVectorFP.GetLen() >= order)
- ELSE
- RETURN ChannelNotUsed
- END;
- *)
- RETURN Ok
- END DecodePacket;
- PROCEDURE ComputeCurve(VAR decState: DecoderState; ch: LONGINT);
- (*
- VAR
- n, i, linearFloorValue, iterationCond: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@FloorType0::ComputeCurve()")
- END;
- n := decState.codec.blocksizes[decState.mode.blockflag] DIV 2;
- (* calculate barkmap *)
- FOR i := 0 TO n-1 DO
- decState.barkMap[i] := Bark((rate * i) / (2 * n)) * barkMapSize DIV Bark(rate DIV 2);
- IF (barkMapSize - 1 < decState.barkMap[i]) THEN decState.barkMap[i] := barkMapSize - 1 END
- END;
- decState.barkMap[n] := -1;
- i := 0;
- LOOP
- IF (order MOD 2 = 1) THEN (* if order is odd *)
- (* TO DO: calculate p and q like this *)
- ELSE
- (* TO DO: calculate p and q like that *)
- END;
- (* TO DO: calculate linearFloorValue *)
- iterationCond := decState.barkMap[i];
- LOOP
- (* TO DO: output element i = linearFloorValue *)
- INC(i);
- IF (decState.barkMap[i] # iterationCond) THEN EXIT END (* else continue inner loop *)
- END;
- IF (i >= n) THEN EXIT END; (* else continue outer loop *)
- END
- *)
- END ComputeCurve;
- (* calculate a bark value *)
- PROCEDURE Bark(x: REAL): LONGINT;
- (*
- VAR res: REAL;
- BEGIN
- res := 13.1 * Math.arctan(0.00074 * x);
- res := res + 2.24 * Math.arctan(0.0000000158 * x * x);
- res := res + 0.0001 * x;
- RETURN ENTIER(res)
- *)
- END Bark;
- END FloorType0;
- *)
- FloorType1 = OBJECT(AbstractFloorType)
- VAR
- partitions*, multiplier*, rangebits*, maxClass*, values*: LONGINT;
- partitionClassList*: ARRAY Floor1PartitionClassListSize OF LONGINT;
- classDimensions*, classSubclasses*, classMasterbooks*: ARRAY Floor1ClassSize OF LONGINT;
- subclassBooks*: ARRAY Floor1ClassSize, Floor1SubclassSize OF LONGINT;
- xList*, xListSortPtr: ARRAY Floor1XListSize OF LONGINT;
- xListSize*, confNr*: LONGINT;
- PROCEDURE &Init*;
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO Floor1XListSize - 1 DO
- xListSortPtr[i] := i
- END
- END Init;
- (** print to the logfile *)
- PROCEDURE Print;
- VAR i: LONGINT;
- BEGIN
- OGGUtilities.String("### FloorType1 ###");
- OGGUtilities.Var("partitions", partitions);
- OGGUtilities.Var("multiplier", multiplier);
- OGGUtilities.Var("rangebits", rangebits);
- OGGUtilities.Var("maxClass", maxClass);
- OGGUtilities.Var("values", values);
- OGGUtilities.Var("xListSize", xListSize);
- OGGUtilities.Array("partitionsClassList", partitionClassList);
- OGGUtilities.Array("classDimensions", classDimensions);
- OGGUtilities.Array("classSubclasses", classSubclasses);
- OGGUtilities.Array("classMasterbooks", classMasterbooks);
- OGGUtilities.Array("xList", xList);
- FOR i := 0 TO Floor1ClassSize - 1 DO
- OGGUtilities.Var("subclassBookNr", i);
- OGGUtilities.Array("subclassBook", subclassBooks[i])
- END;
- OGGUtilities.String("### END (FloorType1) ###"); OGGUtilities.String("")
- END Print;
- PROCEDURE ComputeCurve(VAR decState: DecoderState; ch: LONGINT);
- VAR
- i: LONGINT;
- range, lowNeighborOff, highNeighborOff, predicted, val, highroom, lowroom, room: LONGINT; (* step 1 variables *)
- n, hx, hy, lx, ly: LONGINT; (* step 2 variables *)
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@VorbisCodec::FloorType1::ComputeCurve()")
- END;
- (* step 1: amplitude value synthesis *)
- range := FloorRanges[multiplier-1];
- decState.floor1Step2Flag[0] := TRUE;
- decState.floor1Step2Flag[1] := TRUE;
- FOR i := 2 TO values - 1 DO
- lowNeighborOff := OGGUtilities.LowNeighbor(xList, i);
- highNeighborOff := OGGUtilities.HighNeighbor(xList, i);
- predicted := OGGUtilities.RenderPoint(xList[lowNeighborOff], decState.floor1Y[lowNeighborOff],
- xList[highNeighborOff], decState.floor1Y[highNeighborOff], xList[i]);
- val := decState.floor1Y[i];
- highroom := range - predicted;
- lowroom := predicted;
- IF (highroom < lowroom) THEN
- room := highroom*2
- ELSE
- room := lowroom*2
- END;
- IF (val # 0) THEN
- decState.floor1Step2Flag[lowNeighborOff] := TRUE;
- decState.floor1Step2Flag[highNeighborOff] := TRUE;
- decState.floor1Step2Flag[i] := TRUE;
- IF (val >= room) THEN
- IF (highroom > lowroom) THEN
- decState.floor1Y[i] := val - lowroom + predicted
- ELSE
- decState.floor1Y[i] := predicted - val + highroom - 1;
- END
- ELSE (* val < room *)
- IF (val MOD 2 = 1) THEN (* val is odd *)
- decState.floor1Y[i] := predicted - ((val + 1) DIV 2)
- ELSE (* val is even *)
- decState.floor1Y[i] := predicted + (val DIV 2)
- END
- END
- ELSE (* val = 0 *)
- decState.floor1Step2Flag[i] := FALSE;
- decState.floor1Y[i] := predicted
- END
- END;
- (* step 2: curve synthesis *)
- (* render the lines *)
- hx := 0; lx := 0;
- ly := decState.floor1Y[xListSortPtr[0]] * multiplier;
- FOR i := 1 TO values - 1 DO
- IF (decState.floor1Step2Flag[xListSortPtr[i]]) THEN
- hy := decState.floor1Y[xListSortPtr[i]] * multiplier;
- hx := xList[xListSortPtr[i]];
- OGGUtilities.RenderLine(lx, ly, hx, hy, decState.floor[ch].data);
- lx := hx;
- ly := hy
- END
- END;
- n := decState.n DIV 2;
- IF (hx < n) THEN
- OGGUtilities.RenderLine(hx, hy, n, hy, decState.floor[ch].data)
- END;
- IF (hx > n) THEN
- (* truncate floor-vector to n elements *)
- FOR i := n TO hx - 1 DO
- decState.floor[ch].data[i] := 0
- END
- END;
- (* inverse dB lookup and DotProduct with Residue *)
- FOR i := 0 TO n- 1 DO
- decState.floor[ch].data[i] := InverseDBLookup[decState.floor[ch].data[i]]
- END;
- END ComputeCurve;
- PROCEDURE DecodePacket(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR; VAR decState: DecoderState): LONGINT;
- VAR
- range, book, i, j, class, cdim, cbits, csub, cval, offset, nonzero: LONGINT;
- codebook: Codebook;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@VorbisCodec::FloorType1::DecodePacket()")
- END;
- nonzero := bufReader.GetBits(buf, 1);
- IF (nonzero = 1) THEN
- range := FloorRanges[multiplier-1];
- decState.floor1Y[0] := bufReader.GetBits(buf, OGGUtilities.ILog(range-1));
- decState.floor1Y[1] := bufReader.GetBits(buf, OGGUtilities.ILog(range-1));
- offset := 2;
- FOR i := 0 TO partitions-1 DO
- class := partitionClassList[i];
- cdim := classDimensions[class];
- cbits := classSubclasses[class];
- csub := LSH(LONG(LONG(1)), cbits) - 1;
- cval := 0;
- IF (cbits > 0) THEN
- book := classMasterbooks[class];
- codebook := decState.codec.codebooks[book];
- cval := codebook.GetCodeword(bufReader, buf)
- END;
- FOR j := 0 TO cdim-1 DO
- book := subclassBooks[class, BIT.LAND(cval, csub)];
- cval := LSH(cval, -cbits); (* right shift cval by cbits *)
- IF (book >= 0) THEN
- codebook := decState.codec.codebooks[book];
- decState.floor1Y[j + offset] := codebook.GetCodeword(bufReader, buf)
- ELSE
- decState.floor1Y[j + offset] := 0
- END
- END; (* cdim *)
- INC(offset, cdim)
- END; (* partitions *)
- ELSE (* nonzero = 0 *)
- (* channel contains no audio energy in this frame *)
- IF (Trace IN Debug) THEN
- OGGUtilities.String("VorbisCodec::Floor1::DecodePacket() - RETURN ChannelNotUsed")
- END;
- RETURN ChannelNotUsed
- END;
- IF (Trace IN Debug) THEN
- OGGUtilities.String("VorbisCodec::Floor1::DecodePacket() - RETURN Ok")
- END;
- (* check if there happened an end-of-packet (and therefore an end-of-stream) situation *)
- IF bufReader.IsOk(buf) THEN RETURN Ok ELSE RETURN ChannelNotUsed END
- END DecodePacket;
- (* decode floor1-description from codec setup header *)
- PROCEDURE DecodeHeader(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR info: Info; VAR codec: CodecSetup): BOOLEAN;
- VAR i, j, k: LONGINT;
- BEGIN
- partitions := bufReader.GetBits(buf, 5);
- maxClass := -1;
- FOR i := 0 TO partitions - 1 DO
- partitionClassList[i] := bufReader.GetBits(buf, 4);
- IF (partitionClassList[i] > maxClass) THEN maxClass := partitionClassList[i] END
- END;
- FOR i := 0 TO maxClass DO
- classDimensions[i] := bufReader.GetBits(buf, 3) + 1;
- classSubclasses[i] := bufReader.GetBits(buf, 2);
- IF (classSubclasses[i] # 0) THEN
- classMasterbooks[i] := bufReader.GetBits(buf, 8);
- IF (classMasterbooks[i] > codec.codebookCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Floor1::DecodeHeader() - invalid master-codebook number (too big)")
- END;
- RETURN FALSE
- END
- END;
- FOR j := 0 TO (LSH(LONG(LONG(1)),classSubclasses[i])) - 1 DO
- subclassBooks[i, j] := bufReader.GetBits(buf, 8) - 1;
- IF (subclassBooks[i, j] > codec.codebookCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Floor1::DecodeHeader() - invalid subclass-codebook number (too big)")
- END;
- RETURN FALSE
- END
- END
- END;
- multiplier := bufReader.GetBits(buf, 2) + 1;
- rangebits := bufReader.GetBits(buf, 4);
- (* version of jOrbis' *)
- values := 0;
- k := 0;
- FOR j := 0 TO partitions - 1 DO
- INC(values, classDimensions[partitionClassList[j]]);
- WHILE (k < values) DO
- xList[k + 2] := bufReader.GetBits(buf, rangebits);
- INC(k)
- END
- END;
- INC(values, 2);
- xList[0] := 0;
- xList[1] := LSH(LONG(LONG(1)), rangebits);
- (* sort xList => do not apply, xList is used unsorted only: xListSortPtr *)
- xListSize := 2;
- FOR i := 0 TO partitions - 1 DO
- INC(xListSize, classDimensions[partitionClassList[i]])
- END;
- OGGUtilities.EasySortRemember(xList, xListSortPtr, xListSize);
- RETURN TRUE
- END DecodeHeader;
- END FloorType1;
- (* container for values needed by ResiduePartitionProc *)
- ResidueInfo = OBJECT
- VAR
- partitionSize, outputVectorNr, offset, codebookNr, ch: LONGINT;
- PROCEDURE Init(partitionSize, outputVectorNr, offset, codebookNr, ch: LONGINT);
- BEGIN
- SELF.partitionSize := partitionSize;
- SELF.outputVectorNr := outputVectorNr;
- SELF.offset := offset;
- SELF.codebookNr := codebookNr;
- SELF.ch := ch
- END Init;
- END ResidueInfo;
- Residue = OBJECT
- VAR
- begin, end, partitionSize, classifications, classbook: LONGINT;
- cascades: ARRAY ResidueCascadeSize OF LONGINT;
- books: ARRAY ResidueBookSize, 8 OF LONGINT;
- nr: LONGINT;
- decodemap, partword2: ARRAY 1024, PartwordSize OF LONGINT;
- partword01: ARRAY MaxChannels, 1024, PartwordSize OF LONGINT;
- (** print to the logfile *)
- PROCEDURE Print;
- VAR i: LONGINT;
- BEGIN
- OGGUtilities.String("### Residue ###");
- OGGUtilities.Var("begin", begin);
- OGGUtilities.Var("end", end);
- OGGUtilities.Var("partitionSize", partitionSize);
- OGGUtilities.Var("classifications", classifications);
- OGGUtilities.Var("classbook", classbook);
- OGGUtilities.Array("cascades", cascades);
- FOR i := 0 TO ResidueBookSize - 1 DO
- OGGUtilities.Var("books[i]", i);
- OGGUtilities.Array("book", books[i])
- END;
- OGGUtilities.String("### END (Residue) ###"); OGGUtilities.String("")
- END Print;
- (* decode residue configuration from codec setup header (for all three residue types the same *)
- PROCEDURE DecodeHeader(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR info: Info; VAR codec: CodecSetup): BOOLEAN;
- VAR i, j, k, highBits, lowBits, bitFlag, val, mult, deco, partvals, dim: LONGINT;
- tmpSet: SET;
- BEGIN
- begin := bufReader.GetBits(buf, 24);
- end := bufReader.GetBits(buf, 24);
- partitionSize := bufReader.GetBits(buf, 24) + 1;
- classifications := bufReader.GetBits(buf, 6) + 1;
- classbook := bufReader.GetBits(buf, 8);
- IF (classbook > codec.codebookCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Residue::DecodeHeader() - invalid class-codebook number (too big)")
- END;
- RETURN FALSE
- END;
- FOR i := 0 TO classifications - 1 DO
- highBits := 0;
- lowBits := bufReader.GetBits(buf, 3);
- bitFlag := bufReader.GetBits(buf, 1);
- IF (bitFlag = 1) THEN highBits := bufReader.GetBits(buf, 5) END;
- cascades[i] := highBits * 8 + lowBits
- END;
- FOR i := 0 TO classifications - 1 DO
- FOR j := 0 TO 7 DO
- tmpSet := SYSTEM.VAL(SET, cascades[i]);
- IF (j IN tmpSet) THEN
- books[i, j] := bufReader.GetBits(buf, 8);
- IF (books[i, j] > codec.codebookCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Residue::DecodeHeader() - invalid codebook number (too big)")
- END;
- RETURN FALSE
- END
- ELSE
- books[i, j] := ResidueBookUnused
- END
- END;
- END;
- (* decodemap *)
- dim := codec.codebooks[classbook].dimensions;
- partvals := OGGUtilities.Power(classifications, dim);
- FOR j := 0 TO partvals - 1 DO
- val := j;
- mult := partvals DIV classifications;
- FOR k := 0 TO dim - 1 DO
- deco := val DIV mult;
- val := val - deco * mult;
- mult := mult DIV classifications;
- decodemap[j, k] := deco;
- END
- END;
- RETURN TRUE
- END DecodeHeader;
- (* decode residue vectors filling residue-array, residueNumbers will serve as an index into that array *)
- PROCEDURE DecodePacket(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR decState: DecoderState; ch: LONGINT);
- VAR
- i, j, k, l, s, t: LONGINT;
- samplesPerPartition, partitionsPerWord, n, partvals, offset, temp, vqclass, vqbook: LONGINT;
- codebook: Codebook;
- dim, used: LONGINT;
- BEGIN
- (* decodemap, macht jOrbis so. vielleicht funktionierts ja so ... *)
- dim := decState.codec.codebooks[classbook].dimensions;
- partvals := OGGUtilities.Power(classifications, dim);
- FOR i := 0 TO ch - 1 DO
- decState.residues[i].ZeroBuffer()
- END;
- IF decState.residueType # 2 THEN (* residue-type 0 or 1 *)
- used := 0;
- FOR t := 0 TO ch - 1 DO
- IF ~decState.doNotDecode[t] THEN
- INC(used)
- END
- END;
- IF (used = 0) THEN
- RETURN
- ELSE
- samplesPerPartition := partitionSize;
- partitionsPerWord := decState.codec.codebooks[classbook].dimensions;
- n := end - begin;
- partvals := n DIV samplesPerPartition;
- codebook := decState.codec.codebooks[classbook];
- FOR s := 0 TO 7 DO
- i := 0;
- l := 0;
- WHILE (i < partvals) DO
- IF (s = 0) THEN
- FOR j := 0 TO ch - 1 DO
- temp := codebook.GetCodeword(bufReader, buf);
- FOR t := 0 TO PartwordSize - 1 DO
- partword01[j, l, t] := decodemap[temp, t];
- END
- END (* for ch *)
- END; (* if s = 0 *)
- k := 0;
- WHILE ((k < partitionsPerWord) & (i < partvals)) DO
- FOR j := 0 TO ch - 1 DO
- IF ~decState.doNotDecode[j] THEN
- offset := begin + i * samplesPerPartition;
- vqclass := partword01[j, l, k];
- vqbook := books[vqclass, s];
- IF (vqbook # ResidueBookUnused) THEN
- decState.resInfo.Init(samplesPerPartition, j, offset, vqbook, ch);
- decState.residuePartitionProc[decState.residueType](bufReader, buf, decState)
- END
- END
- END; (* for ch *)
- INC(i);
- INC(k);
- END;
- INC(l);
- END (* while *)
- END (* for s *)
- END (* if doNotDecode *)
- ELSE (* residue-type 2 *)
- t := 0;
- WHILE ((t # ch) & decState.doNotDecode[t]) DO
- INC(t);
- END;
- IF (t = ch) THEN
- (* no residue-vector need to be decoded *)
- RETURN
- END;
- samplesPerPartition := partitionSize;
- partitionsPerWord := decState.codec.codebooks[classbook].dimensions;
- n := end - begin;
- partvals := n DIV samplesPerPartition;
- FOR s := 0 TO 7 DO (* s = pass *)
- i := 0;
- l := 0;
- WHILE (i < partvals) DO
- IF s = 0 THEN
- codebook := decState.codec.codebooks[classbook];
- temp := codebook.GetCodeword(bufReader, buf);
- (* neue version mit decodemap *)
- partword2[l] := decodemap[temp];
- END; (* s = 0 *)
- k := 0;
- WHILE (k < partitionsPerWord) & (i < partvals) DO
- offset := begin + i * samplesPerPartition;
- vqclass := partword2[l, k];
- vqbook := books[vqclass, s];
- IF (vqbook # ResidueBookUnused) THEN
- decState.resInfo.Init(samplesPerPartition, -1, offset, vqbook, ch);
- decState.residuePartitionProc[decState.residueType](bufReader, buf, decState);
- END;
- INC(k);
- INC(i)
- END; (* while *)
- INC(l)
- END; (* while *)
- END (* for s *)
- END; (* if residueType *)
- END DecodePacket;
- END Residue;
- Mapping = OBJECT
- VAR
- submaps*, couplingSteps*: LONGINT;
- magnitude*, angle*: ARRAY MappingMagnitudeSize OF LONGINT;
- mux*: ARRAY MappingMuxSize OF LONGINT;
- submapFloor*, submapResidue*: ARRAY MappingSubmapFloorSize OF LONGINT;
- nr*: LONGINT;
- (** print to the logfile *)
- PROCEDURE Print;
- BEGIN
- OGGUtilities.String("### Mapping ###");
- OGGUtilities.Var("nr", nr);
- OGGUtilities.Var("submaps", submaps);
- OGGUtilities.Var("couplingSteps", couplingSteps);
- OGGUtilities.Array("magnitude", magnitude);
- OGGUtilities.Array("angle", angle);
- OGGUtilities.Array("mux", mux);
- OGGUtilities.Array("submapFloor", submapFloor);
- OGGUtilities.Array("submapResidue", submapResidue);
- OGGUtilities.String("### END (Mapping) ###"); OGGUtilities.String("")
- END Print;
- (* decode mapping configuration from codec setup header *)
- PROCEDURE DecodeHeader(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR info: Info; VAR codec: CodecSetup): BOOLEAN;
- VAR tmp, i: LONGINT;
- BEGIN
- IF (bufReader.GetBits(buf, 1) = 1) THEN
- submaps := bufReader.GetBits(buf, 4) + 1
- ELSE
- submaps := 1
- END;
- IF (bufReader.GetBits(buf, 1) = 1) THEN
- (* square polar channel mapping is in use *)
- couplingSteps := bufReader.GetBits(buf, 8) + 1;
- FOR i := 0 TO couplingSteps - 1 DO
- magnitude[i] := bufReader.GetBits(buf, OGGUtilities.ILog(info.channels - 1));
- angle[i] := bufReader.GetBits(buf, OGGUtilities.ILog(info.channels - 1));
- IF (magnitude[i] = angle[i]) THEN
- IF ((angle[i] > info.channels - 1) OR (magnitude[i] > info.channels - 1)) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Mapping::DecodeHeader() - invalid angle-magnitude-channels constelation")
- END;
- RETURN FALSE
- END
- END
- END
- ELSE
- couplingSteps := 0
- END;
- IF (bufReader.GetBits(buf, 2) # 0) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Mapping::DecodeHeader() - reserved field wrongly in use")
- END;
- RETURN FALSE
- END;
- IF (submaps > 1) THEN
- (* read channel multiplex settings *)
- FOR i := 0 TO info.channels - 1 DO
- mux[i] := bufReader.GetBits(buf, 4);
- IF (mux[i] > submaps - 1) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Mapping::DecodeHeader() - current mux value is greater than submap-1")
- END;
- RETURN FALSE
- END
- END
- END;
- FOR i := 0 TO submaps - 1 DO
- (* read the floor and residue numbers for use in decoding that supmap *)
- tmp := bufReader.GetBits(buf, 8);
- submapFloor[i] := bufReader.GetBits(buf, 8);
- IF (submapFloor[i] > codec.floorCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Mapping::DecodeHeader() - invalid floor number (too big)")
- END;
- RETURN FALSE
- END;
- submapResidue[i] := bufReader.GetBits(buf, 8);
- IF (submapResidue[i] > codec.residueCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Mapping::DecodeHeader() - invalid residue number (too big)")
- END;
- RETURN FALSE
- END
- END;
- RETURN TRUE
- END DecodeHeader;
- END Mapping;
- Mode = OBJECT
- VAR blockflag*, windowType*, transformType*, mapping*: LONGINT;
- (** print to the logfile *)
- PROCEDURE Print;
- BEGIN
- OGGUtilities.String("### Mode ###");
- OGGUtilities.Var("blockflag", blockflag);
- OGGUtilities.Var("windowType", windowType);
- OGGUtilities.Var("transformType", transformType);
- OGGUtilities.Var("mapping", mapping);
- OGGUtilities.String("### END (Mode) ###"); OGGUtilities.String("")
- END Print;
- (* decode mode configurations from codec setup header *)
- PROCEDURE DecodeHeader(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR info: Info; VAR codec: CodecSetup): BOOLEAN;
- BEGIN
- blockflag := bufReader.GetBits(buf, 1);
- windowType := bufReader.GetBits(buf, 16);
- transformType := bufReader.GetBits(buf, 16);
- mapping := bufReader.GetBits(buf, 8);
- IF (mapping > codec.mappingCnt) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Mode::DecodeHeader() - illegal mapping number (too big)")
- END;
- RETURN FALSE
- END;
- IF ((windowType # 0) OR (transformType # 0)) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Mode::DecodeHeader() - illegal window- and/or transform-type")
- END;
- RETURN FALSE
- END;
- RETURN TRUE
- END DecodeHeader;
- END Mode;
- Codebook = OBJECT
- VAR
- entries*, dimensions*, lookupType*, valueBits*, lookupValues*: LONGINT;
- sequenceP*: BOOLEAN;
- minimumValueFP*, deltaValueFP*: HUGEINT; (* fixed-point values *)
- codewordLengths*: OGGUtilities.IntList;
- multiplicandsFP, valuelistFP*: ARRAY MaxNumberOfMultiplicands OF HUGEINT;
- huffmanTree*: OGGUtilities.HuffmanTree;
- valid*: BOOLEAN;
- cbNumber-: LONGINT;
- PROCEDURE &Init*;
- BEGIN
- NEW(codewordLengths, NIL);
- END Init;
- (* print to the logfile *)
- PROCEDURE Print;
- BEGIN
- OGGUtilities.String("### Codebook ###");
- OGGUtilities.Var("cbNumber", cbNumber);
- OGGUtilities.VarH("minimumValueFP", minimumValueFP);
- OGGUtilities.VarH("deltaValueFP", deltaValueFP);
- OGGUtilities.Var("entries", entries);
- OGGUtilities.Var("dimensions", dimensions);
- OGGUtilities.Var("lookupType", lookupType);
- OGGUtilities.Var("valueBits", valueBits);
- OGGUtilities.Var("lookupValues", lookupValues);
- OGGUtilities.ArrayHugeLen("valuelist", valuelistFP, dimensions * entries);
- OGGUtilities.ArrayHugeLen("multiplicands", multiplicandsFP, 32);
- OGGUtilities.String("codewordLengths: ..."); codewordLengths.Print;
- OGGUtilities.String("### END (Codebook) ###"); OGGUtilities.String("")
- END Print;
- (* decode codebooks from codec setup header *)
- PROCEDURE DecodeHeader(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR; nr: LONGINT): BOOLEAN;
- VAR
- curEntry, curLength, number, i, j, k, sparsecount, indexDiv, index: LONGINT;
- valFP, lastFP: HUGEINT;
- newEntry: OGGUtilities.IntElement;
- ordered, sparse, flag: BOOLEAN;
- codewords: OGGUtilities.IntList;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@VorbisCodec::Codebook::DecodeHeader()")
- END;
- SELF.cbNumber := nr;
- (* every codebook starts with a synch-pattern *)
- IF (~(bufReader.GetBits(buf, 24) = CodebookSynchPattern)) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("@VorbisCodec::Codebook::DecodeHeader() - error with synch-pattern of codebook")
- END;
- RETURN FALSE
- END;
- dimensions := bufReader.GetBits(buf, 16);
- entries := bufReader.GetBits(buf, 24);
- ordered := (bufReader.GetBit(buf) = 1);
- IF ~ordered THEN
- (* codeword-list not length-ordered, read each codeword one-by-one *)
- sparse := (bufReader.GetBit(buf) = 1);
- FOR i := 0 TO entries - 1 DO
- IF sparse THEN
- flag := (bufReader.GetBit(buf) = 1);
- IF flag THEN
- curLength := bufReader.GetBits(buf, 5) + 1
- ELSE
- curLength := UnusedCodebookEntry
- END; (* IF flag set *)
- ELSE
- curLength := bufReader.GetBits(buf, 5) + 1;
- END; (* IF sparse set *)
- (* generate new entry and add it to codeword-lengths *)
- IF (curLength > 31) THEN
- KernelLog.String("ASSERTION failed - codeword too long"); KernelLog.Ln
- END;
- (* codewords mustn't be longer than a (positive) LONGINT *)
- ASSERT (curLength <= 31);
- NEW(newEntry, curLength);
- codewordLengths.Append(newEntry)
- END; (* FOR entries *)
- ELSE
- (* codeword-list is in ascending length order, read a number of codewords per length *)
- (* and a total of 'entries' codewords *)
- curEntry := 0;
- curLength := bufReader.GetBits(buf, 5) + 1;
- LOOP
- number := bufReader.GetBits(buf, OGGUtilities.ILog(entries - curEntry));
- IF (curLength > 31) THEN
- KernelLog.String("ASSERTION failed - codeword too long"); KernelLog.Ln
- END;
- (* codewords mustn't be longer than a (positive) LONGINT *)
- ASSERT (curLength <= 31);
- FOR i := curEntry TO (curEntry + number - 1) DO
- NEW(newEntry, curLength);
- codewordLengths.Append(newEntry);
- END;
- curEntry := number + curEntry;
- INC(curLength);
- IF (curEntry > entries) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Codebook::DecodeHeader() - decoding-error (more codebook-entries than expected)");
- RETURN FALSE
- END
- ELSIF curEntry = entries THEN
- EXIT
- (* ELSE
- continue loop *)
- END;
- END; (* LOOP *)
- END;
- (* build a huffman-tree from the codewordLengths *)
- NEW(huffmanTree);
- sparsecount := CountValidCodewords(codewordLengths);
- IF (huffmanTree.IsValidLengthList(codewordLengths, UnusedCodebookEntry)) THEN
- MakeCodewords(codewordLengths, sparsecount, codewords);
- huffmanTree.BuildTree(codewordLengths, codewords, UnusedCodebookEntry);
- valid := TRUE
- ELSIF (~huffmanTree.HasUsedEntries(codewordLengths, UnusedCodebookEntry)) THEN
- valid := FALSE;
- ELSE
- valid := FALSE;
- IF (Error IN Debug) THEN
- OGGUtilities.w.String("error@VorbisCodec::Codebook::DecodeHeader() - invalid huffmanTree");
- IF (huffmanTree.IsOverspecified(codewordLengths, UnusedCodebookEntry)) THEN
- OGGUtilities.w.String(" (overspecified)")
- ELSIF (huffmanTree.IsUnderspecified(codewordLengths, UnusedCodebookEntry)) THEN
- OGGUtilities.w.String(" (underspecified)")
- END;
- OGGUtilities.String("");
- END;
- RETURN FALSE
- END;
- (* prepare for vector-lookup *)
- lookupType := bufReader.GetBits(buf, 4);
- IF (lookupType > 2) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@VorbisCodec::Codebook::DecodeHeader() - decoding-error (invalid codebook-lookupType)")
- END;
- ELSIF (lookupType # 0) THEN
- (* neue Version, a la jOrbis *)
- minimumValueFP := OGGUtilities.Float32Unpack(bufReader.GetBits(buf, 32));
- deltaValueFP := OGGUtilities.Float32Unpack(bufReader.GetBits(buf, 32));
- valueBits := bufReader.GetBits(buf, 4) + 1;
- sequenceP := (bufReader.GetBit(buf) = 1);
- IF (lookupType = 1) THEN
- lookupValues := OGGUtilities.Lookup1Values(entries, dimensions)
- ELSIF (lookupType = 2) THEN
- lookupValues := entries * dimensions
- END;
- IF (lookupValues > MaxNumberOfMultiplicands) THEN
- KernelLog.String("ASSERTION failed - MaxNumberrOfMultiplicands too small"); KernelLog.Ln
- END;
- ASSERT (lookupValues <= MaxNumberOfMultiplicands);
- FOR i := 0 TO lookupValues - 1 DO
- multiplicandsFP[i] := OGGUtilities.ScaleUpHugeInt(bufReader.GetBits(buf, valueBits));
- END;
- IF (lookupType = 1) THEN
- FOR j := 0 TO entries - 1 DO
- lastFP := 0;
- indexDiv := 1;
- FOR k := 0 TO dimensions - 1 DO
- index := (j DIV indexDiv) MOD lookupValues;
- valFP := multiplicandsFP[index];
- (* we need the absolute value *)
- IF valFP < 0 THEN
- valFP := -1 * valFP
- END;
- valFP := OGGUtilities.MultFP(valFP, deltaValueFP);
- valFP := valFP + minimumValueFP + lastFP;
- IF sequenceP THEN lastFP := valFP END;
- valuelistFP[j * dimensions + k] := valFP;
- indexDiv := indexDiv * lookupValues
- END
- END
- ELSIF (lookupType = 2) THEN
- FOR j := 0 TO entries - 1 DO
- lastFP := 0;
- FOR k := 0 TO dimensions - 1 DO
- valFP := multiplicandsFP[j * dimensions + k];
- (* we need the absolute value *)
- IF valFP < 0 THEN
- valFP := -1 * valFP
- END;
- valFP := OGGUtilities.MultFP(valFP, deltaValueFP);
- valFP := valFP + minimumValueFP + lastFP;
- IF sequenceP THEN lastFP := valFP END;
- valuelistFP[j * dimensions + k] := valFP
- END
- END
- END
- END;
- RETURN TRUE
- END DecodeHeader;
- (* read the next codeword from the buffer *)
- PROCEDURE GetCodeword(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR): LONGINT;
- VAR
- bit: LONGINT;
- hNode: OGGUtilities.HuffmanNode;
- BEGIN
- hNode := huffmanTree.start;
- REPEAT
- bit := bufReader.GetBits(buf, 1);
- huffmanTree.GoLeftOrRight(hNode, bit)
- UNTIL (hNode.IsLeaf());
- RETURN hNode.GetValue();
- END GetCodeword;
- (* build the list of codewods from a list of lengths (algorithm from Tremor-source code) *)
- PROCEDURE MakeCodewords(VAR list: OGGUtilities.IntList; sparsecount: LONGINT; VAR res: OGGUtilities.IntList);
- VAR
- i: HUGEINT; j, count, length, entry, tmp: LONGINT;
- marker: ARRAY OGGUtilities.MaxCodewordLength OF LONGINT;
- cur, curRes: OGGUtilities.IntElement;
- BEGIN
- NEW(res, NIL);
- count := 0;
- cur := list.start(OGGUtilities.IntElement);
- FOR i := 0 TO list.length - 1 DO
- length := cur.long;
- IF (length # UnusedCodebookEntry) THEN
- entry := marker[length];
- tmp := LSH(entry, -1*length); (* <=> entry >> length in C *)
- IF ((length < 32) & (tmp # 0)) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@OGGUtilities::HuffmanTree::MakeCodewords() - lengths must specify an overpopulated tree");
- END;
- RETURN
- END;
- (* update ourself *)
- NEW(curRes, entry);
- res.Append(curRes);
- INC(count);
- (* look to see if the next shorter marker points to the node above. if so, update it and repeat *)
- LOOP
- FOR j := length TO 1 BY -1 DO
- IF ((marker[j] MOD 2) = 1) THEN
- IF (j = 1) THEN
- INC(marker[1])
- ELSE
- marker[j] := LSH(marker[j-1], 1) (* <=> marker[j-1] << 1 *)
- END;
- EXIT
- END;
- INC(marker[j]);
- END;
- EXIT (* exit the loop anyway *)
- END; (* LOOP *)
- (* prune the tree; implicit invariant says alle the longer markers were dangling from our just-taken node.
- dangle them from our *new* node *)
- LOOP
- FOR j := length+1 TO OGGUtilities.MaxCodewordLength-1 DO
- IF (LSH(marker[j], -1) = entry) THEN
- entry := marker[j];
- marker[j] := LSH(marker[j-1], 1)
- ELSE
- EXIT
- END
- END;
- EXIT
- END; (* LOOP *)
- ELSE
- IF (sparsecount = 0) THEN INC(count) END
- END; (* IF length > 0 *)
- IF (cur.next # NIL) THEN cur := cur.next(OGGUtilities.IntElement) END
- END(* FOR i=0..n-1 *)
- END MakeCodewords;
- (* count the number of valid codewords *)
- PROCEDURE CountValidCodewords(VAR list: OGGUtilities.IntList): LONGINT;
- VAR
- cur: OGGUtilities.IntElement;
- cnt: LONGINT;
- BEGIN
- cur := list.start(OGGUtilities.IntElement);
- cnt := 0;
- WHILE (cur # NIL) DO
- IF (cur.long # UnusedCodebookEntry) THEN INC(cnt) END;
- IF (cur.next = NIL) THEN cur := NIL ELSE cur := cur.next(OGGUtilities.IntElement) END
- END;
- RETURN cnt
- END CountValidCodewords;
- END Codebook;
- CodecSetup = OBJECT
- VAR
- codebookCnt*, floorCnt*, residueCnt*, mappingCnt*, modeCnt*: LONGINT;
- codebooks*: ARRAY MaxNumberOfCodebooks OF Codebook;
- floorTypes*: ARRAY MaxNumberOfFloors OF LONGINT;
- floorConf*: ARRAY MaxNumberOfFloors OF AbstractFloorType;
- residueTypes*: ARRAY MaxNumberOfResidues OF LONGINT;
- residues*: ARRAY MaxNumberOfResidues OF Residue;
- mappings*: ARRAY MaxNumberOfMappings OF Mapping;
- modes*: ARRAY MaxNumberOfModes OF Mode;
- (** print all elements of the codec setup *)
- PROCEDURE Print;
- VAR i: LONGINT;
- BEGIN
- OGGUtilities.String("***** CodecSetup *****");
- OGGUtilities.Var("codebookCnt", codebookCnt);
- FOR i := 0 TO codebookCnt - 1 DO
- OGGUtilities.Var("codebookNr", i); (* invalid codebooks are NIL *)
- IF (codebooks[i] # NIL) THEN codebooks[i].Print END
- END;
- OGGUtilities.Array("floorTypes", floorTypes);
- OGGUtilities.Var("floorCnt", floorCnt);
- FOR i := 0 TO floorCnt - 1 DO OGGUtilities.Var("floorConfNr", i); floorConf[i].Print END;
- OGGUtilities.Array("residueTypes", residueTypes);
- OGGUtilities.Var("residueCnt", residueCnt);
- FOR i := 0 TO residueCnt - 1 DO OGGUtilities.Var("residueNr", i); residues[i].Print END;
- OGGUtilities.Var("mappingCnt", mappingCnt);
- FOR i := 0 TO mappingCnt - 1 DO OGGUtilities.Var("mappingNr", i); mappings[i].Print END;
- OGGUtilities.Var("modeCnt", modeCnt);
- FOR i := 0 TO modeCnt - 1 DO OGGUtilities.Var("modeNr", i); modes[i].Print END;
- OGGUtilities.String("***** END (CodecSetup) *****");
- END Print;
- END CodecSetup;
- CommentListElement = OBJECT (OGGUtilities.ListElement)
- VAR
- length*: HUGEINT;
- text*: ARRAY MaxCommentLength OF CHAR;
- PROCEDURE Print;
- BEGIN
- KernelLog.String(text); KernelLog.Ln
- END Print;
- END CommentListElement;
- CommentList = OBJECT (OGGUtilities.List)
- VAR
- vendorLength*: HUGEINT;
- vendorString*: ARRAY MaxVendorLength OF CHAR;
- (* other comment fields are already defined in OGGUtilities.List *)
- PROCEDURE Print*;
- VAR cur: CommentListElement;
- BEGIN
- IF cur = NIL THEN
- cur := NIL
- ELSE
- cur := start(CommentListElement)
- END;
- WHILE cur # NIL DO
- cur.Print();
- IF cur.next = NIL THEN
- cur := NIL
- ELSE
- cur := cur.next(CommentListElement)
- END
- END
- END Print;
- END CommentList;
- Info = OBJECT
- VAR
- version, sampleRate: HUGEINT;
- channels, bitrateMax, bitrateNom, bitrateMin: LONGINT;
- blocksizes: ARRAY 2 OF LONGINT;
- comment: CommentList;
- PROCEDURE &Init*;
- BEGIN
- NEW(comment, NIL)
- END Init;
- PROCEDURE Print;
- BEGIN
- OGGUtilities.VarH("version",version);
- OGGUtilities.VarH("sampleRate",sampleRate);
- OGGUtilities.Var("channels",channels);
- OGGUtilities.Var("bitrateMax",bitrateMax);
- OGGUtilities.Var("bitrateNom",bitrateNom);
- OGGUtilities.Var("bitrateMin",bitrateMin);
- OGGUtilities.Var("blocksize0",blocksizes[0]);
- OGGUtilities.Var("blocksize1",blocksizes[1])
- END Print;
- END Info;
- (* buffer for the inverse MDCT *)
- MdctBufferT = ARRAY OGGUtilities.MaxBlocksize DIV 2 OF HUGEINT;
- MdctBuffer = POINTER TO MdctBufferT;
- (** does nothing except printing arguments of Decode()-procedure *)
- DumpDecoder* = OBJECT
- VAR
- packetNr-: LONGINT;
- PROCEDURE &Init*;
- BEGIN
- packetNr := 0;
- END Init;
- PROCEDURE Decode*(VAR buf: ARRAY OF CHAR; pos, len: LONGINT; continuedPacket: BOOLEAN; VAR soundOutput: SoundOutput): BOOLEAN;
- BEGIN
- INC(packetNr);
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@DumpDecoder::Decode()"); OGGUtilities.w.Ln;
- END;
- RETURN TRUE;
- END Decode;
- END DumpDecoder;
- MdctObject = OBJECT
- VAR
- n, log2n: LONGINT;
- bitrev: ARRAY OGGUtilities.MaxBlocksize DIV 4 OF LONGINT;
- trig: ARRAY OGGUtilities.MaxBlocksize + (OGGUtilities.MaxBlocksize DIV 4) OF LONGINT;
- x, w: MdctBuffer;
- PROCEDURE &Init*(n: LONGINT);
- VAR ae, ao, be, bo, ce, co, i, j, acc, mask, msb, notAcc: LONGINT;
- float: LONGREAL;
- BEGIN
- NEW(x);
- NEW(w);
- SELF.n := n;
- log2n := OGGUtilities.Log2n(n);
- ae := 0;
- ao := 1;
- be := ae + n DIV 2;
- bo := be + 1;
- ce := be + n DIV 2;
- co := ce + 1;
- FOR i := 0 TO n DIV 4 - 1 DO
- float := Math.cos((Math.pi / n) * 4 * i);
- trig[ae + i * 2] := OGGUtilities.ScaleUp(float);
- float := - Math.sin((Math.pi / n) * 4 * i);
- trig[ao + i * 2] := OGGUtilities.ScaleUp(float);
- float := Math.cos((Math.pi / (2 * n)) * (2 * i + 1));
- trig[be + i * 2] := OGGUtilities.ScaleUp(float);
- float := Math.sin((Math.pi / (2 * n)) * (2 * i + 1));
- trig[bo + i * 2] := OGGUtilities.ScaleUp(float);
- END;
- FOR i := 0 TO n DIV 8 - 1 DO
- float := Math.cos((Math.pi / n) * (4 * i + 2));
- trig[ce + i * 2] := OGGUtilities.ScaleUp(float);
- float := - Math.sin((Math.pi / n) * (4 * i + 2));
- trig[co + i * 2] := OGGUtilities.ScaleUp(float);
- END;
- mask := LSH(LONG(LONG(1)), log2n - 1) - 1;
- msb := LSH(LONG(LONG(1)), log2n - 2);
- FOR i := 0 TO n DIV 8 - 1 DO
- acc := 0;
- j := 0;
- WHILE (LSH(msb, -j) # 0) DO
- IF ((BIT.LAND(LSH(msb, -j), i)) # 0) THEN
- acc := BIT.LOR(acc, LSH(LONG(LONG(1)), j))
- END;
- INC(j)
- END;
- notAcc := BIT.LXOR(acc, -1); (* !acc, bitwise not *)
- bitrev[i * 2] := BIT.LAND(notAcc, mask);
- bitrev[i * 2 + 1] := acc
- END
- END Init;
- (** performs the inverse MDCT *)
- PROCEDURE Backward(VAR data: ARRAY OF HUGEINT);
- VAR n2, n4, n8, inO, xO, a, i, xx, b, o1, o2, o3, o4: LONGINT;
- temp1, temp2: HUGEINT;
- BEGIN
- n2 := n DIV 2;
- n4 := n DIV 4;
- n8 := n DIV 8;
- (* step 1 and rotation *)
- inO := 1;
- xO := 0;
- a := n2;
- FOR i := 0 TO n8 - 1 DO
- DEC(a, 2);
- x[xO] := OGGUtilities.MultHugeFP(-data[inO + 2], trig[a + 1]);
- DEC(x[xO], OGGUtilities.MultHugeFP(data[inO], trig[a]));
- INC(xO);
- x[xO] := OGGUtilities.MultHugeFP(data[inO], trig[a + 1]);
- DEC(x[xO], OGGUtilities.MultHugeFP(data[inO + 2], trig[a]));
- INC(xO);
- INC(inO, 4);
- END;
- inO := n2 - 4;
- FOR i := 0 TO n8 - 1 DO
- DEC(a, 2);
- x[xO] := OGGUtilities.MultHugeFP(data[inO], trig[a + 1]);
- INC(x[xO], OGGUtilities.MultHugeFP(data[inO + 2], trig[a]));
- INC(xO);
- x[xO] := OGGUtilities.MultHugeFP(data[inO], trig[a]);
- DEC(x[xO], OGGUtilities.MultHugeFP(data[inO + 2], trig[a + 1]));
- INC(xO);
- DEC(inO, 4);
- END;
- (* steps 2 to 7 *)
- Kernel(n, n2, n4, n8);
- xx := 0;
- (* step 8 *)
- b := n2;
- o1 := n4;
- o2 := o1 - 1;
- o3 := n4 + n2;
- o4 := o3 - 1;
- FOR i := 0 TO n4 - 1 DO
- temp1 := OGGUtilities.MultHugeFP(x[xx], trig[b + 1]);
- DEC(temp1, OGGUtilities.MultHugeFP(x[xx + 1], trig[b]));
- temp2 := OGGUtilities.MultHugeFP(x[xx], trig[b]);
- INC(temp2, OGGUtilities.MultHugeFP(x[xx + 1], trig[b + 1]));
- temp2 := -temp2;
- data[o1] := -temp1;
- data[o2] := temp1;
- data[o3] := temp2;
- data[o4] := temp2;
- INC(o1);
- DEC(o2);
- INC(o3);
- DEC(o4);
- INC(xx, 2);
- INC(b, 2)
- END
- END Backward;
- (* Mdct-Kernel: xxx is an out-parameter *)
- PROCEDURE Kernel(n, n2, n4, n8: LONGINT);
- BEGIN
- KernelStep1(n2, n4);
- KernelStep2(n2);
- KernelStep3(n2, n8);
- END Kernel;
- PROCEDURE Swap(VAR a,b: MdctBuffer);
- VAR tmp: MdctBuffer;
- BEGIN
- tmp := a;
- a := b;
- b := tmp
- END Swap;
- (* step 2 *)
- PROCEDURE KernelStep1(n2, n4: LONGINT);
- VAR xA, xB, w2, a, i: LONGINT;
- x0, x1: HUGEINT;
- BEGIN
- xA := n4;
- xB := 0;
- w2 := n4;
- a := n2;
- i := 0;
- WHILE (i < n4) DO
- x0 := x[xA] - x[xB];
- w[w2 + i] := x[xA] + x[xB];
- INC(xA);
- INC(xB);
- x1 := x[xA] - x[xB];
- DEC(a, 4);
- w[i] := OGGUtilities.MultHugeFP(x0, trig[a]);
- INC(w[i], OGGUtilities.MultHugeFP(x1, trig[a + 1]));
- INC(i);
- w[i] := OGGUtilities.MultHugeFP(x1, trig[a]);
- DEC(w[i], OGGUtilities.MultHugeFP(x0, trig[a + 1]));
- w[w2 + i] := x[xA] + x[xB];
- INC(xA);
- INC(xB);
- INC(i)
- END;
- END KernelStep1;
- (* step 3 *)
- PROCEDURE KernelStep2(n2: LONGINT);
- VAR i, s, r, w1, w2, k0, k1, a, wbase, sEnd: LONGINT;
- wA, wB, aev, aov: HUGEINT;
- BEGIN
- FOR i := 0 TO log2n - 3 - 1 DO
- k0 := LSH(n, -(i + 2));
- k1 := LSH(LONG(LONG(1)), i + 3);
- wbase := n2 - 2;
- a := 0;
- FOR r := 0 TO (k0 DIV 4) - 1 DO
- w1 := wbase;
- w2 := w1 - (k0 DIV 2);
- aev := trig[a];
- aov := trig[a + 1];
- DEC(wbase, 2);
- INC(k0);
- sEnd := LSH((LONG(LONG(2))), i);
- FOR s := 0 TO sEnd - 1 DO
- wB := w[w1] - w[w2];
- x[w1] := w[w1] + w[w2];
- INC(w1);
- INC(w2);
- wA := w[w1] - w[w2];
- x[w1] := w[w1] + w[w2];
- x[w2] := OGGUtilities.MultHugeFP(wA, aev);
- DEC(x[w2], OGGUtilities.MultHugeFP(wB, aov));
- x[w2 - 1] := OGGUtilities.MultHugeFP(wB, aev);
- INC(x[w2 - 1], OGGUtilities.MultHugeFP(wA, aov));
- DEC(w1, k0);
- DEC(w2, k0)
- END;
- DEC(k0);
- INC(a, k1)
- END;
- Swap(x, w)
- END;
- END KernelStep2;
- (* step 4, 5, 6, 7 *)
- PROCEDURE KernelStep3(n2, n8: LONGINT);
- VAR c, bit, x1, x2, t1, t2, i: LONGINT;
- wa, wb, wc, wd, wace, waco, wbce, wbco: HUGEINT;
- BEGIN
- c := n;
- bit := 0;
- x1 := 0;
- x2 := n2 - 1;
- FOR i := 0 TO n8 -1 DO
- t1 := bitrev[bit];
- INC(bit);
- t2 := bitrev[bit];
- INC(bit);
- wa := w[t1] - w[t2 + 1];
- wb := w[t1 - 1] + w[t2];
- wc := w[t1] + w[t2 + 1];
- wd := w[t1 - 1] - w[t2];
- wace := OGGUtilities.MultHugeFP(wa, trig[c]);
- wbce := OGGUtilities.MultHugeFP(wb, trig[c]);
- INC(c);
- waco := OGGUtilities.MultHugeFP(wa, trig[c]);
- wbco := OGGUtilities.MultHugeFP(wb, trig[c]);
- INC(c);
- x[x1] := (wc + waco + wbce) DIV 2;
- INC(x1);
- x[x2] := (-wd + wbco - wace) DIV 2;
- DEC(x2);
- x[x1] := (wd + wbco - wace) DIV 2;
- INC(x1);
- x[x2] := (wc - waco - wbce) DIV 2;
- DEC(x2)
- END;
- END KernelStep3;
- END MdctObject;
- (** structure for holding all necessary information for last step in the decode-process like #channels ... *)
- SoundOutput = OBJECT
- VAR
- output: OGGUtilities.BufferPool;
- nrOfBuffers, nrOfChannels, samplingRate, samplingResolution, volume: LONGINT;
- minAmplitude, maxAmplitude: LONGINT;
- initSoundChannelDone*: BOOLEAN;
- channel: SoundDevices.Channel;
- driver: SoundDevices.Driver;
- PROCEDURE &Init*(nrOfBuffers, volume: LONGINT);
- BEGIN
- SELF.volume := volume;
- SELF.nrOfBuffers := nrOfBuffers;
- initSoundChannelDone := FALSE;
- NEW(output, nrOfBuffers)
- END Init;
- PROCEDURE CloseSoundChannel*;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@SoundOutput::CloseSoundChannel()")
- END;
- IF channel # NIL THEN channel.Close() END
- END CloseSoundChannel;
- PROCEDURE InitSoundChannel*(nrOfChannels, samplingRate, samplingResolution: LONGINT);
- VAR i, res: LONGINT;
- buffer: SoundDevices.Buffer;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@SoundOutput::InitSoundChannel()")
- END;
- SELF.samplingRate := samplingRate;
- SELF.samplingResolution := samplingResolution;
- SELF.nrOfChannels := nrOfChannels;
- SetMinMaxAmplitudes();
- (* allocate sound-buffers *)
- FOR i := 0 TO nrOfBuffers - 1 DO
- NEW(buffer);
- (* factor 2 because samplingResolution of 16 results in two 8-bit numbers *)
- NEW(buffer.data, 2 * OGGUtilities.MaxBlocksize);
- buffer.len := 2 * OGGUtilities.MaxBlocksize;
- output.Append(buffer);
- END;
- driver := SoundDevices.GetDefaultDevice();
- driver.OpenPlayChannel(channel, samplingRate, samplingResolution, nrOfChannels, SoundDevices.FormatPCM, res);
- IF (volume < 0) THEN volume := 255 ELSIF (volume > 255) THEN volume := 255 END;
- channel.SetVolume(volume);
- IF (channel # NIL) THEN
- channel.RegisterBufferListener(BufferListener);
- channel.Start
- END;
- initSoundChannelDone := TRUE;
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@END - SoundOutput::Init...()")
- END
- END InitSoundChannel;
- PROCEDURE Output*(VAR input: ARRAY OF OGGUtilities.PCMBuffer; nrOfSamples: LONGINT);
- VAR buffer: SoundDevices.Buffer;
- i, ch, current, bufferPos: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@SoundOutput::Output()")
- END;
- buffer := output.Remove();
- (* adjust buffer.len: samplingResolution of 16 results in twice as many 8-bit chars *)
- buffer.len := nrOfSamples * nrOfChannels * (samplingResolution DIV 8);
- bufferPos := 0;
- FOR i := 0 TO nrOfSamples - 1 DO
- FOR ch := 0 TO nrOfChannels - 1 DO
- IF input[ch].data[i] # 0 THEN
- current := GetSample(input[ch].data[i]);
- ELSE
- current := 0;
- END;
- IF (samplingResolution = 8) THEN
- buffer.data[bufferPos] := CHR(current);
- INC(bufferPos);
- ELSIF (samplingResolution = 16) THEN
- buffer.data[bufferPos] := CHR(current MOD 256);
- buffer.data[bufferPos + 1] := CHR(current DIV 256);
- INC(bufferPos, 2);
- ELSE
- (* no other samplingRate supported yet *)
- END (* samplingRate *)
- END (* nrOfChannels *)
- END; (* nrOfSamples *)
- channel.QueueBuffer(buffer);
- channel.Start;
- IF (Trace IN Debug) THEN
- OGGUtilities.String("finished - SoundOutput::Output()")
- END
- END Output;
- PROCEDURE SetMinMaxAmplitudes;
- BEGIN
- (* so far, only resolutions of 8 resp. 16 bits are supported *)
- IF (samplingResolution = 8) THEN
- maxAmplitude := 127;
- minAmplitude := -128
- ELSIF (samplingResolution = 16) THEN
- maxAmplitude := 32767;
- minAmplitude := -32768
- END
- END SetMinMaxAmplitudes;
- (* calculate the current sample:
- - scales down the fixpoint-number
- - upsizes with the max amplitude
- - does the clipping
- *)
- PROCEDURE GetSample(sample: HUGEINT): LONGINT;
- VAR retSample: LONGINT;
- BEGIN
- (* can do a normal multiplication here *)
- sample := sample * maxAmplitude;
- retSample := OGGUtilities.ScaleDownRoundedHuge(sample);
- IF retSample > maxAmplitude THEN
- RETURN maxAmplitude
- END;
- IF retSample < minAmplitude THEN
- RETURN minAmplitude
- END;
- RETURN retSample
- END GetSample;
- PROCEDURE BufferListener(buffer: SoundDevices.Buffer);
- BEGIN
- output.Append(buffer);
- END BufferListener;
- END SoundOutput;
- (** writes a raw pcm-date to a file *)
- TYPE FileOutput = OBJECT(SoundOutput)
- VAR
- filename-: ARRAY 64 OF CHAR;
- filenameSet: BOOLEAN;
- file: Files.File;
- writer: Files.Writer;
- frameCnt: LONGINT;
- PROCEDURE &Init*(nrOfBuffers, volume: LONGINT);
- BEGIN
- filenameSet := FALSE;
- file := NIL;
- frameCnt := 0;
- filename := ""
- END Init;
- PROCEDURE SetFilename*(VAR filename: ARRAY OF CHAR);
- BEGIN
- Strings.Append(SELF.filename, filename);
- filenameSet := TRUE
- END SetFilename;
- PROCEDURE CloseSoundChannel*;
- BEGIN
- (* close file *)
- IF file # NIL THEN
- writer.Update;
- Files.Register(file)
- END
- END CloseSoundChannel;
- PROCEDURE InitSoundChannel*(localNrOfChannels, samplingRate, localSamplingResolution: LONGINT);
- BEGIN
- nrOfChannels := localNrOfChannels;
- samplingResolution := localSamplingResolution;
- SetMinMaxAmplitudes();
- (* open a file *)
- IF filenameSet THEN
- file := Files.New(filename);
- Files.OpenWriter(writer, file, 0);
- END;
- initSoundChannelDone := TRUE
- END InitSoundChannel;
- PROCEDURE Output*(VAR input: ARRAY OF OGGUtilities.PCMBuffer; nrOfSamples: LONGINT);
- VAR i, ch, current: LONGINT;
- BEGIN
- INC(frameCnt);
- IF file # NIL THEN
- FOR i := 0 TO nrOfSamples - 1 DO
- FOR ch := nrOfChannels - 1 TO 0 BY -1 DO
- current := GetSample(input[ch].data[i]);
- IF samplingResolution = 8 THEN
- writer.Char(CHR(current))
- ELSIF samplingResolution = 16 THEN
- writer.RawInt(SHORT(current))
- END
- END
- END
- ELSE
- KernelLog.String("could not write frame# "); KernelLog.Int(frameCnt, 0); KernelLog.Ln
- END;
- writer.Update
- END Output;
- END FileOutput;
- VorbisDecoder* = OBJECT
- VAR
- buf: ARRAY MaxPageSize OF CHAR; (* why not this size? *)
- pos, packetCnt: LONGINT;
- appendPacket, firstDataPacket: BOOLEAN;
- info: Info;
- soundOutput: SoundOutput;
- bufReader: BufferReader;
- decState: DecoderState;
- nrOfSamplesPlayed: LONGINT;
- mdct: ARRAY 2 OF MdctObject; (* for each of the two blocksizes one Mdct *)
- PROCEDURE &Init*;
- BEGIN
- pos := 0; packetCnt := 0;
- firstDataPacket := TRUE;
- frameCnt := 0;
- NEW(info);
- NEW(bufReader);
- NEW(decState, info.channels)
- END Init;
- PROCEDURE ResetDecoder;
- BEGIN
- SELF.pos := 0
- END ResetDecoder;
- PROCEDURE Decode*(VAR buf: ARRAY OF CHAR; pos,len: LONGINT; continuedPacket:
- BOOLEAN; VAR soundOutput: SoundOutput): LONGINT;
- VAR
- i, typeLen: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@Decode()"); OGGUtilities.w.Ln;
- END;
- (* adjust pos ('vorbis'-string appears only in the three header packets
- or if it's a spanned packet over several pages and first byte with packet type will be used) *)
- typeLen := OggStreamTypeLength + 1;
- IF packetCnt > 2 THEN
- DEC(pos, typeLen)
- ELSIF packetCnt <= 2 THEN
- IF ~appendPacket THEN
- DEC(len, typeLen)
- ELSE
- DEC(pos, typeLen)
- END
- END;
- (* reset BufferReader if it's a new packet *)
- IF (~appendPacket) THEN bufReader.Init() END;
- (* save buf to SELF.buf *)
- i := 0;
- WHILE (i # len) DO
- SELF.buf[SELF.pos + i] := buf[pos + i]; INC(i)
- END;
- INC(SELF.pos, len);
- (* current position is equal to the length of the logical packet *)
- bufReader.SetLen(SELF.pos);
- (* start decoding (if packet is not going to be continued) *)
- IF ~continuedPacket THEN
- appendPacket := FALSE;
- RETURN StartDecode(soundOutput)
- ELSE
- appendPacket := TRUE;
- RETURN Ok
- END
- END Decode;
- (* start the decoding proccess *)
- PROCEDURE StartDecode(VAR soundOutput: SoundOutput): LONGINT;
- VAR res: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@StartDecode()")
- END;
- INC(packetCnt);
- (* identification header *)
- IF (packetCnt = 1) THEN
- res := DecodeIdentificationHeader();
- IF (Codec IN Debug) THEN info.Print END
- (* comment header *)
- ELSIF (packetCnt = 2) THEN
- res := DecodeCommentHeader();
- IF (Codec IN Debug) THEN info.comment.Print END
- (* setup header *)
- ELSIF (packetCnt = 3) THEN
- res := DecodeSetupHeader(decState.codec);
- decState.info := info;
- IF ((info.bitrateMin > 0) & (info.bitrateMax > 0)) THEN
- KernelLog.String("bitrates (min/avg/max): ");
- KernelLog.Int(info.bitrateMin, 0);
- KernelLog.String(" / ");
- KernelLog.Int(info.bitrateNom, 0);
- KernelLog.String(" / ");
- KernelLog.Int(info.bitrateMax, 0);
- KernelLog.String(" bps")
- ELSE
- KernelLog.String("average bitrate: ");
- KernelLog.Int(info.bitrateNom, 0);
- KernelLog.String(" bps")
- END;
- KernelLog.Ln;
- IF (Codec IN Debug) THEN decState.codec.Print END
- (* regular data packet *)
- ELSE
- IF ~decState.bufferAllocated THEN decState.AllocateBuffers(info.channels) END;
- DecodeDataPacket(res);
- IF ~soundOutput.initSoundChannelDone THEN
- soundOutput.InitSoundChannel(decState.info.channels, SHORT(decState.info.sampleRate), DefaultSamplingResolution)
- END;
- IF ~firstDataPacket THEN
- soundOutput.Output(decState.floor, decState.nrOfSamples);
- INC(nrOfSamplesPlayed, decState.nrOfSamples);
- ELSE
- firstDataPacket := FALSE
- END;
- res := Ok
- END;
- ResetDecoder();
- RETURN res
- END StartDecode;
- PROCEDURE DecodeIdentificationHeader(): LONGINT;
- VAR
- tmp: LONGINT;
- set: SET;
- BEGIN
- (* version *)
- info.version := bufReader.GetBits(buf, 32);
- IF (info.version # 0) THEN RETURN ErrorIdentification END;
- (* bitrate and samplerate *)
- info.channels := bufReader.GetBits(buf, 8);
- IF (info.channels > MaxChannels) THEN
- KernelLog.String("ASSERTION failed - too much channels"); KernelLog.Ln
- END;
- ASSERT(info.channels <= MaxChannels);
- info.sampleRate := bufReader.GetBits(buf, 32);
- info.bitrateMax := bufReader.GetBits(buf, 32);
- info.bitrateNom := bufReader.GetBits(buf, 32);
- info.bitrateMin := bufReader.GetBits(buf, 32);
- (* blocksizes *)
- tmp := bufReader.GetBits(buf, 4);
- info.blocksizes[0] := LSH(LONG(LONG(1)), tmp); (* blocksize0 := 2^tmp *)
- tmp := bufReader.GetBits(buf, 4);
- info.blocksizes[1] := LSH(LONG(LONG(1)), tmp); (* blocksize1 := 2^tmp *)
- IF (info.blocksizes[0] > info.blocksizes[1]) THEN RETURN ErrorIdentification END;
- (* framing bit *)
- set := SYSTEM.VAL(SET,bufReader.GetBit(buf));
- IF (set = {}) THEN RETURN ErrorIdentification END;
- RETURN Ok
- END DecodeIdentificationHeader;
- PROCEDURE DecodeCommentHeader(): LONGINT;
- VAR
- i, j: HUGEINT;
- commentElement: CommentListElement;
- BEGIN
- info.comment.vendorLength := bufReader.Get32UnsignedBits(buf);
- IF (info.comment.vendorLength > MaxVendorLength) THEN
- KernelLog.String("ASSERTION failed - vendorLength exceeds MaxVendorLength"); KernelLog.Ln
- END;
- ASSERT(info.comment.vendorLength <= MaxVendorLength);
- i := 0;
- FOR i := 0 TO info.comment.vendorLength-1 DO
- info.comment.vendorString[i] := bufReader.GetChar(buf);
- END;
- info.comment.length := bufReader.Get32UnsignedBits(buf);
- FOR i := 0 TO info.comment.length-1 DO
- NEW(commentElement);
- commentElement.length := bufReader.Get32UnsignedBits(buf);
- FOR j := 0 TO commentElement.length-1 DO
- commentElement.text[j] := bufReader.GetChar(buf);
- END;
- info.comment.Append(commentElement);
- END;
- info.comment.Print();
- RETURN Ok
- END DecodeCommentHeader;
- PROCEDURE DecodeSetupHeader(VAR codec: CodecSetup): LONGINT;
- VAR
- tmp, i, timeCnt: LONGINT;
- codebook: Codebook;
- floor1: FloorType1;
- residue: Residue;
- mapping: Mapping;
- mode: Mode;
- BEGIN
- (* read codebooks *)
- codec.codebookCnt := bufReader.GetBits(buf, 8) + 1;
- FOR i := 0 TO codec.codebookCnt - 1 DO
- NEW(codebook);
- IF ~codebook.DecodeHeader(bufReader, buf, i) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.Var("#codebooks", codec.codebookCnt);
- OGGUtilities.Var("error@VorbisCodec::Codebook::DecodeHeader() - error decoding codebookNr", i)
- END;
- RETURN ErrorSetup
- END;
- codec.codebooks[i] := codebook;
- END;
- (* time domain transforms *)
- timeCnt := bufReader.GetBits(buf, 6) + 1;
- FOR i := 0 TO timeCnt-1 DO
- tmp := bufReader.GetBits(buf, 16);
- IF (tmp # 0) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - time domain transformation error (see Vorbis documentation for further details")
- END;
- RETURN ErrorSetup
- END
- END;
- (* floor decode *)
- codec.floorCnt := bufReader.GetBits(buf, 6) + 1;
- FOR i := 0 TO codec.floorCnt - 1 DO
- codec.floorTypes[i] := bufReader.GetBits(buf, 16);
- IF codec.floorTypes[i] # 1 THEN
- KernelLog.String("ASSERTTION failed - FloorType0 not yet implemented")
- END;
- (* see FloorType0 for reason *)
- ASSERT(codec.floorTypes[i] = 1);
- (*
- IF (codec.floorTypes[i] = 0) THEN
- NEW(floor0);
- IF ~floor0.DecodeHeader(bufReader, buf, info) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - error decoding floor0-header")
- END;
- RETURN ErrorSetup
- END;
- codec.floorConf[i] := floor0
- *)
- IF (codec.floorTypes[i] = 1) THEN
- NEW(floor1);
- IF ~floor1.DecodeHeader(bufReader, buf, info, codec) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - error decoding floor type 1")
- END;
- RETURN ErrorSetup
- END;
- floor1.confNr := i;
- codec.floorConf[i] := floor1
- ELSE
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - invalid floor type")
- END;
- RETURN ErrorSetup
- END;
- END;
- (* residue decode *)
- codec.residueCnt := bufReader.GetBits(buf, 6) + 1;
- FOR i := 0 TO codec.residueCnt - 1 DO
- codec.residueTypes[i] := bufReader.GetBits(buf, 16);
- NEW(residue);
- IF (codec.residueTypes[i] > 2) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - invalid residue type")
- END;
- RETURN ErrorSetup
- END;
- NEW(residue);
- IF ~residue.DecodeHeader(bufReader, buf, info, codec) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - error decoding residue header")
- END;
- RETURN ErrorSetup;
- END;
- residue.nr := i;
- codec.residues[i] := residue;
- END;
- (* mapping decode *)
- codec.mappingCnt := bufReader.GetBits(buf, 6) + 1;
- FOR i := 0 TO codec.mappingCnt - 1 DO
- tmp := bufReader.GetBits(buf, 16);
- IF (tmp # 0) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - invalid mapping type")
- END;
- RETURN ErrorSetup;
- END;
- NEW(mapping);
- IF ~mapping.DecodeHeader(bufReader, buf, info, codec) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - error decoding mapping info")
- END;
- RETURN ErrorSetup
- END;
- mapping.nr := i;
- codec.mappings[i] := mapping
- END;
- (* mode decode *)
- codec.modeCnt := bufReader.GetBits(buf, 6) + 1;
- FOR i := 0 TO codec.modeCnt - 1 DO
- NEW(mode);
- IF ~mode.DecodeHeader(bufReader, buf, info, codec) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - error decoding mode info")
- END;
- RETURN ErrorSetup
- END;
- codec.modes[i] := mode
- END;
- (* check framing *)
- tmp := bufReader.GetBits(buf, 1);
- IF (tmp = 0) THEN
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeSetupHeader() - framing-bit not set at the end of the codec-header")
- END;
- RETURN ErrorSetup
- END;
- RETURN Ok
- END DecodeSetupHeader;
- PROCEDURE DecodeDataPacket(res: LONGINT);
- BEGIN
- IF (Trace IN Debug) THEN OGGUtilities.String("@DecodeDataPacket()") END;
- INC(frameCnt);
- IF firstDataPacket THEN
- (* do stuff that is required only once *)
- NEW(mdct[0], info.blocksizes[0]);
- NEW(mdct[1], info.blocksizes[1]);
- NEW(decState.win, info.blocksizes[0], info.blocksizes[1])
- END;
- IF (bufReader.GetBits(buf, 1) # 0) THEN
- (* it's not a vorbis data packet *)
- IF (Error IN Debug) THEN
- OGGUtilities.String("error@DecodeDataPacket() - wrong packet type (0 expected)")
- END;
- decState.nrOfSamples := 0;
- res := NoDataPacket;
- RETURN
- END;
- decState.nrOfSamples := WindowDecode(res);
- IF res # Ok THEN RETURN END;
- res := FloorCurveDecode();
- NonzeroVectorPropagate();
- ResidueDecode();
- InverseCoupling();
- DotProduct();
- Mdct();
- WindowData();
- OverlapAdd();
- CacheRightHandData();
- res := Ok
- END DecodeDataPacket;
- (* cache the second half of the data and set the cache size correctly
- (cached data starts at offset 0) *)
- PROCEDURE CacheRightHandData;
- VAR ch, i: LONGINT;
- BEGIN
- IF decState.preCached THEN
- FOR ch := 0 TO decState.info.channels - 1 DO
- FOR i := 0 TO decState.n DIV 2 - 1 DO
- decState.rightCache[ch].data[i] := decState.residues[ch].data[i]
- END
- END
- ELSE
- FOR ch := 0 TO decState.info.channels - 1 DO
- FOR i := decState.n DIV 2 TO decState.n - 1 DO
- decState.rightCache[ch].data[i - decState.n DIV 2] := decState.floor[ch].data[i]
- END
- END
- END;
- decState.cacheSize := decState.n DIV 2
- END CacheRightHandData;
- (* overlap cached-data from previous frame with data from current frame
- data starts at offset 0 *)
- PROCEDURE OverlapAdd;
- VAR ch, i, start: LONGINT;
- BEGIN
- FOR ch := 0 TO decState.info.channels - 1 DO
- IF (decState.cacheSize = decState.n DIV 2) THEN
- decState.preCached := FALSE;
- (* previous frame had same size than current: just add cached data to current data *)
- FOR i := 0 TO decState.n DIV 2 - 1 DO
- INC(decState.floor[ch].data[i], decState.rightCache[ch].data[i]);
- END
- ELSIF (decState.cacheSize > decState.n DIV 2) THEN
- (* previous frame was a LONG one: add current data to cached data and insert it as current data *)
- start := (decState.cacheSize DIV 2) - (decState.n DIV 4);
- decState.preCached := TRUE;
- (* add floor data to cached data *)
- FOR i := 0 TO decState.n DIV 2 - 1 DO
- INC(decState.rightCache[ch].data[i + start], decState.floor[ch].data[i])
- END;
- (* pre-cache right floor-data *)
- FOR i:= decState.n DIV 2 TO decState.n - 1 DO
- decState.residues[ch].data[i - decState.n DIV 2] := decState.floor[ch].data[i]
- END;
- (* then copy all cached data to floor-data-vector *)
- FOR i := 0 TO decState.cacheSize - 1 DO
- decState.floor[ch].data[i] := decState.rightCache[ch].data[i]
- END
- ELSIF (decState.cacheSize < decState.n DIV 2) THEN
- (* previous frame was a SHORT one: add cached data to current data *)
- start := (decState.n DIV 4) - (decState.cacheSize DIV 2);
- decState.preCached := FALSE;
- FOR i := start TO start + decState.cacheSize - 1 DO
- INC(decState.floor[ch].data[i], decState.rightCache[ch].data[i - start])
- END;
- (* now, data from [0..leftStart] is all zero, move data to offset 0 *)
- FOR i := decState.win.leftStart TO decState.n DIV 2 - 1 DO
- decState.floor[ch].data[i - decState.win.leftStart] := decState.floor[ch].data[i]
- END
- END
- END
- END OverlapAdd;
- PROCEDURE WindowData;
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO decState.info.channels - 1 DO
- decState.win.ApplyWindow(decState.floor[i].data, decState)
- END
- END WindowData;
- PROCEDURE Mdct;
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO decState.info.channels - 1 DO
- mdct[decState.mode.blockflag].Backward(decState.floor[i].data)
- END
- END Mdct;
- PROCEDURE DotProduct;
- VAR i, n, chptr: LONGINT;
- residueVal, floorVal: HUGEINT;
- BEGIN
- (* multiply each element of the floor-vector with each element of the residue-vector *)
- n := decState.n DIV 2;
- FOR chptr := 0 TO decState.info.channels - 1 DO
- IF ~decState.doNotDecode[chptr] THEN
- FOR i := 0 TO n - 1 DO
- residueVal := decState.residues[chptr].data[i];
- floorVal := decState.floor[chptr].data[i];
- (* arguments must be in this order *)
- decState.floor[chptr].data[i] := OGGUtilities.MultDotProductFP(residueVal, floorVal);
- END
- ELSE
- decState.floor[chptr].ZeroBuffer()
- END
- END
- END DotProduct;
- PROCEDURE InverseCoupling;
- VAR
- i, j, angIdx, magIdx: LONGINT;
- newM, newA, m, a: HUGEINT; (* all fixed-point *)
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@InverseCoupling()")
- END;
- FOR i := decState.mapping.couplingSteps - 1 TO 0 BY -1 DO
- magIdx := decState.residueNumbers[decState.mapping.magnitude[i]];
- angIdx := decState.residueNumbers[decState.mapping.angle[i]];
- FOR j := 0 TO decState.n DIV 2 - 1 DO
- m := decState.residues[magIdx].data[j];
- a := decState.residues[angIdx].data[j];
- IF (m > 0) THEN
- IF (a > 0) THEN
- newM := m; newA := m - a
- ELSE
- newA := m; newM := m + a
- END
- ELSE
- IF (a > 0) THEN
- newM := m; newA := m + a
- ELSE
- newA := m; newM := m - a
- END
- END;
- decState.residues[magIdx].data[j] := newM;
- decState.residues[angIdx].data[j] := newA;
- END
- END;
- END InverseCoupling;
- PROCEDURE ResidueDecode;
- VAR i, j, residueNr, ch: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@ResidueDecode()")
- END;
- FOR i := 0 TO decState.mapping.submaps - 1 DO
- ch := 0;
- FOR j := 0 TO info.channels - 1 DO
- (* if channel [j] is in submap [i] *)
- IF (decState.mapping.mux[j] = i) THEN
- decState.doNotDecode[j] := decState.noResidue[j];
- INC(ch)
- END
- END;
- residueNr := decState.mapping.submapResidue[i];
- decState.residueType := decState.codec.residueTypes[residueNr];
- decState.codec.residues[residueNr].DecodePacket(bufReader, buf, decState, ch);
- ch := 0;
- FOR j := 0 TO info.channels - 1 DO
- (* if channel [j] is in submap [i] *)
- IF (decState.mapping.mux[j] = i) THEN
- decState.residueNumbers[j] := ch; (* used as an index for the residue-array *)
- INC(ch);
- END
- END (* FOR info.channels *)
- END (* FOR submaps *)
- END ResidueDecode;
- PROCEDURE NonzeroVectorPropagate;
- VAR i, magnitude, angle: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@NonZeroVectorPropagate()")
- END;
- FOR i := 0 TO decState.mapping.couplingSteps - 1 DO
- magnitude := decState.mapping.magnitude[i];
- angle := decState.mapping.angle[i];
- IF (~decState.noResidue[magnitude] OR ~decState.noResidue[angle]) THEN
- decState.noResidue[magnitude] := FALSE;
- decState.noResidue[angle] := FALSE
- END
- END
- END NonzeroVectorPropagate;
- PROCEDURE FloorCurveDecode(): LONGINT;
- VAR
- submapNumber, floorNumber, floorType, i, res: LONGINT;
- floor: AbstractFloorType;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@FloorCurveDecode()")
- END;
- FOR i := 0 TO info.channels - 1 DO
- submapNumber := decState.mapping.mux[i];
- floorNumber := decState.mapping.submapFloor[submapNumber];
- floorType := decState.codec.floorTypes[floorNumber];
- floor := decState.codec.floorConf[floorNumber];
- res := floor.DecodePacket(bufReader, buf, decState);
- IF (res = Ok) THEN
- floor.ComputeCurve(decState, i)
- END;
- decState.noResidue[i] := (res = ChannelNotUsed)
- END;
- RETURN res
- END FloorCurveDecode;
- (* calculate determining points of the window and return the amount of data to be returned *)
- PROCEDURE WindowDecode(VAR res: LONGINT): LONGINT;
- VAR modeNr, previousWindowFlag, nextWindowFlag, previousSize, currentSize: LONGINT;
- BEGIN
- IF (Trace IN Debug) THEN
- OGGUtilities.String("@WindowDecode()")
- END;
- res := Ok;
- modeNr := bufReader.GetBits(buf, OGGUtilities.ILog(decState.codec.modeCnt-1));
- decState.mode := decState.codec.modes[modeNr];
- decState.mapping := decState.codec.mappings[decState.mode.mapping];
- decState.n := info.blocksizes[decState.mode.blockflag];
- currentSize := decState.n;
- (* if end-of-stream (=packet) then return an error *)
- IF ~bufReader.IsOk(buf) THEN
- res := ErrorWindowDecode;
- RETURN 0
- END;
- IF (decState.mode.blockflag = 1) THEN
- (* its a long window *)
- previousWindowFlag := bufReader.GetBits(buf, 1);
- nextWindowFlag := bufReader.GetBits(buf, 1)
- ELSE
- previousWindowFlag := 0;
- nextWindowFlag := 0
- END;
- previousSize := decState.info.blocksizes[decState.lastWindowFlag];
- decState.lastWindowFlag := decState.mode.blockflag;
- decState.win.center := decState.n DIV 2;
- IF ((decState.mode.blockflag = 1) & (previousWindowFlag = 0)) THEN
- (* left side of window is a hybrid window for lapping with a short block *)
- decState.win.leftStart := decState.n DIV 4 - info.blocksizes[0] DIV 4;
- decState.win.leftEnd := decState.n DIV 4 + info.blocksizes[0] DIV 4;
- decState.win.leftSize := info.blocksizes[0] DIV 2
- ELSE
- (* left side will have normal shape *)
- decState.win.leftStart := 0;
- decState.win.leftEnd := decState.win.center;
- decState.win.leftSize := decState.n DIV 2
- END;
- IF ((decState.mode.blockflag = 1) & (nextWindowFlag = 0)) THEN
- (* right side of window is a hybrid window for lapping with a short block *)
- decState.win.rightStart := (decState.n * 3) DIV 4 - info.blocksizes[0] DIV 4;
- decState.win.rightEnd := (decState.n * 3) DIV 4 + info.blocksizes[0] DIV 4;
- decState.win.rightSize := info.blocksizes[0] DIV 2;
- ELSE
- (* right side will have normal shape *)
- decState.win.rightStart := decState.win.center;
- decState.win.rightEnd := decState.n;
- decState.win.rightSize := decState.n DIV 2
- END;
- RETURN (previousSize + currentSize) DIV 4
- END WindowDecode;
- END VorbisDecoder;
- (** DELEGATES *)
- (* delegate for residue-type-specific packet decoding *)
- ResiduePartitionProc = PROCEDURE {DELEGATE} (VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR decSate: DecoderState);
- (* slope-function vorbis window-type 0 *)
- SlopeFunction = PROCEDURE {DELEGATE} (x, n: LONGINT): REAL;
- (** decodes len bytes from the buffer starting at pos to a valid soundOutput *)
- Decoder* = PROCEDURE {DELEGATE} (VAR buf: ARRAY OF CHAR; pos, len: LONGINT; continuedPage: BOOLEAN;
- VAR soundOutput: SoundOutput): LONGINT;
- (* descending part of the window *)
- PROCEDURE SlopeRight(x, n: LONGINT): REAL;
- VAR res: REAL;
- BEGIN
- res := Math.sin( ((n - x - 0.5) / n) * (Math.pi / 2) );
- res := Math.sin( res * res * Math.pi / 2);
- RETURN res
- END SlopeRight;
- (* ascending part of the window *)
- PROCEDURE SlopeLeft(x, n: LONGINT): REAL;
- VAR res: REAL;
- BEGIN
- res := Math.sin( ((x + 0.5) / n) * (Math.pi / 2) );
- res := Math.sin( res * res * Math.pi / 2);
- RETURN res
- END SlopeLeft;
- (* for residue-type 0, used as a delegate *)
- PROCEDURE ResiduePartitionProc0(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR decState: DecoderState);
- VAR
- step, i, j, o, offset, entry, outputVectorNr: LONGINT;
- codebook: Codebook;
- t: OGGUtilities.Vector;
- resInfo: ResidueInfo;
- BEGIN
- resInfo := decState.resInfo;
- NEW(t);
- codebook := decState.codec.codebooks[resInfo.codebookNr];
- offset := resInfo.offset;
- outputVectorNr := resInfo.outputVectorNr;
- step := resInfo.partitionSize DIV codebook.dimensions;
- FOR i := 0 TO step - 1 DO
- entry := codebook.GetCodeword(bufReader, buf);
- t.Add(entry * codebook.dimensions)
- END;
- i := 0;
- o := 0;
- WHILE (i < codebook.dimensions) DO
- FOR j := 0 TO step - 1 DO
- INC(decState.residues[outputVectorNr].data[offset + o + j], codebook.valuelistFP[t.GetValueAt(j) + i])
- END;
- INC(o, step);
- INC(i)
- END
- END ResiduePartitionProc0;
- (* for residue-type 1, used as a delegate *)
- PROCEDURE ResiduePartitionProc1(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR decState: DecoderState);
- VAR
- i, j, t, outputVectorNr, offset, entry: LONGINT;
- codebook: Codebook;
- resInfo: ResidueInfo;
- BEGIN
- resInfo := decState.resInfo;
- codebook := decState.codec.codebooks[resInfo.codebookNr];
- outputVectorNr := resInfo.outputVectorNr;
- offset := resInfo.offset;
- WHILE (i < resInfo.partitionSize) DO
- entry := codebook.GetCodeword(bufReader, buf);
- t := entry * codebook.dimensions;
- j := 0;
- WHILE (j < codebook.dimensions) DO
- INC(decState.residues[outputVectorNr].data[offset + i], codebook.valuelistFP[t + j]);
- INC(j);
- INC(i)
- END
- END
- END ResiduePartitionProc1;
- (* for residue-type 2, used as a delegate *)
- PROCEDURE ResiduePartitionProc2(VAR bufReader: BufferReader; VAR buf: ARRAY OF CHAR;
- VAR decState: DecoderState);
- VAR i, j, entry, chptr, t, ch, offset, n, dim: LONGINT;
- cb: Codebook;
- resInfo: ResidueInfo;
- BEGIN
- resInfo := decState.resInfo;
- chptr := 0;
- cb := decState.codec.codebooks[resInfo.codebookNr];
- ch := resInfo.ch;
- offset := resInfo.offset;
- n := resInfo.partitionSize;
- dim := cb.dimensions;
- i := offset DIV resInfo.ch;
- WHILE (i < (offset + n) DIV ch) DO
- entry := cb.GetCodeword(bufReader, buf);
- t := entry * dim;
- FOR j := 0 TO dim - 1 DO
- INC(decState.residues[chptr].data[i], cb.valuelistFP[t + j]);
- INC(chptr);
- IF (chptr = ch) THEN
- chptr := 0;
- INC(i)
- END
- END
- END
- END ResiduePartitionProc2;
- (* lookup table for calculated floor values *)
- PROCEDURE InitInverseDBLookup;
- VAR InverseDBLookupReal: ARRAY 256 OF REAL;
- i: LONGINT;
- BEGIN
- InverseDBLookupReal[0] := 0.00000010649863;
- InverseDBLookupReal[1] := 0.00000011341951;
- InverseDBLookupReal[2] := 0.00000012079015;
- InverseDBLookupReal[3] := 0.00000012863978;
- InverseDBLookupReal[4] := 0.00000013699951;
- InverseDBLookupReal[5] := 0.00000014590251;
- InverseDBLookupReal[6] := 0.00000015538408;
- InverseDBLookupReal[7] := 0.00000016548181;
- InverseDBLookupReal[8] := 0.00000017623575;
- InverseDBLookupReal[9] := 0.00000018768855;
- InverseDBLookupReal[10] := 0.00000019988561;
- InverseDBLookupReal[11] := 0.0000002128753;
- InverseDBLookupReal[12] := 0.00000022670913;
- InverseDBLookupReal[13] := 0.00000024144197;
- InverseDBLookupReal[14] := 0.00000025713223;
- InverseDBLookupReal[15] := 0.00000027384213;
- InverseDBLookupReal[16] := 0.00000029163793;
- InverseDBLookupReal[17] := 0.00000031059021;
- InverseDBLookupReal[18] := 0.00000033077411;
- InverseDBLookupReal[19] := 0.00000035226968;
- InverseDBLookupReal[20] := 0.00000037516214;
- InverseDBLookupReal[21] := 0.00000039954229;
- InverseDBLookupReal[22] := 0.0000004255068;
- InverseDBLookupReal[23] := 0.00000045315863;
- InverseDBLookupReal[24] := 0.00000048260743;
- InverseDBLookupReal[25] := 0.00000051396998;
- InverseDBLookupReal[26] := 0.00000054737065;
- InverseDBLookupReal[27] := 0.00000058294187;
- InverseDBLookupReal[28] := 0.00000062082472;
- InverseDBLookupReal[29] := 0.00000066116941;
- InverseDBLookupReal[30] := 0.00000070413592;
- InverseDBLookupReal[31] := 0.00000074989464;
- InverseDBLookupReal[32] := 0.00000079862701;
- InverseDBLookupReal[33] := 0.0000008505263;
- InverseDBLookupReal[34] := 0.00000090579828;
- InverseDBLookupReal[35] := 0.00000096466216;
- InverseDBLookupReal[36] := 0.0000010273513;
- InverseDBLookupReal[37] := 0.0000010941144;
- InverseDBLookupReal[38] := 0.0000011652161;
- InverseDBLookupReal[39] := 0.0000012409384;
- InverseDBLookupReal[40] := 0.0000013215816;
- InverseDBLookupReal[41] := 0.0000014074654;
- InverseDBLookupReal[42] := 0.0000014989305;
- InverseDBLookupReal[43] := 0.0000015963394;
- InverseDBLookupReal[44] := 0.0000017000785;
- InverseDBLookupReal[45] := 0.0000018105592;
- InverseDBLookupReal[46] := 0.0000019282195;
- InverseDBLookupReal[47] := 0.0000020535261;
- InverseDBLookupReal[48] := 0.0000021869758;
- InverseDBLookupReal[49] := 0.0000023290978;
- InverseDBLookupReal[50] := 0.0000024804557;
- InverseDBLookupReal[51] := 0.0000026416497;
- InverseDBLookupReal[52] := 0.000002813319;
- InverseDBLookupReal[53] := 0.0000029961443;
- InverseDBLookupReal[54] := 0.0000031908506;
- InverseDBLookupReal[55] := 0.0000033982101;
- InverseDBLookupReal[56] := 0.0000036190449;
- InverseDBLookupReal[57] := 0.0000038542308;
- InverseDBLookupReal[58] := 0.0000041047004;
- InverseDBLookupReal[59] := 0.000004371447;
- InverseDBLookupReal[60] := 0.0000046555282;
- InverseDBLookupReal[61] := 0.0000049580707;
- InverseDBLookupReal[62] := 0.000005280274;
- InverseDBLookupReal[63] := 0.000005623416;
- InverseDBLookupReal[64] := 0.0000059888572;
- InverseDBLookupReal[65] := 0.0000063780469;
- InverseDBLookupReal[66] := 0.0000067925283;
- InverseDBLookupReal[67] := 0.0000072339451;
- InverseDBLookupReal[68] := 0.0000077040476;
- InverseDBLookupReal[69] := 0.0000082047;
- InverseDBLookupReal[70] := 0.0000087378876;
- InverseDBLookupReal[71] := 0.0000093057248;
- InverseDBLookupReal[72] := 0.0000099104632;
- InverseDBLookupReal[73] := 0.000010554501;
- InverseDBLookupReal[74] := 0.000011240392;
- InverseDBLookupReal[75] := 0.000011970856;
- InverseDBLookupReal[76] := 0.000012748789;
- InverseDBLookupReal[77] := 0.000013577278;
- InverseDBLookupReal[78] := 0.000014459606;
- InverseDBLookupReal[79] := 0.000015399272;
- InverseDBLookupReal[80] := 0.000016400004;
- InverseDBLookupReal[81] := 0.000017465768;
- InverseDBLookupReal[82] := 0.000018600792;
- InverseDBLookupReal[83] := 0.000019809576;
- InverseDBLookupReal[84] := 0.000021096914;
- InverseDBLookupReal[85] := 0.000022467911;
- InverseDBLookupReal[86] := 0.000023928002;
- InverseDBLookupReal[87] := 0.000025482978;
- InverseDBLookupReal[88] := 0.000027139006;
- InverseDBLookupReal[89] := 0.000028902651;
- InverseDBLookupReal[90] := 0.000030780908;
- InverseDBLookupReal[91] := 0.000032781225;
- InverseDBLookupReal[92] := 0.000034911534;
- InverseDBLookupReal[93] := 0.000037180282;
- InverseDBLookupReal[94] := 0.000039596466;
- InverseDBLookupReal[95] := 0.000042169667;
- InverseDBLookupReal[96] := 0.00004491009;
- InverseDBLookupReal[97] := 0.000047828601;
- InverseDBLookupReal[98] := 0.000050936773;
- InverseDBLookupReal[99] := 0.000054246931;
- InverseDBLookupReal[100] := 0.000057772202;
- InverseDBLookupReal[101] := 0.000061526565;
- InverseDBLookupReal[102] := 0.000065524908;
- InverseDBLookupReal[103] := 0.000069783085;
- InverseDBLookupReal[104] := 0.000074317983;
- InverseDBLookupReal[105] := 0.000079147585;
- InverseDBLookupReal[106] := 0.00008429104;
- InverseDBLookupReal[107] := 0.000089768747;
- InverseDBLookupReal[108] := 0.000095602426;
- InverseDBLookupReal[109] := 0.00010181521;
- InverseDBLookupReal[110] := 0.00010843174;
- InverseDBLookupReal[111] := 0.00011547824;
- InverseDBLookupReal[112] := 0.00012298267;
- InverseDBLookupReal[113] := 0.00013097477;
- InverseDBLookupReal[114] := 0.00013948625;
- InverseDBLookupReal[115] := 0.00014855085;
- InverseDBLookupReal[116] := 0.00015820453;
- InverseDBLookupReal[117] := 0.00016848555;
- InverseDBLookupReal[118] := 0.00017943469;
- InverseDBLookupReal[119] := 0.00019109536;
- InverseDBLookupReal[120] := 0.00020351382;
- InverseDBLookupReal[121] := 0.00021673929;
- InverseDBLookupReal[122] := 0.00023082423;
- InverseDBLookupReal[123] := 0.00024582449;
- InverseDBLookupReal[124] := 0.00026179955;
- InverseDBLookupReal[125] := 0.00027881276;
- InverseDBLookupReal[126] := 0.00029693158;
- InverseDBLookupReal[127] := 0.00031622787;
- InverseDBLookupReal[128] := 0.00033677814;
- InverseDBLookupReal[129] := 0.00035866388;
- InverseDBLookupReal[130] := 0.00038197188;
- InverseDBLookupReal[131] := 0.00040679456;
- InverseDBLookupReal[132] := 0.00043323036;
- InverseDBLookupReal[133] := 0.00046138411;
- InverseDBLookupReal[134] := 0.00049136745;
- InverseDBLookupReal[135] := 0.00052329927;
- InverseDBLookupReal[136] := 0.00055730621;
- InverseDBLookupReal[137] := 0.00059352311;
- InverseDBLookupReal[138] := 0.00063209358;
- InverseDBLookupReal[139] := 0.00067317058;
- InverseDBLookupReal[140] := 0.000716917;
- InverseDBLookupReal[141] := 0.0007635063;
- InverseDBLookupReal[142] := 0.00081312324;
- InverseDBLookupReal[143] := 0.00086596457;
- InverseDBLookupReal[144] := 0.00092223983;
- InverseDBLookupReal[145] := 0.00098217216;
- InverseDBLookupReal[146] := 0.0010459992;
- InverseDBLookupReal[147] := 0.0011139742;
- InverseDBLookupReal[148] := 0.0011863665;
- InverseDBLookupReal[149] := 0.0012634633;
- InverseDBLookupReal[150] := 0.0013455702;
- InverseDBLookupReal[151] := 0.0014330129;
- InverseDBLookupReal[152] := 0.0015261382;
- InverseDBLookupReal[153] := 0.0016253153;
- InverseDBLookupReal[154] := 0.0017309374;
- InverseDBLookupReal[155] := 0.0018434235;
- InverseDBLookupReal[156] := 0.0019632195;
- InverseDBLookupReal[157] := 0.0020908006;
- InverseDBLookupReal[158] := 0.0022266726;
- InverseDBLookupReal[159] := 0.0023713743;
- InverseDBLookupReal[160] := 0.0025254795;
- InverseDBLookupReal[161] := 0.0026895994;
- InverseDBLookupReal[162] := 0.0028643847;
- InverseDBLookupReal[163] := 0.0030505286;
- InverseDBLookupReal[164] := 0.0032487691;
- InverseDBLookupReal[165] := 0.0034598925;
- InverseDBLookupReal[166] := 0.0036847358;
- InverseDBLookupReal[167] := 0.0039241906;
- InverseDBLookupReal[168] := 0.0041792066;
- InverseDBLookupReal[169] := 0.004450795;
- InverseDBLookupReal[170] := 0.0047400328;
- InverseDBLookupReal[171] := 0.0050480668;
- InverseDBLookupReal[172] := 0.0053761186;
- InverseDBLookupReal[173] := 0.0057254891;
- InverseDBLookupReal[174] := 0.0060975636;
- InverseDBLookupReal[175] := 0.0064938176;
- InverseDBLookupReal[176] := 0.0069158225;
- InverseDBLookupReal[177] := 0.0073652516;
- InverseDBLookupReal[178] := 0.0078438871;
- InverseDBLookupReal[179] := 0.0083536271;
- InverseDBLookupReal[180] := 0.0088964928;
- InverseDBLookupReal[181] := 0.009474637;
- InverseDBLookupReal[182] := 0.010090352;
- InverseDBLookupReal[183] := 0.01074608;
- InverseDBLookupReal[184] := 0.011444421;
- InverseDBLookupReal[185] := 0.012188144;
- InverseDBLookupReal[186] := 0.012980198;
- InverseDBLookupReal[187] := 0.013823725;
- InverseDBLookupReal[188] := 0.014722068;
- InverseDBLookupReal[189] := 0.015678791;
- InverseDBLookupReal[190] := 0.016697687;
- InverseDBLookupReal[191] := 0.017782797;
- InverseDBLookupReal[192] := 0.018938423;
- InverseDBLookupReal[193] := 0.020169149;
- InverseDBLookupReal[194] := 0.021479854;
- InverseDBLookupReal[195] := 0.022875735;
- InverseDBLookupReal[196] := 0.02436233;
- InverseDBLookupReal[197] := 0.025945531;
- InverseDBLookupReal[198] := 0.027631618;
- InverseDBLookupReal[199] := 0.029427276;
- InverseDBLookupReal[200] := 0.031339626;
- InverseDBLookupReal[201] := 0.033376252;
- InverseDBLookupReal[202] := 0.035545228;
- InverseDBLookupReal[203] := 0.037855157;
- InverseDBLookupReal[204] := 0.040315199;
- InverseDBLookupReal[205] := 0.042935108;
- InverseDBLookupReal[206] := 0.045725273;
- InverseDBLookupReal[207] := 0.048696758;
- InverseDBLookupReal[208] := 0.051861348;
- InverseDBLookupReal[209] := 0.055231591;
- InverseDBLookupReal[210] := 0.05882085;
- InverseDBLookupReal[211] := 0.062643361;
- InverseDBLookupReal[212] := 0.066714279;
- InverseDBLookupReal[213] := 0.071049749;
- InverseDBLookupReal[214] := 0.075666962;
- InverseDBLookupReal[215] := 0.080584227;
- InverseDBLookupReal[216] := 0.085821044;
- InverseDBLookupReal[217] := 0.091398179;
- InverseDBLookupReal[218] := 0.097337747;
- InverseDBLookupReal[219] := 0.1036633;
- InverseDBLookupReal[220] := 0.11039993;
- InverseDBLookupReal[221] := 0.11757434;
- InverseDBLookupReal[222] := 0.12521498;
- InverseDBLookupReal[223] := 0.13335215;
- InverseDBLookupReal[224] := 0.14201813;
- InverseDBLookupReal[225] := 0.15124727;
- InverseDBLookupReal[226] := 0.16107617;
- InverseDBLookupReal[227] := 0.1715438;
- InverseDBLookupReal[228] := 0.18269168;
- InverseDBLookupReal[229] := 0.19456402;
- InverseDBLookupReal[230] := 0.20720788;
- InverseDBLookupReal[231] := 0.22067342;
- InverseDBLookupReal[232] := 0.23501402;
- InverseDBLookupReal[233] := 0.25028656;
- InverseDBLookupReal[234] := 0.26655159;
- InverseDBLookupReal[235] := 0.28387361;
- InverseDBLookupReal[236] := 0.30232132;
- InverseDBLookupReal[237] := 0.32196786;
- InverseDBLookupReal[238] := 0.34289114;
- InverseDBLookupReal[239] := 0.36517414;
- InverseDBLookupReal[240] := 0.38890521;
- InverseDBLookupReal[241] := 0.41417847;
- InverseDBLookupReal[242] := 0.44109412;
- InverseDBLookupReal[243] := 0.4697589;
- InverseDBLookupReal[244] := 0.50028648;
- InverseDBLookupReal[245] := 0.53279791;
- InverseDBLookupReal[246] := 0.56742212;
- InverseDBLookupReal[247] := 0.6042964;
- InverseDBLookupReal[248] := 0.64356699;
- InverseDBLookupReal[249] := 0.68538959;
- InverseDBLookupReal[250] := 0.72993007;
- InverseDBLookupReal[251] := 0.77736504;
- InverseDBLookupReal[252] := 0.8278826;
- InverseDBLookupReal[253] := 0.88168307;
- InverseDBLookupReal[254] := 0.9389798;
- InverseDBLookupReal[255] := 1;
- (* scale the values according to current scale factor*)
- FOR i := 0 TO 255 DO
- InverseDBLookup[i] := OGGUtilities.ScaleUp(InverseDBLookupReal[i])
- END
- END InitInverseDBLookup;
- (** Tools *)
- (** start playing an ogg-stream
- = possible arguments are:
- - ogg/vorbis-file
- - URL of a ogg/vorbis radio-station ( *.ogg or *.m3u)
- = no need to stop any old sources
- *)
- PROCEDURE PlayURL*(url: Strings.String): BOOLEAN;
- VAR
- isWebStream: BOOLEAN;
- dec: VorbisDecoder;
- ogg: OggStreamReader;
- f: Files.File;
- fr: Files.Reader;
- r : Streams.Reader;
- output: SoundOutput;
- rh : WebHTTP.RequestHeader;
- h : WebHTTP.ResponseHeader;
- res, volume, nrOfBuffers: LONGINT;
- con : TCP.Connection;
- outputFilename: ARRAY 64 OF CHAR;
- timer: Kernel.Timer;
- BEGIN
- IF playing THEN
- (* if it's already playing sth, stop old song and start new one *)
- stopped := TRUE;
- NEW(timer);
- timer.Sleep(1000);
- END;
- IF ~playing THEN
- (* prepare playing *)
- NEW(dec);
- nrOfBuffers := 32;
- volume := 55;
- NEW(output, nrOfBuffers, volume);
- IF IsWebStream(url) THEN
- (* streaming from the internet *)
- IF IsM3UPlaylist(url) THEN
- GetURLFromM3U(url)
- END;
- (* if interpretation failed (it's still a m3u) for some reason exit *)
- IF IsM3UPlaylist(url) THEN
- KernelLog.String("can not interpret m3u-playlist - exiting"); KernelLog.Ln;
- RETURN FALSE
- END;
- KernelLog.String("playing ogg-radio: "); KernelLog.String(url^); KernelLog.Ln;
- isWebStream := TRUE;
- rh.useragent := "Bluebottle OGG Player/0.1";
- WebHTTPClient.Get(url^, rh, con, h, r, res);
- IF res # 0 THEN
- KernelLog.String("Could not open stream");
- KernelLog.Ln;
- RETURN FALSE
- END
- ELSE
- (* playing from a local file *)
- isWebStream := FALSE;
- KernelLog.String("playing ogg-soundfile: "); KernelLog.String(url^); KernelLog.Ln;
- IF (output IS FileOutput) THEN
- Strings.Append(outputFilename, url^);
- Strings.Append(outputFilename, ".pcm");
- KernelLog.String(outputFilename); KernelLog.Ln;
- output(FileOutput).SetFilename(outputFilename)
- END;
- f := Files.Old(url^);
- Files.OpenReader(fr, f, 0);
- r := fr;
- IF r = NIL THEN
- KernelLog.String("Could not open file");
- KernelLog.Ln;
- RETURN FALSE
- END
- END;
- (* allocate an OggStreamReader ... *)
- NEW(ogg, r);
- (* ... and start playing *)
- res:= ogg.RegisterDecoder(dec.Decode, output, Vorbis);
- IF res = Ok THEN
- playing := TRUE;
- res := ogg.Start();
- playing := FALSE;
- stopped := FALSE
- END;
- ogg.Stop()
- (* finished playing *)
- ELSE
- KernelLog.String("is already playing something"); KernelLog.Ln
- END;
- (* close tcp-connection if any *)
- IF con # NIL THEN
- KernelLog.String("closing connection"); KernelLog.Ln;
- con.Close()
- END;
- RETURN TRUE;
- END PlayURL;
- (** start playing an ogg-stream
- = possible arguments ("command line") are:
- - ogg/vorbis-file
- - URL of a ogg/vorbis radio-station ( *.ogg or *.m3u)
- = no need to stop any old sources
- *)
- PROCEDURE Play*(context : Commands.Context);
- VAR
- url: ARRAY 256 OF CHAR;
- tmpBool: BOOLEAN;
- BEGIN
- context.arg.String(url);
- tmpBool := PlayURL(Strings.NewString(url));
- END Play;
- PROCEDURE StopURL*;
- BEGIN
- stopped := TRUE
- END StopURL;
- PROCEDURE Stop*(context : Commands.Context);
- BEGIN
- StopURL();
- context.out.String("Player stopped."); context.out.Ln;
- END Stop;
- PROCEDURE IsWebStream(VAR url: Strings.String): BOOLEAN;
- BEGIN
- RETURN Strings.Pos("http://", url^) > -1
- END IsWebStream;
- PROCEDURE IsM3UPlaylist(VAR url: Strings.String): BOOLEAN;
- BEGIN
- RETURN Strings.Pos(".m3u", url^) > -1
- END IsM3UPlaylist;
- PROCEDURE GetURLFromM3U(VAR url: Strings.String);
- VAR res: LONGINT;
- rh : WebHTTP.RequestHeader;
- h : WebHTTP.ResponseHeader;
- con : TCP.Connection;
- r : Streams.Reader;
- BEGIN
- WebHTTPClient.Get(url^, rh, con, h, r, res);
- r.Token(url^)
- END GetURLFromM3U;
- PROCEDURE Cleanup;
- VAR
- timer: Kernel.Timer;
- BEGIN
- NEW(timer);
- stopped := TRUE;
- (* give some time to close the sound-channel properly *)
- timer.Sleep(2000);
- END Cleanup;
- BEGIN
- Modules.InstallTermHandler(Cleanup);
- FloorRanges[0] := 256;
- FloorRanges[1] := 128;
- FloorRanges[2] := 86;
- FloorRanges[3] := 64;
- OggS[0] := "O";
- OggS[1] := "g";
- OggS[2] := "g";
- OggS[3] := "S";
- nrOfPages := 0;
- stopped := FALSE;
- playing := FALSE;
- InitInverseDBLookup;
- OGGUtilities.InitLogger;
- END OGGVorbisPlayer.
- SystemTools.Free WMOGGPlayer OGGVorbisPlayer OGGUtilities ~
- MixerComponents.MasterIncVol ~
- MixerComponents.MasterDecVol ~
- OGGVorbisPlayer.Stop ~
- #Free Audio
- OGGVorbisPlayer.Play epoq.ogg ~
- OGGVorbisPlayer.Play hydrate.ogg ~
- OGGVorbisPlayer.Play mistoftime.ogg ~
- OGGVorbisPlayer.Play lumme.ogg ~
|