plaything 1.0.0

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 ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ -Ilib
2
+ --color
3
+ --require ./spec/spec_helper
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "pry"
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Plaything
2
+
3
+ Blast raw PCM audio through your speakers using OpenAL.
4
+
5
+ ## License
6
+
7
+ Copyright (c) 2013 Kim Burgestrand
8
+
9
+ MIT License
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining
12
+ a copy of this software and associated documentation files (the
13
+ "Software"), to deal in the Software without restriction, including
14
+ without limitation the rights to use, copy, modify, merge, publish,
15
+ distribute, sublicense, and/or sell copies of the Software, and to
16
+ permit persons to whom the Software is furnished to do so, subject to
17
+ the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be
20
+ included in all copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require "bundler/gem_tasks"
3
+
4
+ task :console do
5
+ exec "pry", "-rbundler/setup", "-rplaything"
6
+ end
7
+ rescue LoadError
8
+ # don't need bundler for dev
9
+ end
10
+
11
+ require "rspec/core/rake_task"
12
+ RSpec::Core::RakeTask.new(:default) do |spec|
13
+ spec.ruby_opts = %w[-W]
14
+ end
data/lib/plaything.rb ADDED
@@ -0,0 +1,147 @@
1
+ require "ffi"
2
+ require "plaything/version"
3
+ require "plaything/monkey_patches/ffi"
4
+ require "plaything/support"
5
+ require "plaything/objects"
6
+ require "plaything/openal"
7
+
8
+ class Plaything
9
+ Error = Class.new(StandardError)
10
+
11
+ # Open the default output device and prepare it for playback.
12
+ #
13
+ # @param [Hash] options
14
+ # @option options [Symbol] sample_type (:int16)
15
+ # @option options [Integer] sample_rate (44100)
16
+ # @option options [Integer] channels (2)
17
+ def initialize(options = { sample_type: :int16, sample_rate: 44100, channels: 2 })
18
+ @device = OpenAL.open_device(nil)
19
+ raise Error, "Failed to open device" if @device.null?
20
+
21
+ @context = OpenAL.create_context(@device, nil)
22
+ OpenAL.make_context_current(@context)
23
+ OpenAL.distance_model(:none)
24
+ OpenAL.listenerf(:gain, 1.0)
25
+
26
+ FFI::MemoryPointer.new(OpenAL::Source, 1) do |ptr|
27
+ OpenAL.gen_sources(ptr.count, ptr)
28
+ @source = OpenAL::Source.new(ptr.read_uint)
29
+ end
30
+
31
+ @sample_type = options.fetch(:sample_type)
32
+ @sample_rate = Integer(options.fetch(:sample_rate))
33
+ @channels = Integer(options.fetch(:channels))
34
+
35
+ @sample_format = { [ :int16, 2 ] => :stereo16, }.fetch([@sample_type, @channels]) do
36
+ raise TypeError, "unknown sample format for type [#{@sample_type}, #{@channels}]"
37
+ end
38
+
39
+ FFI::MemoryPointer.new(OpenAL::Buffer, 3) do |ptr|
40
+ OpenAL.gen_buffers(ptr.count, ptr)
41
+ @buffers = OpenAL::Buffer.extract(ptr, ptr.count)
42
+ end
43
+
44
+ @free_buffers = @buffers.clone
45
+ @queued_buffers = []
46
+ @queued_frames = []
47
+
48
+ # 44100 int16s = 22050 frames = 0.5s (1 frame * 2 channels = 2 int16 = 1 sample = 1/44100 s)
49
+ @buffer_size = @sample_rate * @channels * 1.0
50
+ # how many samples there are in each buffer, irrespective of channels
51
+ @buffer_length = @buffer_size / @channels
52
+ # buffer_duration = buffer_length / sample_rate
53
+
54
+ @total_buffers_processed = 0
55
+ end
56
+
57
+ # Start playback of queued audio.
58
+ #
59
+ # @note You must continue to supply audio, or playback will cease.
60
+ def play
61
+ OpenAL.source_play(@source)
62
+ end
63
+
64
+ # Pause playback of queued audio. Playback will resume from current position when {#play} is called.
65
+ def pause
66
+ OpenAL.source_pause(@source)
67
+ end
68
+
69
+ # Stop playback and clear any queued audio.
70
+ #
71
+ # @note All audio queues are completely cleared, and {#position} is reset.
72
+ def stop
73
+ OpenAL.source_stop(@source)
74
+ @source.detach_buffers
75
+ @free_buffers.concat(@queued_buffers)
76
+ @queued_buffers.clear
77
+ @queued_frames.clear
78
+ @total_buffers_processed = 0
79
+ end
80
+
81
+ # @return [Rational] how many seconds of audio that has been played.
82
+ def position
83
+ Rational(@total_buffers_processed * @buffer_length + sample_offset, @sample_rate)
84
+ end
85
+
86
+ # @return [Integer] total size of current play queue.
87
+ def queue_size
88
+ @source.get(:buffers_queued, Integer) * @buffer_length - sample_offset
89
+ end
90
+
91
+ # @return [Integer] how many audio drops since last call to drops.
92
+ def drops
93
+ 0
94
+ end
95
+
96
+ # Queue audio frames for playback.
97
+ #
98
+ # @param [Array<[ Channels… ]>] frames array of N-sized arrays of integers.
99
+ def <<(frames)
100
+ if buffers_processed > 0
101
+ FFI::MemoryPointer.new(OpenAL::Buffer, buffers_processed) do |ptr|
102
+ OpenAL.source_unqueue_buffers(@source, ptr.count, ptr)
103
+ @total_buffers_processed += ptr.count
104
+ @free_buffers.concat OpenAL::Buffer.extract(ptr, ptr.count)
105
+ @queued_buffers.delete_if { |buffer| @free_buffers.include?(buffer) }
106
+ end
107
+ end
108
+
109
+ wanted_size = (@buffer_size - @queued_frames.length).div(@channels) * @channels
110
+ consumed_frames = frames.take(wanted_size)
111
+ @queued_frames.concat(consumed_frames)
112
+
113
+ if @queued_frames.length >= @buffer_size and @free_buffers.any?
114
+ current_buffer = @free_buffers.shift
115
+
116
+ FFI::MemoryPointer.new(@sample_type, @queued_frames.length) do |frames|
117
+ frames.public_send(:"write_array_of_#{@sample_type}", @queued_frames)
118
+ # stereo16 = 2 int16s (1 frame) = 1 sample
119
+ OpenAL.buffer_data(current_buffer, @sample_format, frames, frames.size, @sample_rate)
120
+ @queued_frames.clear
121
+ end
122
+
123
+ FFI::MemoryPointer.new(OpenAL::Buffer, 1) do |buffers|
124
+ buffers.write_uint(current_buffer.to_native)
125
+ OpenAL.source_queue_buffers(@source, buffers.count, buffers)
126
+ end
127
+
128
+ @queued_buffers.push(current_buffer)
129
+ end
130
+
131
+ consumed_frames.length
132
+ end
133
+
134
+ protected
135
+
136
+ def sample_offset
137
+ @source.get(:sample_offset, Integer)
138
+ end
139
+
140
+ def buffers_processed
141
+ if not @source.stopped?
142
+ @source.get(:buffers_processed, Integer)
143
+ else
144
+ 0
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,7 @@
1
+ require "ffi"
2
+
3
+ class FFI::AbstractMemory
4
+ def count
5
+ size.div(type_size)
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ require "plaything/objects/device"
2
+ require "plaything/objects/context"
3
+ require "plaything/objects/source"
4
+ require "plaything/objects/buffer"
@@ -0,0 +1,7 @@
1
+ class Plaything
2
+ module OpenAL
3
+ class Buffer < TypeClass(FFI::Type::UINT)
4
+ include OpenAL::Paramable(:buffer)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ class Plaything
2
+ module OpenAL
3
+ class Context < ManagedPointer
4
+ def self.release(context)
5
+ super do |pointer|
6
+ OpenAL.make_context_current(nil)
7
+ OpenAL.destroy_context(context)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ class Plaything
2
+ module OpenAL
3
+ class Device < ManagedPointer
4
+ def self.release(device)
5
+ super { |pointer| OpenAL.close_device(device) }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ class Plaything
2
+ module OpenAL
3
+ class Source < TypeClass(FFI::Type::UINT)
4
+ include OpenAL::Paramable(:source)
5
+
6
+ # Detach all queued or attached buffers.
7
+ #
8
+ # @note all buffers must be processed for this operation to succeed.
9
+ # @note all buffers are considered processed when {#stopped?}.
10
+ def detach_buffers
11
+ set(:buffer, 0)
12
+ end
13
+
14
+ # @return [Symbol] :initial, :paused, :playing, :stopped
15
+ def state
16
+ get(:source_state)
17
+ end
18
+
19
+ # @return [Boolean] true if source is in stopped state.
20
+ def stopped?
21
+ state == :stopped
22
+ end
23
+
24
+ # @return [Boolean] true if source is in stopped state.
25
+ def playing?
26
+ state == :playing
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,164 @@
1
+ class Plaything
2
+ module OpenAL
3
+ extend FFI::Library
4
+
5
+ ffi_lib ["openal", "/System/Library/Frameworks/OpenAL.framework/Versions/Current/OpenAL"]
6
+
7
+ typedef :pointer, :attributes
8
+ typedef :int, :sizei
9
+
10
+ # Errors
11
+ Error = Class.new(StandardError)
12
+
13
+ enum :error, [
14
+ :no_error, 0,
15
+ :invalid_name, 0xA001,
16
+ :invalid_enum, 0xA002,
17
+ :invalid_value, 0xA003,
18
+ :invalid_operation, 0xA004,
19
+ :out_of_memory, 0xA005,
20
+ ]
21
+ attach_function :get_error, :alGetError, [ ], :error
22
+
23
+ # Overridden for three purposes.
24
+ #
25
+ # 1. Allows us to only supply OpenAL name, and converts it to snake_case
26
+ # for attaching the function.
27
+ # 2. Wraps the call in an error-raise checker.
28
+ # 3. Creates a bang method that does not do automatic error checking.
29
+ def self.attach_function(c_name, params, returns, options = {})
30
+ ruby_name = c_name
31
+ .to_s
32
+ .sub(/\Aalc?/, "")
33
+ .gsub(/(?<!\A)\p{Lu}/u, '_\0')
34
+ .downcase
35
+ bang_name = "#{ruby_name}!"
36
+
37
+ super(ruby_name, c_name, params, returns, options)
38
+ alias_method(bang_name, ruby_name)
39
+
40
+ define_method(ruby_name) do |*args, &block|
41
+ get_error # clear error
42
+ public_send(bang_name, *args, &block).tap do
43
+ error = get_error
44
+ unless error == :no_error
45
+ raise Error, "#{ruby_name} failed with #{error}"
46
+ end
47
+ end
48
+ end
49
+
50
+ module_function ruby_name
51
+ module_function bang_name
52
+ end
53
+
54
+ # Devices
55
+ attach_function :alcOpenDevice, [ :string ], Device
56
+ attach_function :alcCloseDevice, [ Device ], :bool
57
+
58
+ # Context
59
+ attach_function :alcCreateContext, [ Device, :attributes ], Context
60
+ attach_function :alcDestroyContext, [ Context ], :void
61
+ attach_function :alcMakeContextCurrent, [ Context ], :bool
62
+
63
+ # Sources
64
+ attach_function :alGenSources, [ :sizei, :pointer ], :void
65
+ attach_function :alDeleteSources, [ :sizei, :pointer ], :void
66
+
67
+ attach_function :alSourcePlay, [ Source ], :void
68
+ attach_function :alSourcePause, [ Source ], :void
69
+ attach_function :alSourceStop, [ Source ], :void
70
+
71
+ attach_function :alSourceQueueBuffers, [ Source, :sizei, :pointer ], :void
72
+ attach_function :alSourceUnqueueBuffers, [ Source, :sizei, :pointer ], :void
73
+
74
+ # Buffers
75
+ enum :format, [
76
+ :mono8, 0x1100,
77
+ :mono16, 0x1101,
78
+ :stereo8, 0x1102,
79
+ :stereo16, 0x1103,
80
+ ]
81
+ attach_function :alGenBuffers, [ :sizei, :pointer ], :void
82
+ attach_function :alDeleteBuffers, [ :sizei, :pointer ], :void
83
+
84
+ attach_function :alBufferData, [ Buffer, :format, :pointer, :sizei, :sizei ], :void
85
+
86
+ # Parameters
87
+ enum :parameter, [
88
+ :none, 0x0000,
89
+
90
+ :source_relative, 0x0202,
91
+
92
+ :cone_inner_angle, 0x1001,
93
+ :cone_outer_angle, 0x1002,
94
+ :pitch, 0x1003,
95
+ :position, 0x1004,
96
+ :direction, 0x1005,
97
+ :velocity, 0x1006,
98
+ :looping, 0x1007,
99
+ :buffer, 0x1009,
100
+ :gain, 0x100A,
101
+ :min_gain, 0x100D,
102
+ :max_gain, 0x100E,
103
+ :orientation, 0x100F,
104
+
105
+ :source_state, 0x1010,
106
+ :initial, 0x1011,
107
+ :playing, 0x1012,
108
+ :paused, 0x1013,
109
+ :stopped, 0x1014,
110
+ :buffers_queued, 0x1015,
111
+ :buffers_processed, 0x1016,
112
+
113
+ :reference_distance, 0x1020,
114
+ :rolloff_factor, 0x1021,
115
+ :cone_outer_gain, 0x1022,
116
+ :max_distance, 0x1023,
117
+ :sec_offset, 0x1024,
118
+ :sample_offset, 0x1025,
119
+ :byte_offset, 0x1026,
120
+ :source_type, 0x1027,
121
+
122
+ :frequency, 0x2001,
123
+ :bits, 0x2002,
124
+ :channels, 0x2003,
125
+ :size, 0x2004,
126
+ :unused, 0x2010,
127
+ :pending, 0x2011,
128
+ :processed, 0x2012,
129
+
130
+ :distance_model, 0xD000,
131
+ :inverse_distance, 0xD001,
132
+ :inverse_distance_clamped, 0xD002,
133
+ :linear_distance, 0xD003,
134
+ :linear_distance_clamped, 0xD004,
135
+ :exponent_distance, 0xD005,
136
+ :exponent_distance_clamped, 0xD006,
137
+ ]
138
+
139
+ ## Utility
140
+ attach_function :alGetEnumValue, [ :string ], :int
141
+
142
+ enum_type(:parameter).to_h.each do |name, value|
143
+ real_name = "AL_#{name.to_s.upcase}"
144
+ real_value = get_enum_value(real_name)
145
+ if real_value != -1 && value != real_value
146
+ raise NameError, "#{name} has value #{value}, should be #{real_value}"
147
+ end
148
+ end
149
+
150
+ ## Listeners
151
+ attach_function :alListenerf, [ :parameter, :float ], :void
152
+
153
+ ## Sources
154
+ attach_function :alSourcei, [ Source, :parameter, :int ], :void
155
+ attach_function :alGetSourcei, [ Source, :parameter, :pointer ], :void
156
+
157
+ ## Sources
158
+ attach_function :alBufferi, [ Buffer, :parameter, :int ], :void
159
+ attach_function :alGetBufferi, [ Buffer, :parameter, :pointer ], :void
160
+
161
+ # Global params
162
+ attach_function :alDistanceModel, [ :parameter ], :void
163
+ end
164
+ end
@@ -0,0 +1,3 @@
1
+ require "plaything/support/managed_pointer"
2
+ require "plaything/support/type_class"
3
+ require "plaything/support/paramable"
@@ -0,0 +1,26 @@
1
+ class Plaything
2
+ module OpenAL
3
+ class ManagedPointer < FFI::AutoPointer
4
+ class << self
5
+ def release(pointer)
6
+ if pointer.null?
7
+ warn "Trying to release NULL #{name}."
8
+ elsif block_given?
9
+ yield pointer
10
+ else
11
+ warn "No releaser for #{name}."
12
+ end
13
+ rescue => e
14
+ warn "release for #{name} failed: #{e.message}."
15
+ end
16
+
17
+ def allocate(*args, &block)
18
+ pointer = FFI::MemoryPointer.new(*args)
19
+ yield pointer
20
+ pointer.autorelease = false
21
+ new(FFI::Pointer.new(pointer))
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ class Plaything
2
+ module OpenAL
3
+ def self.Paramable(type)
4
+ Module.new do
5
+ define_method(:al_type) do
6
+ type
7
+ end
8
+
9
+ def set(parameter, value)
10
+ type = if value.is_a?(Integer)
11
+ OpenAL.public_send(:"#{al_type}i", self, parameter, value)
12
+ elsif value.is_a?(Float)
13
+ OpenAL.public_send(:"#{al_type}f", self, parameter, value)
14
+ else
15
+ raise TypeError, "invalid type of #{value}, must be int or float"
16
+ end
17
+ end
18
+
19
+ def get(parameter, type = :enum)
20
+ name = if type == Integer
21
+ :i
22
+ elsif type == Float
23
+ :f
24
+ elsif type == :enum
25
+ :i
26
+ else
27
+ raise TypeError, "unknown type #{type}"
28
+ end
29
+
30
+ reader = { f: :float, i: :int }.fetch(name)
31
+
32
+ FFI::MemoryPointer.new(reader) do |ptr|
33
+ OpenAL.public_send(:"get_#{al_type}#{name}", self, parameter, ptr)
34
+ value = ptr.public_send(:"read_#{reader}")
35
+ value = OpenAL.enum_type(:parameter)[value] if type == :enum
36
+ return value
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,53 @@
1
+ class Plaything
2
+ module OpenAL
3
+ def self.TypeClass(type)
4
+ Class.new do
5
+ extend FFI::DataConverter
6
+ @@type = type
7
+
8
+ class << self
9
+ def inherited(other)
10
+ other.native_type(type)
11
+ end
12
+
13
+ def type
14
+ @@type
15
+ end
16
+
17
+ def to_native(source, ctx)
18
+ source.value
19
+ end
20
+
21
+ def from_native(value, ctx)
22
+ new(value)
23
+ end
24
+
25
+ def size
26
+ type.size
27
+ end
28
+
29
+ def extract(pointer, count)
30
+ pointer.read_array_of_type(self, :read_uint, count).map do |uint|
31
+ new(uint)
32
+ end
33
+ end
34
+ end
35
+
36
+ def initialize(value)
37
+ @value = value
38
+ end
39
+
40
+ def ==(other)
41
+ other.is_a?(self.class) and other.value == value
42
+ end
43
+
44
+ def to_native
45
+ self.class.to_native(self, nil)
46
+ end
47
+
48
+ attr_reader :value
49
+ end
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,3 @@
1
+ class Plaything
2
+ VERSION = "1.0.0"
3
+ end
data/plaything.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ require File.expand_path("./lib/plaything/version", File.dirname(__FILE__))
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "plaything"
6
+ spec.summary = "Blast raw PCM audio through your speakers using OpenAL."
7
+
8
+ spec.homepage = "https://github.com/Burgestrand/plaything"
9
+ spec.authors = ["Kim Burgestrand"]
10
+ spec.email = ["kim@burgestrand.se"]
11
+ spec.license = "MIT"
12
+
13
+ spec.files = `git ls-files`.split($/)
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ["lib"]
17
+
18
+ spec.version = Plaything::VERSION
19
+ spec.required_ruby_version = ">= 1.9"
20
+
21
+ spec.add_dependency "ffi", "~> 1.1"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "rake"
24
+ end
@@ -0,0 +1,5 @@
1
+ describe "Plaything" do
2
+ specify "VERSION is defined" do
3
+ defined?(Plaything::VERSION).should eq "constant"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require "plaything"
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: plaything
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.0
6
+ platform: ruby
7
+ authors:
8
+ - Kim Burgestrand
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ none: false
21
+ prerelease: false
22
+ name: ffi
23
+ requirement: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '1.1'
28
+ none: false
29
+ type: :runtime
30
+ - !ruby/object:Gem::Dependency
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ none: false
37
+ prerelease: false
38
+ name: rspec
39
+ requirement: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ none: false
45
+ type: :development
46
+ - !ruby/object:Gem::Dependency
47
+ version_requirements: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ none: false
53
+ prerelease: false
54
+ name: rake
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ none: false
61
+ type: :development
62
+ description:
63
+ email:
64
+ - kim@burgestrand.se
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - Gemfile
72
+ - README.md
73
+ - Rakefile
74
+ - lib/plaything.rb
75
+ - lib/plaything/monkey_patches/ffi.rb
76
+ - lib/plaything/objects.rb
77
+ - lib/plaything/objects/buffer.rb
78
+ - lib/plaything/objects/context.rb
79
+ - lib/plaything/objects/device.rb
80
+ - lib/plaything/objects/source.rb
81
+ - lib/plaything/openal.rb
82
+ - lib/plaything/support.rb
83
+ - lib/plaything/support/managed_pointer.rb
84
+ - lib/plaything/support/paramable.rb
85
+ - lib/plaything/support/type_class.rb
86
+ - lib/plaything/version.rb
87
+ - plaything.gemspec
88
+ - spec/plaything_spec.rb
89
+ - spec/spec_helper.rb
90
+ homepage: https://github.com/Burgestrand/plaything
91
+ licenses:
92
+ - MIT
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '1.9'
102
+ none: false
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ segments:
109
+ - 0
110
+ hash: 2964046639458012733
111
+ none: false
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 1.8.24
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: Blast raw PCM audio through your speakers using OpenAL.
118
+ test_files:
119
+ - spec/plaything_spec.rb
120
+ - spec/spec_helper.rb