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