cw 0.3.1 → 0.3.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.
@@ -72,7 +72,7 @@ module CWG
72
72
  end
73
73
  sleep 0.01
74
74
  end
75
- Cfg.config["exit"] = true
75
+ # Cfg.config["exit"] = true
76
76
  sleep 0.1
77
77
  end
78
78
 
@@ -46,12 +46,12 @@ module CWG
46
46
 
47
47
  def reset
48
48
  @print_count = 0
49
- puts "\r"
50
49
  end
51
50
 
52
51
  def newline
53
52
  reset
54
53
  update_console_size
54
+ puts "\r"
55
55
  end
56
56
 
57
57
  def force_newline_maybe
@@ -125,6 +125,18 @@ module CWG
125
125
  print paint("#{word}", list_colour)
126
126
  end
127
127
 
128
+ def tx word
129
+ print paint("#{word}", tx_colour)
130
+ end
131
+
132
+ def rx word
133
+ print paint("#{word}", rx_colour)
134
+ end
135
+
136
+ def menu word
137
+ print paint("#{word}", menu_colour)
138
+ end
139
+
128
140
  def success word
129
141
  newline_maybe word
130
142
  return if(@print_count == 0 && word == ' ')
@@ -143,6 +155,18 @@ module CWG
143
155
  Cfg.config["list_colour"].to_sym || :default
144
156
  end
145
157
 
158
+ def tx_colour
159
+ Cfg.config["tx_colour"].to_sym || :red
160
+ end
161
+
162
+ def rx_colour
163
+ Cfg.config["rx_colour"].to_sym || :blue
164
+ end
165
+
166
+ def menu_colour
167
+ Cfg.config["menu_colour"].to_sym || :yellow
168
+ end
169
+
146
170
  def print_advice name
147
171
  puts "#{name}: Press Q 4 times to Exit"
148
172
  end
@@ -58,23 +58,28 @@ module CWG
58
58
  end
59
59
  end
60
60
 
61
+ def threads
62
+ threads ||= CWThreads.new(self, thread_processes)
63
+ end
64
+
61
65
  def run words
62
66
  temp_words = words.all
63
67
  temp_words.each do |word|
64
68
  loop do
69
+ Cfg.config.params["exit"] = false
65
70
  break if test_env
66
71
  @input_word, @words = '', Words.new
67
72
  Cfg.config.params["quit"] = false
68
73
  @words.assign word
69
- @threads = CWThreads.new(self, thread_processes)
70
- @threads.start_threads
71
- @threads.wait_for_threads
74
+ threads.run
75
+ # threads.start_threads
76
+ # threads.wait_for_threads
72
77
  @play = nil
73
78
  system("stty -raw echo")
74
79
  break unless failed?
75
80
  end
76
81
  end
77
- # break if Cfg.config["exit"]
82
+ Cfg.config.params["exit"] = true
78
83
  end
79
84
  end
80
85
  end
@@ -1,5 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'oga'
4
+ require 'httpclient'
5
+ require "htmlentities"
6
+ require 'sanitize'
7
+
3
8
  module CWG
4
9
 
5
10
  #class Rss
@@ -22,25 +27,25 @@ module CWG
22
27
  end
23
28
 
24
29
  def read_rss(src, article_count = 3)
25
- require 'feedjira'
26
- require "htmlentities"
27
- require 'sanitize'
30
+
31
+ Cfg.config.params["words_counted"] = true
32
+ @rss_articles = []
33
+ count = 0
28
34
  coder = HTMLEntities.new
29
35
  url = source(src)
30
- # return a Hash - each url having a Feedjira::Feed object
31
- feed = Feedjira::Feed.fetch_and_parse url
32
- entry_count = 0
33
- @rss_articles = []
34
- feed.entries.each do |entry|
35
- title = entry.title
36
+ content = HTTPClient.new.get_content(url)
37
+ document = Oga.parse_xml(content)
38
+ document.xpath('rss/channel/item').each do |item|
39
+ title = item.at_xpath('title').text
40
+ description = item.at_xpath('description').text
36
41
  unless(title.include?('VIDEO:') ||
37
42
  title.include?('In pictures:') ||
38
43
  title.include?('Morning business round-up'))
39
- words = entry.summary
40
- entry_count += 1
44
+ @rss_articles << Sanitize.clean(coder.decode(title)) + '. ' +
45
+ Sanitize.clean(coder.decode(description))
46
+ count += 1
47
+ break if count >= article_count
41
48
  end
42
- @rss_articles << (Sanitize.clean coder.decode words).split(',')
43
- break if entry_count >= article_count
44
49
  end
45
50
  end
46
51
 
@@ -53,14 +58,12 @@ module CWG
53
58
  end
54
59
 
55
60
  def next_article
56
- temp = @rss_articles[article_index]
57
- return unless temp
61
+ article = @rss_articles[article_index]
62
+ return unless article
58
63
  inc_article_index
59
- quote = ''
60
- temp.map { |i| quote += i }
61
- (quote.split.collect { |article| cw_chars(article.strip.delete("\"").downcase)})
64
+ article.split.collect do |chars|
65
+ cw_chars(chars.strip.delete("\"").downcase)
66
+ end
62
67
  end
63
-
64
68
  end
65
-
66
69
  end
@@ -227,6 +227,11 @@ module CWG
227
227
  exit!
228
228
  end
229
229
 
230
+ def cw_threads
231
+ @cw_threads ||= CWThreads.new(self, thread_processes)
232
+ end
233
+
234
+
230
235
  def thread_processes
231
236
  [
232
237
  :monitor_keys_thread,
@@ -237,8 +242,7 @@ module CWG
237
242
 
238
243
  def run words
239
244
  @words = words
240
- @cw_threads = CWThreads.new(self, thread_processes)
241
- @cw_threads.run
245
+ cw_threads.run
242
246
  @play = nil
243
247
  reset_stdin
244
248
  print.newline
@@ -11,22 +11,48 @@ module CWG
11
11
  include ToneHelpers
12
12
  include FileDetails
13
13
 
14
+ attr_reader :code
15
+
16
+ class Code
17
+
18
+ include FileDetails
19
+
20
+ def initialize sample_rate, wpm
21
+ @sample_rate = sample_rate
22
+ @wpm = wpm
23
+ @spb_short = @sample_rate * 1.2 / @wpm
24
+ @spb_long = @sample_rate * 3.6 / @wpm
25
+ end
26
+
27
+ def filename element
28
+ self.send "#{element}_path"
29
+ end
30
+
31
+ def spb element
32
+ spb = element == :dash ?
33
+ @spb_long :
34
+ @spb_short
35
+ spb.to_i
36
+ end
37
+ end
38
+
14
39
  def initialize
40
+ @sample_rate = 2400
15
41
  @max_amplitude = (Cfg.config["volume"].to_f > 1.0 ?
16
42
  1.0 : Cfg.config["volume"].to_f)
17
43
  @wpm = Cfg.config["wpm"].to_f
18
44
  @frequency = Cfg.config["frequency"].to_i
19
45
  @effective_wpm = Cfg.config["effective_wpm"] ?
20
46
  Cfg.config["effective_wpm"].to_f : @wpm
21
- @sample_rate = 2400
22
47
  @print = Print.new
23
48
  end
24
49
 
25
- def generate wrds
50
+ def code
51
+ @code ||= Code.new(@sample_rate, @wpm)
52
+ end
26
53
 
54
+ def generate wrds
27
55
  word_parts(wrds)
28
- # progress.init elements.size * 3 + (wrds.size)
29
- create_element_methods
30
56
  compile_fundamentals
31
57
  write_word_parts
32
58
  end
@@ -35,11 +61,6 @@ module CWG
35
61
  @play_filename ||= File.join(audio_dir, audio_filename)
36
62
  end
37
63
 
38
- def play
39
- cmd = play_command + ' ' + play_filename
40
- @pid = ! @dry_run ? Process.spawn(cmd) : cmd
41
- end
42
-
43
64
  def cw_encoding
44
65
  @encoding ||= CwEncoding.new
45
66
  end
@@ -48,21 +69,6 @@ module CWG
48
69
  @progress ||= Progress.new('Compiling')
49
70
  end
50
71
 
51
- def data
52
- { :dot => {:name => :dot,
53
- :filename => dot_path,
54
- :spb => (@sample_rate * 1.2 / @wpm).to_i },
55
- :dash => {:name => :dash,
56
- :filename => dash_path,
57
- :spb => (@sample_rate * 3.6 / @wpm).to_i },
58
- :space => {:name => :space,
59
- :filename => space_path,
60
- :spb => (@sample_rate * 1.2 / @wpm).to_i },
61
- :e_space => {:name => :e_space,
62
- :filename => e_space_path,
63
- :spb => (@sample_rate * 1.2 / @effective_wpm).to_i }}
64
- end
65
-
66
72
  def filter_maybe(size, count)
67
73
  ramp = 0.05
68
74
  ramp_point = @max_amplitude / ramp
@@ -83,11 +89,13 @@ module CWG
83
89
  end
84
90
 
85
91
  def generate_buffer audio_samples, ele
86
- WaveFile::Buffer.new(audio_samples, WaveFile::Format.new(:mono, :float, data[ele][:spb]))
92
+ WaveFile::Buffer.new(audio_samples,
93
+ WaveFile::Format.new(:mono, :float, code.spb(ele)))
87
94
  end
88
95
 
89
96
  def write_element_audio_file ele, buffer
90
- WaveFile::Writer.new(data[ele][:filename], WaveFile::Format.new(:mono, :pcm_16, @sample_rate)) do |writer|
97
+ WaveFile::Writer.new(code.filename(ele),
98
+ WaveFile::Format.new(:mono, :pcm_16, @sample_rate)) do |writer|
91
99
  writer.write(buffer)
92
100
  end
93
101
  end
@@ -96,23 +104,9 @@ module CWG
96
104
  [:dot, :dash, :space, :e_space]
97
105
  end
98
106
 
99
- # create dot, dash, space or e_space method
100
-
101
- def create_element_method ele
102
- define_singleton_method(ele) {data[ele]}
103
- end
104
-
105
- # create dot, dash, space and e_space methods
106
-
107
- def create_element_methods
108
- elements.each do |ele|
109
- create_element_method ele
110
- end
111
- end
112
-
113
107
  def generate_samples ele
114
- return generate_space(data[ele][:spb]) if space_sample? ele
115
- generate_tone(data[ele][:spb]) unless space_sample? ele
108
+ return generate_space(code.spb(ele)) if space_sample? ele
109
+ generate_tone(code.spb(ele)) unless space_sample? ele
116
110
  end
117
111
 
118
112
  def compile_fundamentals
@@ -123,50 +117,43 @@ module CWG
123
117
  end
124
118
  end
125
119
 
120
+ def ewpm?
121
+ @effective_wpm != @wpm
122
+ end
123
+
126
124
  def space_or_espace
127
- (@effective_wpm == @wpm) ? space : e_space
125
+ { name: (ewpm? ? :e_space : :space) }
128
126
  end
129
127
 
130
128
  def push_enc chr
131
129
  arry = []
132
130
  chr.each_with_index do |c,idx|
133
131
  arry << c
134
- arry << ((last_element?(idx, chr)) ? (space_or_espace) : space)
132
+ arry << (last_element?(idx, chr) ? space_or_espace : { name: :space })
135
133
  end
136
134
  arry += char_space
137
135
  end
138
136
 
139
- def send_char c
140
- enc = nil
141
- if c == ' '
142
- enc = word_space
143
- else
144
- enc = cw_encoding.fetch(c).map { |e| send(e)}
145
- end
137
+ def send_char(c)
138
+ enc = c == ' ' ? [word_space] : cw_encoding.fetch(c).map { |e|
139
+ { :name => e }
140
+ }
146
141
  push_enc enc
147
142
  end
148
143
 
149
- def word_parts str = nil
144
+ def word_parts(str = nil)
150
145
  return @word_parts if @word_parts
151
146
  @word_parts = []
152
- str.split('').each { |part| @word_parts << part}
147
+ str.split('').each { |part| @word_parts << part }
153
148
  @word_parts
154
149
  end
155
150
 
156
- def make_word_parts
157
- parts = []
158
- @word_parts.each do |part|
159
- parts += send_char part.downcase
160
- end
161
- parts
162
- end
163
-
164
151
  def prepare_buffers
165
152
  @buffers = {}
166
153
  elements.each do |ele|
167
154
  @buffers[ele] = []
168
- WaveFile::Reader.new(data[ele][:filename]).
169
- each_buffer(data[ele][:spb]) do |buffer|
155
+ WaveFile::Reader.new(code.filename(ele))
156
+ .each_buffer(code.spb(ele)) do |buffer|
170
157
  @buffers[ele] = buffer
171
158
  end
172
159
  end
@@ -178,42 +165,40 @@ module CWG
178
165
  end
179
166
 
180
167
  def char_space
181
- @effective_wpm == @wpm ? [space,space] : [e_space,e_space]
168
+ Array.new(2, word_space)
182
169
  end
183
170
 
184
171
  def word_space
185
- @effective_wpm == @wpm ? [space] : [e_space]
172
+ { name: (ewpm? ? :e_space : :space) }
186
173
  end
187
174
 
188
- def word_composite word
175
+ def word_composite(word)
189
176
  send_char word.downcase
190
177
  end
191
178
 
192
- def write_audio
193
- WaveFile::Writer.
194
- new(play_filename,
195
- WaveFile::Format.
196
- new(:mono,
197
- :pcm_16,
198
- @sample_rate)) do |writer|
199
- yield.each do |char|
200
- char.each do |fta|
201
- writer.write(@buffers[fta[:name]])
202
- end
203
- end
204
- end
179
+ def format
180
+ WaveFile::Format.new(:mono, :pcm_16, @sample_rate)
205
181
  end
206
182
 
207
- def reset
208
- @word_parts = @progress = nil
209
- # puts "\r"
183
+ def write_buffer(writer, fta)
184
+ writer.write(@buffers[fta[:name]])
185
+ end
186
+
187
+ def write_audio
188
+ WaveFile::Writer.new(play_filename, format) do |writer|
189
+ yield.map { |ch| ch.map { |fta| write_buffer(writer, fta) } }
190
+ end
210
191
  end
211
192
 
212
193
  def write_audio_file
213
194
  write_audio do
214
- @word_parts.collect {|part| word_composite(part) }
195
+ @word_parts.collect { |part| word_composite(part) }
215
196
  end
216
197
  reset
217
198
  end
199
+
200
+ def reset
201
+ @word_parts = @progress = nil
202
+ end
218
203
  end
219
204
  end
@@ -4,7 +4,7 @@ module CWG
4
4
 
5
5
  module ToneHelpers
6
6
 
7
- TWO_PI = 2 * Math::PI
7
+ TWO_PI = 2 * Math::PI
8
8
 
9
9
  def convert_words wrds
10
10
  wrds.to_array.collect{ |wrd| wrd.delete("\n")}
@@ -0,0 +1,487 @@
1
+ # coding: utf-8
2
+ module CWG
3
+
4
+ class Tx < Tester
5
+
6
+ include ToneHelpers
7
+ include FileDetails
8
+
9
+ def initialize
10
+ @max_amplitude = (Cfg.config["volume"].to_f > 1.0 ?
11
+ 1.0 : Cfg.config["volume"].to_f)
12
+ @wpm = Cfg.config["wpm"].to_f
13
+ @frequency = Cfg.config["frequency"].to_i
14
+ @effective_wpm = Cfg.config["effective_wpm"] ?
15
+ Cfg.config["effective_wpm"].to_f : @wpm
16
+ @sample_rate = 2400
17
+ @print = Print.new
18
+ @words = []
19
+ @recording = []
20
+ print.rx "\n"
21
+ print.tx "\n"
22
+ print.menu "\n"
23
+ end
24
+
25
+ def core_audio
26
+ @core_audio ||= Coreaudio.new
27
+ end
28
+
29
+ def add_space words
30
+ str = ''
31
+ words.to_array.collect { |word| str << word + ' '}
32
+ str
33
+ end
34
+
35
+ def monitor_keys
36
+ @char = '#'
37
+ process_letter
38
+
39
+ loop do
40
+ @char = key_input.read
41
+ break if quit_key_input?
42
+ break if quit?
43
+ break if exit?
44
+ check_sentence_navigation(@char) if self.class == Book
45
+ check_clear @char
46
+ process_letter
47
+ end
48
+ end
49
+
50
+ def check_clear char
51
+ if char == "\e"
52
+ @words = []
53
+ end
54
+ end
55
+
56
+ def print_mode(mode)
57
+ msg = "\n\r" + (mode == :rx ?
58
+ "Receive Mode:" :
59
+ "Transmit Mode:") + "\n\r"
60
+ print.tx msg if :tx == mode
61
+ print.rx msg if :rx == mode
62
+ end
63
+
64
+ def receive_mode
65
+ print_mode :rx
66
+ loop do
67
+ char = key_input.read
68
+ check_clear char
69
+ case char
70
+ when '#'
71
+ print_mode :tx
72
+ return
73
+ when '|'
74
+ capture
75
+ when '\\'
76
+ info
77
+ when '>'
78
+ return '>'
79
+ when "\n"
80
+ puts "\n"
81
+ when "\r"
82
+ puts "\r"
83
+ when 'Q'
84
+ puts "Quitting..."
85
+ quit!
86
+ else
87
+ if(@recording.include? ' ')
88
+ @recording = [char]
89
+ else
90
+ @recording << char
91
+ end
92
+ puts 'here'
93
+ print.rx char
94
+ end
95
+ sleep 0.001
96
+ end
97
+ end
98
+
99
+ def quit!
100
+ Cfg.config.params["exit"] = true
101
+ end
102
+
103
+ def capture
104
+ puts "\n\r"
105
+ puts "\r Menu: [C]allsign, [N]ame, "
106
+ puts "\r [L]ocation, [R]st, "
107
+ puts "\r [T]emperature, [S]tore,"
108
+ puts "\r [I]nfo, [W]PM, "
109
+ puts "\r [Q]uit capture!"
110
+ puts "\r"
111
+ puts "\r Use CAPITAL to capture"
112
+
113
+ loop do
114
+ char = key_input.read
115
+ # print.menu char
116
+ upcase = /[[:upper:]]/.match(char)
117
+ case char.downcase
118
+ when 'c'
119
+ return capture_attribute :callsign, upcase
120
+ when 'n'
121
+ return capture_attribute :name, upcase
122
+ when 'l'
123
+ return capture_attribute :qth, upcase
124
+ when 'r'
125
+ return capture_attribute :rst, upcase
126
+ when 't'
127
+ return capture_attribute :temperature, upcase
128
+ when 'i'
129
+ return info
130
+ when 's'
131
+ return store
132
+ when 'q'
133
+ puts "\rCancelled!"
134
+ return
135
+ else
136
+ puts "\nInvalid letter(#{char}) - try again!"
137
+ end
138
+ sleep 0.001
139
+ end
140
+ end
141
+
142
+ def store
143
+ puts "\n\r"
144
+ puts "\rStoring info:"
145
+ info
146
+ @their_callsign
147
+ @their_name
148
+ @their_location
149
+ @their_rst
150
+ puts "\rCleared info!"
151
+ puts "\r"
152
+ end
153
+
154
+ def capture_attribute(attr_type, use_recording = false)
155
+ puts "\n\r"
156
+ puts "Enter their #{attr_type.to_s} followed by SPACE" unless use_recording
157
+ temp = use_recording ? @recording : []
158
+ print.menu temp.join('').delete(' ') if(@recording && ! use_recording)
159
+ @recording = []
160
+ if use_recording
161
+ write_attribute temp, attr_type
162
+ return
163
+ end
164
+ loop do
165
+ char = key_input.read
166
+ if key_input.is_relevant_char?(char)
167
+ temp << char
168
+ print.menu char unless use_recording
169
+ if ' ' == char
170
+ temp << char
171
+ write_attribute temp, attr_type
172
+ return
173
+ end
174
+ elsif char == 'Q'
175
+ puts "\n\n\rCancelled!\n\n\r"
176
+ return
177
+ end
178
+ end
179
+ end
180
+
181
+ def write_attribute attr, type
182
+ clip = attr.join('').delete(' ')
183
+ @their_callsign = clip if :callsign == type
184
+ @their_name = clip if :name == type
185
+ @their_rst = clip if :rst == type
186
+ @their_qth = clip if :qth == type
187
+ @temperature = clip if :temperature == type
188
+ puts "\n\n\r#{type.to_s}: #{@their_callsign.upcase}\n\n\r" if :callsign == type
189
+ unless :callsign == type
190
+ puts "\n\n\rAttr: #{@temperature}°C\n\n\r" if :temperature == type
191
+ puts "\n\n\rTheir #{type.to_s}: #{clip}\n\n\r" unless :temperature == type
192
+ end
193
+ end
194
+
195
+ def my_callsign
196
+ morsify "m0gzg "
197
+ end
198
+
199
+ def their_callsign
200
+ morsify @their_callsign unless @their_callsign.nil?
201
+ end
202
+
203
+ def return_with_k
204
+ acknowledge
205
+ morsify 'k '
206
+ end
207
+
208
+ def return_with_kn
209
+ morsify '+ '
210
+ acknowledge
211
+ morsify 'kn '
212
+ end
213
+
214
+ def acknowledge
215
+ their_callsign
216
+ morsify ' de '
217
+ my_callsign
218
+ end
219
+
220
+ def received_ok
221
+ acknowledge
222
+ morsify 'en en '
223
+ end
224
+
225
+ def sign_off
226
+ morsify "ok om #{@their_name} 73 es tnx fer nice qso = hpe 2cuagn sn + "
227
+ their_callsign
228
+ morsify ' de '
229
+ my_callsign
230
+ morsify ' sk '
231
+ end
232
+
233
+ def stop
234
+ morsify '= '
235
+ end
236
+
237
+ def long_cq
238
+ morsify "cqcq cqcq de m0gzg m0gzg k "
239
+ end
240
+
241
+ def morsify sentence
242
+ sentence.split('').collect{ |letr| char_to_tx letr }
243
+ end
244
+
245
+ def rst
246
+ morsify "rst is 599 5nn = "
247
+ end
248
+
249
+ def name
250
+ morsify "name is m a r t y n martyn = "
251
+ end
252
+
253
+ def qth
254
+ morsify "qth is o l d w o o d nr l i n c o l n lincoln = "
255
+ end
256
+
257
+ def weather
258
+ morsify "hr wx is sunny with some clouds = temp #{@temperature}c = "
259
+ end
260
+
261
+ def dit_dit
262
+ morsify 'e e '
263
+ end
264
+
265
+ def info
266
+ now = Time.now.utc
267
+ time = now.strftime("%H:%M:%S Z")
268
+ date = now.strftime("%d/%m/%y")
269
+ puts "\r----------------------------\r"
270
+ puts "Time: #{time}\r"
271
+ puts "Date: #{date}\r"
272
+ puts "Temp: #{@temperature}°C\r"
273
+ puts "\r"
274
+ callsign = @their_callsign.nil? ? '' : @their_callsign.upcase
275
+ puts "Their Call: #{callsign}\r"
276
+ puts "Their Name: #{@their_name}\r"
277
+ puts "Their RST: #{@their_rst}\r"
278
+ puts "Their qth: #{@their_qth}\r"
279
+ puts "\r----------------------------\r"
280
+ puts "\n\r"
281
+ end
282
+
283
+ def process_letter
284
+ @input_word ||= ''
285
+ case @char
286
+ when '#'
287
+ return_val = receive_mode
288
+ if '>' == return_val
289
+ return_with_k
290
+ else
291
+ @char = ''
292
+ end
293
+ when '.'
294
+ stop
295
+ when 'F'
296
+ @wpm += 1
297
+ @effective_wpm = @wpm
298
+ when 'S'
299
+ @wpm -= 1
300
+ @effective_wpm = @wpm
301
+ when '='
302
+ morsify '= '
303
+ when ','
304
+ morsify ', '
305
+ when '\\'
306
+ info
307
+ when '|'
308
+ capture
309
+ when '?'
310
+ morsify '? '
311
+ when '@'
312
+ long_cq
313
+ when '£'
314
+ my_callsign
315
+ when '$'
316
+ their_callsign
317
+ when '}'
318
+ sign_off
319
+ when '>'
320
+ return_with_k
321
+ when ')'
322
+ return_with_kn
323
+ when '('
324
+ received_ok
325
+ when '^'
326
+ qth
327
+ when '%'
328
+ rst
329
+ when '&'
330
+ name
331
+ when '*'
332
+ weather
333
+ when 'E'
334
+ dit_dit
335
+ when "\n"
336
+ puts "\n"
337
+ when "\r"
338
+ puts "\r"
339
+ when 'Q'
340
+ puts "Quitting..."
341
+ quit!
342
+ else
343
+ if key_input.is_relevant_char?(@char)
344
+ char_to_tx @char
345
+ end
346
+ end
347
+ @char = ''
348
+ end
349
+
350
+ def char_to_tx char
351
+ @words << char
352
+ # print.tx char
353
+ end
354
+
355
+ def thread_processes
356
+ [
357
+ :tx_words_thread,
358
+ :monitor_keys_thread,
359
+ # :print_words_thread
360
+ ]
361
+ end
362
+
363
+ def word_composite word
364
+ send_char word.downcase
365
+ end
366
+
367
+ def push_enc chr
368
+ arry = []
369
+ chr.each_with_index do |c,idx|
370
+ arry << c
371
+ arry << ((last_element?(idx, chr)) ? (space_or_espace) : space)
372
+ end
373
+ arry += char_space
374
+ end
375
+
376
+ def cw_encoding
377
+ @encoding ||= CwEncoding.new
378
+ end
379
+
380
+ def space_or_espace
381
+ (@effective_wpm == @wpm) ? space : e_space
382
+ end
383
+
384
+ def char_space
385
+ @effective_wpm == @wpm ? [space,space] : [e_space,e_space]
386
+ end
387
+
388
+ def word_space
389
+ @effective_wpm == @wpm ? [space] : [e_space]
390
+ end
391
+
392
+ def send_char c
393
+ enc = nil
394
+ if c == ' '
395
+ enc = word_space
396
+ else
397
+ enc = cw_encoding.fetch(c).map { |e| send(e)}
398
+ end
399
+ push_enc enc
400
+ end
401
+
402
+ def audio_thread
403
+ temp = @word_parts.collect {|part| word_composite(part) }
404
+ @word_parts = nil
405
+ wpm = 1.5
406
+ temp.each do |letr|
407
+ letr.each do |ele|
408
+ if (:space == ele[:name]) || (:e_space == ele[:name])
409
+ core_audio.generate_silence(tone.data[
410
+ ele[:name]][:spb] * 20)
411
+ else
412
+ core_audio.generate_tone( tone.data[
413
+ ele[:name]][:spb] * 20)
414
+ end
415
+ end
416
+ end
417
+ end
418
+
419
+ def generate wrds
420
+ word_parts(wrds)
421
+ create_element_methods
422
+ core_audio.start
423
+ cw_threads.add self, :audio_thread
424
+ # th = Thread.start do
425
+ cw_threads.join :audio_thread
426
+ sleep 0.001
427
+ core_audio.stop
428
+ cw_threads.kill_thread_x :audio_thread
429
+ # puts 'end thread'
430
+ end
431
+
432
+ def word_parts str = nil
433
+ return @word_parts if @word_parts
434
+ @word_parts = []
435
+ str.split('').each { |part| @word_parts << part}
436
+ @word_parts
437
+ end
438
+
439
+ def create_element_method ele
440
+ define_singleton_method(ele) {tone.data[ele]}
441
+ end
442
+
443
+ def create_element_methods
444
+ elements.each do |ele|
445
+ create_element_method ele
446
+ end
447
+ end
448
+
449
+ def elements
450
+ [:dot, :dash, :space, :e_space]
451
+ end
452
+
453
+ def tone
454
+ @tone ||= ToneGenerator.new
455
+ end
456
+
457
+ def cw_threads
458
+ @cw_threads ||= CWThreads.new(self, thread_processes)
459
+ end
460
+
461
+ def tx string
462
+ @winkey = Winkey.new
463
+ @winkey.on
464
+ @winkey.echo
465
+ @winkey.no_weighting
466
+ @winkey.wpm @wpm
467
+ # @winkey.string "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890/=+?>(:;"
468
+ @winkey.string ' fb '
469
+ @winkey.wait_while_sending
470
+ cw_threads.run
471
+ # @winkey.close
472
+ end
473
+
474
+ def tx_words_thread
475
+ loop do
476
+ unless @words == []
477
+ temp = @words.shift
478
+ # generate temp
479
+ # p temp
480
+ @winkey.stringtemp.to_s.upcase
481
+ print.tx temp
482
+ end
483
+ sleep 0.01
484
+ end
485
+ end
486
+ end
487
+ end