def update(self): self.notes = [] self.intArr = [] self.intStr = [] if self.type not in self.chrLst: return self.intArr = self.chrLst[self.type] self.intStr = [self.intLst[n] for n in self.intArr] if self.intArr: self.notes = [Note(self.root.name, i - 12 if '♭' in iStr else i) for i, iStr in zip(self.intArr, self.intStr)] if self.intStr[:3] == ['1', '♭3', '♭5']: self.quality = 'dim' elif self.intStr[:4] == ['1', '3', '5', '♭7']: self.quality = 'dom' elif self.intStr[:4] == ['1', '3', '♭5', '♭7']: self.quality = 'dom' elif self.intStr[:3] == ['1', '♭3', '♯5']: self.quality = 'aug' elif self.intStr[:3] == ['1', '3', '♯5']: self.quality = 'aug' elif self.intStr[:3] == ['1', '2', '5']: self.quality = 'sus' elif self.intStr[:3] == ['1', '4', '5']: self.quality = 'sus' elif self.intStr[:3] == ['1', '3', '5']: self.quality = 'maj' elif self.intStr[:3] == ['1', '♭3', '5']: self.quality = 'min' else: self.quality = '?' warnings.warn('cannot resolve chord quality for ' + self.name)
def __init__(self, nameOrNotes, checkInv=True): self.notes = [] self.intArr = [] self.intStr = [] if isinstance(nameOrNotes, str): root, alt, chrType = re.search(self.regexChord, nameOrNotes).groups() self.root = Note(root + alt) for r in self.chrReplace: chrType = chrType.replace(r[0], r[1]) self.type = chrType elif isinstance(nameOrNotes, Chord): self.root = nameOrNotes.root self.type = nameOrNotes.type else: nameOrNotes = [str(n) for n in nameOrNotes] chrdType = [] if checkInv: seq = list(permutations(nameOrNotes, len(nameOrNotes))) else: seq = [nameOrNotes] for lst in seq: intervals = [n if n >= 0 else n + 12 for n in [Note(n) - Note(lst[0]) for n in lst]] chrdType.extend([lst[0] + cType for cType in self.chrLst if intervals == self.chrLst[cType]]) if len(chrdType) > 1: chrdType.sort(key=len) # todo: Best match shouldnt be done this way # print('Found {} choosing {}'.format(','.join(chrdType), chrdType[0])) if len(chrdType): self.root = Chord(chrdType[0]).root self.type = Chord(chrdType[0]).type else: print('Cannot find a chord from ' + ','.join(nameOrNotes)) self.root = Note(nameOrNotes[0]) self.type = '?' self.name = str(self.root) + self.type self.update()
def test_basics(): for note in Note.chrSharp + Note.chrFlat: assert Note(note) == note assert Note(note).name == note assert Note(note) + 12 == note assert Note(note) - 12 == note assert Note(note + '#b#b#b') == Note(note)
def printNotes(notes, fmt='shade'): if isinstance(notes[0], str): notes = [Note(n) for n in notes] if fmt == 'square': b, w, spc = [u"\u25A1", u"\u25A0", u"\u2005"] elif fmt == 'shade': b, w, spc = [u"\u2591", u"\u2588", u"\u2005"] else: b, w, spc = [u"\u2591", u"\u2588", u"\u2005"] N = [b] * 12 for ni, n in enumerate([ Note(n) for n in ['C', 'C♯', 'D', 'D♯', 'E', 'F', 'F♯', 'G', 'G♯', 'A', 'A♯', 'B'] ]): if n in notes: N[ni] = w print(3 * spc + N[1] + 2 * spc + N[3] + 9 * spc + N[6] + 2 * spc + N[8] + 2 * spc + N[10] + 7 * spc + 3 * spc + N[1] + 2 * spc + N[3] + 9 * spc + N[6] + 2 * spc + N[8] + 2 * spc + N[10] + '\n' + N[0] + 2 * spc + N[2] + 2 * spc + N[4] + 4 * spc + N[5] + 2 * spc + N[7] + 2 * spc + N[9] + 2 * spc + N[11] + 3 * spc + N[0] + 2 * spc + N[2] + 2 * spc + N[4] + 4 * spc + N[5] + 2 * spc + N[7] + 2 * spc + N[9] + 2 * spc + N[11])
def __init__(self, root='C', mode='ion'): if isinstance(root, Note): root = root.name if ' ' in root: root, mode = root.split(' ') if mode in ['Major', 'Maj', 'major', 'maj', 'M']: mode = 'ion' if mode in ['Minor', 'Min', 'Nmin', 'm', 'minor', 'min', 'nmin', 'm']: mode = 'aeo' if mode in ['hmin']: mode = 'hm' if mode.lower() not in self.modesIntervals: raise ValueError('mode {} not implemented'.format(mode)) self.root = Note(root) self.mode = mode self.name = self.root.name + ' ' + self.mode
def test_fromNotes(): assert Chord('C').notes == ['C', Note('E'), 'G'] from itertools import permutations for lst in list(permutations(['C', 'Eb', 'G', 'Bb'], 4)): assert (Chord(lst).name in ['Cm7', 'E♭6'])
def test_relationships(): assert Note('C') - Note('D') == 10 assert Note('D') - Note('C') == 2 assert Note('B') - Note('C') == 11 assert Note('C') - Note('B') == 1 assert Note('C') - Note('C') == 0 assert Note('G') - Note('C') == 7 assert Note('C') - Note('G') == 5 assert Note('A#') == Note('Bb') assert Note(Note('C')) == 'C'
def test_alterations(): assert Note('C♯#') == Note('D') assert Note('C##') == 'D' assert str(Note('C♯♯')) == 'D' assert Note('Dbb') == Note('C') assert Note('C##♯♯') == Note('E') assert Note('C###').name == 'D♯' assert Note('Fbb').name == 'E♭' # We want to keep alterations assert [Note('C') - alt for alt in range(15)] == \ ['C', 'B', 'B♭', 'A', 'A♭', 'G', 'G♭', 'F', 'E', 'E♭', 'D', 'D♭', 'C', 'B', 'B♭'] assert [Note('C') + alt for alt in range(15)] == \ ['C', 'C♯', 'D', 'D♯', 'E', 'F', 'F♯', 'G', 'G♯', 'A', 'A♯', 'B', 'C', 'C♯', 'D']
def parallelMajor(self, asStr=False): if self.mode == 'aeo': return Scale(Note(self.root), 'ion').name if asStr else Scale( Note(self.root), 'ion') else: return None
def relativeMajor(self, asStr=False): if self.mode == 'aeo': # Relative Minor is 1.5 tone above key return Scale(Note(self.root) + 3, 'ion').name if asStr else Scale( Note(self.root) + 3, 'ion') else: return None
def plotNotes(notes, pos=None, name='', ax=0, nbOctaves=1): if pos is None: pos = [0, 0, 100, 40] def plotKey(ax, x, y, w, h, keyType, status): lw = .5 pad = 0.5 # edgeColor = 'w' # parms = dict( # black=dict(color=['skyblue', 'steelblue'], z=1), # white=dict(color=['skyblue', 'steelblue'], z=0) # ) edgeColor = 'k' parms = dict(black=dict(color=['k', 'skyblue'], z=1), white=dict(color=['w', 'skyblue'], z=0)) ax.add_patch( FancyBboxPatch((x + pad, y + pad), abs(w) - 2 * pad, abs(h) - 2 * pad, boxstyle="round,pad=" + str(pad), fc=parms[keyType]['color'][status], ec=edgeColor, zorder=parms[keyType]['z'], lw=lw)) nb = int(np.ceil(len(notes) / (nbOctaves * 12)) * (nbOctaves * 12)) start = 'C' if notes[0] - Note('C') < notes[0] - Note('F') else 'F' chromatic = Note.chrSharp * 4 chromatic = chromatic[chromatic.index(Note(start)):] chromatic = chromatic[:nb] whites = [ n for n in chromatic if n in [Note(n) for n in ['C', 'D', 'E', 'F', 'G', 'A', 'B']] ] whiteWidth = pos[2] / len(whites) blackWidth = whiteWidth / 2 if ax == 0: figure(figsize=(3, 1)) ax = gca() axis('off') nWhites = 0 for i, n in enumerate(chromatic): if n in whites: plotKey(ax, pos[0] + (nWhites) * whiteWidth, pos[1], whiteWidth, pos[3], keyType='white', status=n in notes) nWhites += 1 else: plotKey(ax, pos[0] + (nWhites) * whiteWidth - blackWidth / 2, pos[1] + pos[3] / 3, blackWidth, 2 * pos[3] / 3, keyType='black', status=n in notes) plot(0, 0, '.w', zorder=-1) if name: text(pos[0], pos[1] + pos[3] / 2, name, ha='right', va='center', rotation=90)