ruby-alsa 0.0.5 → 0.7

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.
data/Manifest.txt CHANGED
@@ -6,7 +6,12 @@ History.txt
6
6
  Manifest.txt
7
7
  README.rdoc
8
8
  Rakefile
9
+ debian/changelog
10
+ debian/compat
11
+ debian/control
12
+ debian/rules
9
13
  lib/alsa.rb
14
+ lib/alsa/ffi_ext.rb
10
15
  lib/alsa/logger.rb
11
16
  lib/alsa/native.rb
12
17
  lib/alsa/pcm/capture.rb
@@ -14,13 +19,25 @@ lib/alsa/pcm/hw_parameters.rb
14
19
  lib/alsa/pcm/native.rb
15
20
  lib/alsa/pcm/playback.rb
16
21
  lib/alsa/pcm/stream.rb
22
+ lib/alsa/pcm/sw_parameters.rb
23
+ lib/alsa/sine.rb
17
24
  log/test.log
25
+ refs/alsa_player
26
+ refs/alsa_player.c
27
+ refs/alsa_player.rb
28
+ refs/alsa_player_async
29
+ refs/alsa_player_async.c
30
+ refs/alsa_player_async.rb
31
+ refs/alsa_recorder.rb
32
+ refs/alsa_recorder_async.rb
33
+ refs/pcm_wrap.rb
18
34
  ruby-alsa.gemspec
19
35
  script/console
20
36
  script/destroy
21
37
  script/generate
22
38
  script/play
23
39
  script/record
40
+ setup.rb
24
41
  spec.html
25
42
  spec/alsa/logger_spec.rb
26
43
  spec/alsa/native_spec.rb
@@ -34,4 +51,5 @@ spec/spec.opts
34
51
  spec/spec_helper.rb
35
52
  spec/support/logger.rb
36
53
  tasks/buildbot.rake
54
+ tasks/debian.rake
37
55
  tasks/rspec.rake
data/debian/changelog ADDED
@@ -0,0 +1,11 @@
1
+ libalsa-ruby (0.7-1) unstable; urgency=low
2
+
3
+ * New upstream release
4
+
5
+ -- Alban Peignier <alban@tryphon.eu> Thu, 14 Oct 2010 10:09:54 +0200
6
+
7
+ libalsa-ruby (0.1-1) unstable; urgency=low
8
+
9
+ * Initial release
10
+
11
+ -- Alban Peignier <alban@tryphon.eu> Sun, 1 Aug 2010 17:57:43 +0200
data/debian/compat ADDED
@@ -0,0 +1 @@
1
+ 5
data/debian/control ADDED
@@ -0,0 +1,18 @@
1
+ Source: libalsa-ruby
2
+ Section: sound
3
+ Priority: optional
4
+ Maintainer: Alban Peignier <alban@tryphon.eu>
5
+ Build-Depends: debhelper, cdbs, ruby-pkg-tools, libsetup-ruby1.8
6
+ Build-Depends-Indep: ruby1.8
7
+ Standards-Version: 3.8.1
8
+ Homepage: http://projects.tryphon.eu/ruby-alsa
9
+
10
+ Package: libalsa-ruby1.8
11
+ Architecture: all
12
+ Depends: ruby1.8, libruby1.8, libasound2, libffi-ruby
13
+ Description: Ruby 1.8 binding for ALSA library.
14
+
15
+ Package: libalsa-ruby
16
+ Architecture: all
17
+ Depends: libalsa-ruby1.8
18
+ Description: Ruby binding for ALSA library.
data/debian/rules ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/make -f
2
+
3
+ include /usr/share/cdbs/1/rules/debhelper.mk
4
+ include /usr/share/ruby-pkg-tools/1/class/ruby-setup-rb.mk
5
+
6
+ install/libalsa-ruby::
7
+ # cp $(DEB_SRCDIR)/debian/alsa-backup.conf debian/$(cdbs_curpkg)/etc/
8
+ echo DEB_RUBY_LIB_PACKAGES
9
+ echo $(DEB_RUBY_LIB_PACKAGES)
10
+ echo DEB_RUBY_REAL_LIB_PACKAGES
11
+ echo $(DEB_RUBY_REAL_LIB_PACKAGES)
12
+ echo DEB_RUBY_DUMMY_LIB_PACKAGES
13
+ echo $(DEB_RUBY_DUMMY_LIB_PACKAGES)
14
+ echo DEB_RUBY_LIB_DOC_PACKAGES
15
+ echo $(DEB_RUBY_LIB_DOC_PACKAGES)
data/lib/alsa.rb CHANGED
@@ -5,15 +5,17 @@ require 'ffi'
5
5
 
6
6
  module ALSA
7
7
 
8
- VERSION = "0.0.5"
8
+ VERSION = "0.7"
9
9
 
10
10
  end
11
11
 
12
12
  require 'logger'
13
+ require 'alsa/ffi_ext'
13
14
  require 'alsa/logger'
14
15
  require 'alsa/native'
15
16
  require 'alsa/pcm/native'
16
17
  require 'alsa/pcm/hw_parameters'
18
+ require 'alsa/pcm/sw_parameters'
17
19
  require 'alsa/pcm/stream'
18
20
  require 'alsa/pcm/capture'
19
21
  require 'alsa/pcm/playback'
@@ -0,0 +1,35 @@
1
+ class Integer
2
+
3
+ def to_pointer
4
+ pointer = MemoryPointer.new(:int)
5
+ pointer.write_int(self)
6
+
7
+ unless block_given?
8
+ pointer
9
+ else
10
+ begin
11
+ return yield pointer
12
+ ensure
13
+ pointer.free
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ class Array
21
+
22
+ def to_pointers
23
+ pointers = map(&:to_pointer)
24
+ unless block_given?
25
+ pointers
26
+ else
27
+ begin
28
+ return yield pointers
29
+ ensure
30
+ pointers.each(&:free)
31
+ end
32
+ end
33
+ end
34
+
35
+ end
data/lib/alsa/native.rb CHANGED
@@ -8,5 +8,10 @@ module ALSA
8
8
  def self.error_code?(response)
9
9
  response and response < 0
10
10
  end
11
+
12
+ callback :async_callback, [:pointer], :void
13
+ attach_function :async_add_pcm_handler, :snd_async_add_pcm_handler, [ :pointer, :pointer, :async_callback, :pointer ], :int
14
+ attach_function :async_handler_get_pcm, :snd_async_handler_get_pcm, [ :pointer ], :pointer
15
+ attach_function :async_handler_get_callback_private, :snd_async_handler_get_callback_private, [ :pointer ], :pointer
11
16
  end
12
17
  end
@@ -2,15 +2,14 @@ module ALSA::PCM
2
2
  class Capture < Stream
3
3
 
4
4
  def native_constant
5
- ALSA::PCM::Native::STREAM_CAPTURE
5
+ ALSA::PCM::Native::Stream::CAPTURE
6
6
  end
7
7
 
8
8
  def read
9
9
  check_handle!
10
10
 
11
- ALSA.logger.debug { "start read with #{hw_params.sample_rate}, #{hw_params.channels} channels"}
11
+ ALSA.logger.debug { "start read with #{hw_params.inspect}"}
12
12
 
13
- ALSA.logger.debug { "allocate #{hw_params.buffer_size_for(buffer_frame_count)} bytes for #{buffer_frame_count} frames" }
14
13
  FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count)) do |buffer|
15
14
  begin
16
15
  read_buffer buffer, buffer_frame_count
@@ -18,6 +17,41 @@ module ALSA::PCM
18
17
  end
19
18
  end
20
19
 
20
+ def read_in_background(&block)
21
+ check_handle!
22
+
23
+ async_handler = FFI::MemoryPointer.new(:pointer)
24
+ buffer = FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count))
25
+
26
+ started = false
27
+
28
+ capture_callback = Proc.new do |async_handler|
29
+ if started
30
+ frame_to_read = buffer_frame_count
31
+ read_buffer buffer, frame_to_read
32
+ yield buffer, frame_to_read
33
+ end
34
+ end
35
+
36
+ ALSA::try_to "add pcm handler" do
37
+ ALSA::Native::async_add_pcm_handler(async_handler, handle, capture_callback, nil)
38
+ end
39
+
40
+ ALSA::try_to "start capture" do
41
+ ALSA::PCM::Native::start(handle)
42
+ end
43
+
44
+ hole_frame_count = ALSA::try_to "read available space" do
45
+ ALSA::PCM::Native::avail_update(self.handle)
46
+ end
47
+ ALSA.logger.debug { "read synchronously #{hole_frame_count} frames"}
48
+ FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(hole_frame_count)) do |hole|
49
+ ALSA::PCM::Native::readi self.handle, hole, hole_frame_count
50
+ end
51
+
52
+ started = true
53
+ end
54
+
21
55
  def read_buffer(buffer, frame_count)
22
56
  check_handle!
23
57
 
@@ -31,6 +65,8 @@ module ALSA::PCM
31
65
  end
32
66
  end
33
67
 
68
+ ALSA.logger.debug { "read frame count: #{read_count}/#{frame_count}"}
69
+
34
70
  missing_frame_count = frame_count - read_count
35
71
  if missing_frame_count > 0
36
72
  ALSA.logger.debug { "re-read missing frame count: #{missing_frame_count}"}
@@ -59,10 +59,62 @@ module ALSA::PCM
59
59
  end
60
60
  end
61
61
 
62
+ def period_time=(period_time)
63
+ ALSA::try_to "set period time (#{period_time})" do
64
+ value = FFI::MemoryPointer.new(:int)
65
+ value.write_int(period_time)
66
+
67
+ dir = FFI::MemoryPointer.new(:int)
68
+ dir.write_int(-1)
69
+ error_code = ALSA::PCM::Native::hw_params_set_period_time_near self.device.handle, self.handle, value, dir
70
+
71
+ value.free
72
+ dir.free
73
+
74
+ error_code
75
+ end
76
+ end
77
+
78
+ def period_time
79
+ value = nil
80
+ ALSA::try_to "get period time" do
81
+ value_pointer = FFI::MemoryPointer.new(:int)
82
+ dir_pointer = FFI::MemoryPointer.new(:int)
83
+ dir_pointer.write_int(0)
84
+
85
+ error_code = ALSA::PCM::Native::hw_params_get_period_time self.handle, value_pointer, dir_pointer
86
+
87
+ value = value_pointer.read_int
88
+
89
+ value_pointer.free
90
+ dir_pointer.free
91
+
92
+ error_code
93
+ end
94
+ value
95
+ end
96
+
97
+ def buffer_time=(buffer_time)
98
+ ALSA::try_to "set buffer time (#{buffer_time})" do
99
+ value = FFI::MemoryPointer.new(:int)
100
+ value.write_int(buffer_time)
101
+
102
+ dir = FFI::MemoryPointer.new(:int)
103
+ dir.write_int(-1)
104
+ error_code = ALSA::PCM::Native::hw_params_set_buffer_time_near self.device.handle, self.handle, value, dir
105
+
106
+ value.free
107
+ dir.free
108
+
109
+ error_code
110
+ end
111
+ end
112
+
62
113
  def sample_rate
63
114
  rate = nil
64
115
  ALSA::try_to "get sample rate" do
65
116
  rate_pointer = FFI::MemoryPointer.new(:int)
117
+
66
118
  dir_pointer = FFI::MemoryPointer.new(:int)
67
119
  dir_pointer.write_int(0)
68
120
 
@@ -106,6 +158,39 @@ module ALSA::PCM
106
158
  channels
107
159
  end
108
160
 
161
+ def period_size
162
+ value = nil
163
+ ALSA::try_to "get period size" do
164
+ value_pointer = FFI::MemoryPointer.new(:int)
165
+ dir_pointer = FFI::MemoryPointer.new(:int)
166
+ dir_pointer.write_int(0)
167
+
168
+ error_code = ALSA::PCM::Native::hw_params_get_period_size self.handle, value_pointer, dir_pointer
169
+
170
+ value = value_pointer.read_int
171
+
172
+ value_pointer.free
173
+ dir_pointer.free
174
+
175
+ error_code
176
+ end
177
+ value
178
+ end
179
+
180
+ def buffer_size
181
+ value = nil
182
+ ALSA::try_to "get buffer size" do
183
+ value_pointer = FFI::MemoryPointer.new(:int)
184
+ error_code = ALSA::PCM::Native::hw_params_get_buffer_size self.handle, value_pointer
185
+ value = value_pointer.read_int
186
+
187
+ value_pointer.free
188
+
189
+ error_code
190
+ end
191
+ value
192
+ end
193
+
109
194
  def buffer_size_for(frame_count)
110
195
  ALSA::PCM::Native::format_size(self.sample_format, frame_count) * self.channels
111
196
  end
@@ -120,5 +205,9 @@ module ALSA::PCM
120
205
  end
121
206
  end
122
207
 
208
+ def inspect
209
+ "#<ALSA::PCM::HwParameters:#{object_id} sample_rate=#{sample_rate}, channels=#{channels}, period_time=#{period_time}, period_size=#{period_size}, buffer_size=#{buffer_size}>"
210
+ end
211
+
123
212
  end
124
213
  end
@@ -4,14 +4,19 @@ module ALSA::PCM
4
4
  extend FFI::Library
5
5
  ffi_lib "libasound.so.2"
6
6
 
7
- STREAM_PLAYBACK = 0
8
- STREAM_CAPTURE = 1
7
+ module Stream
8
+ PLAYBACK = 0
9
+ CAPTURE = 1
10
+ end
9
11
 
10
12
  BLOCK = 0
11
13
  attach_function :open, :snd_pcm_open, [:pointer, :string, :int, :int], :int
12
14
  attach_function :prepare, :snd_pcm_prepare, [ :pointer ], :int
13
15
  attach_function :close, :snd_pcm_close, [:pointer], :int
14
16
 
17
+ attach_function :wait, :snd_pcm_wait, [:pointer, :int], :int
18
+ attach_function :avail_update, :snd_pcm_avail_update, [:pointer], :int
19
+
15
20
  attach_function :readi, :snd_pcm_readi, [ :pointer, :pointer, :ulong ], :long
16
21
  attach_function :writei, :snd_pcm_writei, [ :pointer, :pointer, :ulong ], :long
17
22
 
@@ -43,10 +48,25 @@ module ALSA::PCM
43
48
  attach_function :hw_params_get_rate, :snd_pcm_hw_params_get_rate, [ :pointer, :pointer, :pointer ], :int
44
49
  attach_function :hw_params_set_rate_near, :snd_pcm_hw_params_set_rate_near, [ :pointer, :pointer, :pointer, :pointer ], :int
45
50
  attach_function :hw_params_set_channels, :snd_pcm_hw_params_set_channels, [ :pointer, :pointer, :uint ], :int
46
- attach_function :hw_params_get_channels, :snd_pcm_hw_params_get_format, [ :pointer, :pointer ], :int
51
+ attach_function :hw_params_get_channels, :snd_pcm_hw_params_get_channels, [ :pointer, :pointer ], :int
47
52
  attach_function :hw_params_set_periods, :snd_pcm_hw_params_set_periods, [ :pointer, :pointer, :uint, :int ], :int
53
+ attach_function :hw_params_set_period_time_near, :snd_pcm_hw_params_set_period_time_near, [ :pointer, :pointer, :pointer, :pointer ], :int
54
+ attach_function :hw_params_get_period_time, :snd_pcm_hw_params_get_period_time, [ :pointer, :pointer, :pointer ], :int
55
+ attach_function :hw_params_get_period_size, :snd_pcm_hw_params_get_period_size, [ :pointer, :pointer, :pointer ], :int
56
+ attach_function :hw_params_get_buffer_size, :snd_pcm_hw_params_get_buffer_size, [ :pointer, :pointer ], :int
57
+ attach_function :hw_params_set_buffer_time_near, :snd_pcm_hw_params_set_buffer_time_near, [ :pointer, :pointer, :pointer, :pointer ], :int
58
+
59
+ attach_function :sw_params, :snd_pcm_sw_params, [:pointer, :pointer], :int
60
+ attach_function :sw_params_malloc, :snd_pcm_sw_params_malloc, [:pointer], :int
61
+ attach_function :sw_params_free, :snd_pcm_sw_params_free, [:pointer], :int
62
+ attach_function :sw_params_current, :snd_pcm_sw_params_current, [ :pointer, :pointer ], :int
63
+ attach_function :sw_params_set_avail_min, :snd_pcm_sw_params_set_avail_min, [ :pointer, :pointer, :uint ], :int
64
+ attach_function :sw_params_get_avail_min, :snd_pcm_sw_params_get_avail_min, [ :pointer, :pointer ], :int
48
65
 
49
66
  attach_function :format_size, :snd_pcm_format_size, [ :int, :uint ], :int
50
67
  attach_function :bytes_to_frames, :snd_pcm_bytes_to_frames, [ :pointer, :int ], :int
68
+
69
+ attach_function :start, :snd_pcm_start, [ :pointer ], :int
70
+
51
71
  end
52
72
  end
@@ -2,7 +2,7 @@ module ALSA::PCM
2
2
  class Playback < Stream
3
3
 
4
4
  def native_constant
5
- ALSA::PCM::Native::STREAM_PLAYBACK
5
+ ALSA::PCM::Native::Stream::PLAYBACK
6
6
  end
7
7
 
8
8
  def write_buffer(buffer, frame_count)
@@ -11,28 +11,75 @@ module ALSA::PCM
11
11
  write_count = ALSA::try_to "write in audio interface" do
12
12
  response = ALSA::PCM::Native::writei(self.handle, buffer, frame_count)
13
13
  if ALSA::Native::error_code?(response)
14
- ALSA.logger.warn { "try to recover '#{ALSA::Native::strerror(response)}' on read"}
14
+ ALSA.logger.warn { "try to recover '#{ALSA::Native::strerror(response)}' on write"}
15
15
  ALSA::PCM::Native::pcm_recover(self.handle, response, 1)
16
16
  else
17
17
  response
18
18
  end
19
19
  end
20
20
 
21
+ ALSA.logger.debug { "write frame count: #{write_count}/#{frame_count}"}
22
+
21
23
  missing_frame_count = frame_count - write_count
22
24
  if missing_frame_count > 0
23
25
  ALSA.logger.debug { "missing wroted frame count: #{missing_frame_count}"}
24
26
  end
25
27
  end
26
28
 
29
+ def write_in_background(&block)
30
+ check_handle!
31
+
32
+ async_handler = FFI::MemoryPointer.new(:pointer)
33
+ buffer = FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count))
34
+
35
+ started = false
36
+
37
+ playback_callback = Proc.new do |async_handler|
38
+ if started
39
+ audio_content = yield(buffer.size)
40
+ buffer.write_string audio_content
41
+
42
+ read_frame_count =
43
+ if audio_content.size == buffer.size
44
+ buffer_frame_count
45
+ else
46
+ hw_params.frame_count_for(audio_content.size)
47
+ end
48
+
49
+ write_buffer buffer, read_frame_count
50
+ end
51
+ end
52
+
53
+ ALSA::try_to "add pcm handler" do
54
+ ALSA::Native::async_add_pcm_handler(async_handler, handle, playback_callback, nil)
55
+ end
56
+
57
+ ALSA::try_to "start playback" do
58
+ ALSA::PCM::Native::start(handle)
59
+ end
60
+
61
+ silent_frame_count = ALSA::try_to "read available space" do
62
+ ALSA::PCM::Native::avail_update(self.handle)
63
+ end
64
+ ALSA.logger.debug { "write synchronously a silence of #{silent_frame_count} frames"}
65
+ FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(silent_frame_count)) do |silent|
66
+ ALSA::PCM::Native::writei self.handle, silent, silent_frame_count
67
+ end
68
+
69
+ started = true
70
+ end
71
+
27
72
  def write
28
73
  check_handle!
29
74
 
75
+ ALSA.logger.debug { "start write with #{hw_params.inspect}" }
76
+
30
77
  FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count)) do |buffer|
31
78
  while audio_content = yield(buffer.size)
32
79
  buffer.write_string audio_content
33
80
 
34
81
  read_frame_count =
35
- if audio_content.size == buffer.size
82
+ if audio_content.size == buffer.size
36
83
  buffer_frame_count
37
84
  else
38
85
  hw_params.frame_count_for(audio_content.size)