USING: kernel math math.order combinators combinators.extras generalizations math.bitwise accessors sequences arrays ; USING: flac.format flac.stream ; USING: prettyprint ; IN: flac.decoder SYMBOL: current-flac-output : 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 1 + ] } { [ 0b0111 = ] [ drop 16 flac-read 1 + ] } { [ 0b1000 0b1111 between? ] [ 8 - 2^ 256 * ] } } cond-case ; : decode-sample-rate ( n -- n ) { { 0b0000 [ "TODO: GET FROM STREAMINFO" ] } { 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 1000 * ] } ! sample rate in kHz { 0b1101 [ 16 flac-read ] } ! sample rate in Hz { 0b1110 [ 16 flac-read 10 * ] } ! sample rate in tens of Hz { 0b1111 [ invalid-sample-rate ] } } case ; : decode-channel-assignment ( n -- channel-assignment ) { { [ 0b0000 0b0111 between? ] [ 0 ] } { [ 0b1000 = ] [ 1 ] } { [ 0b1001 = ] [ 2 ] } { [ 0b1010 = ] [ 3 ] } [ reserved-channel-assignment ] } cond-case ; : decode-bits-per-sample ( stream-info n -- n ) { { 0b000 [ 0 ] } { 0b001 [ 8 ] } { 0b010 [ 12 ] } { 0b011 [ reserved-sample-size ] } { 0b100 [ 16 ] } { 0b101 [ 20 ] } { 0b110 [ 24 ] } { 0b111 [ reserved-sample-size ] } } case dup 0 = [ drop bits-per-sample>> ] [ nip ] if ; : read/assert-frame-sync-code ( -- ) 15 flac-read 0b111111111111100 = [ sync-code-error ] unless ; : read-flac-frame-header ( stream-info -- frame-header ) [ read/assert-frame-sync-code 1 flac-read 4 flac-read ! blocksize code 4 flac-read ! sample rate code 4 flac-read decode-channel-assignment ] dip 3 flac-read decode-bits-per-sample 1 flac-read drop ! ignore magic sync for now flac-read-coded-number ! decoding blocksize/samplerate potentially reads from end of header [ decode-block-size ] 4dip [ decode-sample-rate ] 3dip 8 flac-read flac-frame-header boa ; : read-flac-subframe-wasted-bits ( -- k ) 1 flac-read 1 = [ 0 [ 1 + 1 flac-read 0 = ] loop ] [ 0 ] if ; : read-flac-subframe-constant ( blocksize bps -- samples ) flac-read-int [ ] map ; : read-flac-subframe-verbatim ( blocksize bps -- samples ) [ flac-read-int ] map ; : adjust-wasted-bits ( wasted-bits samples -- samples' ) [ swap shift ] with map! ; : read-residual-coding-method-type ( -- coding-method param-bits param-escape ) 2 flac-read dup 2 > [ reserved-residual-coding-type ] when dup entropy-coding-partitioned-rice = [ 4 0xf ] [ 5 0x1f ] if ; : read-partition-order/count ( -- partition-order partitions ) 4 flac-read dup 2^ ; ! TODO: even with locals this is pretty gnarly :: read-residuals ( blocksize predictor-order -- residuals ) read-residual-coding-method-type :> ( coding-type parameter-bits escape-parameter ) read-partition-order/count :> ( partition-order partitions ) blocksize partition-order neg shift :> partition-samples { } :> residuals! partitions [| partition | parameter-bits flac-read :> rice-parameter rice-parameter escape-parameter < [ partition 0 = [ partition-samples predictor-order - ] [ partition-samples ] if [ drop residuals rice-parameter flac-read-rice-signed-int suffix residuals! ] each ] [ 5 flac-read :> num-bits partition-samples partition 0 = [ predictor-order ] [ 0 ] if - [| order | residuals num-bits 0 = [ 0 suffix ] [ num-bits flac-read-int suffix ] if residuals! ] each ] if ] each residuals ; : fixed-coefficients ( -- coefficients ) { { } { 1 } { 2 -1 } { 3 -3 1 } { 4 -6 4 1 } } ; : read-warmup-samples ( sample-depth order -- samples ) swap [ flac-read-int ] map ; ! TODO: even with locals this is also gnarly :: restore-linear-prediction ( residuals warmup coefficients quantization-level -- samples ) coefficients length :> order residuals warmup [| samples residual | samples residual coefficients samples order tail* 0 [ * + ] 2reduce quantization-level neg shift + suffix ] reduce ; :: read-flac-subframe-fixed ( blocksize sample-depth order -- samples ) sample-depth order read-warmup-samples :> warmup blocksize order read-residuals :> residuals order fixed-coefficients nth :> coefficients residuals warmup coefficients 0 restore-linear-prediction ; : read-qlp-shift ( -- quantization-level ) 5 flac-read ; : read-qlp-coefficient-precision ( -- precision ) 4 flac-read 1 + ; : read-lpc-coefficients ( order precision -- coefficients ) [ flac-read-int ] map ; :: read-flac-subframe-lpc ( blocksize sample-depth order -- samples ) sample-depth order read-warmup-samples :> warmup read-qlp-coefficient-precision :> precision read-qlp-shift :> qlp-shift order precision read-lpc-coefficients reverse :> coefficients blocksize order read-residuals :> residuals residuals warmup coefficients qlp-shift restore-linear-prediction ; ! 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 dup { { [ 0b000000 = ] [ drop f subframe-type-constant ] } { [ 0b000001 = ] [ drop f subframe-type-verbatim ] } { [ 0b001000 0b001111 between? ] [ 2 0 bit-range subframe-type-fixed ] } { [ 0b100000 0b111111 between? ] [ 4 0 bit-range 1 + subframe-type-lpc ] } [ drop reserved-subframe-type ] } cond-case swap ; : read/assert-flac-subframe-sync ( -- ) 1 flac-read 1 = [ invalid-subframe-sync ] when ; : read-flac-subframe-header ( -- subframe-header ) read/assert-flac-subframe-sync read-flac-subframe-type read-flac-subframe-wasted-bits flac-subframe-header boa ; : calculate-sample-depth ( bps wasted-bits channel-assignment channel -- sample-depth ) [ - ] 2dip swap { { channel-assignment-left [ 1 = [ 1 ] [ 0 ] if ] } { channel-assignment-right [ 0 = [ 1 ] [ 0 ] if ] } { channel-assignment-mid [ 1 = [ 1 ] [ 0 ] if ] } [ 2drop 0 ] } case + ; : stereo-decorrelation ( samples channel-assignment -- samples' ) { { channel-assignment-independent [ ] } ! do nothing { channel-assignment-left [ [ first ] [ first ] [ second ] tri [ - ] 2map 2array ] } { channel-assignment-right [ [ second ] [ first ] [ second ] tri [ + ] 2map swap 2array ] } { channel-assignment-mid [ [ first ] [ second ] bi { { } { } } [ [ over ] dip [ [ first ] dip suffix ] [ [ second ] dip suffix ] 2bi* 2array ] 2reduce ] } } case ; :: read-flac-subframe ( frame-header channel -- samples ) read-flac-subframe-header :> subframe-header subframe-header wasted-bits>> :> wasted-bits subframe-header subframe-type>> :> subframe-type subframe-header predictor-order>> :> predictor-order frame-header bits-per-sample>> :> bps frame-header blocksize>> :> blocksize frame-header channel-assignment>> :> channel-assignment bps wasted-bits channel-assignment channel calculate-sample-depth :> sample-depth subframe-type { { subframe-type-constant [ blocksize sample-depth read-flac-subframe-constant ] } { subframe-type-verbatim [ blocksize sample-depth read-flac-subframe-verbatim ] } { subframe-type-fixed [ blocksize sample-depth predictor-order read-flac-subframe-fixed ] } { subframe-type-lpc [ blocksize sample-depth predictor-order read-flac-subframe-lpc ] } } case :> samples! wasted-bits samples adjust-wasted-bits ; : read-flac-subframes ( frame-header channels -- samples ) [ dup channel-assignment>> swap ] dip [ read-flac-subframe ] with map swap stereo-decorrelation ; ! : read-flac-frame-footer ( -- frame-footer ) 16 flac-read flac-frame-footer boa ; : read-flac-frame ( stream-info -- frame ) [ read-flac-frame-header dup ] [ channels>> ] bi read-flac-subframes flac-align-to-byte read-flac-frame-footer flac-frame boa ;