Class: Plaything
- Inherits:
-
Object
- Object
- Plaything
- Defined in:
- lib/plaything.rb,
lib/plaything/openal.rb,
lib/plaything/version.rb,
lib/plaything/objects/buffer.rb,
lib/plaything/objects/device.rb,
lib/plaything/objects/source.rb,
lib/plaything/objects/context.rb,
lib/plaything/support/paramable.rb,
lib/plaything/support/type_class.rb,
lib/plaything/support/managed_pointer.rb
Defined Under Namespace
Modules: OpenAL
Constant Summary collapse
- Error =
Class.new(StandardError)
- VERSION =
"1.0.0"
Instance Method Summary collapse
-
#<<(frames) ⇒ Object
Queue audio frames for playback.
-
#drops ⇒ Integer
How many audio drops since last call to drops.
-
#initialize(options = { sample_type: :int16, sample_rate: 44100, channels: 2 }) ⇒ Plaything
constructor
Open the default output device and prepare it for playback.
-
#pause ⇒ Object
Pause playback of queued audio.
-
#play ⇒ Object
Start playback of queued audio.
-
#position ⇒ Rational
How many seconds of audio that has been played.
-
#queue_size ⇒ Integer
Total size of current play queue.
-
#stop ⇒ Object
Stop playback and clear any queued audio.
Constructor Details
#initialize(options = { sample_type: :int16, sample_rate: 44100, channels: 2 }) ⇒ Plaything
Open the default output device and prepare it for playback.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/plaything.rb', line 17 def initialize( = { sample_type: :int16, sample_rate: 44100, channels: 2 }) @device = OpenAL.open_device(nil) raise Error, "Failed to open device" if @device.null? @context = OpenAL.create_context(@device, nil) OpenAL.make_context_current(@context) OpenAL.distance_model(:none) OpenAL.listenerf(:gain, 1.0) FFI::MemoryPointer.new(OpenAL::Source, 1) do |ptr| OpenAL.gen_sources(ptr.count, ptr) @source = OpenAL::Source.new(ptr.read_uint) end @sample_type = .fetch(:sample_type) @sample_rate = Integer(.fetch(:sample_rate)) @channels = Integer(.fetch(:channels)) @sample_format = { [ :int16, 2 ] => :stereo16, }.fetch([@sample_type, @channels]) do raise TypeError, "unknown sample format for type [#{@sample_type}, #{@channels}]" end FFI::MemoryPointer.new(OpenAL::Buffer, 3) do |ptr| OpenAL.gen_buffers(ptr.count, ptr) @buffers = OpenAL::Buffer.extract(ptr, ptr.count) end @free_buffers = @buffers.clone @queued_buffers = [] @queued_frames = [] # 44100 int16s = 22050 frames = 0.5s (1 frame * 2 channels = 2 int16 = 1 sample = 1/44100 s) @buffer_size = @sample_rate * @channels * 1.0 # how many samples there are in each buffer, irrespective of channels @buffer_length = @buffer_size / @channels # buffer_duration = buffer_length / sample_rate @total_buffers_processed = 0 end |
Instance Method Details
#<<(frames) ⇒ Object
Queue audio frames for playback.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/plaything.rb', line 99 def <<(frames) if buffers_processed > 0 FFI::MemoryPointer.new(OpenAL::Buffer, buffers_processed) do |ptr| OpenAL.source_unqueue_buffers(@source, ptr.count, ptr) @total_buffers_processed += ptr.count @free_buffers.concat OpenAL::Buffer.extract(ptr, ptr.count) @queued_buffers.delete_if { |buffer| @free_buffers.include?(buffer) } end end wanted_size = (@buffer_size - @queued_frames.length).div(@channels) * @channels consumed_frames = frames.take(wanted_size) @queued_frames.concat(consumed_frames) if @queued_frames.length >= @buffer_size and @free_buffers.any? current_buffer = @free_buffers.shift FFI::MemoryPointer.new(@sample_type, @queued_frames.length) do |frames| frames.public_send(:"write_array_of_#{@sample_type}", @queued_frames) # stereo16 = 2 int16s (1 frame) = 1 sample OpenAL.buffer_data(current_buffer, @sample_format, frames, frames.size, @sample_rate) @queued_frames.clear end FFI::MemoryPointer.new(OpenAL::Buffer, 1) do |buffers| buffers.write_uint(current_buffer.to_native) OpenAL.source_queue_buffers(@source, buffers.count, buffers) end @queued_buffers.push(current_buffer) end consumed_frames.length end |
#drops ⇒ Integer
92 93 94 |
# File 'lib/plaything.rb', line 92 def drops 0 end |
#pause ⇒ Object
Pause playback of queued audio. Playback will resume from current position when #play is called.
65 66 67 |
# File 'lib/plaything.rb', line 65 def pause OpenAL.source_pause(@source) end |
#play ⇒ Object
Note:
You must continue to supply audio, or playback will cease.
Start playback of queued audio.
60 61 62 |
# File 'lib/plaything.rb', line 60 def play OpenAL.source_play(@source) end |
#position ⇒ Rational
82 83 84 |
# File 'lib/plaything.rb', line 82 def position Rational(@total_buffers_processed * @buffer_length + sample_offset, @sample_rate) end |
#queue_size ⇒ Integer
87 88 89 |
# File 'lib/plaything.rb', line 87 def queue_size @source.get(:buffers_queued, Integer) * @buffer_length - sample_offset end |
#stop ⇒ Object
Note:
All audio queues are completely cleared, and #position is reset.
Stop playback and clear any queued audio.
72 73 74 75 76 77 78 79 |
# File 'lib/plaything.rb', line 72 def stop OpenAL.source_stop(@source) @source.detach_buffers @free_buffers.concat(@queued_buffers) @queued_buffers.clear @queued_frames.clear @total_buffers_processed = 0 end |