]> gitweb.factorcode.org Git - factor.git/commitdiff
update ogg player for new accessors, delegation. sound is broken
authorDoug Coleman <doug.coleman@gmail.com>
Thu, 11 Sep 2008 02:11:24 +0000 (21:11 -0500)
committerDoug Coleman <doug.coleman@gmail.com>
Thu, 11 Sep 2008 02:11:24 +0000 (21:11 -0500)
16 files changed:
extra/ogg/authors.txt [new file with mode: 0644]
extra/ogg/ogg.factor [new file with mode: 0644]
extra/ogg/player/authors.txt [new file with mode: 0644]
extra/ogg/player/player.factor [new file with mode: 0755]
extra/ogg/player/summary.txt [new file with mode: 0644]
extra/ogg/player/tags.txt [new file with mode: 0644]
extra/ogg/summary.txt [new file with mode: 0644]
extra/ogg/tags.txt [new file with mode: 0644]
extra/ogg/theora/authors.txt [new file with mode: 0644]
extra/ogg/theora/summary.txt [new file with mode: 0644]
extra/ogg/theora/tags.txt [new file with mode: 0644]
extra/ogg/theora/theora.factor [new file with mode: 0644]
extra/ogg/vorbis/authors.txt [new file with mode: 0644]
extra/ogg/vorbis/summary.txt [new file with mode: 0644]
extra/ogg/vorbis/tags.txt [new file with mode: 0644]
extra/ogg/vorbis/vorbis.factor [new file with mode: 0644]

diff --git a/extra/ogg/authors.txt b/extra/ogg/authors.txt
new file mode 100644 (file)
index 0000000..44b06f9
--- /dev/null
@@ -0,0 +1 @@
+Chris Double
diff --git a/extra/ogg/ogg.factor b/extra/ogg/ogg.factor
new file mode 100644 (file)
index 0000000..37dd30f
--- /dev/null
@@ -0,0 +1,132 @@
+! Copyright (C) 2007 Chris Double.
+! See http://factorcode.org/license.txt for BSD license.
+!
+USING: kernel system combinators alien alien.syntax ;
+IN: ogg
+
+<<
+"ogg" {
+    { [ os winnt? ]  [ "ogg.dll" ] }
+    { [ os macosx? ] [ "libogg.0.dylib" ] }
+    { [ os unix? ]   [ "libogg.so" ] }
+} cond "cdecl" add-library
+>>
+
+LIBRARY: ogg
+
+C-STRUCT: oggpack_buffer
+    { "long" "endbyte" }
+    { "int" "endbit" }
+    { "uchar*" "buffer" }
+    { "uchar*" "ptr" }
+    { "long" "storage" } ;
+
+C-STRUCT: ogg_page
+    { "uchar*" "header" }
+    { "long" "header_len" }
+    { "uchar*" "body" }
+    { "long" "body_len" } ;
+
+C-STRUCT: ogg_stream_state
+    { "uchar*" "body_data" }
+    { "long" "body_storage" }
+    { "long" "body_fill" }
+    { "long" "body_returned" }
+    { "int*" "lacing_vals" } 
+    { "longlong*" "granule_vals" }
+    { "long" "lacing_storage" }
+    { "long" "lacing_fill" }
+    { "long" "lacing_packet" }
+    { "long" "lacing_returned" }
+    { { "uchar" 282 } "header" }
+    { "int" "header_fill" }
+    { "int" "e_o_s" }
+    { "int" "b_o_s" }
+    { "long" "serialno" }
+    { "long" "pageno" }
+    { "longlong" "packetno" }
+    { "longlong" "granulepos" } ;
+
+C-STRUCT: ogg_packet
+    { "uchar*" "packet" }
+    { "long" "bytes" }
+    { "long" "b_o_s" }
+    { "long" "e_o_s" }
+    { "longlong" "granulepos" }
+    { "longlong" "packetno" } ;
+
+C-STRUCT: ogg_sync_state
+    { "uchar*" "data" }
+    { "int" "storage" }
+    { "int" "fill" }  
+    { "int" "returned" }
+    { "int" "unsynced" }
+    { "int" "headerbytes" }
+    { "int" "bodybytes" } ;
+
+FUNCTION: void oggpack_writeinit ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpack_writetrunc ( oggpack_buffer* b, long bits ) ;
+FUNCTION: void  oggpack_writealign ( oggpack_buffer* b) ;
+FUNCTION: void  oggpack_writecopy ( oggpack_buffer* b, void* source, long bits ) ;
+FUNCTION: void  oggpack_reset ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpack_writeclear ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpack_readinit ( oggpack_buffer* b, uchar* buf, int bytes ) ;
+FUNCTION: void  oggpack_write ( oggpack_buffer* b, ulong value, int bits ) ;
+FUNCTION: long  oggpack_look ( oggpack_buffer* b, int bits ) ;
+FUNCTION: long  oggpack_look1 ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpack_adv ( oggpack_buffer* b, int bits ) ;
+FUNCTION: void  oggpack_adv1 ( oggpack_buffer* b ) ;
+FUNCTION: long  oggpack_read ( oggpack_buffer* b, int bits ) ;
+FUNCTION: long  oggpack_read1 ( oggpack_buffer* b ) ;
+FUNCTION: long  oggpack_bytes ( oggpack_buffer* b ) ;
+FUNCTION: long  oggpack_bits ( oggpack_buffer* b ) ;
+FUNCTION: uchar* oggpack_get_buffer ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpackB_writeinit ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpackB_writetrunc ( oggpack_buffer* b, long bits ) ;
+FUNCTION: void  oggpackB_writealign ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpackB_writecopy ( oggpack_buffer* b, void* source, long bits ) ;
+FUNCTION: void  oggpackB_reset ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpackB_writeclear ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpackB_readinit ( oggpack_buffer* b, uchar* buf, int bytes ) ;
+FUNCTION: void  oggpackB_write ( oggpack_buffer* b, ulong value, int bits ) ;
+FUNCTION: long  oggpackB_look ( oggpack_buffer* b, int bits ) ;
+FUNCTION: long  oggpackB_look1 ( oggpack_buffer* b ) ;
+FUNCTION: void  oggpackB_adv ( oggpack_buffer* b, int bits ) ;
+FUNCTION: void  oggpackB_adv1 ( oggpack_buffer* b ) ;
+FUNCTION: long  oggpackB_read ( oggpack_buffer* b, int bits ) ;
+FUNCTION: long  oggpackB_read1 ( oggpack_buffer* b ) ;
+FUNCTION: long  oggpackB_bytes ( oggpack_buffer* b ) ;
+FUNCTION: long  oggpackB_bits ( oggpack_buffer* b ) ;
+FUNCTION: uchar* oggpackB_get_buffer ( oggpack_buffer* b ) ;
+FUNCTION: int      ogg_stream_packetin ( ogg_stream_state* os, ogg_packet* op ) ;
+FUNCTION: int      ogg_stream_pageout ( ogg_stream_state* os, ogg_page* og ) ;
+FUNCTION: int      ogg_stream_flush ( ogg_stream_state* os, ogg_page* og ) ;
+FUNCTION: int      ogg_sync_init ( ogg_sync_state* oy ) ;
+FUNCTION: int      ogg_sync_clear ( ogg_sync_state* oy ) ;
+FUNCTION: int      ogg_sync_reset ( ogg_sync_state* oy ) ;
+FUNCTION: int   ogg_sync_destroy ( ogg_sync_state* oy ) ;
+
+FUNCTION: void* ogg_sync_buffer ( ogg_sync_state* oy, long size ) ;
+FUNCTION: int      ogg_sync_wrote ( ogg_sync_state* oy, long bytes ) ;
+FUNCTION: long     ogg_sync_pageseek ( ogg_sync_state* oy, ogg_page* og ) ;
+FUNCTION: int      ogg_sync_pageout ( ogg_sync_state* oy, ogg_page* og ) ;
+FUNCTION: int      ogg_stream_pagein ( ogg_stream_state* os, ogg_page* og ) ;
+FUNCTION: int      ogg_stream_packetout ( ogg_stream_state* os, ogg_packet* op ) ;
+FUNCTION: int      ogg_stream_packetpeek ( ogg_stream_state* os, ogg_packet* op ) ;
+FUNCTION: int      ogg_stream_init (ogg_stream_state* os, int serialno ) ;
+FUNCTION: int      ogg_stream_clear ( ogg_stream_state* os ) ;
+FUNCTION: int      ogg_stream_reset ( ogg_stream_state* os ) ;
+FUNCTION: int      ogg_stream_reset_serialno ( ogg_stream_state* os, int serialno ) ;
+FUNCTION: int      ogg_stream_destroy ( ogg_stream_state* os ) ;
+FUNCTION: int      ogg_stream_eos ( ogg_stream_state* os ) ;
+FUNCTION: void     ogg_page_checksum_set ( ogg_page* og ) ;
+FUNCTION: int      ogg_page_version ( ogg_page* og ) ;
+FUNCTION: int      ogg_page_continued ( ogg_page* og ) ;
+FUNCTION: int      ogg_page_bos ( ogg_page* og ) ;
+FUNCTION: int      ogg_page_eos ( ogg_page* og ) ;
+FUNCTION: longlong  ogg_page_granulepos ( ogg_page* og ) ;
+FUNCTION: int      ogg_page_serialno ( ogg_page* og ) ;
+FUNCTION: long     ogg_page_pageno ( ogg_page* og ) ;
+FUNCTION: int      ogg_page_packets ( ogg_page* og ) ;
+FUNCTION: void     ogg_packet_clear ( ogg_packet* op ) ;
+
diff --git a/extra/ogg/player/authors.txt b/extra/ogg/player/authors.txt
new file mode 100644 (file)
index 0000000..44b06f9
--- /dev/null
@@ -0,0 +1 @@
+Chris Double
diff --git a/extra/ogg/player/player.factor b/extra/ogg/player/player.factor
new file mode 100755 (executable)
index 0000000..2204aa4
--- /dev/null
@@ -0,0 +1,631 @@
+! Copyright (C) 2007 Chris Double.\r
+! See http://factorcode.org/license.txt for BSD license.\r
+!\r
+! TODO:\r
+!   based on number of channels in file.\r
+! - End of decoding is indicated by an exception when reading the stream.\r
+!   How to work around this? C player example uses feof but streams don't\r
+!   have that in Factor.\r
+! - Work out openal buffer method that plays nicely with streaming over\r
+!   slow connections.\r
+! - Have start/stop/seek methods on the player object.\r
+!\r
+USING: kernel alien ogg ogg.vorbis ogg.theora io byte-arrays\r
+       sequences libc shuffle alien.c-types system openal math\r
+       namespaces threads shuffle opengl arrays ui.gadgets.worlds\r
+       combinators math.parser ui.gadgets ui.render opengl.gl ui\r
+       continuations io.files hints combinators.lib sequences.lib\r
+       io.encodings.binary debugger math.order accessors ;\r
+\r
+IN: ogg.player\r
+\r
+: audio-buffer-size ( -- number ) 128 1024 * ; inline\r
+\r
+TUPLE: player stream temp-state\r
+       op oy og\r
+       vo vi vd vb vc vorbis\r
+       to ti tc td yuv rgb theora video-ready? video-time video-granulepos\r
+       source buffers buffer-indexes start-time\r
+       playing? audio-full? audio-index audio-buffer audio-granulepos\r
+       gadget ;\r
+\r
+: init-vorbis ( player -- )\r
+    dup oy>> ogg_sync_init drop\r
+    dup vi>> vorbis_info_init\r
+    vc>> vorbis_comment_init ;\r
+\r
+: init-theora ( player -- )\r
+    dup ti>> theora_info_init\r
+    tc>> theora_comment_init ;\r
+\r
+: init-sound ( player -- )\r
+    init-openal check-error\r
+    1 gen-buffers check-error >>buffers\r
+    2 "uint" <c-array> >>buffer-indexes\r
+    1 gen-sources check-error first >>source drop ;\r
+\r
+: <player> ( stream -- player )\r
+    player new\r
+        swap >>stream\r
+        0 >>vorbis\r
+        0 >>theora\r
+        0 >>video-time\r
+        0 >>video-granulepos\r
+        f >>video-ready?\r
+        f >>audio-full?\r
+        0 >>audio-index\r
+        0 >>start-time\r
+        audio-buffer-size "short" <c-array> >>audio-buffer\r
+        0 >>audio-granulepos\r
+        f >>playing?\r
+        "ogg_packet" malloc-object >>op\r
+        "ogg_sync_state" malloc-object >>oy\r
+        "ogg_page" malloc-object >>og\r
+        "ogg_stream_state" malloc-object >>vo\r
+        "vorbis_info" malloc-object >>vi\r
+        "vorbis_dsp_state" malloc-object >>vd\r
+        "vorbis_block" malloc-object >>vb\r
+        "vorbis_comment" malloc-object >>vc\r
+        "ogg_stream_state" malloc-object >>to\r
+        "theora_info" malloc-object >>ti\r
+        "theora_comment" malloc-object >>tc\r
+        "theora_state" malloc-object >>td\r
+        "yuv_buffer" <c-object> >>yuv\r
+        "ogg_stream_state" <c-object> >>temp-state\r
+        dup init-sound\r
+        dup init-vorbis\r
+        dup init-theora ;\r
+\r
+: num-channels ( player -- channels )\r
+    vi>> vorbis_info-channels ;\r
+\r
+: al-channel-format ( player -- format )\r
+    num-channels 1 = AL_FORMAT_MONO16 AL_FORMAT_STEREO16 ? ;\r
+\r
+: get-time ( player -- time )\r
+    dup start-time>> zero? [\r
+        millis >>start-time\r
+    ] when\r
+    start-time>> millis swap - 1000.0 /f ;\r
+\r
+: clamp ( n -- n )\r
+    255 min 0 max ; inline\r
+\r
+: stride ( line yuv  -- uvy yy )\r
+    [ yuv_buffer-uv_stride >fixnum swap 2/ * ] 2keep\r
+    yuv_buffer-y_stride >fixnum * >fixnum ; inline\r
+\r
+: each-with4 ( obj obj obj obj seq quot -- )\r
+    4 each-withn ; inline\r
+\r
+: compute-y ( yuv uvy yy x -- y )\r
+    + >fixnum nip swap yuv_buffer-y uchar-nth 16 - ; inline\r
+\r
+: compute-v ( yuv uvy yy x -- v )\r
+    nip 2/ + >fixnum swap yuv_buffer-u uchar-nth 128 - ; inline\r
+\r
+: compute-u ( yuv uvy yy x -- v )\r
+    nip 2/ + >fixnum swap yuv_buffer-v uchar-nth 128 - ; inline\r
+\r
+: compute-yuv ( yuv uvy yy x -- y u v )\r
+    [ compute-y ] 4keep [ compute-u ] 4keep compute-v ; inline\r
+\r
+: compute-blue ( y u v -- b )\r
+    drop 516 * 128 + swap 298 * + -8 shift clamp ; inline\r
+\r
+: compute-green ( y u v -- g )\r
+    >r >r 298 * r> 100 * - r> 208 * - 128 + -8 shift clamp ;\r
+    inline\r
+\r
+: compute-red ( y u v -- g )\r
+    nip 409 * swap 298 * + 128 + -8 shift clamp ; inline\r
+\r
+: compute-rgb ( y u v -- b g r )\r
+    [ compute-blue ] 3keep [ compute-green ] 3keep compute-red ;\r
+    inline\r
+\r
+: store-rgb ( index rgb b g r -- index )\r
+    >r\r
+    >r pick 0 + >fixnum pick set-uchar-nth\r
+    r> pick 1 + >fixnum pick set-uchar-nth\r
+    r> pick 2 + >fixnum pick set-uchar-nth\r
+    drop ; inline\r
+\r
+: yuv>rgb-pixel ( index rgb yuv uvy yy x -- index )\r
+    compute-yuv compute-rgb store-rgb 3 + >fixnum ; inline\r
+\r
+: yuv>rgb-row ( index rgb yuv y -- index )\r
+    over stride\r
+    pick yuv_buffer-y_width >fixnum\r
+    [ yuv>rgb-pixel ] each-with4 ; inline\r
+\r
+: yuv>rgb ( rgb yuv -- )\r
+    0 -rot\r
+    dup yuv_buffer-y_height >fixnum\r
+    [ yuv>rgb-row ] each-with2\r
+    drop ;\r
+\r
+HINTS: yuv>rgb byte-array byte-array ;\r
+\r
+: process-video ( player -- player )\r
+    dup gadget>> [\r
+        {\r
+            [ [ td>> ] [ yuv>> ] bi theora_decode_YUVout drop ]\r
+            [ [ rgb>> ] [ yuv>> ] bi yuv>rgb ]\r
+            [ gadget>> relayout-1 yield ]\r
+            [ ]\r
+        } cleave\r
+    ] when ;\r
+\r
+: num-audio-buffers-processed ( player -- player n )\r
+    dup source>> AL_BUFFERS_PROCESSED 0 <uint>\r
+    [ alGetSourcei check-error ] keep *uint ;\r
+\r
+: append-new-audio-buffer ( player -- player )\r
+    dup buffers>> 1 gen-buffers append >>buffers\r
+    [ [ buffers>> second ] keep al-channel-format ] keep\r
+    [ audio-buffer>> dup length  ] keep\r
+    [ vi>> vorbis_info-rate alBufferData check-error ]  keep\r
+    [ source>> 1 ] keep\r
+    [ buffers>> second <uint> alSourceQueueBuffers check-error ] keep ;\r
+\r
+: fill-processed-audio-buffer ( player n -- player )\r
+    #! n is the number of audio buffers processed\r
+    over >r >r dup source>> r> pick buffer-indexes>>\r
+    [ alSourceUnqueueBuffers check-error ] keep\r
+    *uint dup r> swap >r al-channel-format rot\r
+    [ audio-buffer>> dup length  ] keep\r
+    [ vi>> vorbis_info-rate alBufferData check-error ]  keep\r
+    [ source>> 1 ] keep\r
+    r> <uint> swap >r alSourceQueueBuffers check-error r> ;\r
+\r
+: append-audio ( player -- player bool )\r
+    num-audio-buffers-processed {\r
+        { [ over buffers>> length 1 = over zero? and ] [ drop append-new-audio-buffer t ] }\r
+        { [ over buffers>> length 2 = over zero? and ] [ yield drop f ] }\r
+        [ fill-processed-audio-buffer t ]\r
+    } cond ;\r
+\r
+: start-audio ( player -- player bool )\r
+    [ [ buffers>> first ] keep al-channel-format ] keep\r
+    [ audio-buffer>> dup length ] keep\r
+    [ vi>> vorbis_info-rate alBufferData check-error ]  keep\r
+    [ source>> 1 ] keep\r
+    [ buffers>> first <uint> alSourceQueueBuffers check-error ] keep\r
+    [ source>> alSourcePlay check-error ] keep\r
+    t >>playing? t ;\r
+\r
+: process-audio ( player -- player bool )\r
+    dup playing?>> [ append-audio ] [ start-audio ] if ;\r
+\r
+: read-bytes-into ( dest size stream -- len )\r
+    #! Read the given number of bytes from a stream\r
+    #! and store them in the destination byte array.\r
+    stream-read >byte-array dup length [ memcpy ] keep  ;\r
+\r
+: check-not-negative ( int -- )\r
+    0 < [ "Word result was a negative number." throw ] when ;\r
+\r
+: buffer-size ( -- number )\r
+    4096 ; inline\r
+\r
+: sync-buffer ( player -- buffer size player )\r
+    [ oy>> buffer-size ogg_sync_buffer buffer-size ] keep ;\r
+\r
+: stream-into-buffer ( buffer size player -- len player )\r
+    [ stream>> read-bytes-into ] keep ;\r
+\r
+: confirm-buffer ( len player -- player eof? )\r
+  [ oy>> swap ogg_sync_wrote check-not-negative ] 2keep swap zero? ;\r
+\r
+: buffer-data ( player -- player eof? )\r
+    #! Take some compressed bitstream data and sync it for\r
+    #! page extraction.\r
+    sync-buffer stream-into-buffer confirm-buffer ;\r
+\r
+: queue-page ( player -- player )\r
+    #! Push a page into the stream for packetization\r
+    [ [ vo>> ] [ og>> ] bi ogg_stream_pagein drop ]\r
+    [ [ to>> ] [ og>> ] bi ogg_stream_pagein drop ]\r
+    [ ] tri ;\r
+\r
+: retrieve-page ( player -- player bool )\r
+    #! Sync the streams and get a page. Return true if a page was\r
+    #! successfully retrieved.\r
+    dup [ oy>> ] [ og>> ] bi ogg_sync_pageout 0 > ;\r
+\r
+: standard-initial-header? ( player -- player bool )\r
+    dup og>> ogg_page_bos zero? not ;\r
+\r
+: ogg-stream-init ( player -- state player )\r
+    #! Init the encode/decode logical stream state\r
+    [ temp-state>> ] keep\r
+    [ og>> ogg_page_serialno ogg_stream_init check-not-negative ] 2keep ;\r
+\r
+: ogg-stream-pagein ( state player -- state player )\r
+    #! Add the incoming page to the stream state\r
+    [ og>> ogg_stream_pagein drop ] 2keep ;\r
+\r
+: ogg-stream-packetout ( state player -- state player )\r
+    [ op>> ogg_stream_packetout drop ] 2keep ;\r
+\r
+: decode-packet ( player -- state player )\r
+    ogg-stream-init ogg-stream-pagein ogg-stream-packetout ;\r
+\r
+: theora-header? ( player -- player bool )\r
+    #! Is the current page a theora header?\r
+    dup [ ti>> ] [ tc>> ] [ op>> ] tri theora_decode_header 0 >= ;\r
+\r
+: is-theora-packet? ( player -- player bool )\r
+    dup theora>> zero? [ theora-header? ] [ f ] if ;\r
+\r
+: copy-to-theora-state ( state player -- player )\r
+    #! Copy the state to the theora state structure in the player\r
+    [ to>> swap dup length memcpy ] keep ;\r
+\r
+: handle-initial-theora-header ( state player -- player )\r
+    copy-to-theora-state 1 >>theora ;\r
+\r
+: vorbis-header? ( player -- player bool )\r
+    #! Is the current page a vorbis header?\r
+    dup [ vi>> ] [ vc>> ] [ op>> ] tri vorbis_synthesis_headerin 0 >= ;\r
+\r
+: is-vorbis-packet? ( player -- player bool )\r
+    dup vorbis>> zero? [ vorbis-header? ] [ f ] if ;\r
+\r
+: copy-to-vorbis-state ( state player -- player )\r
+    #! Copy the state to the vorbis state structure in the player\r
+    [ vo>> swap dup length memcpy ] keep ;\r
+\r
+: handle-initial-vorbis-header ( state player -- player )\r
+    copy-to-vorbis-state 1 >>vorbis ;\r
+\r
+: handle-initial-unknown-header ( state player -- player )\r
+    swap ogg_stream_clear drop ;\r
+\r
+: process-initial-header ( player -- player bool )\r
+    #! Is this a standard initial header? If not, stop parsing\r
+    standard-initial-header? [\r
+        decode-packet {\r
+            { [ is-vorbis-packet? ] [ handle-initial-vorbis-header ] }\r
+            { [ is-theora-packet? ] [ handle-initial-theora-header ] }\r
+            [ handle-initial-unknown-header ]\r
+        } cond t\r
+    ] [\r
+        f\r
+    ] if ;\r
+\r
+: parse-initial-headers ( player -- player )\r
+    #! Parse Vorbis headers, ignoring any other type stored\r
+    #! in the Ogg container.\r
+    retrieve-page [\r
+        process-initial-header [\r
+            parse-initial-headers\r
+        ] [\r
+            #! Don't leak the page, get it into the appropriate stream\r
+            queue-page\r
+        ] if\r
+    ] [\r
+        buffer-data not [ parse-initial-headers ] when\r
+    ] if ;\r
+\r
+: have-required-vorbis-headers? ( player -- player bool )\r
+    #! Return true if we need to decode vorbis due to there being\r
+    #! vorbis headers read from the stream but we don't have them all\r
+    #! yet.\r
+    dup vorbis>> 1 2 between? not ;\r
+\r
+: have-required-theora-headers? ( player -- player bool )\r
+    #! Return true if we need to decode theora due to there being\r
+    #! theora headers read from the stream but we don't have them all\r
+    #! yet.\r
+    dup theora>> 1 2 between? not ;\r
+\r
+: get-remaining-vorbis-header-packet ( player -- player bool )\r
+    dup [ vo>> ] [ op>> ] bi ogg_stream_packetout {\r
+        { [ dup 0 <   ] [ "Error parsing vorbis stream; corrupt stream?" throw ] }\r
+        { [ dup zero? ] [ drop f ] }\r
+        { [ t     ] [ drop t ] }\r
+    } cond ;\r
+\r
+: get-remaining-theora-header-packet ( player -- player bool )\r
+    dup [ to>> ] [ op>> ] bi ogg_stream_packetout {\r
+        { [ dup 0 <   ] [ "Error parsing theora stream; corrupt stream?" throw ] }\r
+        { [ dup zero? ] [ drop f ] }\r
+        { [ t     ] [ drop t ] }\r
+    } cond ;\r
+\r
+: decode-remaining-vorbis-header-packet ( player -- player )\r
+    dup [ vi>> ] [ vc>> ] [ op>> ] tri vorbis_synthesis_headerin zero? [\r
+        "Error parsing vorbis stream; corrupt stream?" throw\r
+    ] unless ;\r
+\r
+: decode-remaining-theora-header-packet ( player -- player )\r
+    dup [ ti>> ] [ tc>> ] [ op>> ] tri theora_decode_header zero? [\r
+        "Error parsing theora stream; corrupt stream?" throw\r
+    ] unless ;\r
+\r
+: increment-vorbis-header-count ( player -- player )\r
+    [ 1+ ] change-vorbis ;\r
+\r
+: increment-theora-header-count ( player -- player )\r
+    [ 1+ ] change-theora ;\r
+\r
+: parse-remaining-vorbis-headers ( player -- player )\r
+    have-required-vorbis-headers? not [\r
+        get-remaining-vorbis-header-packet [\r
+            decode-remaining-vorbis-header-packet\r
+            increment-vorbis-header-count\r
+            parse-remaining-vorbis-headers\r
+        ] when\r
+    ] when ;\r
+\r
+: parse-remaining-theora-headers ( player -- player )\r
+    have-required-theora-headers? not [\r
+        get-remaining-theora-header-packet [\r
+            decode-remaining-theora-header-packet\r
+            increment-theora-header-count\r
+            parse-remaining-theora-headers\r
+        ] when\r
+    ] when ;\r
+\r
+: get-more-header-data ( player -- player )\r
+    buffer-data drop ;\r
+\r
+: parse-remaining-headers ( player -- player )\r
+    have-required-vorbis-headers? not swap have-required-theora-headers? not swapd or [\r
+        parse-remaining-vorbis-headers\r
+        parse-remaining-theora-headers\r
+        retrieve-page [ queue-page ] [ get-more-header-data ] if\r
+        parse-remaining-headers\r
+    ] when ;\r
+\r
+: tear-down-vorbis ( player -- player )\r
+    dup vi>> vorbis_info_clear\r
+    dup vc>> vorbis_comment_clear ;\r
+\r
+: tear-down-theora ( player -- player )\r
+    dup ti>> theora_info_clear\r
+    dup tc>> theora_comment_clear ;\r
+\r
+: init-vorbis-codec ( player -- player )\r
+    dup [ vd>> ] [ vi>> ] bi vorbis_synthesis_init drop\r
+    dup [ vd>> ] [ vb>> ] bi vorbis_block_init drop ;\r
+\r
+: init-theora-codec ( player -- player )\r
+    dup [ td>> ] [ ti>> ] bi theora_decode_init drop\r
+    dup ti>> theora_info-frame_width over ti>> theora_info-frame_height\r
+    4 * * <byte-array> >>rgb ;\r
+\r
+\r
+: display-vorbis-details ( player -- player )\r
+    [\r
+        "Ogg logical stream " %\r
+        dup vo>> ogg_stream_state-serialno #\r
+        " is Vorbis " %\r
+        dup vi>> vorbis_info-channels #\r
+        " channel " %\r
+        dup vi>> vorbis_info-rate #\r
+        " Hz audio." %\r
+    ] "" make print ;\r
+\r
+: display-theora-details ( player -- player )\r
+    [\r
+        "Ogg logical stream " %\r
+        dup to>> ogg_stream_state-serialno #\r
+        " is Theora " %\r
+        dup ti>> theora_info-width #\r
+        "x" %\r
+        dup ti>> theora_info-height #\r
+        " " %\r
+        dup ti>> theora_info-fps_numerator\r
+        over ti>> theora_info-fps_denominator /f #\r
+        " fps video" %\r
+    ] "" make print ;\r
+\r
+: initialize-decoder ( player -- player )\r
+    dup vorbis>> zero? [ tear-down-vorbis ] [ init-vorbis-codec display-vorbis-details ] if\r
+    dup theora>> zero? [ tear-down-theora ] [ init-theora-codec display-theora-details ] if ;\r
+\r
+: sync-pages ( player -- player )\r
+    retrieve-page [\r
+        queue-page sync-pages\r
+    ] when ;\r
+\r
+: audio-buffer-not-ready? ( player -- player bool )\r
+    dup vorbis>> zero? not over audio-full?>> not and ;\r
+\r
+: pending-decoded-audio? ( player -- player pcm len bool )\r
+    f <void*> 2dup >r vd>> r> vorbis_synthesis_pcmout dup 0 > ;\r
+\r
+: buffer-space-available ( player -- available )\r
+    audio-buffer-size swap audio-index>> - ;\r
+\r
+: samples-to-read ( player available len -- numread )\r
+    >r swap num-channels / r> min ;\r
+\r
+: each-with3 ( obj obj obj seq quot -- ) 3 each-withn ; inline\r
+\r
+: add-to-buffer ( player val -- )\r
+    over audio-index>> pick audio-buffer>> set-short-nth\r
+    [ 1+ ] change-audio-index drop ;\r
+\r
+: get-audio-value ( pcm sample channel -- value )\r
+    rot *void* void*-nth float-nth ;\r
+\r
+: process-channels ( player pcm sample channel -- )\r
+    get-audio-value 32767.0 * >fixnum 32767 min -32768 max add-to-buffer ;\r
+\r
+: (process-sample) ( player pcm sample -- )\r
+    pick num-channels [ process-channels ] each-with3 ;\r
+\r
+: process-samples ( player pcm numread -- )\r
+    [ (process-sample) ] each-with2 ;\r
+\r
+: decode-pending-audio ( player pcm result -- player )\r
+!     [ "ret = " % dup # ] "" make write\r
+    pick [ buffer-space-available swap ] keep -rot samples-to-read\r
+    pick over >r >r process-samples r> r> swap\r
+    ! numread player\r
+    dup audio-index>> audio-buffer-size = [\r
+        t >>audio-full?\r
+    ] when\r
+    dup vd>> vorbis_dsp_state-granulepos dup 0 >= [\r
+        ! numtoread player granulepos\r
+        #! This is wrong: fix\r
+        pick - >>audio-granulepos\r
+    ] [\r
+        ! numtoread player granulepos\r
+        pick + >>audio-granulepos\r
+    ] if\r
+    [ vd>> swap vorbis_synthesis_read drop ] keep ;\r
+\r
+: no-pending-audio ( player -- player bool )\r
+    #! No pending audio. Is there a pending packet to decode.\r
+    dup [ vo>> ] [ op>> ] bi ogg_stream_packetout 0 > [\r
+        dup [ vb>> ] [ op>> ] bi vorbis_synthesis 0 = [\r
+            dup [ vd>> ] [ vb>> ] bi vorbis_synthesis_blockin drop\r
+        ] when\r
+        t\r
+    ] [\r
+        #! Need more data. Break out to suck in another page.\r
+        f\r
+    ] if ;\r
+\r
+: decode-audio ( player -- player )\r
+    audio-buffer-not-ready? [\r
+        #! If there's pending decoded audio, grab it\r
+        pending-decoded-audio? [\r
+            decode-pending-audio decode-audio\r
+        ] [\r
+            2drop no-pending-audio [ decode-audio ] when\r
+        ] if\r
+    ] when ;\r
+\r
+: video-buffer-not-ready? ( player -- player bool )\r
+    dup theora>> zero? not over video-ready?>> not and ;\r
+\r
+: decode-video ( player -- player )\r
+    video-buffer-not-ready? [\r
+        dup [ to>> ] [ op>> ] bi ogg_stream_packetout 0 > [\r
+            dup [ td>> ] [ op>> ] bi theora_decode_packetin drop\r
+            dup td>> theora_state-granulepos >>video-granulepos\r
+            dup [ td>> ] [ video-granulepos>> ] bi theora_granule_time\r
+            >>video-time\r
+            t >>video-ready?\r
+            decode-video\r
+        ] when\r
+    ] when ;\r
+\r
+: decode ( player -- player )\r
+    get-more-header-data sync-pages\r
+    decode-audio\r
+    decode-video\r
+    dup audio-full?>> [\r
+        process-audio [\r
+            f >>audio-full?\r
+            0 >>audio-index\r
+        ] when\r
+    ] when\r
+    dup video-ready?>> [\r
+        dup video-time>> over get-time - dup 0.0 < [\r
+            -0.1 > [ process-video ] when\r
+            f >>video-ready?\r
+        ] [\r
+            drop\r
+        ] if\r
+    ] when\r
+    decode ;\r
+\r
+: free-malloced-objects ( player -- player )\r
+    {\r
+        [ op>> free ]\r
+        [ oy>> free ]\r
+        [ og>> free ]\r
+        [ vo>> free ]\r
+        [ vi>> free ]\r
+        [ vd>> free ]\r
+        [ vb>> free ]\r
+        [ vc>> free ]\r
+        [ to>> free ]\r
+        [ ti>> free ]\r
+        [ tc>> free ]\r
+        [ td>> free ]\r
+        [ ]\r
+    } cleave ;\r
+\r
+\r
+: unqueue-openal-buffers ( player -- player )\r
+    [\r
+\r
+        num-audio-buffers-processed over source>> rot buffer-indexes>> swapd\r
+        alSourceUnqueueBuffers check-error\r
+    ] keep ;\r
+\r
+: delete-openal-buffers ( player -- player )\r
+    [\r
+        buffers>> [\r
+            1 swap <uint> alDeleteBuffers check-error\r
+        ] each\r
+    ] keep ;\r
+\r
+: delete-openal-source ( player -- player )\r
+    [ source>> 1 swap <uint> alDeleteSources check-error ] keep ;\r
+\r
+: cleanup ( player -- player )\r
+    free-malloced-objects\r
+    unqueue-openal-buffers\r
+    delete-openal-buffers\r
+    delete-openal-source ;\r
+\r
+: wait-for-sound ( player -- player )\r
+    #! Waits for the openal to finish playing remaining sounds\r
+    dup source>> AL_SOURCE_STATE 0 <int> [ alGetSourcei check-error ] keep\r
+    *int AL_PLAYING = [\r
+        100 sleep\r
+        wait-for-sound\r
+    ] when ;\r
+\r
+TUPLE: theora-gadget < gadget player ;\r
+\r
+: <theora-gadget> ( player -- gadget )\r
+    theora-gadget new-gadget\r
+        swap >>player ;\r
+\r
+M: theora-gadget pref-dim*\r
+    player>>\r
+    ti>> dup theora_info-width swap theora_info-height 2array ;\r
+\r
+M: theora-gadget draw-gadget* ( gadget -- )\r
+    0 0 glRasterPos2i\r
+    1.0 -1.0 glPixelZoom\r
+    GL_UNPACK_ALIGNMENT 1 glPixelStorei\r
+    [ pref-dim* first2 GL_RGB GL_UNSIGNED_BYTE ] keep\r
+    player>> rgb>> glDrawPixels ;\r
+\r
+: initialize-gui ( gadget -- )\r
+    "Theora Player" open-window ;\r
+\r
+: play-ogg ( player -- )\r
+    parse-initial-headers\r
+    parse-remaining-headers\r
+    initialize-decoder\r
+    dup gadget>> [ initialize-gui ] when*\r
+    [ decode ] try\r
+    wait-for-sound\r
+    cleanup\r
+    drop ;\r
+\r
+: play-vorbis-stream ( stream -- )\r
+    <player> play-ogg ;\r
+\r
+: play-vorbis-file ( filename -- )\r
+    binary <file-reader> play-vorbis-stream ;\r
+\r
+: play-theora-stream ( stream -- )\r
+    <player>\r
+    dup <theora-gadget> >>gadget\r
+    play-ogg ;\r
+\r
+: play-theora-file ( filename -- )\r
+    binary <file-reader> play-theora-stream ;\r
diff --git a/extra/ogg/player/summary.txt b/extra/ogg/player/summary.txt
new file mode 100644 (file)
index 0000000..d2e32ef
--- /dev/null
@@ -0,0 +1 @@
+Ogg vorbis and theora media player
diff --git a/extra/ogg/player/tags.txt b/extra/ogg/player/tags.txt
new file mode 100644 (file)
index 0000000..1adb6f1
--- /dev/null
@@ -0,0 +1,2 @@
+audio
+video
diff --git a/extra/ogg/summary.txt b/extra/ogg/summary.txt
new file mode 100644 (file)
index 0000000..3d2b551
--- /dev/null
@@ -0,0 +1 @@
+Ogg media library binding
diff --git a/extra/ogg/tags.txt b/extra/ogg/tags.txt
new file mode 100644 (file)
index 0000000..be30e2c
--- /dev/null
@@ -0,0 +1,3 @@
+bindings
+audio
+video
diff --git a/extra/ogg/theora/authors.txt b/extra/ogg/theora/authors.txt
new file mode 100644 (file)
index 0000000..44b06f9
--- /dev/null
@@ -0,0 +1 @@
+Chris Double
diff --git a/extra/ogg/theora/summary.txt b/extra/ogg/theora/summary.txt
new file mode 100644 (file)
index 0000000..aa5ec1f
--- /dev/null
@@ -0,0 +1 @@
+Ogg Theora video library binding
diff --git a/extra/ogg/theora/tags.txt b/extra/ogg/theora/tags.txt
new file mode 100644 (file)
index 0000000..2b68b52
--- /dev/null
@@ -0,0 +1 @@
+video
diff --git a/extra/ogg/theora/theora.factor b/extra/ogg/theora/theora.factor
new file mode 100644 (file)
index 0000000..3d73fb8
--- /dev/null
@@ -0,0 +1,120 @@
+! Copyright (C) 2007 Chris Double.
+! See http://factorcode.org/license.txt for BSD license.
+!
+USING: kernel system combinators alien alien.syntax ;
+IN: ogg.theora
+
+<<
+"theora" {
+    { [ os winnt? ]  [ "theora.dll" ] }
+    { [ os macosx? ] [ "libtheora.0.dylib" ] }
+    { [ os unix? ]   [ "libtheora.so" ] }
+} cond "cdecl" add-library
+>>
+
+LIBRARY: theora
+
+C-STRUCT: yuv_buffer
+    { "int" "y_width" }
+    { "int" "y_height" }
+    { "int" "y_stride" }
+    { "int" "uv_width" }
+    { "int" "uv_height" }
+    { "int" "uv_stride" }
+    { "void*" "y" }
+    { "void*" "u" }
+    { "void*" "v" } ;
+
+: OC_CS_UNSPECIFIED ( -- number ) 0 ; inline
+: OC_CS_ITU_REC_470M ( -- number ) 1 ; inline
+: OC_CS_ITU_REC_470BG ( -- number ) 2 ; inline
+: OC_CS_NSPACES ( -- number ) 3 ; inline
+
+TYPEDEF: int theora_colorspace 
+
+: OC_PF_420 ( -- number ) 0 ; inline
+: OC_PF_RSVD ( -- number ) 1 ; inline
+: OC_PF_422 ( -- number ) 2 ; inline
+: OC_PF_444 ( -- number ) 3 ; inline
+
+TYPEDEF: int theora_pixelformat
+
+C-STRUCT: theora_info
+    { "uint" "width" }
+    { "uint" "height" }
+    { "uint" "frame_width" }
+    { "uint" "frame_height" }
+    { "uint" "offset_x" }
+    { "uint" "offset_y" }
+    { "uint" "fps_numerator" }
+    { "uint" "fps_denominator" }
+    { "uint" "aspect_numerator" }
+    { "uint" "aspect_denominator" }
+    { "theora_colorspace" "colorspace" }
+    { "int" "target_bitrate" }
+    { "int" "quality" }
+    { "int" "quick_p" }
+    { "uchar" "version_major" }
+    { "uchar" "version_minor" } 
+    { "uchar" "version_subminor" }
+    { "void*" "codec_setup" }
+    { "int" "dropframes_p" }
+    { "int" "keyframe_auto_p" }
+    { "uint" "keyframe_frequency" }
+    { "uint" "keyframe_frequency_force" }
+    { "uint" "keyframe_data_target_bitrate" }
+    { "int" "keyframe_auto_threshold" }
+    { "uint" "keyframe_mindistance" }
+    { "int" "noise_sensitivity" }
+    { "int" "sharpness" }
+    { "theora_pixelformat" "pixelformat" } ;
+
+C-STRUCT: theora_state
+    { "theora_info*" "i" }
+    { "longlong" "granulepos" }
+    { "void*" "internal_encode" }
+    { "void*" "internal_decode" } ;
+
+C-STRUCT: theora_comment
+    { "char**" "user_comments" }
+    { "int*" "comment_lengths" }
+    { "int" "comments" }
+    { "char*" "vendor" } ;
+
+: OC_FAULT ( -- number ) -1 ; inline
+: OC_EINVAL ( -- number ) -10 ; inline
+: OC_DISABLED ( -- number ) -11 ; inline
+: OC_BADHEADER ( -- number ) -20 ; inline
+: OC_NOTFORMAT ( -- number ) -21 ; inline
+: OC_VERSION ( -- number ) -22 ; inline
+: OC_IMPL ( -- number ) -23 ; inline
+: OC_BADPACKET ( -- number ) -24 ; inline
+: OC_NEWPACKET ( -- number ) -25 ; inline
+: OC_DUPFRAME ( -- number ) 1 ; inline
+
+FUNCTION: char* theora_version_string ( ) ;
+FUNCTION: uint theora_version_number ( ) ;
+FUNCTION: int theora_encode_init ( theora_state* th, theora_info* ti ) ;
+FUNCTION: int theora_encode_YUVin ( theora_state* t, yuv_buffer* yuv ) ;
+FUNCTION: int theora_encode_packetout ( theora_state* t, int last_p, ogg_packet* op ) ;
+FUNCTION: int theora_encode_header ( theora_state* t, ogg_packet* op ) ;
+FUNCTION: int theora_encode_comment ( theora_comment* tc, ogg_packet* op ) ;
+FUNCTION: int theora_encode_tables ( theora_state* t, ogg_packet* op ) ;
+FUNCTION: int theora_decode_header ( theora_info* ci, theora_comment* cc, ogg_packet* op ) ;
+FUNCTION: int theora_decode_init ( theora_state* th, theora_info* c ) ;
+FUNCTION: int theora_decode_packetin ( theora_state* th, ogg_packet* op ) ;
+FUNCTION: int theora_decode_YUVout ( theora_state* th, yuv_buffer* yuv ) ;
+FUNCTION: int theora_packet_isheader ( ogg_packet* op ) ;
+FUNCTION: int theora_packet_iskeyframe ( ogg_packet* op ) ;
+FUNCTION: int theora_granule_shift ( theora_info* ti ) ;
+FUNCTION: longlong theora_granule_frame ( theora_state* th, longlong granulepos ) ;
+FUNCTION: double theora_granule_time ( theora_state* th, longlong granulepos ) ;
+FUNCTION: void theora_info_init ( theora_info* c ) ;
+FUNCTION: void theora_info_clear ( theora_info* c ) ;
+FUNCTION: void theora_clear ( theora_state* t ) ;
+FUNCTION: void theora_comment_init ( theora_comment* tc ) ;
+FUNCTION: void theora_comment_add ( theora_comment* tc, char* comment ) ;
+FUNCTION: void theora_comment_add_tag ( theora_comment* tc, char* tag, char* value ) ;
+FUNCTION: char* theora_comment_query ( theora_comment* tc, char* tag, int count ) ;
+FUNCTION: int   theora_comment_query_count ( theora_comment* tc, char* tag ) ;
+FUNCTION: void  theora_comment_clear ( theora_comment* tc ) ;
diff --git a/extra/ogg/vorbis/authors.txt b/extra/ogg/vorbis/authors.txt
new file mode 100644 (file)
index 0000000..44b06f9
--- /dev/null
@@ -0,0 +1 @@
+Chris Double
diff --git a/extra/ogg/vorbis/summary.txt b/extra/ogg/vorbis/summary.txt
new file mode 100644 (file)
index 0000000..1a8118f
--- /dev/null
@@ -0,0 +1 @@
+Ogg Vorbis audio library binding
diff --git a/extra/ogg/vorbis/tags.txt b/extra/ogg/vorbis/tags.txt
new file mode 100644 (file)
index 0000000..d5cc284
--- /dev/null
@@ -0,0 +1 @@
+audio
diff --git a/extra/ogg/vorbis/vorbis.factor b/extra/ogg/vorbis/vorbis.factor
new file mode 100644 (file)
index 0000000..5712272
--- /dev/null
@@ -0,0 +1,141 @@
+! Copyright (C) 2007 Chris Double.
+! See http://factorcode.org/license.txt for BSD license.
+!
+USING: kernel system combinators alien alien.syntax ogg ;
+IN: ogg.vorbis
+
+<<
+"vorbis" {
+    { [ os winnt? ]  [ "vorbis.dll" ] }
+    { [ os macosx? ] [ "libvorbis.0.dylib" ] }
+    { [ os unix? ]   [ "libvorbis.so" ] }
+} cond "cdecl" add-library 
+>>
+
+LIBRARY: vorbis
+
+C-STRUCT: vorbis_info 
+    { "int" "version" }
+    { "int" "channels" }
+    { "long" "rate" }
+    { "long" "bitrate_upper" }
+    { "long" "bitrate_nominal" }
+    { "long" "bitrate_lower" }
+    { "long" "bitrate_window" }
+    { "void*" "codec_setup"} 
+    ;
+
+C-STRUCT: vorbis_dsp_state
+    { "int" "analysisp" }
+    { "vorbis_info*" "vi" }
+    { "float**" "pcm" }
+    { "float**" "pcmret" }
+    { "int" "pcm_storage" }
+    { "int" "pcm_current" }
+    { "int" "pcm_returned" }
+    { "int" "preextrapolate" }
+    { "int" "eofflag" }
+    { "long" "lW" }
+    { "long" "W" }
+    { "long" "nW" }
+    { "long" "centerW" }
+    { "longlong" "granulepos" }
+    { "longlong" "sequence" }
+    { "longlong" "glue_bits" }
+    { "longlong" "time_bits" }
+    { "longlong" "floor_bits" }
+    { "longlong" "res_bits" }
+    { "void*" "backend_state" }
+    ;
+
+C-STRUCT: alloc_chain
+    { "void*" "ptr" }
+    { "void*" "next" }
+    ;
+
+C-STRUCT: vorbis_block
+    { "float**" "pcm" }
+    { "oggpack_buffer" "opb" }
+    { "long" "lW" }
+    { "long" "W" }
+    { "long" "nW" }
+    { "int" "pcmend" }
+    { "int" "mode" }
+    { "int" "eofflag" }
+    { "longlong" "granulepos" }
+    { "longlong" "sequence" }
+    { "vorbis_dsp_state*" "vd" }
+    { "void*" "localstore" }
+    { "long" "localtop" }
+    { "long" "localalloc" }
+    { "long" "totaluse" }
+    { "alloc_chain*" "reap" }
+    { "long" "glue_bits" }
+    { "long" "time_bits" }
+    { "long" "floor_bits" }
+    { "long" "res_bits" }
+    { "void*" "internal" }
+    ;
+
+C-STRUCT: vorbis_comment
+    { "char**" "usercomments" }
+    { "int*" "comment_lengths" }
+    { "int" "comments" }
+    { "char*" "vendor" }
+    ;
+
+FUNCTION: void     vorbis_info_init ( vorbis_info* vi ) ;
+FUNCTION: void     vorbis_info_clear ( vorbis_info* vi ) ;
+FUNCTION: int      vorbis_info_blocksize ( vorbis_info* vi, int zo ) ;
+FUNCTION: void     vorbis_comment_init ( vorbis_comment* vc ) ;
+FUNCTION: void     vorbis_comment_add ( vorbis_comment* vc, char* comment ) ;
+FUNCTION: void     vorbis_comment_add_tag ( vorbis_comment* vc, char* tag, char* contents ) ;
+FUNCTION: char*    vorbis_comment_query ( vorbis_comment* vc, char* tag, int count ) ;
+FUNCTION: int      vorbis_comment_query_count ( vorbis_comment* vc, char* tag ) ;
+FUNCTION: void     vorbis_comment_clear ( vorbis_comment* vc ) ;
+FUNCTION: int      vorbis_block_init ( vorbis_dsp_state* v, vorbis_block* vb ) ;
+FUNCTION: int      vorbis_block_clear ( vorbis_block* vb ) ;
+FUNCTION: void     vorbis_dsp_clear ( vorbis_dsp_state* v ) ;
+FUNCTION: double   vorbis_granule_time ( vorbis_dsp_state* v, longlong granulepos ) ;
+FUNCTION: int      vorbis_analysis_init ( vorbis_dsp_state* v, vorbis_info* vi ) ;
+FUNCTION: int      vorbis_commentheader_out ( vorbis_comment* vc, ogg_packet* op ) ;
+FUNCTION: int      vorbis_analysis_headerout ( vorbis_dsp_state* v,
+                                          vorbis_comment* vc,
+                                          ogg_packet* op,
+                                          ogg_packet* op_comm,
+                                          ogg_packet* op_code ) ;
+FUNCTION: float**  vorbis_analysis_buffer ( vorbis_dsp_state* v, int vals ) ;
+FUNCTION: int      vorbis_analysis_wrote ( vorbis_dsp_state* v, int vals ) ;
+FUNCTION: int      vorbis_analysis_blockout ( vorbis_dsp_state* v, vorbis_block* vb ) ;
+FUNCTION: int      vorbis_analysis ( vorbis_block* vb, ogg_packet* op ) ;
+FUNCTION: int      vorbis_bitrate_addblock ( vorbis_block* vb ) ;
+FUNCTION: int      vorbis_bitrate_flushpacket ( vorbis_dsp_state* vd,
+                                           ogg_packet* op ) ;
+FUNCTION: int      vorbis_synthesis_headerin ( vorbis_info* vi, vorbis_comment* vc,
+                                          ogg_packet* op ) ;
+FUNCTION: int      vorbis_synthesis_init ( vorbis_dsp_state* v, vorbis_info* vi ) ;
+FUNCTION: int      vorbis_synthesis_restart ( vorbis_dsp_state* v ) ;
+FUNCTION: int      vorbis_synthesis ( vorbis_block* vb, ogg_packet* op ) ;
+FUNCTION: int      vorbis_synthesis_trackonly ( vorbis_block* vb, ogg_packet* op ) ;
+FUNCTION: int      vorbis_synthesis_blockin ( vorbis_dsp_state* v, vorbis_block* vb ) ;
+FUNCTION: int      vorbis_synthesis_pcmout ( vorbis_dsp_state* v, float*** pcm ) ;
+FUNCTION: int      vorbis_synthesis_lapout ( vorbis_dsp_state* v, float*** pcm ) ;
+FUNCTION: int      vorbis_synthesis_read ( vorbis_dsp_state* v, int samples ) ;
+FUNCTION: long     vorbis_packet_blocksize ( vorbis_info* vi, ogg_packet* op ) ;
+FUNCTION: int      vorbis_synthesis_halfrate ( vorbis_info* v, int flag ) ;
+FUNCTION: int      vorbis_synthesis_halfrate_p ( vorbis_info* v ) ;
+
+: OV_FALSE ( -- number ) -1 ; inline
+: OV_EOF ( -- number ) -2 ; inline
+: OV_HOLE ( -- number ) -3 ; inline
+: OV_EREAD ( -- number ) -128 ; inline
+: OV_EFAULT ( -- number ) -129 ; inline
+: OV_EIMPL ( -- number ) -130 ; inline
+: OV_EINVAL ( -- number ) -131 ; inline
+: OV_ENOTVORBIS ( -- number ) -132 ; inline
+: OV_EBADHEADER ( -- number ) -133 ; inline
+: OV_EVERSION ( -- number ) -134 ; inline
+: OV_ENOTAUDIO ( -- number ) -135 ; inline
+: OV_EBADPACKET ( -- number ) -136 ; inline
+: OV_EBADLINK ( -- number ) -137 ; inline
+: OV_ENOSEEK ( -- number ) -138 ; inline