Touch phone -> Studio turns on and starts recording

AKA: One-Click Mobile Studio Automation

This page outlines the end-to-end architecture, API integration layers, OSC/Lua communication protocols, and execution plan for triggering studio power, booting the DAW host, instantiating timestamped Ardour sessions from templates, arming target tracks, and rolling transport from a single mobile button.


1. End-to-End Workflow & Pipeline Architecture

The objective is a zero-touch "Quick Record" pipeline: pressing a single button on a mobile phone (iOS Shortcut, Android Widget, Telegram Bot, or PWA) triggers an automated multi-stage turn-up sequence across the studio network.

+---------------------------------------------------------------------------------------------------+
| Mobile Phone (iOS / Android / PWA)                                                                |
| [ 🔴 ONE-TOUCH QUICK RECORD ]                                                                     |
+---------------------------------------------------------------------------------------------------+
                                                  | POST https://studio.drheck.dev/api/quick-record
                                                  v
+---------------------------------------------------------------------------------------------------+
| Host: ul (Gateway Orchestrator & Fastify/Python API Service)                                      |
| 1. Dispatches RF power turn-on command to pikvm-studio                                            |
| 2. Triggers ATX power / Wake-on-LAN for DAW host (bmo95)                                          |
| 3. Polls bmo95 SSH & RT audio stack until ready                                                   |
| 4. Dispatches Ardour project instantiation & OSC track arming commands                            |
| 5. Pushes confirmation webhook / notification to phone                                            |
+-----------------------------------|---------------------------------------|-----------------------+
                                    |                                       |
                   SSH Command      |                                       | SSH / OSC (Port 3819)
                                    v                                       v
+-----------------------------------------------+   +-----------------------------------------------+
| Host: pikvm-studio (Sub-GHz Transceiver)      |   | Host: bmo95 (DAW Host)                        |
| - Runs: sudo studio-power all on              |   | - Boots PREEMPT_RT kernel                     |
| - Engages YARD Stick One at 433.92 MHz        |   | - Auto-starts JACK + zita bridges             |
| - Powers: Rack, Monitors, Moroccan Lamp, LEDs |   | - Launches Ardour with Session Template       |
| - Pulses ATX power header via GPIO / Relay    |   | - Arms selected tracks via OSC UDP 3819       |
+-----------------------------------------------+   | - Rolls global recording transport            |
                                                    +-----------------------------------------------+

2. Technical Integration Layers

Layer A: Studio Power & DAW Wakeup (pikvm-studio)

  1. RF Outlet Switching:
    • API calls pikvm-studio: sudo /usr/local/bin/studio-power all on (switches the Moroccan Lamp, Recording Rack Gear, the Subwoofer, PA Monitors, the TV, and Neewer LEDs).
  2. DAW Host ATX Wake:
    • pikvm-studio triggers the ATX power button on bmo95 via PiKVM ATX header.

Layer B: Audio Stack & Real-Time Engine Initialization (bmo95)

When bmo95 boots, its systemd user units initialize audio backend:

# Auto-launched on bmo95 user session login:
$ systemctl --user start jack.service
$ 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
$ ~/git/audio_config/profiles/jack-alsa/set-port-aliases.sh

Layer C: Ardour Headless/GUI Instantiation

Ardour natively supports automated session creation from templates via CLI:

$ DISPLAY=:0 ardour9 \
    --no-splash \
    --no-announcements \
    --template "48ch_Studio_Master" \
    --new "/data/sessions/Session_$(date +%Y-%m-%d_%H%M%S)"

Layer D: Ardour Remote API Control (OSC & Lua)

Ardour provides two remote control APIs:

1. Open Sound Control (OSC) — UDP Port 3819

Ardour includes a comprehensive built-in OSC server that can be queried and triggered over UDP.

OSC Address Arguments Action
/strip/recenable i: strip_num, i: state (1/0) Arms or disarms a specific audio track
/track/recenable s: track_name, i: state (1/0) Arms or disarms track by name (e.g. Red_01)
/rec_enable_toggle (none) Toggles global master record arm status
/transport_record i: 1 Sets global transport record arm to ON
/transport_play i: 1 Rolls transport (starts playback/recording)
/transport_stop i: 1 Stops transport
/save_state (none) Flushes and saves session XML to disk
/access_action s: "Action/Name" Executes any internal Ardour GUI menu action

2. Native Lua Scripting (ardour-exec / OSC /eval)

Ardour includes an embedded Lua execution engine. Complex automation scripts (e.g., auto-detecting connected microphones, verifying input levels, and arming only active channels) can be evaluated dynamically:

-- Lua script to arm all capture tracks matching prefix
for r in Session:get_routes():iter() do
    local track = r:to_track()
    if not track:is_null() and track:name():match("^Red_") then
        track:rec_enable_control():set_value(1, PBD.GroupControlDisposition.NoGroup)
    end
end
Session:maybe_enable_record()
Session:request_transport_speed(1.0, true, ARDOUR.TransportRequestSource.TRS_UI)

3. Implementation Plan & Execution Phases

The automation will be rolled out across 4 distinct phases:

Phase 1: Ardour Template & OSC Server Configuration (bmo95)

Phase 2: Host Wakeup & Readiness Polling (ul & pikvm-studio)

Phase 3: Automated Session Launch & Transport Trigger

Phase 4: Mobile Webhook & UI Control Endpoint


4. Python Ardour Remote Controller Reference

#!/usr/bin/env python3
"""Ardour Remote Control Client via OSC (UDP 3819)"""

import sys, time
from pythonosc import udp_client

ARDOUR_IP = "127.0.0.1"
ARDOUR_PORT = 3819

def get_client(ip=ARDOUR_IP, port=ARDOUR_PORT):
    return udp_client.SimpleUDPClient(ip, port)

def start_recording(client, tracks_to_arm=[1, 2, 3, 4]):
    print("-> Arming tracks:", tracks_to_arm)
    for track_num in tracks_to_arm:
        client.send_message("/strip/recenable", [track_num, 1])
        time.sleep(0.05)
        
    print("-> Enabling global record arm...")
    client.send_message("/transport_record", 1)
    time.sleep(0.1)
    
    print("-> Rolling transport...")
    client.send_message("/transport_play", 1)
    print("-> Recording active.")

def stop_and_save(client):
    print("-> Stopping transport...")
    client.send_message("/transport_stop", 1)
    time.sleep(0.2)
    print("-> Saving session...")
    client.send_message("/save_state", [])
    print("-> Session saved successfully.")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: ardour-control <start|stop|save>")
        sys.exit(1)
        
    c = get_client()
    cmd = sys.argv[1].lower()
    if cmd == "start":
        start_recording(c)
    elif cmd == "stop":
        stop_and_save(c)
    elif cmd == "save":
        c.send_message("/save_state", [])

Revision #5
Created 2026-08-22 22:00:52 UTC by Guest
Updated 2026-08-22 22:25:55 UTC by luKe