Source code for mingus.containers.bar

#!/usr/bin/python
# -*- coding: utf-8 -*-

#    mingus - Music theory Python package, bar module.
#    Copyright (C) 2008-2009, Bart Spaans
#
#    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/>.

from mingus.core import meter as _meter
from mingus.core import progressions, keys
from note_container import NoteContainer
from note import Note
from mt_exceptions import MeterFormatError

[docs]class Bar(object): """A bar object. A Bar is basically a container for NoteContainers. Bars can be stored together with Instruments in Tracks. """ key = 'C' meter = (4, 4) current_beat = 0.0 length = 0.0 bar = []
[docs] def __init__(self, key='C', meter=(4, 4)): # warning should check types if type(key) == str: key = keys.Key(key) self.key = key self.set_meter(meter) self.empty()
[docs] def empty(self): """Empty the Bar, remove all the NoteContainers.""" self.bar = [] self.current_beat = 0.0 return self.bar
[docs] def set_meter(self, meter): """Set the meter of this bar. Meters in mingus are represented by a single tuple. If the format of the meter is not recognised, a MeterFormatError will be raised. """ # warning should raise exception if _meter.valid_beat_duration(meter[1]): self.meter = (meter[0], meter[1]) self.length = meter[0] * (1.0 / meter[1]) elif meter == (0, 0): self.meter = (0, 0) self.length = 0.0 else: raise MeterFormatError("The meter argument '%s' is not an " "understood representation of a meter. " "Expecting a tuple." % meter)
[docs] def place_notes(self, notes, duration): """Place the notes on the current_beat. Notes can be strings, Notes, list of strings, list of Notes or a NoteContainer. Raise a MeterFormatError if the duration is not valid. Return True if succesful, False otherwise (ie. the Bar hasn't got enough room for a note of that duration). """ # note should be able to be one of strings, lists, Notes or # NoteContainers if hasattr(notes, 'notes'): pass elif hasattr(notes, 'name'): notes = NoteContainer(notes) elif type(notes) == str: notes = NoteContainer(notes) elif type(notes) == list: notes = NoteContainer(notes) if self.current_beat + 1.0 / duration <= self.length or self.length\ == 0.0: self.bar.append([self.current_beat, duration, notes]) self.current_beat += 1.0 / duration return True else: return False
[docs] def place_notes_at(self, notes, at): """Place notes at the given index.""" for x in self.bar: if x[0] == at: x[0][2] += notes
[docs] def place_rest(self, duration): """Place a rest of given duration on the current_beat. The same as place_notes(None, duration). """ return self.place_notes(None, duration)
[docs] def remove_last_entry(self): """Remove the last NoteContainer in the Bar.""" self.current_beat -= 1.0 / self.bar[-1][1] self.bar = self.bar[:-1] return self.current_beat
[docs] def is_full(self): """Return False if there is room in this Bar for another NoteContainer, True otherwise.""" if self.length == 0.0: return False if len(self.bar) == 0: return False if self.current_beat >= self.length - 0.001: return True return False
[docs] def change_note_duration(self, at, to): """Change the note duration at the given index to the given duration.""" if valid_beat_duration(to): diff = 0 for x in self.bar: if diff != 0: x[0][0] -= diff if x[0] == at: cur = x[0][1] x[0][1] = to diff = 1 / cur - 1 / to
[docs] def get_range(self): """Return the highest and the lowest note in a tuple.""" (min, max) = (100000, -1) for cont in self.bar: for note in cont[2]: if int(note) < int(min): min = note elif int(note) > int(max): max = note return (min, max)
[docs] def space_left(self): """Return the space left on the Bar.""" return self.length - self.current_beat
[docs] def value_left(self): """Return the value left on the Bar.""" return 1.0 / self.space_left()
[docs] def augment(self): """Augment the NoteContainers in Bar.""" for cont in self.bar: cont[2].augment()
[docs] def diminish(self): """Diminish the NoteContainers in Bar.""" for cont in self.bar: cont[2].diminish()
[docs] def transpose(self, interval, up=True): """Transpose the notes in the bar up or down the interval. Call transpose() on all NoteContainers in the bar. """ for cont in self.bar: cont[2].transpose(interval, up)
[docs] def determine_chords(self, shorthand=False): """Return a list of lists [place_in_beat, possible_chords].""" chords = [] for x in self.bar: chords.append([x[0], x[2].determine(shorthand)]) return chords
[docs] def determine_progression(self, shorthand=False): """Return a list of lists [place_in_beat, possible_progressions].""" res = [] for x in self.bar: res.append([x[0], progressions.determine(x[2].get_note_names(), self.key.key, shorthand)]) return res
[docs] def get_note_names(self): """Return a list of unique note names in the Bar.""" res = [] for cont in self.bar: for x in cont[2].get_note_names(): if x not in res: res.append(x) return res
[docs] def __add__(self, note_container): """Enable the '+' operator on Bars.""" if self.meter[1] != 0: return self.place_notes(note_container, self.meter[1]) else: return self.place_notes(note_container, 4)
[docs] def __getitem__(self, index): """Enable the '[]' notation on Bars to get the item at the index.""" return self.bar[index]
[docs] def __setitem__(self, index, value): """Enable the use of [] = notation on Bars. The value should be a NoteContainer, or a string/list/Note understood by the NoteContainer. """ if hasattr(value, 'notes'): pass elif hasattr(value, 'name'): value = NoteContainer(value) elif type(value) == str: value = NoteContainer(value) elif type(value) == list: res = NoteContainer() for x in value: res + x value = res self.bar[index][2] = value
[docs] def __repr__(self): """Enable str() and repr() for Bars.""" return str(self.bar)
[docs] def __len__(self): """Enable the len() method for Bars.""" return len(self.bar)
[docs] def __eq__(self, other): """Enable the '==' operator for Bars.""" for b in range(0, len(self.bar) - 1): if self.bar[b] != other.bar[b]: return False return True