hallon-openal 0.0.2
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.
- data/.gitignore +21 -0
- data/.rspec +4 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +17 -0
- data/Rakefile +13 -0
- data/ext/hallon/extconf.rb +15 -0
- data/ext/hallon/openal_ext.c +377 -0
- data/hallon-openal.gemspec +19 -0
- data/lib/hallon-openal.rb +1 -0
- data/lib/hallon/openal.rb +3 -0
- data/lib/hallon/openal/version.rb +5 -0
- data/spec/hallon_openal_spec.rb +48 -0
- metadata +85 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Kim Burgestrand
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# OpenAL audio drivers for [Hallon](http://rubygems.org/gems/hallon)
|
2
|
+
|
3
|
+
This gem supplies Hallon with the ability to stream audio through your
|
4
|
+
speakers using OpenAL.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
gem install hallon-openal
|
9
|
+
|
10
|
+
## Issues? Bugs? Feedback?
|
11
|
+
|
12
|
+
I’d be happy to discuss any and all of these with you. Feel free to [create an issue](https://github.com/Burgestrand/hallon-openal/issues),
|
13
|
+
[email me](http://github.com/Burgestrand) or [tweet me at @Burgestrand](http://twitter.com/Burgestrand).
|
14
|
+
|
15
|
+
## License
|
16
|
+
|
17
|
+
X11 license. See LICENSE.txt for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
def error(message)
|
4
|
+
abort "[ERROR] #{message}"
|
5
|
+
end
|
6
|
+
|
7
|
+
$CFLAGS << ' -ggdb -O0 -Wextra'
|
8
|
+
|
9
|
+
error 'Missing ruby header' unless have_header 'ruby.h'
|
10
|
+
error 'Missing OpenAL/alc.h' unless have_header 'OpenAL/alc.h'
|
11
|
+
error 'Missing OpenAL/al.h' unless have_header 'OpenAL/al.h'
|
12
|
+
|
13
|
+
with_ldflags('-framework OpenAL') { RUBY_PLATFORM =~ /darwin/ }
|
14
|
+
|
15
|
+
create_makefile('openal_ext')
|
@@ -0,0 +1,377 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <OpenAL/alc.h>
|
3
|
+
#include <OpenAL/al.h>
|
4
|
+
#include <unistd.h>
|
5
|
+
|
6
|
+
#if DEBUG_H
|
7
|
+
# define DEBUG printf
|
8
|
+
#else
|
9
|
+
# define DEBUG(...) //
|
10
|
+
#endif
|
11
|
+
|
12
|
+
// How many audio buffers to keep
|
13
|
+
#define NUM_BUFFERS 3
|
14
|
+
|
15
|
+
// Globals
|
16
|
+
ID oa_iv_playing;
|
17
|
+
ID oa_iv_format;
|
18
|
+
ID oa_id_call;
|
19
|
+
ID oa_id_puts;
|
20
|
+
VALUE oa_key_channels;
|
21
|
+
VALUE oa_key_rate;
|
22
|
+
VALUE oa_key_type;
|
23
|
+
|
24
|
+
// struct information stored
|
25
|
+
// with the OpenAL driver instance
|
26
|
+
typedef struct
|
27
|
+
{
|
28
|
+
ALCdevice *device;
|
29
|
+
ALCcontext *context;
|
30
|
+
ALuint buffers[NUM_BUFFERS];
|
31
|
+
ALuint source;
|
32
|
+
} oa_struct_t;
|
33
|
+
|
34
|
+
// Utility
|
35
|
+
|
36
|
+
#define SYM2STR(x) rb_id2name(SYM2ID((x)))
|
37
|
+
#define STR2SYM(x) ID2SYM(rb_intern((x)))
|
38
|
+
|
39
|
+
#define OA_CHECK_ERRORS(msg) do { \
|
40
|
+
ALenum _error; \
|
41
|
+
if ((_error = alGetError()) != AL_NO_ERROR) \
|
42
|
+
{ \
|
43
|
+
rb_raise(rb_eRuntimeError, "OpenAL error: %u (%s)", _error, (msg)); \
|
44
|
+
} \
|
45
|
+
} while(0)
|
46
|
+
|
47
|
+
static inline oa_struct_t* oa_struct(VALUE self)
|
48
|
+
{
|
49
|
+
oa_struct_t *data_ptr;
|
50
|
+
Data_Get_Struct(self, oa_struct_t, data_ptr);
|
51
|
+
return data_ptr;
|
52
|
+
}
|
53
|
+
|
54
|
+
static inline void oa_ensure_playing(VALUE self)
|
55
|
+
{
|
56
|
+
ALint state;
|
57
|
+
ALuint source = oa_struct(self)->source;
|
58
|
+
VALUE playing = rb_ivar_get(self, oa_iv_playing);
|
59
|
+
|
60
|
+
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
61
|
+
OA_CHECK_ERRORS("AL_SOURCE_STATE");
|
62
|
+
|
63
|
+
if (RTEST(playing) && state != AL_PLAYING)
|
64
|
+
{
|
65
|
+
alSourcePlay(source);
|
66
|
+
OA_CHECK_ERRORS("alSourcePlay (forced continue)");
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
static inline void oa_puts(const char *message)
|
71
|
+
{
|
72
|
+
VALUE rbmessage = rb_str_new2(message);
|
73
|
+
rb_funcall(rb_cObject, oa_id_puts, 1, rbmessage);
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE oa_format_get(VALUE self);
|
77
|
+
|
78
|
+
static inline int _oa_format_channels(VALUE self)
|
79
|
+
{
|
80
|
+
VALUE channels = rb_hash_aref(oa_format_get(self), oa_key_channels);
|
81
|
+
return FIX2INT(channels);
|
82
|
+
}
|
83
|
+
|
84
|
+
static inline int _oa_format_rate(VALUE self)
|
85
|
+
{
|
86
|
+
VALUE rate = rb_hash_aref(oa_format_get(self), oa_key_rate);
|
87
|
+
return FIX2LONG(rate);
|
88
|
+
}
|
89
|
+
|
90
|
+
static inline VALUE _oa_format_type(VALUE self)
|
91
|
+
{
|
92
|
+
VALUE size = rb_hash_aref(oa_format_get(self), oa_key_type);
|
93
|
+
return size;
|
94
|
+
}
|
95
|
+
|
96
|
+
// implementation
|
97
|
+
|
98
|
+
static void oa_free(oa_struct_t *data_ptr)
|
99
|
+
{
|
100
|
+
int i;
|
101
|
+
|
102
|
+
// exit early if we have no data_ptr at all
|
103
|
+
if ( ! data_ptr) return;
|
104
|
+
|
105
|
+
// deleting a source stops it from playing and
|
106
|
+
// then destroys it
|
107
|
+
if (data_ptr->source)
|
108
|
+
alDeleteSources(1, &data_ptr->source);
|
109
|
+
|
110
|
+
// now that the source is gone, we can safely delete buffers
|
111
|
+
if (data_ptr->buffers[0])
|
112
|
+
alDeleteBuffers(NUM_BUFFERS, data_ptr->buffers);
|
113
|
+
|
114
|
+
// docs tell us to do this to make sure
|
115
|
+
// our source is not the current one
|
116
|
+
alcMakeContextCurrent(NULL);
|
117
|
+
|
118
|
+
if (data_ptr->context)
|
119
|
+
alcDestroyContext(data_ptr->context);
|
120
|
+
|
121
|
+
if (data_ptr->device)
|
122
|
+
alcCloseDevice(data_ptr->device);
|
123
|
+
|
124
|
+
xfree(data_ptr);
|
125
|
+
}
|
126
|
+
|
127
|
+
static VALUE oa_allocate(VALUE klass)
|
128
|
+
{
|
129
|
+
oa_struct_t *data_ptr;
|
130
|
+
return Data_Make_Struct(klass, oa_struct_t, NULL, oa_free, data_ptr);
|
131
|
+
}
|
132
|
+
|
133
|
+
static VALUE oa_initialize(VALUE self)
|
134
|
+
{
|
135
|
+
oa_struct_t *data_ptr;
|
136
|
+
ALenum error = AL_NO_ERROR;
|
137
|
+
|
138
|
+
// initialize openal
|
139
|
+
Data_Get_Struct(self, oa_struct_t, data_ptr);
|
140
|
+
|
141
|
+
data_ptr->device = alcOpenDevice(NULL);
|
142
|
+
if ( ! data_ptr->device)
|
143
|
+
{
|
144
|
+
rb_raise(rb_eRuntimeError, "failed to open device");
|
145
|
+
}
|
146
|
+
|
147
|
+
data_ptr->context = alcCreateContext(data_ptr->device, NULL);
|
148
|
+
if ( ! data_ptr->context)
|
149
|
+
{
|
150
|
+
rb_raise(rb_eRuntimeError, "failed to create context");
|
151
|
+
}
|
152
|
+
|
153
|
+
// reset error state
|
154
|
+
alGetError();
|
155
|
+
|
156
|
+
alcMakeContextCurrent(data_ptr->context);
|
157
|
+
OA_CHECK_ERRORS("context current");
|
158
|
+
|
159
|
+
// Set some defualt properties
|
160
|
+
alListenerf(AL_GAIN, 1.0f);
|
161
|
+
alDistanceModel(AL_NONE);
|
162
|
+
OA_CHECK_ERRORS("listener/distance");
|
163
|
+
|
164
|
+
// generate some buffers
|
165
|
+
alGenBuffers((ALsizei)NUM_BUFFERS, data_ptr->buffers);
|
166
|
+
OA_CHECK_ERRORS("generate buffers");
|
167
|
+
|
168
|
+
// generate our source
|
169
|
+
alGenSources(1, &data_ptr->source);
|
170
|
+
OA_CHECK_ERRORS("gen sources");
|
171
|
+
}
|
172
|
+
|
173
|
+
static VALUE oa_play(VALUE self)
|
174
|
+
{
|
175
|
+
rb_ivar_set(self, oa_iv_playing, Qtrue);
|
176
|
+
alSourcePlay(oa_struct(self)->source);
|
177
|
+
return self;
|
178
|
+
}
|
179
|
+
|
180
|
+
static VALUE oa_stop(VALUE self)
|
181
|
+
{
|
182
|
+
ALuint source = oa_struct(self)->source;
|
183
|
+
rb_ivar_set(self, oa_iv_playing, Qfalse);
|
184
|
+
|
185
|
+
// remove all buffers from the source
|
186
|
+
alSourcei(source, AL_BUFFER, 0);
|
187
|
+
OA_CHECK_ERRORS("remove buffers!");
|
188
|
+
|
189
|
+
// and stop the source
|
190
|
+
alSourceStop(source);
|
191
|
+
OA_CHECK_ERRORS("stop!");
|
192
|
+
|
193
|
+
return self;
|
194
|
+
}
|
195
|
+
|
196
|
+
static VALUE oa_pause(VALUE self)
|
197
|
+
{
|
198
|
+
rb_ivar_set(self, oa_iv_playing, Qfalse);
|
199
|
+
alSourcePause(oa_struct(self)->source);
|
200
|
+
OA_CHECK_ERRORS("pause!");
|
201
|
+
return self;
|
202
|
+
}
|
203
|
+
|
204
|
+
static VALUE oa_drops(VALUE self)
|
205
|
+
{
|
206
|
+
return INT2NUM(0);
|
207
|
+
}
|
208
|
+
|
209
|
+
static ALuint find_empty_buffer(VALUE self)
|
210
|
+
{
|
211
|
+
ALuint empty_buffer;
|
212
|
+
|
213
|
+
oa_struct_t *data_ptr = oa_struct(self);
|
214
|
+
ALuint source = data_ptr->source;
|
215
|
+
ALuint *buffers = data_ptr->buffers;
|
216
|
+
|
217
|
+
ALint num_queued = 0;
|
218
|
+
alGetSourcei(source, AL_BUFFERS_QUEUED, &num_queued);
|
219
|
+
OA_CHECK_ERRORS("AL_BUFFERS_QUEUED");
|
220
|
+
|
221
|
+
if (num_queued < NUM_BUFFERS)
|
222
|
+
{
|
223
|
+
empty_buffer = buffers[num_queued];
|
224
|
+
}
|
225
|
+
else
|
226
|
+
{
|
227
|
+
int processed;
|
228
|
+
struct timeval poll_time;
|
229
|
+
poll_time.tv_sec = 0;
|
230
|
+
poll_time.tv_usec = 100; /* 0.000100 sec */
|
231
|
+
|
232
|
+
for (processed = 0; processed == 0; rb_thread_wait_for(poll_time))
|
233
|
+
{
|
234
|
+
alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
|
235
|
+
OA_CHECK_ERRORS("AL_BUFFERS_PROCESSED");
|
236
|
+
}
|
237
|
+
|
238
|
+
alSourceUnqueueBuffers(source, 1, &empty_buffer);
|
239
|
+
OA_CHECK_ERRORS("alSourceUnqueueBuffers");
|
240
|
+
}
|
241
|
+
|
242
|
+
return empty_buffer;
|
243
|
+
}
|
244
|
+
|
245
|
+
static VALUE oa_format_get(VALUE self)
|
246
|
+
{
|
247
|
+
return rb_ivar_get(self, oa_iv_format);
|
248
|
+
}
|
249
|
+
|
250
|
+
static VALUE oa_format_set(VALUE self, VALUE format)
|
251
|
+
{
|
252
|
+
rb_ivar_set(self, oa_iv_format, format);
|
253
|
+
return format;
|
254
|
+
}
|
255
|
+
|
256
|
+
static VALUE oa_stream(VALUE self)
|
257
|
+
{
|
258
|
+
VALUE int16ne = STR2SYM("int16");
|
259
|
+
ALuint source = oa_struct(self)->source;
|
260
|
+
signed short *sample_ary = NULL;
|
261
|
+
|
262
|
+
for (;;)
|
263
|
+
{
|
264
|
+
// make sure we have no preattached buffers
|
265
|
+
alSourcei(source, AL_BUFFER, 0);
|
266
|
+
OA_CHECK_ERRORS("detach all buffers from the source");
|
267
|
+
|
268
|
+
// make sure we’re not playing audio
|
269
|
+
alSourceStop(source);
|
270
|
+
OA_CHECK_ERRORS("reset driver");
|
271
|
+
|
272
|
+
// read the format (it never changes in the inner loop)
|
273
|
+
int f_channels = _oa_format_channels(self);
|
274
|
+
int f_rate = _oa_format_rate(self);
|
275
|
+
VALUE f_type = _oa_format_type(self);
|
276
|
+
size_t f_size = 0;
|
277
|
+
|
278
|
+
DEBUG("%d channels %d rate", f_channels, f_rate);
|
279
|
+
|
280
|
+
// each time we buffer down there, it’ll be for about .5s of audio each time
|
281
|
+
int sample_ary_frames = f_rate / 2;
|
282
|
+
int sample_ary_length = sample_ary_frames * f_channels; // integer division
|
283
|
+
xfree(sample_ary); // ruby handles NULL pointer too
|
284
|
+
|
285
|
+
if (rb_eql(f_type, int16ne))
|
286
|
+
{
|
287
|
+
sample_ary = ALLOCA_N(short, sample_ary_length);
|
288
|
+
f_size = sizeof(short);
|
289
|
+
}
|
290
|
+
else
|
291
|
+
{
|
292
|
+
printf("Hallon::OpenAL#stream -> cannot handle format size %s!", SYM2STR(f_type));
|
293
|
+
rb_notimplement();
|
294
|
+
}
|
295
|
+
|
296
|
+
for (;;)
|
297
|
+
{
|
298
|
+
// pull some audio out of hallon
|
299
|
+
VALUE frames = rb_yield(INT2FIX(sample_ary_frames));
|
300
|
+
|
301
|
+
// if we received nil, it means format changed; the new
|
302
|
+
// format is already in @format, so we reinitialize!
|
303
|
+
if ( ! RTEST(frames))
|
304
|
+
{
|
305
|
+
break;
|
306
|
+
}
|
307
|
+
|
308
|
+
ALuint buffer = find_empty_buffer(self);
|
309
|
+
OA_CHECK_ERRORS("find_empty_buffer");
|
310
|
+
|
311
|
+
// convert the frames from ruby to C
|
312
|
+
int num_current_samples = ((int) RARRAY_LEN(frames)) * f_channels;
|
313
|
+
|
314
|
+
VALUE frame, sample;
|
315
|
+
int i, rb_i, rb_j;
|
316
|
+
for (i = 0; i < num_current_samples; ++i)
|
317
|
+
{
|
318
|
+
rb_i = i / f_channels; // integer division
|
319
|
+
rb_j = i % f_channels;
|
320
|
+
|
321
|
+
frame = RARRAY_PTR(frames)[rb_i];
|
322
|
+
sample = RARRAY_PTR(frame)[rb_j];
|
323
|
+
|
324
|
+
long value = FIX2LONG(sample);
|
325
|
+
|
326
|
+
sample_ary[i] = (short) value;
|
327
|
+
}
|
328
|
+
|
329
|
+
DEBUG("%d +%d\n", buffer, num_current_samples);
|
330
|
+
|
331
|
+
// pucker up all the params
|
332
|
+
ALenum type = f_channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
333
|
+
ALsizei size = f_size * num_current_samples;
|
334
|
+
ALsizei freq = f_rate;
|
335
|
+
|
336
|
+
// queue the data!
|
337
|
+
alBufferData(buffer, type, sample_ary, size, freq);
|
338
|
+
OA_CHECK_ERRORS("buffer data");
|
339
|
+
|
340
|
+
alSourceQueueBuffers(source, 1, &buffer);
|
341
|
+
OA_CHECK_ERRORS("queue a buffer");
|
342
|
+
|
343
|
+
// OpenAL transitions to :stopped state if we cannot
|
344
|
+
// keep buffers properly feeded — but we want it to
|
345
|
+
// play as soon as it can if we’re playing, so fix it
|
346
|
+
oa_ensure_playing(self);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
return Qtrue;
|
351
|
+
}
|
352
|
+
|
353
|
+
void Init_openal_ext(void)
|
354
|
+
{
|
355
|
+
VALUE mHallon = rb_const_get(rb_cObject, rb_intern("Hallon"));
|
356
|
+
VALUE cOpenAL = rb_define_class_under(mHallon, "OpenAL", rb_cObject);
|
357
|
+
|
358
|
+
oa_iv_playing = rb_intern("@playing");
|
359
|
+
oa_id_call = rb_intern("call");
|
360
|
+
oa_id_puts = rb_intern("puts");
|
361
|
+
oa_iv_format = rb_intern("format");
|
362
|
+
oa_key_channels = STR2SYM("channels");
|
363
|
+
oa_key_rate = STR2SYM("rate");
|
364
|
+
oa_key_type = STR2SYM("type");
|
365
|
+
|
366
|
+
rb_define_alloc_func(cOpenAL, oa_allocate);
|
367
|
+
|
368
|
+
rb_define_method(cOpenAL, "initialize", oa_initialize, 0);
|
369
|
+
rb_define_method(cOpenAL, "play", oa_play, 0);
|
370
|
+
rb_define_method(cOpenAL, "stop", oa_stop, 0);
|
371
|
+
rb_define_method(cOpenAL, "pause", oa_pause, 0);
|
372
|
+
rb_define_method(cOpenAL, "stream", oa_stream, 0);
|
373
|
+
rb_define_method(cOpenAL, "format=", oa_format_set, 1);
|
374
|
+
rb_define_method(cOpenAL, "format", oa_format_get, 0);
|
375
|
+
|
376
|
+
rb_define_method(cOpenAL, "drops", oa_drops, 0);
|
377
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/hallon/openal/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "hallon-openal"
|
6
|
+
|
7
|
+
gem.authors = ["Kim Burgestrand"]
|
8
|
+
gem.email = ["kim@burgestrand.se"]
|
9
|
+
gem.summary = %q{OpenAL audio drivers for Hallon: http://rubygems.org/gems/hallon}
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split("\n")
|
12
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
+
gem.require_paths = ["lib", "ext"]
|
14
|
+
gem.extensions = ["ext/hallon/extconf.rb"]
|
15
|
+
gem.version = Hallon::OpenAL::VERSION
|
16
|
+
|
17
|
+
gem.add_dependency 'hallon', '~> 0.13'
|
18
|
+
gem.add_development_dependency 'rspec', '~> 2.7'
|
19
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'hallon/openal'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'hallon/openal'
|
3
|
+
|
4
|
+
describe Hallon::OpenAL do
|
5
|
+
let(:klass) { described_class }
|
6
|
+
let(:format) { Hash.new }
|
7
|
+
subject { klass.new(format) }
|
8
|
+
|
9
|
+
describe "#initialize" do
|
10
|
+
it "should raise an error if not given a format" do
|
11
|
+
expect { klass.new {} }.to raise_error(ArgumentError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#start" do
|
16
|
+
it "should not raise an error" do
|
17
|
+
expect { subject.start }.to_not raise_error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#stop" do
|
22
|
+
it "should not raise an error" do
|
23
|
+
expect { subject.stop }.to_not raise_error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#pause" do
|
28
|
+
it "should not raise an error" do
|
29
|
+
expect { subject.pause }.to_not raise_error
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#drops" do
|
34
|
+
it "should always return zero" do
|
35
|
+
subject.drops.should be_zero
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#format" do
|
40
|
+
it "should be settable and gettable" do
|
41
|
+
format = { channels: 1, rate: 44100 }
|
42
|
+
|
43
|
+
subject.format.should == {}
|
44
|
+
subject.format = format
|
45
|
+
subject.format.should eq format
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hallon-openal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kim Burgestrand
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: hallon
|
16
|
+
requirement: &70281050669480 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.13'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70281050669480
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70281050668320 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.7'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70281050668320
|
36
|
+
description:
|
37
|
+
email:
|
38
|
+
- kim@burgestrand.se
|
39
|
+
executables: []
|
40
|
+
extensions:
|
41
|
+
- ext/hallon/extconf.rb
|
42
|
+
extra_rdoc_files: []
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- .rspec
|
46
|
+
- CHANGELOG.md
|
47
|
+
- Gemfile
|
48
|
+
- LICENSE.txt
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- ext/hallon/extconf.rb
|
52
|
+
- ext/hallon/openal_ext.c
|
53
|
+
- hallon-openal.gemspec
|
54
|
+
- lib/hallon-openal.rb
|
55
|
+
- lib/hallon/openal.rb
|
56
|
+
- lib/hallon/openal/version.rb
|
57
|
+
- spec/hallon_openal_spec.rb
|
58
|
+
homepage:
|
59
|
+
licenses: []
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
- ext
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.12
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: ! 'OpenAL audio drivers for Hallon: http://rubygems.org/gems/hallon'
|
83
|
+
test_files:
|
84
|
+
- spec/hallon_openal_spec.rb
|
85
|
+
has_rdoc:
|