Source code for Musica.Instrument.StringInstrument

####################################################################################################
#
# 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/>.
#
####################################################################################################

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

import os

# from ..Theory.Temperament import ET12
from ..Theory.Pitch import Pitch
from .Instrument import Instrument

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

[docs]class String: ##############################################
[docs] def __init__(self, pitch, length): self._pitch = pitch self._length = length
############################################## @property def pitch(self): return self._pitch @property def length(self): return self._length ##############################################
[docs] def __eq__(self, other): return self._pitch == other.pitch and self._length == other.length
##############################################
[docs] def fret_position(self, i, from_nut=True): # From nut / sillet position = self._length * 2**(-i/self._pitch.temperament.number_of_steps) if from_nut: position = self._length - position return position
####################################################################################################
[docs]class StringTuning: ##############################################
[docs] def __init__(self, instrument, name, pitches): self._instrument = instrument self._name = name self._pitches = pitches
############################################## @property def instrument(self): return self._instrument @property def name(self): return self._name @property def number_of_strings(self): return len(self._pitches) @property def pitches(self): return self._pitches @property def lowest_pitche(self): return self._pitches[0] @property def highest_pitche(self): return self._pitches[-1] ##############################################
[docs] def __repr__(self): return '{} {} [{}]'.format( self._instrument.name, self._name, ', '.join([pitch.full_name for pitch in self._pitches]) )
##############################################
[docs] def __eq__(self, other): return self._pitches == other.pitches
##############################################
[docs] def __len__(self): return len(self._pitches)
##############################################
[docs] def __iter__(self): return iter(self._pitches)
##############################################
[docs] def __getitem__(self, index): if isinstance(index, Pitch): string = self._pitches.find(index) if string == -1: raise IndexError() else: return string else: return self._pitches[index]
####################################################################################################
[docs]class InstrumentTunings: ##############################################
[docs] def __init__(self, name, **tunings): self._name = name self._tunings = {} for tuning_name, pitches in tunings.items(): self.add(tuning_name, pitches)
############################################## @property def name(self): return self._name @property def tunings(self): return self._tunings.keys() ##############################################
[docs] def __iter__(self): return iter(self._tunings.values())
##############################################
[docs] def __getitem__(self, tuning_name): return self._tunings[tuning_name]
##############################################
[docs] def add(self, name, pitches): if name not in self._tunings: if isinstance(pitches, str): if '...' in pitches: start_pitch, last_pitch = [Pitch(pitch.strip()) for pitch in pitches.split('...')] pitches = [pitch for pitch in start_pitch.pitch_iterator(last_pitch)] else: pitches = [Pitch(pitch) for pitch in pitches.split()] self._tunings[name] = StringTuning(self, name, pitches) else: raise NameError("Tuning {} already exists".format(name))
####################################################################################################
[docs]class StringInstrumentTuningDatabase: ___instance__ = None ##############################################
[docs] @classmethod def instance(cls): if cls.___instance__ is None: yaml_path = os.path.join(os.path.dirname(__file__), 'stringed-instrument-tunings.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: instruments = yaml.load(fh) self._instruments = {instrument:InstrumentTunings(instrument, **tunings) for instrument, tunings in instruments.items()}
############################################## @property def instruments(self): return self._instruments.keys() ##############################################
[docs] def __getitem__(self, instrument): return self._instruments[instrument]
####################################################################################################
[docs]class StringInstrument(Instrument): ##############################################
[docs] def __init__(self, name, category, standard_tuning): super().__init__(name, category) self._standard_tuning = standard_tuning self._tuning = standard_tuning
############################################## @property def standard_tuning(self): return self._standard_tuning @property def number_of_strings(self): return len(self._standard_tuning) @property def tuning(self): return self._tuning @tuning.setter def tuning(self, value): self._tuning = value @property def lowest_pitche(self): return self._tuning.lowest_pitche @property def highest_pitche(self): raise NotImplementedError
# return self._tuning.highest_pitche #################################################################################################### # class Guitar(StringInstrument): # ############################################## # def __init__(): # super().__init__( # name='guitar', # category='fretted string/guitar', # standard_tuning=GuitarTuning.standard, # )