flacinfo-rb 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
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: []