FOSDEM - BrixIT BlogPosts related to the development of the FOSDEM hardwarehttps://blog.brixit.nl/tag/fosdem/page/1Tue, 11 Mar 2025 14:25:08 -000060After-FOSDEM videobox updateshttps://blog.brixit.nl/after-fosdem-videobox-updates/110ElectronicsMartijn BraamMon, 10 Mar 2025 02:30:20 -0000<p>The FOSDEM video capture box is a custom device for doing all the in-room stuff for the live-streams of the event. It contains a Radxa x4 SBC, a digital audio mixer, an HDMI capture card, some USB chargers and a network switch. Every room that is livestreamed has two of these boxes, one in front that captures the audio and the HDMI signal for the projector. The other box is in the back of the room hooked up to the camera.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1741569207/box-base-ethaf.png" class="kg-image"><figcaption>Wiring diagram for the box internals</figcaption></figure> <p>The network switch is the <a href="https://blog.brixit.nl/making-a-linux-managed-network-switch/">managed network switch </a>I've written about before, but instead of being hooked up to an ARM computer and using the DSA system in Linux to make it appear native it's mostly unmanaged here. There is connectivity between the switch and the radxa only for some basic monitoring.</p> <p>The audio mixer here is also the <a href="https://blog.brixit.nl/digital-audio-mixer-pt-2/">digital audio mixer design</a> I've written about before. It's handling the audio input from the wireless microphones used at FOSDEM and it sends out the audio to the XLR inputs on the camera used for recording.</p> <p>The power board is another custom designed board by Dexter, it takes 12V from the wall and provides the power for all the internal components, it also provides 4 USB charging ports in the front which are electrically isolated from the rest of the system to have the wireless receivers plugged into the chargers without creating ground loops. This boards also has a few auxilary functions like controlling the fans in the box.</p> <p>A talk has also been given about this hardware at FOSDEM itself (at the end of the event after we were sure everything was working smoothly) and is watchable at <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6832-fosdem-videobox-2025/">https://fosdem.org/2025/schedule/event/fosdem-2025-6832-fosdem-videobox-2025/</a>.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1741573626/image.png" class="kg-image"></figure> <p>To add a bit of irony to the situation this talk about fixing audio quality issues at FOSDEM has bad audio because we decided at the last moment to plug in a spare wireless mic into the system to have mic handoffs and had the gain of the receiver set higher than the box volume could be adjusted.</p> <h2>Next up after FOSDEM</h2> <p>The hardware worked great during the event and now the pressure of having it work at all is gone some extra time has been spend on fixing up issues in the design.</p> <p>One of the more annoying things about the box is that you can hear it in the recordings and in the rooms because the fans are too loud. This is a combination of various design tradeoffs. The first is that the fans are hooked up to an EMC2305 fan controller chip. This chip is also used in a few computers as the internal fan controller. Sadly the automatic control functionality of this chip simply doesn't work (and we checked the Linux kernel driver for it, it also doesn't use the automatic functions). In this design it's only used to read the tachometer signals of the fans and output the PWM signal for the fans.</p> <p>The second issue is that the fans don't have a PWM input so the fan control is done by applying the PWM signal to the power input. Due to this control mechanic and the limitation that the PWM of the fan controller chip has only 8 bit resolution the usable range of control for the fan is reduced to ~6 levels where there's measureable difference in the fan speed, and the only real levels there are off, slow and 4 levels of way too loud.</p> <p>The firmware that ran at FOSDEM had a control loop on the fans that measured the fan RPM and adjusted the PWM signal to keep the fan speed at a preset PWM which due to the limited control resolution just meant the system occasionally started oscillating and the fan speed was ramped up a lot due to the anti-stall mechanism.</p> <p>This has now been replaced by a far simpler control loop that only allows setting "off, low and fast" so it matches reality and not use any tachometer feedback to control this but instead only use that for stall detection.</p> <h2>Audio firmware changes</h2> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1741573087/20250113_0006.jpg" class="kg-image"></figure> <p>The audio mixer at fosdem did not use the USB audio path at all, the audio signals were mixed and then the analog XLR outputs were used to send the audio to the speakers in the room if available, and to the audio input of the camera so the audio is embedded into the HDMI signal that is captured. This is mainly to maintain sync between audio and video through the system. The firmware running at FOSDEM had stability issues when using the USB soundcard functionality of the box which luckily wasn't needed.</p> <p>But these boxes are not only used at FOSDEM, it would be a shame to make custom hardware that is only used 2 days per year. The boxes are loaned out to other conferences to try it out and one of those conferences is FOSSASIA in Bankok. On this conference there is no HDMI camera used for the capture in the rear of the room but instead it's using a webcam, and webcams don't have inputs for audio input. After figuring out that it was the patches to run the Teensy audio board at 48KHz sampling rate instead of 44.1KHz it was decided that those patches should just be ripped out. So far the firmware has been stable with these changes.</p> <h2>VLAN support for the network switch</h2> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1741573105/20250113_0014.jpg" class="kg-image"></figure> <p>The network switch in the box has performed perfectly during the FOSDEM event but none of the fancy features of the switch chip were used. The main thing that was done was reading out the port status so it can be shown on the display on the front of the box.</p> <p>For more flexibility it would be nice to give this more managed switch functions, one of the main things being VLAN support. The basic functionality for the switch is very easy since you just supply the chip with power and it starts switching, figuring out how to control the chip itself is way harder. There's not nearly enough public information available on programming the RTL8367S, the datasheet only covers the registers for port status that I've been using.</p> <p>Using a lot of puzzling and reverse engineering I've figured out how to load a VLAN config into the chip. This is mainly based around bits of info available from other realtek switch chips and some bits of leaked SDK code for similar chips. This means there's now some extra APIs available in the rp2040 code that controls the switch in the box for setting up a static vlan configuration on boot:</p> <div class="highlight"><pre><span></span><span class="c1">// Set the MemberConfig for all ports to 0 and enable tag handling on the ports</span> <span class="n">nsw_vlan_init</span><span class="p">();</span> <span class="c1">// Enable the VLAN processing in the switch</span> <span class="n">nsw_config_vlans</span><span class="p">(</span><span class="nb">true</span><span class="p">);</span> <span class="c1">// Create a VLAN table entry for VLAN 10 with port 1, 2 and 3 as members</span> <span class="c1">// Port 2 and 3 will be untagged on egress</span> <span class="n">nsw_vlan_cfg_t</span><span class="w"> </span><span class="n">vlan10</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="p">.</span><span class="n">vid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span> <span class="w"> </span><span class="p">.</span><span class="n">mbr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BIT</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BIT</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BIT</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="w"> </span><span class="p">.</span><span class="n">untag</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BIT</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BIT</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="p">};</span> <span class="n">nsw_vlan_set</span><span class="p">(</span><span class="o">&amp;</span><span class="n">vlan10</span><span class="p">);</span> <span class="c1">// Create a MemberConfig row to ingress untagged traffic on port 2 and 3</span> <span class="c1">// Use MemberConfig index 1 and vlan 10</span> <span class="n">nsw_mc_set</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="n">BIT</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BIT</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span> <span class="c1">// Point the two untagged ports to MemberConfig index 1. This needs to</span> <span class="c1">// happen _after_ setting the ports as member in the MemberConfig itself</span> <span class="n">nsw_port_set_mc</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span> <span class="n">nsw_port_set_mc</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">);</span> <span class="c1">// Set the untagged ports to drop traffic with a vlan tag set</span> <span class="n">nsw_port_vlan_filtering</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">PORT_ACCEPT_UNTAGGED_ONLY</span><span class="p">);</span> <span class="n">nsw_port_vlan_filtering</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">PORT_ACCEPT_UNTAGGED_ONLY</span><span class="p">);</span> <span class="c1">// Drop untagged traffic from the trunk port</span> <span class="n">nsw_port_vlan_filtering</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">PORT_ACCEPT_TAGGED_ONLY</span><span class="p">);</span> </pre></div> <p>There's also half an implementation for reading port statistics. The switch provides the standard port statistics MIB block, I just need to figure out the final bits for mapping the MIB numbers to the right address in memory.</p> <p>The current port status information that's read out of the PHY registers of the switch are equivalent of the data in the <code>ethtool eth0</code> command, the MIB registers contain the information presented in the <code>ethtool -S eth0</code> command. This would great to produce some pretty Grafana charts.</p> <h2>Hardware improvements</h2> <p>The audio board performed decently given the constraints of the FOSDEM environment and the hardware plugged into it, but I'd like it to be a bit more flexible. The XLR inputs right now are designed to accept -10dBu consumer line level signals. Plugging in a cheap microphone doesn't really work since the board does not have enough gain available to crank up the levels in hardware and is also too noisy to just boost the levels in software. It is also possible to clip the inputs using the AVX wireless systems used at FOSDEM which also isn't ideal.</p> <p>The reason for the small dynamic range of the inputs is for the FOSDEM constraints the simplest and most reliable solution was to make an analog frontend that works from the 5V usb power directly and is tweaked line level signals. The initial version of the board had switching regulators on it to produce +12V and -12V power rails for the analog inputs and the filtering for these inputs was not enough. To make some more HiFi inputs I'm now working on some prototypes of better power supplies and have some new designs around better ADCs and better analog frontends.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1741572724/image.png" class="kg-image"><figcaption>Power supply 2.0 test board</figcaption></figure> <p>This design of the power supply reverts back to the original switching regulator but now uses the filtering circuitry used with the 5V powered analog inputs of the FOSDEM hardware to hopefully produce a less noisy signal. The redesign for audio input also replaces the integrated TI codec which has a lot of issues with a dedicated ADC and DAC chip, one of the major improvements here is that the inputs of these ADC chips is already balanced so the board doesn't have any unbalanced audio signals on it anymore.</p> <p>One of the main things that needs figuring out is how to have cheap software control of the input gain, for using cheap wired microphones it would be needed to boost the signal levels <i>a lot</i>, somewhere between 40 and 60 dB of extra gain without too much noise added. There are easy solutions for this, but the easy solutions are never cheap, especially considering you need a copy of the circuit for every input channel.</p> <p>Having some better input circuitry would make the FOSS digital audio mixer a lot more widely usable, there's many situations where I really would've used a small audio mixer to do some simple routing.</p> <h3>See also</h3> <p>Want to read more about the FOSDEM hardware? Other video team members have also written some blog posts about other details:</p> <p><a href="https://blog.ubii.me/2025/02/13/fosdem-mixers/">https://blog.ubii.me/2025/02/13/fosdem-mixers/</a></p> <p><a href="https://vasil.ludost.net/blog/?p=3494">https://vasil.ludost.net/blog/?p=3494</a></p> <p></p> Making a Linux-managed network switchhttps://blog.brixit.nl/making-a-linux-managed-network-switch/102LinuxMartijn BraamWed, 03 Jul 2024 14:10:04 -0000<p>Network switches are simple devices, packets go in, packets go out. Luckily people have figured out how to make it complicated instead and invented managed switches.</p> <p>Usually this is done by adding a web-interface for configuring the settings and see things like port status. If you have more expensive switches then you'd even get access to some alternate interfaces like telnet and serial console ports.</p> <p>There is a whole second category of managed switches though that people don't initially think of. These are the network switches that are inside consumer routers. These routers are little Linux devices that have a switch chip inside of them, one or more ports are internally connected to the CPU and the rest are on the outside as physical ports.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1719959978/RB2011UiAS-160620170256_160656.png" class="kg-image"><figcaption>Mikrotik RB2011 block diagram from mikrotik.com</figcaption></figure> <p>Here is an example of such a device that actually has this documented. I always thought that the configuration of these switch connected ports was just a nice abstraction by the webinterface but I was suprised to learn that with the DSA and switchdev subsystem in Linux these ports are actually fully functioning "local" network ports. Due to this practically only being available inside integrated routers It's pretty hard to play around with unfortunately.</p> <p>What is shown as a single line on this diagram is actually the connection of the SoC of the router and the switch over the SGMII bus (or maybe RGMII in this case) and a management bus that's either SMI or MDIO. Network switches have a lot of these fun acronyms that even with the full name written out make little sense unless you know how all of this fits together.</p> <p>Controlling your standard off-the-shelf switch using this system simply isn't possible because the required connections of the switch chip aren't exposed for this. So there's only one option left...</p> <h2>Making my own gigabit network switch</h2> <p>Making my own network switch can't be <i>that</i> hard right? Those things are available for the price of a cup of coffee and are most likely highly integrated to reach that price point. Since I don't see any homemade switches around on the internet I guess the chips for those must be pretty hard to get...</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1719960715/image.png" class="kg-image"></figure> <p>Nope, very easy to get. There's even a datasheet available for these. So I created a new KiCad project and started creating some footprints and symbols.</p> <p>I'm glad there's any amount of datasheet available for this chip since that's not usually the case for Realtek devices, but it's still pretty minimal. I resorted to finding any devices that has schematics available for similar Realtek chips to find out how to integrate it and looking at a lot of documentation for how to implement ethernet in a design at all.</p> <p>The implementation for the chip initially looked very complicated, there's about 7 different power nets it requires and there are several pretty badly documented communication interfaces. After going through other implementations it seem like the easiest way to power it is just connect all the nets with overlapping voltage ranges together and you're left with only needing a 3.3V and 1.1V regulator.</p> <p>The extra communication busses are for all the extra ports I don't seem to need. The switch chip I selected is the RTL8367S which is a very widely used 5-port gigabit switch chip, but it's actually not a 5-port chip. It's a 7 port switch chip where 5 ports have an integrated PHY and two are for CPU connections.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1719961532/image.png" class="kg-image"><figcaption>CPU connection block diagram from the RTL8367S datasheet</figcaption></figure> <p>My plan is different though, while there are these CPU ports available there is actually nothing in the Linux switchdev subsystem that requires the CPU connection to be to those ports. Instead I'll be connecting to port 0 on the switch with a network cable and as far as the switchdev driver knows there's no ethernet PHY in between.</p> <p>The next hurdle is the configuration of the switch chip, there's several configuration systems available and the datasheet does not really describe what is the minimum required setup to actually get it to function as a regular dumb switch. To sum up the configuration options of the chip:</p> <ul><li>There&#x27;s 8 pins on the chip that are read when it&#x27;s starting up. These pins are shared with the led pins for the ports so that makes designing pretty annoying. Switching the setting from pull-up to pull-down also requires the led to be connected in the different orientation.</li> <li>There&#x27;s an i2c bus that can be connected to an eeprom chip. The pins for this are shared with the SMI bus that I require to make this chip talk to Linux though. There is pin configuration to select from one of two eeprom size ranges but does not further specify what this setting actually changes.</li> <li>There&#x27;s a SPI bus that supports connecting a NOR flash chip to it. This can store either configuration registers or firmware for the embedded 8051 core depending on the configuration of the bootup pins. The SPI bus pins are also shared with one of the CPU network ports.</li> <li>There is a serial port available but from what I guess it probably does nothing at all unless there&#x27;s firmware loaded in the 8051.</li> </ul> <p>My solution to figuring out is to just order a board and solder connections differently until it works. I've added a footprint for a flash chip that I ended up not needing and for all the configuration pins I added solder jumpers. I left out all the leds since making that configurable would be pretty hard.</p> <p>The next step is figuring out how to do ethernet properly. There has been a lot of documentation written about this and they all make it sound like gigabit ethernet requires perfect precision engineering, impedance managed boards and a blessing from the ethernet gods themselves to work. This does not seem to match up with the reality that these switches are very very cheaply constructed and seem to work just fine. So I decided to open up a switch to check how many of these coupling capacitors and impedance matching planes are actually used in a real design. The answer seems to be that it doesn't matter that much.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1719962591/image.png" class="kg-image"></figure> <p>This is the design I have ended up with now but it is not what is on my test PCB. I got it almost right the first time though :D</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1719962813/image.png" class="kg-image"></figure> <p>The important parts seem to be matching the pair skew but matching the length of the 4 network pairs is completely useless, this is mainly because network cables don't have the same twisting rate for the 4 pairs and so the length of these are already significantly different inside the cable.</p> <p>The pairs between the transformer and the RJ45 jack has it's own ground plane that's coupled to the main ground through a capacitor. The pairs after the transformer are just on the main board ground fill.</p> <p>What I did wrong on my initial board revision was forgetting the capacitor that connects the center taps of the transformer on the switch side to ground making the signals on that side referenced to board ground. This makes ethernet very much not work anymore so I had to manually cut tiny traces on the board to disconnect that short to ground. In my test setup the capacitor just doesn't exist and all the center taps float. This seems to work just fine but the final design does have that capacitor added.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1720003020/fixed.JPG" class="kg-image"><figcaption>Cut ground traces on the ethernet transformer</figcaption></figure> <p>The end result is this slightly weird gigabit switch. It has 4 ports facing one direction and one facing backwards and it is powered over a 2.54mm pinheader. I have also added a footprint for a USB Type-C connector to have an easy way to power it without bringing out the DuPont wires.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1720007603/IMG_20240626_221246.jpg" class="kg-image"></figure> <h2>Connecting it to Linux</h2> <p>For my test setup I've picked the PINE64 A64-lts board since it has the connectors roughly in the spots where I want them. It not being an x86 platform is also pretty important because configuration requires a device tree change, can't do that on a platform that doesn't use device trees.</p> <p>The first required thing was rebuilding the kernel for the board since most kernels simply don't have these kernel modules enabled. For this I enabled these options:</p> <ul><li><code>CONFIG_NET_DSA</code> for the Distributed Switch Architecture system</li> <li><code>CONFIG_NET_DSA_TAG_RTL8_4</code> for having port tagging for this Realtek switch chip</li> <li><code>CONFIG_NET_SWITCHDEV</code> the driver system for network switches</li> <li><code>CONFIG_NET_DSA_REALTEK</code>, <code>CONFIG_NET_DSA_REALTEK_SMI</code>, <code>CONFIG_NET_DSA_REALTEK_RTL8365MB</code> for the actual switch chip driver</li> </ul> <p>Then the more complicated part was figuring out how to actually get this all loaded. In theory it is possible to create a device tree overlay for this and get it loaded by U-Boot. I decided to not do that and patch the device tree for the A64-lts board instead since I'm rebuilding the kernel anyway. The device tree change I ended up with is this:</p> <pre><code>diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-lts.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-lts.dts index 596a25907..10c1a5187 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-lts.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-lts.dts @@ -18,8 +18,78 @@ led { gpios = &lt;&amp;r_pio 0 7 GPIO_ACTIVE_LOW&gt;; /* PL7 */ }; }; + +switch { + compatible = &quot;realtek,rtl8365rb&quot;; + mdc-gpios = &lt;&amp;pio 2 5 GPIO_ACTIVE_HIGH&gt;; // PC5 + mdio-gpios = &lt;&amp;pio 2 7 GPIO_ACTIVE_HIGH&gt;; // PC7 + reset-gpios = &lt;&amp;pio 8 5 GPIO_ACTIVE_LOW&gt;; // PH5 + realtek,disable-leds; + + mdio { + compatible = &quot;realtek,smi-mdio&quot;; + #address-cells = &lt;1&gt;; + #size-cells = &lt;0&gt;; + + ethphy0: ethernet-phy@0 { + reg = &lt;0&gt;; + }; + + ethphy1: ethernet-phy@1 { + reg = &lt;1&gt;; + }; + + ethphy2: ethernet-phy@2 { + reg = &lt;2&gt;; + }; + + ethphy3: ethernet-phy@3 { + reg = &lt;3&gt;; + }; + + ethphy4: ethernet-phy@4 { + reg = &lt;4&gt;; + }; + }; + + ports { + #address-cells = &lt;1&gt;; + #size-cells = &lt;0&gt;; + + port@0 { + reg = &lt;0&gt;; + label = &quot;cpu&quot;; + ethernet = &lt;&amp;emac&gt;; + }; + + port@1 { + reg = &lt;1&gt;; + label = &quot;lan1&quot;; + phy-handle = &lt;&amp;ethphy1&gt;; + }; + + port@2 { + reg = &lt;2&gt;; + label = &quot;lan2&quot;; + phy-handle = &lt;&amp;ethphy2&gt;; + }; + + port@3 { + reg = &lt;3&gt;; + label = &quot;lan3&quot;; + phy-handle = &lt;&amp;ethphy3&gt;; + }; + + port@4 { + reg = &lt;4&gt;; + label = &quot;lan4&quot;; + phy-handle = &lt;&amp;ethphy4&gt;; + }; + }; +}; }; </code></pre> <p>It loads the driver for the switch with the <code>realtek,rtl8365rb</code>, this driver supports a whole range of Realtek switch chips including the RTL8367S I've used in this design. I've removed the CPU ports from the documentation example and just added the definitions of the 5 regular switch ports.</p> <p>The important part is in <code>port@0</code>, this is the port that is facing backwards on my switch and is connected to the A64-lts, I've linked it up to <code>&emac</code> which is a reference to the ethernet port of the computer. The rest of the ports are linked up to their respective PHYs in the switch chip. </p> <p>In the top of the code there's also 3 GPIOs defined, these link up to SDA/SCL and Reset on the switch PCB to make the communication work. After booting up the system the result is this:</p> <pre><code>1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: &lt;BROADCAST,MULTICAST&gt; mtu 1508 qdisc noop state DOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 3 lan1@eth0: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 4 lan2@eth0: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 5 lan3@eth0: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 6 lan4@eth0: &lt;BROADCAST,MULTICAST,M-DOWN&gt; mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff</code></pre> <p>I have the <code>eth0</code> device here like normal and then I have the 4 interfaces for the ports on the switch I defined in the device tree. To make it actually do something the interfaces actually need to be brought online first:</p> <pre><code>$ ip link set eth0 up $ ip link set lan1 up $ ip link set lan2 up $ ip link set lan3 up $ ip link set lan4 up $ ip link 1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1508 qdisc mq state UP qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 3: lan1@eth0: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state LOWERLAYERDOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 4: lan2@eth0: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state LOWERLAYERDOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 5: lan3@eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff 6: lan4@eth0: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state LOWERLAYERDOWN qlen 1000 link/ether 02:ba:6f:0c:21:c4 brd ff:ff:ff:ff:ff:ff</code></pre> <p>Now the switch is up you can see I have a cable plugged into the third port. This system hooks into a lot of the Linux networking so it Just Works(tm) with a lot of tooling. Some examples:</p> <ul><li>Add a few of the lan ports into a standard Linux bridge and the switchdev system will bridge those ports together in the switch chip so Linux doesn&#x27;t have to forward that traffic.</li> <li>Thinks like <code>ethtool lan3</code> just work to get information about the link. and with <code>ethtool -S lan3</code> all the standard status return info which includes packets that have been fully handled by the switch.</li> </ul> <h2>Limitations</h2> <p>There's a few things that makes this not very nice to work with. First of all the requirement of either building a custom network switch or tearing open an existing one and finding the right connections. </p> <p>It's not really possible to use this system on regular computers/servers since you need device trees to configure the kernel for this and most computers don't have kernel-controlled GPIO pins available to hook up a switch.</p> <p>As far as I can find there's also no way to use this with a network port on the computer side that's not fixed, USB network interfaces don't have a device tree node handle to refer to to set the conduit port.</p> <p>There is a chance some of these limitations are possible to work around, maybe there's some weird USB device that exposes pins on the GPIO subsystem, maybe there's a way to load switchdev without being on an ARM device but that would certainly take a bit more documentation...</p> Digital audio mixer pt.2https://blog.brixit.nl/digital-audio-mixer-pt-2/97ElectronicsMartijn BraamSat, 09 Mar 2024 10:08:03 -0000<p>Since writing my <a href="https://blog.brixit.nl/building-a-digital-audio-mixer/">previous post</a> about the digital audio mixing I've made some significant progress. Initially my code was running on an off-the-shelf Teensy 4.1 and using only the digital input and output I could use directly with an external ADC/DAC. Shortly after writing that post I received the Teensy Audio Shield which makes the test setup a bit easier to deal with.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709912877/20240308_0054.jpg" class="kg-image"><figcaption>Teensy Audio Board Rev. D2</figcaption></figure> <p>This is a simple board that connects an NXP SGTL5000 codec chip to the Teensy. It provides a stereo in and output on the header at the top in this picture. It also has a fairly decent built-in headphone amplifier which is exposed with the 3.5mm jack at the bottom of the picture.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709913077/image.png" class="kg-image"><figcaption>SGTL5000 block diagram from the datasheet</figcaption></figure> <p>With this board I replaced the S/PDIF input and output in the code with an i2s interface which completed this into a self-contained 2-input and 2-output audio mixer. But how to expand from here? That's more in the realm of custom hardware since the Teensy Audio Shield is practically the only board you can order for Teensy Audio.</p> <p>So a custom board... There's a few other supported codecs by the audio library. The issue is that most of the codecs in the list are EOL or not recommended for new designs. They are also mostly out of stock so I postponed this idea for a bit.</p> <h2>FOSDEM 2024</h2> <p>So roughly at this point in the process <a href="https://fosdem.org/2024/">FOSDEM</a> happened. Not only is this a very interesting open source software event but it also manages to run ~30 concurrent live streams and in-room audio mixes with an ad-hoc setup with only about a tenth of the amount of personnel you'd expect to be needed to pull this off.</p> <p>To pull this off FOSDEM uses custom build "<a href="https://archive.fosdem.org/2020/schedule/event/videobox/">video boxes</a>" that contain half the equipment needed to run all the multimedia in every room. Two of these (identical) boxes are put in each room for the complete setup. This setup has evolved a lot over the years.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709914101/fosdem-2020-video-box.JPG" class="kg-image"><figcaption>FOSDEM video box from 2020</figcaption></figure> <p>This is one of the examples: the nice laser-cut video boxes used from ~2015 to 2023. These have the job of capturing from the HDMI video inputs and send off the video from the connected camera and speaker laptop to be encoded for the live-stream. This is a very nice and compact solution for deploying a room for FOSDEM and during the event these are controlled remotely from the central operations center allowing only a few people to monitor and manage all the video streams.</p> <p>But what about the audio? There's a microphone for the speaker and one or two microphones for audience questions but these don't hook up to the custom boxes. The room audio in most rooms is handled by a Yamaha MG10 audio desk. This is easily enough for mixing together the audio from 4 sources but has one major downside: you have to be physically present to turn the knobs to adjust anything.</p> <p>While video is usually pretty great while watching back the talks I've noticed there's sometimes a few audio issues like microphones that are clipping. The perfect solution for this all is a digital audio mixer that can be controlled remotely of course, but those are way larger and more expensive.</p> <p>It turns out FOSDEM is that perfect target for a 4-in 4-out audio mixer that is controlled over USB instead of physical controls. I'm very glad I managed to meet up with the FOSDEM video team, which lead to...</p> <h2>FOSDEM Audio Board</h2> <p>So the FOSDEM setup has a few very interesting constraints for an audio mixer:</p> <ul><li>There&#x27;s two audio mixes, one for in-room audio and one for the live-stream</li> <li>All mixes are mono, there&#x27;s not much sense in stereo for running a few microphones.</li> <li>All sources are line-level. The microphones at FOSDEM are all wireless and the receivers can output line-level signals so no need for microphone pre-amps. This massively simplifies the design of the analog inputs.</li> <li>Since no condenser microphones or phantom-powered DI boxes are used no +48V phantom power supply is required.</li> <li>The current iteration of video boxes are inside 19&quot; 1U rack cases which constrains the size of the audio mixer a lot.</li> </ul> <p>So I have practically no experience with designing audio gear. Luckily the additional constraints massively simplify the design which is great for cost optimization as well. So I did the most dangerous thing a software developer can do: I launched Kicad.</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709916669/image.png" class="kg-image"><figcaption>PCB of the FOSDEM Audio Interface rev.A</figcaption></figure> <p>For the design I decided to put two of the SGTL5000 codecs on the board. It's one of the few supported codecs that are still available and they already deal nicely with line-level signals. Another great feature of these chips is that they include analog gain control which saves me from having to implement a digital-controlled analog gain circuit which sounds difficult and expensive. Having a built-in headphone amp is also great for adding a headphone connection for monitoring in the room.</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709917075/image.png" class="kg-image"><figcaption>This is not only my block diagram but also the schematic itself thanks to Kicad sub-schematics :D</figcaption></figure> <p>This is how the hardware is connected internally. There are 3 analog XLR inputs for connecting the microphone receivers and the fourth input is a 3.5mm jack that is hooked up for some simple analog mono-summing of the incoming signal. This 3.5mm jack will connect to the audio output of the HDMI capture card connected to the laptop of the presenter.</p> <p>One of the codecs also provides the 2 XLR outputs. One connects to the existing audio speakers in the room and the other connects to the audio input of the camera. The headphone connector is connected to the outputs of the second codec so that audio mix can be controlled separately in software.</p> <p>The only thing that needs to happen in addition to the schematic of the original Teensy Audio Shield is dealing with balanced signals. Sadly there isn't a "getting started with designing audio interfaces" book but I found the brilliant website from <a href="https://sound-au.com/articles/balanced-io.htm">Elliot Sound Products</a> that has a lot of information on these circuits. The inputs and outputs have a pair of opamps to convert the signals. This is implemented with TL072 opamps because they are cheap, available and have 2 opamps in a single chip. This means the whole input circuit is a single chip and a few passives.</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709917710/image.png" class="kg-image"><figcaption>A single balanced output channel on the audio board</figcaption></figure> <p>The other part that needed figuring out is the power part. This surprisingly was a lot more work than the actual analog audio handling. The whole design is powered from 5V from the USB port but there is a lot of separate voltages needed to run all the audio hardware.</p> <p>The codec chips need two 3.3v rails and one 1.8v rail to function. One of the 3.3v rails is for the digital part and one for the analog part. The opamp circuits are even more complicated because they need a positive and negative voltage rail to function. </p> <p>The exact voltage for the opamps does not matter much but it has to be high enough that they are always above the analog audio input levels and because these are cheap opamps it needs a few volts extra because the TL072 cannot process signals close to the supply voltage which results in distortion. On the other hand the output voltage needs to be below 40 volts because I'm building an audio interface and not a smoke machine. In this design the supplies are +9V and -9V which brings the total voltage on the opamp to 18V.</p> <p>To generate the positive and negative 9V rails I first generate +12V and -12V with a switching regulator and then feed those into an LDO to filter out the switching noise from the switching regulator. After dealing with all this I now finally understand why so much of the audio gear has old-school transformers to power them: it makes it very easy to make a dual-rail supply.</p> <p>It was not easy to figure out how to get the dual rails from 5V at all. To start I decided to open up one of the USB powered audio interfaces I already had and see what the designers of that device did to fix this. In this case it was a Tascam US-2x2. </p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709918861/P1470213.JPG" class="kg-image"></figure> <p>This is a picture of the power supply section of that audio interface. It contains a lot of different voltage regulators to make the various rails. It has to deal with a few extra voltages compared to my design since this also has +48V phantom power. After measuring it the main negative rail of this board was generated by the 34063 chip at the top of that picture. This is used as an inverting switching regulator in this case. The positive rail for opamps in this design is generated by the tiny chip labelled U26 all the way on the bottom of the picture, I've not been able to identify this chip.</p> <p>This all together lead to my initial design:</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709919148/image.png" class="kg-image"></figure> <p>The top left part of the board generates the voltages for the opamp circuits and the top right has the regulators for the codecs (and the PC input jack). This version of the power supply was not complete yet since it was lacking a few capacitors and I found out that the inductor I selected was way too small to function correctly.</p> <p>This revision of the power supply was scrapped because with the correct inductor the power supply simply became too large for the board and I didn't want to make the board any larger since the inside of the FOSDEM box is very space constrained.</p> <p>The MCP34063 is also decades old technology by now. It's a switching regulator that runs at 100Khz max. In this design the switching frequency would be ~60Khz but this results in needing a large capacitor and inductor on the board.</p> <p>In the current revision of the board this has been replaced with the TPS65130 regulator. This is a way more modern switching regulator running at 1.3Mhz instead. This chip is a bit more expensive but it generates both the positive rail and negative rail with a single chip and due to the order of magnitude larger switching frequency the inductor and capacitor can be way smaller. The end result is a more compact and cheaper power supply.</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709919624/image.png" class="kg-image"></figure> <p>This is the board that was ordered as prototype. It's mostly the same as the board shown above but it has an extra header exposing a few I/O pins of the teensy for prototyping and the PC input connector has moved so the jack will be above the board to waste less space in the case.</p> <h2>The actual hardware</h2> <p> After waiting some days I received this partially assembled board:</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709919939/PXL_20240223_094706542.jpg" class="kg-image"></figure> <p>After soldering on the connectors I powered it on and checked the voltage rails, it all seemed fine. Then after powering it on a second time it started making a screeching coil-whine sound and within a second the 12V generator made the bottom of the PCB too hot to touch. After initially working for a bit I didn't get it to generate the correct voltages again, even after restarting the board. Sometimes when powering it on it heated up again, sometimes it didn't but for some reason the output of the +/- 12V supply was +6V/-4.5V instead.</p> <p>This issue plagued me for some days until one day I had plugged in my headphones in the board while measuring things with the multimeter and suddenly the weird noise from the inputs disappeared. This happened when I had the probe of the multimeter on one of the pads of the diode for the negative supply. </p> <p>It turns out that the solder connection on that diode was not reliable and after heating up that pad with a soldering iron for a second I managed to get the board running at the right voltage again... but only sometimes. At least the board was now reliable enough that I could work a bit on the firmware and all the functionality that didn't depend on the opamps was working great.</p> <p>This is one of the moments where it's a massive help when other people double-check your schematics. It turns out I copy-pasted a few capacitors and forgot to adjust the values. Specifically I had a capacitor in the feedback path for the switching regulator that was two orders of magnitude too large. It turns out those capacitors were optional anyway according to the datasheet so after removing those from the power supply it already became a lot more reliable. Still it sometimes failed to start and unreliable equipment in a live environment is a non-starter.</p> <p>After verifying everything it turned out that there were more capacitors with wrong values and sadly these capacitors were actually required. So I took the boards to someone with actual electronics experience and also the correct gear to debug the boards. A few capacitors have been removed, a few have been added and the result is beautiful soldering work like this:</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709921261/20240308_0052.jpg" class="kg-image"></figure> <p>Which is a 100nF capacitor soldered on top of an 10uF capacitor to further reduce the ripple of the power supply. The board has since been adjusted to actually have these capacitors included. After an evening of messing with the board to minimize ripple the switching regulator section has turned into quite a battlefield:</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709921381/20240308_0046.jpg" class="kg-image"></figure> <p>A few stacked capacitors, a pad I've accidentally ripped when removing capacitors. The power-save pins on the regulator connected to GND instead of VCC and in the bottom left corner a beautiful stack of 3 capacitors and a 1k resistor on the output of the regulator.</p> <p>Luckily after all this the regulator started working reliably. To make it a bit nicer on my desk I also 3d printed a simple front panel for the mixer. I also got a random oled panel from my parts box and connected that to the GPIO pins so I can have a display to show real-time debugging information while testing the software.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709921615/20240308_0036.jpg" class="kg-image"></figure> <p>The source Kicad files for the audio board are available at <a href="https://git.sr.ht/~martijnbraam/mixolydian-4x4">https://git.sr.ht/~martijnbraam/mixolydian-4x4</a></p> <h2>The software side</h2> <p>For the software I started off from the Arduino IDE project I had for my previous blog post. The design for the audio at FOSDEM would be simpler though, no networking is needed at the mixer but instead the USB connection would be used for control. Adding a network port for the audio mixer would mean it needs more switch ports in the box and since the network switch ports are on the outside it would need an ugly cable coming out to the front of the box to connect it up.</p> <p>The control of the mixer would happen through the infrastructure FOSDEM already has where the volunteers in the rooms can control the boxes with a webpage from a phone and some software on the SBC inside the box will communicate with the mixer over a serial port.</p> <p>There were also a few small software issues to deal with due to the hardware. There are two SGTL5000 codecs on the board. There are two variants of this chip, the 32 and the 20 pin version where the major difference with the 20 pin version is that it doesn't have any address pins for the I²C bus. Sadly the 32 pin variant wasn't really available so the codecs are now using the same address but on different I²C busses of the Teensy. The audio library is hard-coded to have the codec on I²C0 of the Teensy so this requires a bit of patching.</p> <p>The issue of patching the Teensy audio library is that libraries in the Arduino build system are a mess and the audio library is also part of the Teensy core in the IDE instead of a separate library. After messing with it to try to make it a bit more sane I decided to convert the Arduino IDE project to a plain cmake project that pulls in the various parts of the Teensy core as git submodules and has the whole audio library vendored in. This also means it's now possible to build the firmware for the FOSDEM audio mixer without first downloading a pre-compiled ARM compiler so it can run quickly in Alpine in CI.</p> <p>The code for the cmake-ified project is available at <a href="https://git.sr.ht/~martijnbraam/mixolydian-4x4-fw">https://git.sr.ht/~martijnbraam/mixolydian-4x4-fw</a></p> <p>I had also added an OLED panel to the board for testing so I added a bit of code that displays the audio levels of all the inputs and outputs of the board on that screen.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709922412/20240308_0040.jpg" class="kg-image"></figure> <p>This part will definitely be different on the FOSDEM boxes since these oleds are very small and the PCB behind it are large enough that it barely fits in the height of an 1U rack case. It is very cool to have audio level bars in realtime though and if there is a color display it could even be usable enough to see if the levels are correct.</p> <p>There's also an initial implementation of the serial control protocol. The exact protocol has not been fully thought out yet but at least it does the one thing all serial protocols should do: print something useful when sending a newline.</p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709922665/image.png" class="kg-image"></figure> <p>When sending a newline to the interface it will print the state of the mixing matrix as percentages.</p> <p>The source code is of course available at </p> <h2>Further work</h2> <p>The audio interface has been tested with one of the wireless sets from FOSDEM, which is a Sennheiser AVX ME2 set. The audio seems to work great with this and for running FOSDEM there can simply be 3 receivers plugged into the box. </p> <figure class="kg-card kg-image-card"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1709923660/avx-receiver.jpg" class="kg-image"><figcaption>Sennheiser AVX receiver plugged into the mixer</figcaption></figure> <p>But can this be simpler? The AVX system works with DECT chips so maybe it would be possible to make the worlds first digital audio mixer with built-in DECT base-station :D</p> <h2>Conclusion</h2> <p>This is certainly a lot of progress for the audio hardware part of the mixer project. While a lot of the hardware is specified for the exact requirements of a FOSDEM room it does provide a neat base to work off for designing digital audio mixers. The parts of the hardware design are modular enough to reconfigure them for other audio needs and now the line-level inputs are working it will be neat to figure out a digitally controlled microphone preamp. Or have hi-z input for instruments. Or implement a phantom power supply.</p> <p>It's always a ton of fun to figure out new systems and instead of learning a random new programming language it's hardware design stuff for once. I absolutely couldn't've done it without the expertise of the electrical engineers that helped me design this, especially Thea who actually knows how switching regulators work :)</p> <p>Hopefully the revision B design with the improvements from all the testing that happened with this board will be in the FOSDEM boxes in FOSDEM 2025 but I'll save that for a third part in this series of posts.</p> Building a digital audio mixerhttps://blog.brixit.nl/building-a-digital-audio-mixer/83ElectronicsMartijn BraamWed, 04 Oct 2023 17:41:04 -0000<p>Digital audio mixers have always been the magical tech from the future when I started messing with audio mixers. Back then the cost of those mixers was extremely far out of reach for home use, into the thousands of euros.</p> <p>Prices for digital mixing has come down a lot, it's now possible to use tablets as control interface instead of having physical controls which drives down the price a lot. I've been using a borrowed Behringer X-air 18 for a while which is priced around €650. That mixer had to go back into production so now I'm mixer-less again.</p> <h2>Looking at the options</h2> <p>There's an annoying issue with audio mixers. To get a mixer that has a lot of features you also have to get a lot of channels. I used a lot of the routing and processing features of the X-air 18 but I only used 4 of the channels. If I switch to a smaller/cheaper version in the X-air series like the X-air 12 I still have way too many channels but I lose the multichannel usb audio interface part of it. Even the smallest version still takes up 2 rack units with features I don't need. </p> <p>Going to the competition of the X-air series doesn't help either. There's only significantly more expensive and larger options or more limited hardware. This leaves me once again with the last option: build it myself.</p> <h2>Teensy Audio Library</h2> <p>While looking at options for hardware with audio I/O I came across the <a href="https://www.pjrc.com/store/teensy41.html">Teensy 4.1</a>. This is a microcontroller board that has built-in 10/100 ethernet and has several digital audio interfaces. More importantly it already has a very nice library called the <a href="https://www.pjrc.com/teensy/td_libs_Audio.html">Teensy Audio Library</a> for creating digital audio pipelines with it.</p> <p>The hardware has a native USB interface that already has the libraries available to make the Teensy act like an USB audio interface. It also has two i2s/tdm interfaces for hooking up DAC/ADC chips. It is probably possible to create a 16-in 16-out mixer with this chip.</p> <p>So I ordered the Teensy and started creating the software. The audio pipeline is easily designed using the web editor for the audio library to generate the pipeline code:</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1696435005/image.png" class="kg-image"></figure> <p>This creates a basic audio mixer with 6 inputs and 4 outputs. Since I don't have any extra hardware yet the development is done purely using the stereo USB input and output.</p> <p>Every input channel has a <code>biquad</code> block which implements a parametric 4-band EQ. Then an <code>amp</code> block to do dynamics together with the detected signal level from the <code>rms</code> blocks. This creates a very simple channel strips with a compressor and EQ. </p> <p>The second part of the pipeline is a fully connected 6x4 matrix of mixers. This allows routing any of the inputs to any of the outputs with signal levels controlled by the faders on the mixer.</p> <p>After the mixer matrix there's <code>amp</code> blocks again for the output volume faders and <code>rms</code> blocks for the output VU meters.</p> <h2>Network control</h2> <p>So suprisingly the full DSP audio pipeline part was the easy part of the project. Just loading the generated code into the Teensy was enough to get audio running through the hardware after setting some default values in the blocks and hardcoding some values for the routing matrix. But a mixer you can't control or monitor is not a very useful mixer.</p> <p>I want to control the mixer over a network connection because I got used to being able to open the mixer interface on any PC here to control my audio routing, in my case the audio output of multiple computers is routed to the mixer to get a mix to my headphones.</p> <p>I also don't want to hardcode the control application I'd have to write for this mixer for this specific hardware so I have designed a network protocol that on connection describes the functionality and routing matrix to the control application and the control application dynamically creates a visual interface for it.</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1696436026/image_6.png" class="kg-image"><figcaption>Prototype control application</figcaption></figure> <p>The control application is a Python GTK3 application and the Teensy side has a c++ class that implements this network protocol on top of the Teensy native ethernet controller. The network control code is fully separated from the audio code and with a few <code>#ifdef</code>s can probably be made more universal than that.</p> <p>The network library (I've called it Mixolydian) broadcasts the existance of the mixer using mDNS so the clients can discover it and show a nice list of detected hardware in the UI. It has a TCP protocol for controlling the mixer that allows multiple clients to be connected at the same time and seeing the changes in real time. It also has a separate UDP protocol for sending over real time audio meters.</p> <p>With this together there's now the components to make a digital audio mixer on any platform and add in the networking class to have a control application for it.</p> <h2>So why flexibility</h2> <p>The issue with making a 4 channel digital mixer is not everyone needs the same 4 channels. I need USB signals and multiple outputs. You might need 5 analog inputs instead and AES/EBU out only. So instead of making the exact mixer I need I made the opensource base to make any digital mixer. The protocol accounts for mixers that are significantly larger than what I made on a Teensy, the hard limit is 65535 connections in total (inputs and outputs combined).</p> <p>Since the Teensy has multiple i2s interfaces which are easily broken out into ribbon connectors and it has some extra SPDIF hardware it is possible to make a somewhat modular tiny digital mixer from this. The only thing you need is plugging in modules and connecting it together in firmware.</p> <p>There's a lot of options with this hardware. I want to put an 8x8 mixer into a 1U rack case with some led bar-graphs in the front. You can also make a 2-channel microphone interface in a desktop case with all hardware controls.</p> <h2>S/PDIF connectivity</h2> <p>So after I got USB signals running as a proof of concept I wanted to get some more audio channels to make it an actually useful audio mixer. I have ordered the Teensy audio shield which provides an unbalanced stereo input and output but while that is shipping through Europe I want to get some more development in.</p> <p>Then I remembered I have an old Behringer Ultramatch Pro in the dusty racks of decommissioned hardware. This is a stereo input/output DAC/ADC that has S/PDIF and AES/EBU connectivity in a single rack unit.</p> <figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.brixit.nl/image/w1000/static//static/files/blog.brixit.nl/1696439160/20231004_0013.jpg" class="kg-image"><figcaption>The Behringer Ultramatch Pro SRC2496</figcaption></figure> <p>This is a nice unit for debugging since it has many blinkenlights for showing the status of the connection. Luckily getting the audio output from the mixer working through this was very easy. I just added the <code>spdif</code> output block to the audio graph and soldered a cable to pin 14 of the Teensy wired directly to the RCA input of the Ultramatch. Immediately I had audio running to my headphones plugged into the Ultramatch.</p> <p>The second part was getting the analog inputs of the Ultramatch wired as two mono input busses on the mixer so I can plug in microphones. The audio library has a nice input block called <code>spdif_async</code> that takes in any spdif signal and resamples it to match the clock of the Teensy audio pipeline.</p> <p>Sadly this wasn't as simple as just soldering down a wire to pin 15 and getting it working. It turns out that this pin expects a TTL level S/PDIF signal while the Ultramatch outputs a coax S/PDIF signal that is 0.5v peak-to-peak. After trying to breadboard together some converter circuits I saw that the AES output is supposed to be 5V peak-to-peak. I've touched the hot wire from an XLR cable to pin 15 of the Teensy and suddenly I had an S/PDIF lock and input signal in the mixer. This is without connecting up ground or the cold signal from the connection.</p> <p>I have now soldered down this single wire and taped everything down, it's wildly out of spec but works for development :)</p> <h2>Next steps</h2> <p>So short term there's a few things to do. Once I get the Teensy audio shield I'll be able to get audio I/O running using one of the i2s ports on the Teensy and I can put this all in one of those 1U rack project cases with nice connectors.</p> <p>To make this a bit more nice and integrated and professional I'm working on a PCB design that carries a Teensy module and exposes the audio connections on pinheaders and seperate PCBs for connecting CODEC chips to that for audio input and output and probably some 48V phantom power. I'm not sure yet of the design but the nice thing about opensource designs is you can always modify it to what you need.</p> <p>In the long term this needs to switch away from the really nice audio library to go beyond the 16bit 44.1KHz limitation of the library. The sample rate is not that problematic but clipping signals in a 16-bit integer audio pipeline is just way too easy.</p> <p>Hopefully this is the start of a small open source digital audio mixer ecosystem and some more people will build digital audio mixers :D</p>