head_music 0.29.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -3
- data/TODO.md +105 -1
- data/lib/head_music/content/bar.rb +4 -1
- data/lib/head_music/content/composition.rb +6 -3
- data/lib/head_music/content/note.rb +8 -5
- data/lib/head_music/content/placement.rb +7 -4
- data/lib/head_music/content/position.rb +5 -2
- data/lib/head_music/content/rhythmic_value.rb +5 -2
- data/lib/head_music/content/voice.rb +6 -3
- data/lib/head_music/data/clefs.yml +3 -1
- data/lib/head_music/data/instrument_families.yml +229 -0
- data/lib/head_music/data/instruments.yml +835 -116
- data/lib/head_music/harmonic_interval.rb +1 -1
- data/lib/head_music/instrument.rb +90 -10
- data/lib/head_music/instrument_family.rb +69 -0
- data/lib/head_music/locales/de.yml +3 -3
- data/lib/head_music/locales/en.yml +6 -8
- data/lib/head_music/locales/es.yml +2 -2
- data/lib/head_music/locales/fr.yml +1 -1
- data/lib/head_music/locales/it.yml +3 -3
- data/lib/head_music/locales/ru.yml +2 -2
- data/lib/head_music/meter.rb +2 -2
- data/lib/head_music/staff.rb +4 -1
- data/lib/head_music/style/guidelines/at_least_eight_notes.rb +2 -2
- data/lib/head_music/version.rb +1 -1
- data/lib/head_music.rb +1 -1
- metadata +5 -4
- data/lib/head_music/grand_staff.rb +0 -56
@@ -7,7 +7,7 @@ class HeadMusic::HarmonicInterval
|
|
7
7
|
def initialize(voice1, voice2, position)
|
8
8
|
@voice1 = voice1
|
9
9
|
@voice2 = voice2
|
10
|
-
@position = position.is_a?(String) ? HeadMusic::Position.new(voice1.composition, position) : position
|
10
|
+
@position = position.is_a?(String) ? HeadMusic::Content::Position.new(voice1.composition, position) : position
|
11
11
|
end
|
12
12
|
|
13
13
|
def diatonic_interval
|
@@ -1,23 +1,47 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
3
|
+
# A musical instrument.
|
4
|
+
# An instrument object can be assigned to a staff object.
|
5
|
+
# Attributes:
|
6
|
+
# name_key: the name of the instrument
|
7
|
+
# alias_name_keys: an array of alternative names for the instrument
|
8
|
+
# orchestra_section_key: the section of the orchestra (e.g. "strings")
|
9
|
+
# family_key: the key for the family of the instrument (e.g. "saxophone")
|
10
|
+
# classification_keys: an array of classification_keys
|
11
|
+
# transposition: the number of semitones between the written and the sounding pitch (optional, default: 0)
|
12
|
+
# default_clefs: the default clef or system of clefs for the instrument
|
13
|
+
# - [treble] for instruments that use the treble clef
|
14
|
+
# - [treble, bass] for instruments that use the grand staff
|
15
|
+
# notation:
|
16
|
+
# a hash of default and alternative notation systems,
|
17
|
+
# each with a staffs key with an array of hashes
|
18
|
+
# including clef and transposition (where applicable)
|
19
|
+
# Associations:
|
20
|
+
# family: the family of the instrument (e.g. "saxophone")
|
21
|
+
# orchestra_section: the section of the orchestra (e.g. "strings")
|
4
22
|
class HeadMusic::Instrument
|
5
23
|
include HeadMusic::Named
|
6
24
|
|
7
25
|
INSTRUMENTS = YAML.load_file(File.expand_path("data/instruments.yml", __dir__)).freeze
|
8
26
|
|
9
27
|
def self.get(name)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
new(name)
|
28
|
+
result = get_by_name(name) || get_by_name(key_for_name(name)) || get_by_alias(name)
|
29
|
+
result || new(name)
|
14
30
|
end
|
15
31
|
|
16
32
|
def self.all
|
17
|
-
|
33
|
+
HeadMusic::InstrumentFamily.all
|
34
|
+
@all ||=
|
35
|
+
INSTRUMENTS.map { |key, _data| get(key) }.sort_by(&:name)
|
18
36
|
end
|
19
37
|
|
20
|
-
attr_reader
|
38
|
+
attr_reader(
|
39
|
+
:name_key, :alias_name_keys,
|
40
|
+
:family_key, :orchestra_section_key,
|
41
|
+
:notation, :classification_keys,
|
42
|
+
:fundamental_pitch_spelling, :transposition,
|
43
|
+
:default_staffs, :default_clefs
|
44
|
+
)
|
21
45
|
|
22
46
|
def ==(other)
|
23
47
|
to_s == other.to_s
|
@@ -29,6 +53,36 @@ class HeadMusic::Instrument
|
|
29
53
|
I18n.translate(name_key, scope: [:instruments], locale: locale)
|
30
54
|
end
|
31
55
|
|
56
|
+
def family
|
57
|
+
return unless family_key
|
58
|
+
|
59
|
+
HeadMusic::InstrumentFamily.get(family_key)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns true if the instrument sounds at a different pitch than written.
|
63
|
+
def transposing?
|
64
|
+
transposition != 0
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns true if the instrument sounds at a different register than written.
|
68
|
+
def transposing_at_the_octave?
|
69
|
+
transposing? && transposition % 12 == 0
|
70
|
+
end
|
71
|
+
|
72
|
+
def single_staff?
|
73
|
+
default_staffs.length == 1
|
74
|
+
end
|
75
|
+
|
76
|
+
def multiple_staffs?
|
77
|
+
default_staffs.length > 1
|
78
|
+
end
|
79
|
+
|
80
|
+
def pitched?
|
81
|
+
return false if default_clefs.compact.uniq == ["percussion"]
|
82
|
+
|
83
|
+
default_clefs.any?
|
84
|
+
end
|
85
|
+
|
32
86
|
private_class_method :new
|
33
87
|
|
34
88
|
private
|
@@ -65,11 +119,37 @@ class HeadMusic::Instrument
|
|
65
119
|
end
|
66
120
|
|
67
121
|
def initialize_data_from_record(record)
|
122
|
+
initialize_family(record)
|
123
|
+
inherit_family_attributes(record)
|
124
|
+
initialize_names(record)
|
125
|
+
initialize_attributes(record)
|
126
|
+
end
|
127
|
+
|
128
|
+
def initialize_family(record)
|
129
|
+
@family_key = record["family_key"]
|
130
|
+
@family = HeadMusic::InstrumentFamily.get(family_key)
|
131
|
+
end
|
132
|
+
|
133
|
+
def inherit_family_attributes(record)
|
134
|
+
return unless family
|
135
|
+
|
136
|
+
@orchestra_section_key = family.orchestra_section_key
|
137
|
+
@classification_keys = family.classification_keys || []
|
138
|
+
end
|
139
|
+
|
140
|
+
def initialize_names(record)
|
68
141
|
@name_key = record["name_key"].to_sym
|
69
|
-
@family = record["family"]
|
70
|
-
@standard_staves = record["standard_staves"] || []
|
71
|
-
@classifications = record["classifications"] || []
|
72
142
|
self.name = I18n.translate(name_key, scope: "instruments", locale: "en", default: inferred_name)
|
143
|
+
@alias_name_keys = record["alias_name_keys"] || []
|
144
|
+
end
|
145
|
+
|
146
|
+
def initialize_attributes(record)
|
147
|
+
@orchestra_section_key ||= record["orchestra_section_key"]
|
148
|
+
@classification_keys = [@classification_keys, record["classification_keys"]].flatten.compact.uniq
|
149
|
+
@fundamental_pitch_spelling = record["fundamental_pitch_spelling"]
|
150
|
+
@default_staffs = (record.dig("notation", "default", "staffs") || [])
|
151
|
+
@default_clefs = @default_staffs.map { |staff| staff["clef"] }
|
152
|
+
@transposition = @default_staffs&.first&.[]("transposition") || 0
|
73
153
|
end
|
74
154
|
|
75
155
|
def inferred_name
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# An *InstrumentFamily* is a species of instrument
|
2
|
+
# that may exist in a variety of keys or other variations.
|
3
|
+
# For example, _saxophone_ is an instrument family, while
|
4
|
+
# _alto saxophone_ and _baritone saxophone_ are specific instruments.
|
5
|
+
class HeadMusic::InstrumentFamily
|
6
|
+
include HeadMusic::Named
|
7
|
+
|
8
|
+
INSTRUMENT_FAMILIES =
|
9
|
+
YAML.load_file(File.expand_path("data/instrument_families.yml", __dir__)).freeze
|
10
|
+
|
11
|
+
attr_reader :name_key, :classification_keys, :orchestra_section_key, :default_staffs
|
12
|
+
attr_accessor :name
|
13
|
+
|
14
|
+
def self.get(name)
|
15
|
+
result = get_by_name(name) || get_by_name(key_for_name(name))
|
16
|
+
result || new(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.all
|
20
|
+
@all ||=
|
21
|
+
INSTRUMENT_FAMILIES.map { |key, _data| get(key) }.sort_by(&:name)
|
22
|
+
end
|
23
|
+
|
24
|
+
private_class_method :new
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def initialize(name)
|
29
|
+
record = record_for_name(name)
|
30
|
+
if record
|
31
|
+
initialize_data_from_record(record)
|
32
|
+
else
|
33
|
+
self.name = name.to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def record_for_name(name)
|
38
|
+
record_for_key(HeadMusic::Utilities::HashKey.for(name)) ||
|
39
|
+
record_for_key(key_for_name(name))
|
40
|
+
end
|
41
|
+
|
42
|
+
def key_for_name(name)
|
43
|
+
INSTRUMENT_FAMILIES.each do |key, _data|
|
44
|
+
I18n.config.available_locales.each do |locale|
|
45
|
+
translation = I18n.t("instruments.#{key}", locale: locale)
|
46
|
+
return key if translation.downcase == name.downcase
|
47
|
+
end
|
48
|
+
end
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def record_for_key(key)
|
53
|
+
INSTRUMENT_FAMILIES.each do |name_key, data|
|
54
|
+
return data.merge!("name_key" => name_key) if name_key.to_s == key.to_s
|
55
|
+
end
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize_data_from_record(record)
|
60
|
+
@name_key = record["name_key"].to_sym
|
61
|
+
@orchestra_section_key = record["orchestra_section_key"]
|
62
|
+
@classification_keys = record["classification_keys"] || []
|
63
|
+
self.name = I18n.translate(name_key, scope: "instruments", locale: "en", default: inferred_name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def inferred_name
|
67
|
+
name_key.to_s.tr("_", " ")
|
68
|
+
end
|
69
|
+
end
|
@@ -6,7 +6,7 @@ de:
|
|
6
6
|
baritone_f_clef: Baritonschlüssel
|
7
7
|
bass_clef: Bassschlüssel
|
8
8
|
c_clef: C-Schlüssel
|
9
|
-
|
9
|
+
vocal_tenor_clef: oktavierten Violinschlüssel
|
10
10
|
contrabass_clef: contrabass clef
|
11
11
|
countertenor_clef: countertenor clef
|
12
12
|
double_treble_clef: double treble clef
|
@@ -61,10 +61,10 @@ de:
|
|
61
61
|
bagpipe: Dudelsack
|
62
62
|
baritone_horn: Baritonhorn
|
63
63
|
baritone_voice: Bariton
|
64
|
-
bass_voice: Bass
|
65
64
|
bass_clarinet: Bassklarinette
|
66
65
|
bass_drum: Grosse Trommel
|
67
66
|
bass_trombone: Bass Posaune
|
67
|
+
bass_voice: Bass
|
68
68
|
bassoon: Fagott
|
69
69
|
castanets: Kastagnetten
|
70
70
|
celesta: Celesta
|
@@ -78,7 +78,7 @@ de:
|
|
78
78
|
english_horn: Englischhorn
|
79
79
|
euphonium: Euphonium
|
80
80
|
fiddle: Geige
|
81
|
-
|
81
|
+
flugelhorn: Flügelhorn
|
82
82
|
flute: Flöte
|
83
83
|
french_horn: Horn
|
84
84
|
glockenspiel: Glockenspiel
|
@@ -6,7 +6,7 @@ en:
|
|
6
6
|
baritone_f_clef: baritone F-clef
|
7
7
|
bass_clef: bass clef
|
8
8
|
c_clef: C-clef
|
9
|
-
|
9
|
+
vocal_tenor_clef: vocal tenor clef
|
10
10
|
contrabass_clef: contrabass clef
|
11
11
|
countertenor_clef: countertenor clef
|
12
12
|
double_treble_clef: double treble clef
|
@@ -92,7 +92,6 @@ en:
|
|
92
92
|
bass_drum: bass drum
|
93
93
|
bass_guitar: bass guitar
|
94
94
|
bass_oboe: bass oboe
|
95
|
-
bass_drum: bass drum
|
96
95
|
bass_trombone: bass trombone
|
97
96
|
bass_tuba: bass tuba
|
98
97
|
bass_voice: bass
|
@@ -102,21 +101,20 @@ en:
|
|
102
101
|
cello: cello
|
103
102
|
chimes: chimes
|
104
103
|
cimbalom: cimbalom
|
105
|
-
cowbell: cowbell
|
106
104
|
clarinet: clarinet
|
107
|
-
clavichord: clavichord
|
108
105
|
clash_cymbals: clash cymbals
|
109
|
-
|
110
|
-
contrabassoon: contrabassoon
|
106
|
+
clavichord: clavichord
|
111
107
|
contra_bass_clarinet: contra bass clarinet
|
108
|
+
contrabassoon: contrabassoon
|
112
109
|
cor_anglais: cor anglais
|
110
|
+
cornet: cornet
|
113
111
|
cowbell: cowbell
|
114
|
-
cymbal: cymbal
|
115
112
|
crotales: crotales
|
113
|
+
cymbal: cymbal
|
116
114
|
double_bass: double bass
|
117
115
|
english_horn: English horn
|
118
116
|
euphonium: euphonium
|
119
|
-
|
117
|
+
flugelhorn: flugelhorn
|
120
118
|
flute: flute
|
121
119
|
french_horn: French horn
|
122
120
|
glockenspiel: glockenspiel
|
@@ -6,7 +6,7 @@ es:
|
|
6
6
|
baritone_f_clef: clave de fa en tercera
|
7
7
|
bass_clef: clave de bajo
|
8
8
|
c_clef: clave de do
|
9
|
-
|
9
|
+
vocal_tenor_clef: vocal tenor clef
|
10
10
|
contrabass_clef: clave de contrabajo
|
11
11
|
countertenor_clef: clave de contratenor
|
12
12
|
double_treble_clef: double clave de sol
|
@@ -72,7 +72,7 @@ es:
|
|
72
72
|
double_bass: contrabajo
|
73
73
|
english_horn: Cuerno inglés
|
74
74
|
euphonium: euphonium
|
75
|
-
|
75
|
+
flugelhorn: fliscorno
|
76
76
|
flute: flauta
|
77
77
|
french_horn: corno
|
78
78
|
glockenspiel: campanólogo
|
@@ -6,7 +6,7 @@ fr:
|
|
6
6
|
baritone_f_clef: clé de fa 3e
|
7
7
|
bass_clef: clé de basse
|
8
8
|
c_clef: clé d'ut
|
9
|
-
|
9
|
+
vocal_tenor_clef: vocal tenor clef
|
10
10
|
contrabass_clef: clé de contrebasse
|
11
11
|
countertenor_clef: clé de contre-ténor
|
12
12
|
double_treble_clef: double clé de sol
|
@@ -6,7 +6,7 @@ it:
|
|
6
6
|
baritone_f_clef: chiave di baritono
|
7
7
|
bass_clef: chiave di basso
|
8
8
|
c_clef: chiave di do
|
9
|
-
|
9
|
+
vocal_tenor_clef: chiave di sol in ottava
|
10
10
|
contrabass_clef: chiave di contrabbasso
|
11
11
|
countertenor_clef: chiave di controtenore
|
12
12
|
double_treble_clef: chiave di sol in ottava
|
@@ -76,7 +76,7 @@ it:
|
|
76
76
|
double_bass: contrabasso
|
77
77
|
english_horn: corno inglese
|
78
78
|
euphonium: eufonio
|
79
|
-
|
79
|
+
flugelhorn: flicorno
|
80
80
|
flute: flauto
|
81
81
|
french_horn: corno
|
82
82
|
glockenspiel: glockenspiel
|
@@ -91,9 +91,9 @@ it:
|
|
91
91
|
natural_horn: corno naturale
|
92
92
|
oboe: oboe
|
93
93
|
oboe_d_amore: oboe d'amore
|
94
|
-
piccolo: ottavino
|
95
94
|
organ: organo
|
96
95
|
piano: piano
|
96
|
+
piccolo: ottavino
|
97
97
|
recorder: flauto dolce
|
98
98
|
saxophone: sassofono
|
99
99
|
snare_drum: tamburo rullante
|
@@ -32,7 +32,7 @@ ru:
|
|
32
32
|
double_bass: kontrabas
|
33
33
|
english_horn: angliiskii rozhok
|
34
34
|
euphonium: evfonium
|
35
|
-
|
35
|
+
flugelhorn: fliugel'gorn
|
36
36
|
flute: fleita
|
37
37
|
french_horn: Gorn
|
38
38
|
glockenspiel: kolokol'chiki
|
@@ -67,4 +67,4 @@ ru:
|
|
67
67
|
violoncello: violonchel'
|
68
68
|
voice: golos
|
69
69
|
xylophone: ksilofon
|
70
|
-
zither: tsitra
|
70
|
+
zither: tsitra
|
data/lib/head_music/meter.rb
CHANGED
@@ -82,9 +82,9 @@ class HeadMusic::Meter
|
|
82
82
|
def beat_unit
|
83
83
|
@beat_unit ||=
|
84
84
|
if compound?
|
85
|
-
HeadMusic::RhythmicValue.new(HeadMusic::RhythmicUnit.for_denominator_value(bottom_number / 2), dots: 1)
|
85
|
+
HeadMusic::Content::RhythmicValue.new(HeadMusic::RhythmicUnit.for_denominator_value(bottom_number / 2), dots: 1)
|
86
86
|
else
|
87
|
-
HeadMusic::RhythmicValue.new(count_unit)
|
87
|
+
HeadMusic::Content::RhythmicValue.new(count_unit)
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
data/lib/head_music/staff.rb
CHANGED
@@ -5,11 +5,14 @@ class HeadMusic::Staff
|
|
5
5
|
DEFAULT_LINE_COUNT = 5
|
6
6
|
|
7
7
|
attr_reader :default_clef, :line_count, :instrument
|
8
|
-
alias_method :clef, :default_clef
|
9
8
|
|
10
9
|
def initialize(default_clef, instrument: nil, line_count: nil)
|
11
10
|
@default_clef = HeadMusic::Clef.get(default_clef)
|
12
11
|
@line_count = line_count || DEFAULT_LINE_COUNT
|
13
12
|
@instrument = HeadMusic::Instrument.get(instrument) if instrument
|
14
13
|
end
|
14
|
+
|
15
|
+
def clef
|
16
|
+
default_clef || instrument&.default_staffs&.first
|
17
|
+
end
|
15
18
|
end
|
@@ -17,8 +17,8 @@ class HeadMusic::Style::Guidelines::AtLeastEightNotes < HeadMusic::Style::Annota
|
|
17
17
|
|
18
18
|
def no_placements_mark
|
19
19
|
HeadMusic::Style::Mark.new(
|
20
|
-
HeadMusic::Position.new(composition, "1:1"),
|
21
|
-
HeadMusic::Position.new(composition, "2:1"),
|
20
|
+
HeadMusic::Content::Position.new(composition, "1:1"),
|
21
|
+
HeadMusic::Content::Position.new(composition, "2:1"),
|
22
22
|
fitness: 0
|
23
23
|
)
|
24
24
|
end
|
data/lib/head_music/version.rb
CHANGED
data/lib/head_music.rb
CHANGED
@@ -39,8 +39,8 @@ require "head_music/circle"
|
|
39
39
|
require "head_music/clef"
|
40
40
|
require "head_music/consonance"
|
41
41
|
require "head_music/diatonic_interval"
|
42
|
-
require "head_music/grand_staff"
|
43
42
|
require "head_music/harmonic_interval"
|
43
|
+
require "head_music/instrument_family"
|
44
44
|
require "head_music/instrument"
|
45
45
|
require "head_music/interval_cycle"
|
46
46
|
require "head_music/key_signature"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: head_music
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Head
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -132,11 +132,12 @@ files:
|
|
132
132
|
- lib/head_music/content/rhythmic_value.rb
|
133
133
|
- lib/head_music/content/voice.rb
|
134
134
|
- lib/head_music/data/clefs.yml
|
135
|
+
- lib/head_music/data/instrument_families.yml
|
135
136
|
- lib/head_music/data/instruments.yml
|
136
137
|
- lib/head_music/diatonic_interval.rb
|
137
|
-
- lib/head_music/grand_staff.rb
|
138
138
|
- lib/head_music/harmonic_interval.rb
|
139
139
|
- lib/head_music/instrument.rb
|
140
|
+
- lib/head_music/instrument_family.rb
|
140
141
|
- lib/head_music/interval_cycle.rb
|
141
142
|
- lib/head_music/key_signature.rb
|
142
143
|
- lib/head_music/letter_name.rb
|
@@ -234,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
234
235
|
- !ruby/object:Gem::Version
|
235
236
|
version: '0'
|
236
237
|
requirements: []
|
237
|
-
rubygems_version: 3.
|
238
|
+
rubygems_version: 3.4.12
|
238
239
|
signing_key:
|
239
240
|
specification_version: 4
|
240
241
|
summary: The rudiments of western music theory.
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# A grand staff is a group of staves for a single instrument, such as a piano.
|
4
|
-
class HeadMusic::GrandStaff
|
5
|
-
GRAND_STAVES = {
|
6
|
-
piano: {
|
7
|
-
instrument: :piano,
|
8
|
-
staves: [
|
9
|
-
{clef: :treble_clef, for: :right_hand},
|
10
|
-
{clef: :bass_clef, for: :left_hand}
|
11
|
-
]
|
12
|
-
},
|
13
|
-
organ: {
|
14
|
-
instrument: :organ,
|
15
|
-
staves: [
|
16
|
-
{clef: :treble_clef, for: :right_hand},
|
17
|
-
{clef: :bass_clef, for: :left_hand},
|
18
|
-
{clef: :bass_clef, for: :pedals}
|
19
|
-
]
|
20
|
-
}
|
21
|
-
}.freeze
|
22
|
-
|
23
|
-
def self.get(name)
|
24
|
-
@grand_staves ||= {}
|
25
|
-
hash_key = HeadMusic::Utilities::HashKey.for(name)
|
26
|
-
return nil unless GRAND_STAVES.key?(hash_key)
|
27
|
-
|
28
|
-
@grand_staves[hash_key] ||= new(hash_key)
|
29
|
-
end
|
30
|
-
|
31
|
-
attr_reader :identifier, :data
|
32
|
-
|
33
|
-
def initialize(name)
|
34
|
-
@identifier = HeadMusic::Utilities::HashKey.for(name)
|
35
|
-
@data = GRAND_STAVES[identifier]
|
36
|
-
end
|
37
|
-
|
38
|
-
def instrument
|
39
|
-
@instrument ||= HeadMusic::Instrument.get(data[:instrument])
|
40
|
-
end
|
41
|
-
|
42
|
-
def staves
|
43
|
-
@staves ||=
|
44
|
-
data[:staves].map do |staff|
|
45
|
-
HeadMusic::Staff.new(staff[:clef], instrument: instrument)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def brace_staves_index_first
|
50
|
-
0
|
51
|
-
end
|
52
|
-
|
53
|
-
def brace_staves_index_last
|
54
|
-
1
|
55
|
-
end
|
56
|
-
end
|