def simplify_line(self, line): ''' line: string returns: list ''' changed = True depth = 0 toks = line.split() try: while changed and depth < sg.max_recursive_depth: changed = False depth += 1 toks, changed = self.group_args(toks, changed) #if sg.debug: sg.trace('changed = %s (toks = %s)' % (changed, toks)) toks, changed = self.simplify_factors(toks, changed) #if sg.debug: sg.trace('changed = %s (toks = %s)' % (changed, toks)) toks, changed = self.simplify_expansions(toks, changed) #if sg.debug: sg.trace('changed = %s (toks = %s)' % (changed, toks)) except Exception as e: return [SilicaEvent('exception', exception=e)] if depth >= sg.max_recursive_depth: e = SilicaInternalError('Infinite loop detected, bailing out.') return [SilicaEvent('exception', exception=e)] #if sg.debug: sg.trace('line: %s' % toks) return toks
def toggledebug(sg, arglist): sg.toggle_debug() if sg.debug: msg = 'Debugging output enabled.' else: msg = 'Debugging output disabled.' return SilicaEvent('meta', message=msg)
def set_tempo(self, value, relative=False): if relative: self.set_tempo(self.tempo + value) else: if value < 20: value = 20 if value > 400: value = 400 self.tempo = value return SilicaEvent('tempo', notestate=self.makestate())
def set_vol(self, value, relative=False): if relative: self.set_vol(self.volume + value) else: if value < 0: value = 0 if value > 16000: value = 16000 self.volume = value return SilicaEvent('volume', notestate=self.makestate())
def rp(self): new = self.degree + 1 if new == len(self.scale[-1]) + 1: new = 1 if self.register < 9: self.register = self.register + 1 self.degree = new self.deltadegree = 'raise' return SilicaEvent('pitch', notestate=self.makestate())
def lp(self): new = self.degree - 1 if new == 0: new = len(self.scale[-1]) if self.register > 0: self.register = self.register - 1 self.degree = new self.deltadegree = 'lower' return SilicaEvent('pitch', notestate=self.makestate())
def define_macro(self, string): # = is syntactic sugar for >> begingroup ... endgroup splitter = '>>' if '=' in string: splitter = '=' vals = string.split(splitter, 1) signature = vals[0].strip() if len(vals) == 2: body = vals[1].strip() if len(body) == 0: ex = SilicaSyntaxError( 'Syntax error in macro definition: macro has no body.') return SilicaEvent('exception', exception=ex) vals = signature.split('(', 1) name = vals[0].strip().upper() if not self.valid_name(name): ex = SilicaNameError('The name %s is invalid in this context.' % name) return SilicaEvent('exception', exception=ex) args = None if len(vals) == 2: arglist = vals[1].strip() if len(arglist) > 0: if arglist[-1] != ')': ex = SilicaSyntaxError( 'Syntax error in macro definition: unbounded arglist.') return SilicaEvent('exception', exception=ex) else: arglist = arglist[:-1] arglist = arglist.split(',') args = [a.strip() for a in arglist] if splitter == '=': body = 'begingroup ' + body + ' endgroup' sg.new_macro(name, body, args) return SilicaEvent('macro_def', message='Macro %s defined.' % name)
def change_scale(self, new_scale, relative=False): if relative: pitch = self.scale[-1].get_name_for_degree(self.degree) new_degree = new_scale.get_degree_for_name(pitch) if new_degree is None: # error! msg = 'Cannot change to scale %s relatively: pitch %s not in scale.' % ( new_scale.name, pitch) error = SilicaAlphabetError(msg) raise error else: self.degree = new_degree self.scale.append(new_scale) else: self.degree = 1 self.scale.append(new_scale) self.deltadegree = 'same' return SilicaEvent('scale', notestate=self.makestate())
def pop_alphabet(self, relative=False): if len(self.scale) == 1: msg = 'Cannot pop alphabet: must leave one in stack.' error = SilicaAlphabetError(msg) raise error if relative: pitch = self.scale[-1].get_name_for_degree(self.degree) new_scale = self.scale[-2] new_degree = new_scale.get_degree_for_name(pitch) if new_degree is None: msg = 'Cannot pop to scale %s relatively: pitch %s not in scale.' % ( new_scale.name, pitch) error = SilicaAlphabetError(msg) raise error self.scale.pop() self.degree = new_degree else: self.scale.pop() self.degree = 1 self.deltadegree = 'same' return SilicaEvent('scale', notestate=self.makestate())
def play(self): se = SilicaEvent('play', notestate=self.makestate()) self.prevregister = self.register self.deltadegree = 'same' return se
def shrink(self, factor): self.duration /= factor return SilicaEvent('duration', notestate=self.makestate())
def parse_line(self, string, reset=True): if reset: self.reset_parsing_state() #@+<< metacommand mode >> #@+node:peckj.20140318084140.4613: *4* << metacommand mode >> if string.startswith('-'): self.mcmode = True #@-<< metacommand mode >> self.notestate = sg.note.makestate( ) # to recover from errors without affecting note.statestack #@+<< macro definition >> #@+node:peckj.20140318084140.4611: *4* << macro definition >> if '>>' in string or '=' in string: # define macro! event = self.define_macro(string) return [event] #@-<< macro definition >> #@+<< mode definition >> #@+node:peckj.20140318084140.4612: *4* << mode definition >> if '!!' in string: ## STUB # define mode! return [] #@-<< mode definition >> #@+<< auto invariance mode >> #@+node:peckj.20140318084140.4614: *4* << auto invariance mode >> if sg.auto_invariance: string = ' '.join(['pushstate', string, 'popstate']) #@-<< auto invariance mode >> toks = self.simplify_line(string) if len(toks) == 1 and type(toks[0]) is SilicaEvent: return toks out = [] #@+<< interpret tokens >> #@+node:peckj.20140318084140.4615: *4* << interpret tokens >> for tok in toks: #if sg.debug: print tok # should all be primitives + metacommands by now... try: element, etype = sg.get_token(tok) #if sg.debug: print (element, etype) if element is not None and etype is not None: v = self.fn_table[etype](element) if v is not None: # v may be a list, in which case, append them all separately if hasattr(v, '__iter__') and not isinstance( v, basestring): for e in v: out.append(e) else: out.append(v) else: raise SilicaInternalError( 'No fn_table type defined in parser for type %s' % etype) else: raise SilicaNameError( 'No token named %s exists in the current namespace' % tok) except Exception as e: sg.note.applystate( self.notestate ) # exception occurred, the notestate must be reset return [SilicaEvent('exception', exception=e)] # only return the exception! #@-<< interpret tokens >> #@+<< groups balanced >> #@+node:peckj.20140318084140.4616: *4* << groups balanced >> if self.groups_are_balanced(out): return out else: e = SilicaGroupError('Groups are unbalanced.') sg.note.applystate(self.notestate) return [SilicaEvent('exception', exception=e)] #@-<< groups balanced >> return out
def endgroup(self): return SilicaEvent('endgroup', notestate=self.makestate())
def begingroup(self): return SilicaEvent('begingroup', notestate=self.makestate())
def popstate(self): if len(self.statestack) > 0: self.applystate(self.statestack.pop()) return SilicaEvent('pushstate', notestate=self.makestate())
def pushstate(self): state = self.makestate() self.statestack.append(state) return SilicaEvent('pushstate', notestate=state)
def rest(self): return SilicaEvent('rest', notestate=self.makestate())
def expand(self, factor): self.duration *= factor return SilicaEvent('duration', notestate=self.makestate())
def change_instrument(self, instrument): self.instrument = instrument return SilicaEvent('instrument', notestate=self.makestate())