class Xi::Supercollider::Stream

Constants

DEFAULT_PARAMS
MAX_NODE_ID

Public Class Methods

new(name, clock, server: 'localhost', port: 57110, base_node_id: 2000, **opts) click to toggle source
Calls superclass method Xi::OSC::new
# File lib/xi/supercollider/stream.rb, line 17
def initialize(name, clock, server: 'localhost', port: 57110, base_node_id: 2000, **opts)
  super

  @base_node_id = base_node_id
  @playing_synths = [].to_set
  at_exit { free_playing_synths }
end

Public Instance Methods

free_playing_synths() click to toggle source
# File lib/xi/supercollider/stream.rb, line 34
def free_playing_synths
  n_free(*@playing_synths.map { |so_id| node_id(so_id) })
end
node_id(so_id) click to toggle source
# File lib/xi/supercollider/stream.rb, line 38
def node_id(so_id)
  (@base_node_id + so_id) % MAX_NODE_ID
end
stop() click to toggle source
Calls superclass method Xi::Stream#stop
# File lib/xi/supercollider/stream.rb, line 25
def stop
  @mutex.synchronize do
    @playing_synths.each do |so_id|
      n_set(node_id(so_id), gate: 0)
    end
  end
  super
end

Private Instance Methods

coerce_osc_value(value) click to toggle source
# File lib/xi/supercollider/stream.rb, line 117
def coerce_osc_value(value)
  v = Array(value).first
  v = v.to_f if v.is_a?(Rational)
  v = v.to_i if !v.is_a?(Float) && !v.is_a?(String) && !v.is_a?(Symbol)
  v
end
do_gate_off_change(changes) click to toggle source
# File lib/xi/supercollider/stream.rb, line 80
def do_gate_off_change(changes)
  debug "Gate off change: #{changes}"

  changes.each do |change|
    at = Time.at(change.fetch(:at))

    change.fetch(:so_ids).each do |so_id|
      n_set(node_id(so_id), gate: 0, at: at)
      @playing_synths.delete(so_id)
    end
  end
end
do_gate_on_change(changes) click to toggle source
# File lib/xi/supercollider/stream.rb, line 60
def do_gate_on_change(changes)
  debug "Gate on change: #{changes}"

  name = @state[:s] || :default
  state_params = @state.reject { |k, _| %i(s).include?(k) }

  freq = Array(state_params[:freq])

  changes.each do |change|
    at = Time.at(change.fetch(:at))

    change.fetch(:so_ids).each.with_index do |so_id, i|
      freq_i = freq.size > 0 ? freq[i % freq.size] : nil

      s_new(name, node_id(so_id), **state_params, gate: 1, freq: freq_i, at: at)
      @playing_synths << so_id
    end
  end
end
do_state_change() click to toggle source
# File lib/xi/supercollider/stream.rb, line 93
def do_state_change
  debug "State change: #{changed_state}"
  @playing_synths.each do |so_id|
    n_set(node_id(so_id), **changed_state)
  end
end
n_free(*ids, at: Time.now) click to toggle source
# File lib/xi/supercollider/stream.rb, line 109
def n_free(*ids, at: Time.now)
  send_bundle('/n_free', *ids, at: at)
end
n_set(id, at: Time.now, **args) click to toggle source
# File lib/xi/supercollider/stream.rb, line 100
def n_set(id, at: Time.now, **args)
  send_bundle('/n_set', id, *osc_args(args), at: at)
end
osc_args(**args) click to toggle source
# File lib/xi/supercollider/stream.rb, line 113
def osc_args(**args)
  args.map { |k, v| [k.to_s, coerce_osc_value(v)] }.flatten(1)
end
s_new(name, id, add_action: 0, target_id: 1, at: Time.now, **args) click to toggle source
# File lib/xi/supercollider/stream.rb, line 104
def s_new(name, id, add_action: 0, target_id: 1, at: Time.now, **args)
  send_bundle('/s_new', name.to_s, id.to_i, add_action.to_i,
              target_id.to_i, *osc_args(args), at: at)
end
transform_state() click to toggle source
Calls superclass method Xi::Stream#transform_state
# File lib/xi/supercollider/stream.rb, line 44
def transform_state
  super

  @state = DEFAULT_PARAMS.merge(@state)

  if changed_param?(:db) && !changed_param?(:amp)
    @state[:amp] = @state[:db].db_to_amp
    @changed_params << :amp
  end

  if changed_param?(:midinote) && !changed_param?(:freq)
    @state[:freq] = Array(@state[:midinote]).map(&:midi_to_cps)
    @changed_params << :freq
  end
end