ruby-audio 1.5.0-x86-mingw32 → 1.6.0-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,8 +12,8 @@ else
12
12
  sndfile_lib = 'sndfile'
13
13
  end
14
14
 
15
- INCLUDE_DIRS = ['/opt/local/include', '/usr/local/include', 'C:/Program Files/Mega-Nerd/libsndfile/include', 'C:/Program Files (x86)/Mega-Nerd/libsndfile/include']
16
- LIB_DIRS = ['/opt/local/lib', '/usr/local/lib', 'C:/Program Files/Mega-Nerd/libsndfile', 'C:/Program Files (x86)/Mega-Nerd/libsndfile']
15
+ INCLUDE_DIRS = ['/opt/local/include', '/usr/local/include', 'C:/Program Files (x86)/Mega-Nerd/libsndfile/include', 'C:/Program Files/Mega-Nerd/libsndfile/include']
16
+ LIB_DIRS = ['/opt/local/lib', '/usr/local/lib', 'C:/Program Files (x86)/Mega-Nerd/libsndfile/bin', 'C:/Program Files/Mega-Nerd/libsndfile/bin']
17
17
 
18
18
  # libsndfile requirements
19
19
  find_header 'sndfile.h', *INCLUDE_DIRS
@@ -15,6 +15,7 @@ extern VALUE eRubyAudioError;
15
15
  void Init_ra_buffer() {
16
16
  VALUE mRubyAudio = rb_define_module("RubyAudio");
17
17
  VALUE cRABuffer = rb_define_class_under(mRubyAudio, "CBuffer", rb_cObject);
18
+ rb_include_module(cRABuffer, rb_mEnumerable);
18
19
  rb_define_alloc_func(cRABuffer, ra_buffer_allocate);
19
20
  rb_define_method(cRABuffer, "initialize", ra_buffer_init, -1);
20
21
  rb_define_method(cRABuffer, "initialize_copy", ra_buffer_init_copy, 1);
@@ -23,6 +24,7 @@ void Init_ra_buffer() {
23
24
  rb_define_method(cRABuffer, "real_size", ra_buffer_real_size, 0);
24
25
  rb_define_method(cRABuffer, "real_size=", ra_buffer_real_size_set, 1);
25
26
  rb_define_method(cRABuffer, "type", ra_buffer_type, 0);
27
+ rb_define_method(cRABuffer, "each", ra_buffer_each, 0);
26
28
  rb_define_method(cRABuffer, "[]", ra_buffer_aref, 1);
27
29
  rb_define_method(cRABuffer, "[]=", ra_buffer_aset, 2);
28
30
 
@@ -210,6 +212,27 @@ static VALUE ra_buffer_type(VALUE self) {
210
212
  }
211
213
  }
212
214
 
215
+ /*
216
+ * call-seq:
217
+ * buf.each {|frame| block } => buf
218
+ * buf.each => anEnumerator
219
+ *
220
+ * Iterates through each frame in the buffer. Each frame is either a number or
221
+ * an array of numbers if there are multiple channels.
222
+ */
223
+ static VALUE ra_buffer_each(VALUE self) {
224
+ RA_BUFFER *buf;
225
+ Data_Get_Struct(self, RA_BUFFER, buf);
226
+
227
+ RETURN_ENUMERATOR(self, 0, 0);
228
+
229
+ long i;
230
+ for(i = 0; i < buf->real_size; i++) {
231
+ rb_yield(ra_buffer_aref(self, LONG2FIX(i)));
232
+ }
233
+ return self;
234
+ }
235
+
213
236
  /*
214
237
  * call-seq:
215
238
  * buf[integer] => frame
@@ -32,6 +32,7 @@ static VALUE ra_buffer_size(VALUE self);
32
32
  static VALUE ra_buffer_real_size(VALUE self);
33
33
  static VALUE ra_buffer_real_size_set(VALUE self, VALUE new_real_size);
34
34
  static VALUE ra_buffer_type(VALUE self);
35
+ static VALUE ra_buffer_each(VALUE self);
35
36
  static VALUE ra_buffer_aref(VALUE self, VALUE index);
36
37
  static VALUE ra_buffer_index_get(RA_BUFFER *buf, long i);
37
38
  static VALUE ra_buffer_aset(VALUE self, VALUE index, VALUE val);
@@ -1,6 +1,11 @@
1
1
  #include "ra_sound.h"
2
2
 
3
3
  extern VALUE eRubyAudioError;
4
+ ID id_size;
5
+ ID id_seek;
6
+ ID id_read;
7
+ ID id_write;
8
+ ID id_tell;
4
9
 
5
10
  /*
6
11
  * Class <code>CSound</code> is a very light wrapper around the
@@ -19,6 +24,13 @@ void Init_ra_sound() {
19
24
  rb_define_method(cRASound, "<<", ra_sound_addbuf, 1);
20
25
  rb_define_method(cRASound, "close", ra_sound_close, 0);
21
26
  rb_define_method(cRASound, "closed?", ra_sound_closed, 0);
27
+
28
+ // Get refs to commonly used symbols and ids
29
+ id_size = rb_intern("size");
30
+ id_seek = rb_intern("seek");
31
+ id_read = rb_intern("read");
32
+ id_write = rb_intern("write");
33
+ id_tell = rb_intern("tell");
22
34
  }
23
35
 
24
36
  static VALUE ra_sound_allocate(VALUE klass) {
@@ -31,6 +43,7 @@ static VALUE ra_sound_allocate(VALUE klass) {
31
43
  static void ra_sound_mark(RA_SOUND *snd) {
32
44
  if(snd) {
33
45
  rb_gc_mark(snd->info);
46
+ if(snd->vio_source) rb_gc_mark(snd->vio_source);
34
47
  }
35
48
  }
36
49
 
@@ -56,15 +69,56 @@ static VALUE ra_sound_s_open(int argc, VALUE *argv, VALUE klass) {
56
69
  return rb_ensure(rb_yield, obj, ra_sound_close_safe, obj);
57
70
  }
58
71
 
72
+ static sf_count_t ra_vir_size(void *user_data) {
73
+ VALUE io = (VALUE)user_data;
74
+ return NUM2OFFT(rb_funcall(io, id_size, 0));
75
+ }
76
+
77
+ static sf_count_t ra_vir_seek(sf_count_t offset, int whence, void *user_data) {
78
+ VALUE io = (VALUE)user_data;
79
+ rb_funcall(io, id_seek, 2, OFFT2NUM(offset), INT2FIX(whence));
80
+ return NUM2OFFT(rb_funcall(io, id_tell, 0));
81
+ }
82
+
83
+ static sf_count_t ra_vir_read(void *ptr, sf_count_t count, void *user_data) {
84
+ VALUE io = (VALUE)user_data;
85
+ if(count <= 0) return 0;
86
+
87
+ // It would be nice if we could create a fake buffer string with ptr as the target
88
+ VALUE read = rb_funcall(io, id_read, 1, OFFT2NUM(count));
89
+ sf_count_t len = RSTRING_LEN(read);
90
+ memcpy(ptr, RSTRING_PTR(read), RSTRING_LEN(read));
91
+ return len;
92
+ }
93
+
94
+ static sf_count_t ra_vir_write(const void *ptr, sf_count_t count, void *user_data) {
95
+ VALUE io = (VALUE)user_data;
96
+ if(count <= 0) return 0;
97
+
98
+ // It would be nice if we could create a fake string with ptr as the source
99
+ VALUE str = rb_str_new(ptr, count);
100
+ VALUE wrote = rb_funcall(io, id_write, 1, str);
101
+ return NUM2OFFT(wrote);
102
+ }
103
+
104
+ static sf_count_t ra_vir_tell(void *user_data) {
105
+ VALUE io = (VALUE)user_data;
106
+ return NUM2OFFT(rb_funcall(io, id_tell, 0));
107
+ }
108
+
59
109
  /*
60
110
  * call-seq:
61
111
  * CSound.new(path, mode, info) => snd
112
+ * CSound.new(io, mode, info) => snd
62
113
  *
63
114
  * Returns a new <code>CSound</code> object for the audio file at the given path
64
- * with the given mode. Valid modes are <code>"r"</code>, <code>"w"</code>, or
65
- * <code>"rw"</code>.
115
+ * or using the given fixed-length IO-like object with the given mode. Valid modes
116
+ * are <code>"r"</code>, <code>"w"</code>, or <code>"rw"</code>.
117
+ * <code>StringIO</code> is the only valid IO-like object in the standard library,
118
+ * although any object that implements <code>size</code>, <code>seek</code>,
119
+ * <code>read</code>, <code>write</code>, and <code>tell</code> will work.
66
120
  */
67
- static VALUE ra_sound_init(VALUE self, VALUE path, VALUE mode, VALUE info) {
121
+ static VALUE ra_sound_init(VALUE self, VALUE source, VALUE mode, VALUE info) {
68
122
  RA_SOUND *snd;
69
123
  Data_Get_Struct(self, RA_SOUND, snd);
70
124
 
@@ -79,10 +133,25 @@ static VALUE ra_sound_init(VALUE self, VALUE path, VALUE mode, VALUE info) {
79
133
  snd->info = info;
80
134
 
81
135
  // Open sound file
82
- const char *p = StringValueCStr(path);
83
136
  SF_INFO *sf_info;
84
137
  Data_Get_Struct(info, SF_INFO, sf_info);
85
- snd->snd = sf_open(p, snd->mode, sf_info);
138
+ if(TYPE(source) == T_STRING) {
139
+ // Open sound file at the path
140
+ const char *p = StringValueCStr(source);
141
+ snd->snd = sf_open(p, snd->mode, sf_info);
142
+ } else {
143
+ // Check if the source implements the right methods
144
+ if(!rb_respond_to(source, id_size)) rb_raise(eRubyAudioError, "source does not implement size");
145
+ if(!rb_respond_to(source, id_seek)) rb_raise(eRubyAudioError, "source does not implement seek");
146
+ if(!rb_respond_to(source, id_read)) rb_raise(eRubyAudioError, "source does not implement read");
147
+ if(!rb_respond_to(source, id_write)) rb_raise(eRubyAudioError, "source does not implement write");
148
+ if(!rb_respond_to(source, id_tell)) rb_raise(eRubyAudioError, "source does not implement tell");
149
+
150
+ // Open sound using the virtual IO API
151
+ snd->vio_source = source;
152
+ SF_VIRTUAL_IO vir_io = {ra_vir_size, ra_vir_seek, ra_vir_read, ra_vir_write, ra_vir_tell};
153
+ snd->snd = sf_open_virtual(&vir_io, snd->mode, sf_info, (void*)source);
154
+ }
86
155
  if(snd->snd == NULL) rb_raise(eRubyAudioError, sf_strerror(snd->snd));
87
156
  snd->closed = 0;
88
157
 
@@ -127,241 +196,69 @@ static VALUE ra_sound_seek(VALUE self, VALUE frames, VALUE whence) {
127
196
  return INT2FIX(0);
128
197
  }
129
198
 
130
- static void ra_sound_read_short(RA_SOUND *snd, RA_BUFFER *buf, sf_count_t frames) {
131
- static short temp[1024];
132
- int temp_len = 1024;
133
- short *data = (short*)buf->data;
134
- short mix_sum;
135
-
136
- // Get info struct
137
- SF_INFO *info;
138
- Data_Get_Struct(snd->info, SF_INFO, info);
139
-
140
- // Up/Downmix based on channel matching
141
- sf_count_t read = 0, r, amount;
142
- int i, k;
143
- if(buf->channels == info->channels) { // Simply read data without mix
144
- read = sf_readf_short(snd->snd, data, frames);
145
- } else if(buf->channels == 1) { // Downmix to mono
146
- sf_count_t max = temp_len / info->channels;
147
- int channels;
148
-
149
- while(read < frames) {
150
- // Calculate # of frames to read
151
- amount = frames - read;
152
- if(amount > max) amount = max;
153
-
154
- r = sf_readf_short(snd->snd, temp, amount);
155
- if(r == 0) break;
156
-
157
- // Mix channels together by averaging all channels and store to buffer
158
- for(i = 0; i < r; i++) {
159
- mix_sum = 0;
160
- for(k = 0; k < info->channels; k++) mix_sum += temp[i * info->channels + k];
161
- data[read] = mix_sum/info->channels;
162
- read++;
163
- }
164
- }
165
- } else if(info->channels == 1) { // Upmix from mono by copying channel
166
- while(read < frames) {
167
- // Calculate # of frames to read
168
- amount = frames - read;
169
- if(amount > temp_len) amount = temp_len;
170
-
171
- r = sf_readf_short(snd->snd, temp, amount);
172
- if(r == 0) break;
173
-
174
- // Write every frame channel times to the buffer
175
- for(i = 0; i < r; i++) {
176
- for(k = 0; k < buf->channels; k++) {
177
- data[read * buf->channels + k] = temp[i];
178
- }
179
- read++;
180
- }
181
- }
182
- } else {
183
- rb_raise(eRubyAudioError, "unsupported mix from %d to %d", buf->channels, info->channels);
184
- }
185
-
186
- buf->real_size = read;
187
- }
188
-
189
- static void ra_sound_read_int(RA_SOUND *snd, RA_BUFFER *buf, sf_count_t frames) {
190
- static int temp[1024];
191
- int temp_len = 1024;
192
- int *data = (int*)buf->data;
193
- int mix_sum;
194
-
195
- // Get info struct
196
- SF_INFO *info;
197
- Data_Get_Struct(snd->info, SF_INFO, info);
198
-
199
- // Up/Downmix based on channel matching
200
- sf_count_t read = 0, r, amount;
201
- int i, k;
202
- if(buf->channels == info->channels) { // Simply read data without mix
203
- read = sf_readf_int(snd->snd, data, frames);
204
- } else if(buf->channels == 1) { // Downmix to mono
205
- sf_count_t max = temp_len / info->channels;
206
- int channels;
207
-
208
- while(read < frames) {
209
- // Calculate # of frames to read
210
- amount = frames - read;
211
- if(amount > max) amount = max;
212
-
213
- r = sf_readf_int(snd->snd, temp, amount);
214
- if(r == 0) break;
215
-
216
- // Mix channels together by averaging all channels and store to buffer
217
- for(i = 0; i < r; i++) {
218
- mix_sum = 0;
219
- for(k = 0; k < info->channels; k++) mix_sum += temp[i * info->channels + k];
220
- data[read] = mix_sum/info->channels;
221
- read++;
222
- }
223
- }
224
- } else if(info->channels == 1) { // Upmix from mono by copying channel
225
- while(read < frames) {
226
- // Calculate # of frames to read
227
- amount = frames - read;
228
- if(amount > temp_len) amount = temp_len;
229
-
230
- r = sf_readf_int(snd->snd, temp, amount);
231
- if(r == 0) break;
232
-
233
- // Write every frame channel times to the buffer
234
- for(i = 0; i < r; i++) {
235
- for(k = 0; k < buf->channels; k++) {
236
- data[read * buf->channels + k] = temp[i];
237
- }
238
- read++;
239
- }
240
- }
241
- } else {
242
- rb_raise(eRubyAudioError, "unsupported mix from %d to %d", buf->channels, info->channels);
243
- }
244
-
245
- buf->real_size = read;
246
- }
247
-
248
- static void ra_sound_read_float(RA_SOUND *snd, RA_BUFFER *buf, sf_count_t frames) {
249
- static float temp[1024];
250
- int temp_len = 1024;
251
- float *data = (float*)buf->data;
252
- float mix_sum;
253
-
254
- // Get info struct
255
- SF_INFO *info;
256
- Data_Get_Struct(snd->info, SF_INFO, info);
257
-
258
- // Up/Downmix based on channel matching
259
- sf_count_t read = 0, r, amount;
260
- int i, k;
261
- if(buf->channels == info->channels) { // Simply read data without mix
262
- read = sf_readf_float(snd->snd, data, frames);
263
- } else if(buf->channels == 1) { // Downmix to mono
264
- sf_count_t max = temp_len / info->channels;
265
- int channels;
266
-
267
- while(read < frames) {
268
- // Calculate # of frames to read
269
- amount = frames - read;
270
- if(amount > max) amount = max;
271
-
272
- r = sf_readf_float(snd->snd, temp, amount);
273
- if(r == 0) break;
274
-
275
- // Mix channels together by averaging all channels and store to buffer
276
- for(i = 0; i < r; i++) {
277
- mix_sum = 0;
278
- for(k = 0; k < info->channels; k++) mix_sum += temp[i * info->channels + k];
279
- data[read] = mix_sum/info->channels;
280
- read++;
281
- }
282
- }
283
- } else if(info->channels == 1) { // Upmix from mono by copying channel
284
- while(read < frames) {
285
- // Calculate # of frames to read
286
- amount = frames - read;
287
- if(amount > temp_len) amount = temp_len;
288
-
289
- r = sf_readf_float(snd->snd, temp, amount);
290
- if(r == 0) break;
291
-
292
- // Write every frame channel times to the buffer
293
- for(i = 0; i < r; i++) {
294
- for(k = 0; k < buf->channels; k++) {
295
- data[read * buf->channels + k] = temp[i];
296
- }
297
- read++;
298
- }
299
- }
300
- } else {
301
- rb_raise(eRubyAudioError, "unsupported mix from %d to %d", buf->channels, info->channels);
302
- }
303
-
304
- buf->real_size = read;
305
- }
306
-
307
- static void ra_sound_read_double(RA_SOUND *snd, RA_BUFFER *buf, sf_count_t frames) {
308
- static double temp[1024];
309
- int temp_len = 1024;
310
- double *data = (double*)buf->data;
311
- double mix_sum;
312
-
313
- // Get info struct
314
- SF_INFO *info;
315
- Data_Get_Struct(snd->info, SF_INFO, info);
316
-
317
- // Up/Downmix based on channel matching
318
- sf_count_t read = 0, r, amount;
319
- int i, k;
320
- if(buf->channels == info->channels) { // Simply read data without mix
321
- read = sf_readf_double(snd->snd, data, frames);
322
- } else if(buf->channels == 1) { // Downmix to mono
323
- sf_count_t max = temp_len / info->channels;
324
- int channels;
325
-
326
- while(read < frames) {
327
- // Calculate # of frames to read
328
- amount = frames - read;
329
- if(amount > max) amount = max;
330
-
331
- r = sf_readf_double(snd->snd, temp, amount);
332
- if(r == 0) break;
333
-
334
- // Mix channels together by averaging all channels and store to buffer
335
- for(i = 0; i < r; i++) {
336
- mix_sum = 0;
337
- for(k = 0; k < info->channels; k++) mix_sum += temp[i * info->channels + k];
338
- data[read] = mix_sum/info->channels;
339
- read++;
340
- }
341
- }
342
- } else if(info->channels == 1) { // Upmix from mono by copying channel
343
- while(read < frames) {
344
- // Calculate # of frames to read
345
- amount = frames - read;
346
- if(amount > temp_len) amount = temp_len;
347
-
348
- r = sf_readf_double(snd->snd, temp, amount);
349
- if(r == 0) break;
350
-
351
- // Write every frame channel times to the buffer
352
- for(i = 0; i < r; i++) {
353
- for(k = 0; k < buf->channels; k++) {
354
- data[read * buf->channels + k] = temp[i];
355
- }
356
- read++;
357
- }
358
- }
359
- } else {
360
- rb_raise(eRubyAudioError, "unsupported mix from %d to %d", buf->channels, info->channels);
361
- }
362
-
363
- buf->real_size = read;
199
+ #define DEFINE_RA_SOUND_READ_TYPE(itype) \
200
+ static void ra_sound_read_##itype(RA_SOUND *snd, RA_BUFFER *buf, sf_count_t frames) { \
201
+ static itype temp[1024]; \
202
+ int temp_len = 1024; \
203
+ itype *data = (itype*)buf->data; \
204
+ itype mix_sum; \
205
+ \
206
+ /* Get info struct */ \
207
+ SF_INFO *info; \
208
+ Data_Get_Struct(snd->info, SF_INFO, info); \
209
+ \
210
+ /* Up/Downmix based on channel matching */ \
211
+ sf_count_t read = 0, r, amount; \
212
+ int i, k; \
213
+ if(buf->channels == info->channels) { /* Simply read data without mix */ \
214
+ read = sf_readf_##itype(snd->snd, data, frames); \
215
+ } else if(buf->channels == 1) { /* Downmix to mono */ \
216
+ sf_count_t max = temp_len / info->channels; \
217
+ int channels; \
218
+ \
219
+ while(read < frames) { \
220
+ /* Calculate # of frames to read */ \
221
+ amount = frames - read; \
222
+ if(amount > max) amount = max; \
223
+ \
224
+ r = sf_readf_##itype(snd->snd, temp, amount); \
225
+ if(r == 0) break; \
226
+ \
227
+ /* Mix channels together by averaging all channels and store to buffer */ \
228
+ for(i = 0; i < r; i++) { \
229
+ mix_sum = 0; \
230
+ for(k = 0; k < info->channels; k++) mix_sum += temp[i * info->channels + k]; \
231
+ data[read] = mix_sum/info->channels; \
232
+ read++; \
233
+ } \
234
+ } \
235
+ } else if(info->channels == 1) { /* Upmix from mono by copying channel */ \
236
+ while(read < frames) { \
237
+ /* Calculate # of frames to read */ \
238
+ amount = frames - read; \
239
+ if(amount > temp_len) amount = temp_len; \
240
+ \
241
+ r = sf_readf_##itype(snd->snd, temp, amount); \
242
+ if(r == 0) break; \
243
+ \
244
+ /* Write every frame channel times to the buffer */ \
245
+ for(i = 0; i < r; i++) { \
246
+ for(k = 0; k < buf->channels; k++) { \
247
+ data[read * buf->channels + k] = temp[i]; \
248
+ } \
249
+ read++; \
250
+ } \
251
+ } \
252
+ } else { \
253
+ rb_raise(eRubyAudioError, "unsupported mix from %d to %d", buf->channels, info->channels); \
254
+ } \
255
+ \
256
+ buf->real_size = read; \
364
257
  }
258
+ DEFINE_RA_SOUND_READ_TYPE(short);
259
+ DEFINE_RA_SOUND_READ_TYPE(int);
260
+ DEFINE_RA_SOUND_READ_TYPE(float);
261
+ DEFINE_RA_SOUND_READ_TYPE(double);
365
262
 
366
263
  /*
367
264
  * call-seq:
@@ -9,6 +9,7 @@
9
9
  typedef struct {
10
10
  SNDFILE *snd;
11
11
  VALUE info;
12
+ VALUE vio_source;
12
13
  int mode;
13
14
  int closed;
14
15
  } RA_SOUND;
Binary file
Binary file
@@ -10,14 +10,6 @@ module RubyAudio
10
10
  # buf = RubyAudio::Buffer.float(1000)
11
11
  # buf = RubyAudio::Buffer.new("float", 1000, 1)
12
12
  class Buffer < CBuffer
13
- include Enumerable
14
-
15
- def each
16
- self.size.times do |i|
17
- yield self[i]
18
- end
19
- end
20
-
21
13
  [:short, :int, :float, :double].each do |type|
22
14
  eval "def self.#{type}(frames, channels=1); self.new(:#{type}, frames, channels); end"
23
15
  end
@@ -24,7 +24,7 @@ module RubyAudio
24
24
  end
25
25
  end
26
26
 
27
- # Returns a new <code>SoundInfo</code> object that is has the same channel
27
+ # Returns a new <code>SoundInfo</code> object that has the same channel
28
28
  # count, sample rate, and format. This is useful in creating a new sound with
29
29
  # the same format as an already existing sound.
30
30
  #
@@ -37,16 +37,33 @@ module RubyAudio
37
37
 
38
38
  alias_method :seekable?, :seekable
39
39
 
40
+ # Returns the main format constant as a string
41
+ #
42
+ # Example:
43
+ # info = RubyAudio::SoundInfo.new :channels => 1, :samplerate => 48000, :format => RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
44
+ # info.main_format
45
+ # #=> "FORMAT_WAV"
40
46
  def main_format
41
47
  calculate_format if @main_format.nil?
42
48
  @main_format
43
49
  end
44
50
 
51
+ # Returns the sub format constant as a string
52
+ #
53
+ # Example:
54
+ # info = RubyAudio::SoundInfo.new :channels => 1, :samplerate => 48000, :format => RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
55
+ # info.sub_format
56
+ # #=> "FORMAT_PCM_16"
45
57
  def sub_format
46
58
  calculate_format if @sub_format.nil?
47
59
  @sub_format
48
60
  end
49
61
 
62
+ # Returns the length of the audio file in seconds
63
+ def length
64
+ frames / samplerate.to_f
65
+ end
66
+
50
67
  private
51
68
  def calculate_format
52
69
  RubyAudio.constants.grep(/FORMAT_/).map(&:to_s).each do |f|
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'ruby-audio'
5
- s.version = '1.5.0'
5
+ s.version = '1.6.0'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ['Stephen Augenstein']
8
8
  s.email = ['perl.programmer@gmail.com']
@@ -78,11 +78,16 @@ describe RubyAudio::Buffer do
78
78
  end
79
79
 
80
80
  it "shouldn't do anything on an empty buffer" do
81
- buf = RubyAudio::Buffer.int(0, 2)
81
+ buf = RubyAudio::Buffer.int(50, 2)
82
82
 
83
83
  buf.each do
84
84
  fail "This shouldn't be executed"
85
85
  end
86
86
  end
87
+
88
+ it "should support usage through returned enumerable" do
89
+ enum = @buf.each
90
+ enum.any? {|frame| frame[0] == 5}.should == true
91
+ end
87
92
  end
88
93
  end
@@ -46,4 +46,10 @@ describe RubyAudio::SoundInfo do
46
46
  info.main_format.should == "FORMAT_WAVEX"
47
47
  info.sub_format.should == "FORMAT_MS_ADPCM"
48
48
  end
49
+
50
+ it "should return the length of an audio file" do
51
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
52
+ snd.info.length.should == 26413 / 16000.0
53
+ end
54
+ end
49
55
  end
@@ -1,30 +1,31 @@
1
1
  require "spec_helper.rb"
2
2
 
3
3
  describe RubyAudio::Sound do
4
- MONO_TEST_WAV = File.dirname(__FILE__)+'/data/what.wav'
5
- STEREO_TEST_WAV = File.dirname(__FILE__)+'/data/what2.wav'
6
- TEST_MP3 = File.dirname(__FILE__)+'/data/what.mp3'
7
- OUT_WAV = File.dirname(__FILE__)+'/data/temp.wav'
8
-
9
4
  after :each do
10
- File.delete(OUT_WAV) if File.exists?(OUT_WAV)
5
+ File.delete(fixture('temp.wav')) if File.exists?(fixture('temp.wav'))
11
6
  end
12
7
 
13
8
  it "should open a standard wav without issues" do
14
9
  lambda {
15
- RubyAudio::Sound.open(MONO_TEST_WAV)
10
+ RubyAudio::Sound.open(fixture('what.wav'))
11
+ }.should_not raise_error
12
+ end
13
+
14
+ it "should open an IO conformer without issues" do
15
+ lambda {
16
+ RubyAudio::Sound.open(io_fixture('what.wav'))
16
17
  }.should_not raise_error
17
18
  end
18
19
 
19
20
  it "should raise an exception if the mode is invalid" do
20
21
  lambda {
21
- RubyAudio::Sound.open(MONO_TEST_WAV, 'q')
22
+ RubyAudio::Sound.open(fixture('what.wav'), 'q')
22
23
  }.should raise_error(ArgumentError, 'invalid access mode q')
23
24
  end
24
25
 
25
26
  it "should close the sound on block exit" do
26
27
  s = nil
27
- RubyAudio::Sound.open(MONO_TEST_WAV) do |snd|
28
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
28
29
  snd.closed?.should be_false
29
30
  s = snd
30
31
  end
@@ -33,18 +34,18 @@ describe RubyAudio::Sound do
33
34
 
34
35
  it "should raise an exception for an unsupported file" do
35
36
  lambda {
36
- RubyAudio::Sound.open(TEST_MP3)
37
+ RubyAudio::Sound.open(fixture('what.mp3'))
37
38
  }.should raise_error(RubyAudio::Error, "File contains data in an unknown format.")
38
39
  end
39
40
 
40
41
  it "should raise an exception if file does not exist" do
41
42
  lambda {
42
- RubyAudio::Sound.open(TEST_MP3+'.not')
43
+ RubyAudio::Sound.open(fixture('what.mp3')+'.not')
43
44
  }.should raise_error(RubyAudio::Error, "System error : No such file or directory.")
44
45
  end
45
46
 
46
47
  it "should have the proper sound info" do
47
- RubyAudio::Sound.open(MONO_TEST_WAV) do |snd|
48
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
48
49
  snd.info.channels.should == 1
49
50
  snd.info.samplerate.should == 16000
50
51
  snd.info.format.should == RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
@@ -53,7 +54,17 @@ describe RubyAudio::Sound do
53
54
 
54
55
  it "should allow seeking" do
55
56
  lambda {
56
- RubyAudio::Sound.open(MONO_TEST_WAV) do |snd|
57
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
58
+ snd.seek(100)
59
+ buf = snd.read(:float, 100)
60
+ buf[0].should > 0
61
+ end
62
+ }.should_not raise_error
63
+ end
64
+
65
+ it "should allow seeking in IO conformers" do
66
+ lambda {
67
+ RubyAudio::Sound.open(io_fixture('what.wav')) do |snd|
57
68
  snd.seek(100)
58
69
  buf = snd.read(:float, 100)
59
70
  buf[0].should > 0
@@ -63,15 +74,24 @@ describe RubyAudio::Sound do
63
74
 
64
75
  it "should raise exceptions for invalid seeks" do
65
76
  lambda {
66
- RubyAudio::Sound.open(MONO_TEST_WAV) {|snd| snd.seek(-1)}
77
+ RubyAudio::Sound.open(fixture('what.wav')) {|snd| snd.seek(-1)}
67
78
  }.should raise_error(RubyAudio::Error, "invalid seek")
68
79
  lambda {
69
- RubyAudio::Sound.open(MONO_TEST_WAV) {|snd| snd.seek(1000000)}
80
+ RubyAudio::Sound.open(fixture('what.wav')) {|snd| snd.seek(1000000)}
70
81
  }.should raise_error(RubyAudio::Error, "invalid seek")
71
82
  end
72
83
 
73
84
  it "should allow reading samples from the sound" do
74
- RubyAudio::Sound.open(STEREO_TEST_WAV) do |snd|
85
+ RubyAudio::Sound.open(fixture('what2.wav')) do |snd|
86
+ buf = snd.read(:float, 1000)
87
+ buf.size.should == 1000
88
+ buf.real_size.should == 1000
89
+ buf[999].length.should == 2
90
+ end
91
+ end
92
+
93
+ it "should allow reading samples from IO conformers" do
94
+ RubyAudio::Sound.open(io_fixture('what2.wav')) do |snd|
75
95
  buf = snd.read(:float, 1000)
76
96
  buf.size.should == 1000
77
97
  buf.real_size.should == 1000
@@ -82,7 +102,7 @@ describe RubyAudio::Sound do
82
102
  it "should allow reading into an existing buffer" do
83
103
  buf = RubyAudio::Buffer.float(1000)
84
104
  buf.real_size.should == 0
85
- RubyAudio::Sound.open(MONO_TEST_WAV) do |snd|
105
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
86
106
  snd.read(buf)
87
107
  end
88
108
  buf.real_size.should == 1000
@@ -92,7 +112,7 @@ describe RubyAudio::Sound do
92
112
  it "should allow reading into an existing buffer partially" do
93
113
  buf = RubyAudio::Buffer.float(1000)
94
114
  buf.real_size.should == 0
95
- RubyAudio::Sound.open(MONO_TEST_WAV) do |snd|
115
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
96
116
  snd.read(buf, 100)
97
117
  end
98
118
  buf.real_size.should == 100
@@ -103,7 +123,7 @@ describe RubyAudio::Sound do
103
123
  it "should allow downmixing to mono on read" do
104
124
  buf = RubyAudio::Buffer.int(100, 1)
105
125
  buf2 = RubyAudio::Buffer.int(100, 2)
106
- RubyAudio::Sound.open(STEREO_TEST_WAV, 'r') do |snd|
126
+ RubyAudio::Sound.open(fixture('what2.wav'), 'r') do |snd|
107
127
  snd.read(buf)
108
128
  snd.seek(0)
109
129
  snd.read(buf2)
@@ -116,7 +136,7 @@ describe RubyAudio::Sound do
116
136
  it "should allow upmixing from mono on read" do
117
137
  buf = RubyAudio::Buffer.int(100, 1)
118
138
  buf2 = RubyAudio::Buffer.int(100, 2)
119
- RubyAudio::Sound.open(STEREO_TEST_WAV, 'r') do |snd|
139
+ RubyAudio::Sound.open(fixture('what2.wav'), 'r') do |snd|
120
140
  snd.read(buf2)
121
141
  snd.seek(0)
122
142
  snd.read(buf)
@@ -128,7 +148,7 @@ describe RubyAudio::Sound do
128
148
  it "should fail read on unsupported up/downmixing" do
129
149
  buf = RubyAudio::Buffer.float(100, 5)
130
150
  lambda {
131
- RubyAudio::Sound.open(STEREO_TEST_WAV) do |snd|
151
+ RubyAudio::Sound.open(fixture('what2.wav')) do |snd|
132
152
  snd.read(buf)
133
153
  end
134
154
  }.should raise_error(RubyAudio::Error, "unsupported mix from 5 to 2")
@@ -138,12 +158,30 @@ describe RubyAudio::Sound do
138
158
  in_buf = RubyAudio::Buffer.float(100)
139
159
  out_buf = RubyAudio::Buffer.float(100)
140
160
  out_info = nil
141
- RubyAudio::Sound.open(MONO_TEST_WAV) do |snd|
161
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
162
+ snd.read(in_buf)
163
+ out_info = snd.info.clone
164
+ end
165
+
166
+ RubyAudio::Sound.open(fixture('temp.wav'), 'rw', out_info) do |snd|
167
+ snd.write(in_buf)
168
+ snd.seek(0)
169
+ snd.read(out_buf)
170
+ end
171
+
172
+ out_buf[50].should == in_buf[50]
173
+ end
174
+
175
+ it "should allow writing to an IO conformer" do
176
+ in_buf = RubyAudio::Buffer.float(100)
177
+ out_buf = RubyAudio::Buffer.float(100)
178
+ out_info = nil
179
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
142
180
  snd.read(in_buf)
143
181
  out_info = snd.info.clone
144
182
  end
145
183
 
146
- RubyAudio::Sound.open(OUT_WAV, 'rw', out_info) do |snd|
184
+ RubyAudio::Sound.open(io_fixture, 'rw', out_info) do |snd|
147
185
  snd.write(in_buf)
148
186
  snd.seek(0)
149
187
  snd.read(out_buf)
@@ -156,12 +194,12 @@ describe RubyAudio::Sound do
156
194
  in_buf = RubyAudio::Buffer.float(100)
157
195
  out_buf = RubyAudio::Buffer.float(100)
158
196
  out_info = nil
159
- RubyAudio::Sound.open(MONO_TEST_WAV) do |snd|
197
+ RubyAudio::Sound.open(fixture('what.wav')) do |snd|
160
198
  snd.read(in_buf)
161
199
  out_info = snd.info.clone
162
200
  end
163
201
 
164
- RubyAudio::Sound.open(OUT_WAV, 'rw', out_info) do |snd|
202
+ RubyAudio::Sound.open(fixture('temp.wav'), 'rw', out_info) do |snd|
165
203
  snd << in_buf
166
204
  snd.seek(0)
167
205
  snd.read(out_buf)
@@ -174,7 +212,7 @@ describe RubyAudio::Sound do
174
212
  buf = RubyAudio::Buffer.float(100, 5)
175
213
  info = RubyAudio::SoundInfo.new :channels => 2, :samplerate => 48000, :format => RubyAudio::FORMAT_WAV|RubyAudio::FORMAT_PCM_16
176
214
  lambda {
177
- RubyAudio::Sound.open(OUT_WAV, 'w', info) do |snd|
215
+ RubyAudio::Sound.open(fixture('temp.wav'), 'w', info) do |snd|
178
216
  snd.write(buf)
179
217
  end
180
218
  }.should raise_error(RubyAudio::Error, "channel count mismatch: 5 vs 2")
@@ -8,4 +8,17 @@ end
8
8
  require 'spec/autorun'
9
9
 
10
10
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
- require 'ruby-audio'
11
+ require 'ruby-audio'
12
+
13
+ def fixture file_name
14
+ File.join(File.dirname(__FILE__), 'data', file_name)
15
+ end
16
+
17
+ def io_fixture file_name=nil
18
+ if file_name
19
+ path = fixture(file_name)
20
+ StringIO.new(File.read(path))
21
+ else
22
+ StringIO.new
23
+ end
24
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-audio
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
- - 5
7
+ - 6
9
8
  - 0
10
- version: 1.5.0
9
+ version: 1.6.0
11
10
  platform: x86-mingw32
12
11
  authors:
13
12
  - Stephen Augenstein
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-07-06 00:00:00 -04:00
17
+ date: 2011-11-19 00:00:00 -05:00
19
18
  default_executable:
20
19
  dependencies: []
21
20
 
@@ -71,27 +70,23 @@ rdoc_options:
71
70
  require_paths:
72
71
  - lib
73
72
  required_ruby_version: !ruby/object:Gem::Requirement
74
- none: false
75
73
  requirements:
76
74
  - - ">="
77
75
  - !ruby/object:Gem::Version
78
- hash: 3
79
76
  segments:
80
77
  - 0
81
78
  version: "0"
82
79
  required_rubygems_version: !ruby/object:Gem::Requirement
83
- none: false
84
80
  requirements:
85
81
  - - ">="
86
82
  - !ruby/object:Gem::Version
87
- hash: 3
88
83
  segments:
89
84
  - 0
90
85
  version: "0"
91
86
  requirements:
92
87
  - libsndfile (http://www.mega-nerd.com/libsndfile/)
93
88
  rubyforge_project:
94
- rubygems_version: 1.3.7
89
+ rubygems_version: 1.3.6
95
90
  signing_key:
96
91
  specification_version: 3
97
92
  summary: libsndfile wrapper for ruby