import os import wave from .room import Room class Program: NOTES_OF_OCTAVE = { 0: ['C', 'B#'], 1: ['C#', 'Db'], 2: ['D'], 3: ['D#', 'Eb'], 4: ['E', 'Fb'], 5: ['F', 'E#'], 6: ['F#', 'Gb'], 7: ['G'], 8: ['G#', 'Ab'], 9: ['A'], 10: ['A#', 'Bb'], 11: ['B', 'Cb'] } def __init__(self, name): self.name = name self.room = Room() self.volume = 0.1 self.actions = [] def reset(self): self.room = Room() def note_to_freq(self, note): note_no = self.note_to_note_no(note) return self.note_no_to_freq(note_no) def note_to_note_no(self, note): octave = int(note[-1]) note = note[:-1] note_no_oct = 1 for note_no_oct, notelst in self.NOTES_OF_OCTAVE.items(): if note in notelst: break corr_note_no_oct = note_no_oct - 8 return corr_note_no_oct + (octave*12) def note_no_to_freq(self, note_no): return 2**((note_no-49) / 12.0) * 440 def st(self, t_sec): # seconds to ticks return self.room.sample_rate * t_sec def generate_frames(self, start_t_sec, end_t_sec): frames = [] start_t = int(start_t_sec * self.room.sample_rate) end_t = int(end_t_sec * self.room.sample_rate) for t in range(start_t, end_t): self.tick(t) left_frame, right_frame = self.room.generate_frame(t) frames.append(left_frame) frames.append(right_frame) return frames def write_frames_to_wavefile(self, frames, fn = 'export.wav'): with wave.open(fn, 'wb') as wav: wav.setnchannels(2) wav.setsampwidth(self.room.sample_width) wav.setframerate(self.room.sample_rate) wav.writeframes(b''.join(frames)) def playback(self, start_t_sec, end_t_sec, fn = 'export.wav'): cmd = f'play -q --volume {self.volume} {fn} trim {start_t_sec} {end_t_sec-start_t_sec}' os.system(cmd) def export(self, start_t_sec, end_t_sec, fn = "export.wav"): frames = self.generate_frames(start_t_sec, end_t_sec) self.write_frames_to_wavefile(frames, fn=fn) def interface(self): print(f'\nRunning program: {self.name}') print(f'[g 10] to generate 10 seconds') print(f'[vol 10] to set playback volume to 10%') print(f'[p 1 5] to play seconds 1 to 5') cmd = '' while cmd != 'q': cmd = input('\n[vol {self.volume*100}%]>> ') if cmd.startswith('g '): end_sec = float(cmd[2:]) self.export(0, end_sec) if cmd.startswith('vol '): vol = float(cmd[4:]) self.volume = vol / 100.0 if cmd.startswith('p'): pp = cmd.split(' ') start_sec = float(pp[1]) end_sec = float(pp[2]) self.playback(start_sec, end_sec) def tick(self, t): for action in self.actions: action.tick(t) # REIMPLEMENT THESE def setup(self): pass