diff --git a/extra/flac/decoder/decoder.factor b/extra/flac/decoder/decoder.factor index d5bb18e2a2..c161a0d1f8 100644 --- a/extra/flac/decoder/decoder.factor +++ b/extra/flac/decoder/decoder.factor @@ -1,23 +1,35 @@ ! Copyright (C) 2020 . ! See http://factorcode.org/license.txt for BSD license. -USING: alien.syntax math io.encodings.binary kernel io io.files locals endian bit-arrays ; +USING: alien.syntax math io.encodings.binary kernel io io.files locals endian bit-arrays math.intervals combinators math.order sequences io.streams.peek io.binary namespaces accessors ; USING: prettyprint ; USING: flac.metadata.private flac.metadata ; QUALIFIED: bitstreams - IN: flac.decoder ALIAS: read-bit bitstreams:read +ALIAS: peek-bits bitstreams:peek + CONSTANT: sync-code 16382 ERROR: sync-code-error ; +ERROR: invalid-channel-assignment ; +ERROR: reserved-block-size ; +ERROR: invalid-sample-rate ; ENUM: flac-channel-assignment - channel-assignment-independent - channel-assignment-left-side - channel-assignment-right-side - channel-assignment-mid-side ; + channels-mono + channels-left/right + channels-left/right/center + channels-left/right/left-surround/right-surround + channels-left/right/center/left-surround/right-surround + channels-left/right/center/lfe/left-surround/right-surround + channels-left/right/center/lfe/center-surround/side-left/side-right + channels-left/right/center/lfe/left-surround/right-surround/side-left/side-right + channels-left + channels-right + channels-mid ; + ENUM: flac-frame-number-type frame-number-type-frame frame-number-type-sample ; @@ -39,44 +51,167 @@ TUPLE: subframe subframe-type-lpc } } ; TUPLE: frame-header + { number-type maybe{ frame-number-type-frame frame-number-type-sample } } { blocksize integer } { sample-rate integer } { channels integer } - { channel-assignment maybe{ channel-assignment-independent - channel-assignment-left-side - channel-assignment-right-side - channel-assignment-mid-side } } + { channel-assignment maybe{ channels-mono + channels-left/right + channels-left/right/center + channels-left/right/left-surround/right-surround + channels-left/right/center/left-surround/right-surround + channels-left/right/center/lfe/left-surround/right-surround + channels-left/right/center/lfe/center-surround/side-left/side-right + channels-left/right/center/lfe/left-surround/right-surround/side-left/side-right + channels-left + channels-right + channels-mid } } { bits-per-sample integer } - { number-type maybe{ frame-number-type-frame frame-number-type-sample } } - { number integer } + { frame|sample-number integer } { crc integer } ; TUPLE: frame-footer { crc integer } ; -:: read-sync-code ( bitstream -- ? ) - 14 bitstream read-bit sync-code = ; +: 0xxxxxxx? ( n -- ? ) 0x80 bitand 0x80 = not ; +: 110xxxxx? ( n -- ? ) dup [ 0xc0 bitand 0xc0 = ] [ 0x20 bitand 0x20 = not ] bi* and ; +: 1110xxxx? ( n -- ? ) dup [ 0xe0 bitand 0xe0 = ] [ 0x10 bitand 0x10 = not ] bi* and ; +: 11110xxx? ( n -- ? ) dup [ 0xf0 bitand 0xf0 = ] [ 0x08 bitand 0x08 = not ] bi* and ; +: 111110xx? ( n -- ? ) dup [ 0xf8 bitand 0xf8 = ] [ 0x04 bitand 0x04 = not ] bi* and ; +: 1111110x? ( n -- ? ) dup [ 0xfc bitand 0xfc = ] [ 0x02 bitand 0x02 = not ] bi* and ; +: 11111110? ( n -- ? ) dup [ 0xfe bitand 0xfe = ] [ 0x01 bitand 0x01 = not ] bi* and ; -:: (decode-frame-header) ( bitstream -- ) +: remaining-bytes ( n -- n ) + { + { [ dup 110xxxxx? ] [ drop 1 ] } + { [ dup 1110xxxx? ] [ drop 2 ] } + { [ dup 11110xxx? ] [ drop 3 ] } + { [ dup 111110xx? ] [ drop 4 ] } + { [ dup 1111110x? ] [ drop 5 ] } + { [ dup 11111110? ] [ drop 6 ] } + } cond ; + +! : frame-bytes ( byte-array -- n ) +! bitstreams: +! 0 +! { +! { 0b00000000 [ 1 ] } +! { 0b11000000 [ 2 ] } +! { 0b11100000 [ 3 ] } +! { 0b11110000 [ 4 ] } +! { 0b11111000 [ 5 ] } +! { 0b11111100 [ 6 ] } +! } case ; + +:: decode-utf8-uint ( frame-length bitstream -- n ) + frame-length 7 - + bitstream read-bit + frame-length [ - bitstream read-sync-code [ sync-code-error ] unless - 1 bitstream read-bit drop - 1 bitstream read-bit drop - 4 bitstream read-bit integer>bit-array . - 4 bitstream read-bit integer>bit-array . + drop + 2 bitstream read-bit drop + 6 shift 6 bitstream read-bit bitor + ] each ; - ] with-big-endian ; +: read-utf8-uint ( -- n ) + 1 read dup + be> 0xxxxxxx? + [ be> ] + [ + dup be> remaining-bytes read + B{ } append-as be> + ] if ; -: decode-frame-header ( -- ) +: decode-block-size ( n -- n ) + { + { [ dup 0b0000 = ] [ drop reserved-block-size ] } + { [ dup 0b0001 = ] [ drop 192 ] } + { [ dup 0b0010 0b0101 between? ] [ 2 - 2^ 567 * ] } + { [ dup 0b0110 0b0111 between? ] [ ] } + { [ dup 0b1000 0b1111 between? ] [ 8 - 2^ 256 * ] } + } cond ; + +: decode-bits-per-sample ( n -- n ) + { + { 0b000 [ -99 ] } + { 0b001 [ 8 ] } + { 0b010 [ 12 ] } + { 0b011 [ -99 ] } + { 0b100 [ 16 ] } + { 0b101 [ 20 ] } + { 0b110 [ 24 ] } + { 0b111 [ -99 ] } + } case ; + +: decode-sample-rate ( n -- n ) + { + { 0b0000 [ -99 ] } + { 0b0001 [ 88200 ] } + { 0b0010 [ 17640 ] } + { 0b0011 [ 19200 ] } + { 0b0100 [ 8000 ] } + { 0b0101 [ 16000 ] } + { 0b0110 [ 22050 ] } + { 0b0111 [ 24000 ] } + { 0b1000 [ 32000 ] } + { 0b1001 [ 44100 ] } + { 0b1010 [ 48000 ] } + { 0b1011 [ 96000 ] } + { 0b1100 [ 1 read be> 1000 * ] } + { 0b1101 [ 2 read be> ] } + { 0b1110 [ 2 read be> 10 * ] } + { 0b1111 [ invalid-sample-rate ] } + } case ; + +: decode-channels ( n -- channels channel-assignment ) + dup + { + { [ dup 0b0000 0b0111 between? ] [ 1 + ] } + { [ 0b1000 0b1010 between? ] [ 2 ] } + [ invalid-channel-assignment ] + } cond swap + ; + +:: decode-header ( bitstream -- frame-header ) [ - 3 read bitstreams: (decode-frame-header) - ] with-big-endian ; + 14 bitstream read-bit drop ! ignore sync + 1 bitstream read-bit drop ! reserved + 1 bitstream read-bit + 4 bitstream read-bit + 4 bitstream read-bit + 4 bitstream read-bit + 3 bitstream read-bit + 1 bitstream read-bit drop ! ignore magic sync + read-utf8-uint + [ + { + [ ] + [ decode-block-size ] + [ decode-sample-rate ] + [ decode-channels ] + [ decode-bits-per-sample ] + } spread + ] dip + 1 read be> + ] with-big-endian + frame-header boa ; -: decode-file ( filename -- ) +: read-subframe ( frame-header channel -- subframe ) + drop drop -9 ; + +: read-subframes ( frame-header -- seq ) + dup channels>> swap [ read-subframe ] map-index ; + +: read-frame-header ( -- frame-header ) + 4 read bitstreams: decode-header ; + +: decode-file ( filename -- something ) binary [ read-flac-magic [ not-a-flac-file ] unless - read-stream-info drop + read-stream-info . skip-metadata - decode-frame-header +! 51448296 seek-absolute seek-input + read-frame-header + contents . ] with-file-reader ; diff --git a/extra/flac/metadata/metadata-tests.factor b/extra/flac/metadata/metadata-tests.factor new file mode 100644 index 0000000000..3e788bf7ca --- /dev/null +++ b/extra/flac/metadata/metadata-tests.factor @@ -0,0 +1,4 @@ +! Copyright (C) 2020 . +! See http://factorcode.org/license.txt for BSD license. +USING: tools.test ; + diff --git a/extra/flac/metadata/metadata.factor b/extra/flac/metadata/metadata.factor index 68f94a9f2a..535208655d 100644 --- a/extra/flac/metadata/metadata.factor +++ b/extra/flac/metadata/metadata.factor @@ -125,10 +125,10 @@ TUPLE: metadata @@ -136,13 +136,13 @@ TUPLE: metadata ] with-big-endian metadata-block-header boa ; -: parse-metadata-block-header ( byte-array -- header ) - bitstreams: (parse-metadata-block-header) ; +: decode-metadata-block-header ( byte-array -- header ) + bitstreams: (decode-metadata-block-header) ; : read-metadata-block-header ( -- header ) - 4 read parse-metadata-block-header ; + 4 read decode-metadata-block-header ; -:: (parse-stream-info) ( bitstream -- stream-info ) +:: (decode-stream-info) ( bitstream -- stream-info ) [ 16 bitstream read-bit 16 bitstream read-bit @@ -156,10 +156,10 @@ TUPLE: metadata ] with-big-endian stream-info boa ; -: parse-stream-info ( byte-array -- stream-info ) - bitstreams: (parse-stream-info) ; +: decode-stream-info ( byte-array -- stream-info ) + bitstreams: (decode-stream-info) ; -: parse-seek-table ( byte-array -- seek-table ) +: decode-seek-table ( byte-array -- seek-table ) dup binary [ @@ -168,7 +168,7 @@ TUPLE: metadata ] with-byte-reader seek-table boa ; -: parse-vorbis-comment ( byte-array -- comments ) +: decode-vorbis-comment ( byte-array -- comments ) binary [ 4 read le> read utf8 decode @@ -179,13 +179,31 @@ TUPLE: metadata ] map ] with-byte-reader >alist vorbis-comment boa ; -: parse-padding ( byte-array -- padding ) +: encode-vorbis-string ( str -- byte-array ) + dup binary [ length 4 >le write utf8 encode write ] with-byte-writer ; + +: encode-vorbis-comments ( assoc -- byte-array ) + dup binary [ + length 4 >le write + [ 2array "=" join encode-vorbis-string write ] assoc-each + ] with-byte-writer ; + +: encode-vorbis-comment ( vorbis-comment -- byte-array ) + binary [ + [ vendor-string>> encode-vorbis-string write ] + [ comments>> encode-vorbis-comments write ] bi + ] with-byte-writer ; + +: encode-padding ( padding -- byte-array ) + length>> ; + +: decode-padding ( byte-array -- padding ) length padding boa ; -: parse-application ( byte-array -- application ) +: decode-application ( byte-array -- application ) drop application new ; -: parse-cuesheet ( byte-array -- cuesheet ) +: decode-cuesheet ( byte-array -- cuesheet ) binary [ 128 read ascii decode @@ -208,7 +226,7 @@ TUPLE: metadata ] map ] with-byte-reader cuesheet boa ; -: parse-picture ( byte-array -- picture ) +: decode-picture ( byte-array -- picture ) binary [ 4 read be> @@ -221,22 +239,22 @@ TUPLE: metadata 4 read be> read ] with-byte-reader picture boa ; -: read-metadata-block ( metadata byte-array type -- metadata ) +: decode-metadata-block ( metadata byte-array type -- metadata ) { - { metadata-stream-info [ parse-stream-info >>stream-info ] } - { metadata-padding [ parse-padding >>padding ] } - { metadata-application [ parse-application >>application ] } - { metadata-seek-table [ parse-seek-table >>seek-table ] } - { metadata-vorbis-comment [ parse-vorbis-comment >>vorbis-comment ] } - { metadata-cuesheet [ parse-cuesheet >>cuesheet ] } - { metadata-picture [ parse-picture >>picture ] } + { metadata-stream-info [ decode-stream-info >>stream-info ] } + { metadata-padding [ decode-padding >>padding ] } + { metadata-application [ decode-application >>application ] } + { metadata-seek-table [ decode-seek-table >>seek-table ] } + { metadata-vorbis-comment [ decode-vorbis-comment >>vorbis-comment ] } + { metadata-cuesheet [ decode-cuesheet >>cuesheet ] } + { metadata-picture [ decode-picture >>picture ] } } case ; PRIVATE> : read-stream-info ( -- stream-info ) read-metadata-block-header - length>> read bitstreams: parse-stream-info ; + length>> read decode-stream-info ; : skip-metadata ( -- ) [ @@ -253,7 +271,7 @@ PRIVATE> [ read-metadata-block-header [ length>> read ] [ type>> ] [ last?>> not ] tri - [ read-metadata-block ] dip + [ decode-metadata-block ] dip ] loop ] with-file-reader ;