chromaprint 0.0.1

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