test version; does not work
This commit is contained in:
parent
49d70f9395
commit
b20299ff78
4 changed files with 184 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -29,6 +29,7 @@ testfiles/
|
|||
env/
|
||||
build/
|
||||
osm/env
|
||||
*.wav
|
||||
osm/cache
|
||||
*.jpg
|
||||
*.bin
|
||||
|
|
|
|||
110
core/room.py
Normal file
110
core/room.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import wave
|
||||
import math
|
||||
|
||||
from .soundnode import *
|
||||
|
||||
TAU = 2 * math.pi
|
||||
|
||||
def stb(i: int) -> bytes:
|
||||
return i.to_bytes(3, byteorder='big', signed=True)
|
||||
|
||||
class Room:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.speed_of_sound = 330 #m/s
|
||||
self.dissipation_quotient = 0.9993
|
||||
self.sample_rate = 44100
|
||||
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)
|
||||
|
||||
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.setsampwidth(3)
|
||||
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))
|
||||
45
core/soundnode.py
Normal file
45
core/soundnode.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import math
|
||||
TAU = 2 * math.pi
|
||||
|
||||
class SoundNode:
|
||||
|
||||
def __init__(self, name, room):
|
||||
|
||||
self.name = name
|
||||
self.room = room
|
||||
|
||||
self.air_in = []
|
||||
self.air_out = []
|
||||
self.wire_in = []
|
||||
self.wire_out = []
|
||||
|
||||
self.start_location = (0, 0, 0)
|
||||
|
||||
def location(self, t):
|
||||
|
||||
# Location of the soundnote (x,y,z) in meters
|
||||
# at time t.
|
||||
|
||||
return self.start_location
|
||||
|
||||
def distance_to_node(self, other_node, t):
|
||||
|
||||
loc = self.location(t)
|
||||
other_loc = other_node.location(t)
|
||||
|
||||
return (loc[0]-other_loc[0])**2 + (loc[1]-other_loc[1])**2 + (loc[2]-other_loc[2])**2
|
||||
|
||||
def frequency_max_rel_amp(self, f, t):
|
||||
return 0
|
||||
|
||||
def amp_at_tick(self, f, t):
|
||||
|
||||
return self.room.max_amp * self.frequency_max_rel_amp(f, t) * math.sin(TAU * f * t/float(self.room.sample_rate))
|
||||
|
||||
def amp_at_tick_by_air(self, f, t, node):
|
||||
|
||||
dist = self.distance_to_node(node, t)
|
||||
t = t - ((self.room.speed_of_sound*dist)/float(self.room.sample_rate))
|
||||
|
||||
return self.room.max_amp * self.frequency_max_rel_amp(f, t) * math.sin(TAU * f * t/float(self.room.sample_rate))
|
||||
|
||||
28
test.py
Normal file
28
test.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
from core.room import Room
|
||||
from core.soundnode import SoundNode
|
||||
|
||||
R = Room()
|
||||
R.left_sink.start_location = (-1, 0, 0)
|
||||
R.right_sink.start_location = (2, 0, 0)
|
||||
|
||||
class SineNode(SoundNode):
|
||||
|
||||
def __init__(self, freq, room):
|
||||
|
||||
super().__init__("sine", room)
|
||||
self.freq = freq
|
||||
self.volume = 0.8
|
||||
|
||||
def frequency_max_rel_amp(self, f, t):
|
||||
|
||||
if f == self.freq:
|
||||
return self.volume
|
||||
|
||||
return 0
|
||||
|
||||
sn = SineNode(440, R)
|
||||
|
||||
R.link_wire(sn, R.left_sink)
|
||||
R.link_wire(sn, R.right_sink)
|
||||
|
||||
R.record('test5.wav', 0, 2)
|
||||
Loading…
Add table
Reference in a new issue