lib/head_music/instrument.rb in head_music-1.0.0 vs lib/head_music/instrument.rb in head_music-2.0.0
- old
+ new
@@ -1,25 +1,49 @@
# frozen_string_literal: true
-# An instrument can be assigned to a staff.
+# A musical instrument.
+# An instrument object can be assigned to a staff object.
+# Attributes:
+# name_key: the name of the instrument
+# alias_name_keys: an array of alternative names for the instrument
+# orchestra_section_key: the section of the orchestra (e.g. "strings")
+# family_key: the key for the family of the instrument (e.g. "saxophone")
+# classification_keys: an array of classification_keys
+# transposition: the number of semitones between the written and the sounding pitch (optional, default: 0)
+# default_clefs: the default clef or system of clefs for the instrument
+# - [treble] for instruments that use the treble clef
+# - [treble, bass] for instruments that use the grand staff
+# notation:
+# a hash of default and alternative notation systems,
+# each with a staffs key with an array of hashes
+# including clef and transposition (where applicable)
+# Associations:
+# family: the family of the instrument (e.g. "saxophone")
+# orchestra_section: the section of the orchestra (e.g. "strings")
class HeadMusic::Instrument
include HeadMusic::Named
INSTRUMENTS = YAML.load_file(File.expand_path("data/instruments.yml", __dir__)).freeze
def self.get(name)
- return get_by_name(name) if get_by_name(name)
- return get_by_name(key_for_name(name)) if key_for_name(name)
-
- new(name)
+ result = get_by_name(name) || get_by_name(key_for_name(name)) || get_by_alias(name)
+ result || new(name)
end
def self.all
- INSTRUMENTS.map { |key, _data| get(key) }.sort_by(&:name)
+ HeadMusic::InstrumentFamily.all
+ @all ||=
+ INSTRUMENTS.map { |key, _data| get(key) }.sort_by(&:name)
end
- attr_reader :name_key, :family, :standard_staves, :classifications
+ attr_reader(
+ :name_key, :alias_name_keys,
+ :family_key, :orchestra_section_key,
+ :notation, :classification_keys,
+ :fundamental_pitch_spelling, :transposition,
+ :default_staffs, :default_clefs
+ )
def ==(other)
to_s == other.to_s
end
@@ -27,10 +51,40 @@
return name unless name_key
I18n.translate(name_key, scope: [:instruments], locale: locale)
end
+ def family
+ return unless family_key
+
+ HeadMusic::InstrumentFamily.get(family_key)
+ end
+
+ # Returns true if the instrument sounds at a different pitch than written.
+ def transposing?
+ transposition != 0
+ end
+
+ # Returns true if the instrument sounds at a different register than written.
+ def transposing_at_the_octave?
+ transposing? && transposition % 12 == 0
+ end
+
+ def single_staff?
+ default_staffs.length == 1
+ end
+
+ def multiple_staffs?
+ default_staffs.length > 1
+ end
+
+ def pitched?
+ return false if default_clefs.compact.uniq == ["percussion"]
+
+ default_clefs.any?
+ end
+
private_class_method :new
private
def initialize(name)
@@ -63,14 +117,40 @@
end
nil
end
def initialize_data_from_record(record)
+ initialize_family(record)
+ inherit_family_attributes(record)
+ initialize_names(record)
+ initialize_attributes(record)
+ end
+
+ def initialize_family(record)
+ @family_key = record["family_key"]
+ @family = HeadMusic::InstrumentFamily.get(family_key)
+ end
+
+ def inherit_family_attributes(record)
+ return unless family
+
+ @orchestra_section_key = family.orchestra_section_key
+ @classification_keys = family.classification_keys || []
+ end
+
+ def initialize_names(record)
@name_key = record["name_key"].to_sym
- @family = record["family"]
- @standard_staves = record["standard_staves"] || []
- @classifications = record["classifications"] || []
self.name = I18n.translate(name_key, scope: "instruments", locale: "en", default: inferred_name)
+ @alias_name_keys = record["alias_name_keys"] || []
+ end
+
+ def initialize_attributes(record)
+ @orchestra_section_key ||= record["orchestra_section_key"]
+ @classification_keys = [@classification_keys, record["classification_keys"]].flatten.compact.uniq
+ @fundamental_pitch_spelling = record["fundamental_pitch_spelling"]
+ @default_staffs = (record.dig("notation", "default", "staffs") || [])
+ @default_clefs = @default_staffs.map { |staff| staff["clef"] }
+ @transposition = @default_staffs&.first&.[]("transposition") || 0
end
def inferred_name
name_key.to_s.tr("_", " ")
end