cw 0.0.1
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 +7 -0
- data/.gitignore +3 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +21 -0
- data/Rakefile +1 -0
- data/audio/audio_output.wav +0 -0
- data/audio/audio_output.wav0000.mp3 +0 -0
- data/audio/dash.wav +0 -0
- data/audio/dot.wav +0 -0
- data/audio/e_space.wav +0 -0
- data/audio/space.wav +0 -0
- data/cw.gemspec +18 -0
- data/daily.rb +182 -0
- data/data/text/abbreviations.txt +1 -0
- data/data/text/common_words.txt +90 -0
- data/data/text/cw_conversation.txt +1 -0
- data/data/text/most_common_words.txt +1 -0
- data/data/text/progress.txt +1 -0
- data/data/text/q_codes.txt +1 -0
- data/data/text/tom_sawyer.txt +6477 -0
- data/example.rb +139 -0
- data/lib/cw.rb +111 -0
- data/lib/cw/alphabet.rb +29 -0
- data/lib/cw/audio_player.rb +63 -0
- data/lib/cw/book.rb +239 -0
- data/lib/cw/book_details.rb +47 -0
- data/lib/cw/cl.rb +112 -0
- data/lib/cw/cw_dsl.rb +211 -0
- data/lib/cw/cw_encoding.rb +56 -0
- data/lib/cw/cw_params.rb +29 -0
- data/lib/cw/cw_threads.rb +36 -0
- data/lib/cw/file_details.rb +13 -0
- data/lib/cw/key_input.rb +53 -0
- data/lib/cw/monitor.rb +36 -0
- data/lib/cw/monitor_keys.rb +37 -0
- data/lib/cw/numbers.rb +29 -0
- data/lib/cw/print.rb +137 -0
- data/lib/cw/process.rb +11 -0
- data/lib/cw/progress.rb +27 -0
- data/lib/cw/randomize.rb +73 -0
- data/lib/cw/repeat_word.rb +91 -0
- data/lib/cw/rss.rb +71 -0
- data/lib/cw/sentence.rb +78 -0
- data/lib/cw/speak.rb +11 -0
- data/lib/cw/spoken.rb +11 -0
- data/lib/cw/str.rb +67 -0
- data/lib/cw/stream.rb +161 -0
- data/lib/cw/test_letters.rb +52 -0
- data/lib/cw/test_words.rb +59 -0
- data/lib/cw/tester.rb +221 -0
- data/lib/cw/timing.rb +92 -0
- data/lib/cw/tone_generator.rb +225 -0
- data/lib/cw/voice.rb +16 -0
- data/lib/cw/words.rb +182 -0
- data/read_book.rb +33 -0
- data/test/run_tests_continuously.rb +4 -0
- data/test/test_cw.rb +527 -0
- data/test/test_stream.rb +401 -0
- metadata +102 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class TestLetters < FileDetails
|
4
|
+
|
5
|
+
include Tester
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@print_letters = Params.print_letters
|
9
|
+
super()
|
10
|
+
# print_test_advice
|
11
|
+
end
|
12
|
+
|
13
|
+
def print_test_advice ; print.print_advice('Test Letters') ; end
|
14
|
+
|
15
|
+
def print_words words
|
16
|
+
timing.init_char_timer
|
17
|
+
(words.to_s + space).each_char do |letr|
|
18
|
+
process_letter letr
|
19
|
+
stream.add_char letr
|
20
|
+
loop do
|
21
|
+
process_word_maybe
|
22
|
+
break if timing.char_delay_timeout?
|
23
|
+
end
|
24
|
+
print.prn letr if print_letters?
|
25
|
+
break if quit?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def process_input_word_maybe
|
30
|
+
if @word_to_process
|
31
|
+
stream.match_first_active_element @process_input_word # .strip
|
32
|
+
@process_input_word = @word_to_process = nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_word_maybe
|
37
|
+
@input_word ||= empty_string
|
38
|
+
@input_word << key_chr if is_relevant_char?
|
39
|
+
move_word_to_process if is_relevant_char?
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_letter letr
|
43
|
+
letr.downcase!
|
44
|
+
sleep_char_delay letr
|
45
|
+
end
|
46
|
+
|
47
|
+
def print_marked_maybe
|
48
|
+
@popped = stream.pop_next_marked
|
49
|
+
print.char_result(@popped) if(@popped && ! print_letters?)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class TestWords < FileDetails
|
4
|
+
|
5
|
+
include Tester
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@print_letters = Params.print_letters
|
9
|
+
|
10
|
+
super()
|
11
|
+
|
12
|
+
# print_test_advice
|
13
|
+
end
|
14
|
+
|
15
|
+
def print_test_advice ; print.print_advice('Test Words') ; end
|
16
|
+
|
17
|
+
def print_failed_exit_words
|
18
|
+
until stream.stream_empty?
|
19
|
+
print.prn_red stream.pop[:value] + ' '
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def print_words words
|
24
|
+
timing.init_char_timer
|
25
|
+
(words.to_s + space).each_char do |letr|
|
26
|
+
process_letter letr
|
27
|
+
loop do
|
28
|
+
process_space_maybe letr
|
29
|
+
process_word_maybe
|
30
|
+
break if timing.char_delay_timeout?
|
31
|
+
end
|
32
|
+
print.prn letr if print_letters?
|
33
|
+
break if quit?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_input_word_maybe
|
38
|
+
if @word_to_process
|
39
|
+
stream.match_last_active_element @process_input_word.strip
|
40
|
+
@process_input_word = @word_to_process = nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_word_maybe
|
45
|
+
@input_word ||= empty_string
|
46
|
+
@input_word << key_chr if is_relevant_char?
|
47
|
+
move_word_to_process if complete_word?
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_letter letr
|
51
|
+
current_word.process_letter letr
|
52
|
+
sleep_char_delay letr
|
53
|
+
end
|
54
|
+
|
55
|
+
def print_marked_maybe
|
56
|
+
@popped = stream.pop_next_marked
|
57
|
+
print.results(@popped) if(@popped && ! print_letters?)
|
58
|
+
end
|
59
|
+
end
|
data/lib/cw/tester.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Tester
|
4
|
+
|
5
|
+
def quit? ; @quit ; end
|
6
|
+
def quit ; @quit = true ; end
|
7
|
+
def global_quit? ; @global_quit ; end
|
8
|
+
def global_quit ; @global_quit = true ; end
|
9
|
+
def print ; @print ||= Print.new ; end
|
10
|
+
def timing ; @timing ||= Timing.new ; end
|
11
|
+
def audio ; @audio ||= AudioPlayer.new ; end
|
12
|
+
def kill_threads ; @threads.kill ; end
|
13
|
+
def space ; ' ' ; end
|
14
|
+
def empty_string ; '' ; end
|
15
|
+
def spawn_play(cmd) ; Process.spawn(cmd) ; end
|
16
|
+
def start_sync ; @start_sync = true ; end
|
17
|
+
def get_key_input ; key_input.read ; end
|
18
|
+
def key_chr ; key_input.char ; end
|
19
|
+
def key_input ; @key_input ||= KeyInput.new ; end
|
20
|
+
def is_relevant_char? ; key_input.is_relevant_char? ; end
|
21
|
+
def quit_key_input? ; key_input.quit_input? ; end
|
22
|
+
def stream ; @stream ||= Stream.new ; end
|
23
|
+
def reset_stdin ; key_input.reset_stdin ; end
|
24
|
+
def current_word ; @current_word ||= CurrentWord.new ; end
|
25
|
+
def init_char_timer ; timing.init_char_timer ; end
|
26
|
+
def audio_still_playing? ; audio.still_playing? ; end
|
27
|
+
|
28
|
+
def add_space words
|
29
|
+
str = ''
|
30
|
+
words.to_array.collect { |word| str << word + space}
|
31
|
+
str
|
32
|
+
end
|
33
|
+
|
34
|
+
def audio_play
|
35
|
+
audio.convert_words add_space @words
|
36
|
+
start_sync
|
37
|
+
audio.play
|
38
|
+
end
|
39
|
+
|
40
|
+
def play_words_until_quit
|
41
|
+
audio_play
|
42
|
+
play_words_exit unless @print_letters
|
43
|
+
end
|
44
|
+
|
45
|
+
def play_words_exit
|
46
|
+
timing.init_play_words_timeout
|
47
|
+
loop do
|
48
|
+
break if quit?
|
49
|
+
break if timing.play_words_timeout?
|
50
|
+
sleep 0.01
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_word_maybe
|
55
|
+
print_marked_maybe
|
56
|
+
process_input_word_maybe
|
57
|
+
end
|
58
|
+
|
59
|
+
def play_words_thread
|
60
|
+
play_words_until_quit
|
61
|
+
print "\n\rplay has quit " if @debug
|
62
|
+
end
|
63
|
+
|
64
|
+
def print_words_thread
|
65
|
+
print_words_until_quit
|
66
|
+
kill_threads
|
67
|
+
print "\n\rprint has quit " if @debug
|
68
|
+
end
|
69
|
+
|
70
|
+
def print_words_until_quit
|
71
|
+
sync_with_audio_player
|
72
|
+
print_words @words
|
73
|
+
print_words_exit unless @print_letters
|
74
|
+
quit
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_failed_exit_words
|
78
|
+
until stream.stream_empty?
|
79
|
+
print.prn_red stream.pop[:value]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def print_words_exit
|
84
|
+
timing.init_print_words_timeout
|
85
|
+
loop do
|
86
|
+
process_word_maybe
|
87
|
+
break if stream.stream_empty?
|
88
|
+
break if timing.print_words_timeout?
|
89
|
+
break if quit?
|
90
|
+
sleep 0.01
|
91
|
+
end
|
92
|
+
@failed = true unless stream.stream_empty?
|
93
|
+
print_failed_exit_words unless @repeat_word
|
94
|
+
end
|
95
|
+
|
96
|
+
def audio_stop
|
97
|
+
audio.stop if audio_still_playing?
|
98
|
+
end
|
99
|
+
|
100
|
+
def wait_player_startup_delay
|
101
|
+
audio.startup_delay
|
102
|
+
end
|
103
|
+
|
104
|
+
def sync_with_audio_player
|
105
|
+
wait_for_start_sync
|
106
|
+
wait_player_startup_delay
|
107
|
+
end
|
108
|
+
|
109
|
+
def check_quit_key_input
|
110
|
+
if quit_key_input?
|
111
|
+
quit
|
112
|
+
global_quit
|
113
|
+
audio_stop
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def push_letter_to_current_word letr
|
118
|
+
current_word.push_letter letr
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_word_last_char
|
122
|
+
@input_word.split(//).last(1).first
|
123
|
+
end
|
124
|
+
|
125
|
+
def wait_for_no_word_process
|
126
|
+
while @word_to_process
|
127
|
+
sleep 0.1
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def complete_word?
|
132
|
+
get_word_last_char == space
|
133
|
+
end
|
134
|
+
|
135
|
+
def move_word_to_process
|
136
|
+
wait_for_no_word_process
|
137
|
+
@process_input_word, @input_word = @input_word, ''
|
138
|
+
@word_to_process = true
|
139
|
+
end
|
140
|
+
|
141
|
+
def start_sync?
|
142
|
+
if @start_sync
|
143
|
+
@start_sync = nil
|
144
|
+
true
|
145
|
+
else
|
146
|
+
nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def sleep_char_delay letr
|
151
|
+
timing.append_char_delay letr, Params.wpm, Params.effective_wpm
|
152
|
+
end
|
153
|
+
|
154
|
+
def wait_for_start_sync
|
155
|
+
until start_sync?
|
156
|
+
sleep 0.001
|
157
|
+
break if quit?
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def process_space_maybe letr
|
162
|
+
if letr == space
|
163
|
+
stream.add_word current_word.strip
|
164
|
+
current_word.clear
|
165
|
+
letr.clear
|
166
|
+
print.prn space if print_letters?
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def print_letters?
|
171
|
+
@print_letters && ! quit?
|
172
|
+
end
|
173
|
+
|
174
|
+
def sync_with_play
|
175
|
+
loop do
|
176
|
+
break if sentence_index_current?
|
177
|
+
break if quit?
|
178
|
+
sleep 0.015
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def sync_with_print
|
183
|
+
loop do
|
184
|
+
make_sentence_index_current if ! sentence_index_current?
|
185
|
+
break if sentence_index_current?
|
186
|
+
break if quit?
|
187
|
+
sleep 0.015
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def monitor_keys_thread
|
192
|
+
monitor_keys
|
193
|
+
print "\n\rmonitor keys has quit " if @debug
|
194
|
+
end
|
195
|
+
|
196
|
+
def thread_processes
|
197
|
+
[:monitor_keys_thread,
|
198
|
+
:play_words_thread,
|
199
|
+
:print_words_thread]
|
200
|
+
end
|
201
|
+
|
202
|
+
def run words
|
203
|
+
@words = words
|
204
|
+
words.double_words if Params.double_words
|
205
|
+
@threads = CWThreads.new(self, thread_processes)
|
206
|
+
@threads.run
|
207
|
+
reset_stdin
|
208
|
+
print.newline
|
209
|
+
end
|
210
|
+
|
211
|
+
def monitor_keys
|
212
|
+
loop do
|
213
|
+
get_key_input
|
214
|
+
check_quit_key_input
|
215
|
+
break if quit?
|
216
|
+
# check_sentence_navigation key_chr
|
217
|
+
build_word_maybe
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
data/lib/cw/timing.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Timing
|
4
|
+
|
5
|
+
attr_accessor :delay_time
|
6
|
+
attr_accessor :start_time
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@delay_time = 0.0
|
10
|
+
@cw_encoding = CwEncoding.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def cw_encoding enc
|
14
|
+
@cw_encoding.fetch(enc)
|
15
|
+
end
|
16
|
+
|
17
|
+
def dot wpm
|
18
|
+
1.2 / wpm
|
19
|
+
end
|
20
|
+
|
21
|
+
def dot_ms
|
22
|
+
dot @wpm
|
23
|
+
end
|
24
|
+
|
25
|
+
def init_print_words_timeout
|
26
|
+
@start_print_time, @delay_print_time = Time.now, 2.0
|
27
|
+
end
|
28
|
+
|
29
|
+
def print_words_timeout?
|
30
|
+
(Time.now - @start_print_time) > @delay_print_time
|
31
|
+
end
|
32
|
+
|
33
|
+
def init_play_words_timeout
|
34
|
+
@start_play_time, @delay_play_time = Time.now, 2.0
|
35
|
+
end
|
36
|
+
|
37
|
+
def play_words_timeout?
|
38
|
+
(Time.now - @start_play_time) > @delay_play_time
|
39
|
+
end
|
40
|
+
|
41
|
+
def effective_dot_ms
|
42
|
+
dot @effective_wpm
|
43
|
+
end
|
44
|
+
|
45
|
+
def init_char_timer
|
46
|
+
@start_time, @delay_time = Time.now, 0.0
|
47
|
+
end
|
48
|
+
|
49
|
+
def char_delay_timeout?
|
50
|
+
(Time.now - @start_time) > @delay_time
|
51
|
+
end
|
52
|
+
|
53
|
+
def char_timing(* args)
|
54
|
+
timing = 0
|
55
|
+
args.flatten.each do |arg|
|
56
|
+
case arg
|
57
|
+
when :dot then timing += 2
|
58
|
+
when :dash then timing += 4
|
59
|
+
else
|
60
|
+
puts "Error! invalid morse symbol - was #{arg}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
timing -= 1
|
64
|
+
timing = timing.to_f * dot_ms
|
65
|
+
timing + code_space_timing
|
66
|
+
end
|
67
|
+
|
68
|
+
def code_space_timing
|
69
|
+
@effective_wpm ? 3.0 * effective_dot_ms :
|
70
|
+
3.0 * dot_ms
|
71
|
+
end
|
72
|
+
|
73
|
+
def space_timing
|
74
|
+
space = 4.0
|
75
|
+
@effective_wpm ? space * effective_dot_ms :
|
76
|
+
space * dot_ms
|
77
|
+
end
|
78
|
+
|
79
|
+
def char_delay(char, wpm, ewpm)
|
80
|
+
@wpm, @effective_wpm = wpm, ewpm
|
81
|
+
if(char != ' ')
|
82
|
+
char_timing(cw_encoding(char)) unless(char == ' ')
|
83
|
+
else
|
84
|
+
space_timing
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def append_char_delay letr, wpm, ewpm
|
89
|
+
@delay_time += char_delay(letr, wpm, ewpm)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'wavefile'
|
4
|
+
|
5
|
+
class ToneGenerator
|
6
|
+
|
7
|
+
DOT_FILENAME = "audio/dot.wav"
|
8
|
+
DASH_FILENAME = "audio/dash.wav"
|
9
|
+
SPACE_FILENAME = "audio/space.wav"
|
10
|
+
E_SPACE_FILENAME = "audio/e_space.wav"
|
11
|
+
TWO_PI = 2 * Math::PI
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@max_amplitude = 0.5
|
15
|
+
@wpm = Params.wpm
|
16
|
+
@frequency = Params.frequency
|
17
|
+
@effective_wpm = Params.effective_wpm ? Params.effective_wpm : @wpm
|
18
|
+
@sample_rate = 2400
|
19
|
+
@print = Print.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def cw_encoding
|
23
|
+
@encoding ||= CwEncoding.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def convert_words wrds
|
27
|
+
wrds.to_array.collect{ |wrd| wrd.gsub("\n","")}
|
28
|
+
end
|
29
|
+
|
30
|
+
def progress
|
31
|
+
@progress ||= Progress.new('Compiling')
|
32
|
+
end
|
33
|
+
|
34
|
+
def generate wrds
|
35
|
+
word_parts(wrds)
|
36
|
+
# progress.init elements.size * 3 + (wrds.size)
|
37
|
+
create_element_methods
|
38
|
+
compile_fundamentals
|
39
|
+
write_word_parts
|
40
|
+
end
|
41
|
+
|
42
|
+
def play_filename
|
43
|
+
"audio/#{Params.audio_filename}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def play
|
47
|
+
cmd = play_command + ' ' + play_filename
|
48
|
+
@pid = ! @dry_run ? Process.spawn(cmd) : cmd
|
49
|
+
end
|
50
|
+
def data
|
51
|
+
{ :dot => {:name => :dot,
|
52
|
+
:filename => DOT_FILENAME,
|
53
|
+
:spb => (@sample_rate * 1.2 / @wpm).to_i },
|
54
|
+
:dash => {:name => :dash,
|
55
|
+
:filename => DASH_FILENAME,
|
56
|
+
:spb => (@sample_rate * 3.6 / @wpm).to_i },
|
57
|
+
:space => {:name => :space,
|
58
|
+
:filename => SPACE_FILENAME ,
|
59
|
+
:spb => (@sample_rate * 1.2 / @wpm).to_i },
|
60
|
+
:e_space => {:name => :e_space,
|
61
|
+
:filename => E_SPACE_FILENAME ,
|
62
|
+
:spb => (@sample_rate * 1.2 / @effective_wpm).to_i }}
|
63
|
+
end
|
64
|
+
|
65
|
+
def generate_space number_of_samples
|
66
|
+
[].fill(0.0, 0, number_of_samples)
|
67
|
+
end
|
68
|
+
|
69
|
+
def filter_maybe(size, count)
|
70
|
+
ramp = 0.05
|
71
|
+
ramp_point = @max_amplitude / ramp
|
72
|
+
ampl = (count < ramp_point) ? (ramp * count) : @max_amplitude
|
73
|
+
(count > (size - ramp_point)) ? (ramp * (size - count)) : ampl
|
74
|
+
end
|
75
|
+
|
76
|
+
def generate_tone(number_of_samples)
|
77
|
+
position_in_period, position_in_period_delta = 0.0, @frequency / @sample_rate
|
78
|
+
audio_samples = [].fill(0.0, 0, number_of_samples)
|
79
|
+
number_of_samples.times do |sample_number|
|
80
|
+
amplitude = filter_maybe(number_of_samples, sample_number)
|
81
|
+
# amplitude = 1.0 # @max_amplitude
|
82
|
+
sine_radians = ((@frequency * TWO_PI) / @sample_rate) * sample_number
|
83
|
+
audio_samples[sample_number] = amplitude * Math.sin(sine_radians)
|
84
|
+
end
|
85
|
+
audio_samples
|
86
|
+
end
|
87
|
+
|
88
|
+
def generate_buffer audio_samples, ele
|
89
|
+
WaveFile::Buffer.new(audio_samples, WaveFile::Format.new(:mono, :float, data[ele][:spb]))
|
90
|
+
end
|
91
|
+
|
92
|
+
def write_element_audio_file ele, buffer
|
93
|
+
WaveFile::Writer.new(data[ele][:filename], WaveFile::Format.new(:mono, :pcm_16, @sample_rate)) do |writer|
|
94
|
+
writer.write(buffer)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def elements
|
99
|
+
[:dot, :dash, :space, :e_space]
|
100
|
+
end
|
101
|
+
|
102
|
+
def create_element_method ele
|
103
|
+
define_singleton_method(ele) {data[ele]}
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_element_methods
|
107
|
+
elements.each do |ele|
|
108
|
+
# progress.increment
|
109
|
+
create_element_method ele
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def space_sample? ele
|
114
|
+
ele == :space || ele == :e_space
|
115
|
+
end
|
116
|
+
|
117
|
+
def generate_samples ele
|
118
|
+
return generate_space(data[ele][:spb]) if space_sample? ele
|
119
|
+
generate_tone(data[ele][:spb]) unless space_sample? ele
|
120
|
+
end
|
121
|
+
|
122
|
+
def compile_fundamentals
|
123
|
+
elements.each do |ele|
|
124
|
+
# progress.increment
|
125
|
+
audio_samples = generate_samples ele
|
126
|
+
buffer = generate_buffer(audio_samples, ele)
|
127
|
+
write_element_audio_file ele, buffer
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def space_or_espace
|
132
|
+
(@effective_wpm == @wpm) ? space : e_space
|
133
|
+
end
|
134
|
+
|
135
|
+
def last_element? idx, chr
|
136
|
+
idx == chr.size - 1
|
137
|
+
end
|
138
|
+
|
139
|
+
def push_enc chr
|
140
|
+
arry = []
|
141
|
+
chr.each_with_index do |c,idx|
|
142
|
+
arry << c
|
143
|
+
arry << ((last_element?(idx, chr)) ? (space_or_espace) : space)
|
144
|
+
end
|
145
|
+
arry += char_space
|
146
|
+
end
|
147
|
+
|
148
|
+
def send_char c
|
149
|
+
if c == ' '
|
150
|
+
enc = word_space
|
151
|
+
else
|
152
|
+
enc = cw_encoding.fetch(c).map { |enc| send(enc)}
|
153
|
+
end
|
154
|
+
push_enc enc
|
155
|
+
end
|
156
|
+
|
157
|
+
def word_parts str = nil
|
158
|
+
return @word_parts if @word_parts
|
159
|
+
@word_parts = []
|
160
|
+
str.split('').each { |part| @word_parts << part}
|
161
|
+
@word_parts
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
def make_word_parts words
|
166
|
+
parts = []
|
167
|
+
@word_parts.each do |part|
|
168
|
+
# progress.increment
|
169
|
+
parts += send_char part.downcase
|
170
|
+
end
|
171
|
+
parts
|
172
|
+
end
|
173
|
+
|
174
|
+
def prepare_buffers
|
175
|
+
@buffers = {}
|
176
|
+
elements.each do |ele|
|
177
|
+
# progress.increment
|
178
|
+
@buffers[ele] = []
|
179
|
+
WaveFile::Reader.new(data[ele][:filename]).
|
180
|
+
each_buffer(data[ele][:spb]) do |buffer|
|
181
|
+
@buffers[ele] = buffer
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def write_word_parts
|
187
|
+
prepare_buffers
|
188
|
+
write_audio_file
|
189
|
+
end
|
190
|
+
|
191
|
+
def char_space
|
192
|
+
@effective_wpm == @wpm ? [space,space] : [e_space,e_space]
|
193
|
+
end
|
194
|
+
|
195
|
+
def word_space
|
196
|
+
@effective_wpm == @wpm ? [space] : [e_space]
|
197
|
+
end
|
198
|
+
|
199
|
+
def word_composite word
|
200
|
+
send_char word.downcase
|
201
|
+
end
|
202
|
+
|
203
|
+
def write_audio
|
204
|
+
WaveFile::Writer.new(play_filename, WaveFile::Format.new(:mono, :pcm_16, @sample_rate)) do |writer|
|
205
|
+
yield.each do |char|
|
206
|
+
# progress.increment
|
207
|
+
char.each do |fta|
|
208
|
+
writer.write(@buffers[fta[:name]])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def reset
|
215
|
+
@word_parts = @progress = nil
|
216
|
+
# puts "\r"
|
217
|
+
end
|
218
|
+
|
219
|
+
def write_audio_file
|
220
|
+
write_audio { @word_parts.collect {|part| word_composite(part) } }
|
221
|
+
reset
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|