133 lines
No EOL
2.7 KiB
Python
133 lines
No EOL
2.7 KiB
Python
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 |