fet 0.3.0 → 0.3.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 +4 -4
- data/.rubocop.yml +3 -0
- data/{.ruby_version → .ruby-version} +0 -0
- data/CHANGELOG.md +9 -1
- data/Gemfile.lock +4 -1
- data/README.md +15 -2
- data/bin/fet +5 -88
- data/fet.gemspec +1 -0
- data/fet.rdoc +57 -2
- data/lib/fet/cli/generate/listening.rb +0 -1
- data/lib/fet/cli/generate/listening_command.rb +72 -0
- data/lib/fet/cli/generate/singing.rb +0 -1
- data/lib/fet/cli/generate/singing_command.rb +54 -0
- data/lib/fet/cli/generate/single_note_listening.rb +0 -1
- data/lib/fet/cli/generate/single_note_listening_command.rb +46 -0
- data/lib/fet/cli/play/listening.rb +1 -0
- data/lib/fet/cli/play/listening_command.rb +76 -0
- data/lib/fet/cli/score/summary.rb +20 -0
- data/lib/fet/cli/score/summary_command.rb +74 -0
- data/lib/fet/degrees.rb +12 -2
- data/lib/fet/generator/listening.rb +11 -5
- data/lib/fet/generator/singing.rb +10 -4
- data/lib/fet/generator/single_note_listening.rb +10 -4
- data/lib/fet/score.rb +33 -2
- data/lib/fet/score_summary.rb +133 -0
- data/lib/fet/score_summary_writer.rb +51 -0
- data/lib/fet/ui/game.rb +23 -37
- data/lib/fet/ui/level.rb +4 -4
- data/lib/fet/ui/level_loop_handler.rb +4 -0
- data/lib/fet/ui/note_box.rb +7 -6
- data/lib/fet/ui/score.rb +4 -0
- data/lib/fet/version.rb +1 -1
- metadata +31 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67009d9f1befb2258f255e646971889e81afdc34dc56fec363a5624bffb868f0
|
4
|
+
data.tar.gz: e0277de27773dd8bebd89d2f7aedad3c4e8aac24c6a0099a00656b22ce2620ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 119ea1729a8c11ec5f0ec54a25f47b9007cf4d23c23c89f98ed8c4f5d66829b6dfb35363592a528b3293a7b01649b8348422bf8eb123702b7bd3cebe09a1bb1c
|
7
|
+
data.tar.gz: 64620f0f58519de0bfa633d783d652a5442ebc1b34ce9a7e91a0712e164152ddb2cc315338e94f7cc7c34cbc1c1feb6b3f556094cbadf2086c2503bb1d577eb0
|
data/.rubocop.yml
CHANGED
File without changes
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
|
1
|
+
# [Unreleased]
|
2
|
+
|
3
|
+
# [Released]
|
4
|
+
|
5
|
+
## [0.3.1] - 2021-09-27
|
6
|
+
- Allow limiting questions to specific degrees.
|
7
|
+
- Improve positioning of the score element in the UI.
|
8
|
+
- Add ability to show score summary over multiple games.
|
9
|
+
- Write game files to system temporary directory.
|
2
10
|
|
3
11
|
## [0.3.0] - 2021-09-06
|
4
12
|
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fet (0.3.
|
4
|
+
fet (0.3.1)
|
5
5
|
gli (~> 2.20, >= 2.20.1)
|
6
6
|
ice_nine (~> 0.11.2)
|
7
7
|
midilib (~> 2.0, >= 2.0.5)
|
8
8
|
ruby2d (~> 0.10.0)
|
9
|
+
terminal-table (~> 3.0, >= 3.0.1)
|
9
10
|
|
10
11
|
GEM
|
11
12
|
remote: https://rubygems.org/
|
@@ -55,6 +56,8 @@ GEM
|
|
55
56
|
simplecov_json_formatter (~> 0.1)
|
56
57
|
simplecov-html (0.12.3)
|
57
58
|
simplecov_json_formatter (0.1.3)
|
59
|
+
terminal-table (3.0.1)
|
60
|
+
unicode-display_width (>= 1.1.1, < 3)
|
58
61
|
timecop (0.9.4)
|
59
62
|
unicode-display_width (2.0.0)
|
60
63
|
|
data/README.md
CHANGED
@@ -8,6 +8,18 @@ Every level, a chord progression is played to identify a major/minor key, follow
|
|
8
8
|
<img src="./assets/readme/demo.gif">
|
9
9
|
|
10
10
|
## Installation
|
11
|
+
### Prerequisites
|
12
|
+
Install TiMidity++ for required performance improvements when converting MIDI to other formats.
|
13
|
+
#### OS X
|
14
|
+
```sh
|
15
|
+
brew install timidity
|
16
|
+
```
|
17
|
+
#### Ubuntu
|
18
|
+
```sh
|
19
|
+
apt install timidity
|
20
|
+
```
|
21
|
+
|
22
|
+
### Gem
|
11
23
|
Add this line to your application's Gemfile:
|
12
24
|
|
13
25
|
```ruby
|
@@ -29,7 +41,7 @@ The UI currently supports listening exercises, where a chord progression is play
|
|
29
41
|
|
30
42
|
The binary can be executed as follows:
|
31
43
|
```sh
|
32
|
-
fet play listening --degrees 1 --key-type major --next-on-correct --tempo 200
|
44
|
+
fet play listening --degrees 1 --key-type major --next-on-correct --tempo 200 --limit-degrees b6 --limit-degrees 5
|
33
45
|
```
|
34
46
|
|
35
47
|
All flags are optional, and serve the following purposes:
|
@@ -40,6 +52,7 @@ All flags are optional, and serve the following purposes:
|
|
40
52
|
| --key-type | Type of key to play, can be "major" or "minor". |
|
41
53
|
| --[no-]next-on-correct | Go to the next level automatically when answered correctly. |
|
42
54
|
| --tempo | The tempo at which the chord progression is played. |
|
55
|
+
| --limit-degrees | Limit to specific degrees. Can be supplied multiple times. |
|
43
56
|
|
44
57
|
When using the UI, the following keyboard shortcuts are defined to allow for mouse-free interaction:
|
45
58
|
| Keyboard Shortcut | Description |
|
@@ -49,7 +62,7 @@ When using the UI, the following keyboard shortcuts are defined to allow for mou
|
|
49
62
|
| c | Repeat the chord progression only. |
|
50
63
|
| n | Repeat the notes only. |
|
51
64
|
| l | Repeat the question (looping). |
|
52
|
-
| 1-7 | Select the degree, e.g. "2" selects the 2nd degree. |
|
65
|
+
| 1-7 | Select the degree, e.g. "2" selects the 2nd degree. Will also play that degree once the level is over. |
|
53
66
|
| - | Modify the above degree to flatten it, e.g. "-" followed by "2" will select the b2nd degree. |
|
54
67
|
| + | Modify the above degree to sharpen it, e.g. "+" followed by "4" will select the #4th degree. |
|
55
68
|
| 0 | Make the degree natural, e.g. "+" followed by followed by "0" followed by "4" will select the 4th degree. |
|
data/bin/fet
CHANGED
@@ -16,94 +16,11 @@ class App
|
|
16
16
|
subcommand_option_handling(:normal)
|
17
17
|
arguments(:strict)
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
c.command :listening do |listening|
|
25
|
-
listening.desc("Tempo at which the chord progression is played at")
|
26
|
-
listening.default_value(120)
|
27
|
-
listening.flag([:t, :tempo], type: Integer)
|
28
|
-
|
29
|
-
listening.desc("Number of degrees to play")
|
30
|
-
listening.default_value(1)
|
31
|
-
listening.flag([:d, :degrees], type: Integer, must_match: (1..11).map(&:to_s))
|
32
|
-
|
33
|
-
listening.desc("Number of exercises to generate")
|
34
|
-
listening.default_value(200)
|
35
|
-
listening.flag([:e, :exercises], type: Integer)
|
36
|
-
|
37
|
-
listening.desc("Generate all single degree listening exercises (ignores -e and -d flag)")
|
38
|
-
listening.default_value(false)
|
39
|
-
listening.switch [:a, :"all-single-degree"]
|
40
|
-
|
41
|
-
listening.action do |global_options, options, args|
|
42
|
-
Fet::Cli::Generate::Listening.run(global_options, options, args)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
command(:generate) do |c|
|
48
|
-
c.desc("Generate MIDI files for listening (single note)")
|
49
|
-
c.long_desc("Each MIDI file will contain a chord progression, followed the same note across all files.")
|
50
|
-
c.command :single_note_listening do |single_note_listening|
|
51
|
-
single_note_listening.desc("Tempo at which the chord progression is played at")
|
52
|
-
single_note_listening.default_value(120)
|
53
|
-
single_note_listening.flag([:t, :tempo], type: Integer)
|
54
|
-
|
55
|
-
single_note_listening.action do |global_options, options, args|
|
56
|
-
Fet::Cli::Generate::SingleNoteListening.run(global_options, options, args)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
command(:generate) do |c|
|
62
|
-
c.desc("Generate MIDI files for singing")
|
63
|
-
c.long_desc("Each MIDI file will contain a chord progression, followed by a specified pause, during which the degree should be sung."\
|
64
|
-
" The degree is then played for confirmation.")
|
65
|
-
c.command :singing do |singing|
|
66
|
-
singing.desc("Tempo at which the chord progression is played at")
|
67
|
-
singing.default_value(120)
|
68
|
-
singing.flag([:t, :tempo], type: Integer)
|
69
|
-
|
70
|
-
singing.desc("How many seconds to wait before playing the correct note")
|
71
|
-
singing.default_value(3)
|
72
|
-
singing.flag([:p, :pause], type: Integer)
|
73
|
-
|
74
|
-
singing.action do |global_options, options, args|
|
75
|
-
Fet::Cli::Generate::Singing.run(global_options, options, args)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
desc("Run the ear training application")
|
81
|
-
# arg_name "Describe arguments to generate here"
|
82
|
-
command(:play) do |c|
|
83
|
-
c.desc("Run the ear training application for listening")
|
84
|
-
c.long_desc("Each level will contain a chord progression, followed by the specified number of degrees - first harmonically, then melodically after a pause.")
|
85
|
-
c.command :listening do |listening|
|
86
|
-
listening.desc("Tempo at which the chord progression is played at")
|
87
|
-
listening.default_value(120)
|
88
|
-
listening.flag([:t, :tempo], type: Integer)
|
89
|
-
|
90
|
-
listening.desc("Number of degrees to play")
|
91
|
-
listening.default_value(1)
|
92
|
-
listening.flag([:d, :degrees], type: Integer, must_match: (1..11).map(&:to_s))
|
93
|
-
|
94
|
-
listening.desc("Type of the chord progression")
|
95
|
-
listening.default_value("major")
|
96
|
-
listening.flag([:k, :"key-type"], type: String, must_match: ["major", "minor"])
|
97
|
-
|
98
|
-
listening.desc("Automatically go to the next exercise when the answer was correct")
|
99
|
-
listening.default_value(true)
|
100
|
-
listening.switch [:n, :"next-on-correct"]
|
101
|
-
|
102
|
-
listening.action do |global_options, options, args|
|
103
|
-
Fet::Cli::Play::Listening.run(global_options, options, args)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
19
|
+
include ::Fet::Cli::Generate::ListeningCommand
|
20
|
+
include ::Fet::Cli::Generate::SingleNoteListeningCommand
|
21
|
+
include ::Fet::Cli::Generate::SingingCommand
|
22
|
+
include ::Fet::Cli::Play::ListeningCommand
|
23
|
+
include ::Fet::Cli::Score::SummaryCommand
|
107
24
|
|
108
25
|
on_error do |exception|
|
109
26
|
puts exception.backtrace
|
data/fet.gemspec
CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_dependency "ice_nine", "~> 0.11.2"
|
33
33
|
spec.add_dependency "midilib", "~> 2.0", ">= 2.0.5"
|
34
34
|
spec.add_dependency "ruby2d", "~> 0.10.0"
|
35
|
+
spec.add_dependency "terminal-table", "~> 3.0", ">= 3.0.1"
|
35
36
|
|
36
37
|
# RDoc configuration
|
37
38
|
spec.extra_rdoc_files = ["README.rdoc", "fet.rdoc"]
|
data/fet.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
== fet - Functional Ear Trainer
|
2
2
|
|
3
|
-
v0.
|
3
|
+
v0.3.0
|
4
4
|
|
5
5
|
=== Global Options
|
6
6
|
=== --help
|
@@ -100,7 +100,7 @@ Run the ear training application
|
|
100
100
|
====== Command: <tt>listening </tt>
|
101
101
|
Run the ear training application for listening
|
102
102
|
|
103
|
-
Each level will
|
103
|
+
Each level will play a chord progression, followed by the specified number of degrees harmonically. The correct degrees should be selected.
|
104
104
|
======= Options
|
105
105
|
======= -d|--degrees arg
|
106
106
|
|
@@ -118,6 +118,14 @@ Type of the chord progression
|
|
118
118
|
[Must Match] ["major", "minor"]
|
119
119
|
|
120
120
|
|
121
|
+
======= -l|--limit-degrees arg
|
122
|
+
|
123
|
+
Limit which degrees can play
|
124
|
+
|
125
|
+
[Default Value] []
|
126
|
+
[Must Match] ["1", "#1", "b2", "2", "#2", "b3", "3", "4", "#4", "b5", "5", "#5", "b6", "6", "#6", "b7", "7"]
|
127
|
+
|
128
|
+
|
121
129
|
======= -t|--tempo arg
|
122
130
|
|
123
131
|
Tempo at which the chord progression is played at
|
@@ -130,3 +138,50 @@ Automatically go to the next exercise when the answer was correct
|
|
130
138
|
|
131
139
|
|
132
140
|
|
141
|
+
==== Command: <tt>score </tt>
|
142
|
+
Score commands
|
143
|
+
|
144
|
+
|
145
|
+
===== Commands
|
146
|
+
====== Command: <tt>summary </tt>
|
147
|
+
Show the score summary
|
148
|
+
|
149
|
+
|
150
|
+
======= Options
|
151
|
+
======= -b|--begin-offset arg
|
152
|
+
|
153
|
+
Offset beginning index of resulting array
|
154
|
+
|
155
|
+
[Default Value] 0
|
156
|
+
|
157
|
+
|
158
|
+
======= -d|--degrees arg
|
159
|
+
|
160
|
+
Number of degrees to play
|
161
|
+
|
162
|
+
[Default Value] 1
|
163
|
+
[Must Match] ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]
|
164
|
+
|
165
|
+
|
166
|
+
======= -e|--end-offset arg
|
167
|
+
|
168
|
+
Offset end index of resulting array
|
169
|
+
|
170
|
+
[Default Value] 0
|
171
|
+
|
172
|
+
|
173
|
+
======= -k|--key-type arg
|
174
|
+
|
175
|
+
Type of the chord progression
|
176
|
+
|
177
|
+
[Default Value] major
|
178
|
+
[Must Match] ["major", "minor"]
|
179
|
+
|
180
|
+
|
181
|
+
======= -s|--seconds arg
|
182
|
+
|
183
|
+
Only include games that had greater or equal playtime to the specified amount (in seconds)
|
184
|
+
|
185
|
+
[Default Value] 0
|
186
|
+
|
187
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Cli
|
5
|
+
module Generate
|
6
|
+
# Defines the CLI "generate listening" command
|
7
|
+
module ListeningCommand
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
|
12
|
+
desc("Generate MIDI files for ear training")
|
13
|
+
command(:generate) do |c|
|
14
|
+
define_listening_command(c)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal methods for the "generate listening" command
|
20
|
+
module ClassMethods
|
21
|
+
private
|
22
|
+
|
23
|
+
def define_listening_command(command)
|
24
|
+
command.desc("Generate MIDI files for listening")
|
25
|
+
command.long_desc(long_listening_command_description)
|
26
|
+
command.command :listening do |listening|
|
27
|
+
define_tempo_flag(listening)
|
28
|
+
define_degrees_flag(listening)
|
29
|
+
define_exerises_flag(listening)
|
30
|
+
define_all_single_degree_flag(listening)
|
31
|
+
define_action(listening)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def long_listening_command_description
|
36
|
+
return "Each MIDI file will contain a chord progression, followed by the specified number of degrees - first harmonically, then melodically after a pause."
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_tempo_flag(command)
|
40
|
+
command.desc("Tempo at which the chord progression is played at")
|
41
|
+
command.default_value(120)
|
42
|
+
command.flag([:t, :tempo], type: Integer)
|
43
|
+
end
|
44
|
+
|
45
|
+
def define_degrees_flag(command)
|
46
|
+
command.desc("Number of degrees to play")
|
47
|
+
command.default_value(1)
|
48
|
+
command.flag([:d, :degrees], type: Integer, must_match: (1..11).map(&:to_s))
|
49
|
+
end
|
50
|
+
|
51
|
+
def define_exerises_flag(command)
|
52
|
+
command.desc("Number of exercises to generate")
|
53
|
+
command.default_value(200)
|
54
|
+
command.flag([:e, :exercises], type: Integer)
|
55
|
+
end
|
56
|
+
|
57
|
+
def define_all_single_degree_flag(command)
|
58
|
+
command.desc("Generate all single degree listening exercises (ignores -e and -d flag)")
|
59
|
+
command.default_value(false)
|
60
|
+
command.switch [:a, :"all-single-degree"]
|
61
|
+
end
|
62
|
+
|
63
|
+
def define_action(command)
|
64
|
+
command.action do |global_options, options, args|
|
65
|
+
Fet::Cli::Generate::Listening.run(global_options, options, args)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Cli
|
5
|
+
module Generate
|
6
|
+
# Defines the CLI "generate singing" command
|
7
|
+
module SingingCommand
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
|
12
|
+
command(:generate) do |c|
|
13
|
+
define_singing_command(c)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Internal methods for the "generate singing" command
|
19
|
+
module ClassMethods
|
20
|
+
private
|
21
|
+
|
22
|
+
def define_singing_command(command)
|
23
|
+
command.desc("Generate MIDI files for singing")
|
24
|
+
command.long_desc("Each MIDI file will contain a chord progression, followed by a specified pause, during which the degree should be sung."\
|
25
|
+
" The degree is then played for confirmation.")
|
26
|
+
command.command :singing do |singing|
|
27
|
+
define_tempo_flag(singing)
|
28
|
+
define_pause_flag(singing)
|
29
|
+
define_singing_action(singing)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def define_tempo_flag(command)
|
34
|
+
command.desc("Tempo at which the chord progression is played at")
|
35
|
+
command.default_value(120)
|
36
|
+
command.flag([:t, :tempo], type: Integer)
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_pause_flag(command)
|
40
|
+
command.desc("How many seconds to wait before playing the correct note")
|
41
|
+
command.default_value(3)
|
42
|
+
command.flag([:p, :pause], type: Integer)
|
43
|
+
end
|
44
|
+
|
45
|
+
def define_singing_action(command)
|
46
|
+
command.action do |global_options, options, args|
|
47
|
+
Fet::Cli::Generate::Singing.run(global_options, options, args)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Cli
|
5
|
+
module Generate
|
6
|
+
# Defines the CLI "generate single_note_listening" command
|
7
|
+
module SingleNoteListeningCommand
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
|
12
|
+
command(:generate) do |c|
|
13
|
+
define_single_note_listening_command(c)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Internal methods for the "generate single_note_listening" command
|
19
|
+
module ClassMethods
|
20
|
+
private
|
21
|
+
|
22
|
+
def define_single_note_listening_command(command)
|
23
|
+
command.desc("Generate MIDI files for listening (single note)")
|
24
|
+
command.long_desc("Each MIDI file will contain a chord progression, followed the same note across all files.")
|
25
|
+
command.command :single_note_listening do |single_note_listening|
|
26
|
+
define_tempo_flag(single_note_listening)
|
27
|
+
define_single_note_listening_action(single_note_listening)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def define_tempo_flag(command)
|
32
|
+
command.desc("Tempo at which the chord progression is played at")
|
33
|
+
command.default_value(120)
|
34
|
+
command.flag([:t, :tempo], type: Integer)
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_single_note_listening_action(command)
|
38
|
+
command.action do |global_options, options, args|
|
39
|
+
Fet::Cli::Generate::SingleNoteListening.run(global_options, options, args)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Cli
|
5
|
+
module Play
|
6
|
+
# Defines the CLI "play listening" command
|
7
|
+
module ListeningCommand
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
|
12
|
+
desc("Run the ear training application")
|
13
|
+
command(:play) do |c|
|
14
|
+
define_listening_command(c)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal methods for the "play listening" command
|
20
|
+
module ClassMethods
|
21
|
+
private
|
22
|
+
|
23
|
+
def define_listening_command(command)
|
24
|
+
command.desc("Run the ear training application for listening")
|
25
|
+
command.long_desc("Each level will play a chord progression, followed by the specified number of degrees harmonically. The correct degrees should be selected.")
|
26
|
+
command.command :listening do |listening|
|
27
|
+
define_tempo_flag(listening)
|
28
|
+
define_degrees_flag(listening)
|
29
|
+
define_key_type_flag(listening)
|
30
|
+
define_next_on_correct_flag(listening)
|
31
|
+
define_limit_degrees_flag(listening)
|
32
|
+
|
33
|
+
define_listening_action(listening)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_tempo_flag(command)
|
38
|
+
command.desc("Tempo at which the chord progression is played at")
|
39
|
+
command.default_value(120)
|
40
|
+
command.flag([:t, :tempo], type: Integer)
|
41
|
+
end
|
42
|
+
|
43
|
+
def define_degrees_flag(command)
|
44
|
+
command.desc("Number of degrees to play")
|
45
|
+
command.default_value(1)
|
46
|
+
command.flag([:d, :degrees], type: Integer, must_match: (1..11).map(&:to_s))
|
47
|
+
end
|
48
|
+
|
49
|
+
def define_key_type_flag(command)
|
50
|
+
command.desc("Type of the chord progression")
|
51
|
+
command.default_value("major")
|
52
|
+
command.flag([:k, :"key-type"], type: String, must_match: ["major", "minor"])
|
53
|
+
end
|
54
|
+
|
55
|
+
def define_next_on_correct_flag(command)
|
56
|
+
command.desc("Automatically go to the next exercise when the answer was correct")
|
57
|
+
command.default_value(true)
|
58
|
+
command.switch [:n, :"next-on-correct"]
|
59
|
+
end
|
60
|
+
|
61
|
+
def define_limit_degrees_flag(command)
|
62
|
+
command.desc("Limit which degrees can play")
|
63
|
+
command.default_value([])
|
64
|
+
command.flag([:l, :"limit-degrees"], type: String, must_match: Fet::Degree::DEGREE_NAMES.flatten, multiple: true)
|
65
|
+
end
|
66
|
+
|
67
|
+
def define_listening_action(command)
|
68
|
+
command.action do |global_options, options, args|
|
69
|
+
Fet::Cli::Play::Listening.run(global_options, options, args)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Cli
|
5
|
+
module Score
|
6
|
+
# CLI implementation for the "score summary" command
|
7
|
+
module Summary
|
8
|
+
def self.run(_global_options, options, _args)
|
9
|
+
Fet::ScoreSummary.new(
|
10
|
+
minimum_session_length: options[:seconds],
|
11
|
+
number_of_degrees: options[:degrees],
|
12
|
+
key_type: options[:"key-type"],
|
13
|
+
begin_offset: options[:"begin-offset"],
|
14
|
+
end_offset: options[:"end-offset"],
|
15
|
+
).summary
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Cli
|
5
|
+
module Score
|
6
|
+
# Defines the CLI "score summary" command
|
7
|
+
module SummaryCommand
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
|
12
|
+
desc("Score commands")
|
13
|
+
command(:score) do |c|
|
14
|
+
define_summary_command(c)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal methods for the "score summary" command
|
20
|
+
module ClassMethods
|
21
|
+
private
|
22
|
+
|
23
|
+
def define_summary_command(command)
|
24
|
+
command.desc("Show the score summary")
|
25
|
+
command.command :summary do |summary|
|
26
|
+
define_seconds_flag(summary)
|
27
|
+
define_degrees_flag(summary)
|
28
|
+
define_key_type_flag(summary)
|
29
|
+
define_begin_offset_flag(summary)
|
30
|
+
define_end_offset_flag(summary)
|
31
|
+
define_score_action(summary)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def define_seconds_flag(command)
|
36
|
+
command.desc("Only include games that had greater or equal playtime to the specified amount (in seconds)")
|
37
|
+
command.default_value(0)
|
38
|
+
command.flag([:s, :seconds], type: Integer)
|
39
|
+
end
|
40
|
+
|
41
|
+
def define_degrees_flag(command)
|
42
|
+
command.desc("Number of degrees to play")
|
43
|
+
command.default_value(1)
|
44
|
+
command.flag([:d, :degrees], type: Integer, must_match: (1..11).map(&:to_s))
|
45
|
+
end
|
46
|
+
|
47
|
+
def define_key_type_flag(command)
|
48
|
+
command.desc("Type of the chord progression")
|
49
|
+
command.default_value("major")
|
50
|
+
command.flag([:k, :"key-type"], type: String, must_match: ["major", "minor"])
|
51
|
+
end
|
52
|
+
|
53
|
+
def define_begin_offset_flag(command)
|
54
|
+
command.desc("Offset beginning index of resulting array")
|
55
|
+
command.default_value(0)
|
56
|
+
command.flag([:b, :"begin-offset"], type: Integer)
|
57
|
+
end
|
58
|
+
|
59
|
+
def define_end_offset_flag(command)
|
60
|
+
command.desc("Offset end index of resulting array")
|
61
|
+
command.default_value(0)
|
62
|
+
command.flag([:e, :"end-offset"], type: Integer)
|
63
|
+
end
|
64
|
+
|
65
|
+
def define_score_action(command)
|
66
|
+
command.action do |global_options, options, args|
|
67
|
+
Fet::Cli::Score::Summary.run(global_options, options, args)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|