def _loadMinMax(self, min, max): ''' >>> a = Parameter([]) >>> post = a._loadMinMax(45, 34) >>> post[0].type, post[1].type ('constant', 'constant') >>> post = a._loadMinMax(45, ['ru', 0, 1]) >>> post[0].type, post[1].type ('constant', 'randomUniform') >>> post = a._loadMinMax(['ru', 0, 1], ['ru', 0, 1]) >>> post[0].type, post[1].type ('randomUniform', 'randomUniform') ''' if drawer.isNum(min): minArgs = ('c', min) elif drawer.isList(min): minArgs = min # check max if drawer.isNum(max): maxArgs = ('c', max) elif drawer.isList(max): maxArgs = max # create a parameter object from athenaCL.libATH.libPmtr import parameter try: minObj = parameter.factory(minArgs) except error.ParameterObjectSyntaxError, msg: raise error.ParameterObjectSyntaxError, 'failed sub-parameter: %s' % msg
def ruleCount(srcSpan, dstValues, srcValues=None): """ >>> k=2; r=1; q=k-1 >>> pow(k,((r*2)+1)*q) 8 >>> ruleCount(((r*2)+1),range(k),(((r*2)+1)*(k-1))) 8 >>> k=3; r=2; q=k-1 >>> pow(k,((r*2)+1)*q) 59049 >>> ruleCount(((r*2)+1),range(k),(((r*2)+1)*(k-1))) 59049 """ # srcSpan == r*2+1, len(dstValues) == k # totalistic rule count: k = k, len(dstValues) if drawer.isNum(dstValues): k = dstValues dstValues = range(dstValues) else: # assume its a list k = len(dstValues) if srcValues == None: # not totalistic count = pow(k, pow(k, srcSpan)) else: # totalistic, srcValues are provided if drawer.isNum(srcValues): q = srcValues else: # assume its a list q = len(srcValues) count = pow(k, q) # print _MOD, 'rule count', count return count
def _guessType(self): """try to determine what kind of duration/dynamic data is given can be string or integer tuple/list: (2,1,1) or (3,1) can be string char like q, e, t, s, th? can be string acc list .5 1 .3 1 """ data = copy.copy(self.srcData) if drawer.isStr(data): data = data.strip() # temp data data = data.lower() if len(data) == 0: return None # no data found if data[0].islower(): # if has chars if data in REFdurStr.keys(): return 'str' elif data in REFdynStr.keys(): # maybe its a dynmaic return 'acc' # acc string value alone else: raise error.PulseSyntaxError elif data[0] == '[' or data[0] == '(': # its a list or tuple return 'triple' elif data.find(',') >= 0: # if there are commas in string return 'triple' else: # assume its an acc string return 'acc' if drawer.isNum(data): # acc list return 'acc' if drawer.isList(data): return 'triple'
def checkArgs(self): for item in self.switch('transpositionList'): if not drawer.isNum(item): return 0, 'elements in transpositionList must be numbers.' if self.switch('timeDelay') < 0: msg = 'timeDelay must be greater than or equal to zero.' return 0, msg return 1, ''
def _processType(self): """process raw data into appropriate primative format""" data = copy.copy(self.srcData) if self.format == 'psName': if drawer.isStr(data): return data else: return None elif self.format == 'psReal': # psReal values should not be rounded if drawer.isStr(data): try: return float(data) except ValueError: return None else: return data elif self.format == 'midi': #midi values should always be rounded if drawer.isStr(data): data = drawer.strStripAlpha(data) try: return float(data) # dont convert to int except ValueError: return None elif drawer.isInt(data): return data else: # its a float, round return data elif self.format == 'pch': # floating point values if drawer.isStr(data): data = drawer.strStripAlpha(data) try: return _normalizePch(float(data)) except ValueError: return None if drawer.isFloat(data): return _normalizePch(data) else: # something is wrong return None elif self.format == 'fq': # floating point values if drawer.isStr(data): data = drawer.strStripAlpha(data) try: return float(data) except ValueError: return None if drawer.isNum(data): return float(data) # convert to float else: # something is wrong return None else: # error return None
def iMod(self, axis=0): """axis transposition, but retaining octave positon like tMod """ # find desired index if drawer.isNum(axis): index = _InvAxisToIndex(axis) if drawer.isList(axis): index = _InvPcPairToIndex(axis[0], axis[1]) self._real = pcoInverter(self._real, index) self.data = self._convert(self.format, 'psReal', self._real)
def clear(self): """processes init value and replaces history with first generation""" stepInit = self._getTemplate() if drawer.isNum(self.init): for y in range(self.size[1]): for x in range(self.size[0]): self.stepTemplate[y][x] = self.init elif drawer.isList(self.init): # assume list is same size from for row in self.init: for col in row: self.stepTemplate[y][x] = col self.stepHistory = [stepInit] # a list of arrays
def convertBoolCancel(usrData): """converts arg strings: on, off, or cancel or numbers 0, 1 get strings from language; check english for preferences >>> convertBoolCancel('y') 1 >>> convertBoolCancel('no') 0 >>> convertBoolCancel(-1) -1 """ if drawer.isNum(usrData): usrStr = str(int(round(usrData))) else: usrStr = drawer.strScrub(usrData, 'L') if usrStr == '': return None # off if (usrStr in ['0', lang.OFF.lower(), lang.NO.lower(), lang.FALSE.lower()] or usrStr[0] == lang.NO[0].lower()): return 0 if len(usrStr) >= len(lang.OFF): if usrStr[-len(lang.OFF):] == lang.OFF.lower(): return 0 if len(usrStr) >= 3: # check literal english if usrStr[-3:] == 'off': return 0 # on if (usrStr in ['1', lang.ON.lower(), lang.YES.lower(), lang.TRUE.lower()] or usrStr[0] == lang.YES[0].lower()): return 1 if len(usrStr) >= len(lang.ON): if usrStr[-len(lang.ON):] == lang.ON.lower(): return 1 if len(usrStr) >= 2: # check literal english if usrStr[-2:] == 'on': return 1 # cancel if (usrStr in ['-1', lang.CANCEL.lower(), lang.BREAK.lower()] or usrStr[0] == lang.CANCEL[0].lower()): return -1 # if no match return None return None
def clear(self): """processes init value and replaces history with first generation will always add an init to the history, meaning that there will always be one more generation than expected in most cases """ stepInit = self._getTemplate() if drawer.isStr(self.init): numStr, junk = drawer.strExtractNum(self.init) if self.init == 'center': centerIndex = self._getCenter() if self.dstValues == None: # continuous case if self.DECIMAL: val = decimal.Decimal(1) else: val = 1.0 # should add one here, but need -1 for list position shift stepInit[self._getCenter()] = val else: # center value is dependent; must provude as variable stepInit[self._getCenter()] = self.dstValues[ self.dstIndexCenter] elif self.init == 'random': for x in range(self.size): if self.dstValues == None: # continuous case if self.DECIMAL: val = decimal.Decimal(str(random.random())) else: val = random.random() stepInit[x] = val else: # discrete stepInit[x] = random.choice(self.dstValues) # may be number as a string; treat as a list elif len(numStr) == len(self.init): for x in range(self.size): # must be integers, use force to limit at min / max if self.dstValues != None: min = self.dstValues[0] max = self.dstValues[-1] else: # continuous, unit interval min = 0 max = 1 val = drawer.strToNum(self.init[(x % len(self.init))], 'int', min, max, 1) stepInit[x] = val elif drawer.isNum(self.init): for x in range(self.size): stepInit[x] = self.init elif drawer.isList(self.init): for x in range(self.size): stepInit[x] = self.init[(x % len(self.init))] self.stepHistory = [stepInit] # a list of arrays
def __init__(self, data): # ds is decimal seconds, or values less than 1, as a decimal # ds is not converted to ms or any other unit self.time = {'f': 0, 's': 0, 'm': 0, 'h': 0, 'd': 0} self.sec = 0 self.srcData = data self.timeLabels = ['d', 'h', 'm', 's', 'f'] # must be in order if drawer.isStr(data): self._humanToSec(data) # load to self.time elif drawer.isNum(data): # assume seconds self.time['s'] = data # keep floating point values else: raise ValueError, 'unsupported data type' self._updateTime() # update and shifts all values
def __init__(self, data): # ds is decimal seconds, or values less than 1, as a decimal # ds is not converted to ms or any other unit self.time = {'f':0, 's':0, 'm':0, 'h':0, 'd':0} self.sec = 0 self.srcData = data self.timeLabels = ['d', 'h', 'm', 's', 'f'] # must be in order if drawer.isStr(data): self._humanToSec(data) # load to self.time elif drawer.isNum(data): # assume seconds self.time['s'] = data # keep floating point values else: raise ValueError, 'unsupported data type' self._updateTime() # update and shifts all values
def _tripleMonadTest(self, srcData): """determine if a rhythm is a single rhythm triple, or rather a pulse list (1,1,1) will be interpreterd as pulse list (1,) (3,1) will be rhythm triple (1,2) will be rhythm triple """ if len(srcData) == 2 or len(srcData) == 3: d = srcData[0] m = srcData[1] if drawer.isNum(d): if d >= 2 or m >= 2: # one value needs to be greater than 1 if d != 0 and m != 0: # neither can be zerp return 1 # rhythm triple return 0 # it is a pulse list
def clear(self): """processes init value and replaces history with first generation will always add an init to the history, meaning that there will always be one more generation than expected in most cases """ stepInit = self._getTemplate() if drawer.isStr(self.init): numStr, junk = drawer.strExtractNum(self.init) if self.init == 'center': centerIndex = self._getCenter() if self.dstValues == None: # continuous case if self.DECIMAL: val = decimal.Decimal(1) else: val = 1.0 # should add one here, but need -1 for list position shift stepInit[self._getCenter()] = val else: # center value is dependent; must provude as variable stepInit[self._getCenter()] = self.dstValues[self.dstIndexCenter] elif self.init == 'random': for x in range(self.size): if self.dstValues == None: # continuous case if self.DECIMAL: val = decimal.Decimal(str(random.random())) else: val = random.random() stepInit[x] = val else: # discrete stepInit[x] = random.choice(self.dstValues) # may be number as a string; treat as a list elif len(numStr) == len(self.init): for x in range(self.size): # must be integers, use force to limit at min / max if self.dstValues != None: min = self.dstValues[0] max = self.dstValues[-1] else: # continuous, unit interval min = 0 max = 1 val = drawer.strToNum(self.init[(x % len(self.init))], 'int', min, max, 1) stepInit[x] = val elif drawer.isNum(self.init): for x in range(self.size): stepInit[x] = self.init elif drawer.isList(self.init): for x in range(self.size): stepInit[x] = self.init[(x % len(self.init))] self.stepHistory = [stepInit] # a list of arrays
def _pmtrNumberToUsr(self, pmtr, shift, style='str'): """convert a parameter number string into data numbers are returned as numbers, strings as strings str, and cmd produce un-altered numbers usr wil shift by appropriate values""" if drawer.isNum(pmtr): if style in ['str', 'cmd']: return pmtr elif style == 'usr': return pmtr + shift if drawer.isStr(pmtr): if style in ['str', 'cmd']: return pmtr elif style == 'usr': pmtr = drawer.strScrub(pmtr, 'lower') pmtr = pmtr.replace('q', '') return str(int(pmtr) + shift)
def _updateDefault(self, src): """make a ca dictionary rule and mutation are left out, as dynamic""" xMAX = 1000 yMAX = 10000 ref = { # these are the limits 'f': ('s', ), # must be first element of a list 'k': (2, 0, 36), # def, min, max 'r': (1, .5, 10), 'i': ('center', ), 'x': (91, 1, xMAX), # should be odd value 'y': (135, 1, yMAX), 'w': (0, 0, yMAX), # will get value of 'c': (0, -xMAX, xMAX), # center 's': (0, 0, yMAX), # skip } # src keys have already been formated to single character refs for key in ref.keys(): if key not in src.keys(): src[key] = ref[key][0] else: # keu exists, eval numbers if necessary if drawer.isNum(ref[key][0]): # check numbers min = ref[key][1] max = ref[key][2] # permit r values w/ decimal .5 if key == 'r' and '.' in src[key]: # double, round, and divide; will be either 0 or .5 value = drawer.strToNum(src[key], 'float', min, max) value = round(value * 2) / 2 else: value = drawer.strToNum(src[key], 'int', min, max) if value != None: src[key] = value else: # cant resolve value, provide default src[key] = ref[key][0] if drawer.isStr(ref[key][0]): # check strings if key == 'f': value = caFormatParser(src[key]) elif key == 'i': value = caInitParser(src[key]) if value != None: src[key] = value else: src[key] = ref[key][0] return src
def _updateDefault(self, src): """make a ca dictionary rule and mutation are left out, as dynamic""" xMAX = 1000 yMAX = 10000 ref = { # these are the limits 'f' : ('s',), # must be first element of a list 'k' : (2, 0, 36), # def, min, max 'r' : (1, .5, 10), 'i' : ('center',), 'x' : (91, 1, xMAX), # should be odd value 'y' : (135, 1, yMAX), 'w' : (0, 0, yMAX), # will get value of 'c' : (0, -xMAX, xMAX), # center 's' : (0, 0, yMAX), # skip } # src keys have already been formated to single character refs for key in ref.keys(): if key not in src.keys(): src[key] = ref[key][0] else: # keu exists, eval numbers if necessary if drawer.isNum(ref[key][0]): # check numbers min = ref[key][1] max = ref[key][2] # permit r values w/ decimal .5 if key =='r' and '.' in src[key]: # double, round, and divide; will be either 0 or .5 value = drawer.strToNum(src[key], 'float', min, max) value = round(value*2) / 2 else: value = drawer.strToNum(src[key], 'int', min, max) if value != None: src[key] = value else: # cant resolve value, provide default src[key] = ref[key][0] if drawer.isStr(ref[key][0]): # check strings if key == 'f': value = caFormatParser(src[key]) elif key == 'i': value = caInitParser(src[key]) if value != None: src[key] = value else: src[key] = ref[key][0] return src
def caInitParser(usrStr): """ >>> caInitParser('center') 'center' >>> caInitParser('junk') == None True """ usrNum, junk = drawer.strExtractNum(usrStr) if drawer.isNum(usrStr) or (len(usrNum) == len(usrStr) or drawer.isList(usrStr)): return usrStr # not a string, a data obj # only parse if a string ref = { 'center': ['c', 'center'], 'random': ['r', 'random'], } usrStr = drawer.selectionParse(usrStr, ref) return usrStr # may be Non
def caInitParser(usrStr): """ >>> caInitParser('center') 'center' >>> caInitParser('junk') == None True """ usrNum, junk = drawer.strExtractNum(usrStr) if drawer.isNum(usrStr) or (len(usrNum) == len(usrStr) or drawer.isList(usrStr)): return usrStr # not a string, a data obj # only parse if a string ref = { 'center' : ['c', 'center'], 'random' : ['r', 'random'], } usrStr = drawer.selectionParse(usrStr, ref) return usrStr # may be Non
def _loadAutoConstantStr(self, arg, ref, lib='genPmtrObjs'): """accept a number, a list parameter object, or a string from within a dfeind string group""" # ref = {'0' : ['tn', 't', 't n' '0'], # } if drawer.isNum(arg): pmtrArgs = ('c', arg) elif drawer.isStr(arg): post = drawer.selectionParse(arg, ref, 0) # autosearch off if post == None: raise error.ParameterObjectSyntaxError, 'no such preset name known.' pmtrArgs = ('c', post) # a constant pmtr obj else: # its a list to create a ParameterObject pmtrArgs = arg # create a ParameterObject from athenaCL.libATH.libPmtr import parameter try: obj = parameter.factory(pmtrArgs, lib) except error.ParameterObjectSyntaxError, msg: raise error.ParameterObjectSyntaxError, 'failed sub-parameter: %s' % msg
def _keyParser(self, usrStr): if drawer.isNum(usrStr) or drawer.isList(usrStr): return usrStr # not a string, a data obj # only parse if a string # may need to add: 'd' for dimension # 'z' for z axis? ref = { 'f': ['f', 'format', 'form', 'type'], 'k': ['k', 'colors'], 'r': ['r', 'radius'], 'i': ['i', 'init', 'initial'], 'x': ['x', 'size'], 'y': ['y', 'steps', 'gen'], 'w': ['w', 'width'], 'c': ['c', 'center'], 's': ['s', 'skip'], } usrStr = drawer.selectionParse(usrStr, ref) return usrStr # may be None
def _keyParser(self, usrStr): if drawer.isNum(usrStr) or drawer.isList(usrStr): return usrStr # not a string, a data obj # only parse if a string # may need to add: 'd' for dimension # 'z' for z axis? ref = { 'f' : ['f', 'format', 'form', 'type'], 'k' : ['k', 'colors'], 'r' : ['r', 'radius'], 'i' : ['i', 'init', 'initial'], 'x' : ['x', 'size'], 'y' : ['y', 'steps', 'gen'], 'w' : ['w', 'width'], 'c' : ['c', 'center'], 's' : ['s', 'skip'], } usrStr = drawer.selectionParse(usrStr, ref) return usrStr # may be None
def _loadAutoConstant(self, arg, lib='genPmtrObjs'): """take args and if a number, returns as a constant value parameterObj otherwise, keep as is >>> a = Parameter([]) >>> post = a._loadAutoConstant(45) >>> post.type 'constant' >>> post = a._loadAutoConstant(['ru', 0, 1]) >>> post.type 'randomUniform' """ if drawer.isNum(arg): pmtrArgs = ('c', arg) # fit within a constant else: # its a list to create a ParameterObject pmtrArgs = arg # create a ParameterObject from athenaCL.libATH.libPmtr import parameter try: obj = parameter.factory(pmtrArgs, lib) except error.ParameterObjectSyntaxError, msg: raise error.ParameterObjectSyntaxError, 'failed sub-parameter: %s' % msg
def _loadPulse(self): objList = [] if drawer.isStr(self.srcData): # if whole argument is a string; not yet implemented # this is not going to work, cannot devide a compelete string w/ , strList = self.srcData.split(',') # split for element in strList: obj = Pulse(element) # will raise exception on load error objList.append(obj) elif drawer.isNum(self.srcData): obj = Pulse(self.srcData) # will raise exception on load error objList.append(obj) elif drawer.isList(self.srcData): if self._tripleMonadTest(self.srcData): # a single triple obj = Pulse(self.srcData) objList.append(obj) else: # get individual chunks; a pulse list for element in self.srcData: obj = Pulse(element) # will raise exception on load error objList.append(obj) else: raise error.PulseSyntaxError return objList
def _expandRawTriple(self, data): """take an int, 2, or three element tuple and provide defaults returns None if nothing expandable if third element in list exists and is a string will be converted does checks on div and mult, divide by zero error and all raise exception """ defD = 1 # default values defM = 1 defA = 1 if drawer.isNum(data): # assum its an acc return (defD, defM, self. _normAcc(data)) elif drawer.isStr(data): # assum its an acc as string return (defD, defM, self. _normAcc(self._dynStrToVal(data))) elif drawer.isList(data): data = list(data) # convert to list for assignment if len(data) == 0: return None elif len(data) == 1: # its an acc return (defD, defM, self. _normAcc(data)) elif len(data) == 2: try: data[0], data[1] = self._normDivMult(data[0], data[1]) except error.PulseSyntaxError: return None # error return (data[0], data[1], defA) else: # other info in a list will be removed try: data[0], data[1] = self._normDivMult(data[0], data[1]) except error.PulseSyntaxError: return None # error if drawer.isStr(data[2]): acc = self._dynStrToVal(data[2]) else: # its a number acc = data[2] return (data[0], data[1], self. _normAcc(acc)) else: return None # error
def _expandRawTriple(self, data): """take an int, 2, or three element tuple and provide defaults returns None if nothing expandable if third element in list exists and is a string will be converted does checks on div and mult, divide by zero error and all raise exception """ defD = 1 # default values defM = 1 defA = 1 if drawer.isNum(data): # assum its an acc return (defD, defM, self._normAcc(data)) elif drawer.isStr(data): # assum its an acc as string return (defD, defM, self._normAcc(self._dynStrToVal(data))) elif drawer.isList(data): data = list(data) # convert to list for assignment if len(data) == 0: return None elif len(data) == 1: # its an acc return (defD, defM, self._normAcc(data)) elif len(data) == 2: try: data[0], data[1] = self._normDivMult(data[0], data[1]) except error.PulseSyntaxError: return None # error return (data[0], data[1], defA) else: # other info in a list will be removed try: data[0], data[1] = self._normDivMult(data[0], data[1]) except error.PulseSyntaxError: return None # error if drawer.isStr(data[2]): acc = self._dynStrToVal(data[2]) else: # its a number acc = data[2] return (data[0], data[1], self._normAcc(acc)) else: return None # error
def findNormalT(pcSet, setMatrix=None): """finds normal form of any pc set and returns forte number as a scTriple data structure, and transposition from normal form pcSet may contain psReals, and as such, need to be converted to ints >>> findNormalT([3,4,5]) ((3, 1, 0), 3) """ if setMatrix == None: # use forte as default setMatrix = FORTE MONADscTuple = (1,1,0) # check for bad data if drawer.isStr(pcSet): return None # error, no strings supported here if drawer.isList(pcSet): for psReal in pcSet:# make sure all values are numbers; no strings allowed if drawer.isStr(psReal): return None # break, return None as error # check for unusual data if drawer.isNum(pcSet): # its a single number pcVal = pitchTools.roundMicro(pcSet) # second number is transposition from 0 return MONADscTuple, (pcVal % 12) if len(pcSet) == 1: #filter out monad! pcVal = pitchTools.roundMicro(pcSet[0]) return MONADscTuple, (pcVal % 12) # scrub and go pcSetClone = [] for psReal in pcSet: # pcSet may contian psReal, w/ floating values pcSetClone.append(pitchTools.roundMicro(psReal)) #check fr non base 12 numbers, negative numbers, redundancies pcSetClone = list(pcSetTransposer(pcSetClone, 0)) pcSetClone.sort() i = 0 chord = [] for i in range(0,12): # remove redundancies if i in pcSetClone: chord.append(i) card = len(chord) if card < 1: # monad has already been filtered out return None # 2nd no is transposition from 0 if card == 1: # this is a set like (3,3,3,3) return MONADscTuple, (pcSet[0] % 12) elif card > 12: return None # 'irrational cardinality error' rotIndices = range(0, card) foundIndex = None #control variable for rot in rotIndices: r = rot # dont need to add 1? + 1 rotSet = chord[r:card] + chord[0:r] dif = rotSet[0] pSet = pcSetTransposer(rotSet, -dif) iSet = tuple(pcInverter(pSet)) maxRange = len(setMatrix[card]) # check all sets of given card for match for index in range(1, maxRange): # start with 1, not zero # this is a default; may be a symmetrical set and have no inversion foundInv = 'A' # test each set in this cardinality; "0" gets pitches testSet = tuple(setMatrix[card][index][0]) if iSet == testSet: foundIndex = index foundInv = 'B' #nt sure yet if 1 or 0 break elif pSet == testSet: foundIndex = index foundInv = 'A' #nt sure yet if 1 or 0 break if foundIndex != None: break if foundIndex == None: ## no set found return None #'failed!!!' if foundInv == 'B': # has inversion that is non-redundant (variant) if setMatrix[card][foundIndex][2][1] == 0 : scInv = -1 else: scInv = 0 elif foundInv == 'A': # has inversion that is non-redundant (variant) if setMatrix[card][foundIndex][2][1] == 0 : scInv = 1 else: scInv = 0 return (card, foundIndex, scInv), dif
def advance(self, ageStep=1): """Advance the particle one frame. The `ageStep` argumetn can be a function that returns a number or a number (value around 1). This value is rounded to the nearest integer; floating point values outside of .5 and 1.5 cause shifts. >>> pairs = [('a', 2)] >>> a = Particle(pairs) >>> a.advance() True >>> a.advance() True >>> a.advance() False >>> pairs = [('a', 2)] >>> a = Particle(pairs) >>> a.advance(2) True >>> a.advance(2) False >>> pairs = [('a', 1), ('b', 1), ('c', 1)] >>> a = Particle(pairs) >>> a.advance() True >>> a.state 'a' >>> a.advance() True >>> a.state 'b' >>> a.advance() True >>> a.state 'c' >>> a.advance() False >>> a.state == None True """ if drawer.isNum(ageStep): ageUnit = ageStep else: ageUnit = ageStep() # assume it is a function # Probabilistic rounding of floating point values ageUnitInt = drawer.floatToInt(ageUnit, 'weight') self.age += ageUnitInt if self.age > self.lifeSpan: # must be greater, not >= self.state = None return False # cant advance, as is dead # check each state in the life bounds, see if this age # is within the range of any of those bounds for key in self.lifeBounds: if (self.age >= self.lifeBounds[key][0] and self.age <= self.lifeBounds[key][1]): self.state = key # assign new state break return True # still alive
def strongType(usrArgs, argTypes, defaultArgs=[], argCountOffset=0): """Argument checking tool. checks raw arg type and number, one level deep (does not recurse into list) will supply defaults if missing args after last given and self.defaultArgs defined two arguments required, both lists: args = a list of arguments, of proper python data types argTypes = list of one-level deap types, specified w/ strings 'list', 'num', 'float', 'int', 'str'; see drawer.py one optional args defaultArgs = list of default args to substitute returns: newArgs, ok, msg >>> strongType([[1,2,3]], ['list']) ([[1, 2, 3]], 1, '') >>> strongType([.5, 3, 'three'], ['float', 'int', 'str']) ([0.5, 3, 'three'], 1, '') >>> strongType([3.2], ['num', 'num']) ([3.2000...], 0, 'incorrect number of arguments; enter 2 arguments.') >>> strongType([3.2, 5, 6], ['num', 'num']) ([3.2000..., 5, 6], 0, 'too many arguments; enter 2 arguments.') """ argCount = len(argTypes) if len(usrArgs) < argCount: # try to get from defaults if len(defaultArgs) == argCount: # defaults exits (default is 0) for retrieve in defaultArgs[len(usrArgs):]: usrArgs.append(retrieve) # add missing to end #print 'argTools.py: adding default', retrieve, defaultArgs else: # nothing we can do: failure msg = ('incorrect number of arguments; enter %i arguments.' % (argCount + argCountOffset)) # add incase if name offset return usrArgs, 0, msg elif len(usrArgs) > argCount: #print _MOD, len(usrArgs), argCount msg = 'too many arguments; enter %i arguments.' % (argCount + argCountOffset) return usrArgs, 0, msg for pos in range(0, argCount): argTest = usrArgs[pos] # can be [list, num, float, int, str] typeCandidates = argTypes[pos] if not drawer.isList(typeCandidates): typeCandidates = [ typeCandidates, ] # add to list for type in typeCandidates: if type == 'list' and drawer.isList(argTest): match = 1 break elif type == 'num' and drawer.isNum(argTest): match = 1 break elif type == 'float' and drawer.isFloat(argTest): match = 1 break elif type == 'int' and drawer.isInt(argTest): match = 1 break elif type == 'str' and drawer.isStr(argTest): match = 1 break else: # dont break; need to through other possbilities match = 0 # should covnert types to better strings if match == 0: msg = ( 'wrong type of data used as an argument. replace %s with a %s argument type.' % ( repr(typeset.anyDataToStr(argTest)), # provide 'or' to show that any type in candidate is good drawer.typeListAsStr(typeCandidates, 'or'))) return usrArgs, 0, msg # all good return usrArgs, 1, ''
def extractNeighbors(pitchGroup, baseNote, scales=None): """takes a set, or a whole path, and derives a pc scale, a pitch space scale, and provides the upper and lower note to baseNote baseNote should be represented in the pitch group we need to know our current reference position in the pitchGroup pitchGroup has pitch pre-temperament; thus baseNote should be pre-temperament may be a psReal pitchGroup: from a refDict, containing stateCurrentChord, or statePathList will be a list of raw psReal values: could be floats, and could have micro specification """ # if scales given and no pitchGroup is given if scales != None and pitchGroup == None: colPitchSpace = scales[0] colPitchClass = scales[1] else: # given a set or path as pitchGroup if drawer.isNum(pitchGroup[0]): pitchGroup = [ pitchGroup, ] # make all look like paths colPitchSpace = [] colPitchClass = [] for set in pitchGroup: for entry in set: if entry not in colPitchSpace: colPitchSpace.append(entry) # round; zero trans gets mod12 entryPC = pitchTools.pcTransposer(entry, 0) if entryPC not in colPitchClass: colPitchClass.append(entryPC) colPitchSpace.sort() colPitchClass.sort() scales = colPitchSpace, colPitchClass # use pitch class space to get neighbors # can use pitch space in the future? wrap around is strange octaveAdjust = 0 baseOctMult, basePC = pitchTools.splitOctPs(baseNote) # although baseNote may be a float (already tempered) # basePC seems to need to be an int, as it is used to find # a position in the scale; for this reason it seems like # the path positions value, and not the tempered pitch # should be coming in as the baseNote: tmerperament could cause # a rounding error and pass a pitch that is not in the scale at all #print _MOD, basePC, colPitchClass idx = None try: idx = colPitchClass.index(basePC) except ValueError: # not in the collected pitches; try rounding for i in range(len(colPitchClass)): # compare rounded versions, as floats may not match if round(colPitchClass[i], 2) == round(basePC, 2): idx = i # print _MOD, 'found rounded match' if idx == None: idx = 0 environment.printDebug( 'no match between base pitch and collected pitches') idxL = idx - 1 # lower neighbor if idxL == -1: # wrap index around idxL = len(colPitchClass) - 1 octaveAdjust = -1 idxU = idx + 1 # upper neighbor if idxU == len(colPitchClass): idxU = 0 octaveAdjust = 1 neighborL = colPitchClass[idxL] if octaveAdjust == -1: neighborL = pitchTools.psTransposer(neighborL, -12) neighborU = colPitchClass[idxU] if octaveAdjust == 1: neighborU = pitchTools.psTransposer(neighborU, 12) # do octave adjust ment relative to baseNote in pitch space neighborL = pitchTools.psTransposer(neighborL, (12 * baseOctMult)) neighborU = pitchTools.psTransposer(neighborU, (12 * baseOctMult)) lowerUpper = neighborL, neighborU return scales, lowerUpper
def strongType(usrArgs, argTypes, defaultArgs=[], argCountOffset=0): """Argument checking tool. checks raw arg type and number, one level deep (does not recurse into list) will supply defaults if missing args after last given and self.defaultArgs defined two arguments required, both lists: args = a list of arguments, of proper python data types argTypes = list of one-level deap types, specified w/ strings 'list', 'num', 'float', 'int', 'str'; see drawer.py one optional args defaultArgs = list of default args to substitute returns: newArgs, ok, msg >>> strongType([[1,2,3]], ['list']) ([[1, 2, 3]], 1, '') >>> strongType([.5, 3, 'three'], ['float', 'int', 'str']) ([0.5, 3, 'three'], 1, '') >>> strongType([3.2], ['num', 'num']) ([3.2000...], 0, 'incorrect number of arguments; enter 2 arguments.') >>> strongType([3.2, 5, 6], ['num', 'num']) ([3.2000..., 5, 6], 0, 'too many arguments; enter 2 arguments.') """ argCount = len(argTypes) if len(usrArgs) < argCount: # try to get from defaults if len(defaultArgs) == argCount: # defaults exits (default is 0) for retrieve in defaultArgs[len(usrArgs):]: usrArgs.append(retrieve) # add missing to end #print 'argTools.py: adding default', retrieve, defaultArgs else: # nothing we can do: failure msg = ('incorrect number of arguments; enter %i arguments.' % (argCount + argCountOffset)) # add incase if name offset return usrArgs, 0, msg elif len(usrArgs) > argCount: #print _MOD, len(usrArgs), argCount msg = 'too many arguments; enter %i arguments.' % (argCount + argCountOffset) return usrArgs, 0, msg for pos in range(0, argCount): argTest = usrArgs[pos] # can be [list, num, float, int, str] typeCandidates = argTypes[pos] if not drawer.isList(typeCandidates): typeCandidates = [typeCandidates,] # add to list for type in typeCandidates: if type == 'list' and drawer.isList(argTest): match = 1 break elif type == 'num' and drawer.isNum(argTest): match = 1 break elif type == 'float' and drawer.isFloat(argTest): match = 1 break elif type == 'int' and drawer.isInt(argTest): match = 1 break elif type == 'str' and drawer.isStr(argTest): match = 1 break else: # dont break; need to through other possbilities match = 0 # should covnert types to better strings if match == 0: msg = ('wrong type of data used as an argument. replace %s with a %s argument type.' % (repr(typeset.anyDataToStr(argTest)), # provide 'or' to show that any type in candidate is good drawer.typeListAsStr(typeCandidates, 'or'))) return usrArgs, 0, msg # all good return usrArgs, 1, ''
def findNormalT(pcSet, setMatrix=None): """finds normal form of any pc set and returns forte number as a scTriple data structure, and transposition from normal form pcSet may contain psReals, and as such, need to be converted to ints >>> findNormalT([3,4,5]) ((3, 1, 0), 3) """ if setMatrix == None: # use forte as default setMatrix = FORTE MONADscTuple = (1, 1, 0) # check for bad data if drawer.isStr(pcSet): return None # error, no strings supported here if drawer.isList(pcSet): for psReal in pcSet: # make sure all values are numbers; no strings allowed if drawer.isStr(psReal): return None # break, return None as error # check for unusual data if drawer.isNum(pcSet): # its a single number pcVal = pitchTools.roundMicro(pcSet) # second number is transposition from 0 return MONADscTuple, (pcVal % 12) if len(pcSet) == 1: #filter out monad! pcVal = pitchTools.roundMicro(pcSet[0]) return MONADscTuple, (pcVal % 12) # scrub and go pcSetClone = [] for psReal in pcSet: # pcSet may contian psReal, w/ floating values pcSetClone.append(pitchTools.roundMicro(psReal)) #check fr non base 12 numbers, negative numbers, redundancies pcSetClone = list(pcSetTransposer(pcSetClone, 0)) pcSetClone.sort() i = 0 chord = [] for i in range(0, 12): # remove redundancies if i in pcSetClone: chord.append(i) card = len(chord) if card < 1: # monad has already been filtered out return None # 2nd no is transposition from 0 if card == 1: # this is a set like (3,3,3,3) return MONADscTuple, (pcSet[0] % 12) elif card > 12: return None # 'irrational cardinality error' rotIndices = list(range(0, card)) foundIndex = None #control variable for rot in rotIndices: r = rot # dont need to add 1? + 1 rotSet = chord[r:card] + chord[0:r] dif = rotSet[0] pSet = pcSetTransposer(rotSet, -dif) iSet = tuple(pcInverter(pSet)) maxRange = len(setMatrix[card]) # check all sets of given card for match for index in range(1, maxRange): # start with 1, not zero # this is a default; may be a symmetrical set and have no inversion foundInv = 'A' # test each set in this cardinality; "0" gets pitches testSet = tuple(setMatrix[card][index][0]) if iSet == testSet: foundIndex = index foundInv = 'B' #nt sure yet if 1 or 0 break elif pSet == testSet: foundIndex = index foundInv = 'A' #nt sure yet if 1 or 0 break if foundIndex != None: break if foundIndex == None: ## no set found return None #'failed!!!' if foundInv == 'B': # has inversion that is non-redundant (variant) if setMatrix[card][foundIndex][2][1] == 0: scInv = -1 else: scInv = 0 elif foundInv == 'A': # has inversion that is non-redundant (variant) if setMatrix[card][foundIndex][2][1] == 0: scInv = 1 else: scInv = 0 return (card, foundIndex, scInv), dif
def extractNeighbors(pitchGroup, baseNote, scales=None): """takes a set, or a whole path, and derives a pc scale, a pitch space scale, and provides the upper and lower note to baseNote baseNote should be represented in the pitch group we need to know our current reference position in the pitchGroup pitchGroup has pitch pre-temperament; thus baseNote should be pre-temperament may be a psReal pitchGroup: from a refDict, containing stateCurrentChord, or statePathList will be a list of raw psReal values: could be floats, and could have micro specification """ # if scales given and no pitchGroup is given if scales != None and pitchGroup == None: colPitchSpace = scales[0] colPitchClass = scales[1] else: # given a set or path as pitchGroup if drawer.isNum(pitchGroup[0]): pitchGroup = [pitchGroup, ] # make all look like paths colPitchSpace = [] colPitchClass = [] for set in pitchGroup: for entry in set: if entry not in colPitchSpace: colPitchSpace.append(entry) # round; zero trans gets mod12 entryPC = pitchTools.pcTransposer(entry, 0) if entryPC not in colPitchClass: colPitchClass.append(entryPC) colPitchSpace.sort() colPitchClass.sort() scales = colPitchSpace, colPitchClass # use pitch class space to get neighbors # can use pitch space in the future? wrap around is strange octaveAdjust = 0 baseOctMult, basePC = pitchTools.splitOctPs(baseNote) # although baseNote may be a float (already tempered) # basePC seems to need to be an int, as it is used to find # a position in the scale; for this reason it seems like # the path positions value, and not the tempered pitch # should be coming in as the baseNote: tmerperament could cause # a rounding error and pass a pitch that is not in the scale at all #print _MOD, basePC, colPitchClass idx = None try: idx = colPitchClass.index(basePC) except ValueError: # not in the collected pitches; try rounding for i in range(len(colPitchClass)): # compare rounded versions, as floats may not match if round(colPitchClass[i], 2) == round(basePC, 2): idx = i # print _MOD, 'found rounded match' if idx == None: idx = 0 environment.printDebug('no match between base pitch and collected pitches') idxL = idx - 1 # lower neighbor if idxL == -1: # wrap index around idxL = len(colPitchClass) - 1 octaveAdjust = -1 idxU = idx + 1 # upper neighbor if idxU == len(colPitchClass): idxU = 0 octaveAdjust = 1 neighborL = colPitchClass[idxL] if octaveAdjust == -1: neighborL = pitchTools.psTransposer(neighborL, -12) neighborU = colPitchClass[idxU] if octaveAdjust == 1: neighborU = pitchTools.psTransposer(neighborU, 12) # do octave adjust ment relative to baseNote in pitch space neighborL = pitchTools.psTransposer(neighborL, (12 * baseOctMult)) neighborU = pitchTools.psTransposer(neighborU, (12 * baseOctMult)) lowerUpper = neighborL, neighborU return scales, lowerUpper