Source code for Musica.Instrument.InstrumentDatabase

####################################################################################################
#
# Musica - A Music Theory Package for Python
# Copyright (C) 2017 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################

"""
"""

####################################################################################################

__all__ = [
    'InstrumentDatabase',
]

####################################################################################################

import os

from ..Notation.Stave import StaveKeys, Stave, StavePair
from ..Theory.Pitch import Pitch, PitchInterval
from .Instrument import Instrument, InstrumentWriting, InstrumentTransposition, Ambitus

####################################################################################################

[docs]class InstrumentDatabase: ___instance__ = None ##############################################
[docs] @classmethod def instance(cls): if cls.___instance__ is None: yaml_path = os.path.join(os.path.dirname(__file__), 'instruments.yml') cls.___instance__ = cls(yaml_path) return cls.___instance__
##############################################
[docs] def __init__(self, yaml_path): self._yaml_path = yaml_path self._instruments = {} self._load()
##############################################
[docs] def _load(self): import yaml with open(self._yaml_path, 'r') as fh: data = yaml.load(fh) for family, family_dict in data.items(): if family_dict is not None: for instrument_name, instrument_dict in family_dict.items(): self._load_instrument(family, instrument_name, instrument_dict)
##############################################
[docs] @staticmethod def _to_pitch_interval(string): lower_pitch, upper_pitch = [Pitch(x) for x in string.split()] return PitchInterval(lower_pitch, upper_pitch)
##############################################
[docs] def _load_instrument(self, family, instrument_name, instrument_dict): writings = [] if 'writings' in instrument_dict: for name, writing_data in instrument_dict['writings'].items(): writing = self._load_writing(name, writing_data) if writing: writings.append(writing) else: writing = self._load_writing('default', instrument_dict) if writing: writings.append(writing) kwargs = {} transposition_data = instrument_dict.get('transposition', False) if transposition_data: kwargs['transposition'] = [InstrumentTransposition(name, pitch) for name, pitch in transposition_data] if 'ambitus' in instrument_dict: kwargs['ambitus'] = [Ambitus(name, self._to_pitch_interval(string)) for name, string in instrument_dict['ambitus'].items()] instrument = Instrument(name=instrument_name, family=family, writings=writings, **kwargs, ) self._instruments[instrument_name] = instrument
##############################################
[docs] def _load_writing(self, name, data): try: keys = [StaveKeys[x] for x in data['staff key'].split()] if len(keys) == 1: stave = Stave(keys[0]) else: stave = StavePair(keys[0], keys[1]) pitch_interval = self._to_pitch_interval(data['written range']) return InstrumentWriting(name, stave, pitch_interval) except KeyError: return None
############################################## @property def instruments(self): return self._instruments.keys() ##############################################
[docs] def __getitem__(self, instrument): return self._instruments[instrument]