audio 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
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