Class: Sound::Device

Inherits:
Object
  • Object
show all
Includes:
DeviceLibrary
Defined in:
lib/sound/device.rb

Defined Under Namespace

Classes: Buffer

Constant Summary

Constants included from DeviceLibrary

Sound::DeviceLibrary::DEFAULT_DEVICE_ID

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(direction = "w", id = DeviceLibrary::DEFAULT_DEVICE_ID, &block) ⇒ Device

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.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 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

Instance Attribute Details

#idObject (readonly)

Returns the value of attribute id.



14
15
16
# File 'lib/sound/device.rb', line 14

def id
  @id
end

#statusObject (readonly)

Returns the value of attribute status.



14
15
16
# File 'lib/sound/device.rb', line 14

def status
  @status
end

Class Method Details

.open(device = Device.new, direction = "w", &block) ⇒ Object

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



63
64
65
66
67
68
69
70
71
72
# 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

Instance Method Details

#closeObject

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



133
134
135
136
137
138
139
140
141
142
# 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!Object

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



147
148
149
150
151
152
153
154
155
156
# 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?Boolean

checks if the current status of the device is :closed

Returns:

  • (Boolean)


46
47
48
# File 'lib/sound/device.rb', line 46

def closed?
  status == :closed
end

#flushObject

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



161
162
163
164
165
166
167
168
169
170
171
172
173
# 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!Object

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



178
179
180
181
# File 'lib/sound/device.rb', line 178

def flush!
  @queue = Device::Buffer.new
  self
end

#openObject

opens the device.



77
78
79
80
# File 'lib/sound/device.rb', line 77

def open
  @status = :open
  self
end

#open?Boolean

checks if the current status of the device is :open

Returns:

  • (Boolean)


40
41
42
# File 'lib/sound/device.rb', line 40

def open?
  status == :open
end

#play(data = Sound::Data.new) ⇒ Object

writes data to the queue and immediately flushes the queue.



84
85
86
87
# File 'lib/sound/device.rb', line 84

def play(data = Sound::Data.new)
  write(data)
  flush
end

#queueObject

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



52
53
54
# File 'lib/sound/device.rb', line 52

def queue
  @queue.dup.freeze
end

#write(data = Sound::Data.new) ⇒ Object

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.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# 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) ⇒ Object

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.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# 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