def compute_array(meshpath, src_coord, lis_coord, r, s, micarray): mesh = ps.loadobj(meshpath, os.path.join(os.path.dirname(meshpath), ''), r, s) ctx = ps.Context() ctx.diffuse_count = 20000 ctx.specular_count = 2000 ctx.channel_type = ps.ChannelLayoutType.mono scene = ps.Scene() scene.setMesh(mesh) src = ps.Source(src_coord) src.radius = 0.01 res = {} res_buffer = [] rate = 0 abandon_flag = False for offset in micarray: lis = ps.Listener((offset + lis_coord).tolist()) lis.radius = 0.01 res_ch = scene.computeIR(src, lis, ctx) rate = res_ch['rate'] sa = res_ch['samples'] res['rate'] = rate res_buffer.append(sa) res['samples'] = np.zeros((len(res_buffer), np.max([len(ps) for ps in res_buffer]))) for i, c in enumerate(res_buffer): res['samples'][i, :len(c)] = c return res
def main(): # Simulation using .obj file (and an optional .mtl file) ctx = ps.Context() ctx.diffuse_count = 20000 ctx.specular_count = 2000 ctx.channel_type = ps.ChannelLayoutType.stereo mesh1 = ps.loadobj( "cube.obj", "" ) # if the second argument is empty, the code will infer the .mtl name using .obj name scene = ps.Scene() scene.setMesh(mesh1) src_coord = [1, 1, 0.5] lis_coord = [5, 3, 0.5] src = ps.Source(src_coord) src.radius = 0.01 lis = ps.Listener(lis_coord) lis.radius = 0.01 res = scene.computeMultichannelIR(src, lis, ctx) w = WaveWriter('test1.wav', channels=np.shape(res['samples'])[0], samplerate=int(res['rate'])) w.write(np.array(res['samples'])) print("IR using .obj input written to test1.wav.") # Simulation using a shoebox definition ctx = ps.Context() ctx.diffuse_count = 20000 ctx.specular_count = 2000 ctx.channel_type = ps.ChannelLayoutType.stereo mesh2 = ps.createbox(10, 6, 2, 0.5, 0.5) scene = ps.Scene() scene.setMesh(mesh2) res = scene.computeMultichannelIR(src, lis, ctx) w2 = WaveWriter('test2.wav', channels=np.shape(res['samples'])[0], samplerate=int(res['rate'])) w2.write(np.array(res['samples'])) print("IR using shoebox input written to test2.wav.")
def compute_scene_ir_absorb(roomdim, tasks, r): # Initialize scene mesh try: mesh = ps.createbox(roomdim[0], roomdim[1], roomdim[2], r, 0.5) except Exception as e: print(str(e)) ctx = ps.Context() ctx.diffuse_count = 2000 ctx.specular_count = 2000 ctx.threads_count = min(multiprocessing.cpu_count(), 8) scene = ps.Scene() scene.setMesh(mesh) channel = ps.ChannelLayoutType.mono ctx.channel_type = channel ctx.sample_rate = 16000 status = 0 for task in tasks: src_coord = task[0] lis_coord = task[1] wavname = task[2] cnt = 0 src = ps.Source(src_coord) src.radius = 0.01 lis = ps.Listener(lis_coord) lis.radius = 0.01 # lis.channel_layout_type = ps.ChannelLayoutType.mono a = np.array(src_coord) b = np.array(lis_coord) dist = np.linalg.norm(a - b) direct_idx = int(ctx.sample_rate * dist / 343) res = scene.computeIR(src, lis, ctx) res['samples'] = np.atleast_2d(res['samples']) if (np.argmax(np.fabs(res['samples'])) == 0): status = 1 wavname += '_startzero.wav' elif (np.max(np.fabs(res['samples'])) == 0): status = 2 wavname += '_zeromax.wav' elif (np.isnan(res['samples']).any()): status = 3 wavname += '_nan.wav' return status
def main(): l = 10 w = 6 h = 2 absorb = 0.3 reflec = np.sqrt(1.0 - absorb) ctx = ps.Context() ctx.diffuse_count = 20000 ctx.specular_count = 2000 ctx.channel_type = ps.ChannelLayoutType.mono scene = ps.Scene() mesh = ps.createbox(l, w, h, absorb, 0.5) scene.setMesh(mesh) src_coord = [1, 1, 0.5] lis_coord = [5, 3, 0.5] src = ps.Source(src_coord) src.radius = 0.01 lis = ps.Listener(lis_coord) lis.radius = 0.01 rir_gs = scene.computeIR(src, lis, ctx) rir_img = rg.rir_generator(343, 16000, lis_coord, src_coord, [l, w, h], beta=[reflec] * 6) rir_img = rir_img / max(abs(rir_img[0])) max_cnt = min(len(rir_gs['samples']), len(rir_img[0])) * 2 fig, axs = plt.subplots(4, 1, figsize=(10, 20)) axs[0].set_title('Image Method (waveform)') axs[0].plot(rir_img[0], linewidth=0.5) axs[0].set_xlabel('Sample') axs[0].set_xlim(0, max_cnt) axs[0].set_ylim(-1, 1) axs[0].set_ylabel('Amplitude') axs[1].set_title('Geometric Sound Propagation (waveform)') axs[1].plot(rir_gs['samples'], linewidth=0.5) axs[1].set_xlabel('Sample') axs[1].set_xlim(0, max_cnt) axs[1].set_ylim(-1, 1) axs[1].set_ylabel('Amplitude') axs[2].set_title('Image Method (spectrogram)') axs[2].specgram(rir_img[0], mode='magnitude', NFFT=1024, Fs=16000, noverlap=512) axs[2].set_xlim(0, max_cnt / 16000) axs[2].set_xlabel('Times (s)') axs[2].set_ylabel('Frequency (Hz)') axs[3].set_title('Geometric Sound Propagation (spectrogram)') axs[3].specgram(rir_gs['samples'], mode='magnitude', NFFT=1024, Fs=16000, noverlap=512) axs[3].set_xlim(0, max_cnt / 16000) axs[3].set_xlabel('Times (s)') axs[3].set_ylabel('Frequency (Hz)') fig.tight_layout() plt.savefig('img_comparison.png') plt.show()
def compute_room_irs( room_dim, mic_pos, source_pos, ray_tracing=False, room_properties=0.5, sample_rate=16000, ism_order=None, air_absorption=False, ray_tracing_param=None, scattering=0.5, temperature=None, software=RoomSimSoftware.PYROOMACOUSTICS, ): """ Compute the RIRs between a provided mic position and one or multiple source position(s). Default is to apply Image Source Method (ISM) with order 17. Parameters ---------- room_dim : array or list 3D array, specifying (width, length, height) or a Shoebox room. mic_pos : array or list 3D array specifying coordinates of microphone. source_pos : list of arrays List of coordinates for source positions. ray_tracing : bool Whether to apply ray tracing. room_properties : float or dict, optional If float, average RT60 of the room from which the average absorption is determined using Eyring's equation. If dict, one entry per wall in `WallRegistry` for the corresponding material. sample_rate : int, optional Sample rate in Hz. ism_order : int, optional Number of specular reflections to model with ISM. air_absorption : bool Whether to include air absorption in the simulation. ray_tracing_param : dict, optional Dict of parameters for ray tracing. scattering : float, optional Average scattering coefficient for all surfaces and frequencies. temperature : float, optional Temperature in Celsius. software : str, optional Which simulation software to use. "pyroomacoustics" (default) or "pygsound". """ # check input parameters assert len(room_dim) == 3 assert len(mic_pos) == 3 mic_pos = np.array(mic_pos, ndmin=2).T for _pos in source_pos: assert len(_pos) == 3 # prepare parameters energy_absorption = None scattering_config = { "description": "Flat scattering", "coeffs": [scattering], } if isinstance(room_properties, dict): materials_config = dict() for wall in room_properties: materials_config[wall] = pra.Material( energy_absorption=materials_absorption_table[ room_properties[wall] ], scattering=scattering_config, ) elif isinstance(room_properties, float): energy_absorption = rt60_to_absorption( room_dim=room_dim, rt60=room_properties ) materials_config = pra.Material( energy_absorption=energy_absorption, scattering=scattering_config ) else: raise ValueError( "Invalid `materials`, must be `dict` with an entry" " for each wall or a `float` for an RT60." ) # build room and simulate if software == RoomSimSoftware.PYROOMACOUSTICS: if ism_order is None: ism_order = 17 pyroomacoustics_rt_param = { "n_rays": int(1e5), "receiver_radius": 0.5, "time_thres": 10.0, } if ray_tracing_param is not None: pyroomacoustics_rt_param.update(ray_tracing_param) room = pra.room.ShoeBox( p=room_dim, fs=sample_rate, materials=materials_config, max_order=ism_order, mics=pra.MicrophoneArray(mic_pos, sample_rate), air_absorption=air_absorption, ray_tracing=ray_tracing, temperature=temperature, humidity=0 if temperature is not None else None, ) if ray_tracing: room.set_ray_tracing(**pyroomacoustics_rt_param) # add sources for _source_loc in source_pos: room.add_source(list(_source_loc)) # compute RIRs room.compute_rir() rirs = room.rir[0] elif software == RoomSimSoftware.PYGSOUND: assert energy_absorption is not None assert isinstance( room_properties, float ), "`room_property` must be an RT60 value for `pygsound`" if air_absorption: print("Air absorption not available for `pygsound`.") if ism_order is not None: print("ISM order cannot be set for `pygsound`.") pygsound_param = { "diffuse_count": 20000, "specular_count": 2000, "src_radius": 0.01, "mic_radius": 0.01, } if ray_tracing_param is not None: pygsound_param.update(ray_tracing_param) # simulation variables ctx = ps.Context() ctx.diffuse_count = pygsound_param["diffuse_count"] ctx.specular_count = pygsound_param["specular_count"] if "specular_depth" in pygsound_param: ctx.specular_depth = pygsound_param["specular_depth"] ctx.channel_type = ps.ChannelLayoutType.mono ctx.sample_rate = sample_rate # create ShoeBox room mesh2 = ps.createbox( _width=room_dim[0], _length=room_dim[1], _height=room_dim[2], _absorp=energy_absorption, _scatter=scattering, ) scene = ps.Scene() scene.setMesh(mesh2) # compute RIRs rirs = [] for _pos in source_pos: _rir = pygsound_compute_ir( scene=scene, context=ctx, source_pos=_pos, mic_pos=mic_pos, src_radius=pygsound_param["src_radius"], mic_radius=pygsound_param["mic_radius"], ) rirs.append(_rir) else: raise ValueError("Invalid simulation software.") return rirs, sample_rate