chromaprint 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 46c10be2f763ed40a48543683aaaa81fdd80da24
4
+ data.tar.gz: 6ab14b4dc5ea352d68a2274924ac950a75fc9801
5
+ SHA512:
6
+ metadata.gz: d1e6683a756e65ea4dcd4e52cb3525a8a9b2062c4c335a276e80f918d6e18f0e53f0423f4945647c9216896f78029a99b13f77ab84a4eb47a7c8e37660ff123f
7
+ data.tar.gz: a71826f62481bcd988cb7771d746ce49b92deae867702500dc145c779f8519d82ed8202e1dfe8283a7d0597ca17532cdab6972d2e0a9fd90c75762ce2054ef62
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 TMX Credit, author Potapov Sergey
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # Chromaprint
2
+
3
+ Port of [Chromaprint](http://acoustid.org/chromaprint) C/C++ library to Ruby.
4
+
5
+ > A client-side library that implements a custom algorithm for extracting fingerprints from any audio source.
6
+
7
+
8
+ ## Dependencies
9
+
10
+ * Chromaprint
11
+
12
+ ### Debian / Ubuntu
13
+
14
+ ```sh
15
+ apt-get install libchromaprint-dev
16
+ ```
17
+
18
+ ### Mac
19
+
20
+ ```sh
21
+ # At the time of this writing, chromaprint is unavailable in MacPorts or Fink:
22
+ brew install chromaprint
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+ # Create context for rate=44100 and channel=1.
29
+ context1 = Chromaprint::Context.new(44100, 1)
30
+
31
+ # Get audio data. Data should be in raw audio format with 16-bit signed samples.
32
+ # The library doesn't care about decoding formats like mp3 or ogg, you should
33
+ # do it yourself.
34
+ data1 = File.binread('/1.wav')
35
+
36
+ # Create context for rate=22050 and channel=2 and get fingerprint
37
+ context2 = Chromaprint::Context.new(22050, 1)
38
+ fingerprint1 = context1.get_fingerprint(data1)
39
+
40
+ # Get fingerprint of another audio
41
+ context2 = Chromaprint::Context.new(44100, 2)
42
+ fingerprint2 = context2.get_fingerprint(File.binread('/2.wav')
43
+
44
+ # Compressed fingerprint, returned by chromaprint_get_fingerprint() C function.
45
+ fingerprint1.compressed # => "AQAALOkUKdlChE92NNeFn8EjF9..."
46
+
47
+ # Raw fingerprint, returned by chromaprint_get_raw_fingerprint() C function.
48
+ fingerprint1.raw # => [294890785, 328373552, 315802880, 303481088, ...]
49
+
50
+ # Compare 2 fingerprints, result is 0..1 range, where 1 is 100% similarity.
51
+ fingerprint1.compare(fingerprint2) # => 0.93231
52
+ ```
53
+
54
+ ## Run tests
55
+
56
+ ```sh
57
+ rake spec
58
+ ```
59
+
60
+ ## Credits
61
+
62
+ * [Sergey Potapov](https://github.com/greyblake)
63
+
64
+ ## Copyright
65
+
66
+ Copyright (c) 2013 TMX Credit.
@@ -0,0 +1,31 @@
1
+ require 'ffi'
2
+
3
+ require 'chromaprint/lib'
4
+ require 'chromaprint/context'
5
+ require 'chromaprint/fingerprint'
6
+
7
+ # Chromaprint is originally written in C/C++, a library which provides tools
8
+ # to calculate fingerprints of audio data. This is its port for the Ruby language.
9
+ module Chromaprint
10
+ # All algorithm constants are taken from +chromaprint.h+
11
+ ALGORITHM_TEST1 = 0
12
+
13
+ # :nodoc:
14
+ ALGORITHM_TEST2 = 1
15
+
16
+ # :nodoc:
17
+ ALGORITHM_TEST3 = 2
18
+
19
+ # Default algorithm. Taken from +chromaprint.h+
20
+ ALGORITHM_DEFAULT = ALGORITHM_TEST2
21
+
22
+ # Chromaprint works with 16 bit samples
23
+ BYTES_PER_SAMPLE = 2
24
+
25
+ # Get version of Chromaprint library
26
+ #
27
+ # @return [String] version
28
+ def self.lib_version
29
+ Lib.chromaprint_get_version
30
+ end
31
+ end
@@ -0,0 +1,63 @@
1
+ module Chromaprint
2
+ # Calculates fingerprints of audio data.
3
+ #
4
+ # @example
5
+ # chromaprint = Chromaprint::Context.new(44100, 1)
6
+ # data = File.binread('song.wav')
7
+ # fingerprint = chromaprint.get_fingerprint(data)
8
+ class Context
9
+ # @param rate [Integer] sample rate of audio
10
+ # @param num_channels [Integer] number of channels (1 or 2)
11
+ # @param algorithm [Integer] specify algorithm to be used to Chromaprint
12
+ # library. Must be {ALGORITHM_TEST1}, {ALGORITHM_TEST2} or
13
+ # {ALGORITHM_TEST3}.
14
+ def initialize(rate, num_channels, algorithm = ALGORITHM_DEFAULT)
15
+ @rate = rate
16
+ @num_channels = num_channels
17
+ @algorithm = ALGORITHM_DEFAULT
18
+ end
19
+
20
+
21
+ # Calculate raw and compressed fingerprints of the audio data.
22
+ #
23
+ #
24
+ # @param data [String] raw audio data preseted by 16-bit signed integers
25
+ #
26
+ # @return [Chromaprint::Fingerprint]
27
+ def get_fingerprint(data)
28
+ # Allocate memory for context and initialize
29
+ p_context = Lib.chromaprint_new(@algorithm)
30
+ Lib.chromaprint_start(p_context, @rate, @num_channels)
31
+
32
+ # Create a pointer to the data
33
+ p_data = FFI::MemoryPointer.from_string(data)
34
+
35
+ # Calculate number of samples and feed data.
36
+ data_size = p_data.size / BYTES_PER_SAMPLE
37
+ Lib.chromaprint_feed(p_context, p_data, data_size)
38
+
39
+ # Calculate the fingerprint
40
+ Lib.chromaprint_finish(p_context)
41
+
42
+ # Get compressed fingerprint
43
+ p_p_fingerprint = FFI::MemoryPointer.new(:pointer)
44
+ Lib.chromaprint_get_fingerprint(p_context, p_p_fingerprint)
45
+ p_fingerprint = p_p_fingerprint.get_pointer(0)
46
+ fingerprint = p_fingerprint.get_string(0)
47
+
48
+ # Get raw fingerprint
49
+ p_p_raw_fingerprint = FFI::MemoryPointer.new(:pointer)
50
+ p_size = FFI::MemoryPointer.new(:pointer)
51
+ Lib.chromaprint_get_raw_fingerprint(p_context, p_p_raw_fingerprint, p_size)
52
+ p_raw_fingerprint = p_p_raw_fingerprint.get_pointer(0)
53
+ raw_fingerprint = p_raw_fingerprint.get_array_of_uint(0, p_size.get_int32(0))
54
+
55
+ Fingerprint.new(fingerprint, raw_fingerprint)
56
+ ensure
57
+ # Free memory
58
+ Lib.chromaprint_free(p_context) if p_context
59
+ Lib.chromaprint_dealloc(p_fingerprint) if p_fingerprint
60
+ Lib.chromaprint_dealloc(p_raw_fingerprint) if p_raw_fingerprint
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,66 @@
1
+ module Chromaprint
2
+ # Contains compressed and raw fingerprints and provides a method to compare
3
+ # them against other fingerprints.
4
+ class Fingerprint
5
+ # Number of bits in one item of raw fingerprint
6
+ BITS_PER_RAW_ITEM = 32
7
+
8
+ # @attr_reader compressed [String] compressed fingerprints
9
+ attr_reader :compressed
10
+
11
+ # @attr_reader raw [Array<Integer>] raw fingerprints,
12
+ # array of 32-bit integers returned by native C library.
13
+ attr_reader :raw
14
+
15
+ # @param compressed [String] compressed fingerprint
16
+ # @param raw [Array<Integer>] raw fingerprint
17
+ def initialize(compressed, raw)
18
+ @compressed = compressed
19
+ @raw = raw
20
+ end
21
+
22
+ # Compare a fingerprint against another fingerprint.
23
+ #
24
+ # @param fingerprint [Chromaprint::Fingerprint] fingerprint to compare against
25
+ #
26
+ # @return [Float] float in 0..1 range where 1 is 100% match
27
+ def compare(fingerprint)
28
+ max_raw_size = [@raw.size, fingerprint.raw.size].max
29
+ bit_size = max_raw_size * BITS_PER_RAW_ITEM
30
+
31
+ distance = hamming_distance(@raw, fingerprint.raw)
32
+
33
+ 1 - distance.to_f / bit_size
34
+ end
35
+
36
+ # Calculate hamming distance between 32 bit integer arrays.
37
+ # In short we're calculating number of bits which are different.
38
+ #
39
+ # Read more: http://en.wikipedia.org/wiki/Hamming_distance
40
+ #
41
+ # It's sad to say but according to Stackoverflow it's the fastest
42
+ # way to calculate hamming distance between 2 integers in ruby:
43
+ # (a^b).to_s(2).count("1")
44
+ #
45
+ # ref: http://stackoverflow.com/questions/6395165/most-efficient-way-to-calculate-hamming-distance-in-ruby/6397116#6397116
46
+ #
47
+ # If array sizes are different we add difference to the distance.
48
+ #
49
+ # @param raw1 [Array<Integer>] array of 32 bit integers.
50
+ # @param raw2 [Array<Integer>] array of 32 bit integers.
51
+ #
52
+ # @return [Integer] hamming distance
53
+ def hamming_distance(raw1, raw2)
54
+ distance = 0
55
+
56
+ min_size, max_size = [raw1, raw2].map(&:size).sort
57
+
58
+ min_size.times do |i|
59
+ distance += (raw1[i] ^ raw2[i]).to_s(2).count('1')
60
+ end
61
+
62
+ distance += (max_size - min_size) * BITS_PER_RAW_ITEM
63
+ end
64
+ private :hamming_distance
65
+ end
66
+ end
@@ -0,0 +1,172 @@
1
+ module Chromaprint
2
+ # Ports the chromaprint API functions. To get their detailed documentation
3
+ # please see +chromaprint.h+ of the original C/C++ library.
4
+ #
5
+ # ref: https://bitbucket.org/acoustid/chromaprint/src/master/src/chromaprint.h
6
+ module Lib
7
+ extend FFI::Library
8
+ ffi_lib 'chromaprint'
9
+
10
+ # Return the version number of Chromaprint.
11
+ #
12
+ # const char *chromaprint_get_version(void)
13
+ attach_function :chromaprint_get_version, [], :string
14
+
15
+ # Allocate and initialize the Chromaprint context.
16
+ #
17
+ # Parameters:
18
+ # - version: Version of the fingerprint algorithm, use
19
+ # CHROMAPRINT_ALGORITHM_DEFAULT for the default
20
+ # algorithm
21
+ #
22
+ # Returns:
23
+ # - Chromaprint context pointer
24
+ #
25
+ # ChromaprintContext *chromaprint_new(int algorithm)
26
+ attach_function :chromaprint_new, [:int], :pointer
27
+
28
+ # Deallocate the Chromaprint context.
29
+ #
30
+ # Parameters:
31
+ # - ctx: Chromaprint context pointer
32
+ #
33
+ # void chromaprint_free(ChromaprintContext *ctx)
34
+ attach_function :chromaprint_free, [:pointer], :void
35
+
36
+ # Return the fingerprint algorithm this context is configured to use.
37
+ #
38
+ # int chromaprint_get_algorithm(ChromaprintContext *ctx)
39
+ #
40
+ # @note
41
+ # In Debian Wheezy chromaprint.so (version 6.0.0) doesn't have
42
+ # chromaprint_get_algorithm() function. So we comment it out to not
43
+ # raise exception on loading.
44
+ #
45
+ # attach_function :chromaprint_get_algorithm, [:pointer], :int
46
+
47
+ # Restart the computation of a fingerprint with a new audio stream.
48
+ #
49
+ # Parameters:
50
+ # - ctx: Chromaprint context pointer
51
+ # - sample_rate: sample rate of the audio stream (in Hz)
52
+ # - num_channels: numbers of channels in the audio stream (1 or 2)
53
+ #
54
+ # Returns:
55
+ # - 0 on error, 1 on success
56
+ #
57
+ # int chromaprint_start(ChromaprintContext *ctx, int sample_rate, int num_channels)
58
+ attach_function :chromaprint_start, [:pointer, :int, :int], :int
59
+
60
+ # Send audio data to the fingerprint calculator.
61
+ #
62
+ # Parameters:
63
+ # - ctx: Chromaprint context pointer
64
+ # - data: raw audio data, should point to an array of 16-bit signed
65
+ # integers in native byte-order
66
+ # - size: size of the data buffer (in samples)
67
+ #
68
+ # Returns:
69
+ # - 0 on error, 1 on success
70
+ #
71
+ # int chromaprint_feed(ChromaprintContext *ctx, void *data, int size)
72
+ attach_function :chromaprint_feed, [:pointer, :pointer, :int], :int
73
+
74
+ # Process any remaining buffered audio data and calculate the fingerprint.
75
+ #
76
+ # Parameters:
77
+ # - ctx: Chromaprint context pointer
78
+ #
79
+ # Returns:
80
+ # - 0 on error, 1 on success
81
+ #
82
+ # int chromaprint_finish(ChromaprintContext *ctx)
83
+ attach_function :chromaprint_finish, [:pointer], :int
84
+
85
+ # Return the calculated fingerprint as a compressed string.
86
+ #
87
+ # The caller is responsible for freeing the returned pointer using
88
+ # chromaprint_dealloc().
89
+ #
90
+ # Parameters:
91
+ # - ctx: Chromaprint context pointer
92
+ # - fingerprint: pointer to a pointer, where a pointer to the allocated array
93
+ # will be stored
94
+ #
95
+ # Returns:
96
+ # - 0 on error, 1 on success
97
+ #
98
+ # int chromaprint_get_fingerprint(ChromaprintContext *ctx, char **fingerprint)
99
+ attach_function :chromaprint_get_fingerprint, [:pointer, :pointer], :int
100
+
101
+ # Return the calculated fingerprint as an array of 32-bit integers.
102
+ #
103
+ # The caller is responsible for freeing the returned pointer using
104
+ # chromaprint_dealloc().
105
+ #
106
+ # Parameters:
107
+ # - ctx: Chromaprint context pointer
108
+ # - fingerprint: pointer to a pointer, where a pointer to the allocated array
109
+ # will be stored
110
+ # - size: number of items in the returned raw fingerprint
111
+ #
112
+ # Returns:
113
+ # - 0 on error, 1 on success
114
+ #
115
+ # int chromaprint_get_raw_fingerprint(ChromaprintContext *ctx, void **fingerprint, int *size)
116
+ attach_function :chromaprint_get_raw_fingerprint, [:pointer, :pointer, :pointer], :int
117
+
118
+ # Compress and optionally base64-encode a raw fingerprint
119
+ #
120
+ # The caller is responsible for freeing the returned pointer using
121
+ # chromaprint_dealloc().
122
+ #
123
+ # Parameters:
124
+ # - fp: pointer to an array of 32-bit integers representing the raw
125
+ # fingerprint to be encoded
126
+ # - size: number of items in the raw fingerprint
127
+ # - algorithm: Chromaprint algorithm version which was used to generate the
128
+ # raw fingerprint
129
+ # - encoded_fp: pointer to a pointer, where the encoded fingerprint will be
130
+ # stored
131
+ # - encoded_size: size of the encoded fingerprint in bytes
132
+ # - base64: Whether to return binary data or base64-encoded ASCII data. The
133
+ # compressed fingerprint will be encoded using base64 with the
134
+ # URL-safe scheme if you set this parameter to 1. It will return
135
+ # binary data if it's 0.
136
+ #
137
+ # Returns:
138
+ # - 0 on error, 1 on success
139
+ # int chromaprint_encode_fingerprint(void *fp, int size, int algorithm, void **encoded_fp, int *encoded_size, int base64)
140
+ attach_function :chromaprint_encode_fingerprint, [:pointer, :int, :int, :pointer, :pointer, :int], :int
141
+
142
+ # Uncompress and optionally base64-decode an encoded fingerprint
143
+ #
144
+ # The caller is responsible for freeing the returned pointer using
145
+ # chromaprint_dealloc().
146
+ #
147
+ # Parameters:
148
+ # - encoded_fp: Pointer to an encoded fingerprint
149
+ # - encoded_size: Size of the encoded fingerprint in bytes
150
+ # - fp: Pointer to a pointer, where the decoded raw fingerprint (array
151
+ # of 32-bit integers) will be stored
152
+ # - size: Number of items in the returned raw fingerprint
153
+ # - algorithm: Chromaprint algorithm version which was used to generate the
154
+ # raw fingerprint
155
+ # - base64: Whether the encoded_fp parameter contains binary data or
156
+ # base64-encoded ASCII data. If 1, it will base64-decode the data
157
+ # before uncompressing the fingerprint.
158
+ #
159
+ # Returns:
160
+ # - 0 on error, 1 on success
161
+ #
162
+ # int chromaprint_decode_fingerprint(void *encoded_fp, int encoded_size, void **fp, int *size, int *algorithm, int base64)
163
+ attach_function :chromaprint_decode_fingerprint, [:pointer, :int, :pointer, :pointer, :pointer, :int], :int
164
+
165
+ # Free memory allocated by any function from the Chromaprint API.
166
+ #
167
+ # - ptr: Pointer to be deallocated
168
+ #
169
+ # void chromaprint_dealloc(void *ptr);
170
+ attach_function :chromaprint_dealloc, [:pointer], :void
171
+ end
172
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chromaprint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - TMX Credit
8
+ - Potapov Sergey
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 2.14.1
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: 2.14.1
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '1.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '1.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: jeweler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 1.8.7
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.8.7
70
+ - !ruby/object:Gem::Dependency
71
+ name: yard
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: A client-side library that implements a custom algorithm for extracting
99
+ fingerprints from any audio source
100
+ email:
101
+ - rubygems@tmxcredit.com
102
+ - blake131313@gmail.com
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files:
106
+ - LICENSE.txt
107
+ - README.markdown
108
+ files:
109
+ - LICENSE.txt
110
+ - README.markdown
111
+ - lib/chromaprint.rb
112
+ - lib/chromaprint/context.rb
113
+ - lib/chromaprint/fingerprint.rb
114
+ - lib/chromaprint/lib.rb
115
+ homepage: http://github.com/greyblake/chromaprint
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.0.3
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: Port of Chromaprint library to Ruby
139
+ test_files: []