flacinfo-rb 0.1 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/README +4 -2
  2. data/{lib/flacinfo.rb → flacinfo.rb} +226 -45
  3. metadata +5 -4
data/README CHANGED
@@ -17,8 +17,9 @@ seektable :: hash of arrays of seek points
17
17
  comment :: array of VORBIS COMMENT block metadata
18
18
  tags :: user-friendly hash of Vorbis comment metadata key=value pairs
19
19
  application :: hash of APPLICATION block metadata
20
- padding :: hash of PADDING block metadata (currently just ['block_size'])
21
- cuesheet :: hash of CUESHEET block metadata (currently just ['block_size'])
20
+ padding :: hash of PADDING block metadata
21
+ cuesheet :: hash of CUESHEET block metadata
22
+ picture :: hash of PICTURE block metadata
22
23
  flac_file :: hash of APPLICATION Id 0x41544348 (Flac File) metadata if present
23
24
 
24
25
  == Public methods ==
@@ -30,6 +31,7 @@ print_seektable :: pretty-print seektable hash
30
31
  meta_flac :: prints all META BLOCKS. (Mostly) equivelant to 'metaflac --list'
31
32
  raw_data_dump(?) :: if passed a filename it will dump flac_file['raw_data'] to that file,
32
33
  otherwise it will dump it to the console (even if binary!)
34
+ write_picture(?) :: write image from PICTURE block(s) to optional file
33
35
 
34
36
  For more/different documentation see http://badcomputer.org/unix/code/flacinfo/
35
37
 
@@ -1,27 +1,34 @@
1
1
  # = Description
2
2
  #
3
3
  # flacinfo-rb gives you access to low level information on Flac files.
4
- # * It parses stream information (STREAMINFO).
5
- # * It parses Vorbis comments (VORBIS_COMMENT).
6
- # * It parses the seek table (SEEKTABLE).
7
- # * It parses the 'application metadata block' (APPLICATION).
8
- # * If (APPLICATION) is ID 0x41544348 (Flac File)
4
+ # * It parses stream information (METADATA_BLOCK_STREAMINFO).
5
+ # * It parses Vorbis comments (METADATA_BLOCK_VORBIS_COMMENT).
6
+ # * It parses the seek table (METADATA_BLOCK_SEEKTABLE).
7
+ # * It parses the 'application metadata block' (METADATA_BLOCK_APPLICATION).
8
+ # * If application is ID 0x41544348 (Flac File)
9
9
  # then we can parse that too.
10
- # * It recognizes (but does not yet parse) the cue sheet (CUESHEET TRACK).
10
+ # * It recognizes (but does not yet parse) the cue sheet (METADATA_BLOCK_CUESHEET).
11
+ # * It parses zero or more picture blocks (METADATA_BLOCK_PICTURE)
12
+ # * It allows you to write embedded images to a file.
13
+ #
14
+ # My plans are to eventually have this library write as well as read data to/from Flac files,
15
+ # so in the future it should become quite a nice native Ruby library interface which will allow
16
+ # the user to mimic most functionality of the 'metaflac' binary programmatically.
11
17
  #
12
18
  # = Copyright and Disclaimer
19
+ #
13
20
  # Copyright:: (c) 2006 Darren Kirby
14
21
  # FlacInfo is free software.
15
22
  # No warranty is provided and the author cannot accept responsibility
16
23
  # for lost or damaged files.
17
24
  # License:: Ruby
18
25
  # Author:: Darren Kirby (mailto:bulliver@badcomputer.org)
19
- # Website:: http://badcomputer.org/unix/code/flacinfo/
26
+ # Website:: http://badcomputer.org/unix/code/flacinfo/index.bot
20
27
  #
21
28
  # = More information
22
29
  #
23
30
  # * There is an example irb session that shows typical usage at
24
- # http://badcomputer.org/unix/code/flacinfo/
31
+ # http://badcomputer.org/unix/code/flacinfo/index.bot
25
32
  # * The Flac spec is at:
26
33
  # http://flac.sourceforge.net/format.html
27
34
  # * The Vorbis Comment spec is at:
@@ -33,39 +40,86 @@
33
40
  class FlacInfoError < StandardError
34
41
  end
35
42
 
36
- # Note: STREAMINFO is the only block guaranteed to be present.
37
- # Other attributes will be present, but empty if the associated block is not present in the Flac file.
43
+ # Note: STREAMINFO is the only block guaranteed to be present in the Flac file.
44
+ # All attributes will be present, but empty if the associated block is not present in the Flac file.
38
45
  class FlacInfo
39
46
 
40
- # Hash of values extracted from the STREAMINFO block. Keys are 'samplerate', 'bits_per_sample', 'total_samples'
41
- # 'channels', 'minimum_frame', 'maximum_frame', 'minimum_block', 'maximum_block', 'md5', and 'block_size'
47
+ # Hash of values extracted from the STREAMINFO block. Keys are:
48
+ # 'offset':: The STREAMINFO block's offset from the beginning of the file (not including the block header).
49
+ # 'block_size':: The size of the STREAMINFO block (not including the block header).
50
+ # 'minimum_block':: The minimum block size (in samples) used in the stream.
51
+ # 'maximum_block':: The maximum block size (in samples) used in the stream.
52
+ # 'minimum_frame':: The minimum frame size (in bytes) used in the stream.
53
+ # 'maximum_frame':: The maximum frame size (in bytes) used in the stream.
54
+ # 'samplerate':: Sample rate in Hz.
55
+ # 'channels':: The number of channels used in the stream.
56
+ # 'bits_per_sample':: The number of bits per sample used in the stream.
57
+ # 'total_samples':: The total number of samples in stream.
58
+ # 'md5':: MD5 signature of the unencoded audio data.
42
59
  attr_reader :streaminfo
43
60
 
44
- # Hash of values extracted from the SEEKTABLE block. Keys are 'seek_points', 'block_size' and 'points'.
45
- # 'points' is another hash whose keys start at 0 and end at ('seek_points' - 1). Each "seektable['points'][n]" hash
46
- # contains an array whose values are [sample number, stream offset, number of frame samples] of each seek point.
61
+ # Hash of values extracted from the SEEKTABLE block. Keys are:
62
+ # 'offset':: The SEEKTABLE block's offset from the beginning of the file (not including the block header).
63
+ # 'block_size':: The size of the SEEKTABLE block (not including the block header).
64
+ # 'seek_points':: The number of seek points in the block.
65
+ # 'points':: Another hash whose keys start at 0 and end at ('seek_points' - 1). Each "seektable['points'][n]" hash
66
+ # contains an array whose (integer) values are:
67
+ # '0':: Sample number of first sample in the target frame, or 0xFFFFFFFFFFFFFFFF for a placeholder point.
68
+ # '1':: Offset (in bytes) from the first byte of the first frame header to the first byte of the target frame's header.
69
+ # '2':: Number of samples in the target frame.
47
70
  attr_reader :seektable
48
71
 
49
72
  # Array of "name=value" strings extracted from the VORBIS_COMMENT block. This is just the contents, metadata is in 'tags'.
50
73
  attr_reader :comment
51
74
 
52
- # Hash of the 'comment' values separated into "key => value" pairs as well as 'vendor_tag' and 'block_size'.
75
+ # Hash of the 'comment' values separated into "key => value" pairs as well as the keys:
76
+ # 'offset':: The VORBIS_COMMENT block's offset from the beginning of the file (not including the block header).
77
+ # 'block_size':: The size of the VORBIS_COMMENT block (not including the block header).
78
+ # 'vendor_tag':: Typically, the name and version of the software that encoded the file.
53
79
  attr_reader :tags
54
80
 
55
- # Hash of values extracted from the APPLICATION block. Keys are 'name', 'ID', and 'block_size'.
81
+ # Hash of values extracted from the APPLICATION block. Keys are:
82
+ # 'offset':: The APPLICATION block's offset from the beginning of the file (not including the block header).
83
+ # 'block_size':: The size of the APPLICATION block (not including the block header).
84
+ # 'ID':: Registered application ID. See http://flac.sourceforge.net/id.html
85
+ # 'name':: Name of the registered application ID.
56
86
  attr_reader :application
57
87
 
58
- # Hash of values extracted from the PADDING block. Just one key: 'block_size'.
88
+ # Hash of values extracted from the PADDING block. Keys are:
89
+ # 'offset':: The PADDING block's offset from the beginning of the file (not including the block header).
90
+ # 'block_size':: The size of the PADDING block (not including the block header).
59
91
  attr_reader :padding
60
92
 
61
- # Hash of values extracted from the CUESHEET block. Just one key: 'block_size'.
93
+ # Hash of values extracted from the CUESHEET block. Keys are:
94
+ # 'offset':: The CUESHEET block's offset from the beginning of the file (not including the block header).
95
+ # 'block_size':: The size of the CUESHEET block (not including the block header).
62
96
  attr_reader :cuesheet
63
97
 
64
- # Hash of values extracted from an APPLICATION block if it is type 0x41544348 (Flac File).
65
- # Keys are 'description', 'mime_type', and 'raw_data'.
98
+ # Hash of values extracted from one or more PICTURE blocks. This hash always includes the key 'n' which is the number of
99
+ # PICTURE blocks found, else '0'. For each block found there will be an integer key starting from 1. Each of these is a
100
+ # hash which contains the keys:
101
+ # 'offset':: The PICTURE block's offset from the beginning of the file (not including the block header).
102
+ # 'block_size':: The size of the PICTURE block (not including the block header).
103
+ # 'type_int':: The picture type according to the ID3v2 APIC frame.
104
+ # 'type_string':: A text value representing the picture type.
105
+ # 'description_string':: A text description of the picture.
106
+ # 'mime_type':: The MIME type string. May be '-->' to signify that the data part is a URL of the picture.
107
+ # 'colour_depth':: The color depth of the picture in bits-per-pixel.
108
+ # 'n_colours':: For indexed-color pictures (e.g. GIF), the number of colors used, or 0 for non-indexed pictures.
109
+ # 'width':: The width of the picture in pixels.
110
+ # 'height':: The height of the picture in pixels.
111
+ # 'raw_data_offset':: The raw picture data's offset from the beginning of the file.
112
+ # 'raw_data_length':: The length of the picture data in bytes.
113
+ attr_reader :picture
114
+
115
+ # Hash of values extracted from an APPLICATION block if it is type 0x41544348 (Flac File).
116
+ # Keys are:
117
+ # 'description':: A brief text description of the contents.
118
+ # 'mime_type':: The Mime type of the contents.
119
+ # 'raw_data':: The contents. May be binary.
66
120
  attr_reader :flac_file
67
121
 
68
- # FlacInfo is the main class for parsing Flac files
122
+ # FlacInfo is the class for parsing Flac files.
69
123
  #
70
124
  # :call-seq:
71
125
  # FlacInfo.new(file) -> FlacInfo instance
@@ -75,7 +129,7 @@ class FlacInfo
75
129
  parse_flac_meta_blocks
76
130
  end
77
131
 
78
- # Returns true if @tags[<string>] has a value, false otherwise.
132
+ # Returns true if @tags[tag] has a value, false otherwise.
79
133
  #
80
134
  # :call-seq:
81
135
  # FlacInfo.hastag?(tag) -> bool
@@ -84,7 +138,7 @@ class FlacInfo
84
138
  @tags["#{tag}"] ? true : false
85
139
  end
86
140
 
87
- # Prettyprint comment hash.
141
+ # Pretty print comment hash.
88
142
  #
89
143
  # :call-seq:
90
144
  # FlacInfo.print_tags -> nil
@@ -94,7 +148,7 @@ class FlacInfo
94
148
  nil
95
149
  end
96
150
 
97
- # Prettyprint streaminfo hash
151
+ # Pretty print streaminfo hash.
98
152
  #
99
153
  # :call-seq:
100
154
  # FlacInfo.print_streaminfo -> nil
@@ -104,7 +158,7 @@ class FlacInfo
104
158
  nil
105
159
  end
106
160
 
107
- # Prettyprint the seektable
161
+ # Pretty print the seektable.
108
162
  #
109
163
  # :call-seq:
110
164
  # FlacInfo.print_seektable -> nil
@@ -121,13 +175,14 @@ class FlacInfo
121
175
  nil
122
176
  end
123
177
 
124
- # This method produces output (mostly) identical to 'metaflac --list'
178
+ # This method produces output similar to 'metaflac --list'.
125
179
  #
126
180
  # :call-seq:
127
181
  # FlacInfo.meta_flac -> nil
128
182
  #
129
183
  def meta_flac
130
184
  n = 0
185
+ pictures_seen = 0
131
186
  @metadata_blocks.each do |block|
132
187
  puts "METADATA block ##{n}"
133
188
  puts " type: #{block[1]} (#{block[0].upcase})"
@@ -145,6 +200,9 @@ class FlacInfo
145
200
  meta_vorb
146
201
  when 5
147
202
  meta_cue
203
+ when 6
204
+ pictures_seen += 1
205
+ meta_pict(pictures_seen)
148
206
  end
149
207
  n += 1
150
208
  end
@@ -154,7 +212,7 @@ class FlacInfo
154
212
  # Dumps the contents of flac_file['raw_data']
155
213
  #
156
214
  # :call-seq:
157
- # FlacInfo.raw_data_dump() -> nil
215
+ # FlacInfo.raw_data_dump() -> nil
158
216
  # FlacInfo.raw_data_dump(outfile) -> nil
159
217
  #
160
218
  # If passed with 'outfile', the data will be written to a file with that name
@@ -179,6 +237,57 @@ class FlacInfo
179
237
  end
180
238
  end
181
239
 
240
+ # Writes embedded images to a file
241
+ #
242
+ # :call-seq:
243
+ # FlacInfo.write_picture() -> nil
244
+ # FlacInfo.write_picture(:outfile=>"str") -> nil
245
+ # FlacInfo.write_picture(:n=>int) -> nil
246
+ # FlacInfo.write_picture(:outfile=>"str", :n=>int) -> nil
247
+ #
248
+ # If passed with ':outfile', the image will be written to a file with that name
249
+ # otherwise it is written to the value of the 'album' tag if it exists, otherwise it
250
+ # is written to 'flacimage'. All three of these will have a dot plus the relevant file
251
+ # extension appended. The argument to ':n' is which image to write in case of multiples.
252
+ #
253
+ def write_picture(args = {})
254
+ if @picture["n"] == 0
255
+ raise FlacInfoError, "There is no METADATA_BLOCK_PICTURE"
256
+ end
257
+
258
+ if args.has_key?(:n)
259
+ n = args[:n]
260
+ else
261
+ n = 1
262
+ end
263
+
264
+ # "image/jpeg" => "jpeg"
265
+ extension = @picture[n]["mime_type"].split("/")[1]
266
+
267
+ if not args.has_key?(:outfile)
268
+ if @tags["album"] == nil or @tags["album"] == ""
269
+ outfile = "flacimage#{n}.#{extension}"
270
+ else
271
+ outfile = "#{@tags["album"]}#{n}.#{extension}"
272
+ end
273
+ else
274
+ outfile = "#{args[:outfile]}.#{extension}"
275
+ end
276
+
277
+ in_p = File.new(@filename, "rb")
278
+ out_p = File.new(outfile, "wb")
279
+
280
+ out_p.binmode
281
+
282
+ in_p.seek(@picture[n]['raw_data_offset'], IO::SEEK_CUR)
283
+ raw_data = in_p.read(@picture[n]['raw_data_length'])
284
+ out_p.write(raw_data)
285
+
286
+ in_p.close
287
+ out_p.close
288
+
289
+ nil
290
+ end
182
291
 
183
292
  private
184
293
  # The following six methods are just helpers for meta_flac
@@ -226,7 +335,7 @@ class FlacInfo
226
335
 
227
336
  def meta_vorb
228
337
  puts " length: #{@tags['block_size']}"
229
- puts " length: #{@tags['vendor_tag']}"
338
+ puts " vendor string: #{@tags['vendor_tag']}"
230
339
  puts " comments: #{@comment.size}"
231
340
  n = 0
232
341
  @comment.each do |c|
@@ -239,6 +348,19 @@ class FlacInfo
239
348
  puts " length: #{@cuesheet['block_size']}"
240
349
  end
241
350
 
351
+ def meta_pict(n)
352
+ puts " length: #{@picture[n]['block_size']}"
353
+ puts " type: #{@picture[n]['type_int']} => #{@picture[n]['type_string']}"
354
+ puts " mimetype: #{@picture[n]['mime_type']}"
355
+ puts " description: #{@picture[n]['description_string']}"
356
+ puts " image width: #{@picture[n]['width']}"
357
+ puts " image height: #{@picture[n]['height']}"
358
+ puts " colour depth: #{@picture[n]['colour_depth']}"
359
+ puts " number of colours: #{@picture[n]['n_colours']}"
360
+ puts " image size: #{@picture[n]['raw_data_length']} bytes"
361
+ end
362
+
363
+
242
364
  # This is where the 'real' parsing starts.
243
365
  def parse_flac_meta_blocks
244
366
  @fp = File.new(@filename, "rb")
@@ -248,9 +370,7 @@ class FlacInfo
248
370
  @padding = {}
249
371
  @application = {}
250
372
  @cuesheet = {}
251
-
252
- typetable = { 0 => "streaminfo", 1 => "padding", 2 => "application",
253
- 3 => "seektable", 4 => "vorbis_comment", 5 => "cuesheet" }
373
+ @picture = {"n" => 0}
254
374
 
255
375
  header = @fp.read(4)
256
376
  # First 4 bytes must be 0x66, 0x4C, 0x61, and 0x43
@@ -258,9 +378,14 @@ class FlacInfo
258
378
  raise FlacInfoError, "#{@filename} does not appear to be a valid Flac file"
259
379
  end
260
380
 
381
+ typetable = { 0 => "streaminfo", 1 => "padding", 2 => "application",
382
+ 3 => "seektable", 4 => "vorbis_comment", 5 => "cuesheet",
383
+ 6 => "picture" }
384
+
261
385
  @metadata_blocks = []
262
386
  lastheader = 0
263
387
  n = 0
388
+
264
389
  until lastheader == 1
265
390
  # first bit = Last-metadata-block flag
266
391
  # bits 2-7 = BLOCK_TYPE. See typetable above
@@ -268,17 +393,26 @@ class FlacInfo
268
393
  lastheader = block_header[0].to_i & 1
269
394
  type = sprintf("%u", "0b#{block_header[1..7]}").to_i
270
395
  @metadata_blocks[n] = ["#{typetable[type]}", type, lastheader]
396
+
397
+ if type >= typetable.size
398
+ raise FlacInfoError, "Invalid block header type"
399
+ end
400
+
271
401
  self.send "parse_#{typetable[type]}"
272
402
  n += 1
273
403
  end
404
+
405
+ @fp.close
274
406
  end
275
407
 
276
408
  def parse_seektable
277
409
  begin
278
410
  @seektable['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
411
+ @seektable['offset'] = @fp.tell
279
412
  @seektable['seek_points'] = @seektable['block_size'] / 18
280
413
  n = 0
281
414
  @seektable['points'] = {}
415
+
282
416
  @seektable['seek_points'].times do
283
417
  pt_arr = []
284
418
  pt_arr << @fp.read(8).reverse.unpack("V*")[0]
@@ -287,23 +421,61 @@ class FlacInfo
287
421
  @seektable['points'][n] = pt_arr
288
422
  n += 1
289
423
  end
424
+
290
425
  rescue
291
- raise FlacInfoError, "Could not parse seek table"
426
+ raise FlacInfoError, "Could not parse METADATA_BLOCK_SEEKTABLE"
292
427
  end
293
428
  end
294
429
 
295
430
  # Not parsed yet, I have no flacs with a cuesheet!
296
431
  def parse_cuesheet
297
- @cuesheet['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
298
- @fp.seek(@cuesheet['block_size'], IO::SEEK_CUR)
432
+ begin
433
+ @cuesheet['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
434
+ @cuesheet['offset'] = @fp.tell
435
+ @fp.seek(@cuesheet['block_size'], IO::SEEK_CUR)
436
+ rescue
437
+ raise FlacInfoError, "Could not parse METADATA_BLOCK_CUESHEET"
438
+ end
439
+ end
440
+
441
+ def parse_picture
442
+ n = @picture["n"] + 1
443
+ @picture["n"] = n
444
+ @picture[n] = {}
445
+
446
+ picture_type = ["Other", "32x32 pixels file icon", "Other file icon", "Cover (front)", "Cover (back)",
447
+ "Leaflet page", "Media", "Lead artist/lead performer/soloist", "Artist/performer",
448
+ "Conductor", "Band/Orchestra", "Composer", "Lyricist/text writer", "Recording Location",
449
+ "During recording", "During performance", "Movie/video screen capture", "A bright
450
+ coloured fish", "Illustration", "Band/artist logotype", "Publisher/Studio logotype"]
451
+
452
+ begin
453
+ @picture[n]['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
454
+ @picture[n]['offset'] = @fp.tell
455
+ @picture[n]['type_int'] = @fp.read(4).reverse.unpack("v*")[0]
456
+ @picture[n]['type_string'] = picture_type[@picture[n]['type_int']]
457
+ mime_length = @fp.read(4).reverse.unpack("v*")[0]
458
+ @picture[n]['mime_type'] = @fp.read(mime_length).unpack("a*")[0]
459
+ description_length = @fp.read(4).reverse.unpack("v*")[0]
460
+ @picture[n]['description_string'] = @fp.read(description_length).unpack("M*")[0]
461
+ @picture[n]['width'] = @fp.read(4).reverse.unpack("v*")[0]
462
+ @picture[n]['height'] = @fp.read(4).reverse.unpack("v*")[0]
463
+ @picture[n]['colour_depth'] = @fp.read(4).reverse.unpack("v*")[0]
464
+ @picture[n]['n_colours'] = @fp.read(4).reverse.unpack("v*")[0]
465
+ @picture[n]['raw_data_length'] = @fp.read(4).reverse.unpack("V*")[0]
466
+ @picture[n]['raw_data_offset'] = @fp.tell
467
+ @fp.seek((@picture[n]['raw_data_length']), IO::SEEK_CUR)
468
+ rescue
469
+ raise FlacInfoError, "Could not parse METADATA_BLOCK_PICTURE"
470
+ end
299
471
  end
300
472
 
301
473
  def parse_application
302
474
  begin
303
475
  @application['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
476
+ @application['offset'] = @fp.tell
304
477
  @application['ID'] = @fp.read(4).unpack("H*")[0]
305
478
 
306
- # See http://flac.sourceforge.net/id.html
307
479
  app_id = {"41544348" => "Flac File", "43756573" => "GoldWave Cue Points",
308
480
  "4D754D4C" => "MusicML", "46696361" => "CUE Splitter",
309
481
  "46746F6C" => "flac-tools", "5346464C" => "Sound Font FLAC",
@@ -319,30 +491,33 @@ class FlacInfo
319
491
  @application['raw_data'] = @fp.read(@application['block_size'] - 4)
320
492
  end
321
493
  rescue
322
- raise FlacInfoError, "Could not parse application block"
494
+ raise FlacInfoError, "Could not parse METADATA_BLOCK_APPLICATION"
323
495
  end
324
496
  end
325
497
 
326
498
  # Unlike most values in the Flac header
327
- # the Vorbis comments are in LSB order
499
+ # the Vorbis comments are in LSB order
328
500
  #
329
501
  # @comment is an array of values according to the official spec implementation
330
- # @tags is a more user-friendly data structure with the values
331
- # separated into key=value pairs
502
+ # @tags is a more user-friendly data structure with the values
503
+ # separated into key=value pairs
332
504
  def parse_vorbis_comment
333
505
  begin
334
506
  @tags = {}
335
507
  @tags['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
508
+ @tags['offset'] = @fp.tell
336
509
  vendor_length = @fp.read(4).unpack("V")[0]
337
510
  @tags['vendor_tag'] = @fp.read(vendor_length)
338
511
  user_comment_list_length = @fp.read(4).unpack("V")[0]
339
512
  @comment = []
340
513
  n = 0
514
+
341
515
  user_comment_list_length.times do
342
516
  length = @fp.read(4).unpack("V")[0]
343
517
  @comment[n] = @fp.read(length)
344
518
  n += 1
345
519
  end
520
+
346
521
  @comment.each do |c|
347
522
  k,v = c.split("=")
348
523
  # Vorbis spec says we can have more than one identical comment ie:
@@ -355,21 +530,27 @@ class FlacInfo
355
530
  @tags[k] = v
356
531
  end
357
532
  end
533
+
358
534
  rescue
359
- raise FlacInfoError, "Could not parse Vorbis comments block"
535
+ raise FlacInfoError, "Could not parse METADATA_BLOCK_VORBIS_COMMENT"
360
536
  end
361
537
  end
362
538
 
363
539
  # padding is just a bunch of '0' bytes
364
540
  def parse_padding
365
- @padding['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
366
- @fp.seek(@padding['block_size'], IO::SEEK_CUR)
541
+ begin
542
+ @padding['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
543
+ @padding['offset'] = @fp.tell
544
+ @fp.seek(@padding['block_size'], IO::SEEK_CUR)
545
+ rescue
546
+ raise FlacInfoError, "Could not parse METADATA_BLOCK_PADDING"
547
+ end
367
548
  end
368
549
 
369
550
  def parse_streaminfo
370
551
  begin
371
- # Length (in bytes) of metadata to follow (not including header)
372
552
  @streaminfo['block_size'] = @fp.read(3).reverse.unpack("v*")[0]
553
+ @streaminfo['offset'] = @fp.tell
373
554
  @streaminfo['minimum_block'] = @fp.read(2).reverse.unpack("v*")[0]
374
555
  @streaminfo['maximum_block'] = @fp.read(2).reverse.unpack("v*")[0]
375
556
  @streaminfo['minimum_frame'] = @fp.read(3).reverse.unpack("v*")[0]
@@ -389,7 +570,7 @@ class FlacInfo
389
570
  # 128 bits :: MD5 signature of the unencoded audio data.
390
571
  @streaminfo['md5'] = @fp.read(16).unpack("H32")[0]
391
572
  rescue
392
- raise FlacInfoError, "Could not parse stream info block"
573
+ raise FlacInfoError, "Could not parse METADATA_BLOCK_STREAMINFO"
393
574
  end
394
575
  end
395
576
 
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.11
2
+ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: flacinfo-rb
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.1"
7
- date: 2006-09-18 00:00:00 -07:00
6
+ version: "0.2"
7
+ date: 2007-06-23 00:00:00 -06:00
8
8
  summary: Pure Ruby lib for accessing metadata (including Vorbis tags) from Flac files
9
9
  require_paths:
10
10
  - lib
@@ -25,11 +25,12 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
25
25
  platform: ruby
26
26
  signing_key:
27
27
  cert_chain:
28
+ post_install_message:
28
29
  authors:
29
30
  - Darren Kirby
30
31
  files:
31
32
  - README
32
- - lib/flacinfo.rb
33
+ - flacinfo.rb
33
34
  test_files: []
34
35
 
35
36
  rdoc_options: []