import math TAU = 2 * math.pi class SoundNode: def __init__(self, name, room): self.name = name self.room = room self.room.nodes.append(self) self.r_amps = dict() # {tick: {freq: r_amp}} self.air_in = [] self.wire_in = [] self.start_location = (0, 0, 0) # Used by the tick cycle to correctly order the nodes. # Do not touch this. self.tick_done = False def distance_to_node(self, other_node, t): loc = self.location(t) other_loc = other_node.location(t) if (loc, other_loc) in self.room.dist_cache: return self.room.dist_cache[(loc, other_loc)] if (other_loc, loc) in self.room.dist_cache: return self.room.dist_cache[(other_loc, loc)] diff_x = loc[0]-other_loc[0] diff_y = loc[1]-other_loc[1] diff_z = loc[2]-other_loc[2] dist = diff_x*diff_x + diff_y*diff_y + diff_z * diff_z self.room.dist_cache[(loc, other_loc)] = dist return dist return (loc[0]-other_loc[0])**2 + (loc[1]-other_loc[1])**2 + (loc[2]-other_loc[2])**2 def sample_r_amps_by_wire(self, source_node, current_t): if current_t in source_node.r_amps: return source_node.r_amps[current_t] return dict() def sample_r_amps_by_air(self, source_node, current_t): dist = self.distance_to_node(source_node, current_t) #sample_t = current_t - int(dist / self.room.speed_of_sound) sample_t = current_t - int(128.571428 * dist) if sample_t in source_node.r_amps: attenuation = math.exp(-(dist/100.0)) return {f: a * attenuation for f, a in source_node.r_amps[sample_t].items()} return dict() def air_to(self, out_node): if not self in out_node.air_in: out_node.air_in.append(self) def wire_to(self, out_node): if not self in out_node.wire_in: out_node.wire_in.append(self) ## THE FOLLOWING FUNCTIONS NEED TO BE DEFINED BY CONCRETE NODES def location(self, t): # Location of the soundnote (x,y,z) in meters # at time t. return self.start_location def calc_r_amps(self, t): # Fill the amp_cache for tick t # {freq: relative_amp} # relative_amp must be between 0 and 1 self.r_amps[t] = dict()