initial flac metadata read

flac
Steve Ayerhart 2020-02-25 22:45:30 -06:00
parent 2235eadf04
commit 1dfba430a8
No known key found for this signature in database
GPG Key ID: 5BFD39C5359E967D
8 changed files with 371 additions and 0 deletions

1
extra/flac/authors.txt Normal file
View File

@ -0,0 +1 @@
Steve Ayerhart

View File

@ -0,0 +1,82 @@
! 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: prettyprint ;
USING: flac.metadata.private flac.metadata ;
QUALIFIED: bitstreams
IN: flac.decoder
ALIAS: read-bit bitstreams:read
CONSTANT: sync-code 16382
ERROR: sync-code-error ;
ENUM: flac-channel-assignment
channel-assignment-independent
channel-assignment-left-side
channel-assignment-right-side
channel-assignment-mid-side ;
ENUM: flac-frame-number-type
frame-number-type-frame
frame-number-type-sample ;
ENUM: flac-subframe-type
subframe-type-constant
subframe-type-verbatim
subframe-type-fixed
subframe-type-lpc ;
ENUM: flac-entropy-coding-method
entropy-coding-partioned-rice
entropy-coding-partioned-rice2 ;
TUPLE: subframe
{ type maybe{ subframe-type-constant
subframe-type-verbatim
subframe-type-fixed
subframe-type-lpc } } ;
TUPLE: frame-header
{ 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 } }
{ bits-per-sample integer }
{ number-type maybe{ frame-number-type-frame frame-number-type-sample } }
{ number integer }
{ crc integer } ;
TUPLE: frame-footer
{ crc integer } ;
:: read-sync-code ( bitstream -- ? )
14 bitstream read-bit sync-code = ;
:: (decode-frame-header) ( bitstream -- )
[
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 .
] with-big-endian ;
: decode-frame-header ( -- )
[
3 read bitstreams:<msb0-bit-reader> (decode-frame-header)
] with-big-endian ;
: decode-file ( filename -- )
binary
[
read-flac-magic [ not-a-flac-file ] unless
read-stream-info drop
skip-metadata
decode-frame-header
] with-file-reader ;

View File

@ -0,0 +1,10 @@
! Copyright (C) 2020 .
! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax ;
IN: flac
ARTICLE: "flac" "flac"
{ $vocab-link "flac" }
;
ABOUT: "flac"

View File

@ -0,0 +1,4 @@
! Copyright (C) 2020 .
! See http://factorcode.org/license.txt for BSD license.
USING: tools.test flac ;
IN: flac.tests

5
extra/flac/flac.factor Normal file
View File

@ -0,0 +1,5 @@
! Copyright (C) 2020 .
! See http://factorcode.org/license.txt for BSD license.
USING: ;
IN: flac

View File

@ -0,0 +1,267 @@
! Copyright (C) 2020 .
! See http://factorcode.org/license.txt for BSD license.
USING: endian sequences kernel classes.struct io io.binary io.files io.encodings io.encodings.string io.encodings.utf8 io.encodings.binary alien.c-types alien.endian math locals accessors prettyprint combinators pack math.parser strings arrays io.streams.byte-array sequences.generalizations assocs splitting byte-arrays alien.syntax alien.enums io.encodings.ascii ;
QUALIFIED: bitstreams
IN: flac.metadata
ALIAS: read-bit bitstreams:read
CONSTANT: FLAC-MAGIC "fLaC"
ENUM: metadata-type
metadata-stream-info
metadata-padding
metadata-application
metadata-seek-table
metadata-vorbis-comment
metadata-cuesheet
metadata-picture
{ metadata-invalid 127 } ;
ERROR: not-a-flac-file ;
ERROR: cuesheet-index-reserved-must-be-zero ;
TUPLE: metadata-block-header
{ last? boolean }
{ type maybe{ metadata-stream-info
metadata-padding
metadata-application
metadata-seek-table
metadata-vorbis-comment
metadata-cuesheet
metadata-picture
metadata-invalid } }
{ length integer } ;
TUPLE: stream-info
{ min-block-size integer }
{ max-block-size integer }
{ min-frame-size integer }
{ max-frame-size integer }
{ sample-rate integer }
{ channels integer }
{ bits-per-sample integer }
{ samples integer }
{ md5 string } ;
TUPLE: seek-table
{ seek-points array } ;
TUPLE: seek-point
{ sample-number integer }
{ offset integer }
{ total-samples } ;
TUPLE: vorbis-comment
{ vendor-string string }
{ comments assoc } ;
TUPLE: padding
{ length integer } ;
TUPLE: application
{ id string }
{ data byte-array } ;
ENUM: cuesheet-track-type audio non-audio ;
TUPLE: cuesheet-track
{ offset integer }
{ number number }
{ isrc string }
{ type integer }
{ pre-emphasis boolean }
{ indices array } ;
TUPLE: cuesheet-index
{ offset integer }
{ number integer } ;
TUPLE: cuesheet
{ catalog-number integer }
{ lead-in integer }
{ cd? boolean }
{ tracks array } ;
ENUM: picture-type
other
file-icon
other-file-icon
front-cover
back-cover
leaflet-page
media
lead-artist/performer/soloist
artist/performer
conductor
band/orchestra
composer
lyricist/text-writer
recording-location
during-recording
during-performance
movie/video-screen-capture
bright-coloured-fish
illustration
badn/artist-logotype
publisher/studio-logotype ;
TUPLE: picture
type
{ mime-type string }
{ description string }
{ width integer }
{ height integer }
{ depth integer }
{ colors integer }
{ data byte-array } ;
TUPLE: metadata
{ stream-info stream-info }
{ padding maybe{ padding } }
{ application maybe{ application } }
{ seek-table maybe{ seek-table } }
{ vorbis-comment maybe{ vorbis-comment } }
{ cuesheet maybe{ cuesheet } }
{ picture maybe{ picture } } ;
<PRIVATE
: read-flac-magic ( -- magic )
4 read utf8 decode FLAC-MAGIC = ;
:: (parse-metadata-block-header) ( bitstream -- header )
[
1 bitstream read-bit 1 =
7 bitstream read-bit <metadata-type>
24 bitstream read-bit
] with-big-endian
metadata-block-header boa ;
: parse-metadata-block-header ( byte-array -- header )
bitstreams:<msb0-bit-reader> (parse-metadata-block-header) ;
: read-metadata-block-header ( -- header )
4 read parse-metadata-block-header dup . ;
:: (parse-stream-info) ( bitstream -- stream-info )
[
16 bitstream read-bit
16 bitstream read-bit
24 bitstream read-bit
24 bitstream read-bit
20 bitstream read-bit
3 bitstream read-bit 1 +
5 bitstream read-bit 1 +
36 bitstream read-bit
128 bitstream read-bit u128>byte-array bytes>hex-string
] with-big-endian
stream-info boa ;
: parse-stream-info ( byte-array -- stream-info )
bitstreams:<msb0-bit-reader> (parse-stream-info) ;
: parse-seek-table ( byte-array -- seek-table )
dup
binary
[
length 18 / <iota>
[ drop 8 read be> 8 read be> 2 read be> seek-point boa ] map
] with-byte-reader
seek-table boa ;
: parse-vorbis-comment ( byte-array -- comments )
binary
[
4 read le> read utf8 decode
4 read le> <iota> [
drop
4 read le> read utf8 decode
"=" split
] map
] with-byte-reader >alist vorbis-comment boa ;
: parse-padding ( byte-array -- padding )
length padding boa ;
: parse-application ( byte-array -- application )
drop application new ;
: parse-cuesheet ( byte-array -- cuesheet )
binary
[
128 read ascii decode
8 read be>
259 read drop f
1 read be> <iota> [
drop
8 read be>
1 read be>
12 read ascii decode
21 read drop 0 <cuesheet-track-type> t
1 read <iota> [
drop
8 read be>
1 read be>
3 read be> = 0 [ cuesheet-index-reserved-must-be-zero ] unless
cuesheet-index boa
] map
cuesheet-track boa
] map
] with-byte-reader cuesheet boa ;
: parse-picture ( byte-array -- picture )
binary
[
4 read be> <picture-type>
4 read be> read utf8 decode
4 read be> read utf8 decode
4 read be>
4 read be>
4 read be>
4 read be>
4 read be> read
] with-byte-reader picture boa ;
: read-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 ] }
} case ;
PRIVATE>
: read-stream-info ( -- stream-info )
read-metadata-block-header
length>> read bitstreams:<msb0-bit-reader> parse-stream-info ;
: skip-metadata ( -- )
[
read-metadata-block-header
[ length>> read drop ] [ last?>> not ] bi
] loop ;
! TODO: handle other formats gracefully such as ID3
: read-metadata ( filename -- metadata )
binary
[
read-flac-magic [ not-a-flac-file ] unless
metadata new
[
read-metadata-block-header
[ length>> read ] [ type>> ] [ last?>> not ] tri
[ read-metadata-block ] dip
] loop
] with-file-reader ;
: <flac-metadata> ( filename -- metadata )
read-metadata ;
:: write-something ( bitstream -- header )
1 1 bitstream bitstreams:poke
1 7 bitstream bitstreams:poke
34 24 bitstream bitstreams:poke
bitstream bitstreams:bit-writer-bytes ;

1
extra/flac/summary.txt Normal file
View File

@ -0,0 +1 @@
flac

1
extra/flac/tags.txt Normal file
View File

@ -0,0 +1 @@
flac audio