radio 0.0.2 → 0.0.3

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.
@@ -1,102 +0,0 @@
1
- # Copyright 2012 The ham21/radio Authors
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
-
16
- begin
17
- require 'coreaudio'
18
- rescue LoadError => e
19
- end
20
-
21
-
22
- class Radio
23
- module Input
24
-
25
- class CoreAudio
26
-
27
- def self.status
28
- if defined? ::CoreAudio
29
- return "Loaded: %d input devices" % sources.count
30
- end
31
- unless defined? @is_darwin
32
- @is_darwin = (`uname`.strip == 'Darwin') rescue false
33
- end
34
- return "Unsupported: requires Apple OS" unless @is_darwin
35
- return 'Unavailable: gem install coreaudio'
36
- end
37
-
38
- # I don't see a way to automatically set the CoreAudio CODEC rate.
39
- # We'll present the nominal_rate as the only option.
40
- def self.sources
41
- return {} unless defined? ::CoreAudio
42
- result = {}
43
- ::CoreAudio.devices.each do |dev|
44
- channels = dev.input_stream.channels
45
- if channels > 0
46
- result[dev.devid] = {
47
- name: dev.name,
48
- rates: [dev.nominal_rate.to_i],
49
- channels: channels
50
- }
51
- end
52
- end
53
- result
54
- end
55
-
56
- attr_reader :rate, :channels
57
-
58
- # id is the key from the sources hash.
59
- # rate is the desired hardware rate. do not decimate/interpolate here.
60
- def initialize id, rate, channel_i, channel_q
61
- @device = ::CoreAudio::AudioDevice.new id.to_i
62
- @rate = @device.nominal_rate
63
- raise 'I channel fail' unless channel_i < @device.input_stream.channels
64
- @channel_i = channel_i
65
- @channels = 1
66
- if channel_q
67
- raise 'Q channel fail' unless channel_q < @device.input_stream.channels
68
- @channel_q = channel_q
69
- extend IQ
70
- @channels = 2
71
- end
72
- # Half second of buffer
73
- coreaudio_input_buffer_size = @channels * rate / 2
74
- @buf = @device.input_buffer coreaudio_input_buffer_size
75
- @buf.start
76
- end
77
-
78
- # This is called on its own thread in Rig and is expected to block.
79
- def call samples
80
- # CoreAudio range of -32767..32767 makes easy conversion to -1.0..1.0
81
- @buf.read(samples)[@channel_i,true].to_f.div!(32767)
82
- end
83
-
84
- # Once stopped, rig won't attempt starting again on this object.
85
- def stop
86
- @buf.stop
87
- end
88
-
89
- module IQ
90
- def call samples
91
- b = @buf.read samples
92
- c_out = NArray.scomplex samples
93
- c_out[0..-1] = b[@channel_i,true].to_f.div!(32767)
94
- c_out.imag = b[@channel_q,true].to_f.div!(32767)
95
- c_out
96
- end
97
- end
98
-
99
- end
100
-
101
- end
102
- end
@@ -1,292 +0,0 @@
1
- # These are from LGPL licensed programs if they are even copyrightable.
2
- # They will be removed after I implement remez in Ruby.
3
-
4
-
5
- class Radio
6
- class PSK31
7
-
8
- # 48000 to 8000 decimation
9
- FIR_DEC6 = [
10
- -0.001026086585,
11
- -0.002131424398,
12
- -0.003473651912,
13
- -0.005415991401,
14
- -0.007094896149,
15
- -0.008685456592,
16
- -0.009325598368,
17
- -0.009096149588,
18
- -0.007453841473,
19
- -0.004787743788,
20
- -0.001155271744,
21
- 0.002594565142,
22
- 0.005930466661,
23
- 0.007902971637,
24
- 0.008117998323,
25
- 0.006209532708,
26
- 0.002565394219,
27
- -0.002211033166,
28
- -0.006928668876,
29
- -0.010456837484,
30
- -0.011638240040,
31
- -0.009915015895,
32
- -0.005261804435,
33
- 0.001469200215,
34
- 0.008865519609,
35
- 0.015027698257,
36
- 0.018157576105,
37
- 0.016869453853,
38
- 0.010745489111,
39
- 0.000474997075,
40
- -0.012015135186,
41
- -0.023901641616,
42
- -0.031878023716,
43
- -0.032876349281,
44
- -0.024689692215,
45
- -0.006586586958,
46
- 0.020417464549,
47
- 0.053543134171,
48
- 0.088652482149,
49
- 0.120891532319,
50
- 0.145553464727,
51
- 0.158910442030,
52
- 0.158910442030,
53
- 0.145553464727,
54
- 0.120891532319,
55
- 0.088652482149,
56
- 0.053543134171,
57
- 0.020417464549,
58
- -0.006586586958,
59
- -0.024689692215,
60
- -0.032876349281,
61
- -0.031878023716,
62
- -0.023901641616,
63
- -0.012015135186,
64
- 0.000474997075,
65
- 0.010745489111,
66
- 0.016869453853,
67
- 0.018157576105,
68
- 0.015027698257,
69
- 0.008865519609,
70
- 0.001469200215,
71
- -0.005261804435,
72
- -0.009915015895,
73
- -0.011638240040,
74
- -0.010456837484,
75
- -0.006928668876,
76
- -0.002211033166,
77
- 0.002565394219,
78
- 0.006209532708,
79
- 0.008117998323,
80
- 0.007902971637,
81
- 0.005930466661,
82
- 0.002594565142,
83
- -0.001155271744,
84
- -0.004787743788,
85
- -0.007453841473,
86
- -0.009096149588,
87
- -0.009325598368,
88
- -0.008685456592,
89
- -0.007094896149,
90
- -0.005415991401,
91
- -0.003473651912,
92
- -0.002131424398,
93
- -0.001026086585
94
- ].freeze
95
-
96
-
97
- # 64-tap raised-cosine
98
- FIR_DEC16 = [
99
- 0.000000,
100
- 0.000038,
101
- 0.000150,
102
- 0.000336,
103
- 0.000595,
104
- 0.000922,
105
- 0.001317,
106
- 0.001773,
107
- 0.002288,
108
- 0.002856,
109
- 0.003472,
110
- 0.004130,
111
- 0.004823,
112
- 0.005545,
113
- 0.006288,
114
- 0.007047,
115
- 0.007812,
116
- 0.008578,
117
- 0.009337,
118
- 0.010080,
119
- 0.010802,
120
- 0.011495,
121
- 0.012153,
122
- 0.012769,
123
- 0.013337,
124
- 0.013852,
125
- 0.014308,
126
- 0.014703,
127
- 0.015030,
128
- 0.015289,
129
- 0.015475,
130
- 0.015587,
131
- 0.015625,
132
- 0.015587,
133
- 0.015475,
134
- 0.015289,
135
- 0.015030,
136
- 0.014703,
137
- 0.014308,
138
- 0.013852,
139
- 0.013337,
140
- 0.012769,
141
- 0.012153,
142
- 0.011495,
143
- 0.010802,
144
- 0.010080,
145
- 0.009337,
146
- 0.008578,
147
- 0.007813,
148
- 0.007047,
149
- 0.006288,
150
- 0.005545,
151
- 0.004823,
152
- 0.004130,
153
- 0.003472,
154
- 0.002856,
155
- 0.002288,
156
- 0.001773,
157
- 0.001317,
158
- 0.000922,
159
- 0.000595,
160
- 0.000336,
161
- 0.000150,
162
- 0.000038
163
- ].freeze
164
-
165
-
166
- # Design method: Parks-McClellan method
167
- # Number of taps = 35
168
- # Number of bands = 2
169
- # Band Lower Upper Value Weight
170
- # edge edge
171
- # 1 0.0 .0125 1.0 1
172
- # 2 .125 .5 .000001 10
173
- FIR_DEC = [
174
- -0.00021203644,
175
- -0.00070252426,
176
- -0.0016680526,
177
- -0.0031934799,
178
- -0.0051899752,
179
- -0.0072862086,
180
- -0.0087714235,
181
- -0.0086272102,
182
- -0.0056735648,
183
- 0.0011784719,
184
- 0.01261353,
185
- 0.028615709,
186
- 0.048280707,
187
- 0.069812051,
188
- 0.090735013,
189
- 0.10830381,
190
- 0.12001897,
191
- 0.12413413,
192
- 0.12001897,
193
- 0.10830381,
194
- 0.090735013,
195
- 0.069812051,
196
- 0.048280707,
197
- 0.028615709,
198
- 0.01261353,
199
- 0.0011784719,
200
- -0.0056735648,
201
- -0.0086272102,
202
- -0.0087714235,
203
- -0.0072862086,
204
- -0.0051899752,
205
- -0.0031934799,
206
- -0.0016680526,
207
- -0.00070252426,
208
- -0.00021203644
209
- ].freeze
210
-
211
-
212
- # 16 Hz bw LP filter for data recovery
213
- # Filter type: Multiband filter
214
- # Design method: Parks-McClellan method
215
- # Number of taps = 65
216
- # Number of bands = 2
217
- # Band Lower Upper Value Weight
218
- # edge edge
219
- #
220
- # 1 0.0 .03125 1. 1.
221
- # 2 .0625 .5 .0000 286.
222
- FIR_BIT = [
223
- 4.3453566e-005,
224
- -0.00049122414,
225
- -0.00078771292,
226
- -0.0013507826,
227
- -0.0021287814,
228
- -0.003133466,
229
- -0.004366817,
230
- -0.0058112187,
231
- -0.0074249976,
232
- -0.0091398882,
233
- -0.010860157,
234
- -0.012464086,
235
- -0.013807772,
236
- -0.014731191,
237
- -0.015067057,
238
- -0.014650894,
239
- -0.013333425,
240
- -0.01099166,
241
- -0.0075431246,
242
- -0.0029527849,
243
- 0.0027546292,
244
- 0.0094932775,
245
- 0.017113308,
246
- 0.025403511,
247
- 0.034099681,
248
- 0.042895839,
249
- 0.051458575,
250
- 0.059444853,
251
- 0.066521003,
252
- 0.072381617,
253
- 0.076767694,
254
- 0.079481619,
255
- 0.080420311,
256
- 0.079481619,
257
- 0.076767694,
258
- 0.072381617,
259
- 0.066521003,
260
- 0.059444853,
261
- 0.051458575,
262
- 0.042895839,
263
- 0.034099681,
264
- 0.025403511,
265
- 0.017113308,
266
- 0.0094932775,
267
- 0.0027546292,
268
- -0.0029527849,
269
- -0.0075431246,
270
- -0.01099166,
271
- -0.013333425,
272
- -0.014650894,
273
- -0.015067057,
274
- -0.014731191,
275
- -0.013807772,
276
- -0.012464086,
277
- -0.010860157,
278
- -0.0091398882,
279
- -0.0074249976,
280
- -0.0058112187,
281
- -0.004366817,
282
- -0.003133466,
283
- -0.0021287814,
284
- -0.0013507826,
285
- -0.00078771292,
286
- -0.00049122414,
287
- 4.3453566e-005
288
- ].freeze
289
-
290
-
291
- end
292
- end
@@ -1,76 +0,0 @@
1
- require_relative '../lib/radio'
2
-
3
- # Basic loading of uncompressed wav files for testing
4
- def load_wav filename
5
- sample_rate = nil
6
- fmt = nil
7
- data = ''
8
- File.open(filename) do |file|
9
- head = file.read(12)
10
- until file.eof?
11
- type = file.read(4)
12
- size = file.read(4).unpack("V")[0].to_i
13
- case type
14
- when 'fmt '
15
- fmt = file.read(size)
16
- fmt = {
17
- :id => fmt.slice(0,2).unpack('c')[0],
18
- :channel => fmt.slice(2,2).unpack('c')[0],
19
- :hz => fmt.slice(4,4).unpack('V').join.to_i,
20
- :byte_sec => fmt.slice(8,4).unpack('V').join.to_i,
21
- :block_size => fmt.slice(12,2).unpack('c')[0],
22
- :bit_sample => fmt.slice(14,2).unpack('c')[0]
23
- }
24
- when 'data'
25
- data += file.read size
26
- else
27
- raise type
28
- end
29
- end
30
- end
31
- [fmt, data]
32
- end
33
-
34
- # Generate a float enumerator for binary string audio data.
35
- # Packing is defined with Array#pack/String#unpack formats.
36
- # Usage: floats = $iterators['C'].enum_for(:call, data)
37
- # 'C' should be almost as fast as String#each_byte.
38
- # If slow, you probably need to: data.force_encoding('binary')
39
- $iterators = Hash.new do |hash, packing|
40
- packing = packing.to_s.dup
41
- sample_size = [0].pack(packing).size
42
- case ("\x80"*16).unpack(packing)[0]
43
- when 128
44
- max = 128
45
- offset = -128
46
- when -128
47
- max = 128
48
- offset = 0
49
- when 32768 + 128
50
- max = 32768
51
- offset = -32768
52
- when -32768 + 128
53
- max = 32768
54
- offset = 0
55
- else
56
- raise 'unable to interpret packing format'
57
- end
58
- hash[packing] = Proc.new do |data, &block|
59
- pos = 0
60
- size = data.size
61
- while pos < size
62
- sample = data.slice(pos,sample_size).unpack(packing)[0] || 0
63
- block.call (sample + offset).to_f / max
64
- pos += sample_size
65
- end
66
- end
67
- end
68
-
69
-
70
- fmt, data = load_wav 'wav/bpsk8k.wav'
71
- data.force_encoding('binary')
72
- radio = Radio::PSK31::Rx.new 1000
73
-
74
- # "CQ CQ CQ de EA2BAJ EA2BAJ EA2BAJ\rPSE K\r"
75
- i = $iterators['C'].enum_for(:call, data)
76
- radio.call(i){|o| p o}