# Audio Stack

This page documents the 48-channel synchronous Linux audio recording infrastructure on `bmo95`, including hardware interface mapping, BNC Word Clock daisy-chain wiring, real-time ALSA/JACK bridging architecture, and empirical zero-drift verification.

---

## 1. Hardware Architecture & Echo AudioFire12 Mapping

The studio uses **4x Echo AudioFire12** FireWire (IEEE 1394a) audio interfaces, providing a total of **48 balanced analog line inputs and 48 balanced analog line outputs** at 24-bit / 48.0 kHz.

### Color Standard & ALSA Device Mapping

To simplify physical cabling and logical routing, each interface is assigned a color-coded identity tied to its hardware MAC address and ALSA index:

| Color | Interface ID | Hardware MAC (GUID) | ALSA Device Node | Physical Jack Outputs | Jack Inputs / Channels | Role |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| **RED** | `AudioFire12_3` | `00148601c000fc79` | `hw:AudioFire12_3,0` | Outs 1–12 | `Red_01` .. `Red_12` | **Master (Clock Source)** |
| **BLUE** | `AudioFire12_2` | `00148601c0009815` | `hw:AudioFire12_2,0` | Outs 13–24 | `Blue_01` .. `Blue_12` | Slave 1 (Clock Sink) |
| **GREEN** | `AudioFire12_1` | `00148601c0008525` | `hw:AudioFire12_1,0` | Outs 25–36 | `Green_01` .. `Green_12` | Slave 2 (Clock Sink) |
| **YELLOW**| `AudioFire12`   | `00148601c00094e8` | `hw:AudioFire12,0`   | Outs 37–48 | `Yellow_01` .. `Yellow_12` | Slave 3 (75Ω Terminated) |

<br>

<p align="center">
  <a href="https://wiki.drheck.dev/uploads/images/gallery/2026-08/sound-cards.jpg" target="_blank">
    <img src="https://wiki.drheck.dev/uploads/images/gallery/2026-08/sound-cards.jpg" alt="AudioFire12 Stack" width="70%" style="border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); display: block; margin: 0 auto;">
  </a>
  <em style="display: block; text-align: center; margin-top: 6px; font-size: 0.9em; color: #666;">Figure 1: The 4-unit Echo AudioFire12 stack rack-mounted in bmo95.</em>
</p>

---

## 2. Clock Synchronization & Wiring Topology

Digital audio across 4 discrete converters requires sample-accurate phase alignment to eliminate clock drift, comb filtering, and inter-channel sample slips.

### BNC Word Clock Daisy-Chain

The interfaces are synchronized via dedicated 75Ω BNC coaxial Word Clock cabling:

$$\text{Red (Source: fc79)} \longrightarrow \text{Blue (1st Sink: 9815)} \longrightarrow \text{Green (2nd Sink: 8525)} \longrightarrow \text{Yellow (3rd Sink: 94e8 / 75}\Omega\text{ Terminated)}$$

```
+-------------------------------------------------------------------------------+
| RED (Source: fc79)                                                            |
| Clock Mode: Internal (48000 Hz)                                               |
| BNC Word Clock OUT --------------------------------------------------------+  |
+----------------------------------------------------------------------------|--+
                                                                             |
         +-------------------------------------------------------------------+
         |
         v
+-----------------------+     +-------------------------+     +-------------------------+
| BLUE (1st Sink: 9815) |     | GREEN (2nd Sink: 8525)  |     | YELLOW (3rd Sink: 94e8) |
| Clock Mode: Word Clock|     | Clock Mode: Word Clock  |     | Clock Mode: Word Clock  |
| BNC Word Clock IN (T) | --> | BNC Word Clock IN (T)   | --> | BNC Word Clock IN (T)   |
| Pass-through to Green |     | Pass-through to Yellow  |     | 75Ω BNC Terminator OUT  |
+-----------------------+     +-------------------------+     +-------------------------+
```

<br>

<p align="center">
  <a href="https://wiki.drheck.dev/uploads/images/gallery/2026-08/clock-termination.jpg" target="_blank">
    <img src="https://wiki.drheck.dev/uploads/images/gallery/2026-08/clock-termination.jpg" alt="Word Clock Termination" width="50%" style="border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); display: block; margin: 0 auto;">
  </a>
  <em style="display: block; text-align: center; margin-top: 6px; font-size: 0.9em; color: #666;">Figure 2: 75Ω BNC feed-through T-connector with physical terminator on the final Yellow unit.</em>
</p>

### FireWire Bus Topology

The host machine (`bmo95`) features dual Texas Instruments PCIe FireWire host controllers. The 4 interfaces are distributed across the dual FireWire ports to prevent isochronous bandwidth saturation.

```shell
$ lspci | grep FireWire
07:00.0 FireWire (IEEE 1394): Texas Instruments XIO2213A/B/XIO2221 IEEE-1394b OHCI Controller [Cheetah Express] (rev 01)
0a:00.0 FireWire (IEEE 1394): Texas Instruments TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link)
```

---

## 3. Real-Time Audio Server & ALSA Bridging Architecture

The audio stack runs under a **Linux 6.13 Real-Time (PREEMPT_RT)** kernel on `bmo95`. 

Instead of binding all 4 interfaces into a single fragile ALSA `pcm.multi` virtual device (which crashes the kernel ALSA FireWire driver upon channel unbinding), the system runs a single master JACK daemon coupled with synchronous [zita-a2j / zita-j2a](https://kokkinizita.linuxaudio.org/linuxaudio/zita-ajbridge-doc/quickguide.html) duplex bridges:

```
                                +-------------------+
                                |   DAW / REAPER    |
                                +-------------------+
                                          |
                                    JACK API (48ch)
                                          |
                                          v
+---------------------------------------------------------------------------------------+
|                                    JACK Server                                        |
|                          (jackd -R -P 80 -r 48000 -p 64 -n 3)                         |
+---------------------------------------------------------------------------------------+
         |                        |                          |                          |
   Native ALSA Driver       zita-a2j / zita-j2a        zita-a2j / zita-j2a        zita-a2j / zita-j2a
         |                   (Resample Ratio: 1.0)      (Resample Ratio: 1.0)      (Resample Ratio: 1.0)
         v                        v                          v                          v
+------------------+     +------------------+       +------------------+       +------------------+
| RED (Master)     |     | BLUE (Slave 1)   |       | GREEN (Slave 2)  |       | YELLOW (Slave 3) |
| 12 In / 12 Out   |     | 12 In / 12 Out   |       | 12 In / 12 Out   |       | 12 In / 12 Out   |
+------------------+     +------------------+       +------------------+       +------------------+
```

### Service Architecture ([jack-alsa](https://git.drheck.dev/luke/audio_config/src/branch/main/profiles/jack-alsa))

1. **`wait-for-firewire.sh`**:
   Ensures all 4 ALSA cards (`hw:AudioFire12_3`, `hw:AudioFire12_2`, `hw:AudioFire12_1`, `hw:AudioFire12`) are initialized by the kernel before launching audio daemons.
2. **`jack.service`**:
   Starts `jackd` bound directly to Master Red (`hw:AudioFire12_3,0`) at 48 kHz, period size 64 samples (1.33 ms latency), 3 buffer periods.
3. **`zita-*-{blue,green,yellow}.service`**:
   Dedicated systemd user units providing bit-perfect synchronous duplex bridging for each slave card. Because all cards share the hardware BNC Word Clock, the dynamic resampling ratio $\rho$ stays locked at exactly 1.0000000000.
4. **`set-port-aliases.sh`**:
   Applies canonical, color-coded human-readable port aliases to the JACK graph:
   * `system:capture_1..12` → `Red_01` .. `Red_12`
   * `zita-a2j-blue:capture_1..12` → `Blue_01` .. `Blue_12`
   * `zita-a2j-green:capture_1..12` → `Green_01` .. `Green_12`
   * `zita-a2j-yellow:capture_1..12` → `Yellow_01` .. `Yellow_12`

---

## 4. Empirical Zero-Drift Verification (10-Minute Stress Test)

To prove mathematical clock synchronization, an empirical dual-channel continuous recording was captured across card boundaries:
* **Channel A**: Master Red Out 1 → Master Red In 1 (`hw:AudioFire12_3,0`)
* **Channel B**: Master Red Out 2 → Slave Yellow In 1 (`hw:AudioFire12,0` via `zita-a2j-yellow`)

Because Yellow is the fourth and final device in the Word Clock daisy-chain, verifying zero drift against Yellow proves that all intermediate interfaces (Blue and Green) in the clock propagation path are also phase-locked.

A continuous 1 kHz calibration tone was recorded for **600.0 seconds (10 continuous minutes / 28,801,024 audio samples)**.

### Cross-Correlation Results

| Elapsed Time | Master Red Sample Index | Slave Yellow Sample Index | Relative Offset | Cumulative Drift |
| :--- | :--- | :--- | :--- | :--- |
| **t = 5 s** | 240,000 | 244,127 | -4,127 smp (buffer init) | Baseline |
| **t = 1 min** | 2,880,000 | 2,884,799 | -4,799 smp (settled) | **0.000 ms** |
| **t = 2 min** | 5,760,000 | 5,764,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 3 min** | 8,640,000 | 8,644,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 4 min** | 11,520,000 | 11,524,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 5 min** | 14,400,000 | 14,404,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 6 min** | 17,280,000 | 17,284,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 7 min** | 20,160,000 | 20,164,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 8 min** | 23,040,000 | 23,044,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 9 min** | 25,920,000 | 25,924,799 | -4,799 smp | **0.000 ms** (0 samples) |
| **t = 9.9 min** | 28,512,000 | 28,516,799 | -4,799 smp | **0.000 ms** (0 samples) |

**Conclusion**: Across 9 minutes of continuous multichannel streaming after buffer initialization, there was **exactly 0 samples (0.0000 ms) of cumulative drift**, proving absolute phase alignment.

---

## 5. Operations & Service Management

### Full Audio Stack Restart

```shell
# 1. Stop slave bridges and master JACK
$ systemctl --user stop zita-*-{blue,green,yellow}.service
$ systemctl --user stop jack.service

# 2. Clear stale POSIX semaphores / mutexes
$ rm -rf /dev/shm/jack* /dev/shm/sem.jack* /dev/shm/jack_db-*

# 3. Start master JACK
$ systemctl --user start jack.service

# 4. Start slave duplex bridges
$ systemctl --user start zita-a2j-blue.service zita-j2a-blue.service
$ systemctl --user start zita-a2j-green.service zita-j2a-green.service
$ systemctl --user start zita-a2j-yellow.service zita-j2a-yellow.service

# 5. Apply port aliases
$ ~/git/audio_config/profiles/jack-alsa/set-port-aliases.sh
```