from sonnum import Sonnum from activity import Activity from instruction import * class SonnumCompiler: def __init__(self): self.sonnum = Sonnum() # {order: name} self.activities = [] def list_activities(self): print('ACTIVITY LISTING') for activity in self.activities: print(activity) def list_bytecode(self): print('BYTECODE LISTING') for activity in self.activities: print(list(activity.to_bytes())) def add_activity(self, name, tick_start, tick_end, src_node, trg_node, operands): a = Activity(self.sonnum, name, tick_start, tick_end, src_node, trg_node, operands) self.activities.append(a) def sanitize_operand(self, operand): try: return str(float(operand)) except: return str(operand) def transpile_snm_to_py(self, snm_src): py_src = [] for ln in snm_src.split('\n'): tablevel = 0 while ln.startswith('\t'): tablevel += 1 ln = ln[1:] if ln.startswith(';'): if ln.endswith('*'): name = ln[1:-1] ln = f"i_create_simple(self, self.sonnum, '{name}')" elif ln.endswith('!'): ticklen = int(ln[1:-1]) ln = f"i_end_tick(self, self.sonnum, {ticklen})" elif ln.endswith('@'): name = ln[1:-1] ln = f"i_create_relay(self, self.sonnum, '{name}')" elif '=>' in ln: name_src, name_trg = ln[1:].split('=>') ln = f"i_wire(self, self.sonnum, '{name_src}', '{name_trg}')" elif '->' in ln: name_src, name_trg = ln[1:].split('->') ln = f"i_air(self, self.sonnum, '{name_src}', '{name_trg}')" else: print(ln) lst = ln[1:].split(' ') src_node_name = lst.pop(0) instr = lst.pop(0) operands = [self.sanitize_operand(op) for op in lst] ln = f"i_{instr}(self, self.sonnum, '{src_node_name}', "+', '.join(operands)+")" ln = tablevel*'\t' + ln py_src.append(ln) else: ln = tablevel*'\t' + ln py_src.append(ln) return '\n'.join(py_src) def run_transpiled_code(self, py_src): exec(py_src) def sort_activities(self): new = [] to_delete = [] for activity in self.activities: if activity.name == 'endtick': new.append(activity) to_delete.append(activity) for activity in to_delete: self.activities.remove(activity) to_delete = [] for activity in self.activities: if activity.name == 'create': new.append(activity) to_delete.append(activity) for activity in to_delete: self.activities.remove(activity) to_delete = [] for activity in self.activities: if activity.name in ('wire','air'): new.append(activity) to_delete.append(activity) for activity in to_delete: self.activities.remove(activity) self.activities.sort(key=lambda x: x.tick_start, reverse = False) new.extend(self.activities) self.activities = new def compile_to_smnb(self, snm_src, fn): py_src = self.transpile_snm_to_py(snm_src) self.run_transpiled_code(py_src) self.sort_activities() self.list_activities() bytecode = [] for activity in self.activities: bytecode.append(activity.to_bytes()) with open(fn, 'wb') as fl: fl.write(b''.join(bytecode)) TEST = """;44100! ;left_mic@ ;right_mic@ ;synth* ;synth setfreq 0 440 0.9 ;synth=>left_mic ;synth=>right_mic""" C = SonnumCompiler() snm = C.compile_to_smnb(TEST, '../zigsonnum/test.snmb')