audio 0.1 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f7750670a7a9f4d0554765012808dbe2f6477c9
4
- data.tar.gz: a9e49107f1c2d316f416ecacc9a0f4ede1df1e66
3
+ metadata.gz: f3cab4fbb003f03b5a3803b5c7df3b59cebc5d23
4
+ data.tar.gz: b9be9609b5ba0bae0f4bc73d45e535a343ad253a
5
5
  SHA512:
6
- metadata.gz: 8a813230ad12d52963266b54ab57dfef88728af3fc6b6883bc19a1c71b783e9fcae205b2f06dfcecb2f06869e91185dfb2c47c2defbdec07d286b61c2a8ab414
7
- data.tar.gz: a6dbf92c29fbce40913e41e099f549b9f314e1c7bed5f50eeaf73f2d79a73a41cf847b94e870c609cc0bc71bb2029d7cddbf21d081d43e9e100a7e148902c6bb
6
+ metadata.gz: 1a79f5be46891faa3ac670afcc4f151f5c8deb57bac77dd3a6a1041dc6c1efb5084c941a4ffac0037215cb9f9590e84be9b75949b0162a715a14c7e26d831e5d
7
+ data.tar.gz: 7341e4f79c1f4bdddcb8cfd9ee30c2ee56cd620d68e89e97f953f08549b6872546a98ad3a6ab19c57f48900ef5d2e9bc903f8f3ecf7dec5f1bad9f25d25e63c9
data/README.md CHANGED
@@ -40,6 +40,15 @@ Device Name: Built-in Output
40
40
  Device Name: Blue Snowball
41
41
  ```
42
42
 
43
+ ### Using the default Audio Devices
44
+
45
+ If you just want to use a default device, Audio has you covered.
46
+
47
+ ```ruby
48
+ Audio.default_input # => Device Name: Built-in Microphone
49
+ Audio.default_output # => Device Name: Built-in Output
50
+ ```
51
+
43
52
  ### Recording Audio
44
53
 
45
54
  You can record audio from a particular device by calling its `start` method.
@@ -48,8 +57,7 @@ called. If you provide a block parameter to `start`, it will be called whenever
48
57
  the host OS provides a new buffer of audio samples.
49
58
 
50
59
  ```ruby
51
- device = Audio.devices.last # Hopefully that's an input device
52
- device.start do |*args|
60
+ Audio.default_input.start do |*args|
53
61
  # Do something fancy
54
62
  end
55
63
 
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "audio"
7
- spec.version = '0.1'
7
+ spec.version = '0.2'
8
8
  spec.authors = ["Brandon Fosdick"]
9
9
  spec.email = ["bfoz@bfoz.net"]
10
10
  spec.summary = %q{Cross-platform Audio Device Input and Output}
@@ -1,4 +1,5 @@
1
- require_relative 'core_audio'
1
+ require_relative 'macos/core_audio'
2
+ require_relative 'macos/audio_toolbox'
2
3
 
3
4
  module Audio
4
5
  # @return [Array<Device>] the list of available audio devices
@@ -0,0 +1,55 @@
1
+ require 'ffi'
2
+
3
+ require_relative 'audio_toolbox/audio_converter'
4
+ require_relative 'core_foundation'
5
+ require_relative 'core_audio/audio_stream'
6
+
7
+ module AudioToolbox
8
+ extend FFI::Library
9
+ ffi_lib '/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox'
10
+
11
+ OSStatus = CoreFoundation::OSStatus
12
+ AudioStreamBasicDescription = CoreAudio::AudioStreamBasicDescription
13
+
14
+ typedef :pointer, :AudioConverterRef
15
+
16
+ # OSStatus (*AudioConverterComplexInputDataProc)(AudioConverterRef inAudioConverter,
17
+ # UInt32* ioNumberDataPackets,
18
+ # AudioBufferList* ioData,
19
+ # AudioStreamPacketDescription** outDataPacketDescription,
20
+ # void* inUserData)
21
+ callback :AudioConverterComplexInputDataProc, [:AudioConverterRef, :pointer, :pointer, :pointer, :pointer], OSStatus
22
+
23
+ # OSStatus AudioConverterNew(const AudioStreamBasicDescription* inSourceFormat,
24
+ # const AudioStreamBasicDescription* inDestinationFormat,
25
+ # AudioConverterRef* outAudioConverter)
26
+ attach_function :AudioConverterNew, [AudioStreamBasicDescription.by_ref, AudioStreamBasicDescription.by_ref, :pointer], OSStatus
27
+
28
+ # OSStatus AudioConverterFillComplexBuffer(AudioConverterRef inAudioConverter,
29
+ # AudioConverterComplexInputDataProc inInputDataProc,
30
+ # void* inInputDataProcUserData,
31
+ # UInt32* ioOutputDataPacketSize,
32
+ # AudioBufferList* outOutputData,
33
+ # AudioStreamPacketDescription* outPacketDescription)
34
+ attach_function :AudioConverterFillComplexBuffer, [:AudioConverterRef, :AudioConverterComplexInputDataProc, :pointer, :pointer, :pointer, :pointer], OSStatus
35
+
36
+ # OSStatus AudioConverterSetProperty(AudioConverterRef inAudioConverter,
37
+ # AudioConverterPropertyID inPropertyID,
38
+ # UInt32 inPropertyDataSize,
39
+ # const void* inPropertyData)
40
+ attach_function :AudioConverterSetProperty, [:AudioConverterRef, :uint32, :uint32, :pointer], OSStatus
41
+
42
+ # Create a new {AudioConverter} that convertes between the given stream formats
43
+ # @param from [AudioStreamBasicDescription] the stream format to convert from
44
+ # @param to [AudioStreamBasicDescription] the stream format to convert to
45
+ # @return [AudioConverterRef]
46
+ def self.converter(from, to)
47
+ reference = FFI::MemoryPointer.new(AudioConverterRef)
48
+ status = AudioToolbox.AudioConverterNew(from, to, reference)
49
+ raise "No converter '#{[status].pack('L').reverse}'" unless status.zero?
50
+ AudioConverterRef.new(reference.get_pointer(0)).tap do |converter|
51
+ converter.from = from
52
+ converter.to = to
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ module AudioToolbox
2
+ class AudioConverterRef < FFI::Pointer
3
+ attr_accessor :from
4
+ attr_accessor :to
5
+
6
+ # @group AudioConverter.h
7
+ PrimeMethod = 'prmm'
8
+ # @endgroup
9
+
10
+ # @param buffer [AudioBufferList] the list of buffers to be converted
11
+ # @return [AudioBufferList] the converted data
12
+ def convert(buffer)
13
+ num_from_packets = (buffer.bytesize / from[:mBytesPerPacket]).floor
14
+ remaining_packets = num_from_packets
15
+
16
+ block = Proc.new do |_, num_packets, buffer_list, _|
17
+ unless remaining_packets.zero?
18
+ buffer_list = CoreAudio::AudioBufferList.new(buffer_list)
19
+ buffer_list.buffers.first[:mData] = buffer.buffers.first[:mData]
20
+ buffer_list.buffers.first[:mDataByteSize] = buffer.buffers.first[:mDataByteSize]
21
+ end
22
+
23
+ # Report the number of packets actually sent
24
+ num_packets.put_uint32(0, remaining_packets)
25
+
26
+ remaining_packets = 0 # No more packets remaining
27
+
28
+ 0 # All is well
29
+ end
30
+
31
+ bytes_per_packet = to[:mBytesPerPacket]
32
+ num_output_packets = (num_from_packets * to.sample_rate / from.sample_rate).floor
33
+
34
+ output_list = CoreAudio::AudioBufferList.buffer_list(size:bytes_per_packet * num_output_packets)
35
+ raise("No buffer list") unless output_list
36
+
37
+ num_packets = FFI::MemoryPointer.new(:uint32).put_uint32(0, num_output_packets)
38
+ status = AudioToolbox.AudioConverterFillComplexBuffer(self, block, nil, num_packets, output_list, nil)
39
+ raise("Convert failed: '#{[status].pack('L').reverse}'") unless status.zero?
40
+
41
+ output_list
42
+ end
43
+
44
+ # @param method [Symbol] :pre, :normal, or :none
45
+ def prime_method=(method=:normal)
46
+ method = case method
47
+ when :pre then 0
48
+ when :normal then 1
49
+ when :none then 2
50
+ end
51
+ data = FFI::MemoryPointer.new(:uint32).put_uint32(0, method)
52
+ AudioToolbox.AudioConverterSetProperty(self, PrimeMethod.reverse.unpack('L').first, 4, data)
53
+ end
54
+ end
55
+ end
@@ -1,34 +1,18 @@
1
1
  require 'ffi'
2
2
 
3
+ require_relative 'core_audio/audio_types'
4
+
3
5
  module CoreAudio
4
6
  extend FFI::Library
5
7
  ffi_lib '/System/Library/Frameworks/CoreAudio.framework/CoreAudio'
6
8
 
7
9
  typedef :uint32, :OSStatus
8
-
9
- # @group CoreAudioTypes.h
10
- class AudioBuffer < FFI::Struct
11
- layout :mNumberChannels, :uint32,
12
- :mDataByteSize, :uint32,
13
- :mData, :pointer
14
-
15
- # @return [String] the raw bytes
16
- def bytes
17
- self[:mData].get_bytes(0, self[:mDataByteSize])
18
- end
19
- end
20
-
21
- class AudioBufferList < FFI::Struct
22
- layout :mNumberBuffers, :uint32,
23
- :mBuffers, AudioBuffer
24
- end
25
- # @endgroup
26
10
  end
27
11
 
28
12
  require_relative 'core_audio/audio_device'
29
13
 
30
14
  module CoreAudio
31
- # AudioHardware.h
15
+ # @group AudioHardware.h
32
16
  # OSStatus AudioObjectGetPropertyDataSize(AudioObjectID inObjectID,
33
17
  # const AudioObjectPropertyAddress* inAddress,
34
18
  # UInt32 inQualifierDataSize,
@@ -44,6 +28,15 @@ module CoreAudio
44
28
  # void* outData)
45
29
  attach_function :AudioObjectGetPropertyData, [AudioObject::ObjectID, AudioObject::PropertyAddress.by_ref, :uint32, :pointer, :pointer, :pointer], :OSStatus
46
30
 
31
+ # OSStatus AudioObjectSetPropertyData(AudioObjectID inObjectID,
32
+ # const AudioObjectPropertyAddress* inAddress,
33
+ # UInt32 inQualifierDataSize,
34
+ # const void* inQualifierData,
35
+ # UInt32 inDataSize,
36
+ # const void* inData)
37
+ attach_function :AudioObjectSetPropertyData, [AudioObject::ObjectID, AudioObject::PropertyAddress.by_ref, :uint32, :pointer, :uint32, :pointer], :OSStatus
38
+ # @endgroup
39
+
47
40
  # @return [Array<AudioObject>] the list of available audio devices
48
41
  def self.devices
49
42
  address = AudioObject::PropertyAddress.global_master(AudioHardware::PropertyDevices)
@@ -51,4 +44,18 @@ module CoreAudio
51
44
  device_IDs = buffer.get_array_of_int32(0, buffer.size/4)
52
45
  device_IDs.map {|id| AudioDevice.new(id)}
53
46
  end
47
+
48
+ # @return [AudioDevice] the default input device
49
+ def self.default_input
50
+ address = AudioObject::PropertyAddress.global_master(AudioHardware::PropertyDefaultInputDevice)
51
+ buffer = AudioObject.system.get_property(address)
52
+ AudioDevice.new(buffer.get_uint32(0))
53
+ end
54
+
55
+ # @return [AudioDevice] the default output device
56
+ def self.default_output
57
+ address = AudioObject::PropertyAddress.global_master(AudioHardware::PropertyDefaultOutputDevice)
58
+ buffer = AudioObject.system.get_property(address)
59
+ AudioDevice.new(buffer.get_uint32(0))
60
+ end
54
61
  end
@@ -35,8 +35,35 @@ module CoreAudio
35
35
 
36
36
  # @endgroup
37
37
 
38
+ # Split the constants so that AudioStream can see 'PropertyLatency'
38
39
  class AudioDevice < AudioObject
40
+ # @group AudioHardwareBase.h: AudioDevice Properties
41
+ PropertyConfigurationApplication = 'capp'
42
+ PropertyDeviceUID = 'uid '
43
+ PropertyModelUID = 'muid'
44
+ PropertyTransportType = 'tran'
45
+ PropertyRelatedDevices = 'akin'
46
+ PropertyClockDomain = 'clkd'
47
+ PropertyDeviceIsAlive = 'livn'
48
+ PropertyDeviceIsRunning = 'goin'
49
+ PropertyDeviceCanBeDefaultDevice = 'dflt'
50
+ PropertyDeviceCanBeDefaultSystemDevice = 'sflt'
51
+ PropertyLatency = 'ltnc'
52
+ PropertyStreams = 'stm#'
53
+ PropertyControlList = 'ctrl'
54
+ PropertySafetyOffset = 'saft'
55
+ PropertyNominalSampleRate = 'nsrt'
56
+ PropertyAvailableNominalSampleRates = 'nsr#'
57
+ PropertyIcon = 'icon'
58
+ PropertyIsHidden = 'hidn'
59
+ PropertyPreferredChannelsForStereo = 'dch2'
60
+ PropertyPreferredChannelLayout = 'srnd'
61
+ # @endgroup
62
+ end
39
63
 
64
+ require_relative 'audio_stream'
65
+
66
+ class AudioDevice
40
67
  # @group AudioHardware.h: AudioDevice Properties
41
68
  PropertyPlugIn = 'plug'
42
69
  PropertyDeviceHasChanged = 'diff'
@@ -54,20 +81,63 @@ module CoreAudio
54
81
  # @endgroup
55
82
 
56
83
  # @group Properties
57
- def actual_sample_rate
58
- address = PropertyAddress.global_master(PropertyActualSampleRate)
59
- get_property(address).get_float64(0)
60
- end
61
84
 
62
85
  def buffer_frame_size
63
86
  address = PropertyAddress.global_master(PropertyBufferFrameSize)
64
87
  get_property(address).get_uint32(0)
65
88
  end
66
89
 
90
+ # @return [Bool] true if the device is running
91
+ def running?
92
+ address = PropertyAddress.global_master(PropertyDeviceIsRunning)
93
+ 0 != get_property(address).get_uint32(0)
94
+ end
95
+
67
96
  def running_somewhere?
68
97
  address = PropertyAddress.global_master(PropertyDeviceIsRunningSomewhere)
69
98
  0 != get_property(address).get_uint32(0)
70
99
  end
100
+
101
+ # @return [Array<AudioStream>] an array of {AudioStream}s, one for each stream provided by the device
102
+ def streams
103
+ address = PropertyAddress.global_master(PropertyStreams)
104
+ buffer = get_property(address)
105
+ buffer.get_array_of_uint32(0, buffer.size/FFI::Type::UINT32.size).map {|stream_id| AudioStream.new(stream_id)}
106
+ end
107
+
108
+ # @group Sample Rate
109
+
110
+ # @return [Float] the measured sample rate in Hertz
111
+ def actual_sample_rate
112
+ address = PropertyAddress.global_master(PropertyActualSampleRate)
113
+ get_property(address).get_float64(0)
114
+ end
115
+
116
+ # @return [Array<Number,Range>] the available sampling rates, or sample-rate-ranges
117
+ def available_sample_rates
118
+ address = PropertyAddress.global_master(PropertyAvailableNominalSampleRates)
119
+ buffer = get_property(address)
120
+ buffer = buffer.get_array_of_float64(0, buffer.size / FFI::Type::DOUBLE.size)
121
+
122
+ # Convert the range pairs into actual Ranges, unless the Range is empty
123
+ buffer.each_slice(2).map {|a,b| (a==b) ? a : (a..b)}
124
+ end
125
+
126
+ # @return [Float] the device's nominal sample rate
127
+ def sample_rate
128
+ address = PropertyAddress.global_master(PropertyNominalSampleRate)
129
+ get_property(address).get_float64(0)
130
+ end
131
+
132
+ # @param rate [Float] the new sample rate in Hertz
133
+ def sample_rate=(rate)
134
+ address = PropertyAddress.global_master(PropertyNominalSampleRate)
135
+ ffi_rate = FFI::MemoryPointer.new(:double)
136
+ ffi_rate.put_float64(0, rate)
137
+ status = set_property(address, ffi_rate)
138
+ raise "status #{status} => '#{[status].pack('L').reverse}'" unless 0 == status
139
+ end
140
+ # @endgroup
71
141
  # @endgroup
72
142
 
73
143
  # Start the AudioDevice
@@ -51,21 +51,6 @@ module CoreAudio
51
51
  PropertyUserSessionIsActiveOrHeadless = 'user'
52
52
  PropertyServiceRestarted = 'srst'
53
53
  PropertyPowerHint = 'powh'
54
-
55
- # AudioHardware.h: AudioDevice Properties
56
- AudioDevicePropertyPlugIn = 'plug'
57
- AudioDevicePropertyDeviceHasChanged = 'diff'
58
- AudioDevicePropertyDeviceIsRunningSomewhere = 'gone'
59
- AudioDeviceProcessorOverload = 'over'
60
- AudioDevicePropertyIOStoppedAbnormally = 'stpd'
61
- AudioDevicePropertyHogMode = 'oink'
62
- AudioDevicePropertyBufferFrameSize = 'fsiz'
63
- AudioDevicePropertyBufferFrameSizeRange = 'fsz#'
64
- AudioDevicePropertyUsesVariableBufferFrameSizes = 'vfsz'
65
- AudioDevicePropertyIOCycleUsage = 'ncyc'
66
- AudioDevicePropertyStreamConfiguration = 'slay'
67
- AudioDevicePropertyIOProcStreamUsage = 'suse'
68
- AudioDevicePropertyActualSampleRate = 'asrt'
69
54
  end
70
55
 
71
56
  class AudioObject
@@ -123,6 +108,11 @@ module CoreAudio
123
108
  buffer
124
109
  end
125
110
 
111
+ def set_property(address, buffer, qualifier=nil)
112
+ qualifier_size = qualifier.size rescue 0
113
+ CoreAudio.AudioObjectSetPropertyData(id, address, 0, nil, buffer.size, buffer)
114
+ end
115
+
126
116
  # @group Convenience Attributes
127
117
  def external?
128
118
  not internal?
@@ -0,0 +1,95 @@
1
+ module CoreAudio
2
+ class AudioStreamBasicDescription < FFI::Struct
3
+ # @group CoreAudioTypes.h
4
+ FormatFlagIsFloat = (1 << 0)
5
+ FormatFlagIsSignedInteger = (1 << 2)
6
+ # @endgroup
7
+
8
+ layout :mSampleRate, :double,
9
+ :mFormatID, :uint32,
10
+ :mFormatFlags, :uint32,
11
+ :mBytesPerPacket, :uint32,
12
+ :mFramesPerPacket, :uint32,
13
+ :mBytesPerFrame, :uint32,
14
+ :mChannelsPerFrame, :uint32,
15
+ :mBitsPerChannel, :uint32,
16
+ :mReserved, :uint32
17
+
18
+ # @!attribute channels
19
+ # @return [Integer] the number of channels per frame
20
+ def channels
21
+ self[:mChannelsPerFrame]
22
+ end
23
+
24
+ # @param number [Integer] the number of channels per frame
25
+ def channels=(number)
26
+ self[:mChannelsPerFrame] = number.to_i
27
+ end
28
+
29
+ # @!attribute channel_width
30
+ # @return [Integer] the number of bits per channel
31
+ def channel_width=(bits)
32
+ self[:mBitsPerChannel] = bits
33
+ self[:mBytesPerFrame] = self[:mChannelsPerFrame] * bits / 8
34
+ self[:mBytesPerPacket] = self[:mBytesPerFrame] * self[:mFramesPerPacket]
35
+ end
36
+
37
+ # @!attribute float?
38
+ # @return [Bool] true if the stream samples are {Float}
39
+ def float?
40
+ (self[:mFormatFlags] & FormatFlagIsFloat) != 0
41
+ end
42
+
43
+ def integer
44
+ self[:mFormatFlags] &= ~FormatFlagIsFloat
45
+ self[:mFormatFlags] |= FormatFlagIsSignedInteger
46
+ end
47
+
48
+ # @!attribute sample_rate
49
+ # @return [Float] the number of sample frames per second
50
+ def sample_rate; self[:mSampleRate]; end
51
+ def sample_rate=(rate)
52
+ self[:mSampleRate] = rate
53
+ end
54
+ end
55
+
56
+ class AudioValueRange < FFI::Struct
57
+ layout :minimum, :double,
58
+ :maximum, :double
59
+ end
60
+
61
+ class AudioStreamRangedDescription < FFI::Struct
62
+ layout :mFormat, AudioStreamBasicDescription,
63
+ :mSampleRateRange, AudioValueRange
64
+ end
65
+
66
+ class AudioStream < AudioObject
67
+ PropertyIsActive = 'sact',
68
+ PropertyDirection = 'sdir',
69
+ PropertyTerminalType = 'term',
70
+ PropertyStartingChannel = 'schn',
71
+ PropertyLatency = CoreAudio::AudioDevice::PropertyLatency,
72
+ PropertyVirtualFormat = 'sfmt',
73
+ PropertyAvailableVirtualFormats = 'sfma',
74
+ PropertyPhysicalFormat = 'pft ',
75
+ PropertyAvailablePhysicalFormats = 'pfta'
76
+
77
+ def virtual_format
78
+ address = PropertyAddress.global_master(PropertyVirtualFormat)
79
+ buffer = get_property(address)
80
+ AudioStreamBasicDescription.new(buffer)
81
+ end
82
+
83
+ def virtual_formats
84
+ address = PropertyAddress.global_master(PropertyAvailableVirtualFormats)
85
+ buffer = get_property(address)
86
+ count = buffer.size/AudioStreamRangedDescription.size
87
+ output = []
88
+ count.times do |i|
89
+ output << AudioStreamRangedDescription.new(buffer)
90
+ buffer += AudioStreamRangedDescription.size
91
+ end
92
+ output
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,73 @@
1
+ module CoreAudio
2
+ class AudioBuffer < FFI::Struct
3
+ layout :mNumberChannels, :uint32,
4
+ :mDataByteSize, :uint32,
5
+ :mData, :pointer
6
+
7
+ # @return [String] the raw bytes
8
+ def bytes
9
+ self[:mData].get_bytes(0, self[:mDataByteSize])
10
+ end
11
+
12
+ def bytesize
13
+ self[:mDataByteSize]
14
+ end
15
+
16
+ # @return [Array<Integer>] an array of samples, converted to signed integers
17
+ def samples_int(bytes_per_channel)
18
+ self[:mData].get_array_of_int16(0, self[:mDataByteSize]/bytes_per_channel)
19
+ end
20
+
21
+ # @return [Array<Float>] an array of samples, converted to {Float}
22
+ def samples_float(bytes_per_channel)
23
+ self[:mData].get_array_of_float32(0, self[:mDataByteSize]/bytes_per_channel)
24
+ end
25
+ end
26
+
27
+ class AudioBufferList < FFI::Struct
28
+ layout :mNumberBuffers, :uint32,
29
+ :mBuffers, AudioBuffer
30
+
31
+ def self.buffer_list(channels:1, size:nil)
32
+ self.new.tap do |list|
33
+ list[:mNumberBuffers] = 1
34
+ list[:mBuffers][:mNumberChannels] = channels
35
+
36
+ if( size )
37
+ list[:mBuffers][:mData] = FFI::MemoryPointer.new(size)
38
+ list[:mBuffers][:mDataByteSize] = size
39
+ else
40
+ list[:mBuffers][:mDataByteSize] = 0
41
+ end
42
+ end
43
+ end
44
+
45
+ # @return [Array] the buffers
46
+ def buffers
47
+ raise("Can't handle multiple buffers yet") if self[:mNumberBuffers] > 1
48
+ [self[:mBuffers]]
49
+ end
50
+
51
+ # @return [String] the raw bytes
52
+ def bytes
53
+ buffers.map(&:bytes).join
54
+ end
55
+
56
+ # @return [Number] the total number of bytes in the buffer list
57
+ def bytesize
58
+ buffers.map(&:bytesize).reduce(&:+)
59
+ end
60
+
61
+ # Retrieve the samples as an {Array}, after converting to the requested type
62
+ # @param type [Symbol] :float or :int. Convert the samples to the given type.
63
+ # @param bytes_per_channel [Number] the number of bytes for each sample
64
+ # @return [Array<Float,Integer>] an array of samples, converted to {Float} or {Integer}
65
+ def samples(type, bytes_per_channel)
66
+ if type == :float
67
+ buffers.map {|buffer| buffer.samples_float(bytes_per_channel)}.flatten
68
+ else
69
+ buffers.map {|buffer| buffer.samples_int(bytes_per_channel)}.flatten
70
+ end
71
+ end
72
+ end
73
+ end
@@ -6,6 +6,8 @@ module CoreFoundation
6
6
 
7
7
  typedef :pointer, :CFStringRef
8
8
 
9
+ OSStatus = typedef :uint32, :OSStatus
10
+
9
11
  if FFI::Platform::ARCH == 'x86_64'
10
12
  CFIndex = FFI::Type::LONG_LONG
11
13
  else
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: audio
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Fosdick
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-23 00:00:00.000000000 Z
11
+ date: 2015-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -51,10 +51,14 @@ files:
51
51
  - Rakefile
52
52
  - audio.gemspec
53
53
  - lib/audio.rb
54
- - lib/core_audio.rb
55
- - lib/core_audio/audio_device.rb
56
- - lib/core_audio/audio_object.rb
57
- - lib/core_foundation.rb
54
+ - lib/macos/audio_toolbox.rb
55
+ - lib/macos/audio_toolbox/audio_converter.rb
56
+ - lib/macos/core_audio.rb
57
+ - lib/macos/core_audio/audio_device.rb
58
+ - lib/macos/core_audio/audio_object.rb
59
+ - lib/macos/core_audio/audio_stream.rb
60
+ - lib/macos/core_audio/audio_types.rb
61
+ - lib/macos/core_foundation.rb
58
62
  homepage: http://github.com/bfoz/audio-ruby
59
63
  licenses:
60
64
  - BSD