mb-discid 0.1.4-x86-mswin32-60

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.
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
+