Class: HeadMusic::Time::KeySignatureEvent
- Inherits:
-
Object
- Object
- HeadMusic::Time::KeySignatureEvent
- Defined in:
- lib/head_music/time/key_signature_event.rb
Overview
A key signature change at a musical position.
The event carries two things, because neither derives the other:
- the signature, as fifths (sharps positive, flats negative), which is what is printed at the clef;
- optionally a tonal context, a Key or a Mode, which is the analytical claim about what that signature means.
A signature underdetermines its interpretation -- two sharps is D major, B minor, E dorian, or A mixolydian -- so the interpretation is optional. And the interpretation does not determine the signature either, because the two legitimately diverge: C dorian written in cantus mollis takes the parallel minor's three flats and naturalizes the sixth, so the collection is two flats while the signature is three.
Fifths rather than a KeySignature because a KeySignature cannot be built from a bare signature -- naming three flats means naming an interpretation of it, after which the stored tonic and quality are wrong whenever the tonal context disagrees. Fifths is also exactly what MusicXML stores.
Instance Attribute Summary collapse
-
#position ⇒ MusicalPosition
Where the change occurs.
-
#signature ⇒ Integer
readonly
Fifths: sharps positive, flats negative.
-
#tonal_context ⇒ HeadMusic::Rudiment::DiatonicContext, ...
readonly
The interpretation of the signature: usually a Key or a Mode, and a KeySignature where the scale type is one neither subclass can hold.
Class Method Summary collapse
-
.fifths_of(key_signature) ⇒ Integer
The fifths a key signature prints.
Instance Method Summary collapse
- #agreeing_interpretation ⇒ Object private
- #conventional_reading ⇒ Object private
-
#initialize(position, signature, tonal_context: nil) ⇒ KeySignatureEvent
constructor
A new instance of KeySignatureEvent.
-
#key_signature ⇒ HeadMusic::Rudiment::KeySignature
The key signature in the sense the rest of the gem means it: the collection plus, where one was claimed, the tonic and scale type that a style guideline needs in order to know what the first degree is.
-
#printed_key_signature ⇒ HeadMusic::Rudiment::KeySignature
What is printed at the clef.
-
#same_tonic_key ⇒ Object
private
An ordinary major or minor key on the interpretation's own tonic that prints this signature, which keeps the tonic the music is actually in.
- #to_s ⇒ Object
Constructor Details
#initialize(position, signature, tonal_context: nil) ⇒ KeySignatureEvent
Returns a new instance of KeySignatureEvent.
42 43 44 45 46 47 48 |
# File 'lib/head_music/time/key_signature_event.rb', line 42 def initialize(position, signature, tonal_context: nil) raise ArgumentError, "signature must be an Integer number of fifths, got #{signature.inspect}" unless signature.is_a?(Integer) @position = position @signature = signature @tonal_context = tonal_context end |
Instance Attribute Details
#position ⇒ MusicalPosition
Returns where the change occurs.
28 29 30 |
# File 'lib/head_music/time/key_signature_event.rb', line 28 def position @position end |
#signature ⇒ Integer (readonly)
Returns fifths: sharps positive, flats negative.
31 32 33 |
# File 'lib/head_music/time/key_signature_event.rb', line 31 def signature @signature end |
#tonal_context ⇒ HeadMusic::Rudiment::DiatonicContext, ... (readonly)
The interpretation of the signature: usually a Key or a Mode, and a KeySignature where the scale type is one neither subclass can hold.
37 38 39 |
# File 'lib/head_music/time/key_signature_event.rb', line 37 def tonal_context @tonal_context end |
Class Method Details
.fifths_of(key_signature) ⇒ Integer
Returns the fifths a key signature prints.
79 80 81 |
# File 'lib/head_music/time/key_signature_event.rb', line 79 def self.fifths_of(key_signature) key_signature.num_sharps - key_signature.num_flats end |
Instance Method Details
#agreeing_interpretation ⇒ Object (private)
89 90 91 92 93 |
# File 'lib/head_music/time/key_signature_event.rb', line 89 def agreeing_interpretation return nil if tonal_context.nil? key_signature if self.class.fifths_of(key_signature) == signature end |
#conventional_reading ⇒ Object (private)
106 107 108 |
# File 'lib/head_music/time/key_signature_event.rb', line 106 def conventional_reading HeadMusic::Rudiment::KeySignature.get(HeadMusic::Rudiment::Key.for_fifths(signature).name) end |
#key_signature ⇒ HeadMusic::Rudiment::KeySignature
The key signature in the sense the rest of the gem means it: the collection plus, where one was claimed, the tonic and scale type that a style guideline needs in order to know what the first degree is.
Falls back to the conventional reading of the signature when no interpretation was given.
58 59 60 |
# File 'lib/head_music/time/key_signature_event.rb', line 58 def key_signature @key_signature ||= tonal_context ? HeadMusic::Rudiment::KeySignature.get(tonal_context.name) : printed_key_signature end |
#printed_key_signature ⇒ HeadMusic::Rudiment::KeySignature
What is printed at the clef.
The interpretation, where it agrees with the signature -- so a flow in D dorian still prints as dorian, which LilyPond can say.
Where the two diverge the signature wins, because the signature is by definition what is printed. The tonic is kept if an ordinary key on it prints that signature, so C dorian in cantus mollis prints as C minor rather than as its relative major; failing that, the conventional reading of the signature is used.
74 75 76 |
# File 'lib/head_music/time/key_signature_event.rb', line 74 def printed_key_signature @printed_key_signature ||= agreeing_interpretation || same_tonic_key || conventional_reading end |
#same_tonic_key ⇒ Object (private)
An ordinary major or minor key on the interpretation's own tonic that prints this signature, which keeps the tonic the music is actually in.
97 98 99 100 101 102 103 104 |
# File 'lib/head_music/time/key_signature_event.rb', line 97 def same_tonic_key return nil if tonal_context.nil? HeadMusic::Rudiment::Key::QUALITIES.filter_map { |quality| candidate = HeadMusic::Rudiment::KeySignature.get("#{tonal_context.tonic_spelling} #{quality}") candidate if self.class.fifths_of(candidate) == signature }.first end |
#to_s ⇒ Object
83 84 85 |
# File 'lib/head_music/time/key_signature_event.rb', line 83 def to_s [signature, tonal_context].compact.join(" ") end |