Class: FlacInfo
- Inherits:
-
Object
- Object
- FlacInfo
- Defined in:
- lib/flacinfo.rb
Overview
STREAMINFO is the only block guaranteed to be present in the Flac file. All attributes will be present but empty if the associated block is not present in the Flac file, except for ‘picture’ which will have the key ‘n’ with the value ‘0’. All ‘offset’ and ‘block_size’ values do not include the block header. All block headers are 4 bytes no matter the type, so if you need the offset including the header, subtract 4. If you need the size including the header, add 4.
Constant Summary collapse
- STANDARD_FIELD_NAMES =
A list of ‘standard field names’ according to the Vorbis Comment specification. It is certainly possible to use a non-standard name, but the spec recommends against it. See: www.xiph.org/vorbis/doc/v-comment.html
%w[TITLE VERSION ALBUM TRACKNUMBER ARTIST PERFORMER COPYRIGHT LICENSE ORGANIZATION DESCRIPTION GENRE DATE LOCATION CONTACT ISRC].freeze
Instance Attribute Summary collapse
-
#application ⇒ Object
readonly
Hash of values extracted from the APPLICATION block.
-
#comment ⇒ Object
Array of “name=value” strings extracted from the VORBIS_COMMENT block.
-
#cuesheet ⇒ Object
readonly
Hash of values extracted from the CUESHEET block.
-
#flac_file ⇒ Object
readonly
Hash of values extracted from an APPLICATION block if it is type 0x41544348 (Flac File).
-
#padding ⇒ Object
readonly
Hash of values extracted from the PADDING block.
-
#picture ⇒ Object
readonly
Hash of values extracted from one or more PICTURE blocks.
-
#seektable ⇒ Object
readonly
Hash of values extracted from the SEEKTABLE block.
-
#streaminfo ⇒ Object
readonly
Hash of values extracted from the STREAMINFO block.
-
#tags ⇒ Object
readonly
- Hash of the ‘comment’ values separated into “key => value” pairs as well as the keys: ‘offset’
-
The VORBIS_COMMENT block’s offset from the beginning of the file (not including the block header).
Instance Method Summary collapse
-
#comment_add(name) ⇒ Object
Adds a new comment to the comment array.
-
#comment_del(name) ⇒ Object
Deletes a comment from the comment array.
-
#hastag?(tag) ⇒ Boolean
Returns true if @tags has a value, false otherwise.
-
#initialize(filename) ⇒ FlacInfo
constructor
FlacInfo is the class for parsing Flac files.
-
#inspect ⇒ Object
– This cleans up the output when using FlacInfo in irb.
-
#meta_flac ⇒ Object
This method produces output similar to ‘metaflac –list’.
-
#padding_add!(size = 4096) ⇒ Object
Adds a padding block.
-
#padding_del! ⇒ Object
Removes a padding block.
-
#padding_resize!(size = 4096) ⇒ Object
Resizes a padding block.
-
#print_seektable ⇒ Object
Pretty print the seektable.
-
#print_streaminfo ⇒ Object
Pretty print streaminfo hash.
-
#print_tags ⇒ Object
Pretty print tags hash.
-
#raw_data_dump(outfile = nil) ⇒ Object
Dumps the contents of flac_file.
-
#update! ⇒ Object
Writes Vorbis tag changes to disk.
-
#write_picture(args = {}) ⇒ Object
Writes embedded images to a file.
Constructor Details
#initialize(filename) ⇒ FlacInfo
FlacInfo is the class for parsing Flac files.
:call-seq:
FlacInfo.new(file) -> FlacInfo instance
143 144 145 146 |
# File 'lib/flacinfo.rb', line 143 def initialize(filename) @filename = filename end |
Instance Attribute Details
#application ⇒ Object (readonly)
Hash of values extracted from the APPLICATION block. Keys are:
- ‘offset’
-
The APPLICATION block’s offset from the beginning of the file (not including the block header).
- ‘block_size’
-
The size of the APPLICATION block (not including the block header).
- ‘ID’
-
Registered application ID. See flac.sourceforge.net/id.html
- ‘name’
-
Name of the registered application ID.
102 103 104 |
# File 'lib/flacinfo.rb', line 102 def application @application end |
#comment ⇒ Object
Array of “name=value” strings extracted from the VORBIS_COMMENT block. This is just the contents, metadata is in ‘tags’. You should not normally operate on this array directly. Rather, use the comment_add and comment_del methods to make changes.
89 90 91 |
# File 'lib/flacinfo.rb', line 89 def comment @comment end |
#cuesheet ⇒ Object (readonly)
Hash of values extracted from the CUESHEET block. Keys are:
- ‘offset’
-
The CUESHEET block’s offset from the beginning of the file (not including the block header).
- ‘block_size’
-
The size of the CUESHEET block (not including the block header).
112 113 114 |
# File 'lib/flacinfo.rb', line 112 def cuesheet @cuesheet end |
#flac_file ⇒ Object (readonly)
Hash of values extracted from an APPLICATION block if it is type 0x41544348 (Flac File). Keys are:
- ‘description’
-
A brief text description of the contents.
- ‘mime_type’
-
The Mime type of the contents.
- ‘raw_data’
-
The contents. May be binary.
136 137 138 |
# File 'lib/flacinfo.rb', line 136 def flac_file @flac_file end |
#padding ⇒ Object (readonly)
Hash of values extracted from the PADDING block. Keys are:
- ‘offset’
-
The PADDING block’s offset from the beginning of the file (not including the block header).
- ‘block_size’
-
The size of the PADDING block (not including the block header).
107 108 109 |
# File 'lib/flacinfo.rb', line 107 def padding @padding end |
#picture ⇒ Object (readonly)
Hash of values extracted from one or more PICTURE blocks. This hash always includes the key ‘n’ which is the number of PICTURE blocks found, else ‘0’. For each block found there will be an integer key starting from 1. Each of these is a hash which contains the keys:
- ‘offset’
-
The PICTURE block’s offset from the beginning of the file (not including the block header).
- ‘block_size’
-
The size of the PICTURE block (not including the block header).
- ‘type_int’
-
The picture type according to the ID3v2 APIC frame.
- ‘type_string’
-
A text value representing the picture type.
- ‘description_string’
-
A text description of the picture.
- ‘mime_type’
-
The MIME type string. May be ‘–>’ to signify that the data part is a URL of the picture.
- ‘colour_depth’
-
The colour depth of the picture in bits-per-pixel.
- ‘n_colours’
-
For indexed-colour pictures (e.g. GIF), the number of colours used, or 0 for non-indexed pictures.
- ‘width’
-
The width of the picture in pixels.
- ‘height’
-
The height of the picture in pixels.
- ‘raw_data_offset’
-
The raw picture data’s offset from the beginning of the file.
- ‘raw_data_length’
-
The length of the picture data in bytes.
129 130 131 |
# File 'lib/flacinfo.rb', line 129 def picture @picture end |
#seektable ⇒ Object (readonly)
Hash of values extracted from the SEEKTABLE block. Keys are:
- ‘offset’
-
The SEEKTABLE block’s offset from the beginning of the file (not including the block header).
- ‘block_size’
-
The size of the SEEKTABLE block (not including the block header).
- ‘seek_points’
-
The number of seek points in the block.
- ‘points’
-
Another hash whose keys start at 0 and end at (‘seek_points’ - 1). Each “seektable[n]” hash contains an array whose (integer) values are:
- ‘0’
-
Sample number of first sample in the target frame, or 0xFFFFFFFFFFFFFFFF for a placeholder point.
- ‘1’
-
Offset (in bytes) from the first byte of the first frame header to the first byte of the target frame’s header.
- ‘2’
-
Number of samples in the target frame.
85 86 87 |
# File 'lib/flacinfo.rb', line 85 def seektable @seektable end |
#streaminfo ⇒ Object (readonly)
Hash of values extracted from the STREAMINFO block. Keys are:
- ‘offset’
-
The STREAMINFO block’s offset from the beginning of the file (not including the block header).
- ‘block_size’
-
The size of the STREAMINFO block (not including the block header).
- ‘minimum_block’
-
The minimum block size (in samples) used in the stream.
- ‘maximum_block’
-
The maximum block size (in samples) used in the stream.
- ‘minimum_frame’
-
The minimum frame size (in bytes) used in the stream.
- ‘maximum_frame’
-
The maximum frame size (in bytes) used in the stream.
- ‘samplerate’
-
Sample rate in Hz.
- ‘channels’
-
The number of channels used in the stream.
- ‘bits_per_sample’
-
The number of bits per sample used in the stream.
- ‘total_samples’
-
The total number of samples in stream.
- ‘md5’
-
MD5 signature of the unencoded audio data.
74 75 76 |
# File 'lib/flacinfo.rb', line 74 def streaminfo @streaminfo end |
#tags ⇒ Object (readonly)
Hash of the ‘comment’ values separated into “key => value” pairs as well as the keys:
- ‘offset’
-
The VORBIS_COMMENT block’s offset from the beginning of the file (not including the block header).
- ‘block_size’
-
The size of the VORBIS_COMMENT block (not including the block header).
- ‘vendor_tag’
-
Typically, the name and version of the software that encoded the file.
95 96 97 |
# File 'lib/flacinfo.rb', line 95 def @tags end |
Instance Method Details
#comment_add(name) ⇒ Object
Adds a new comment to the comment array
:call-seq:
FlacInfo.comment_add(str) -> bool
‘str’ must be in the form ‘name=value’, or ‘name=’ if you want to set an empty value for a particular tag. Returns ‘true’ if successful, false otherwise. Remember to call ‘update!’ to write changes to the file.
337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/flacinfo.rb', line 337 def comment_add(name) if name !~ /\w=/ # We accept 'name=' in case you want to leave the value empty raise FlacInfoError, "comments must be in the form 'name=value'" end begin @comment << name @comments_changed = 1 rescue StandardError return false end true end |
#comment_del(name) ⇒ Object
Deletes a comment from the comment array
:call-seq:
FlacInfo.comment_del(str) -> bool
If ‘str’ is in the form ‘name=value’ only exact matches will be deleted. If ‘str’ is in the form ‘name’ any and all comments named ‘name’ will be deleted. Returns ‘true’ if a comment was deleted, false otherwise. Remember to call ‘update!’ to write changes to the file.
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/flacinfo.rb', line 362 def comment_del(name) bc = Array.new(@comment) # We need a copy nc = if name.include? '=' @comment.delete_if { |x| x == name } else @comment.delete_if { |x| x.split('=')[0] == name } end if nc == bc false else @comments_changed = 1 true end end |
#hastag?(tag) ⇒ Boolean
153 154 155 |
# File 'lib/flacinfo.rb', line 153 def hastag?(tag) @tags[tag.to_s] ? true : false end |
#inspect ⇒ Object
–
This cleans up the output when using FlacInfo in irb
422 423 424 425 426 427 428 |
# File 'lib/flacinfo.rb', line 422 def inspect # :nodoc: s = "#<#{self.class}:0x#{(object_id * 2).to_s(16)} " @metadata_blocks.each do |blk| s += "(#{blk[0].upcase} size=#{blk[4]} offset=#{blk[3]}) " end "#{s}\b>" end |
#meta_flac ⇒ Object
This method produces output similar to ‘metaflac –list’.
:call-seq:
FlacInfo.meta_flac -> nil
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/flacinfo.rb', line 208 def n = 0 pictures_seen = 0 @metadata_blocks.each do |block| puts "METADATA block ##{n}" puts " type: #{block[1]} (#{block[0].upcase})" puts " is last: #{block[2].zero? ? 'false' : 'true'}" case block[1] when 0 when 1 when 2 when 3 when 4 when 5 when 6 pictures_seen += 1 (pictures_seen) else # This will never run ... file already parsed. raise FlacInfoError, 'Unknown metadata blocktype found' end n += 1 end nil end |
#padding_add!(size = 4096) ⇒ Object
Adds a padding block
:call-seq:
FlacInfo.padding_add!(size) --> Boolean
‘size’ is an optional integer argument for the size of the padding block. It defaults to 4096 bytes. Returns true if successful, else false.
387 388 389 390 391 392 |
# File 'lib/flacinfo.rb', line 387 def padding_add!(size = 4096) @metadata_blocks.each do |type| raise FlacInfoError, "PADDING block exists. Use 'padding_resize!'" if type[0] == 'padding' end build_padding_block(size) ? true : false end |
#padding_del! ⇒ Object
Removes a padding block
:call-seq:
FlacInfo.padding_del!() --> Boolean
Returns true if the padding block is successfully removed else false.
402 403 404 |
# File 'lib/flacinfo.rb', line 402 def padding_del! remove_padding_block ? true : false end |
#padding_resize!(size = 4096) ⇒ Object
Resizes a padding block
:call-seq:
FlacInfo.padding_resize!(size) --> Boolean
‘size’ is an optional integer argument for the size of the new padding block. It defaults to 4096 bytes. Returns true if successful, else false.
415 416 417 418 |
# File 'lib/flacinfo.rb', line 415 def padding_resize!(size = 4096) remove_padding_block build_padding_block(size) end |
#print_seektable ⇒ Object
Pretty print the seektable.
:call-seq:
FlacInfo.print_seektable -> nil
Raises FlacInfoError if METADATA_BLOCK_SEEKTABLE is not present.
189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/flacinfo.rb', line 189 def print_seektable raise FlacInfoError, 'METADATA_BLOCK_SEEKTABLE not present' if @seektable == {} puts " seek points: #{@seektable['seek_points']}" n = 0 @seektable['seek_points'].times do print " point #{n}: sample number: #{@seektable['points'][n][0]}, " print "stream offset: #{@seektable['points'][n][1]}, " print "frame samples: #{@seektable['points'][n][2]}\n" n += 1 end nil end |
#print_streaminfo ⇒ Object
Pretty print streaminfo hash.
:call-seq:
FlacInfo.print_streaminfo -> nil
176 177 178 179 180 |
# File 'lib/flacinfo.rb', line 176 def print_streaminfo # No test: METADATA_BLOCK_STREAMINFO must be present in valid Flac file @streaminfo.each_pair { |key, val| puts "#{key}: #{val}" } nil end |
#print_tags ⇒ Object
Pretty print tags hash.
:call-seq:
FlacInfo.print_tags -> nil
Raises FlacInfoError if METADATA_BLOCK_VORBIS_COMMENT is not present.
164 165 166 167 168 169 |
# File 'lib/flacinfo.rb', line 164 def raise FlacInfoError, 'METADATA_BLOCK_VORBIS_COMMENT not present' if @tags == {} @tags.each_pair { |key, val| puts "#{key}: #{val}" } nil end |
#raw_data_dump(outfile = nil) ⇒ Object
Dumps the contents of flac_file
:call-seq:
FlacInfo.raw_data_dump() -> nil
FlacInfo.raw_data_dump(outfile) -> nil
If passed with ‘outfile’, the data will be written to a file with that name otherwise it is written to the console (even if binary!). Raises FlacInfoError if there is no Flac File data present.
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/flacinfo.rb', line 250 def raw_data_dump(outfile = nil) raise FlacInfoError, 'Flac File data not present' if @flac_file == {} if outfile.nil? puts @flac_file['raw_data'] else f = if @flac_file['mime_type'] =~ /text/ File.new(outfile, 'w') else File.new(outfile, 'wb') end f.write(@flac_file['raw_data']) f.close end end |
#update! ⇒ Object
Writes Vorbis tag changes to disk
:call-seq:
FlacInfo.update! -> bool
Returns true if write was successful, false otherwise.
324 325 326 |
# File 'lib/flacinfo.rb', line 324 def update! write_to_disk ? true : false end |
#write_picture(args = {}) ⇒ Object
Writes embedded images to a file
:call-seq:
FlacInfo.write_picture() -> nil
FlacInfo.write_picture(:outfile=>"str") -> nil
FlacInfo.write_picture(:n=>int) -> nil
FlacInfo.write_picture(:outfile=>"str", :n=>int) -> nil
If passed with ‘:outfile’, the image will be written to a file with that name otherwise it is written to the value of the ‘album’ tag if it exists, otherwise it is written to ‘flacimage’. All three of these will have a dot plus the relevant file extension appended. The argument to ‘:n’ is which image to write in case of multiples.
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/flacinfo.rb', line 279 def write_picture(args = {}) raise FlacInfoError, 'There is no METADATA_BLOCK_PICTURE' if @picture['n'].zero? n = if args.key?(:n) args[:n] else 1 end # "image/jpeg" => "jpeg" extension = @picture[n]['mime_type'].split('/')[1] outfile = if !args.key?(:outfile) if [nil, ''].include?(@tags['album']) "flacimage#{n}.#{extension}" else # Try to use contents of "album" tag for the filename "#{@tags['album']}#{n}.#{extension}" end else "#{args[:outfile]}.#{extension}" end in_p = File.new(@filename, 'rb') out_p = File.new(outfile, 'wb') out_p.binmode # For Windows folks... in_p.seek(@picture[n]['raw_data_offset'], IO::SEEK_CUR) raw_data = in_p.read(@picture[n]['raw_data_length']) out_p.write(raw_data) in_p.close out_p.close nil end |