sound 0.0.9 → 0.1.0
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 +8 -8
- data/examples/example.rb +1 -1
- data/lib/os/os.rb +20 -15
- data/lib/sound.rb +17 -19
- data/lib/sound/data.rb +0 -3
- data/lib/sound/device.rb +72 -33
- data/lib/sound/device_library.rb +19 -0
- data/lib/sound/device_library/alsa.rb +240 -0
- data/lib/sound/device_library/base.rb +44 -0
- data/lib/sound/device_library/mmlib.rb +237 -0
- data/lib/sound/format.rb +8 -29
- data/lib/sound/format_library.rb +15 -0
- data/lib/sound/format_library/alsa.rb +10 -0
- data/lib/sound/format_library/base.rb +16 -0
- data/lib/sound/format_library/mmlib.rb +61 -0
- metadata +14 -14
- data/lib/sound/alsa.rb +0 -211
- data/lib/sound/win32.rb +0 -150
data/lib/sound/alsa.rb
DELETED
@@ -1,211 +0,0 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module Sound
|
4
|
-
module ALSA
|
5
|
-
|
6
|
-
class Handle
|
7
|
-
def initialize
|
8
|
-
@handle = FFI::MemoryPointer.new(:pointer)
|
9
|
-
end
|
10
|
-
def pointer
|
11
|
-
@handle
|
12
|
-
end
|
13
|
-
def id
|
14
|
-
@handle.read_pointer
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
SND_PCM_STREAM_PLAYBACK = 0
|
19
|
-
SND_PCM_STREAM_CAPTURE = 1
|
20
|
-
DEFAULT_DEVICE_ID = "default"
|
21
|
-
|
22
|
-
extend FFI::Library
|
23
|
-
ffi_lib 'asound'
|
24
|
-
ffi_convention :stdcall
|
25
|
-
|
26
|
-
attach_function :snd_pcm_open, [:pointer, :string, :int, :int], :int
|
27
|
-
attach_function :snd_pcm_close, [:pointer], :int
|
28
|
-
attach_function :snd_pcm_drain, [:pointer], :int
|
29
|
-
attach_function :snd_pcm_prepare, [:pointer], :int
|
30
|
-
attach_function :write_noninterleaved, :snd_pcm_writen, [:pointer, :pointer, :ulong], :long
|
31
|
-
attach_function :snd_pcm_writei, [:pointer, :pointer, :ulong], :long
|
32
|
-
attach_function :snd_pcm_hw_params_malloc, [:pointer], :int
|
33
|
-
attach_function :snd_pcm_hw_params_any, [:pointer, :pointer], :int
|
34
|
-
attach_function :snd_pcm_hw_params_set_access, [:pointer, :pointer, :int], :int
|
35
|
-
attach_function :snd_pcm_hw_params_set_format, [:pointer, :pointer, :int], :int
|
36
|
-
attach_function :snd_pcm_hw_params_set_rate, [:pointer, :pointer, :uint, :int], :int
|
37
|
-
attach_function :snd_pcm_hw_params_set_channels, [:pointer, :pointer, :int], :int
|
38
|
-
attach_function :snd_pcm_hw_params, [:pointer, :pointer], :int
|
39
|
-
attach_function :snd_pcm_hw_params_free, [:pointer], :void
|
40
|
-
|
41
|
-
def snd_pcm_open(*args)
|
42
|
-
output = `aplay -l 2>&1`
|
43
|
-
if output.match(/no soundcard/m)
|
44
|
-
raise NoDeviceError, "No sound devices present"
|
45
|
-
elsif output.match(/not found/m)
|
46
|
-
raise NoDependencyError, "aplay is not present in your environment. Install alsa-utils package for audio playback."
|
47
|
-
else
|
48
|
-
snd_pcm_open(*args)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def open_device
|
53
|
-
begin
|
54
|
-
snd_pcm_open(handle.pointer, id, 0, ASYNC)
|
55
|
-
rescue NoDeviceError
|
56
|
-
Sound.no_device = true
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def prepare_buffer
|
61
|
-
|
62
|
-
unless Sound.no_device
|
63
|
-
buffer_length
|
64
|
-
|
65
|
-
snd_pcm_hw_params_malloc(params_handle.pointer)
|
66
|
-
snd_pcm_hw_params_any(handle.id, params_handle.id)
|
67
|
-
|
68
|
-
snd_pcm_hw_params_set_access(handle.id, params_handle.id, SND_PCM_ACCESS_RW_INTERLEAVED)
|
69
|
-
set_formsnd_pcm_hw_params_set_formatat(handle.id, params_handle.id, SND_PCM_FORMAT_S16_LE)
|
70
|
-
# need to change this to set_rate_near at some point
|
71
|
-
snd_pcm_hw_params_set_rate(handle.id, params_handle.id, data.format.sample_rate, 0)
|
72
|
-
snd_pcm_hw_params_set_channels(handle.id, params_handle.id, 1)
|
73
|
-
|
74
|
-
snd_pcm_hw_params(handle.id, params_handle.id)
|
75
|
-
snd_pcm_hw_params_free(params_handle.id)
|
76
|
-
|
77
|
-
snd_pcm_prepare(handle.id)
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
def write_to_device
|
83
|
-
snd_pcm_writei(handle.id, data_buffer, buffer_length) unless Sound.no_device
|
84
|
-
end
|
85
|
-
|
86
|
-
def unprepare_buffer
|
87
|
-
snd_pcm_drain(handle.id) unless Sound.no_device
|
88
|
-
end
|
89
|
-
|
90
|
-
def close_device
|
91
|
-
snd_pcm_close(handle.id) unless Sound.no_device
|
92
|
-
end
|
93
|
-
|
94
|
-
def handle
|
95
|
-
Thread.current[:handle] ||= Handle.new
|
96
|
-
end
|
97
|
-
|
98
|
-
def params_handle
|
99
|
-
Thread.current[:params_handle] ||= Handle.new
|
100
|
-
end
|
101
|
-
|
102
|
-
def data
|
103
|
-
Thread.current[:data]
|
104
|
-
end
|
105
|
-
|
106
|
-
def data_buffer
|
107
|
-
Thread.current[:data_buffer] ||= FFI::MemoryPointer.new(:int, data.pcm_data.size).write_array_of_int data.pcm_data
|
108
|
-
end
|
109
|
-
|
110
|
-
def buffer_length
|
111
|
-
Thread.current[:buffer_length] ||= data_buffer.size/2
|
112
|
-
end
|
113
|
-
|
114
|
-
SND_PCM_ASYNC = 2
|
115
|
-
ASYNC = SND_PCM_ASYNC
|
116
|
-
#snd_pcm formats
|
117
|
-
# Unknown
|
118
|
-
SND_PCM_FORMAT_UNKNOWN = -1
|
119
|
-
# Signed 8 bit
|
120
|
-
SND_PCM_FORMAT_S8 = 0
|
121
|
-
# Unsigned 8 bit
|
122
|
-
SND_PCM_FORMAT_U8 = 1
|
123
|
-
# Signed 16 bit Little Endian
|
124
|
-
SND_PCM_FORMAT_S16_LE = 2
|
125
|
-
# Signed 16 bit Big Endian
|
126
|
-
SND_PCM_FORMAT_S16_BE = 3
|
127
|
-
# Unsigned 16 bit Little Endian
|
128
|
-
SND_PCM_FORMAT_U16_LE = 4
|
129
|
-
# Unsigned 16 bit Big Endian
|
130
|
-
SND_PCM_FORMAT_U16_BE = 5
|
131
|
-
# Signed 24 bit Little Endian using low three bytes in 32-bit word
|
132
|
-
SND_PCM_FORMAT_S24_LE = 6
|
133
|
-
# Signed 24 bit Big Endian using low three bytes in 32-bit word
|
134
|
-
SND_PCM_FORMAT_S24_BE = 7
|
135
|
-
# Unsigned 24 bit Little Endian using low three bytes in 32-bit word
|
136
|
-
SND_PCM_FORMAT_U24_LE = 8
|
137
|
-
# Unsigned 24 bit Big Endian using low three bytes in 32-bit word
|
138
|
-
SND_PCM_FORMAT_U24_BE = 9
|
139
|
-
# Signed 32 bit Little Endian
|
140
|
-
SND_PCM_FORMAT_S32_LE = 10
|
141
|
-
# Signed 32 bit Big Endian
|
142
|
-
SND_PCM_FORMAT_S32_BE = 11
|
143
|
-
# Unsigned 32 bit Little Endian
|
144
|
-
SND_PCM_FORMAT_U32_LE = 12
|
145
|
-
# Unsigned 32 bit Big Endian
|
146
|
-
SND_PCM_FORMAT_U32_BE = 13
|
147
|
-
# Float 32 bit Little Endian, Range -1.0 to 1.0
|
148
|
-
SND_PCM_FORMAT_FLOAT_LE = 14
|
149
|
-
# Float 32 bit Big Endian, Range -1.0 to 1.0
|
150
|
-
SND_PCM_FORMAT_FLOAT_BE = 15
|
151
|
-
# Float 64 bit Little Endian, Range -1.0 to 1.0
|
152
|
-
SND_PCM_FORMAT_FLOAT64_LE = 16
|
153
|
-
# Float 64 bit Big Endian, Range -1.0 to 1.0
|
154
|
-
SND_PCM_FORMAT_FLOAT64_BE = 17
|
155
|
-
# IEC-958 Little Endian
|
156
|
-
SND_PCM_FORMAT_IEC958_SUBFRAME_LE = 18
|
157
|
-
# IEC-958 Big Endian
|
158
|
-
SND_PCM_FORMAT_IEC958_SUBFRAME_BE = 19
|
159
|
-
# Mu-Law
|
160
|
-
SND_PCM_FORMAT_MU_LAW = 20
|
161
|
-
# A-Law
|
162
|
-
SND_PCM_FORMAT_A_LAW = 21
|
163
|
-
# Ima-ADPCM
|
164
|
-
SND_PCM_FORMAT_IMA_ADPCM = 22
|
165
|
-
# MPEG
|
166
|
-
SND_PCM_FORMAT_MPEG = 23
|
167
|
-
# GSM
|
168
|
-
SND_PCM_FORMAT_GSM = 24
|
169
|
-
# Special
|
170
|
-
SND_PCM_FORMAT_SPECIAL = 31
|
171
|
-
# Signed 24bit Little Endian in 3bytes format
|
172
|
-
SND_PCM_FORMAT_S24_3LE = 32
|
173
|
-
# Signed 24bit Big Endian in 3bytes format
|
174
|
-
SND_PCM_FORMAT_S24_3BE = 33
|
175
|
-
# Unsigned 24bit Little Endian in 3bytes format
|
176
|
-
SND_PCM_FORMAT_U24_3LE = 34
|
177
|
-
# Unsigned 24bit Big Endian in 3bytes format
|
178
|
-
SND_PCM_FORMAT_U24_3BE = 35
|
179
|
-
# Signed 20bit Little Endian in 3bytes format
|
180
|
-
SND_PCM_FORMAT_S20_3LE = 36
|
181
|
-
# Signed 20bit Big Endian in 3bytes format
|
182
|
-
SND_PCM_FORMAT_S20_3BE = 37
|
183
|
-
# Unsigned 20bit Little Endian in 3bytes format
|
184
|
-
SND_PCM_FORMAT_U20_3LE = 38
|
185
|
-
# Unsigned 20bit Big Endian in 3bytes format
|
186
|
-
SND_PCM_FORMAT_U20_3BE = 39
|
187
|
-
# Signed 18bit Little Endian in 3bytes format
|
188
|
-
SND_PCM_FORMAT_S18_3LE = 40
|
189
|
-
# Signed 18bit Big Endian in 3bytes format
|
190
|
-
SND_PCM_FORMAT_S18_3BE = 41
|
191
|
-
# Unsigned 18bit Little Endian in 3bytes format
|
192
|
-
SND_PCM_FORMAT_U18_3LE = 42
|
193
|
-
# Unsigned 18bit Big Endian in 3bytes format
|
194
|
-
SND_PCM_FORMAT_U18_3BE = 43
|
195
|
-
SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_U18_3BE
|
196
|
-
|
197
|
-
#snd_pcm access
|
198
|
-
# mmap access with simple interleaved channels
|
199
|
-
SND_PCM_ACCESS_MMAP_INTERLEAVED = 0
|
200
|
-
# mmap access with simple non interleaved channels
|
201
|
-
SND_PCM_ACCESS_MMAP_NONINTERLEAVED = 1
|
202
|
-
# mmap access with complex placement
|
203
|
-
SND_PCM_ACCESS_MMAP_COMPLEX = 2
|
204
|
-
# snd_pcm_readi/snd_pcm_writei access
|
205
|
-
SND_PCM_ACCESS_RW_INTERLEAVED = 3
|
206
|
-
# snd_pcm_readn/snd_pcm_writen access
|
207
|
-
SND_PCM_ACCESS_RW_NONINTERLEAVED = 4
|
208
|
-
SND_PCM_ACCESS_LAST = SND_PCM_ACCESS_RW_NONINTERLEAVED
|
209
|
-
|
210
|
-
end
|
211
|
-
end
|
data/lib/sound/win32.rb
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module Sound
|
4
|
-
module Win32
|
5
|
-
|
6
|
-
class Handle
|
7
|
-
def initialize
|
8
|
-
@handle = HWAVEOUT.new
|
9
|
-
end
|
10
|
-
def pointer
|
11
|
-
@handle.pointer
|
12
|
-
end
|
13
|
-
def id
|
14
|
-
@handle[:i]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
extend FFI::Library
|
19
|
-
|
20
|
-
typedef :ulong, :dword
|
21
|
-
typedef :uintptr_t, :hwaveout
|
22
|
-
typedef :uint, :mmresult
|
23
|
-
|
24
|
-
ffi_lib :winmm
|
25
|
-
|
26
|
-
attach_function :waveOutOpen, [:pointer, :uint, :pointer, :dword, :dword, :dword], :mmresult
|
27
|
-
attach_function :waveOutPrepareHeader, [:hwaveout, :pointer, :uint], :mmresult
|
28
|
-
attach_function :waveOutWrite, [:hwaveout, :pointer, :uint], :mmresult
|
29
|
-
attach_function :waveOutUnprepareHeader, [:hwaveout, :pointer, :uint], :mmresult
|
30
|
-
attach_function :waveOutClose, [:hwaveout], :mmresult
|
31
|
-
|
32
|
-
WAVE_FORMAT_PCM = 1
|
33
|
-
WAVE_MAPPER = -1
|
34
|
-
DEFAULT_DEVICE_ID = WAVE_MAPPER
|
35
|
-
|
36
|
-
def open_device
|
37
|
-
waveOutOpen(handle.pointer, id, data.format.pointer, 0, 0, 0)
|
38
|
-
end
|
39
|
-
|
40
|
-
def prepare_buffer
|
41
|
-
waveOutPrepareHeader(handle.id, header.pointer, header.size)
|
42
|
-
end
|
43
|
-
|
44
|
-
def write_to_device
|
45
|
-
waveOutWrite(handle.id, header.pointer, header.size)
|
46
|
-
end
|
47
|
-
|
48
|
-
def unprepare_buffer
|
49
|
-
while waveOutUnprepareHeader(handle.id, header.pointer, header.size) == 33
|
50
|
-
sleep 0.001
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def close_device
|
55
|
-
waveOutClose(handle.id)
|
56
|
-
end
|
57
|
-
|
58
|
-
def handle
|
59
|
-
Thread.current[:handle] ||= Handle.new
|
60
|
-
end
|
61
|
-
|
62
|
-
def data
|
63
|
-
Thread.current[:data]
|
64
|
-
end
|
65
|
-
|
66
|
-
def header
|
67
|
-
Thread.current[:header] ||= WAVEHDR.new(data_buffer, buffer_length)
|
68
|
-
end
|
69
|
-
|
70
|
-
def data_buffer
|
71
|
-
Thread.current[:data_buffer] ||= FFI::MemoryPointer.new(:int, data.pcm_data.size).write_array_of_int data.pcm_data
|
72
|
-
end
|
73
|
-
|
74
|
-
def buffer_length
|
75
|
-
Thread.current[:buffer_length] ||= data.format.avg_bps*data.duration/1000
|
76
|
-
end
|
77
|
-
|
78
|
-
# Define an HWAVEOUT struct for use by all the waveOut functions.
|
79
|
-
# It is a handle to a waveOut stream, so starting up multiple
|
80
|
-
# streams using different handles allows for simultaneous playback.
|
81
|
-
# You never need to actually look at the struct, C takes care of
|
82
|
-
# its value.
|
83
|
-
#
|
84
|
-
class HWAVEOUT < FFI::Struct
|
85
|
-
layout :i, :int
|
86
|
-
end
|
87
|
-
|
88
|
-
# Define WAVEFORMATEX which defines the format (PCM in this case)
|
89
|
-
# and various properties like sampling rate, number of channels, etc.
|
90
|
-
#
|
91
|
-
class WAVEFORMATEX < FFI::Struct
|
92
|
-
|
93
|
-
# Initializes struct with sensible defaults for most commonly used
|
94
|
-
# values. While setting these manually is possible, please be
|
95
|
-
# sure you know what changes will result in, as an incorrectly
|
96
|
-
# set struct will result in unpredictable behavior.
|
97
|
-
#
|
98
|
-
def initialize(nSamplesPerSec = 44100, wBitsPerSample = 16, nChannels = 1, cbSize = 0)
|
99
|
-
self[:wFormatTag] = WAVE_FORMAT_PCM
|
100
|
-
self[:nChannels] = nChannels
|
101
|
-
self[:nSamplesPerSec] = nSamplesPerSec
|
102
|
-
self[:wBitsPerSample] = wBitsPerSample
|
103
|
-
self[:cbSize] = cbSize
|
104
|
-
self[:nBlockAlign] = (self[:wBitsPerSample] >> 3) * self[:nChannels]
|
105
|
-
self[:nAvgBytesPerSec] = self[:nBlockAlign] * self[:nSamplesPerSec]
|
106
|
-
end
|
107
|
-
|
108
|
-
layout(
|
109
|
-
:wFormatTag, :ushort,
|
110
|
-
:nChannels, :ushort,
|
111
|
-
:nSamplesPerSec, :ulong,
|
112
|
-
:nAvgBytesPerSec, :ulong,
|
113
|
-
:nBlockAlign, :ushort,
|
114
|
-
:wBitsPerSample, :ushort,
|
115
|
-
:cbSize, :ushort
|
116
|
-
)
|
117
|
-
end
|
118
|
-
|
119
|
-
#define WAVEHDR which is a header to a block of audio
|
120
|
-
#lpData is a pointer to the block of native memory that,
|
121
|
-
# in this case, is an integer array of PCM data
|
122
|
-
|
123
|
-
class WAVEHDR < FFI::Struct
|
124
|
-
|
125
|
-
# Initializes struct with sensible defaults for most commonly used
|
126
|
-
# values. While setting these manually is possible, please be
|
127
|
-
# sure you know what changes will result in, as an incorrectly
|
128
|
-
# set struct will result in unpredictable behavior.
|
129
|
-
#
|
130
|
-
def initialize(lpData, dwBufferLength, dwFlags = 0, dwLoops = 1)
|
131
|
-
self[:lpData] = lpData
|
132
|
-
self[:dwBufferLength] = dwBufferLength
|
133
|
-
self[:dwFlags] = dwFlags
|
134
|
-
self[:dwLoops] = dwLoops
|
135
|
-
end
|
136
|
-
|
137
|
-
layout(
|
138
|
-
:lpData, :pointer,
|
139
|
-
:dwBufferLength, :ulong,
|
140
|
-
:dwBytesRecorded, :ulong,
|
141
|
-
:dwUser, :ulong,
|
142
|
-
:dwFlags, :ulong,
|
143
|
-
:dwLoops, :ulong,
|
144
|
-
:lpNext, :pointer,
|
145
|
-
:reserved, :ulong
|
146
|
-
)
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
end
|