fet 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +2 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +9 -3
- data/Gemfile +2 -0
- data/Gemfile.lock +7 -1
- data/README.md +43 -6
- data/assets/fonts/PTSans/OFL.txt +94 -0
- data/assets/fonts/PTSans/PTSans-Bold.ttf +0 -0
- data/assets/fonts/PTSans/PTSans-BoldItalic.ttf +0 -0
- data/assets/fonts/PTSans/PTSans-Italic.ttf +0 -0
- data/assets/fonts/PTSans/PTSans-Regular.ttf +0 -0
- data/assets/readme/demo.gif +0 -0
- data/bin/fet +32 -5
- data/fet.gemspec +1 -0
- data/fet.rdoc +38 -0
- data/lib/fet/cli/play/listening.rb +19 -0
- data/lib/fet/degree.rb +4 -0
- data/lib/fet/degrees.rb +19 -2
- data/lib/fet/exceptions.rb +4 -0
- data/lib/fet/generator/listening.rb +21 -24
- data/lib/fet/midi_file_generator.rb +48 -0
- data/lib/fet/midilib_interface.rb +2 -26
- data/lib/fet/score.rb +52 -0
- data/lib/fet/ui/color_scheme.rb +13 -0
- data/lib/fet/ui/custom_event.rb +45 -0
- data/lib/fet/ui/game.rb +87 -0
- data/lib/fet/ui/game_loop_handler.rb +74 -0
- data/lib/fet/ui/game_setup_helper.rb +49 -0
- data/lib/fet/ui/key.rb +44 -0
- data/lib/fet/ui/level.rb +108 -0
- data/lib/fet/ui/level_loop_handler.rb +57 -0
- data/lib/fet/ui/note_box.rb +117 -0
- data/lib/fet/ui/note_box_loop_handler.rb +107 -0
- data/lib/fet/ui/note_boxes.rb +81 -0
- data/lib/fet/ui/score.rb +85 -0
- data/lib/fet/ui/timer.rb +81 -0
- data/lib/fet/version.rb +1 -1
- data/lib/fet.rb +3 -0
- metadata +38 -3
- data/LICENSE.txt +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6482a7f1b9a0e8375267c1220690f706e9058b0b485bb3079c174726425594ec
|
4
|
+
data.tar.gz: 0fd439a8ac3631db1f88d345bb8c50a8f0baf1dd267017b88ec7884613f4b867
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e3bec0d13c52547ab1f71aa2197b38ec85abf794f8d2e160fbb34bf45219e006a28e47cbab9d6f86e9067694cedbff2164621684fa9339ab21c424b3f722d7f
|
7
|
+
data.tar.gz: bc68f79d35ba1114f79963f027ee3155b260f462e0a6589b3e5562f82615a1910ca01ea5b2fea5e2c99c4936b31e6a75c0b4f6ad788a10e0e4358079400abdb8
|
data/.github/workflows/main.yml
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
-
## [
|
1
|
+
## [Released]
|
2
2
|
|
3
|
-
## [0.
|
3
|
+
## [0.3.0] - 2021-09-06
|
4
4
|
|
5
|
-
-
|
5
|
+
- Smoother singing MIDI exercises.
|
6
|
+
- UI for listening exercises.
|
7
|
+
|
8
|
+
## [0.2.0] - 2021-09-01
|
9
|
+
|
10
|
+
- Initial release.
|
11
|
+
- Convert individual binaries to a self-contained gem and add 100% test coverage.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fet (0.
|
4
|
+
fet (0.3.0)
|
5
5
|
gli (~> 2.20, >= 2.20.1)
|
6
6
|
ice_nine (~> 0.11.2)
|
7
7
|
midilib (~> 2.0, >= 2.0.5)
|
8
|
+
ruby2d (~> 0.10.0)
|
8
9
|
|
9
10
|
GEM
|
10
11
|
remote: https://rubygems.org/
|
@@ -20,6 +21,7 @@ GEM
|
|
20
21
|
method_source (1.0.0)
|
21
22
|
midilib (2.0.5)
|
22
23
|
minitest (5.14.4)
|
24
|
+
minitest-stub_any_instance (1.0.2)
|
23
25
|
parallel (1.20.1)
|
24
26
|
parser (3.0.2.0)
|
25
27
|
ast (~> 2.4.1)
|
@@ -46,12 +48,14 @@ GEM
|
|
46
48
|
rubocop-ast (1.11.0)
|
47
49
|
parser (>= 3.0.1.1)
|
48
50
|
ruby-progressbar (1.11.0)
|
51
|
+
ruby2d (0.10.0)
|
49
52
|
simplecov (0.21.2)
|
50
53
|
docile (~> 1.1)
|
51
54
|
simplecov-html (~> 0.11)
|
52
55
|
simplecov_json_formatter (~> 0.1)
|
53
56
|
simplecov-html (0.12.3)
|
54
57
|
simplecov_json_formatter (0.1.3)
|
58
|
+
timecop (0.9.4)
|
55
59
|
unicode-display_width (2.0.0)
|
56
60
|
|
57
61
|
PLATFORMS
|
@@ -61,11 +65,13 @@ DEPENDENCIES
|
|
61
65
|
codecov (~> 0.6.0)
|
62
66
|
fet!
|
63
67
|
minitest (~> 5.0)
|
68
|
+
minitest-stub_any_instance (~> 1.0, >= 1.0.2)
|
64
69
|
pry-byebug (~> 3.9)
|
65
70
|
rake (~> 13.0)
|
66
71
|
rdoc (~> 6.3, >= 6.3.2)
|
67
72
|
rubocop (~> 1.7)
|
68
73
|
simplecov (~> 0.21.2)
|
74
|
+
timecop (~> 0.9.4)
|
69
75
|
|
70
76
|
BUNDLED WITH
|
71
77
|
2.2.22
|
data/README.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
[![codecov](https://codecov.io/gh/DimitriosLisenko/fet/branch/master/graph/badge.svg?token=6W2B0Z4E4S)](https://codecov.io/gh/DimitriosLisenko/fet)
|
2
2
|
|
3
3
|
# FET (Functional Ear Trainer)
|
4
|
-
|
4
|
+
This is a functional ear trainer, meaning that it teaches you to identify degrees in a key.
|
5
|
+
|
6
|
+
Every level, a chord progression is played to identify a major/minor key, followed by random notes played harmonically. The degrees of these notes should be identified and selected.
|
7
|
+
|
8
|
+
<img src="./assets/readme/demo.gif">
|
5
9
|
|
6
10
|
## Installation
|
7
11
|
Add this line to your application's Gemfile:
|
@@ -19,12 +23,42 @@ Or install it yourself as:
|
|
19
23
|
$ gem install fet
|
20
24
|
|
21
25
|
## Usage
|
22
|
-
Refer to [the rdoc](https://github.com/DimitriosLisenko/fet/blob/master/fet.rdoc) for detailed usage instructions and descriptions of commands.
|
23
26
|
|
24
|
-
|
27
|
+
### Ear Training via the UI
|
28
|
+
The UI currently supports listening exercises, where a chord progression is played to establish a key, followed by notes played harmonically. The degrees of these notes should be identified by selecting them in the UI.
|
29
|
+
|
30
|
+
The binary can be executed as follows:
|
31
|
+
```sh
|
32
|
+
fet play listening --degrees 1 --key-type major --next-on-correct --tempo 200
|
33
|
+
```
|
34
|
+
|
35
|
+
All flags are optional, and serve the following purposes:
|
36
|
+
|
37
|
+
| Flag | Description |
|
38
|
+
| ------------- | ------------- |
|
39
|
+
| --degrees | How many unique degrees to play for the random notes - maximum of 11. |
|
40
|
+
| --key-type | Type of key to play, can be "major" or "minor". |
|
41
|
+
| --[no-]next-on-correct | Go to the next level automatically when answered correctly. |
|
42
|
+
| --tempo | The tempo at which the chord progression is played. |
|
43
|
+
|
44
|
+
When using the UI, the following keyboard shortcuts are defined to allow for mouse-free interaction:
|
45
|
+
| Keyboard Shortcut | Description |
|
46
|
+
| ------------- | ------------- |
|
47
|
+
| ENTER | Go to the next level once this level is over. |
|
48
|
+
| q | Quit the application. |
|
49
|
+
| c | Repeat the chord progression only. |
|
50
|
+
| n | Repeat the notes only. |
|
51
|
+
| l | Repeat the question (looping). |
|
52
|
+
| 1-7 | Select the degree, e.g. "2" selects the 2nd degree. |
|
53
|
+
| - | Modify the above degree to flatten it, e.g. "-" followed by "2" will select the b2nd degree. |
|
54
|
+
| + | Modify the above degree to sharpen it, e.g. "+" followed by "4" will select the #4th degree. |
|
55
|
+
| 0 | Make the degree natural, e.g. "+" followed by followed by "0" followed by "4" will select the 4th degree. |
|
56
|
+
|
57
|
+
### Ear Training via MIDI files
|
58
|
+
#### Filename Format
|
25
59
|
The generators will currently create MIDI files. The correct answer is included in the filename.
|
26
60
|
|
27
|
-
|
61
|
+
#### Listening exercises
|
28
62
|
For listening exercises, here is a potential list of generated MIDI files (for 2 degrees):
|
29
63
|
```sh
|
30
64
|
$ find .
|
@@ -54,7 +88,7 @@ The file name contains all the information required for the answer. For example,
|
|
54
88
|
|
55
89
|
`(G#2)`: the [scientific pitch notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation) of which is G#2
|
56
90
|
|
57
|
-
|
91
|
+
#### Singing exercises
|
58
92
|
The singing exercises will generate all possible combinations for keys and degrees as follows:
|
59
93
|
```sh
|
60
94
|
$ find .
|
@@ -78,7 +112,7 @@ The file name contains all the information required for the answer. For example,
|
|
78
112
|
|
79
113
|
`3`: you should sing the 3rd degree.
|
80
114
|
|
81
|
-
|
115
|
+
#### Single Note Listening exercises
|
82
116
|
For single note listening exercises, the same note is played across all possible keys:
|
83
117
|
```sh
|
84
118
|
$ find .
|
@@ -98,6 +132,9 @@ The file name contains all the information required for the answer. For example,
|
|
98
132
|
|
99
133
|
`3`: the note that is played is the 3rd degree in this key.
|
100
134
|
|
135
|
+
### More Information
|
136
|
+
Refer to [the rdoc](https://github.com/DimitriosLisenko/fet/blob/master/fet.rdoc) for detailed usage instructions and descriptions of commands.
|
137
|
+
|
101
138
|
## Development
|
102
139
|
|
103
140
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,94 @@
|
|
1
|
+
Copyright (c) 2010, ParaType Ltd. (http://www.paratype.com/public),
|
2
|
+
with Reserved Font Names "PT Sans" and "ParaType".
|
3
|
+
|
4
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
5
|
+
This license is copied below, and is also available with a FAQ at:
|
6
|
+
http://scripts.sil.org/OFL
|
7
|
+
|
8
|
+
|
9
|
+
-----------------------------------------------------------
|
10
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
11
|
+
-----------------------------------------------------------
|
12
|
+
|
13
|
+
PREAMBLE
|
14
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
15
|
+
development of collaborative font projects, to support the font creation
|
16
|
+
efforts of academic and linguistic communities, and to provide a free and
|
17
|
+
open framework in which fonts may be shared and improved in partnership
|
18
|
+
with others.
|
19
|
+
|
20
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
21
|
+
redistributed freely as long as they are not sold by themselves. The
|
22
|
+
fonts, including any derivative works, can be bundled, embedded,
|
23
|
+
redistributed and/or sold with any software provided that any reserved
|
24
|
+
names are not used by derivative works. The fonts and derivatives,
|
25
|
+
however, cannot be released under any other type of license. The
|
26
|
+
requirement for fonts to remain under this license does not apply
|
27
|
+
to any document created using the fonts or their derivatives.
|
28
|
+
|
29
|
+
DEFINITIONS
|
30
|
+
"Font Software" refers to the set of files released by the Copyright
|
31
|
+
Holder(s) under this license and clearly marked as such. This may
|
32
|
+
include source files, build scripts and documentation.
|
33
|
+
|
34
|
+
"Reserved Font Name" refers to any names specified as such after the
|
35
|
+
copyright statement(s).
|
36
|
+
|
37
|
+
"Original Version" refers to the collection of Font Software components as
|
38
|
+
distributed by the Copyright Holder(s).
|
39
|
+
|
40
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
41
|
+
or substituting -- in part or in whole -- any of the components of the
|
42
|
+
Original Version, by changing formats or by porting the Font Software to a
|
43
|
+
new environment.
|
44
|
+
|
45
|
+
"Author" refers to any designer, engineer, programmer, technical
|
46
|
+
writer or other person who contributed to the Font Software.
|
47
|
+
|
48
|
+
PERMISSION & CONDITIONS
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
50
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
51
|
+
redistribute, and sell modified and unmodified copies of the Font
|
52
|
+
Software, subject to the following conditions:
|
53
|
+
|
54
|
+
1) Neither the Font Software nor any of its individual components,
|
55
|
+
in Original or Modified Versions, may be sold by itself.
|
56
|
+
|
57
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
58
|
+
redistributed and/or sold with any software, provided that each copy
|
59
|
+
contains the above copyright notice and this license. These can be
|
60
|
+
included either as stand-alone text files, human-readable headers or
|
61
|
+
in the appropriate machine-readable metadata fields within text or
|
62
|
+
binary files as long as those fields can be easily viewed by the user.
|
63
|
+
|
64
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
65
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
66
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
67
|
+
presented to the users.
|
68
|
+
|
69
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
70
|
+
Software shall not be used to promote, endorse or advertise any
|
71
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
72
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
73
|
+
permission.
|
74
|
+
|
75
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
76
|
+
must be distributed entirely under this license, and must not be
|
77
|
+
distributed under any other license. The requirement for fonts to
|
78
|
+
remain under this license does not apply to any document created
|
79
|
+
using the Font Software.
|
80
|
+
|
81
|
+
TERMINATION
|
82
|
+
This license becomes null and void if any of the above conditions are
|
83
|
+
not met.
|
84
|
+
|
85
|
+
DISCLAIMER
|
86
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
87
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
88
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
89
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
90
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
91
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
92
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
93
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
94
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/bin/fet
CHANGED
@@ -77,11 +77,38 @@ class App
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
107
|
+
|
108
|
+
on_error do |exception|
|
109
|
+
puts exception.backtrace
|
110
|
+
true
|
111
|
+
end
|
85
112
|
end
|
86
113
|
|
87
114
|
exit App.run(ARGV)
|
data/fet.gemspec
CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_dependency "gli", "~> 2.20", ">= 2.20.1"
|
32
32
|
spec.add_dependency "ice_nine", "~> 0.11.2"
|
33
33
|
spec.add_dependency "midilib", "~> 2.0", ">= 2.0.5"
|
34
|
+
spec.add_dependency "ruby2d", "~> 0.10.0"
|
34
35
|
|
35
36
|
# RDoc configuration
|
36
37
|
spec.extra_rdoc_files = ["README.rdoc", "fet.rdoc"]
|
data/fet.rdoc
CHANGED
@@ -92,3 +92,41 @@ List commands one per line, to assist with shell completion
|
|
92
92
|
|
93
93
|
|
94
94
|
|
95
|
+
==== Command: <tt>play </tt>
|
96
|
+
Run the ear training application
|
97
|
+
|
98
|
+
|
99
|
+
===== Commands
|
100
|
+
====== Command: <tt>listening </tt>
|
101
|
+
Run the ear training application for listening
|
102
|
+
|
103
|
+
Each level will contain a chord progression, followed by the specified number of degrees - first harmonically, then melodically after a pause.
|
104
|
+
======= Options
|
105
|
+
======= -d|--degrees arg
|
106
|
+
|
107
|
+
Number of degrees to play
|
108
|
+
|
109
|
+
[Default Value] 1
|
110
|
+
[Must Match] ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]
|
111
|
+
|
112
|
+
|
113
|
+
======= -k|--key-type arg
|
114
|
+
|
115
|
+
Type of the chord progression
|
116
|
+
|
117
|
+
[Default Value] major
|
118
|
+
[Must Match] ["major", "minor"]
|
119
|
+
|
120
|
+
|
121
|
+
======= -t|--tempo arg
|
122
|
+
|
123
|
+
Tempo at which the chord progression is played at
|
124
|
+
|
125
|
+
[Default Value] 120
|
126
|
+
|
127
|
+
|
128
|
+
======= -n|--[no-]next-on-correct
|
129
|
+
Automatically go to the next exercise when the answer was correct
|
130
|
+
|
131
|
+
|
132
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Cli
|
5
|
+
module Play
|
6
|
+
# CLI implementation for the "play listening" command
|
7
|
+
module Listening
|
8
|
+
def self.run(_global_options, options, _args)
|
9
|
+
Fet::Ui::Game.new(
|
10
|
+
tempo: options[:tempo],
|
11
|
+
degrees: options[:degrees],
|
12
|
+
key_type: options[:"key-type"],
|
13
|
+
next_on_correct: options[:"next-on-correct"],
|
14
|
+
).start
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/fet/degree.rb
CHANGED
data/lib/fet/degrees.rb
CHANGED
@@ -23,10 +23,18 @@ module Fet
|
|
23
23
|
return Degree::DEGREE_NAMES[degree_index_of_midi_value(midi_value)]
|
24
24
|
end
|
25
25
|
|
26
|
+
def degree_index_of_midi_value(midi_value)
|
27
|
+
return MidiNote.new(midi_value).degree(root_midi_value)
|
28
|
+
end
|
29
|
+
|
26
30
|
def note_name_of_degree(degree_name)
|
27
31
|
return degree_to_note_name[Degree.new(degree_name).degree_name]
|
28
32
|
end
|
29
33
|
|
34
|
+
def select_degrees_from_midi_values(midi_value_range, number_of_degrees)
|
35
|
+
return select_degrees_from_midi_values_recursive(midi_value_range, [], number_of_degrees)
|
36
|
+
end
|
37
|
+
|
30
38
|
private
|
31
39
|
|
32
40
|
attr_writer :root_name,
|
@@ -54,8 +62,17 @@ module Fet
|
|
54
62
|
return result
|
55
63
|
end
|
56
64
|
|
57
|
-
def
|
58
|
-
return
|
65
|
+
def select_degrees_from_midi_values_recursive(all_notes, chosen_notes, number_of_degrees)
|
66
|
+
return chosen_notes if number_of_degrees.zero?
|
67
|
+
|
68
|
+
selected_note = all_notes.sample
|
69
|
+
chosen_notes << selected_note
|
70
|
+
|
71
|
+
all_notes_without_note_degree = all_notes.reject do |note|
|
72
|
+
Fet::MidiNote.new(note).degree(root_midi_value) == Fet::MidiNote.new(selected_note).degree(root_midi_value)
|
73
|
+
end
|
74
|
+
|
75
|
+
select_degrees_from_midi_values_recursive(all_notes_without_note_degree, chosen_notes, number_of_degrees - 1)
|
59
76
|
end
|
60
77
|
end
|
61
78
|
end
|