Suggestions for creating comb filters

Technical questions regarding the XTC tools and programming with XMOS.
unahm
Junior Member
Posts: 5
Joined: Mon Oct 13, 2025 1:21 pm

Suggestions for creating comb filters

Post by unahm »

Hello,

As part of an effects unit design I would like to implement feed-forward comb filters on the XK-AUDIO-316-MC-AB. Conceptually this is done by mixing a very slightly delayed version of the dry signal with itself to cause the comb filtering effect.

Looking at the python references (https://www.xmos.com/documentation/XM-0 ... html#delay), the 'Delay' effect seems to be appropriate, but I'm confused by the parameters. I couldn't find an example of how it's implemented, so I thought I'd ask here.

Thanks in advance!
Last edited by unahm on Mon Oct 13, 2025 4:23 pm, edited 1 time in total.
unahm
Junior Member
Posts: 5
Joined: Mon Oct 13, 2025 1:21 pm

Post by unahm »

Sorry to bump, but I think the problem I'm having is due to the documentation being different to what is implemented in the AN02014 note. I noticed that 'set_gain' is being deprecated, and to use 'target_gain_db', and a quick test to try this yielded this error in the Jupyter notebook:

AttributeError: 'VolumeControl' object has no attribute 'target_gain_db'

Which version of lib_audio_dsp is consistent with the documentation?
User avatar
Ross
Verified
XCore Legend
Posts: 1289
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

The app note SW download should have the complete codebase with all dependencies so it should all "line up". The changelog will also mention versions of all dependencies. You can also check the manifest.txt file in the SW zip download.
Technical Director @ XMOS. Opinions expressed are my own
unahm
Junior Member
Posts: 5
Joined: Mon Oct 13, 2025 1:21 pm

Post by unahm »

Ah, I see - the app note documentation lines up with the ZIP file. That makes sense, but the lib_audio_dsp unfortunately doesn't, as demonstrated above.

What I've started with is this:

Code: Select all

from audio_dsp.design.pipeline import Pipeline
from audio_dsp.stages import *

# create a DSP pipeline with 16 inputs
pipeline, input_edges = Pipeline.begin(16, fs=48000)

# add stage to the DSP pipeline
#edge_a2u = pipeline.stage(VolumeControl, input_edges[1], "in_to_usb_volume")
guitar_in0 = pipeline.stage(VolumeControl, input_edges[0], "guitar_in0")
guitar_in1 = pipeline.stage(VolumeControl, input_edges[1], "guitar_in1")
guitar_in2 = pipeline.stage(VolumeControl, input_edges[2], "guitar_in2")
guitar_in3 = pipeline.stage(VolumeControl, input_edges[3], "guitar_in3")
guitar_in4 = pipeline.stage(VolumeControl, input_edges[4], "guitar_in4")
guitar_in5 = pipeline.stage(VolumeControl, input_edges[5], "guitar_in5")

guitar_comb0 = pipeline.stage(Delay, guitar_in0, "guitar_comb0")

# set the DSP pipeline outputs
pipeline.set_outputs(guitar_comb0 + guitar_in1 + guitar_in2 + guitar_in3 + guitar_in4 + guitar_in5 + edge_u2a)
pipeline["guitar_in0"].set_gain(-1)
pipeline["guitar_comb0"].set_delay(1024)
pipeline["guitar_in1"].set_gain(-1)
pipeline["guitar_in2"].set_gain(-1)
pipeline["guitar_in3"].set_gain(-1)
pipeline["guitar_in4"].set_gain(-1)
pipeline["guitar_in5"].set_gain(-1)
# set stage defaults
#pipeline["in_to_usb_volume"].set_gain(-1)
pipeline["usb_to_out_volume"].set_gain(-1)

pipeline.draw()
but Jupyter returns this:

Code: Select all

Warning: flat edge between adjacent nodes one of which has a record shape - replace records with HTML-like labels
  Edge deb07dac69c7477ca18b6df0a7a373b2 -> end
Error: lost deb07dac69c7477ca18b6df0a7a373b2 end edge
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:88, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     87 try:
---> 88     proc.check_returncode()
     89 except subprocess.CalledProcessError as e:

File /usr/lib/python3.12/subprocess.py:502, in CompletedProcess.check_returncode(self)
    501 if self.returncode:
--> 502     raise CalledProcessError(self.returncode, self.args, self.stdout,
    503                              self.stderr)

CalledProcessError: Command '[PosixPath('dot'), '-Kdot', '-Tsvg']' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

CalledProcessError                        Traceback (most recent call last)
File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/IPython/core/formatters.py:1036, in MimeBundleFormatter.__call__(self, obj, include, exclude)
   1033     method = get_real_method(obj, self.print_method)
   1035     if method is not None:
-> 1036         return method(include=include, exclude=exclude)
   1037     return None
   1038 else:

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
    110 def _repr_image_svg_xml(self) -> str:
    111     """Return the rendered graph as SVG string."""
--> 112     return self.pipe(format='svg', encoding=SVG_ENCODING)

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/_tools.py:185, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    177     wanted = ', '.join(f'{name}={value!r}'
    178                        for name, value in deprecated.items())
    179     warnings.warn(f'The signature of {func_name} will be reduced'
    180                   f' to {supported_number} positional arg{s_}{qualification}'
    181                   f' {list(supported)}: pass {wanted} as keyword arg{s_}',
    182                   stacklevel=stacklevel,
    183                   category=category)
--> 185 return func(*args, **kwargs)

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=1, ignore_arg='self')
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    146 if encoding is not None:
    147     if codecs.lookup(encoding) is codecs.lookup(self.encoding):
    148         # common case: both stdin and stdout need the same encoding
--> 149         return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
    150     try:
    151         raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
    206 cmd = dot_command.command(engine, format,
    207                           renderer=renderer,
    208                           formatter=formatter,
    209                           neato_no_op=neato_no_op)
    210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    213 return proc.stdout

File ~/XMOS/AN02014_-Integrating-DSP-into-the-XMOS-USB-reference-design-_sw_2_0_1/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:90, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     88     proc.check_returncode()
     89 except subprocess.CalledProcessError as e:
---> 90     raise CalledProcessError(*e.args)
     92 return proc

CalledProcessError: Command '[PosixPath('dot'), '-Kdot', '-Tsvg']' returned non-zero exit status 1. [stderr: 'Warning: flat edge between adjacent nodes one of which has a record shape - replace records with HTML-like labels\n  Edge deb07dac69c7477ca18b6df0a7a373b2 -> end\nError: lost deb07dac69c7477ca18b6df0a7a373b2 end edge\n']
I assume that's an internal error of some sort, but I don't know how to resolve it :)