fet 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6482a7f1b9a0e8375267c1220690f706e9058b0b485bb3079c174726425594ec
4
- data.tar.gz: 0fd439a8ac3631db1f88d345bb8c50a8f0baf1dd267017b88ec7884613f4b867
3
+ metadata.gz: 67009d9f1befb2258f255e646971889e81afdc34dc56fec363a5624bffb868f0
4
+ data.tar.gz: e0277de27773dd8bebd89d2f7aedad3c4e8aac24c6a0099a00656b22ce2620ce
5
5
  SHA512:
6
- metadata.gz: 8e3bec0d13c52547ab1f71aa2197b38ec85abf794f8d2e160fbb34bf45219e006a28e47cbab9d6f86e9067694cedbff2164621684fa9339ab21c424b3f722d7f
7
- data.tar.gz: bc68f79d35ba1114f79963f027ee3155b260f462e0a6589b3e5562f82615a1910ca01ea5b2fea5e2c99c4936b31e6a75c0b4f6ad788a10e0e4358079400abdb8
6
+ metadata.gz: 119ea1729a8c11ec5f0ec54a25f47b9007cf4d23c23c89f98ed8c4f5d66829b6dfb35363592a528b3293a7b01649b8348422bf8eb123702b7bd3cebe09a1bb1c
7
+ data.tar.gz: 64620f0f58519de0bfa633d783d652a5442ebc1b34ce9a7e91a0712e164152ddb2cc315338e94f7cc7c34cbc1c1feb6b3f556094cbadf2086c2503bb1d577eb0
data/.rubocop.yml CHANGED
@@ -40,6 +40,9 @@ Layout/CaseIndentation:
40
40
  Layout/LineLength:
41
41
  Max: 175
42
42
 
43
+ Style/Lambda:
44
+ EnforcedStyle: lambda
45
+
43
46
  Style/RedundantReturn:
44
47
  Enabled: false
45
48
 
File without changes
data/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
- ## [Released]
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.0)
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
- desc("Generate MIDI files for ear training")
20
- # arg_name "Describe arguments to generate here"
21
- command(:generate) do |c|
22
- c.desc("Generate MIDI files for listening")
23
- c.long_desc("Each MIDI file will contain a chord progression, followed by the specified number of degrees - first harmonically, then melodically after a pause.")
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.2.0
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 contain a chord progression, followed by the specified number of degrees - first harmonically, then melodically after a pause.
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
+
@@ -11,7 +11,6 @@ module Fet
11
11
  tempo: options[:tempo],
12
12
  degrees: options[:degrees],
13
13
  all_single_degree: options[:"all-single-degree"],
14
- directory_prefix: options[:directory_prefix] || "",
15
14
  ).generate
16
15
  end
17
16
  end
@@ -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
@@ -9,7 +9,6 @@ module Fet
9
9
  Fet::Generator::Singing.new(
10
10
  tempo: options[:tempo],
11
11
  pause: options[:pause],
12
- directory_prefix: options[:directory_prefix] || "",
13
12
  ).generate
14
13
  end
15
14
  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
@@ -8,7 +8,6 @@ module Fet
8
8
  def self.run(_global_options, options, _args)
9
9
  Fet::Generator::SingleNoteListening.new(
10
10
  tempo: options[:tempo],
11
- directory_prefix: options[:directory_prefix] || "",
12
11
  ).generate
13
12
  end
14
13
  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
@@ -11,6 +11,7 @@ module Fet
11
11
  degrees: options[:degrees],
12
12
  key_type: options[:"key-type"],
13
13
  next_on_correct: options[:"next-on-correct"],
14
+ limit_degrees: options[:"limit-degrees"],
14
15
  ).start
15
16
  end
16
17
  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