Class: Radio::Signal::CoreAudio

Inherits:
Object
  • Object
show all
Defined in:
lib/radio/signals/coreaudio.rb

Constant Summary collapse

VERSION =
'>= 0.0.9'
BUFFER =

seconds of buffer

0.3
JITTER =

percent of buffer for output adjust

0.6

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ CoreAudio

Returns a new instance of CoreAudio.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/radio/signals/coreaudio.rb', line 62

def initialize options 
  @device = ::CoreAudio::AudioDevice.new options[:id].to_i
  @input_channels = @output_channels = 0
  if @input = options[:input]
    @input_channels = @input.size
    buffer_size = @input_channels * rate * BUFFER
    @input_buf = @device.input_buffer buffer_size
    @input_buf.start
  end
  if @output = options[:output]
    @output_channels = @output.size
    buffer_size = @output_channels * rate * BUFFER
    @output_buf = @device.output_buffer buffer_size
    @output_buf.start
  end
end

Instance Attribute Details

#input_channelsObject (readonly)

Returns the value of attribute input_channels.



60
61
62
# File 'lib/radio/signals/coreaudio.rb', line 60

def input_channels
  @input_channels
end

#output_channelsObject (readonly)

Returns the value of attribute output_channels.



60
61
62
# File 'lib/radio/signals/coreaudio.rb', line 60

def output_channels
  @output_channels
end

Class Method Details

.devicesObject

I don’t see a way to automatically set the CoreAudio CODEC rate. We’ll present the nominal_rate as the only option.



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/radio/signals/coreaudio.rb', line 46

def self.devices
  return {} unless defined? ::CoreAudio
  result = {}
  ::CoreAudio.devices.each do |dev|
    result[dev.devid] = {
      name: dev.name,
      rates: [dev.nominal_rate.to_i],
      input: dev.input_stream.channels,
      output: dev.output_stream.channels,
    }
  end
  result
end

.statusObject



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/radio/signals/coreaudio.rb', line 32

def self.status
  if defined? ::CoreAudio
    return "Loaded: %d devices" % devices.count
  end
  unless defined? @is_darwin
    @is_darwin = (`uname`.strip == 'Darwin') rescue false
  end
  return 'Unsupported: requires Apple OS' unless @is_darwin
  return 'Unavailable: gem update coreaudio '+ VERSION.dump if @bad_coreaudio
  return 'Unavailable: gem install coreaudio'
end

Instance Method Details

#in(samples) ⇒ Object

This is called on its own thread in Rig and is expected to block.



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/radio/signals/coreaudio.rb', line 80

def in samples
  # CoreAudio range of -32767..32767 makes easy conversion to -1.0..1.0
  if @input_channels == 1
    @input_buf.read(samples)[@input[0],true].to_f.div!(32767)
  else
    b = @input_buf.read samples
    c_out = NArray.scomplex samples
    c_out[0..-1] = b[@input[0],true].to_f.div!(32767)
    c_out.imag = b[@input[1],true].to_f.div!(32767)
    c_out
  end
end

#out(data) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/radio/signals/coreaudio.rb', line 93

def out data
  resetting = false
  if @output_buf.dropped_frame > 0
    p 'filling because frame dropped' #TODO logger
    resetting = true
    filler = rate * BUFFER * JITTER - data.size
    @output_buf << NArray.sfloat(filler) if filler > 0
  end
  output_buf_space = @output_buf.space
  if output_buf_space < data.size
    p 'dropping some data' #TODO logger
    # we'll drop all the data that won't fit
    @drop_data = data.size - output_buf_space
    # plus enough data to swing back
    @drop_data += rate * BUFFER * JITTER
  end
  out = nil
  if @drop_data
    if @drop_data < data.size
      out = data[@drop_data..-1] * 32767
    end
    @drop_data -= data.size
    @drop_data = nil if @drop_data <= 0
  else
    out = data * 32767
  end
  @output_buf << out if out
  @output_buf.reset_dropped_frame if resetting
end

#rateObject



129
130
131
# File 'lib/radio/signals/coreaudio.rb', line 129

def rate
  @device.nominal_rate
end

#stopObject

Once stopped, rig won’t attempt starting again on this object.



124
125
126
127
# File 'lib/radio/signals/coreaudio.rb', line 124

def stop
  @input_buf.stop if @input_buf
  @output_buf.stop if @output_buf
end