sonnum/core/room.py
2025-08-09 08:15:49 +03:00

111 lines
No EOL
2.6 KiB
Python

import wave
import math
from .soundnode import *
TAU = 2 * math.pi
def stb(i: int) -> bytes:
return i.to_bytes(3, byteorder='little', signed=True)
class Room:
def __init__(self):
self.dissipation_quotient = 0.9993
self.sample_rate = 44100
self.speed_of_sound = 343 / float(self.sample_rate) #m/tick
self.set_bit_depth(24)
self.lowest_freq = 430
self.highest_freq = 450
self.freq_sample_step = 1
self.producers = []
self.left_sink = SoundNode('LEFT', self)
self.right_sink = SoundNode('RIGHT', self)
self.sine_multiplier = TAU / self.sample_rate
def set_bit_depth(self, bit_depth):
self.bit_depth = bit_depth
self.max_amp = int((2**bit_depth) / 2.0 - 1)
self.min_amp = -int((2**bit_depth) / 2.0)
def link_air(self, node1, node2):
if not node2 in node1.air_out:
node1.air_out.append(node2)
if not node1 in node2.air_in:
node2.air_in.append(node1)
def link_wire(self, node1, node2):
if not node2 in node1.wire_out:
node1.wire_out.append(node2)
if not node1 in node2.wire_in:
node2.wire_in.append(node1)
def record(self, fn, start_t_sec, end_t_sec):
with wave.open(fn, 'wb') as wav:
wav.setnchannels(2)
wav.setsampwidth(int(self.bit_depth / 8.0))
wav.setframerate(self.sample_rate)
frames = []
start_t = start_t_sec * self.sample_rate
end_t = end_t_sec * self.sample_rate
for t in range(start_t, end_t):
#№if t%1000 == 0:
# print(t)
f = self.lowest_freq
left_total_amp = 0
right_total_amp = 0
left_amps = []
right_amps = []
while f < self.highest_freq:
for in_node in self.left_sink.air_in:
left_amps.append(in_node.amp_at_tick_by_air(f, t, self.left_sink))
for in_node in self.left_sink.wire_in:
left_amps.append(in_node.amp_at_tick(f, t))
for in_node in self.right_sink.air_in:
right_amps.append(in_node.amp_at_tick_by_air(f, t, self.right_sink))
for in_node in self.right_sink.wire_in:
right_amps.append(in_node.amp_at_tick(f, t))
f += self.freq_sample_step
left_total_amp = sum(left_amps)
right_total_amp = sum(right_amps)
if left_total_amp > self.max_amp:
left_total_amp = self.max_amp
if left_total_amp < self.min_amp:
left_total_amp = self.min_amp
if right_total_amp > self.max_amp:
right_total_amp = self.max_amp
if right_total_amp < self.min_amp:
right_total_amp = self.min_amp
frames.append(stb(int(left_total_amp)))
frames.append(stb(int(right_total_amp)))
wav.writeframes(b''.join(frames))