mb-discid 0.1.4-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,29 @@
1
+ = Changelog
2
+
3
+ == 0.1.4 (2009-11-19)
4
+ * Fixed calling +read+ method without argument
5
+
6
+ == 0.1.3 (2009-11-19)
7
+ * Added singleton method +sectors_to_seconds+ to convert sectors into seconds
8
+ * Added method +seconds+ to retrieve disc length in seconds
9
+ * Added method +track_info+ for accessing more detailed information about tracks
10
+ * Fixed building with Ruby 1.9 (Mihaly Csomay)
11
+
12
+ == 0.1.2 (2007-07-04)
13
+ * Support the method +put+ to set the TOC information directly instead of
14
+ reading it from a device.
15
+ * Fixed possible core dump if +read+ was called twice and failed the
16
+ second time.
17
+ * New to_s method (returns string representation of the ID itself).
18
+ * Complete RDoc documentation.
19
+
20
+ == 0.1.1 (2007-06-03)
21
+ * Minor changes to source to support MS compiler
22
+ * Provide Win32 binary gem
23
+ * Changed require of library to "require 'mb-discid'" (was "require 'DiscID'"
24
+ before, which was likely to cause problems)
25
+
26
+ == 0.1.0 (2007-06-02)
27
+ * Initial release
28
+
29
+ $Id: CHANGES 301 2009-11-19 11:39:31Z phw $
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2007, Philipp Wolfer
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ 3. Neither the name of the RBrainz project nor the names of the
12
+ contributors may be used to endorse or promote products derived from
13
+ this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,54 @@
1
+ = MB-DiscID - Ruby bindings for MusicBrainz libdiscid
2
+
3
+ == About
4
+ MB-DiscID provides Ruby bindings for the MusicBrainz DiscID library libdiscid.
5
+ It allows you to calculate MusicBrainz DiscIDs from audio CDs which you can use
6
+ to find the release entry for your CD in the MusicBrainz database.
7
+
8
+ == Requirements
9
+ * Ruby >= 1.8.6
10
+ * libdiscid >= 0.1.0
11
+
12
+ == Installation
13
+ Before installing rdiscid make sure you have libdiscid installed. See
14
+ http://musicbrainz.org/doc/libdiscid for more information on how to do this.
15
+
16
+ === Installation with RubyGems
17
+ gem install mb-discid
18
+
19
+ === Installation on Windows operating systems.
20
+ For Windows a binary gem <tt>mb-discid-x.x.x-mswin32.gem</tt> is available. To
21
+ install it follow the instructions below:
22
+
23
+ 1. Make sure you have at least Ruby 1.8.6 installed.
24
+ 2. Install RubyGems, if you don't already have it.
25
+ 3. Download <tt>libdiscid-0.1.1-win32bin.zip</tt> from
26
+ http://musicbrainz.org/doc/libdiscid.
27
+ 4. Copy the file <tt>discid.dll</tt> from <tt>libdiscid-0.1.1-win32bin.zip</tt>
28
+ to your Ruby bin directory (normally <tt>C:\ruby\bin</tt>).
29
+ 5. Run <tt>gem install mb-discid</tt> to install MB-DiscID.
30
+ 6. To test the installation try to run <tt>examples/discid.rb</tt>.
31
+
32
+ === Installing from source
33
+ rake install
34
+
35
+ == Usage
36
+ See the documentation of MusicBrainz::DiscID or the example files in the
37
+ +examples+ directory for usage information.
38
+
39
+ == Contact
40
+ MB-DiscID is part of the RBrainz project which provides a library to query
41
+ the MusicBrainz XML web service. For more information about MB-DiscID or
42
+ RBrainz visit http://rbrainz.rubyforge.org.
43
+
44
+ If you have any questions or suggestions regarding MB-DiscID please write to
45
+ the rbrainz-user mailinglist[http://rubyforge.org/mail/?group_id=3677].
46
+ If you find bugs or if you have any feature requests please use the
47
+ RBrainz bug tracker[http://rubyforge.org/tracker/?group_id=3677].
48
+
49
+ == License
50
+ MB-DiscID is Copyright (c) 2007 Philipp Wolfer.
51
+ It is free softare distributed under a BSD style license. See
52
+ LICENSE[link:files/LICENSE.html] for details.
53
+
54
+ $Id: README 298 2009-11-19 09:26:45Z phw $
data/Rakefile ADDED
@@ -0,0 +1,137 @@
1
+ # $Id: Rakefile 300 2009-11-19 11:31:42Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ # Rakefile for RDiscID
7
+
8
+ require 'rubygems'
9
+ require 'rake/gempackagetask'
10
+ require 'rake/testtask'
11
+ require 'rake/rdoctask'
12
+
13
+ task :default do
14
+ puts "Please see 'rake --tasks' for an overview of the available tasks."
15
+ end
16
+
17
+ # Packaging tasks: -------------------------------------------------------
18
+
19
+ PKG_NAME = 'mb-discid'
20
+ PKG_VERSION = '0.1.4'
21
+ PKG_SUMMARY = 'Ruby bindings for libdiscid.'
22
+ PKG_AUTHOR = 'Philipp Wolfer'
23
+ PKG_EMAIL = 'phw@rubyforge.org'
24
+ PKG_HOMEPAGE = 'http://rbrainz.rubyforge.org'
25
+ PKG_DESCRIPTION = <<EOF
26
+ Ruby bindings for libdiscid. See http://musicbrainz.org/doc/libdiscid
27
+ for more information on libdiscid and MusicBrainz.
28
+ EOF
29
+ PKG_FILES = FileList[
30
+ 'Rakefile', 'LICENSE', 'README', 'CHANGES',
31
+ 'examples/**/*.rb',
32
+ 'ext/**/*.{c,rb}',
33
+ 'lib/**/*.rb',
34
+ 'test/**/*.rb'
35
+ ]
36
+ PKG_EXTRA_RDOC_FILES = ['README', 'LICENSE', 'CHANGES']
37
+
38
+ spec = Gem::Specification.new do |spec|
39
+ spec.name = PKG_NAME
40
+ spec.version = PKG_VERSION
41
+ spec.summary = PKG_SUMMARY
42
+ if ENV['BINARY_GEM']
43
+ spec.platform = Gem::Platform::CURRENT
44
+ spec.files = PKG_FILES << 'ext/MB_DiscID.so'
45
+ spec.bindir = 'bin'
46
+ spec.required_ruby_version = ">= #{RUBY_VERSION}"
47
+ else
48
+ spec.platform = Gem::Platform::RUBY
49
+ spec.files = PKG_FILES
50
+ spec.extensions << 'ext/extconf.rb'
51
+ spec.required_ruby_version = ">= 1.8.6"
52
+ end
53
+ spec.requirements << 'libdiscid (http://musicbrainz.org/doc/libdiscid)'
54
+ spec.require_paths = ['lib', 'ext']
55
+ spec.autorequire = spec.name
56
+ spec.description = PKG_DESCRIPTION
57
+ spec.author = PKG_AUTHOR
58
+ spec.email = PKG_EMAIL
59
+ spec.homepage = PKG_HOMEPAGE
60
+ spec.rubyforge_project = 'rbrainz'
61
+ spec.has_rdoc = true
62
+ spec.extra_rdoc_files = PKG_EXTRA_RDOC_FILES
63
+ end
64
+
65
+ Rake::GemPackageTask.new(spec) do |pkg|
66
+ pkg.need_zip = true
67
+ pkg.need_tar_gz= true
68
+ end
69
+
70
+ # Build tasks: -----------------------------------------------------------
71
+
72
+ desc 'Build all the extensions'
73
+ task :build do
74
+ extconf_args = ''
75
+
76
+ unless ENV['DISCID_DIR'].nil?
77
+ extconf_args = "--with-discid-dir=#{ENV['DISCID_DIR']}"
78
+ end
79
+
80
+ cd 'ext' do
81
+ unless system("ruby extconf.rb #{extconf_args}")
82
+ STDERR.puts "ERROR: could not configure extension!\n" +
83
+ "\n#{INFO_NOTE}\n"
84
+ break
85
+ end
86
+
87
+ unless system('make') or system('nmake')
88
+ STDERR.puts 'ERROR: could not build extension!'
89
+ break
90
+ end
91
+ end
92
+ end
93
+
94
+ desc 'Install (and build) extensions'
95
+ task :install => [:build] do
96
+ cd 'ext' do
97
+ unless system('make install')
98
+ STDERR.puts 'ERROR: could not install extension!'
99
+ break
100
+ end
101
+ end
102
+ end
103
+
104
+ desc 'Remove extension products'
105
+ task :clobber_build do
106
+ FileList['ext/**/*'].each do |file|
107
+ unless FileList['ext/**/*.{c,rb}'].include?(file)
108
+ rm_r file if File.exists?(file)
109
+ end
110
+ end
111
+ end
112
+
113
+ desc 'Force a rebuild of the extension files'
114
+ task :rebuild => [:clobber_build, :build]
115
+
116
+ desc 'Remove all files created during the build process'
117
+ task :clobber => [:clobber_build, :clobber_package]
118
+
119
+ # Test tasks: ------------------------------------------------------------
120
+
121
+ desc "Run just the unit tests"
122
+ Rake::TestTask.new(:test => [:rebuild]) do |test|
123
+ test.test_files = FileList['test/test*.rb']
124
+ test.libs = ['lib', 'ext']
125
+ test.warning = true
126
+ end
127
+
128
+ # Documentation tasks: ---------------------------------------------------
129
+
130
+ Rake::RDocTask.new do |rdoc|
131
+ rdoc.title = "MB-DiscID %s" % PKG_VERSION
132
+ rdoc.main = 'README'
133
+ rdoc.rdoc_dir = 'doc/api'
134
+ rdoc.rdoc_files.include('ext/**/*.c', 'lib/**/*.rb', PKG_EXTRA_RDOC_FILES)
135
+ rdoc.options << '--inline-source' << '--line-numbers' #<< '--diagram'
136
+ end
137
+
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Example script for MB-DiscID.
4
+ #
5
+ # This script will read the disc ID from the default device and print
6
+ # the results. You can specify an alternate device to use by giving the
7
+ # device's name as the first command line argument.
8
+ #
9
+ # Example:
10
+ # ./discid.rb /dev/dvd
11
+ #
12
+ # $Id: discid.rb 201 2008-02-13 14:59:48Z phw $
13
+
14
+ require 'mb-discid'
15
+
16
+ # Read the device name from the command line or use the default.
17
+ device = $*[0] ? $*[0] : MusicBrainz::DiscID.default_device
18
+
19
+ # Create a new DiscID object and read the disc information.
20
+ # In case of errors exit the application.
21
+ puts "Reading TOC from device '#{device}'."
22
+ begin
23
+ disc = MusicBrainz::DiscID.new
24
+ disc.read(device)
25
+
26
+ # Instead of reading from a device we could set the TOC directly:
27
+ # disc.put(1, 82255, [150, 16157, 35932, 57527])
28
+ rescue Exception => e
29
+ puts e
30
+ exit(1)
31
+ end
32
+
33
+ # Print information about the disc:
34
+ print <<EOF
35
+
36
+ DiscID : #{disc.id}
37
+ FreeDB ID : #{disc.freedb_id}
38
+ First track : #{disc.first_track_num}
39
+ Last track : #{disc.last_track_num}
40
+ Total length: #{disc.seconds} seconds
41
+ Sectors : #{disc.sectors}
42
+ EOF
43
+
44
+ # Print information about individual tracks:
45
+ disc.track_details do |track_info|
46
+ puts "Track ##{track_info.number}"
47
+ puts " Length: %02d:%02d (%i sectors)" %
48
+ [track_info.seconds / 60, track_info.seconds % 60, track_info.sectors]
49
+ puts " Start : %02d:%02d (sector %i)" %
50
+ [track_info.start_time / 60, track_info.start_time % 60, track_info.start_sector]
51
+ puts " End : %02d:%02d (sector %i)" %
52
+ [track_info.end_time / 60, track_info.end_time % 60, track_info.end_sector]
53
+ end
54
+
55
+ # Print a submission URL that can be used to submit
56
+ # the disc ID to MusicBrainz.org.
57
+ puts "\nSubmit via #{disc.submission_url}"
data/ext/MB_DiscID.so ADDED
Binary file
data/ext/extconf.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # $Id: extconf.rb 68 2007-06-03 14:12:21Z phw $
3
+
4
+ require 'mkmf'
5
+
6
+ if have_library('discid', 'discid_new') or
7
+ have_library('discid.dll', 'discid_new')
8
+ # Remove -MD from compiler flags on Windows.
9
+ $CFLAGS.sub!('-MD', '') if RUBY_PLATFORM.include? 'win32'
10
+ create_makefile('MB_DiscID')
11
+ else
12
+ puts 'Required library libdiscid not found.'
13
+ end
data/ext/mb_discid.c ADDED
@@ -0,0 +1,360 @@
1
+ /**
2
+ * $Id: mb_discid.c 301 2009-11-19 11:39:31Z phw $
3
+ *
4
+ * Ruby bindings for libdiscid. See http://musicbrainz.org/doc/libdiscid
5
+ * for more information on libdiscid and MusicBrainz.
6
+ *
7
+ * Author:: Philipp Wolfer (mailto:phw@rubyforge.org)
8
+ * Copyright:: Copyright (c) 2007, Philipp Wolfer
9
+ * License:: MB-DiscID is free software distributed under a BSD style license.
10
+ * See LICENSE for permissions.
11
+ */
12
+
13
+ #include "ruby.h"
14
+ #include "discid/discid.h"
15
+
16
+ /**
17
+ * The MusicBrainz module.
18
+ */
19
+ static VALUE mMusicBrainz;
20
+
21
+ /**
22
+ * The DiscID class.
23
+ */
24
+ static VALUE cDiscID;
25
+
26
+ /**
27
+ * call-seq:
28
+ * id() -> string or nil
29
+ *
30
+ * Returns the DiscID as a string.
31
+ *
32
+ * Returns +nil+ if no ID was yet read.
33
+ */
34
+ static VALUE mb_discid_id(VALUE self)
35
+ {
36
+ if (rb_iv_get(self, "@read") == Qfalse)
37
+ return Qnil;
38
+ else
39
+ {
40
+ DiscId *disc;
41
+ Data_Get_Struct(self, DiscId, disc);
42
+
43
+ return rb_str_new2(discid_get_id(disc));
44
+ }
45
+ }
46
+
47
+ /**
48
+ * call-seq:
49
+ * submission_url() -> string or nil
50
+ *
51
+ * Returns a submission URL for the DiscID as a string.
52
+ *
53
+ * Returns +nil+ if no ID was yet read.
54
+ */
55
+ static VALUE mb_discid_submission_url(VALUE self)
56
+ {
57
+ if (rb_iv_get(self, "@read") == Qfalse)
58
+ return Qnil;
59
+ else
60
+ {
61
+ DiscId *disc;
62
+ Data_Get_Struct(self, DiscId, disc);
63
+
64
+ return rb_str_new2(discid_get_submission_url(disc));
65
+ }
66
+ }
67
+
68
+ /**
69
+ * call-seq:
70
+ * freedb_id() -> string or nil
71
+ *
72
+ * Returns a FreeDB DiscID as a string.
73
+ *
74
+ * Returns +nil+ if no ID was yet read.
75
+ */
76
+ static VALUE mb_discid_freedb_id(VALUE self)
77
+ {
78
+ if (rb_iv_get(self, "@read") == Qfalse)
79
+ return Qnil;
80
+ else
81
+ {
82
+ DiscId *disc;
83
+ Data_Get_Struct(self, DiscId, disc);
84
+
85
+ return rb_str_new2(discid_get_freedb_id(disc));
86
+ }
87
+ }
88
+
89
+ /**
90
+ * call-seq:
91
+ * first_track_num() -> int or nil
92
+ *
93
+ * Return the number of the first track on this disc (usually 1).
94
+ *
95
+ * Returns +nil+ if no ID was yet read.
96
+ */
97
+ static VALUE mb_discid_first_track_num(VALUE self)
98
+ {
99
+ if (rb_iv_get(self, "@read") == Qfalse)
100
+ return Qnil;
101
+ else
102
+ {
103
+ DiscId *disc;
104
+ Data_Get_Struct(self, DiscId, disc);
105
+
106
+ return INT2FIX(discid_get_first_track_num(disc));
107
+ }
108
+ }
109
+
110
+ /**
111
+ * call-seq:
112
+ * last_track_num() -> int or nil
113
+ *
114
+ * Return the number of the last track on this disc.
115
+ *
116
+ * Returns +nil+ if no ID was yet read.
117
+ */
118
+ static VALUE mb_discid_last_track_num(VALUE self)
119
+ {
120
+ if (rb_iv_get(self, "@read") == Qfalse)
121
+ return Qnil;
122
+ else
123
+ {
124
+ DiscId *disc;
125
+ Data_Get_Struct(self, DiscId, disc);
126
+
127
+ return INT2FIX(discid_get_last_track_num(disc));
128
+ }
129
+ }
130
+
131
+ /**
132
+ * call-seq:
133
+ * sectors() -> int or nil
134
+ *
135
+ * Return the length of the disc in sectors.
136
+ *
137
+ * Returns +nil+ if no ID was yet read.
138
+ */
139
+ static VALUE mb_discid_sectors(VALUE self)
140
+ {
141
+ if (rb_iv_get(self, "@read") == Qfalse)
142
+ return Qnil;
143
+ else
144
+ {
145
+ DiscId *disc;
146
+ Data_Get_Struct(self, DiscId, disc);
147
+
148
+ return INT2FIX(discid_get_sectors(disc));
149
+ }
150
+ }
151
+
152
+ /**
153
+ * call-seq:
154
+ * tracks() -> array
155
+ * tracks() {|offset, length| block }
156
+ *
157
+ * Returns an array of <tt>[offset, length]</tt> tuples for each track.
158
+ *
159
+ * Offset and length are both integer values representing sectors.
160
+ * If a block is given this method returns +nil+ and instead iterates over the
161
+ * block calling the block with two arguments <tt>|offset, length|</tt>.
162
+ *
163
+ * Returns always +nil+ if no ID was yet read. The block won't be called in
164
+ * this case.
165
+ *
166
+ * You may want to use the method track_details instead of this method to
167
+ * retrieve more detailed information about the tracks.
168
+ */
169
+ static VALUE mb_discid_tracks(VALUE self)
170
+ {
171
+ if (rb_iv_get(self, "@read") == Qfalse)
172
+ return Qnil;
173
+ else
174
+ {
175
+ DiscId *disc; /* Pointer to the disc struct */
176
+ VALUE result = rb_ary_new(); /* Array of all [offset, length] tuples */
177
+ VALUE tuple; /* Array to store one [offset, length] tuple. */
178
+ int track; /* Counter for the track number to process. */
179
+
180
+ Data_Get_Struct(self, DiscId, disc);
181
+
182
+ track = discid_get_first_track_num(disc); /* First track number */
183
+ while (track <= discid_get_last_track_num(disc))
184
+ {
185
+ tuple = rb_ary_new3(2,
186
+ INT2FIX(discid_get_track_offset(disc, track)),
187
+ INT2FIX(discid_get_track_length(disc, track)) );
188
+
189
+ if (rb_block_given_p())
190
+ rb_yield(tuple);
191
+ else
192
+ rb_ary_push(result, tuple);
193
+
194
+ track++;
195
+ }
196
+
197
+ if (rb_block_given_p())
198
+ return Qnil;
199
+ else
200
+ return result;
201
+ }
202
+ }
203
+
204
+ /**
205
+ * call-seq:
206
+ * read(device=nil)
207
+ *
208
+ * Read the disc ID from the given device.
209
+ *
210
+ * If no device is given the default device of the platform will be used.
211
+ * Throws an _Exception_ if the CD's TOC can not be read.
212
+ *
213
+ * Raises:: ArgumentError, TypeError, Exception
214
+ */
215
+ static VALUE mb_discid_read(int argc, VALUE *argv, VALUE self)
216
+ {
217
+ DiscId *disc; /* Pointer to the disc struct */
218
+ VALUE device = Qnil; /* The device string as a Ruby string */
219
+ char* cdevice; /* The device string as a C string */
220
+
221
+ Data_Get_Struct(self, DiscId, disc);
222
+
223
+ /* Check the number and types of arguments */
224
+ rb_scan_args(argc, argv, "01", &device);
225
+
226
+ /* Use the default device if none was given. */
227
+ if (device == Qnil)
228
+ cdevice = discid_get_default_device();
229
+ else if (rb_respond_to(device, rb_intern("to_s")))
230
+ {
231
+ device = rb_funcall(device, rb_intern("to_s"), 0, 0);
232
+ cdevice = StringValuePtr(device);
233
+ }
234
+ else
235
+ rb_raise(rb_eTypeError, "wrong argument type (expected String)");
236
+
237
+ /* Mark the disc id as unread in case something goes wrong. */
238
+ rb_iv_set(self, "@read", Qfalse);
239
+
240
+ /* Read the discid */
241
+ if (discid_read(disc, cdevice) == 0)
242
+ rb_raise(rb_eException, discid_get_error_msg(disc));
243
+ else /* Remember that we already read the ID. */
244
+ rb_iv_set(self, "@read", Qtrue);
245
+
246
+ return Qnil;
247
+
248
+ }
249
+
250
+ /**
251
+ * call-seq:
252
+ * put(first_track, sectors, offsets)
253
+ *
254
+ * Set the TOC information directly instead of reading it from a device.
255
+ *
256
+ * Use this instead of read if the TOC information was already read elsewhere
257
+ * and you want to recalculate the ID.
258
+ * Throws an _Exception_ if the CD's TOC can not be read.
259
+ *
260
+ * <b>Parameters:</b>
261
+ * [first_track] The number of the first track on the disc (usually 1).
262
+ * [sectors] The total number of sectors on the disc.
263
+ * [offsets] Array of all track offsets. The number of tracks must not exceed 99.
264
+ *
265
+ * Raises:: Exception
266
+ */
267
+ static VALUE mb_discid_put(VALUE self, VALUE first_track, VALUE sectors,
268
+ VALUE offsets)
269
+ {
270
+ DiscId *disc; /* Pointer to the disc struct */
271
+ long length = RARRAY_LEN(offsets); /* length of the offsets array */
272
+ int cfirst = NUM2INT(first_track); /* number of the first track */
273
+ int clast = length + 1 - cfirst; /* number of the last track */
274
+ int coffsets[100]; /* C array to hold the offsets */
275
+ int i = 1; /* Counter for iterating over coffsets*/
276
+
277
+ Data_Get_Struct(self, DiscId, disc);
278
+
279
+ /* Convert the Ruby array to an C array of integers. discid_puts expects
280
+ always an offsets array with exactly 100 elements. */
281
+ coffsets[0] = NUM2INT(sectors); /* 0 is always the leadout track */
282
+ while (i <= length && i < 100)
283
+ {
284
+ coffsets[i] = NUM2INT(rb_ary_entry(offsets, i - 1));
285
+ i++;
286
+ }
287
+
288
+ /* Mark the disc id as unread in case something goes wrong. */
289
+ rb_iv_set(self, "@read", Qfalse);
290
+
291
+ /* Read the discid */
292
+ if (discid_put(disc, cfirst, clast, coffsets) == 0)
293
+ rb_raise(rb_eException, discid_get_error_msg(disc));
294
+ else /* Remember that we already read the ID. */
295
+ rb_iv_set(self, "@read", Qtrue);
296
+
297
+ return Qnil;
298
+ }
299
+
300
+ /**
301
+ * call-seq:
302
+ * MusicBrainz::DiscID.new(device=nil) -> obj
303
+ *
304
+ * Construct a new DiscID object.
305
+ *
306
+ * As an optional argument the name of the device to read the ID from
307
+ * may be given. If you don't specify a device here you can later read
308
+ * the ID with the read method.
309
+ *
310
+ * Raises:: ArgumentError, TypeError, Exception
311
+ */
312
+ VALUE mb_discid_new(int argc, VALUE *argv, VALUE class)
313
+ {
314
+ DiscId *disc = discid_new();
315
+ VALUE tdata = Data_Wrap_Struct(class, 0, discid_free, disc);
316
+ VALUE device = Qnil;
317
+ rb_obj_call_init(tdata, 0, 0);
318
+ rb_iv_set(tdata, "@read", Qfalse);
319
+
320
+ /* Check the number of arguments */
321
+ rb_scan_args(argc, argv, "01", &device);
322
+
323
+ if (device != Qnil)
324
+ rb_funcall(tdata, rb_intern("read"), 1, device);
325
+
326
+ return tdata;
327
+ }
328
+
329
+ /**
330
+ * call-seq:
331
+ * MusicBrainz::DiscID.default_device(device=nil) -> string
332
+ *
333
+ * Returns a device string for the default device for this platform.
334
+ */
335
+ VALUE mb_discid_default_device(VALUE class)
336
+ {
337
+ return rb_str_new2(discid_get_default_device());
338
+ }
339
+
340
+ /**
341
+ * Initialize the DiscID class and make it available in Ruby.
342
+ */
343
+ void Init_MB_DiscID()
344
+ {
345
+ mMusicBrainz = rb_define_module("MusicBrainz");
346
+ cDiscID = rb_define_class_under(mMusicBrainz, "DiscID", rb_cObject);
347
+ rb_define_singleton_method(cDiscID, "new", mb_discid_new, -1);
348
+ rb_define_singleton_method(cDiscID, "default_device",
349
+ mb_discid_default_device, 0);
350
+
351
+ rb_define_method(cDiscID, "read", mb_discid_read, -1);
352
+ rb_define_method(cDiscID, "put", mb_discid_put, 3);
353
+ rb_define_method(cDiscID, "id", mb_discid_id, 0);
354
+ rb_define_method(cDiscID, "submission_url", mb_discid_submission_url, 0);
355
+ rb_define_method(cDiscID, "freedb_id", mb_discid_freedb_id, 0);
356
+ rb_define_method(cDiscID, "first_track_num", mb_discid_first_track_num, 0);
357
+ rb_define_method(cDiscID, "last_track_num", mb_discid_last_track_num, 0);
358
+ rb_define_method(cDiscID, "sectors", mb_discid_sectors, 0);
359
+ rb_define_method(cDiscID, "tracks", mb_discid_tracks, 0);
360
+ }
data/lib/mb-discid.rb ADDED
@@ -0,0 +1,229 @@
1
+ # $Id: mb-discid.rb 201 2008-02-13 14:59:48Z phw $
2
+ #
3
+ # Just a helper file to allow loading the MB-DiscID library with
4
+ # <tt>require 'mb-discid'</tt>, which is the only recommended way
5
+ # to load the library.
6
+ #
7
+ # This file may even provide extensions to the library in the future
8
+ # to avoid to have to write everything in C.
9
+ #
10
+ # Author:: Philipp Wolfer (mailto:phw@rubyforge.org)
11
+ # Copyright:: Copyright (c) 2007, Philipp Wolfer
12
+ # License:: MB-DiscID is free software distributed under a BSD style license.
13
+ # See LICENSE[file:../LICENSE.html] for permissions.
14
+
15
+ require 'MB_DiscID.so'
16
+
17
+ module MusicBrainz
18
+
19
+ # Class to calculate a MusicBrainz DiscID from an audio CD in the drive.
20
+ #
21
+ # This is basically an interface to the libdiscid C library
22
+ # (http://musicbrainz.org/doc/libdiscid).
23
+ #
24
+ # == Usage
25
+ # === Basic Usage:
26
+ #
27
+ # require 'mb-discid'
28
+ #
29
+ # # Create a new DiscID object.
30
+ # disc = MusicBrainz::DiscID.new
31
+ #
32
+ # # Read the TOC from the default device.
33
+ # # An audio CD must be inserted in the drive. An exception will be thrown
34
+ # # if the CD can't be read.
35
+ # begin
36
+ # disc.read
37
+ # rescue Exception => e
38
+ # puts e
39
+ # exit(1)
40
+ # end
41
+ #
42
+ # # Print information about the disc:
43
+ # print <<EOF
44
+ # DiscID : #{disc.id}
45
+ # Submit via : #{disc.submission_url}
46
+ # FreeDB ID : #{disc.freedb_id}
47
+ # First track : #{disc.first_track_num}
48
+ # Last track : #{disc.last_track_num}
49
+ # Total length: #{disc.seconds} seconds
50
+ # Sectors : #{disc.sectors}
51
+ # EOF
52
+ #
53
+ # # Print information about individual tracks:
54
+ # disc.track_details do |track_info|
55
+ # puts "Track ##{track_info.number}"
56
+ # puts " Length: %02d:%02d (%i sectors)" %
57
+ # [track_info.seconds / 60, track_info.seconds % 60, track_info.sectors]
58
+ # puts " Start : %02d:%02d (sector %i)" %
59
+ # [track_info.start_time / 60, track_info.start_time % 60, track_info.start_sector]
60
+ # puts " End : %02d:%02d (sector %i)" %
61
+ # [track_info.end_time / 60, track_info.end_time % 60, track_info.end_sector]
62
+ # end
63
+ #
64
+ # # Print a submission URL that can be used to submit
65
+ # # the disc ID to MusicBrainz.org.
66
+ # puts "\nSubmit via #{disc.submission_url}"
67
+ #
68
+ # === Specifying the device to read from:
69
+ #
70
+ # # Create a new DiscID object and read the disc in /dev/dvd:
71
+ # disc = MusicBrainz::DiscID.new
72
+ # disc.read('/dev/dvd')
73
+ #
74
+ # # Create a new DiscID object and directly read the disc in /dev/dvd:
75
+ # disc = MusicBrainz::DiscID.new('/dev/dvd')
76
+ #
77
+ # # Create a new DiscID object and directly read the disc in the platform's
78
+ # # default device:
79
+ # disc = MusicBrainz::DiscID.new(MusicBrainz::DiscID.default_device)
80
+ #
81
+ # === Calculating the DiscID for a given TOC
82
+ #
83
+ # disc = MusicBrainz::DiscID.new
84
+ #
85
+ # first_track = 1
86
+ # sectors = 224556
87
+ # track_offsets = [150, 9078, 13528, 34182, 53768, 70987, 96424,
88
+ # 118425, 136793, 159514, 179777, 198006]
89
+ #
90
+ # disc.put(first_track, sectors, track_offsets)
91
+ # puts disc.id # Should print "T_prJXQSrqbnH8OE.dgOKsHm5Uw-"
92
+ #
93
+ class DiscID
94
+
95
+ # This class holds information about a single track.
96
+ #
97
+ # Currently this includes the following fields:
98
+ # [number] The number of the track on the disc.
99
+ # [sectors] Length of the track in sectors.
100
+ # [start_sector] Start position of the track on the disc in sectors.
101
+ # [end_sector] End position of the track on the disc in sectors.
102
+ # [seconds] Length of the track in seconds.
103
+ # [start_time] Start position of the track on the disc in seconds.
104
+ # [end_time] End position of the track on the disc in seconds.
105
+ #
106
+ # You can access all fields either with directly or with the square bracket
107
+ # notation:
108
+ #
109
+ # track = TrackInfo.new(1, 150, 16007)
110
+ # puts track.sectors # 16007
111
+ # puts track[:sectors] # 16007
112
+ #
113
+ # See:: DiscID#track_details
114
+ class TrackInfo
115
+
116
+ # The number of the track on the disc.
117
+ attr_reader :number
118
+
119
+ # Length of the track in sectors.
120
+ attr_reader :sectors
121
+
122
+ # Start position of the track on the disc in sectors.
123
+ attr_reader :start_sector
124
+
125
+ # Returns a new TrackInfo.
126
+ def initialize(number, offset, length)
127
+ @number = number
128
+ @start_sector = offset
129
+ @sectors = length
130
+ end
131
+
132
+ # End position of the track on the disc in sectors.
133
+ def end_sector
134
+ start_sector + sectors
135
+ end
136
+
137
+ # Length of the track in seconds.
138
+ def seconds
139
+ DiscID.sectors_to_seconds(sectors)
140
+ end
141
+
142
+ # Start position of the track on the disc in seconds.
143
+ def start_time
144
+ DiscID.sectors_to_seconds(start_sector)
145
+ end
146
+
147
+ # End position of the track on the disc in seconds.
148
+ def end_time
149
+ DiscID.sectors_to_seconds(end_sector)
150
+ end
151
+
152
+ # Allows access to all fields similar to accessing values in a hash.
153
+ #
154
+ # Example:
155
+ # track = TrackInfo.new(1, 150, 16007)
156
+ # puts track.sectors # 16007
157
+ # puts track[:sectors] # 16007
158
+ def [](key)
159
+ if [:number, :sectors, :start_sector, :end_sector,
160
+ :seconds, :start_time, :end_time].include?(key.to_sym)
161
+ method(key).call
162
+ end
163
+ end
164
+
165
+ # Converts the TrackInfo into a Hash.
166
+ def to_hash
167
+ {
168
+ :sectors => sectors,
169
+ :start_sector => start_sector,
170
+ :end_sector => end_sector,
171
+ :seconds => seconds,
172
+ :start_time => start_time,
173
+ :end_time => end_time,
174
+ }
175
+ end
176
+
177
+ end
178
+
179
+ # DiscID to String conversion. Same as calling the method id but guaranteed
180
+ # to return a string.
181
+ def to_s
182
+ id.to_s
183
+ end
184
+
185
+ # Return the length of the disc in sectors.
186
+ #
187
+ # Returns <tt>nil</tt> if no ID was yet read.
188
+ def seconds
189
+ DiscID.sectors_to_seconds(sectors) unless @read == false
190
+ end
191
+
192
+ # Returns an array of TrackInfo objects. Each TrackInfo object contains
193
+ # detailed information about the track.
194
+ #
195
+ # If a block is given this method returns <tt>nil</tt> and instead iterates
196
+ # over the block calling the block with one argument <tt>|track_info|</tt>.
197
+ #
198
+ # Returns always <tt>nil</tt> if no ID was yet read. The block won't be
199
+ # called in this case.
200
+ def track_details
201
+ unless @read == false
202
+ track_number = self.first_track_num - 1
203
+ tracks = []
204
+
205
+ self.tracks do |offset, length|
206
+ track_number += 1
207
+ track_info = TrackInfo.new(track_number, offset, length)
208
+
209
+ if block_given?
210
+ yield track_info
211
+ else
212
+ tracks << track_info
213
+ end
214
+ end
215
+
216
+ return tracks unless block_given?
217
+ end
218
+ end
219
+
220
+ # Converts sectors to seconds.
221
+ #
222
+ # According to the red book standard 75 sectors are one second.
223
+ def self.sectors_to_seconds(sectors)
224
+ return (sectors.to_f / 75).round
225
+ end
226
+
227
+ end
228
+
229
+ end
@@ -0,0 +1,173 @@
1
+ # $Id: test_discid.rb 236 2009-05-07 05:58:07Z phw $
2
+ #
3
+ # Author:: Philipp Wolfer (mailto:phw@rubyforge.org)
4
+ # Copyright:: Copyright (c) 2007, Philipp Wolfer
5
+ # License:: RBrainz is free software distributed under a BSD style license.
6
+ # See LICENSE[file:../LICENSE.html] for permissions.
7
+
8
+ require 'test/unit'
9
+ require 'mb-discid'
10
+
11
+ # Helper class which can't be converted into a string.
12
+ class NotAString
13
+
14
+ private
15
+
16
+ def to_s
17
+ end
18
+
19
+ end
20
+
21
+ # Unit test for the MusicBrainz::DiscID class.
22
+ class TestDiscID < Test::Unit::TestCase
23
+
24
+ def setup
25
+ @fiction_disc_id = 'Wn8eRBtfLDfM0qjYPdxrz.Zjs_U-'
26
+ @fiction_first_track = 1
27
+ @fiction_last_track = 10
28
+ @fiction_sectors = 206535
29
+ @fiction_seconds = 2754
30
+ @fiction_offsets = [150, 18901, 39738, 59557, 79152, 100126,
31
+ 124833, 147278, 166336, 182560]
32
+ @fiction_lengths = [18751, 20837, 19819, 19595, 20974,
33
+ 24707, 22445, 19058, 16224, 23975]
34
+ end
35
+
36
+ def teardown
37
+ end
38
+
39
+ # Test reading the disc id from a device.
40
+ # We would need some kind of small test data to do this.
41
+ #def test_read
42
+ # assert false, "Not implemented yet"
43
+ #end
44
+
45
+ # Test how read reacts on different arguments.
46
+ # Those reads should all fail, but they must never cause a segmentation fault.
47
+ def test_read_invalid_arguments
48
+ assert_raise(TypeError) {MusicBrainz::DiscID.new(NotAString.new)}
49
+ assert_raise(Exception) {MusicBrainz::DiscID.new(1)}
50
+ assert_raise(Exception) {MusicBrainz::DiscID.new('invalid_device')}
51
+ assert_raise(Exception) {MusicBrainz::DiscID.new(:invalid_device)}
52
+ assert_raise(ArgumentError) {MusicBrainz::DiscID.new(
53
+ MusicBrainz::DiscID.default_device,
54
+ 'second argument')}
55
+
56
+ disc = MusicBrainz::DiscID.new
57
+ assert_raise(TypeError) {disc.read(NotAString.new)}
58
+ assert_raise(Exception) {disc.read(1)}
59
+ assert_raise(Exception) {disc.read('invalid_device')}
60
+ assert_raise(Exception) {disc.read(:invalid_device)}
61
+ assert_raise(ArgumentError) {disc.read(MusicBrainz::DiscID.default_device,
62
+ 'second argument')}
63
+ end
64
+
65
+ # Test calculation of the disc id if the TOC information
66
+ # gets set by the put method.
67
+ # All attributes should be nil after a failure, even if there was a
68
+ # successfull put before.
69
+ def test_put
70
+ disc = MusicBrainz::DiscID.new
71
+ assert_equal nil, disc.id
72
+ assert_equal '', disc.to_s
73
+ assert_equal nil, disc.first_track_num
74
+ assert_equal nil, disc.last_track_num
75
+ assert_equal nil, disc.sectors
76
+ assert_equal nil, disc.seconds
77
+ assert_equal nil, disc.tracks
78
+
79
+ # First erroneous put
80
+ assert_raise(Exception) {disc.put(-1, @fiction_sectors, @fiction_offsets)}
81
+ assert_equal nil, disc.id
82
+ assert_equal '', disc.to_s
83
+ assert_equal nil, disc.first_track_num
84
+ assert_equal nil, disc.last_track_num
85
+ assert_equal nil, disc.sectors
86
+ assert_equal nil, disc.seconds
87
+ assert_equal nil, disc.tracks
88
+
89
+ # Second successfull put
90
+ assert_nothing_raised {disc.put(@fiction_first_track, @fiction_sectors,
91
+ @fiction_offsets)}
92
+ assert_equal @fiction_disc_id, disc.id
93
+ assert_equal @fiction_disc_id, disc.to_s
94
+ assert_equal @fiction_first_track, disc.first_track_num
95
+ assert_equal @fiction_last_track, disc.last_track_num
96
+ assert_equal @fiction_sectors, disc.sectors
97
+ assert_equal @fiction_seconds, disc.seconds
98
+ assert_equal @fiction_offsets, disc.tracks.map{|t| t[0]}
99
+ assert_equal @fiction_lengths, disc.tracks.map{|t| t[1]}
100
+
101
+ # Third erroneous put
102
+ assert_raise(Exception) {disc.put(@fiction_first_track, @fiction_sectors,
103
+ Array.new(100, 1))}
104
+ assert_equal nil, disc.id
105
+ assert_equal '', disc.to_s
106
+ assert_equal nil, disc.first_track_num
107
+ assert_equal nil, disc.last_track_num
108
+ assert_equal nil, disc.sectors
109
+ assert_equal nil, disc.seconds
110
+ assert_equal nil, disc.tracks
111
+ end
112
+
113
+ # Test the track info method and TrackInfo objects
114
+ def test_track_details
115
+ disc = MusicBrainz::DiscID.new
116
+
117
+ assert_equal nil, disc.track_details
118
+ assert_nothing_raised {disc.put(@fiction_first_track, @fiction_sectors,
119
+ @fiction_offsets)}
120
+
121
+
122
+ # Save a block for testing each track
123
+ number = 0
124
+ proc_test_track = lambda do |track|
125
+ assert_equal number + 1, track.number
126
+
127
+ assert_equal @fiction_offsets[number], track.start_sector
128
+ assert_equal @fiction_lengths[number], track.sectors
129
+ assert_equal @fiction_offsets[number]+ @fiction_lengths[number],
130
+ track.end_sector
131
+
132
+ assert_equal MusicBrainz::DiscID.sectors_to_seconds(@fiction_offsets[number]),
133
+ track.start_time
134
+ assert_equal MusicBrainz::DiscID.sectors_to_seconds(@fiction_lengths[number]),
135
+ track.seconds
136
+ assert_equal MusicBrainz::DiscID.sectors_to_seconds(
137
+ @fiction_offsets[number]+ @fiction_lengths[number]),
138
+ track.end_time
139
+
140
+ assert_equal track.number, track[:number]
141
+ assert_equal track.sectors, track[:sectors]
142
+ assert_equal track.start_sector, track[:start_sector]
143
+ assert_equal track.end_sector, track[:end_sector]
144
+ assert_equal track.seconds, track[:seconds]
145
+ assert_equal track.start_time, track[:start_time]
146
+ assert_equal track.end_time, track[:end_time]
147
+
148
+ assert_equal nil, track[:invalid_value]
149
+
150
+ number += 1
151
+ end
152
+
153
+ # Call track_info and retrieve an Array
154
+ track_info = []
155
+ assert_nothing_raised {track_info = disc.track_details}
156
+ assert track_info.is_a?(Array)
157
+ track_info.each(&proc_test_track)
158
+ assert_equal disc.last_track_num, number
159
+
160
+ # Calling track_info directly with a given block
161
+ number = 0 # Reset the number of tracks (the above block is a closure, so this works)
162
+ assert_equal nil, disc.track_details(&proc_test_track)
163
+ assert_equal disc.last_track_num, number
164
+ end
165
+
166
+ # Test the conversion from sectors to seconds
167
+ def test_sectors_to_seconds
168
+ assert_equal 0, MusicBrainz::DiscID.sectors_to_seconds(0)
169
+ assert_equal @fiction_seconds,
170
+ MusicBrainz::DiscID.sectors_to_seconds(@fiction_sectors)
171
+ end
172
+
173
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mb-discid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: x86-mswin32-60
6
+ authors:
7
+ - Philipp Wolfer
8
+ autorequire: mb-discid
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-19 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: " Ruby bindings for libdiscid. See http://musicbrainz.org/doc/libdiscid\n for more information on libdiscid and MusicBrainz.\n"
17
+ email: phw@rubyforge.org
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - LICENSE
25
+ - CHANGES
26
+ files:
27
+ - Rakefile
28
+ - LICENSE
29
+ - README
30
+ - CHANGES
31
+ - examples/discid.rb
32
+ - ext/mb_discid.c
33
+ - ext/extconf.rb
34
+ - lib/mb-discid.rb
35
+ - test/test_discid.rb
36
+ - ext/MB_DiscID.so
37
+ has_rdoc: true
38
+ homepage: http://rbrainz.rubyforge.org
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ - ext
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 1.8.7
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements:
60
+ - libdiscid (http://musicbrainz.org/doc/libdiscid)
61
+ rubyforge_project: rbrainz
62
+ rubygems_version: 1.3.5
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: Ruby bindings for libdiscid.
66
+ test_files: []
67
+