Files
3d_audio/lib_audio_dsp/test/pipeline/test_thread_crossings.py
Steven Dan d8b2974133 init
2025-12-11 09:43:42 +08:00

147 lines
4.9 KiB
Python

# Copyright 2025 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
from audio_dsp.design.pipeline import Pipeline, generate_dsp_main
from audio_dsp.stages import *
def test_bad_pipelines():
with pytest.raises(RuntimeError) as excinfo:
p, inputs = Pipeline.begin(2, fs=48000)
# inputs[1] is not used on thread 0
x1 = p.stage(Biquad, inputs[0], 'bq1')
p.next_thread()
# inputs[1] first used on thread 1
x = p.stage(Biquad, x1 + inputs[1], 'bq2')
p.set_outputs(x)
assert "must cross the same number of threads" in str(excinfo.value)
def test_good_pipelines():
p, inputs = Pipeline.begin(2, fs=48000)
# both inputs are not used on this thread
x1 = p.stage(Biquad, inputs[0], 'bq1')
x2 = p.stage(Bypass, inputs[1], 'by1')
p.next_thread()
x = p.stage(Biquad, x1 + x2, 'bq2')
p.set_outputs(x)
def test_parallel_pipelines():
p, inputs = Pipeline.begin(2, fs=48000)
x1 = p.stage(Biquad, inputs[0], 'bq1')
p.next_thread()
x2 = p.stage(Bypass, inputs[1], 'by1')
p.next_thread()
# x1 and x2 have both crossed 1 thread already
x = p.stage(Biquad, x1 + x2, 'bq2')
p.set_outputs(x)
def test_good_complex():
# 4 inputs
p, i = Pipeline.begin(4, fs=48000)
mic1 = p.stage(Fork, i[2], count=3).forks
mic2 = p.stage(Fork, i[3], count=3).forks
p.stage(EnvelopeDetectorRMS, mic1[0], "edr1")
p.stage(EnvelopeDetectorRMS, mic2[0], "edr2")
mic_mono = p.stage(Adder, mic1[1] + mic2[1], "adder1")
mic_mono = p.stage(Fork, mic_mono, count=3).forks
mic_dnr = p.stage(NoiseSuppressorExpander, mic_mono[0], "ns")
peq1 = p.stage(CascadedBiquads, mic_dnr, "peq1")
sw_1 = p.stage(SwitchStereo, mic_mono[1] + mic_mono[2] + mic1[2] + mic2[2], "sw_1")
i_bypass = p.stage(Bypass, i[:2])
p.next_thread()
mic_peq = p.stage(Fork, peq1, count=3).forks
peq2 = p.stage(CascadedBiquads, mic_peq[2], "peq2")
mic_rv = p.stage(Fork, peq2).forks
i_bypass = p.stage(Bypass, i_bypass)
sw_1 = p.stage(Bypass, sw_1)
p.next_thread()
mic_rv = p.stage(ReverbPlateStereo, mic_rv[0] + mic_rv[1], "reverb")
cfs1 = p.stage(CrossfaderStereo, mic_peq[0] + mic_peq[1] + mic_rv[0] + mic_rv[1], "cfs1")
rv_sw = p.stage(SwitchStereo, cfs1 + sw_1, "reverb_sw")
vol1 = p.stage(VolumeControl, rv_sw[0], "vol1")
vol2 = p.stage(VolumeControl, rv_sw[1], "vol2")
i_bypass = p.stage(Bypass, i_bypass)
p.next_thread()
usb_play, usb_mon = p.stage(Fork, i_bypass).forks
usb_play = p.stage(VolumeControl, usb_play, "vol3")
mic_play, mic_mon = p.stage(Fork, vol1 + vol2).forks
usb0 = p.stage(Adder, usb_play[0] + mic_play[0], "adder2")
usb1 = p.stage(Adder, usb_play[1] + mic_play[1], "adder3")
cfs2 = p.stage(CrossfaderStereo, usb_mon[0] + usb_mon[1] + mic_mon[0] + mic_mon[1], "cfs2")
mon0, mon1 = p.stage(VolumeControl, cfs2, "vol4")
p.set_outputs(usb0 + usb1 + mon0 + mon1)
def test_bad_complex():
with pytest.raises(RuntimeError) as excinfo:
# 4 inputs
p, i = Pipeline.begin(4, fs=48000)
mic1 = p.stage(Fork, i[2], count=3).forks
mic2 = p.stage(Fork, i[3], count=3).forks
p.stage(EnvelopeDetectorRMS, mic1[0], "edr1")
p.stage(EnvelopeDetectorRMS, mic2[0], "edr2")
mic_mono = p.stage(Adder, mic1[1] + mic2[1], "adder1")
mic_mono = p.stage(Fork, mic_mono, count=3).forks
mic_dnr = p.stage(NoiseSuppressorExpander, mic_mono[0], "ns")
peq1 = p.stage(CascadedBiquads, mic_dnr, "peq1")
sw_1 = p.stage(SwitchStereo, mic_mono[1] + mic_mono[2] + mic1[2] + mic2[2], "sw_1")
p.next_thread()
mic_peq = p.stage(Fork, peq1, count=3).forks
peq2 = p.stage(CascadedBiquads, mic_peq[2], "peq2")
mic_rv = p.stage(Fork, peq2).forks
p.next_thread()
mic_rv = p.stage(ReverbPlateStereo, mic_rv[0] + mic_rv[1], "reverb")
cfs1 = p.stage(CrossfaderStereo, mic_peq[0] + mic_peq[1] + mic_rv[0] + mic_rv[1], "cfs1")
rv_sw = p.stage(SwitchStereo, cfs1 + sw_1, "reverb_sw")
vol1 = p.stage(VolumeControl, rv_sw[0], "vol1")
vol2 = p.stage(VolumeControl, rv_sw[1], "vol2")
p.next_thread()
usb_play, usb_mon = p.stage(Fork, i[:2]).forks
usb_play = p.stage(VolumeControl, usb_play, "vol3")
mic_play, mic_mon = p.stage(Fork, vol1 + vol2).forks
usb0 = p.stage(Adder, usb_play[0] + mic_play[0], "adder2")
usb1 = p.stage(Adder, usb_play[1] + mic_play[1], "adder3")
cfs2 = p.stage(CrossfaderStereo, usb_mon[0] + usb_mon[1] + mic_mon[0] + mic_mon[1], "cfs2")
mon0, mon1 = p.stage(VolumeControl, cfs2, "vol4")
p.set_outputs(usb0 + usb1 + mon0 + mon1)
assert "must cross the same number of threads" in str(excinfo.value)
if __name__ == "__main__":
# test_bad_pipelines()
test_bad_complex()
test_good_complex()