add ffi and metadata

master
Steve Ayerhart 2021-06-06 12:53:59 -04:00
parent ebd93fd55f
commit eb6b7e9c10
No known key found for this signature in database
GPG Key ID: 5C815FDF3A00B8BA
2 changed files with 287 additions and 0 deletions

147
flac/ffi/ffi.factor Normal file
View File

@ -0,0 +1,147 @@
! Copyright (C) 2020 .
! See http://factorcode.org/license.txt for BSD license.
USING: system combinators alien alien.libraries alien.syntax alien.c-types classes.struct ;
IN: flac.ffi
<<
"avcodec" {
{ [ os unix? ] [ "libFLAC.so" ] }
} cond cdecl add-library
>>
TYPEDEF: int FLAC__bool
TYPEDEF: int16_t FLAC__int16
TYPEDEF: int32_t FLAC__int32
TYPEDEF: int64_t FLAC__int64
TYPEDEF: uint FLAC__uint8
TYPEDEF: uint16_t FLAC__uint16
TYPEDEF: uint32_t FLAC__uint32
TYPEDEF: uint64_t FLAC__uint64
TYPEDEF: uint unsigned
TYPEDEF: uint8_t FLAC__byte
ENUM: FLAC__MetadataType
FLAC__METADATA_TYPE_STREAMINFO
FLAC__METADATA_TYPE_PADDING
FLAC__METADATA_TYPE_APPLICATION
FLAC__METADATA_TYPE_SEEKTABLE
FLAC__METADATA_TYPE_VORBIS_COMMENT
FLAC__METADATA_TYPE_CUESHEET
FLAC__METADATA_TYPE_PICTURE
FLAC__METADATA_TYPE_UNDEFINED
FLAC__METADATA_TYPE_TYPE ;
STRUCT: FLAC__StreamMetadata_StreamInfo
{ min_blocksize unsigned }
{ max_blocksize unsigned }
{ min_framesize unsigned }
{ max_framesize unsigned }
{ sample_rate unsigned }
{ channels unsigned }
{ bits_per_sample unsigned }
{ total_samples FLAC__uint64 }
{ md5sum FLAC__byte[16] } ;
STRUCT: FLAC__StreamMetadata_Padding
{ dummy int } ;
STRUCT: FLAC__StreamMetadata_Application
{ id FLAC__byte[4] }
{ data FLAC__byte* } ;
STRUCT: FLAC__StreamMetadata_SeekPoint
{ sample_number FLAC__uint64 }
{ stream_offset FLAC__uint64 }
{ frame_samples unsigned } ;
STRUCT: FLAC__StreamMetadata_SeekTable
{ num_points unsigned }
{ points FLAC__StreamMetadata_SeekPoint* } ;
STRUCT: FLAC__StreamMetadata_VorbisComment_Entry
{ length FLAC__uint32 }
{ entry FLAC__byte* } ;
STRUCT: FLAC__StreamMetadata_VorbisComment
{ vendor_string FLAC__StreamMetadata_VorbisComment_Entry }
{ num_comments FLAC__uint32 }
{ comments FLAC__StreamMetadata_VorbisComment_Entry* } ;
STRUCT: FLAC__StreamMetadata_CueSheet_Index
{ offset FLAC__uint64 }
{ number FLAC__byte } ;
STRUCT: FLAC__StreamMetadata_CueSheet_Track
{ offset FLAC__uint64 }
{ number FLAC__byte }
{ isrc char[13] }
{ type unsigned bits: 1 }
{ pre_emphasis unsigned bits: 1 }
{ num_indices FLAC__byte }
{ indices FLAC__StreamMetadata_CueSheet_Index* } ;
STRUCT: FLAC__StreamMetadata_CueSheet
{ media_catalog_number char[129] }
{ lead_in FLAC__uint64 }
{ is_cd FLAC__bool }
{ num_tracks unsigned }
{ tracks FLAC__StreamMetadata_CueSheet_Track* } ;
ENUM: FLAC__StreamMetadata_Picture_Type
FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER
FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD
FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON
FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER
FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER
FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE
FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA
FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST
FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST
FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR
FLAC__STREAM_METADATA_PICTURE_TYPE_BAND
FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER
FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST
FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION
FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING
FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE
FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE
FLAC__STREAM_METADATA_PICTURE_TYPE_FISH
FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION
FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE
FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE ;
STRUCT: FLAC__StreamMetadata_Picture
{ type FLAC__StreamMetadata_Picture_Type }
{ mime_type char* }
{ description FLAC__byte* }
{ width FLAC__uint32 }
{ height FLAC__uint32 }
{ depth FLAC__uint32 }
{ colors FLAC__uint32 }
{ data_length FLAC__uint32 }
{ data FLAC__byte* } ;
STRUCT: FLAC__StreamMetadata_Unknown
{ data FLAC__byte* } ;
UNION-STRUCT: metadata-union
{ stream_info FLAC__StreamMetadata_StreamInfo }
{ padding FLAC__StreamMetadata_Padding }
{ application FLAC__StreamMetadata_Application }
{ seek_table FLAC__StreamMetadata_SeekTable }
{ vorbis_comment FLAC__StreamMetadata_VorbisComment }
{ cue_sheet FLAC__StreamMetadata_CueSheet }
{ picture FLAC__StreamMetadata_Picture }
{ unknown FLAC__StreamMetadata_Unknown } ;
STRUCT: FLAC__StreamMetadata
{ type FLAC__MetadataType }
{ is_last FLAC__bool }
{ length unsigned }
{ data metadata-union } ;
FUNCTION: FLAC__bool FLAC__metadata_get_streaminfo ( c-string filename, FLAC__StreamMetadata* streaminfo )
FUNCTION: FLAC__bool FLAC__metadata_get_tags ( c-string filename, FLAC__StreamMetadata** streaminfo )

View File

@ -0,0 +1,140 @@
! Copyright (C) 2020 .
! See http://factorcode.org/license.txt for BSD license.
USING: endian sequences kernel classes.struct 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 math.parser strings arrays io.streams.byte-array sequences.generalizations assocs splitting byte-arrays alien.syntax alien.enums io.encodings.ascii pack ;
USING: flac.bitstream flac.format ;
QUALIFIED: bitstreams
QUALIFIED: io
IN: flac.metadata
ERROR: cuesheet-index-reserved-must-be-zero ;
: read-metadata-block-header ( -- header )
1 flac-read-uint 1 =
7 flac-read-uint <metadata-type>
24 flac-read-uint
metadata-block-header boa ;
: read-metadata-block-stream-info ( -- stream-info )
16 flac-read-uint
16 flac-read-uint
24 flac-read-uint
24 flac-read-uint
20 flac-read-uint
3 flac-read-uint 1 +
5 flac-read-uint 1 +
36 flac-read-uint
128 flac-read-uint 16 >be bytes>hex-string
stream-info boa ;
: read-metadata-block-seek-table ( length -- seek-table )
18 / <iota> [
drop
64 flac-read-uint
64 flac-read-uint
16 flac-read-uint
seek-point boa
] map
seek-table boa ;
: read-metadata-block-vorbis-comment ( length -- vorbis-comment )
! vorbis comments are in little endian...
drop
32 flac-read-uint 4 >le be> dup 8 * flac-read-uint swap >n-byte-array utf8 decode
32 flac-read-uint 4 >le be> <iota>
[
drop
32 flac-read-uint 4 >le be> dup 8 * flac-read-uint swap >n-byte-array utf8 decode
"=" split
] map
>alist vorbis-comment boa ;
: encode-vorbis-string ( str -- byte-array )
dup binary [ length 4 >le io:write utf8 encode io:write ] with-byte-writer ;
: encode-vorbis-comments ( assoc -- byte-array )
dup binary [
length 4 >le io:write
[ 2array "=" join encode-vorbis-string io:write ] assoc-each
] with-byte-writer ;
: encode-vorbis-comment ( vorbis-comment -- byte-array )
binary [
[ vendor-string>> encode-vorbis-string io:write ]
[ comments>> encode-vorbis-comments io:write ] bi
] with-byte-writer ;
: encode-padding ( padding -- byte-array )
length>> <byte-array> ;
: read-metadata-block-padding ( length -- padding )
dup 8 * flac-read-uint drop flac-padding boa ;
: read-metadata-block-application ( length -- application )
8 * flac-read-uint drop application new ;
: read-metadata-block-cuesheet ( length -- cuesheet )
dup [ 8 * flac-read-uint ] dip >be
binary
[
128 io:read ascii decode
8 io:read be>
259 io:read drop f
1 io:read be> <iota> [
drop
8 io:read be>
1 io:read be>
12 io:read ascii decode
21 io:read drop 0 <cuesheet-track-type> t
1 io:read <iota> [
drop
8 io:read be>
1 io:read be>
3 io:read be> = 0 [ cuesheet-index-reserved-must-be-zero ] unless
cuesheet-index boa
] map
cuesheet-track boa
] map
] with-byte-reader cuesheet boa ;
: read-metadata-block-picture ( length -- picture )
drop
32 flac-read-uint <picture-type>
32 flac-read-uint dup 8 * flac-read-uint swap >n-byte-array utf8 decode
32 flac-read-uint dup 8 * flac-read-uint swap >n-byte-array utf8 decode
32 flac-read-uint
32 flac-read-uint
32 flac-read-uint
32 flac-read-uint
32 flac-read-uint dup 8 * flac-read-uint swap >n-byte-array
picture boa ;
: read-metadata-block ( metadata length type -- metadata )
[
{
{ metadata-stream-info [ drop read-metadata-block-stream-info >>stream-info ] }
{ metadata-padding [ read-metadata-block-padding >>padding ] }
{ metadata-application [ read-metadata-block-application >>application ] }
{ metadata-seek-table [ read-metadata-block-seek-table >>seek-table ] }
{ metadata-vorbis-comment [ read-metadata-block-vorbis-comment >>vorbis-comment ] }
{ metadata-cuesheet [ read-metadata-block-cuesheet >>cuesheet ] }
{ metadata-picture [ read-metadata-block-picture >>picture ] }
} case
] with-big-endian ;
: read/assert-flac-magic ( -- )
32 flac-read-uint FLAC-MAGIC = [ not-a-flac-file ] unless ;
: read-flac-metadata ( -- metadata )
read/assert-flac-magic
metadata new
[
read-metadata-block-header
[ length>> ] [ type>> ] [ last?>> not ] tri
[ read-metadata-block ] dip
] loop ;
: <flac-metadata> ( filename -- metadata )
[ read-flac-metadata ] with-flac-file-reader ;