class Sound::Device

Attributes

id[R]
status[R]

Public Class Methods

new(direction = "w", id = DeviceLibrary::DEFAULT_DEVICE_ID, &block) click to toggle source

creates a new device for writing by default. default id is set by whatever device interface was included (Win32 or ALSA, e.g.) if a block is passed, it executes the code in the block, passing the newly created device, and then closes the device.

# File lib/sound/device.rb, line 21
def initialize(direction = "w", id = DeviceLibrary::DEFAULT_DEVICE_ID, &block)
  
  @id = id
  @status = :open
  @queue = Device::Buffer.new
  @mutex = Mutex.new
  @direction = direction
  
  puts "opening device: '#{id}'" if Sound.verbose
  
  if block_given?
    block.call(self)
    close
  end
  
end
open(device = Device.new, direction = "w", &block) click to toggle source

Opens a sound device for reading or writing device is one of several devices, usually defined by a constant direction is reading or writing or both format is MIDI vs PCM or others this method can take a block and if so closes the device after execution

# File lib/sound/device.rb, line 63
def open(device = Device.new, direction = "w", &block)
  puts "opening device: '#{device.id}'" if Sound.verbose
  if block_given?
    block.call(device)
    device.close
  else
    device.open
    device
  end
end

Public Instance Methods

close() click to toggle source

flushes any pending queue data blocks, waits for them to finish playing, and then closes the device.

# File lib/sound/device.rb, line 133
def close
  if closed?
    warn("warning: device is already closed")
  else
    flush
    puts "device '#{id}' is closing now" if Sound.verbose
    @status = :closed
  end
  self
end
close!() click to toggle source

closes the device as quickly as possible without flushing the data buffer.

# File lib/sound/device.rb, line 147
def close!
  if closed?
    warn("warning: device is already closed")
  else
    flush!
    puts "device '#{id}' is closing immediately now" if Sound.verbose
    @status = :closed
  end
  self
end
closed?() click to toggle source

checks if the current status of the device is :closed

# File lib/sound/device.rb, line 46
def closed?
  status == :closed
end
flush() click to toggle source

flushes each block after previous finishes. Should make other options, like flush each block after a specified amount of time.

# File lib/sound/device.rb, line 161
def flush
  until @queue.empty?
    output = @queue.shift
    if output.kind_of? Thread
      finish_up(output).join
    else
      output.each do |thread|
        finish_up(thread)
      end
      output.last.join if output.last.alive?
    end
  end
end
flush!() click to toggle source

works like flush, but empties the buffer without playing any sounds and closes the physical device as quickly as possible for its platform.

# File lib/sound/device.rb, line 178
def flush!
  @queue = Device::Buffer.new
  self
end
open() click to toggle source

opens the device.

# File lib/sound/device.rb, line 77
def open
  @status = :open
  self
end
open?() click to toggle source

checks if the current status of the device is :open

# File lib/sound/device.rb, line 40
def open?
  status == :open
end
play(data = Sound::Data.new) click to toggle source

writes data to the queue and immediately flushes the queue.

# File lib/sound/device.rb, line 84
def play(data = Sound::Data.new)
  write(data)
  flush
end
queue() click to toggle source

returns the current queue. should be used for debugging only.

# File lib/sound/device.rb, line 52
def queue
  @queue.dup.freeze
end
write(data = Sound::Data.new) click to toggle source

writes given Data to the queue as a data block thread. Threads pause after preperation, and during flushing they get started back up. If a thread isn't done preparing when flushed, it finished preparing and immediately writes data to the device.

# File lib/sound/device.rb, line 94
def write(data = Sound::Data.new)
  if closed?
    warn("warning: cannot write to a closed device")
  else
    @mutex.lock
    @queue << Thread.new do
      Thread.current[:async] = false
      Thread.current[:data] = data
      write_thread
    end
    @mutex.unlock
    puts "writing to queue of device '#{id}': #{data}" if Sound.verbose
  end
  self
end
write_async(data = Sound::Data.new, force_new = false) click to toggle source

starts up data block threads that get played back at the same time. Need to make all threads wait until others are finished preparing the buffer.

# File lib/sound/device.rb, line 113
def write_async(data = Sound::Data.new, force_new = false)
  if closed?
    warn("warning: cannot write to a closed device")
  else
    @mutex.lock
    @queue.force = force_new
    if @queue.new_block
      @queue << [new_async_thread_for(data)]
    else
      @queue.last << new_async_thread_for(data)
    end
    @mutex.unlock
    puts "writing async to queue of device '#{id}': #{data}" if Sound.verbose
  end
  self
end

Private Instance Methods

finish_up(thread) click to toggle source
# File lib/sound/device.rb, line 216
def finish_up(thread)
  thread[:stop] = false
  puts "writing to device '#{id}': #{thread[:data].class}" if Sound.verbose #this may be NilClass if parent thread is too fast
  thread.run
end
new_async_thread_for(data) click to toggle source
# File lib/sound/device.rb, line 208
def new_async_thread_for(data)
  Thread.new do
    Thread.current[:async] = true
    Thread.current[:data] = data
    write_thread
  end
end
set_up() click to toggle source
# File lib/sound/device.rb, line 196
def set_up
  open_device(self)
  prepare_buffer
  Thread.stop if Thread.current[:stop]
  Thread.pass if Thread.current[:async]
end
tear_down() click to toggle source
# File lib/sound/device.rb, line 203
def tear_down
  unprepare_buffer
  close_device
end
write_thread() click to toggle source
# File lib/sound/device.rb, line 185
def write_thread
  Thread.current[:stop] = true if Thread.current[:stop].nil?
  if Sound.platform_supported
    set_up
    write_to_device
    tear_down
  else
    warn("warning: playback is not yet supported on this platform")
  end
end