Menu

[r61]: / trunk / PyChoReLib / lib / ScaleRecognizer.py  Maximize  Restore  History

Download this file

137 lines (122 with data), 6.5 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# This file is part of PyChoReLib.
#
# PyChoReLib 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 2 of the License, or
# (at your option) any later version.
#
# PyChoReLib 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 PyChoReLib; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from Exceptions import NoMatch
from KnowledgeBasedRecognizer import KnowledgeBasedRecognizer
from Scale import Scale
from ScaleName import ScaleName
from ScaleBuilder import ScaleBuilder
from ScaleDefinitions import ScaleDefinitions
from HelperFunctions import P
import copy
ALLNOTES = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g' ]
ALLNOTES.extend( ['a#', 'b#', 'c#', 'd#', 'e#', 'f#', 'g#' ] )
ALLNOTES.extend( ['ab', 'bb', 'cb', 'db', 'eb', 'fb', 'gb' ] )
ALLNOTES.extend( ['ax', 'bx', 'cx', 'dx', 'ex', 'fx', 'gx' ] )
ALLNOTES.extend( ['abb', 'bbb', 'cbb', 'dbb', 'ebb', 'fbb', 'gbb' ] )
class ScaleRecognizer(KnowledgeBasedRecognizer):
def RegisterScaleDefinitionByExample(self, AScale, AScaleName, Verbosity):
"""
Method to register a new scale type, by showing an example of such a scale.
"""
SimplifiedScale = AScale.FindCanonicForm()
if SimplifiedScale != AScale.Notes:
if Verbosity != 0:
print "*** Warning: registration of non-canonical scale", AScale.Notes, "as ", SimplifiedScale
pass
Intervals= Scale(SimplifiedScale).ToIntervalPattern()
DBKey = tuple(Intervals)
if self.KnowledgeBase.has_key(DBKey):
if Verbosity != 0:
print "*** Warning: duplicate Scale definition overrules earlier defined scale. Old: ",self.KnowledgeBase[DBKey][0].Print(),"New: ",AScaleName.Print()
RootNoteIndex = SimplifiedScale.index(AScaleName.GetRootName())
ModeRootNoteIndex = SimplifiedScale.index(AScaleName.GetModeRootName())
self.KnowledgeBase[DBKey] = tuple([AScaleName, RootNoteIndex, ModeRootNoteIndex])
def RegisterScaleSetByExample(self, ScaleType, ListOfScaleNotes, ModeNames, Verbosity):
"""
Convenience method to register a whole set of modes formed by starting AScale on successive notes.
"""
for Mode in ModeNames:
if Mode:
StartNoteIdx = ModeNames.index(Mode)
TheScale = Scale(ListOfScaleNotes[StartNoteIdx:] + ListOfScaleNotes[:StartNoteIdx])
TheScaleName = ScaleName(ListOfScaleNotes[0], ScaleType, ListOfScaleNotes[StartNoteIdx], Mode)
self.RegisterScaleDefinitionByExample(TheScale, TheScaleName, Verbosity)
def InitializeKnowledgeBase(self,Verbosity=0):
""" Teach all scale types to the system. This may take some time.
Alternatively, a generated database can be serialized to disk, and loaded on start-up
"""
P(Verbosity,"Start teach scale types. This may take some time")
for BaseScale, Notes, Modes in ScaleDefinitions:
self.RegisterScaleSetByExample(BaseScale, Notes, Modes, Verbosity)
P(Verbosity,"Done teaching")
def ScaleToKey(self, AScale):
""" Method that takes a Scale AScale, and transforms it to a key into the knowledge base """
SimplifiedScale = Scale(AScale.FindCanonicForm())
Intervals = SimplifiedScale.ToIntervalPattern()
return tuple(Intervals)
def RecognizeScale(self, AScale):
""" Method to lookup a Scale AScale in the knowledge base """
DBKey = self.ScaleToKey(AScale)
if self.KnowledgeBase.has_key(DBKey):
MatchedScale = self.KnowledgeBase[DBKey][0]
SimplifiedScale = Scale(AScale.FindCanonicForm())
RootName = SimplifiedScale.Notes[self.KnowledgeBase[DBKey][1]]
MatchedScale.SetRootName(RootName)
ModeRootName = SimplifiedScale.Notes[self.KnowledgeBase[DBKey][2]]
MatchedScale.SetModeRootName(ModeRootName)
return (MatchedScale, SimplifiedScale, RootName)
else:
raise NoMatch
# Method to find out from which scales (modes) a given chord can be
# derived.
def CreateScaleListMatchingChord(self, ListOfNotenamesInChord, AllowModes):
sb = ScaleBuilder()
found_scales = []
for n in ALLNOTES:
for s in self.KnowledgeBase:
ScaleName = self.KnowledgeBase[s][0]
#print "ScaleName=",ScaleName
RootIdx = self.KnowledgeBase[s][1]
#print "RootIdx=",RootIdx
ModeRootIdx = self.KnowledgeBase[s][2]
#print "ModeRootIdx=",ModeRootIdx
try:
ScaleNotes = sb.GetNotes(n, ScaleName.GetMode())
except NoMatch:
continue
#print ScaleNotes
if set(ListOfNotenamesInChord).issubset(set(ScaleNotes)):
s = ScaleName
s.SetRootName( ScaleNotes[RootIdx] )
s.SetModeRootName( ScaleNotes[ModeRootIdx] )
#print "Chord: ", ListOfNotenamesInChord, " ScaleNotes: ", ScaleNotes, " n = ", n, " ScaleType= ", ScaleName.GetType(), "RootIdx=", RootIdx, "ModeRootIdx=", ModeRootIdx, " ScaleName = ", ScaleName, "Match: RootName = ", ScaleNotes[RootIdx], " ModeName ", ScaleNotes[ModeRootIdx]
#print s
FirstMode = RootIdx == ModeRootIdx
if AllowModes or FirstMode:
found_scales.append(copy.copy(s))
return found_scales
def KnownScales(self):
""" Return list of known scales."""
return [self.KnowledgeBase[DBKey][0].__repr__() for DBKey in self.KnowledgeBase]
if __name__ == "__main__":
s = ScaleRecognizer()
C = ['c', 'd', 'eb', 'g' ]
print "******************************************"
for x in s.CreateScaleListMatchingChord(C, True):
print x
print "******************************************"
for y in s.CreateScaleListMatchingChord(C, False):
print y