factor-work/flac/decoder/decoder.factor

229 lines
7.9 KiB
Factor

! Copyright (C) 2020 .
! See http://factorcode.org/license.txt for BSD license.
USING: math io.encodings.binary kernel io io.files locals endian bit-arrays math.intervals combinators combinators.extras math.order math.bits sequences namespaces accessors byte-arrays math.bitwise arrays generalizations ;
USING: prettyprint ;
USING: flac.bitstream flac.metadata flac.format ;
IN: flac.decoder
: decode-block-size ( n -- n )
dup
{
{ [ 0b0000 = ] [ drop reserved-block-size ] }
{ [ 0b0001 = ] [ drop 192 ] }
{ [ 0b0010 0b0101 between? ] [ 2 - 2^ 567 * ] }
{ [ 0b0110 = ] [ drop 8 flac-read-uint 1 + ] }
{ [ 0b0111 = ] [ drop 16 flac-read-uint 1 + ] }
{ [ 0b1000 0b1111 between? ] [ 8 - 2^ 256 * ] }
} cond-case ;
: decode-bits-per-sample ( n -- n )
{
{ 0b000 [ "TODO" ] }
{ 0b001 [ 8 ] }
{ 0b010 [ 12 ] }
{ 0b011 [ reserved-sample-size ] }
{ 0b100 [ 16 ] }
{ 0b101 [ 20 ] }
{ 0b110 [ 24 ] }
{ 0b111 [ reserved-sample-size ] }
} case ;
: decode-sample-rate ( n -- n )
{
{ 0b0000 [ "TODO" ] }
{ 0b0001 [ 88200 ] }
{ 0b0010 [ 17640 ] }
{ 0b0011 [ 19200 ] }
{ 0b0100 [ 8000 ] }
{ 0b0101 [ 16000 ] }
{ 0b0110 [ 22050 ] }
{ 0b0111 [ 24000 ] }
{ 0b1000 [ 32000 ] }
{ 0b1001 [ 44100 ] }
{ 0b1010 [ 48000 ] }
{ 0b1011 [ 96000 ] }
{ 0b1100 [ 8 flac-read-uint 1000 * ] } ! sample rate in kHz
{ 0b1101 [ 16 flac-read-uint ] } ! sample rate in Hz
{ 0b1110 [ 16 flac-read-uint 10 * ] } ! sample rate in tens of Hz
{ 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
<flac-channel-assignment> ;
: read-flac-subframe-verbatim ( frame-header subframe-header -- verbatim-subframe )
[ [ blocksize>> ] [ bits-per-sample>> ] bi ] dip wasted-bits>> - <repetition>
[ flac-read-uint ] map
flac-subframe-constant boa ;
: read-flac-subframe-constant ( frame-header subframe-header -- constant-subframe )
[ [ blocksize>> ] [ bits-per-sample>> ] bi ] dip wasted-bits>> - flac-read-uint <repetition> [ ] map ;
! :: read-residual-partitioned-rice ( frame-header subframe-header -- rice residual )
! 4 flac-read-uint :> partition-order
! partition-order .
! frame-header blocksize>> -1 partition-order * shift :> samples
! samples .
! 1 partition-order shift 4 <array> [
! dup .
! flac-read-uint :> param
! param 0b1111 =
! [ 5 flac-read-uint :> numbits samples numbits <array> [ flac-read-uint ] map drop "dicks" . param ]
! [ samples param <array> [ flac-read-uint ] map first . "balls" . param dup . ] if
! ] map :> parameters
! parameters .
! partition-order
! flac-entropy-coding-method-partitioned-rice-contents new
! flac-entropy-coding-method-partitioned-rice boa parameters ;
:: read-residual-partitioned-rice ( frame-header subframe-header -- rice residual )
frame-header blocksize>> :> blocksize
4 flac-read-uint :> partition-order
partition-order 2^ :> partitions
blocksize mod partitions 0 = [ invalid-blocksize/rice-partitions ] unless
partitions <iota>
[
]
2drop flac-entropy-coding-method-partitioned-rice-contents new f ;
: read-residual-partitioned-rice2 ( frame-header subframe-header -- rice residual )
2drop flac-entropy-coding-method-partitioned-rice-contents new f ;
: read-residual-coding-method-type ( -- coding-method )
2 flac-read-uint dup
2 > [ reserved-residual-coding-type ] when
<flac-entropy-coding-method-type> ;
: flac-read-residuals ( frame-header subframe-header -- entropy-coding-method residual )
read-residual-coding-method-type
dup {
{ entropy-coding-partitioned-rice [ read-residual-partitioned-rice ] }
{ entropy-coding-partitioned-rice2 [ read-residual-partitioned-rice2 ] }
[ reserved-residual-coding-type ]
} case
flac-entropy-coding-method boa ;
: read-flac-subframe-warmup-samples ( frame-header subframe-header -- seq )
! TODO: handle wasted bits...
[ bits-per-sample>> ] [ predictor-order>> ] bi* swap <repetition> [ flac-read-uint ] map ;
: read-flac-subframe-fixed ( frame-header subframe-header -- fixed-subframe )
2dup [ read-flac-subframe-warmup-samples ] [ flac-read-residuals ] 2bi*
flac-subframe-fixed boa ;
: read-flac-subframe-qlp-coeff-precision ( -- precision )
4 flac-read-uint 1 + ;
: read-flac-qlp-shift ( -- quantization-level )
5 flac-read-uint ;
: read-flac-qlp-coeff ( subframe-header coeff-precision -- seq )
[ predictor-order>> ] dip <repetition> [ flac-read-uint ] map ;
: read-flac-subframe-lpc ( frame-header subframe-header -- lpc-subframe )
2drop 1 ;
! : read-flac-subframe-lpc ( frame-header subframe-header -- lpc-subframe )
! [ read-flac-subframe-warmup-samples ] 2keep
! [
! nip
! read-flac-subframe-qlp-coeff-precision dup
! read-flac-qlp-shift
! [ swap read-flac-qlp-coeff ] dip
! ]
! [ flac-read-residuals ] 2tri
! flac-subframe boa ;
: read-flac-subframe-sync ( -- )
1 flac-read-uint 1 = [ invalid-subframe-sync ] when ;
! 000000 constant
! 000001 verbatim
! 00001x reserved
! 0001xx reserved
! 001xxx if xxx <= 4 fixed, xxx = order ; else reserved
! 01xxxx reserved
! 1xxxxx lpc
: read-flac-subframe-type ( -- subframe-type order )
6 flac-read-uint dup
{
{ [ 0b0 = ] [ drop f subframe-type-constant ] }
{ [ 0b1 = ] [ drop f subframe-type-verbatim ] }
{ [ 0b1000 0b1100 between? ] [ 3 clear-bit subframe-type-fixed ] }
{ [ 0b100000 0b111111 between? ] [ 5 clear-bit 1 + subframe-type-lpc ] }
[ drop reserved-subframe-type ]
} cond-case swap ;
: read-flac-subframe-wasted-bits ( -- k )
1 flac-read-uint
1 = [ [ flac-read-uint dup 0 = ] [ 1 + ] while ] [ 0 ] if* ;
: read-flac-subframe-header ( -- subframe-header )
read-flac-subframe-sync
read-flac-subframe-type
read-flac-subframe-wasted-bits
flac-subframe-header boa ;
: read-flac-subframe ( frame-header -- subframe )
read-flac-subframe-header dup dup
[
subframe-type>>
{
{ subframe-type-constant [ read-flac-subframe-constant ] }
{ subframe-type-verbatim [ read-flac-subframe-verbatim ] }
{ subframe-type-fixed [ read-flac-subframe-fixed ] }
{ subframe-type-lpc [ read-flac-subframe-lpc ] }
} case
] dip swap
flac-subframe boa ;
: read-flac-subframes ( frame-header -- seq )
dup channels>> swap <repetition> [ read-flac-subframe ] map ;
: read-flac-sync-frame ( -- )
14 flac-read-uint drop ! sync
1 flac-read-uint drop ; ! TODO: handle unparsable frame
: read-flac-frame-header ( -- frame-header )
read-flac-sync-frame
1 flac-read-uint <flac-frame-blocking-strategy>
4 flac-read-uint ! blocksize code
4 flac-read-uint ! sample rate code
4 flac-read-uint decode-channels
3 flac-read-uint decode-bits-per-sample
1 flac-read-uint drop ! ignore magic sync for now
flac-read-utf8-uint
! decoding blocksize/samplerate potentially reads from end of header
[ decode-block-size ] 5 ndip
[ decode-sample-rate ] 4dip
8 flac-read-uint
flac-frame-header boa ;
: read-flac-frame-footer ( -- frame-footer )
16 flac-read-uint flac-frame-footer boa ;
: read-flac-frame ( -- frame )
read-flac-frame-header dup
read-flac-subframes
read-flac-frame-footer
flac-frame boa ;
: read-flac-file ( filename -- flac-stream )
[
read-flac-metadata drop
read-flac-frame drop
read-flac-frame drop
read-flac-frame drop
read-flac-frame
] with-flac-file-reader ;