fet 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a6eaf2c2012e548d709b7c60d8bb087f55062ea7a069fade95adb5ee04f8c70
4
- data.tar.gz: d9a82a31165883c5219fd94b042dcc0ceda2c12e4e2c8fb915257e5bb02e6df6
3
+ metadata.gz: 6482a7f1b9a0e8375267c1220690f706e9058b0b485bb3079c174726425594ec
4
+ data.tar.gz: 0fd439a8ac3631db1f88d345bb8c50a8f0baf1dd267017b88ec7884613f4b867
5
5
  SHA512:
6
- metadata.gz: 9c78069eab1b047f0e7bf72580e5d5dac1c12467e606ff8be3637fcd202a6e666d009900bbcee3e7bad66992fbf488df3abe049d0a14494a54c9209223401d30
7
- data.tar.gz: b7d43fc3d8edff904615b9e6b681edc4b77d6becca9beee2a137c3b2e8fdd0071aab9953dffd090a3f107f5b0e24054fd5af4cdfba544920949aa6ee39490fd6
6
+ metadata.gz: 8e3bec0d13c52547ab1f71aa2197b38ec85abf794f8d2e160fbb34bf45219e006a28e47cbab9d6f86e9067694cedbff2164621684fa9339ab21c424b3f722d7f
7
+ data.tar.gz: bc68f79d35ba1114f79963f027ee3155b260f462e0a6589b3e5562f82615a1910ca01ea5b2fea5e2c99c4936b31e6a75c0b4f6ad788a10e0e4358079400abdb8
@@ -7,6 +7,8 @@ jobs:
7
7
  runs-on: ubuntu-latest
8
8
  steps:
9
9
  - uses: actions/checkout@v2
10
+ - name: Ruby2D dependencies
11
+ run: sudo apt-get install -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
10
12
  - name: Set up Ruby
11
13
  uses: ruby/setup-ruby@v1
12
14
  with:
data/.rubocop.yml CHANGED
@@ -44,4 +44,7 @@ Style/RedundantReturn:
44
44
  Enabled: false
45
45
 
46
46
  Style/EmptyCaseCondition:
47
+ Enabled: false
48
+
49
+ Style/ExplicitBlockArgument:
47
50
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
- ## [Unreleased]
1
+ ## [Released]
2
2
 
3
- ## [0.1.0] - 2021-08-26
3
+ ## [0.3.0] - 2021-09-06
4
4
 
5
- - Initial release
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
@@ -7,7 +7,9 @@ gemspec
7
7
 
8
8
  group :test do
9
9
  gem "minitest", "~> 5.0"
10
+ gem "minitest-stub_any_instance", "~> 1.0", ">= 1.0.2"
10
11
  gem "simplecov", "~> 0.21.2"
12
+ gem "timecop", "~> 0.9.4"
11
13
  end
12
14
 
13
15
  group :test, :development do
data/Gemfile.lock CHANGED
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fet (0.2.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
- Create MIDI files for functional ear training. Each file will contain a major/minor chord progression, followed by note(s) that you should identify the scale degree of by ear.
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
- ## Filename Format
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
- ### Listening exercises
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
- ### Singing exercises
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
- ### Single Note Listening exercises
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
data/bin/fet CHANGED
@@ -77,11 +77,38 @@ class App
77
77
  end
78
78
  end
79
79
 
80
- # NOTE: if you need the backtrace for an exception, this can be uncommented
81
- # on_error do |exception|
82
- # puts exception.backtrace
83
- # true
84
- # end
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
@@ -33,6 +33,10 @@ module Fet
33
33
  return degree_name.size == 2 ? degree_name[1].to_i : degree_name[0].to_i
34
34
  end
35
35
 
36
+ def degree_index
37
+ return DEGREE_NAMES.index { |degree_names| degree_names.include?(degree_name) }
38
+ end
39
+
36
40
  private
37
41
 
38
42
  attr_writer :degree_name
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 degree_index_of_midi_value(midi_value)
58
- return MidiNote.new(midi_value).degree(root_midi_value)
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