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 +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
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fet
|
4
|
+
module Ui
|
5
|
+
# Class that handles draw all degree boxes
|
6
|
+
class NoteBoxes
|
7
|
+
attr_accessor :level, :note_boxes
|
8
|
+
|
9
|
+
GLOBAL_X_OFFSET = 60
|
10
|
+
GLOBAL_Y_OFFSET = 244
|
11
|
+
NOTE_BOX_OFFSETS = {
|
12
|
+
"1" => [(GLOBAL_X_OFFSET + 0), GLOBAL_Y_OFFSET + 75],
|
13
|
+
"2" => [(GLOBAL_X_OFFSET + 75), GLOBAL_Y_OFFSET + 75],
|
14
|
+
"3" => [(GLOBAL_X_OFFSET + 150), GLOBAL_Y_OFFSET + 75],
|
15
|
+
"4" => [(GLOBAL_X_OFFSET + 225), GLOBAL_Y_OFFSET + 75],
|
16
|
+
"5" => [(GLOBAL_X_OFFSET + 300), GLOBAL_Y_OFFSET + 75],
|
17
|
+
"6" => [(GLOBAL_X_OFFSET + 375), GLOBAL_Y_OFFSET + 75],
|
18
|
+
"7" => [(GLOBAL_X_OFFSET + 450), GLOBAL_Y_OFFSET + 75],
|
19
|
+
"b2" => [(GLOBAL_X_OFFSET + 40), GLOBAL_Y_OFFSET],
|
20
|
+
"b3" => [(GLOBAL_X_OFFSET + 115), GLOBAL_Y_OFFSET],
|
21
|
+
"b5" => [(GLOBAL_X_OFFSET + 265), GLOBAL_Y_OFFSET],
|
22
|
+
"b6" => [(GLOBAL_X_OFFSET + 340), GLOBAL_Y_OFFSET],
|
23
|
+
"b7" => [(GLOBAL_X_OFFSET + 415), GLOBAL_Y_OFFSET],
|
24
|
+
}.deep_freeze
|
25
|
+
|
26
|
+
def initialize(level)
|
27
|
+
self.level = level
|
28
|
+
end
|
29
|
+
|
30
|
+
def start
|
31
|
+
self.note_boxes ||= generate_note_boxes
|
32
|
+
note_boxes.each(&:start)
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_event_loop(event)
|
36
|
+
handle_note_selected_event(event)
|
37
|
+
note_boxes.each { |note_box| note_box.handle_event_loop(event) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_update_loop; end
|
41
|
+
|
42
|
+
def all_correct_selected?
|
43
|
+
return (correct_note_boxes.map(&:degree_name) & selected_note_boxes.map(&:degree_name)).size == correct_note_boxes.size
|
44
|
+
end
|
45
|
+
|
46
|
+
def any_wrong_selected?
|
47
|
+
return selected_note_boxes.any? { |note_box| !note_box.correct? }
|
48
|
+
end
|
49
|
+
|
50
|
+
def correct_remaining
|
51
|
+
return note_boxes.select { |note_box| !note_box.selected && note_box.correct? }
|
52
|
+
end
|
53
|
+
|
54
|
+
def correct_note_boxes
|
55
|
+
return note_boxes.select(&:correct?)
|
56
|
+
end
|
57
|
+
|
58
|
+
def selected_note_boxes
|
59
|
+
return note_boxes.select(&:selected)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def generate_note_boxes
|
65
|
+
NOTE_BOX_OFFSETS.map do |degree_name, _|
|
66
|
+
Fet::Ui::NoteBox.new(note_boxes: self, degree_name: degree_name)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_note_selected_event(event)
|
71
|
+
return unless event.is_a?(CustomEvent) && event.type == CustomEvent::EVENT_TYPE_NOTE_SELECTED
|
72
|
+
|
73
|
+
if all_correct_selected?
|
74
|
+
level.game.set_level_complete_event_flag
|
75
|
+
elsif any_wrong_selected?
|
76
|
+
correct_remaining.first.manually_select
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/fet/ui/score.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ruby2d"
|
4
|
+
require_relative "color_scheme"
|
5
|
+
require_relative "custom_event"
|
6
|
+
|
7
|
+
module Fet
|
8
|
+
module Ui
|
9
|
+
# Shows the UI elements for score
|
10
|
+
class Score
|
11
|
+
attr_accessor :game, :score, :text
|
12
|
+
|
13
|
+
def initialize(game)
|
14
|
+
self.game = game
|
15
|
+
self.score = Fet::Score.new
|
16
|
+
self.correct_questions = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
self.text ||= generate_text
|
21
|
+
update_text
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_event_loop(event)
|
25
|
+
handle_level_started_event(event)
|
26
|
+
handle_level_complete_event(event)
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle_update_loop; end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_accessor :correct_questions
|
34
|
+
|
35
|
+
TEXT_SIZE = 36
|
36
|
+
X_OFFSET = 508
|
37
|
+
Y_OFFSET = 90
|
38
|
+
private_constant :TEXT_SIZE, :X_OFFSET, :Y_OFFSET
|
39
|
+
|
40
|
+
def text_value
|
41
|
+
return "#{correct_questions}/#{game.level.question_number}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate_text
|
45
|
+
return Ruby2D::Text.new(
|
46
|
+
text_value,
|
47
|
+
x: X_OFFSET, y: Y_OFFSET,
|
48
|
+
font: File.join(Fet.root, "assets/fonts/PTSans/PTSans-Regular.ttf"),
|
49
|
+
size: TEXT_SIZE,
|
50
|
+
color: ColorScheme::WHITE,
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def handle_level_started_event(event)
|
55
|
+
return unless event.is_a?(CustomEvent) && event.type == CustomEvent::EVENT_TYPE_LEVEL_STARTED
|
56
|
+
|
57
|
+
update_text
|
58
|
+
end
|
59
|
+
|
60
|
+
def handle_level_complete_event(event)
|
61
|
+
return unless event.is_a?(CustomEvent) && event.type == CustomEvent::EVENT_TYPE_LEVEL_COMPLETE
|
62
|
+
|
63
|
+
update_score
|
64
|
+
update_text
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_score
|
68
|
+
note_boxes = game.level.note_boxes
|
69
|
+
correct_note_boxes = note_boxes.correct_note_boxes
|
70
|
+
|
71
|
+
user_selected_correct_note_boxes = correct_note_boxes.select(&:user_selected)
|
72
|
+
non_user_selected_correct_note_boxes = correct_note_boxes.reject(&:user_selected)
|
73
|
+
|
74
|
+
score.answer_correctly(*user_selected_correct_note_boxes.map(&:degree_index))
|
75
|
+
score.answer_incorrectly(*non_user_selected_correct_note_boxes.map(&:degree_index))
|
76
|
+
|
77
|
+
self.correct_questions += 1 if non_user_selected_correct_note_boxes.empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_text
|
81
|
+
text.text = text_value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/fet/ui/timer.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
module Fet
|
6
|
+
module Ui
|
7
|
+
# Determines and outputs the time spent playing
|
8
|
+
class Timer
|
9
|
+
attr_accessor :game, :started_at
|
10
|
+
|
11
|
+
def initialize(game)
|
12
|
+
self.game = game
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
self.started_at ||= DateTime.now.new_offset(0)
|
17
|
+
self.start_time ||= current_time
|
18
|
+
self.text ||= generate_text
|
19
|
+
text.text = time_elapsed
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_event_loop(event); end
|
23
|
+
|
24
|
+
def handle_update_loop
|
25
|
+
update_time_elapsed
|
26
|
+
end
|
27
|
+
|
28
|
+
def seconds_elapsed
|
29
|
+
current_time - start_time
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_accessor :text, :start_time
|
35
|
+
|
36
|
+
X_OFFSET = 284
|
37
|
+
Y_OFFSET = 90
|
38
|
+
private_constant :X_OFFSET, :Y_OFFSET
|
39
|
+
|
40
|
+
def update_time_elapsed
|
41
|
+
text.text = time_elapsed
|
42
|
+
end
|
43
|
+
|
44
|
+
def time_elapsed
|
45
|
+
current_seconds_elapsed = seconds_elapsed
|
46
|
+
|
47
|
+
minutes_elapsed = current_seconds_elapsed / 60
|
48
|
+
current_seconds_elapsed -= minutes_elapsed * 60
|
49
|
+
|
50
|
+
hours_elapsed = minutes_elapsed / 60
|
51
|
+
minutes_elapsed -= (hours_elapsed * 60)
|
52
|
+
|
53
|
+
return format_time_elapsed(hours_elapsed, minutes_elapsed, current_seconds_elapsed)
|
54
|
+
end
|
55
|
+
|
56
|
+
def format_time_elapsed(hours, minutes, seconds)
|
57
|
+
hours_elapsed = format("%02d", hours)
|
58
|
+
minutes_elapsed = format("%02d", minutes)
|
59
|
+
seconds_elapsed = format("%02d", seconds)
|
60
|
+
|
61
|
+
result = "#{minutes_elapsed}:#{seconds_elapsed}"
|
62
|
+
result = "#{hours_elapsed}:#{result}" unless hours.zero?
|
63
|
+
return result
|
64
|
+
end
|
65
|
+
|
66
|
+
def current_time
|
67
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC).to_i
|
68
|
+
end
|
69
|
+
|
70
|
+
def generate_text
|
71
|
+
Text.new(
|
72
|
+
time_elapsed,
|
73
|
+
x: X_OFFSET, y: Y_OFFSET,
|
74
|
+
font: File.join(Fet.root, "assets/fonts/PTSans/PTSans-Regular.ttf"),
|
75
|
+
size: 36,
|
76
|
+
color: Fet::Ui::ColorScheme::WHITE,
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/fet/version.rb
CHANGED
data/lib/fet.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitrios Lisenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gli
|
@@ -64,6 +64,20 @@ dependencies:
|
|
64
64
|
- - ">="
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: 2.0.5
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: ruby2d
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.10.0
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 0.10.0
|
67
81
|
description: Teaches your ear to recognize notes based on their function in a key.
|
68
82
|
email:
|
69
83
|
- dimitrioslisenko@gmail.com
|
@@ -82,10 +96,15 @@ files:
|
|
82
96
|
- Gemfile
|
83
97
|
- Gemfile.lock
|
84
98
|
- LICENSE
|
85
|
-
- LICENSE.txt
|
86
99
|
- README.md
|
87
100
|
- README.rdoc
|
88
101
|
- Rakefile
|
102
|
+
- assets/fonts/PTSans/OFL.txt
|
103
|
+
- assets/fonts/PTSans/PTSans-Bold.ttf
|
104
|
+
- assets/fonts/PTSans/PTSans-BoldItalic.ttf
|
105
|
+
- assets/fonts/PTSans/PTSans-Italic.ttf
|
106
|
+
- assets/fonts/PTSans/PTSans-Regular.ttf
|
107
|
+
- assets/readme/demo.gif
|
89
108
|
- bin/bash_scripts/cleanup_listening_exercises.sh
|
90
109
|
- bin/bash_scripts/cleanup_singing_exercises.sh
|
91
110
|
- bin/bash_scripts/midi_to_mp3.sh
|
@@ -99,6 +118,7 @@ files:
|
|
99
118
|
- lib/fet/cli/generate/listening.rb
|
100
119
|
- lib/fet/cli/generate/singing.rb
|
101
120
|
- lib/fet/cli/generate/single_note_listening.rb
|
121
|
+
- lib/fet/cli/play/listening.rb
|
102
122
|
- lib/fet/degree.rb
|
103
123
|
- lib/fet/degrees.rb
|
104
124
|
- lib/fet/exceptions.rb
|
@@ -107,11 +127,26 @@ files:
|
|
107
127
|
- lib/fet/generator/single_note_listening.rb
|
108
128
|
- lib/fet/hardcoded_midi_values.rb
|
109
129
|
- lib/fet/instrument_ranges.rb
|
130
|
+
- lib/fet/midi_file_generator.rb
|
110
131
|
- lib/fet/midi_note.rb
|
111
132
|
- lib/fet/midilib_interface.rb
|
112
133
|
- lib/fet/music_theory.rb
|
113
134
|
- lib/fet/note.rb
|
114
135
|
- lib/fet/note_validations.rb
|
136
|
+
- lib/fet/score.rb
|
137
|
+
- lib/fet/ui/color_scheme.rb
|
138
|
+
- lib/fet/ui/custom_event.rb
|
139
|
+
- lib/fet/ui/game.rb
|
140
|
+
- lib/fet/ui/game_loop_handler.rb
|
141
|
+
- lib/fet/ui/game_setup_helper.rb
|
142
|
+
- lib/fet/ui/key.rb
|
143
|
+
- lib/fet/ui/level.rb
|
144
|
+
- lib/fet/ui/level_loop_handler.rb
|
145
|
+
- lib/fet/ui/note_box.rb
|
146
|
+
- lib/fet/ui/note_box_loop_handler.rb
|
147
|
+
- lib/fet/ui/note_boxes.rb
|
148
|
+
- lib/fet/ui/score.rb
|
149
|
+
- lib/fet/ui/timer.rb
|
115
150
|
- lib/fet/version.rb
|
116
151
|
homepage: https://github.com/DimitriosLisenko/fet
|
117
152
|
licenses:
|
data/LICENSE.txt
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
The MIT License (MIT)
|
2
|
-
|
3
|
-
Copyright (c) 2021 Dimitrios Lisenko
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
13
|
-
all copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
THE SOFTWARE.
|