Python实现两个独立进程输出同步:3D音频模拟器参数对齐问题
解答
你现在的输出错位主要来自三个核心问题:
compute_cutoff逻辑有问题:哪怕没有新的声源位置输入,每秒都会把当前的cutoff值塞入输出队列,导致cutoff队列的产出速度远高于HRIR队列,两个队列的元素从数量上就不对等,自然没法一一对应。- 两个子进程的计算耗时可能存在差异,没有对齐机制的情况下,先完成的结果会先出队列,自然会出现错位。
- 没有给每个声源位置的计算任务加唯一标识,主进程拿到结果后也没法验证两个结果是不是对应同一个声源位置。
改造方案
1. 给每个任务加唯一序列ID
所有声源位置入队的时候附带一个自增的ID,子进程计算完把ID和结果一起返回,方便主进程配对。
2. 修复compute_cutoff的输出逻辑
只有当处理了新的声源位置、生成了新的cutoff值时才往输出队列放结果,不要空塞旧值。
3. 主进程侧加结果配对逻辑
用两个字典暂存还没配对的HRIR和cutoff结果,只有同一个ID的两个结果都就绪时,才取出做后续DSP处理。
4. 优化障碍物位置入队逻辑
你现在的代码每次循环都重复入队相同的障碍物位置,会导致子进程反复做无意义的更新,只有当障碍物位置变化时再入队即可。
改造后完整代码
import time import numpy as np from classes.convolutioner import Convolutioner import librosa from classes.HRIR_interpreter_min_phase_linear_interpolation import HRIR_interpreter_min_phase_linear_interpolation from classes.object_renderer import ObjectRenderer import multiprocessing from multiprocessing import Queue def compute_hrir(queue_source_position, queue_computed_hrirs): print('computing hrir') SOFA_filename = '../HRTF_data/HUTUBS_min_phase.sofa' HRIRInterpreter = HRIR_interpreter_min_phase_linear_interpolation(SOFA_filename=SOFA_filename) while True: time.sleep(1) if not queue_source_position.empty(): # 取出带ID的位置数据 seq_id, position = queue_source_position.get() required_IR = HRIRInterpreter.get_interpolated_IR(position[0], position[1], 1) # 返回ID+结果 queue_computed_hrirs.put((seq_id, required_IR)) def compute_cutoff(queue_source_position, queue_object_position, queue_computed_cutoff): print('computing cutoff') cutoff = 20000 object_renderer = ObjectRenderer() while True: time.sleep(1) # 先处理障碍物位置更新 if not queue_object_position.empty(): object_positions = queue_object_position.get() object_renderer.update_object_position(object_positions) # 只有有新的声源位置时才计算并输出结果 if not queue_source_position.empty(): seq_id, source_position = queue_source_position.get() cutoff = object_renderer.get_cutoff(azimuth=source_position[0], elevation=source_position[1]) # 仅计算完新值后再入队,附带ID queue_computed_cutoff.put((seq_id, cutoff)) if __name__ == '__main__': i = 0 source_position = np.zeros(2) current_cutoff = 0 object_positions = np.array([(20, 0), (40, 0), (180, 0), (225, 0)]) queue_source_position_hrir_calculator = Queue() queue_source_position_cutoff_calculator = Queue() queue_object_position = Queue() queue_computed_hrirs = Queue() queue_computed_cutoff = Queue() # 预存入带ID的声源位置 while (i < 100): # 序列号和位置一起入队,注意要copy数组,避免后续修改影响已入队的值 queue_source_position_hrir_calculator.put((i, source_position.copy())) queue_source_position_cutoff_calculator.put((i, source_position.copy())) source_position[0] = source_position[0] + 10 i = i + 1 # 障碍物位置仅入队一次,后续有更新再追加即可 queue_object_position.put(object_positions) p1 = multiprocessing.Process(target=compute_hrir, args = (queue_source_position_hrir_calculator,queue_computed_hrirs)) p2 = multiprocessing.Process(target=compute_cutoff, args=(queue_source_position_cutoff_calculator, queue_object_position, queue_computed_cutoff)) p1.start() p2.start() # 暂存未配对的结果 pending_hrir = dict() pending_cutoff = dict() # 下一个要处理的序列号,保证按顺序处理 next_seq = 0 while True: # 先把队列里的结果都收到暂存区 while not queue_computed_hrirs.empty(): seq_id, hrir = queue_computed_hrirs.get() pending_hrir[seq_id] = hrir while not queue_computed_cutoff.empty(): seq_id, cutoff = queue_computed_cutoff.get() pending_cutoff[seq_id] = cutoff # 按顺序处理已配对的结果 while next_seq in pending_hrir and next_seq in pending_cutoff: current_hrir = pending_hrir.pop(next_seq) current_cutoff = pending_cutoff.pop(next_seq) print(f'处理序列号{next_seq}的参数,current cutoff:{current_cutoff}') # 此处替换为你的DSP处理逻辑 print('doing stuff with the new values of current_hrir and current_cutoff') next_seq += 1 time.sleep(1)
内容的提问来源于stack exchange,提问作者Mattia Surricchio
相关产品推荐
相关产品推荐

