ruby-audio-heroku 1.6.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,342 @@
1
+ #include "ra_buffer.h"
2
+
3
+ ID ra_short_sym, ra_int_sym, ra_float_sym, ra_double_sym;
4
+ extern VALUE eRubyAudioError;
5
+
6
+ // Before RFLOAT_VALUE, value was in a different place in the struct
7
+ #ifndef RFLOAT_VALUE
8
+ #define RFLOAT_VALUE(v) (RFLOAT(v)->value)
9
+ #endif
10
+
11
+ /*
12
+ * Class <code>CBuffer</code> is a very light wrapper around a standard C array
13
+ * that can be read from and written to by libsndfile.
14
+ */
15
+ void Init_ra_buffer() {
16
+ VALUE mRubyAudio = rb_define_module("RubyAudio");
17
+ VALUE cRABuffer = rb_define_class_under(mRubyAudio, "CBuffer", rb_cObject);
18
+ rb_include_module(cRABuffer, rb_mEnumerable);
19
+ rb_define_alloc_func(cRABuffer, ra_buffer_allocate);
20
+ rb_define_method(cRABuffer, "initialize", ra_buffer_init, -1);
21
+ rb_define_method(cRABuffer, "initialize_copy", ra_buffer_init_copy, 1);
22
+ rb_define_method(cRABuffer, "channels", ra_buffer_channels, 0);
23
+ rb_define_method(cRABuffer, "size", ra_buffer_size, 0);
24
+ rb_define_method(cRABuffer, "real_size", ra_buffer_real_size, 0);
25
+ rb_define_method(cRABuffer, "real_size=", ra_buffer_real_size_set, 1);
26
+ rb_define_method(cRABuffer, "type", ra_buffer_type, 0);
27
+ rb_define_method(cRABuffer, "each", ra_buffer_each, 0);
28
+ rb_define_method(cRABuffer, "[]", ra_buffer_aref, 1);
29
+ rb_define_method(cRABuffer, "[]=", ra_buffer_aset, 2);
30
+
31
+ ra_short_sym = rb_intern("short");
32
+ ra_int_sym = rb_intern("int");
33
+ ra_float_sym = rb_intern("float");
34
+ ra_double_sym = rb_intern("double");
35
+ }
36
+
37
+ static VALUE ra_buffer_allocate(VALUE klass) {
38
+ RA_BUFFER *buf = ALLOC(RA_BUFFER);
39
+ memset(buf, 0, sizeof(RA_BUFFER));
40
+ VALUE self = Data_Wrap_Struct(klass, NULL, ra_buffer_free, buf);
41
+ return self;
42
+ }
43
+
44
+ static void ra_buffer_free(RA_BUFFER *buf) {
45
+ if(buf->data != NULL) xfree(buf->data);
46
+ xfree(buf);
47
+ }
48
+
49
+ /*
50
+ * Uses size, channels, and type to allocate a properly sized array and set data
51
+ * to the pointer for that data. Returns size.
52
+ */
53
+ static long ra_buffer_alloc_data(RA_BUFFER *buf) {
54
+ long size = 0;
55
+ switch(buf->type) {
56
+ case RA_BUFFER_TYPE_SHORT:
57
+ size = sizeof(short) * buf->size * buf->channels;
58
+ break;
59
+ case RA_BUFFER_TYPE_INT:
60
+ size = sizeof(int) * buf->size * buf->channels;
61
+ break;
62
+ case RA_BUFFER_TYPE_FLOAT:
63
+ size = sizeof(float) * buf->size * buf->channels;
64
+ break;
65
+ case RA_BUFFER_TYPE_DOUBLE:
66
+ size = sizeof(double) * buf->size * buf->channels;
67
+ break;
68
+ }
69
+ buf->data = (void*)xmalloc(size);
70
+ memset(buf->data, 0, size);
71
+ return size;
72
+ }
73
+
74
+ /*
75
+ * call-seq:
76
+ * RubyAudio::CBuffer.new(type, size, channels=1) => buf
77
+ *
78
+ * Returns a new <code>CBuffer</code> object which can contain the given number
79
+ * of audio frames of the given data type.
80
+ *
81
+ * buf = RubyAudio::CBuffer.new("float", 1000)
82
+ */
83
+ static VALUE ra_buffer_init(int argc, VALUE *argv, VALUE self) {
84
+ RA_BUFFER *buf;
85
+ Data_Get_Struct(self, RA_BUFFER, buf);
86
+
87
+ // Check args
88
+ if(argc < 2) rb_raise(rb_eArgError, "At least 2 arguments required");
89
+
90
+ // Get type of object
91
+ const char *buf_type;
92
+ switch(TYPE(argv[0])) {
93
+ case T_SYMBOL:
94
+ buf_type = rb_id2name(SYM2ID(argv[0]));
95
+ if(!buf_type) rb_raise(rb_eArgError, "bad type");
96
+ break;
97
+ case T_STRING:
98
+ buf_type = RSTRING_PTR(argv[0]);
99
+ break;
100
+ default:
101
+ rb_raise(rb_eArgError, "bad type");
102
+ break;
103
+ }
104
+
105
+ // Populate channels
106
+ buf->channels = (argc == 3) ? FIX2INT(argv[2]) : 1;
107
+
108
+ // Allocate data array based on type
109
+ buf->size = FIX2LONG(argv[1]);
110
+ buf->real_size = 0;
111
+ if(strcmp(buf_type, "short") == 0) buf->type = RA_BUFFER_TYPE_SHORT;
112
+ else if(strcmp(buf_type, "int") == 0) buf->type = RA_BUFFER_TYPE_INT;
113
+ else if(strcmp(buf_type, "float") == 0) buf->type = RA_BUFFER_TYPE_FLOAT;
114
+ else if(strcmp(buf_type, "double") == 0) buf->type = RA_BUFFER_TYPE_DOUBLE;
115
+ else rb_raise(rb_eArgError, "Invalid type: %s", buf_type);
116
+ ra_buffer_alloc_data(buf);
117
+
118
+ // Return self
119
+ return self;
120
+ }
121
+
122
+ /* :nodoc: */
123
+ static VALUE ra_buffer_init_copy(VALUE copy, VALUE buf) {
124
+ if (copy == buf) return copy;
125
+
126
+ // Checks
127
+ rb_check_frozen(copy);
128
+ if (!rb_obj_is_instance_of(buf, rb_obj_class(copy))) {
129
+ rb_raise(rb_eTypeError, "wrong argument class");
130
+ }
131
+
132
+ RA_BUFFER *copy_struct, *buf_struct;
133
+ Data_Get_Struct(copy, RA_BUFFER, copy_struct);
134
+ Data_Get_Struct(buf, RA_BUFFER, buf_struct);
135
+
136
+ // Clone data
137
+ memcpy(copy_struct, buf_struct, sizeof(RA_BUFFER));
138
+ long size = ra_buffer_alloc_data(copy_struct);
139
+ memcpy(copy_struct->data, buf_struct->data, size);
140
+
141
+ return copy;
142
+ }
143
+
144
+ /*
145
+ * call-seq:
146
+ * buf.channels => integer
147
+ *
148
+ * Returns the number of channels in a frame of the buffer.
149
+ */
150
+ static VALUE ra_buffer_channels(VALUE self) {
151
+ RA_BUFFER *buf;
152
+ Data_Get_Struct(self, RA_BUFFER, buf);
153
+ return INT2FIX(buf->channels);
154
+ }
155
+
156
+ /*
157
+ * call-seq:
158
+ * buf.size => integer
159
+ *
160
+ * Returns the number of frames the buffer can store.
161
+ */
162
+ static VALUE ra_buffer_size(VALUE self) {
163
+ RA_BUFFER *buf;
164
+ Data_Get_Struct(self, RA_BUFFER, buf);
165
+ return LONG2FIX(buf->size);
166
+ }
167
+
168
+ /*
169
+ * call-seq:
170
+ * buf.real_size => integer
171
+ *
172
+ * Returns the number of frames of actual data are currently stored in the
173
+ * buffer.
174
+ */
175
+ static VALUE ra_buffer_real_size(VALUE self) {
176
+ RA_BUFFER *buf;
177
+ Data_Get_Struct(self, RA_BUFFER, buf);
178
+ return LONG2FIX(buf->real_size);
179
+ }
180
+
181
+ /*:nodoc:*/
182
+ static VALUE ra_buffer_real_size_set(VALUE self, VALUE real_size) {
183
+ RA_BUFFER *buf;
184
+ Data_Get_Struct(self, RA_BUFFER, buf);
185
+
186
+ long new_real_size = FIX2LONG(real_size);
187
+ if(new_real_size > buf->size) {
188
+ buf->real_size = buf->size;
189
+ } else if(new_real_size < 0) {
190
+ buf->real_size = 0;
191
+ } else {
192
+ buf->real_size = new_real_size;
193
+ }
194
+
195
+ return LONG2FIX(buf->real_size);
196
+ }
197
+
198
+ /*
199
+ * call-seq:
200
+ * buf.type => symbol
201
+ *
202
+ * Returns the type of audio data being stored. <code>:short</code>,
203
+ * <code>:int</code>, <code>:float</code>, or <code>:double</code>.
204
+ */
205
+ static VALUE ra_buffer_type(VALUE self) {
206
+ RA_BUFFER *buf;
207
+ Data_Get_Struct(self, RA_BUFFER, buf);
208
+ switch(buf->type) {
209
+ case RA_BUFFER_TYPE_SHORT: return ID2SYM(ra_short_sym);
210
+ case RA_BUFFER_TYPE_INT: return ID2SYM(ra_int_sym);
211
+ case RA_BUFFER_TYPE_FLOAT: return ID2SYM(ra_float_sym);
212
+ case RA_BUFFER_TYPE_DOUBLE: return ID2SYM(ra_double_sym);
213
+ }
214
+ }
215
+
216
+ /*
217
+ * call-seq:
218
+ * buf.each {|frame| block } => buf
219
+ * buf.each => anEnumerator
220
+ *
221
+ * Iterates through each frame in the buffer. Each frame is either a number or
222
+ * an array of numbers if there are multiple channels.
223
+ */
224
+ static VALUE ra_buffer_each(VALUE self) {
225
+ RA_BUFFER *buf;
226
+ Data_Get_Struct(self, RA_BUFFER, buf);
227
+
228
+ RETURN_ENUMERATOR(self, 0, 0);
229
+
230
+ long i;
231
+ for(i = 0; i < buf->real_size; i++) {
232
+ rb_yield(ra_buffer_aref(self, LONG2FIX(i)));
233
+ }
234
+ return self;
235
+ }
236
+
237
+ /*
238
+ * call-seq:
239
+ * buf[integer] => frame
240
+ *
241
+ * Returns a frame of audio data at the given offset.
242
+ *
243
+ * buf = snd.read(:float, 100) # Mono sound
244
+ * buf[5] #=> 0.4
245
+ *
246
+ * buf2 = snd2.read(:float, 100) # Stereo sound
247
+ * buf[5] #=> [0.4, 0.3]
248
+ */
249
+ static VALUE ra_buffer_aref(VALUE self, VALUE index) {
250
+ RA_BUFFER *buf;
251
+ Data_Get_Struct(self, RA_BUFFER, buf);
252
+
253
+ // Bounds check
254
+ long f = FIX2LONG(index);
255
+ if(f < 0 || f >= buf->real_size) return Qnil;
256
+ long i = f * buf->channels;
257
+
258
+ if(buf->channels == 1) {
259
+ return ra_buffer_index_get(buf, i);
260
+ } else {
261
+ VALUE frame = rb_ary_new();
262
+ long j;
263
+ for(j = 0; j < buf->channels; j++) {
264
+ rb_ary_push(frame, ra_buffer_index_get(buf, i+j));
265
+ }
266
+ return frame;
267
+ }
268
+ }
269
+
270
+ static VALUE ra_buffer_index_get(RA_BUFFER *buf, long i) {
271
+ switch(buf->type) {
272
+ case RA_BUFFER_TYPE_SHORT: return INT2FIX((int)((short*)buf->data)[i]);
273
+ case RA_BUFFER_TYPE_INT: return INT2FIX(((int*)buf->data)[i]);
274
+ case RA_BUFFER_TYPE_FLOAT: return rb_float_new((double)((float*)buf->data)[i]);
275
+ case RA_BUFFER_TYPE_DOUBLE: return rb_float_new(((double*)buf->data)[i]);
276
+ }
277
+ }
278
+
279
+ /*
280
+ * call-seq:
281
+ * buf[integer] = numeric => numeric
282
+ * buf[integer] = array => array
283
+ *
284
+ * Sets the frame of audio data at the given offset to the value. For
285
+ * multi-channel audio, pass in an array of values.
286
+ *
287
+ * buf = RubyAudio::Buffer.int(100, 1)
288
+ * buf[0] = 5
289
+ *
290
+ * buf = RubyAudio::Buffer.double(100, 2)
291
+ * buf[0] = [0.5, 0.3]
292
+ */
293
+ static VALUE ra_buffer_aset(VALUE self, VALUE index, VALUE val) {
294
+ RA_BUFFER *buf;
295
+ Data_Get_Struct(self, RA_BUFFER, buf);
296
+
297
+ // Bounds check
298
+ long f = FIX2LONG(index);
299
+ if(f < 0 || f >= buf->size) rb_raise(eRubyAudioError, "setting frame out of bounds");
300
+ long i = f * buf->channels;
301
+
302
+ // Set data
303
+ if(buf->channels == 1) {
304
+ ra_buffer_index_set(buf, i, val);
305
+ } else {
306
+ if(TYPE(val) != T_ARRAY) rb_raise(eRubyAudioError, "must pass in array for multi-channel buffer");
307
+ long length = RARRAY_LEN(val);
308
+ if(length != buf->channels) rb_raise(eRubyAudioError, "array length must match channel count");
309
+
310
+ long j;
311
+ for(j = 0; j < length; j++) {
312
+ ra_buffer_index_set(buf, i+j, rb_ary_entry(val, j));
313
+ }
314
+ }
315
+
316
+ // Bump real_size
317
+ if(f + 1 > buf->real_size) {
318
+ buf->real_size = f + 1;
319
+ }
320
+
321
+ return val;
322
+ }
323
+
324
+ static void ra_buffer_index_set(RA_BUFFER *buf, long i, VALUE val) {
325
+ if(buf->type == RA_BUFFER_TYPE_SHORT || buf->type == RA_BUFFER_TYPE_INT) {
326
+ // Convert val to an integer
327
+ VALUE int_obj = rb_Integer(val);
328
+ if(TYPE(int_obj) != T_FIXNUM) rb_raise(eRubyAudioError, "could not convert frame value to an integer");
329
+ long int_val = FIX2LONG(int_obj);
330
+
331
+ // Set it
332
+ if(buf->type == RA_BUFFER_TYPE_SHORT) ((short*)buf->data)[i] = (short)int_val;
333
+ else ((int*)buf->data)[i] = (int)int_val;
334
+ } else {
335
+ // Convert val to a float
336
+ double float_val = RFLOAT_VALUE(rb_Float(val));
337
+
338
+ // Set it
339
+ if(buf->type == RA_BUFFER_TYPE_FLOAT) ((float*)buf->data)[i] = (float)float_val;
340
+ else ((double*)buf->data)[i] = float_val;
341
+ }
342
+ }
@@ -0,0 +1,41 @@
1
+ #ifndef RA_BUFFER_H
2
+ #define RA_BUFFER_H
3
+
4
+ #include <ruby.h>
5
+
6
+ typedef enum {
7
+ RA_BUFFER_TYPE_SHORT,
8
+ RA_BUFFER_TYPE_INT,
9
+ RA_BUFFER_TYPE_FLOAT,
10
+ RA_BUFFER_TYPE_DOUBLE
11
+ } BUFFER_TYPE;
12
+
13
+ typedef struct {
14
+ BUFFER_TYPE type;
15
+ void *data;
16
+ long size;
17
+ long real_size;
18
+ int channels;
19
+ } RA_BUFFER;
20
+
21
+ void Init_ra_buffer();
22
+
23
+ /*** Initialization and Memory Manangement ***/
24
+ static VALUE ra_buffer_allocate(VALUE klass);
25
+ static void ra_buffer_free(RA_BUFFER *buf);
26
+
27
+ /*** Instance Methods ***/
28
+ static VALUE ra_buffer_init(int argc, VALUE *argv, VALUE self);
29
+ static VALUE ra_buffer_init_copy(VALUE copy, VALUE buf);
30
+ static VALUE ra_buffer_channels(VALUE self);
31
+ static VALUE ra_buffer_size(VALUE self);
32
+ static VALUE ra_buffer_real_size(VALUE self);
33
+ static VALUE ra_buffer_real_size_set(VALUE self, VALUE new_real_size);
34
+ static VALUE ra_buffer_type(VALUE self);
35
+ static VALUE ra_buffer_each(VALUE self);
36
+ static VALUE ra_buffer_aref(VALUE self, VALUE index);
37
+ static VALUE ra_buffer_index_get(RA_BUFFER *buf, long i);
38
+ static VALUE ra_buffer_aset(VALUE self, VALUE index, VALUE val);
39
+ static void ra_buffer_index_set(RA_BUFFER *buf, long i, VALUE val);
40
+
41
+ #endif // #ifndef RA_BUFFER_H