Class: SFML::SoundRecorder
- Inherits:
-
Object
- Object
- SFML::SoundRecorder
- Defined in:
- lib/sfml/audio/sound_recorder.rb
Overview
Callback-based audio-capture base class. Subclass and override
#on_start (initialise capture state, return true to begin),
#on_process_samples(samples, channels) (called every audio chunk
with an Arraytrue to
keep recording or false to stop), and #on_stop (release any
resources).
The simpler "record to a SoundBuffer" path lives in SFML::SoundBufferRecorder — reach for SoundRecorder only when you need to stream samples somewhere else (file, socket, DSP pipeline).
class LevelMeter < SFML::SoundRecorder
def on_start
@peak = 0
true
end
def on_process_samples(samples, _channels)
@peak = [@peak, *samples.map(&:abs)].max
true
end
def on_stop
puts "Peak: #{@peak}"
end
end
meter = LevelMeter.new
meter.start(sample_rate: 44_100)
sleep 2
meter.stop
CAVEATS
- All three callbacks run on CSFML's audio thread; heavy Ruby work on the audio thread will glitch the capture.
- Always keep a reference to the SoundRecorder object — if the Ruby object is GC'd while CSFML is mid-capture, the process crashes.
Instance Attribute Summary collapse
-
#handle ⇒ Object
readonly
:nodoc:.
Class Method Summary collapse
-
.available? ⇒ Boolean
---- Static helpers (work without a recorder instance) ------------.
-
.default_device ⇒ Object
Returns the self.
-
.devices ⇒ Object
All input devices the OS exposes to SFML, as an Array of String names.
Instance Method Summary collapse
-
#channel_count ⇒ Object
Returns the channel count.
-
#channel_count=(n) ⇒ Object
Set the channel count.
-
#channel_map ⇒ Object
The channel layout the recorder is producing, as an Array of
sfSoundChannelenum values (1 = Mono, 2 = FrontLeft, 3 = FrontRight, etc — see SoundBuffer::DEFAULT_CHANNEL_MAPS). -
#device ⇒ Object
Returns the device.
-
#device=(name) ⇒ Object
Set the device.
-
#initialize ⇒ SoundRecorder
constructor
---- Instance API -------------------------------------------------.
-
#on_process_samples(_samples, _channels) ⇒ Object
Called with each chunk of captured audio.
-
#on_start ⇒ Object
Called once before the capture starts.
-
#on_stop ⇒ Object
Called once after the capture is done.
-
#sample_rate ⇒ Object
Returns the sample rate.
-
#start(sample_rate: 44_100) ⇒ Object
---- Public recorder API ----.
-
#stop ⇒ Object
Returns the stop.
Constructor Details
#initialize ⇒ SoundRecorder
---- Instance API -------------------------------------------------
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/sfml/audio/sound_recorder.rb', line 64 def initialize # Strong refs so the GC doesn't disappear callbacks under CSFML. @start_cb = FFI::Function.new(:bool, [:pointer]) do |_user| on_start ? true : false end @process_cb = FFI::Function.new(:bool, [:pointer, :size_t, :pointer]) do |samples_ptr, count, _user| samples = count.zero? ? [] : samples_ptr.read_array_of_int16(count) on_process_samples(samples, channel_count) ? true : false end @stop_cb = FFI::Function.new(:void, [:pointer]) do |_user| on_stop nil end ptr = C::Audio.sfSoundRecorder_create(@start_cb, @process_cb, @stop_cb, nil) raise AudioError, "sfSoundRecorder_create returned NULL" if ptr.null? @handle = FFI::AutoPointer.new(ptr, C::Audio.method(:sfSoundRecorder_destroy)) end |
Instance Attribute Details
#handle ⇒ Object (readonly)
:nodoc:
148 149 150 |
# File 'lib/sfml/audio/sound_recorder.rb', line 148 def handle @handle end |
Class Method Details
.available? ⇒ Boolean
---- Static helpers (work without a recorder instance) ------------
42 43 44 |
# File 'lib/sfml/audio/sound_recorder.rb', line 42 def self.available? C::Audio.sfSoundRecorder_isAvailable end |
.default_device ⇒ Object
Returns the self.
47 48 49 |
# File 'lib/sfml/audio/sound_recorder.rb', line 47 def self.default_device C::Audio.sfSoundRecorder_getDefaultDevice end |
.devices ⇒ Object
All input devices the OS exposes to SFML, as an Array of String names. Pass any of them to SoundRecorder#device= or SoundBufferRecorder#device= to switch.
54 55 56 57 58 59 60 |
# File 'lib/sfml/audio/sound_recorder.rb', line 54 def self.devices count_buf = FFI::MemoryPointer.new(:size_t) array_ptr = C::Audio.sfSoundRecorder_getAvailableDevices(count_buf) n = count_buf.read(:size_t) return [] if array_ptr.null? || n.zero? array_ptr.read_array_of_pointer(n).map { |p| p.read_string } end |
Instance Method Details
#channel_count ⇒ Object
Returns the channel count.
121 |
# File 'lib/sfml/audio/sound_recorder.rb', line 121 def channel_count = C::Audio.sfSoundRecorder_getChannelCount(@handle) |
#channel_count=(n) ⇒ Object
Set the channel count.
124 125 126 |
# File 'lib/sfml/audio/sound_recorder.rb', line 124 def channel_count=(n) C::Audio.sfSoundRecorder_setChannelCount(@handle, Integer(n)) end |
#channel_map ⇒ Object
The channel layout the recorder is producing, as an Array of
sfSoundChannel enum values (1 = Mono, 2 = FrontLeft,
3 = FrontRight, etc — see SoundBuffer::DEFAULT_CHANNEL_MAPS).
140 141 142 143 144 145 146 |
# File 'lib/sfml/audio/sound_recorder.rb', line 140 def channel_map count_buf = FFI::MemoryPointer.new(:size_t) ptr = C::Audio.sfSoundRecorder_getChannelMap(@handle, count_buf) n = count_buf.read(:size_t) return [] if ptr.null? || n.zero? ptr.read_array_of_int32(n) end |
#device ⇒ Object
Returns the device.
129 |
# File 'lib/sfml/audio/sound_recorder.rb', line 129 def device = C::Audio.sfSoundRecorder_getDevice(@handle) |
#device=(name) ⇒ Object
Set the device.
132 133 134 135 |
# File 'lib/sfml/audio/sound_recorder.rb', line 132 def device=(name) C::Audio.sfSoundRecorder_setDevice(@handle, name.to_s) || raise(AudioError, "sfSoundRecorder_setDevice failed for #{name.inspect}") end |
#on_process_samples(_samples, _channels) ⇒ Object
Called with each chunk of captured audio. samples is an
Arraytrue to keep capturing or false to stop.
Default raises so subclasses must implement it.
97 98 99 |
# File 'lib/sfml/audio/sound_recorder.rb', line 97 def on_process_samples(_samples, _channels) raise NoMethodError, "#{self.class} must override #on_process_samples" end |
#on_start ⇒ Object
Called once before the capture starts. Return true to begin
the capture or false to abort. Default does nothing and
accepts the start.
89 90 91 |
# File 'lib/sfml/audio/sound_recorder.rb', line 89 def on_start true end |
#on_stop ⇒ Object
Called once after the capture is done. Default is a no-op.
102 |
# File 'lib/sfml/audio/sound_recorder.rb', line 102 def on_stop; end |
#sample_rate ⇒ Object
Returns the sample rate.
119 120 |
# File 'lib/sfml/audio/sound_recorder.rb', line 119 def sample_rate = C::Audio.sfSoundRecorder_getSampleRate(@handle) # Returns the channel count. |
#start(sample_rate: 44_100) ⇒ Object
---- Public recorder API ----
106 107 108 109 110 |
# File 'lib/sfml/audio/sound_recorder.rb', line 106 def start(sample_rate: 44_100) C::Audio.sfSoundRecorder_start(@handle, Integer(sample_rate)) || raise(AudioError, "sfSoundRecorder_start failed (no input device or driver error)") self end |