farleyknight-sndx 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+
2
+ == 0.1.0
3
+
4
+ First Gem release
5
+
@@ -0,0 +1,9 @@
1
+ Manifest.txt
2
+ README.txt
3
+ CHANGELOG.txt
4
+ Rakefile
5
+ lib/sndx.rb
6
+ test/test_sndx.rb
7
+ ext/sndx/sndx.c
8
+ ext/sndx/extconf.rb
9
+
@@ -0,0 +1,62 @@
1
+ = sndx
2
+
3
+ * http://github.com/farleyknight/sndx
4
+
5
+ == DESCRIPTION:
6
+
7
+ libsndfile + libXtract = Awesome audio analysis library
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * Wraps some of libsndfile
12
+ * Wraps some of libXtract
13
+ * Has tests so you see what I got working
14
+ * Doesn't wrap all of libXtract
15
+ * Don't think I really need to wrap much of libsndfile
16
+ * Just numbers so you have no idea what they mean unless you
17
+ put some kind of GUI on it..
18
+
19
+ == SYNOPSIS:
20
+
21
+ >> require 'lib/sndx'
22
+ => true
23
+ >> @file = Sndfile.new("test/assets/48550__gusrikh__Hit_3.wav")
24
+ => #<Sndfile:0xb7def820>
25
+ >> Xtract.analyze(Xtract::MEAN, @file)
26
+ => -7.02867037034594e-05
27
+ >> Xtract.analyze(Xtract::SPECTRAL_CENTROID, @file)
28
+ => 0.114604391157627
29
+
30
+ == REQUIREMENTS:
31
+
32
+ libsndfile [http://www.mega-nerd.com/libsndfile/]
33
+ libXtract [http://libxtract.sourceforge.net]
34
+
35
+ == INSTALL:
36
+
37
+ Not yet
38
+
39
+ == LICENSE:
40
+
41
+ (The MIT License)
42
+
43
+ Copyright (c) 2009
44
+
45
+ Permission is hereby granted, free of charge, to any person obtaining
46
+ a copy of this software and associated documentation files (the
47
+ 'Software'), to deal in the Software without restriction, including
48
+ without limitation the rights to use, copy, modify, merge, publish,
49
+ distribute, sublicense, and/or sell copies of the Software, and to
50
+ permit persons to whom the Software is furnished to do so, subject to
51
+ the following conditions:
52
+
53
+ The above copyright notice and this permission notice shall be
54
+ included in all copies or substantial portions of the Software.
55
+
56
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
57
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
58
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
59
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
60
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
61
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
62
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ gem 'rake-compiler', '>= 0.4.1'
4
+ require "rake/extensiontask"
5
+
6
+ require 'lib/sndx'
7
+
8
+ HOE = Hoe.spec('sndx') do
9
+ developer('Farley Knight', 'farleyknight@gmail.com')
10
+ self.readme_file = 'README.txt'
11
+ self.history_file = 'CHANGELOG.txt'
12
+ self.version = Sndx::VERSION
13
+ self.spec_extras = { :extensions => ["ext/sndx/extconf.rb"] }
14
+ self.extra_deps = ['rake-compiler', '>= 0.4.1']
15
+ end
16
+
17
+ Rake::ExtensionTask.new("sndx", HOE.spec) do |ext|
18
+ ext.lib_dir = File.join('lib', 'sndx')
19
+ end
20
+
@@ -0,0 +1,15 @@
1
+
2
+ require 'mkmf'
3
+
4
+ unless find_library('sndfile', 'sf_open')
5
+ abort "Couldn't find libsndfile! Make sure it's installed.."
6
+ end
7
+
8
+ unless find_library('xtract', 'xtract_init_mfcc')
9
+ abort "Couldn't find libxtract! Make sure it's installed.."
10
+ end
11
+
12
+
13
+ create_makefile('sndx/sndx')
14
+
15
+
@@ -0,0 +1,312 @@
1
+ #include <ruby.h>
2
+ #include <sndfile.h>
3
+ #include "xtract/libxtract.h"
4
+
5
+
6
+ /*********************************************************
7
+ libsndfile
8
+ **********************************************************/
9
+
10
+ VALUE cSndfile;
11
+
12
+ typedef struct {
13
+ char *filename;
14
+ SNDFILE *sndfile;
15
+ SF_INFO sf_info;
16
+ } sndfile_t;
17
+
18
+
19
+ // TODO: Close file upon dealloc
20
+ // TODO: Should only receive a sndfile_t, not the three args for constructing
21
+ // one
22
+ VALUE Data_Wrap_sndfile_t(char *filename, SNDFILE *infile, SF_INFO sf_info) {
23
+ sndfile_t *sndfile = malloc(sizeof(sndfile_t));
24
+
25
+ sndfile->filename = filename;
26
+ sndfile->sndfile = infile;
27
+ sndfile->sf_info = sf_info;
28
+
29
+ return Data_Wrap_Struct(cSndfile, 0, 0, sndfile);
30
+ }
31
+
32
+ sndfile_t *Data_Get_sndfile_t(VALUE value) {
33
+ sndfile_t *sndfile;
34
+ Data_Get_Struct(value, sndfile_t, sndfile);
35
+ return sndfile;
36
+ }
37
+
38
+ VALUE new(VALUE klass, VALUE filename) {
39
+ Check_Type(filename, T_STRING);
40
+
41
+ SNDFILE *infile;
42
+ SF_INFO info;
43
+
44
+ memset(&info, 0, sizeof (info));
45
+
46
+ infile = sf_open(StringValuePtr(filename), SFM_READ, &info);
47
+
48
+ if (infile == NULL) {
49
+ rb_raise(rb_eRuntimeError, "Error : failed to open file '%s' : %s", StringValuePtr(filename), sf_strerror (NULL));
50
+ return Qnil;
51
+ } else {
52
+ // return Qnil;
53
+ return Data_Wrap_sndfile_t(StringValuePtr(filename), infile, info);
54
+ }
55
+ }
56
+
57
+ VALUE close(VALUE self) {
58
+ sndfile_t *sndfile = Data_Get_sndfile_t(self);
59
+
60
+ if (sf_close(sndfile->sndfile)) {
61
+ return Qtrue;
62
+ } else {
63
+ rb_raise(rb_eRuntimeError, "Couldn't close Sndfile '%s'!", StringPtrValue(sndfile->filename));
64
+ return Qfalse;
65
+ }
66
+ }
67
+
68
+
69
+ VALUE read_sample(VALUE self, VALUE index) {
70
+ sndfile_t *sndfile = Data_Get_sndfile_t(self);
71
+
72
+ sf_seek(sndfile->sndfile, FIX2INT(index), SEEK_SET);
73
+
74
+ float *buffer = (float *) malloc(sizeof(float)*1);
75
+ sf_readf_float(sndfile->sndfile, buffer, 1);
76
+
77
+ return rb_float_new(buffer[0]);
78
+ }
79
+
80
+ int frame_count(sndfile_t *sndfile) {
81
+ return sndfile->sf_info.frames;
82
+ }
83
+
84
+
85
+ VALUE get(VALUE self, VALUE arg) {
86
+ long begin, length;
87
+
88
+ if (FIXNUM_P(arg)) {
89
+ return get_sample(self, FIX2INT(arg));
90
+ }
91
+
92
+ switch (rb_range_beg_len(arg, &begin, &length, frame_count(Data_Get_sndfile_t(self)), 0)) {
93
+ case Qfalse:
94
+ break;
95
+ case Qnil:
96
+ return Qnil;
97
+ default:
98
+ return get_range(self, begin, length);
99
+ }
100
+
101
+ rb_raise(rb_eRuntimeError, "Type must be either Fixnum or Range!");
102
+ return Qnil;
103
+ }
104
+
105
+
106
+ VALUE frames(VALUE self) {
107
+ sndfile_t *sndfile = Data_Get_sndfile_t(self);
108
+
109
+ return INT2FIX(sndfile->sf_info.frames);
110
+ }
111
+
112
+ VALUE samplerate(VALUE self) {
113
+ sndfile_t *sndfile = Data_Get_sndfile_t(self);
114
+ return INT2FIX(sndfile->sf_info.samplerate);
115
+ }
116
+
117
+ VALUE filename(VALUE self) {
118
+ sndfile_t *sndfile = Data_Get_sndfile_t(self);
119
+ return rb_str_new2(sndfile->filename);
120
+ }
121
+
122
+ int channel_count(sndfile_t *sndfile) {
123
+ return sndfile->sf_info.channels;
124
+ }
125
+
126
+ VALUE channels(VALUE self) {
127
+ sndfile_t *sndfile = Data_Get_sndfile_t(self);
128
+ return INT2FIX(sndfile->sf_info.channels);
129
+ }
130
+
131
+ VALUE format_name(int format) {
132
+ VALUE name = rb_str_new2("");
133
+
134
+ if ((format | SF_FORMAT_WAV) == format)
135
+ rb_str_concat(name, rb_str_new2("Microsoft WAV"));
136
+ else if ((format | SF_FORMAT_AIFF) == format)
137
+ rb_str_concat(name, rb_str_new2("Apple/SGI AIFF"));
138
+ else if ((format | SF_FORMAT_AU) == format)
139
+ rb_str_concat(name, rb_str_new2("Sun/NeXT AU"));
140
+ else if ((format | SF_FORMAT_RAW) == format)
141
+ rb_str_concat(name, rb_str_new2("RAW PCM data"));
142
+ else
143
+ rb_str_concat(name, rb_str_new2("Dunno"));
144
+
145
+ if ((format | SF_FORMAT_PCM_S8) == format)
146
+ rb_str_concat(name, rb_str_new2(" 8 bit"));
147
+ else if ((format | SF_FORMAT_PCM_16) == format)
148
+ rb_str_concat(name, rb_str_new2(" 16 bit"));
149
+ else if ((format | SF_FORMAT_PCM_24) == format)
150
+ rb_str_concat(name, rb_str_new2(" 24 bit"));
151
+ else if ((format | SF_FORMAT_PCM_32) == format)
152
+ rb_str_concat(name, rb_str_new2(" 32 bit"));
153
+
154
+ return name;
155
+ }
156
+
157
+
158
+ VALUE format(VALUE self) {
159
+ sndfile_t *sndfile = Data_Get_sndfile_t(self);
160
+ return format_name(sndfile->sf_info.format);
161
+ }
162
+
163
+
164
+ /*********************************************************
165
+ libxtract
166
+ **********************************************************/
167
+
168
+ VALUE mXtract;
169
+
170
+ float *all_samples(sndfile_t *sndfile) {
171
+ long length = frame_count(sndfile);
172
+ int i;
173
+ float *buffer;
174
+
175
+ sf_seek(sndfile->sndfile, 0, SEEK_SET);
176
+
177
+ buffer = calloc(sizeof(float), channel_count(sndfile) * length);
178
+ int samples_read = sf_readf_float(sndfile->sndfile, buffer, length);
179
+
180
+ return buffer;
181
+ }
182
+
183
+ VALUE analyze(VALUE klass, VALUE analysis_code, VALUE sound) {
184
+ Check_Type(analysis_code, T_FIXNUM);
185
+ Check_Type(sound, T_DATA);
186
+
187
+ sndfile_t *sndfile = Data_Get_sndfile_t(sound);
188
+ float result, *samples = all_samples(sndfile);
189
+
190
+ int analysis_type = FIX2INT(analysis_code);
191
+
192
+ int return_code = xtract[analysis_type](samples, frame_count(sndfile), NULL, &result);
193
+
194
+ if (return_code == XTRACT_FEATURE_NOT_IMPLEMENTED) {
195
+ rb_raise(rb_eRuntimeError, "Xtract feature '%d' not implemented", analysis_type);
196
+ return Qnil;
197
+ } else {
198
+ return rb_float_new(result);
199
+ }
200
+ }
201
+
202
+
203
+ void Init_sndx() {
204
+ /*********************************************************
205
+ libsndfile
206
+ **********************************************************/
207
+
208
+ cSndfile = rb_define_class("Sndfile", rb_cObject);
209
+ rb_define_singleton_method(cSndfile, "new", new, 1);
210
+
211
+ // File handling and accessing
212
+ // rb_define_method(cSndfile, "read", read, 2);
213
+ // rb_define_method(cSndfile, "write", write, 1);
214
+ rb_define_method(cSndfile, "[]", get, 1);
215
+ rb_define_method(cSndfile, "read", read_sample, 1);
216
+ // rb_define_method(cSndfile, "read_range", read_sample_range, 1);
217
+ rb_define_method(cSndfile, "close", close, 0);
218
+
219
+ // SF_INFO accessors
220
+ rb_define_method(cSndfile, "frames", frames, 0);
221
+ rb_define_method(cSndfile, "samplerate", samplerate, 0);
222
+ rb_define_method(cSndfile, "filename", filename, 0);
223
+ rb_define_method(cSndfile, "channels", channels, 0);
224
+ rb_define_method(cSndfile, "format", format, 0);
225
+
226
+ /*********************************************************
227
+ libxtract
228
+ **********************************************************/
229
+
230
+ mXtract = rb_define_module("Xtract");
231
+ rb_define_singleton_method(mXtract, "analyze", analyze, 2);
232
+ // rb_define_singleton_method(mXtract, "feature_list", feature_list, 0);
233
+
234
+ // Require no arguments
235
+ rb_define_const(mXtract, "MEAN", INT2FIX(XTRACT_MEAN));
236
+ rb_define_const(mXtract, "SHARPNESS", INT2FIX(XTRACT_SHARPNESS));
237
+ rb_define_const(mXtract, "RMS_AMPLITUDE", INT2FIX(XTRACT_RMS_AMPLITUDE));
238
+ rb_define_const(mXtract, "SPECTRAL_CENTROID", INT2FIX(XTRACT_SPECTRAL_CENTROID));
239
+ rb_define_const(mXtract, "POWER", INT2FIX(XTRACT_POWER));
240
+ rb_define_const(mXtract, "ODD_EVEN_RATIO", INT2FIX(XTRACT_ODD_EVEN_RATIO));
241
+ rb_define_const(mXtract, "NONZERO_COUNT", INT2FIX(XTRACT_NONZERO_COUNT));
242
+ rb_define_const(mXtract, "LOUDNESS", INT2FIX(XTRACT_LOUDNESS));
243
+ rb_define_const(mXtract, "IRREGULARITY_K", INT2FIX(XTRACT_IRREGULARITY_K));
244
+ rb_define_const(mXtract, "IRREGULARITY_J", INT2FIX(XTRACT_IRREGULARITY_J));
245
+ rb_define_const(mXtract, "FLATNESS", INT2FIX(XTRACT_FLATNESS));
246
+ rb_define_const(mXtract, "ZCR", INT2FIX(XTRACT_ZCR));
247
+
248
+
249
+ // Require .. ? arguments
250
+ /*
251
+ rb_define_const(mXtract, "VARIANCE", INT2FIX(XTRACT_VARIANCE));
252
+ rb_define_const(mXtract, "STANDARD_DEVIATION", INT2FIX(XTRACT_STANDARD_DEVIATION));
253
+ rb_define_const(mXtract, "AVERAGE_DEVIATION", INT2FIX(XTRACT_AVERAGE_DEVIATION));
254
+ rb_define_const(mXtract, "SKEWNESS", INT2FIX(XTRACT_SKEWNESS));
255
+ rb_define_const(mXtract, "KURTOSIS", INT2FIX(XTRACT_KURTOSIS));
256
+ */
257
+
258
+
259
+ /*
260
+
261
+ XTRACT_KURTOSIS,
262
+ XTRACT_SPECTRAL_MEAN,
263
+ XTRACT_SPECTRAL_VARIANCE,
264
+ XTRACT_SPECTRAL_STANDARD_DEVIATION,
265
+ XTRACT_SPECTRAL_AVERAGE_DEVIATION,
266
+ XTRACT_SPECTRAL_SKEWNESS,
267
+ XTRACT_SPECTRAL_KURTOSIS,
268
+ XTRACT_IRREGULARITY_K,
269
+ XTRACT_IRREGULARITY_J,
270
+ XTRACT_TRISTIMULUS_1,
271
+ XTRACT_TRISTIMULUS_2,
272
+ XTRACT_TRISTIMULUS_3,
273
+ XTRACT_SMOOTHNESS,
274
+ XTRACT_SPREAD,
275
+ XTRACT_ROLLOFF,
276
+ XTRACT_FLATNESS,
277
+ XTRACT_TONALITY,
278
+ XTRACT_CREST,
279
+ XTRACT_NOISINESS,
280
+ XTRACT_SPECTRAL_INHARMONICITY,
281
+ */
282
+
283
+
284
+
285
+
286
+
287
+ /*
288
+ XTRACT_SPECTRAL_SLOPE,
289
+ XTRACT_LOWEST_VALUE,
290
+ XTRACT_HIGHEST_VALUE,
291
+ XTRACT_SUM,
292
+ XTRACT_NONZERO_COUNT,
293
+ XTRACT_HPS,
294
+ XTRACT_F0,
295
+ XTRACT_FAILSAFE_F0,
296
+ XTRACT_FLUX,
297
+ XTRACT_ATTACK_TIME,
298
+ XTRACT_DECAY_TIME,
299
+ XTRACT_DELTA_FEATURE,
300
+ XTRACT_AUTOCORRELATION,
301
+ XTRACT_AMDF,
302
+ XTRACT_ASDF,
303
+ XTRACT_BARK_COEFFICIENTS,
304
+ XTRACT_PEAK_SPECTRUM,
305
+ XTRACT_SPECTRUM,
306
+ XTRACT_AUTOCORRELATION_FFT,
307
+ XTRACT_MFCC,
308
+ XTRACT_DCT,
309
+ XTRACT_HARMONIC_SPECTRUM
310
+ */
311
+
312
+ }
@@ -0,0 +1,5 @@
1
+ require 'lib/sndx/sndx'
2
+
3
+ module Sndx
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,61 @@
1
+ require "test/unit"
2
+
3
+ require 'lib/sndx'
4
+
5
+ class TestSndfile < Test::Unit::TestCase
6
+ def setup
7
+ @file = Sndfile.new("test/assets/48550__gusrikh__Hit_3.wav")
8
+ end
9
+
10
+ def teardown
11
+ @file.close
12
+ end
13
+
14
+ def test_open_file
15
+ assert_not_nil @file
16
+ end
17
+
18
+ def test_frames
19
+ assert_equal 79332, @file.frames
20
+ end
21
+
22
+ def test_samplerate
23
+ assert_equal 44100, @file.samplerate
24
+ end
25
+
26
+ def test_channels
27
+ assert_equal 2, @file.channels
28
+ end
29
+
30
+ def test_format
31
+ assert_equal "Microsoft WAV 16 bit", @file.format
32
+ end
33
+
34
+ def test_read
35
+ sample_data.each_with_index do |data, i|
36
+ assert_equal [data, i], [@file.read(i), i]
37
+ end
38
+ end
39
+
40
+ def sample_data
41
+ [-0.00054931640625,
42
+ -0.000396728515625,
43
+ -0.000396728515625,
44
+ -0.000396728515625,
45
+ -0.00054931640625,
46
+ -0.000701904296875,
47
+ -0.000274658203125,
48
+ -0.000396728515625,
49
+ 0.00054931640625,
50
+ -0.0001220703125]
51
+ end
52
+
53
+ def test_features_zero_args
54
+ [Xtract::MEAN, Xtract::SHARPNESS, Xtract::RMS_AMPLITUDE, Xtract::SPECTRAL_CENTROID,
55
+ Xtract::ODD_EVEN_RATIO, Xtract::NONZERO_COUNT, Xtract::LOUDNESS,
56
+ Xtract::IRREGULARITY_K, Xtract::IRREGULARITY_J, Xtract::FLATNESS, Xtract::ZCR].each do |analysis_code|
57
+ assert_not_equal nil, Xtract.analyze(analysis_code, @file)
58
+ end
59
+ end
60
+
61
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: farleyknight-sndx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Farley Knight
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-18 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: libsndfile + libXtract = Awesome audio analysis library
17
+ email: farleyknight@gmail.com
18
+ executables: []
19
+
20
+ extensions:
21
+ - ext/sndx/extconf.rb
22
+ extra_rdoc_files:
23
+ - README.txt
24
+ files:
25
+ - Manifest.txt
26
+ - README.txt
27
+ - CHANGELOG.txt
28
+ - Rakefile
29
+ - lib/sndx.rb
30
+ - test/test_sndx.rb
31
+ - ext/sndx/sndx.c
32
+ - ext/sndx/extconf.rb
33
+ has_rdoc: false
34
+ homepage: https://github.com/farleyknight/sndx
35
+ licenses:
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 2
59
+ summary: libsndfile + libXtract = Awesome audio analysis library
60
+ test_files: []
61
+