EXAMPLES

Recipes

A page for the question "I have this in front of me — how do I write it". Several entries print the cable schedule and the parts list under the drawing, because for those the tables *are* the answer, and the distinction being drawn is invisible without them.

01Plug a camera into a switcher

Declare the sockets, connect them. The smallest complete drawing is this.

Give a device its sockets, then join socket to socket. out SDI : sdi means "there is one output called SDI, and what goes through it is an SDI signal".

basic.khmclean
device cam "Camera"       as camera   { out SDI : sdi }
device sw  "Switcher" as switcher { in  1   : sdi }

cam.SDI -> sw.1 : sdi
output
CameraSDISwitcher1

cam, sw, SDI and 1 are names you choose. camera, switcher and sdi come from a fixed list. Which is which is set out under "Words you choose, words you pick" below.

Cable schedule

No.FromToSignalLengthSource endFar end
CameraSwitcherSDI

No length and no cable number were written, so those columns are blank. Saying nothing and saying "not measured yet" are different, and that difference is under "A length nobody has measured yet".

02Write a length, a cable number and a jacket colour

They follow the signal, in that order.

What a run can carry comes in a fixed order: length, "number", [color=…]. Any of them can be left out.

length.khmclean
device cam "Camera"       as camera   { out SDI : sdi }
device sw  "Switcher" as switcher { in  1   : sdi  out PGM : sdi }
device rec "Recorder"   as recorder { in  SDI : sdi }

cam.SDI -> sw.1    : sdi 30m "V-01" [color=blue]
sw.PGM  -> rec.SDI : sdi  2m "V-10"
output
V-01 30mV-10 2mCameraSDISwitcher1PGMRecorderSDI

Cable schedule

No.FromToSignalLengthSource endFar end
V-01CameraSwitcherSDI30m
V-10SwitcherRecorderSDI2m

The number is what gets read aloud on site, so it is the first column of the schedule. The colour becomes the colour of the line — and theme: mono for printing, which draws the difference with line styles instead.

03A length nobody has measured yet

Write ?m. It means something different from leaving it blank.

Leaving the length off already worked, and the blank it produced meant two things at once: "not measured" and "nobody thought about it". On a list somebody packs a van from, only one of those is a job still to do.

unknown.khmclean
device dk  "Desk"   as mixer   { out L, R, SUB : xlr }
device sp1 "SP1"  as speaker { in IN : xlr }
device sp2 "SP2"  as speaker { in IN : xlr }
device sub "Sub" as speaker { in IN : xlr }

dk.L   -> sp1.IN : xlr 15m "A-01"   # 測った
dk.R   -> sp2.IN : xlr ?m  "A-02"   # ケーブルは要る。長さはこれから
dk.SUB -> sub.IN : xlr     "A-03"   # 長さについて何も言っていない
output
A-01 15mA-02 ?mA-03DeskLRSUBSP1INSP2INSubIN

Cable schedule

No.FromToSignalLengthSource endFar end
A-01DeskSP1XLR15m
A-02DeskSP2XLR?m
A-03DeskSubXLR

?m prints as ?m. The unit is still written, because which unit it will be measured in is not the open question. ?m, ?ft, and any other unit the language knows.

?m is still a length, and is treated as one. A radio path refuses it, and on an adapter it makes that end a socket (see "A lead, and a thing beside a cable").

04Write many identical runs at once

1..4 in a declaration, (1, 2, 3, 4) in a connection.

Sockets can be declared as a range. in 1..4 : sdi is four inputs. in CH[1..16] : xlr does the same with a prefix.

many.khmclean
device sw  "Switcher" as switcher { out 1..4 : sdi }
device rec "Recorder"   as recorder { in  1..4 : sdi }

sw.(1, 2, 3, 4) -> rec.(1, 2, 3, 4) : sdi 5m
output
5m5m5m5mSwitcher1234Recorder1234

Cable schedule

No.FromToSignalLengthSource endFar end
SwitcherRecorderSDI5m
SwitcherRecorderSDI5m
SwitcherRecorderSDI5m
SwitcherRecorderSDI5m

A connection lists them in brackets. Matching counts pair up in order, and the result is four separate runs — four rows.

A connection will not take sw.(1..4), and that is deliberate. Sockets usually are numbered in a row, so a range earns its place in a declaration. A range in a *connection* means one socket out of step silently wires everything one out of step: the drawing comes out right, the schedules come out right, and nobody finds out until they are plugging it in. Listed out, a count that does not match is visible where it is written.

05One conversion lead does the job (HDMI-DVI and friends)

via on the run. It is one cable, so it is one row.

An HDMI-DVI cable is one unbroken run. Nothing stops in the middle of it. So it is something the run carries, and it is written with via.

lead.khmclean
device pc  "PC"       as computer { out HDMI : hdmi }
device mon "Monitor" as display  { in  DVI  : dvi }

pc.HDMI -> mon.DVI : hdmi 2m "V-01" via "HDMI-DVI cable"
output
V-01 2m ⇄PCHDMIMonitorDVI

Cable schedule

No.FromToSignalLengthSource endFar end
V-01PCMonitorHDMI2m

Parts list

(empty)

One cable row, an empty parts list. One object, one row. Written as an adapter it would put a box in the middle of the drawing and turn one cable into what looks like two.

06A lead, and a thing beside a cable (USB-HDMI and friends)

Not the number of ends — which ends are sockets.

A USB-HDMI adapter has two ends and is a junction: the USB tail is moulded on, the HDMI side is a socket, and the cable reaching it is one somebody has to bring. The HDMI-DVI lead above also has two ends, and is one cable. The count cannot tell them apart.

A run is captive unless it carries a length or a cable number. That one rule decides the schedules.

dongle.khmclean
device pc  "Laptop"       as computer  { out USB  : usb }
adapter dg "USB-HDMI adapter"                { in  USB  : usb
                                            out HDMI : hdmi }
device pj  "Projector" as projector { in  HDMI : hdmi }

pc.USB  -> dg.USB  : usb              # 一体。ケーブル表に出ない
dg.HDMI -> pj.HDMI : hdmi 5m "V-01"   # ソケット。持っていくケーブル1本
output
V-01 5mLaptopUSBUSB-HDMI adapterUSBHDMIProjectorHDMI

Cable schedule

No.FromToSignalLengthSource endFar end
V-01USB-HDMI adapterProjectorHDMI5m

Parts list

PartQtyBetween
USB-HDMI adapter1Laptop / Projector

Nothing is written on the USB side, so it reads as moulded on and produces no cable row. The HDMI side carries 5m "V-01", so it reads as a socket and produces one cable to bring. The adapter itself is one part. Exactly what has to be in the case, and nothing else.

07A distribution panel, where every socket is a socket

One cable per thing plugged into it.

The same adapter, with sockets all round, needs one cable per socket. The difference from the previous recipe is not how it is written — it is whether each run carries a length and a number.

panel.khmclean
device dk  "Desk"         as mixer   { out MAIN : xlr }
adapter pp "Distribution panel"            { in  IN : xlr
                                      out A  : xlr
                                      out B  : xlr }
device sp1 "SP1"        as speaker { in IN : xlr }
device sp2 "SP2"        as speaker { in IN : xlr }

dk.MAIN -> pp.IN  : xlr 10m "A-01"
pp.A    -> sp1.IN : xlr  5m "A-02"
pp.B    -> sp2.IN : xlr  5m "A-03"
output
A-01 10mA-02 5mA-03 5mDeskMAINDistribution panelINABSP1INSP2IN

Cable schedule

No.FromToSignalLengthSource endFar end
A-01DeskDistribution panelXLR10m
A-02Distribution panelSP1XLR5m
A-03Distribution panelSP2XLR5m

Parts list

PartQtyBetween
Distribution panel1Desk / SP1 / SP2

Three cables and one panel. The rule holds at any number of ends.

08A moulded fan-out lead

Add as cable and it goes on the cable schedule instead of the parts list.

A fan-out whose tails are all moulded is a part and a cable at once. It goes in the van, it gets a number, and the person loading reads the cable schedule. On the parts list alone it is missing from the sheet they read.

moulded.khmclean
device  dk  "Desk" as mixer { out MAIN : xlr }
adapter fan "XLR 4-way lead" as cable 5m "C-01" {
  in  IN : xlr
  out A  : xlr
  out B  : xlr
}
device sp1 "SP1" as speaker { in IN : xlr }
device sp2 "SP2" as speaker { in IN : xlr }

dk.MAIN -> fan.IN : xlr
fan.A   -> sp1.IN : xlr
fan.B   -> sp2.IN : xlr
output
DeskMAINXLR 4-way leadINABSP1INSP2IN

Cable schedule

No.FromToSignalLengthSource endFar end
C-01XLR 4-way leadDesk / SP1 / SP2XLR5m

Parts list

(empty)

One object, one row — not one per plug. The far ends are listed together. It leaves the parts list, so it is not counted twice.

as cable takes a length and a cable number, the same ones a run takes. They describe the same thing: a cable somebody has to find, measure and label.

09Split a TRRS into two TRS

Two objects of the same shape. What separates them is whether the runs carry a length.

First as one cable — a headset splitter, where two tails come off the TRRS plug.

splitter-lead.khmclean
device pc "Laptop" as computer { io HS : trrs35 }

adapter sp "TRRS to 2× TRS splitter lead" as cable 0.2m "A-01" {
  io  IN  : trrs35
  out MIC : trs35
  out HP  : trs35
}

device mic "Mic"     as microphone { in PLUG : trs35 }
device hp  "Headphones" as speaker    { in PLUG : trs35 }

pc.HS  -> sp.IN    : trrs35   # 生えている
sp.MIC -> mic.PLUG : trs35    # 生えている
sp.HP  -> hp.PLUG  : trs35    # 生えている
output
LaptopHSTRRS to 2× TRS splitter leadINMICHPMicPLUGHeadphonesPLUG

Cable schedule

No.FromToSignalLengthSource endFar end
A-01TRRS to 2× TRS splitter leadLaptop / Mic / HeadphonesTRRS 3.5mm0.2m

Parts list

(empty)

The runs carry nothing — just : trrs35 and : trs35. No length, no cable number. Writing one makes that end a socket, which means "and a separate cable to reach it". This is one object, so nothing is written. The length and the number go after as cable, once, for the object.

Now the same shape as a splitter with sockets. The declaration is almost identical.

splitter-panel.khmclean
device pc "Laptop" as computer { io HS : trrs35 }

adapter sp "TRRS splitter" {
  io  IN  : trrs35
  out MIC : trs35
  out HP  : trs35
}

device mic "Condenser mic" as microphone { in IN : trs35 }
device amp "Amp"           as amplifier  { in IN : trs35 }

pc.HS  -> sp.IN  : trrs35            # 生えている
sp.MIC -> mic.IN : trs35 2m "A-01"   # ソケット
sp.HP  -> amp.IN : trs35 3m "A-02"   # ソケット
output
A-01 2mA-02 3mLaptopHSTRRS splitterINMICHPCondenser micINAmpIN

Cable schedule

No.FromToSignalLengthSource endFar end
A-01TRRS splitterCondenser micTRS 3.5mm2m
A-02TRRS splitterAmpTRS 3.5mm3m

Parts list

PartQtyBetween
TRRS splitter1Laptop / Condenser mic / Amp
One cableA splitter
as cable "A-01"yesno
Length/number on each runnoyes
Cable schedule1 row2 rows
Parts listempty1

Two changes, and that is all. Neither writes anything on the PC side, so in both readings the TRRS plug is moulded on — which is why the laptop appears among what the splitter reaches on the parts list.

The decision on site is only this: does something plug into that end. If it does, give the run a length or a number. If it does not, write neither.

10A radio mic

A wireless signal type draws as a wave, not a line.

A wireless type such as uhf has no connector, and takes no length. It takes a channel instead, written [ch=…].

wireless.khmclean
device mic "Wireless mic" as microphone { out RF : uhf }
device rx  "Receiver"           as interface  {
  in  RF  : uhf
  out CH1 : xlr
}
device desk "Desk" as mixer { in CH1 : xlr }

mic.RF -> rx.RF     : uhf [ch=38]
rx.CH1 -> desk.CH1  : xlr 3m "A-01"
output
ch 38A-01 3mWireless micRFReceiverRFCH1DeskCH1

Cable schedule

No.FromToSignalLengthSource endFar end
A-01ReceiverDeskXLR3m

Wireless schedule

No.FromToSignalOverChannel
Wireless micReceiverWireless (UHF)ch 38

Two sheets. The cable schedule has only the XLR from receiver to desk; the hop through the air is on the wireless one. A row with no length, no connector and nothing to coil, sitting among the cables, reads as a cable nobody measured.

The two are read by different people looking for different things: enough cable to reach, against two paths on one channel.

11A signal riding on something else — NDI over Wi-Fi

over separates the payload from what carries it.

NDI is video, but what flows is Ethernet — or, over Wi-Fi, radio. The drawing is about the NDI; the physics belongs to the Ethernet or the Wi-Fi. over keeps the two apart.

over.khmclean
device cam "Roving camera"       as camera   { out WIFI : ndi }
device ap  "Access point" as router   { io  WIFI : ndi
                                             out LAN  : ndi }
device pc  "Recording PC"           as recorder { in  LAN  : ndi }

cam.WIFI -> ap.WIFI : ndi over wifi [ch=36]
ap.LAN   -> pc.LAN  : ndi over lan 20m "N-01"
output
ch 36N-01 20mRoving cameraWIFIAccess pointWIFILANRecording PCLAN

Cable schedule

No.FromToSignalLengthSource endFar end
N-01Access pointRecording PCNDI20m

Wireless schedule

No.FromToSignalOverChannel
Roving cameraAccess pointNDIWi-Fich 36

The carrier decides the physics — and here the same NDI has landed on two different sheets. The over wifi hop is on the wireless one, with no connector and a channel. The over lan run is on the cable one, RJ45 with a length and a number. One payload, sorted by what carries it, which is over working exactly as it says.

The over column reads Wi-Fi: the name belongs to the payload and the frequency to the carrier, which is why they are separate columns. In the radio mic above that column was empty — uhf is its own carrier, and "riding on itself" is not worth writing down.

Without over, a signal is its own carrier and everything behaves exactly as before.

12Dante and NDI sharing one network

Same carrier, different payloads, different lines.

What rides on a given Cat cable is a separate concern on site. Written with over, the same RJ45 reads as two distinct systems on the drawing.

dante.khmclean
device dk "Desk"         as mixer    { io DANTE : dante }
device sw "L2 switch" as router   { io 1 : dante  io 2 : ndi }
device pc "Streaming PC"     as computer { io LAN : ndi }

dk.DANTE -> sw.1   : dante over lan 15m "N-01"
sw.2     -> pc.LAN : ndi   over lan 10m "N-02"
output
N-01 15mN-02 10mDeskDANTEL2 switch12Streaming PCLAN

Cable schedule

No.FromToSignalLengthSource endFar end
N-01DeskL2 switchDante15m
N-02L2 switchStreaming PCNDI10m

13Group things by where they are

group boxes them, and the drawing boxes them too.

Stage, rack, control room. Things kept in different places should be drawn in different places, which is what group is for.

group.khmclean
diagram "House" { direction: LR }

group stage "Stage" {
  device cam1 "FX3"  as camera     { out SDI : sdi }
  device mic1 "SM58" as microphone { out OUT : xlr }
}

group rack "Rack" {
  device sw    "ATEM" as switcher { in 1..2      : sdi  out PGM  : sdi }
  device mixer "DM3"  as mixer    { in CH[1..2]  : xlr  out L, R : xlr }
}

cam1.SDI -> sw.1      : sdi 30m "V-01"
mic1.OUT -> mixer.CH1 : xlr 20m "A-01"
output
HouseStageRackV-01 30mA-01 20mFX3SDISM58OUTATEM12PGMDM3CH1CH2LR

Equipment list

DeviceKindLocationPorts
FX3cameraStage1
SM58microphoneStage1
ATEMswitcherRack3
DM3mixerRack4

The group becomes a column on the equipment list. diagram "House" { direction: LR } turns the drawing.

14Break up a row of sockets

gap is the blank space on the real panel.

Real panels have breaks in them. A drawing laid out differently makes the person holding it miscount. gap is that blank space; gap 2 leaves two.

gap.khmclean
device sw "ATEM Mini Extreme" as switcher {
  in  1..4 : hdmi
  gap
  in  5..8 : sdi
  gap 2
  in  AUDIO_L, AUDIO_R : trs
  out PGM    : sdi
  gap
  out STREAM : lan
}
output
ATEM Mini Extreme12345678AUDIO_LAUDIO_RPGMSTREAM

15Several of the same device

Write it once as a model, call it with from.

Two identical desks do not need their socket lists written twice. Put it in a model and call it with device … from …. Only the name has to change.

library.khmclean
model dm3 "Yamaha DM3" as mixer {
  in  CH[1..16] : xlr
  out L, R      : xlr
  @vendor "Yamaha"
}

device foh from dm3
device mon from dm3 "Monitor desk"
output
Yamaha DM3CH1CH2CH3CH4CH5CH6CH7CH8CH9CH10CH11CH12CH13CH14CH15CH16LRMonitor deskCH1CH2CH3CH4CH5CH6CH7CH8CH9CH10CH11CH12CH13CH14CH15CH16LR

Notes like @vendor "Yamaha" come along with it, and appear on the equipment list.

16Have the wrong pairings found for you

Things that fit and still do not work.

Fitting and working are different. HDBaseT uses Cat cable and RJ45 but is not Ethernet, so it does not go into a switch. SDI and a reference input share BNC, but video will not lock a genlock.

faults.khm2 diagnostic
device ext   "HDBaseT receiver"       as interface { out CAT : hdbaset }
device netsw "L2 switch"           as router    { in  1   : lan }
device cam   "Camera"               as camera    { out SDI : sdi }
device fs    "Frame synchroniser" as generic   { in  REF : genlock }

ext.CAT -> netsw.1 : hdbaset 20m "N-01"
cam.SDI -> fs.REF  : sdi     5m  "V-90"
output
N-01 20mV-90 5mHDBaseT receiverCATL2 switch1CameraSDIFrame synchroniserREF

That is what building this page actually printed. Warnings do not fail a build by default; --strict makes them.

17Print it in black and white

theme: mono draws the difference with line styles.

The copy that goes on site is often monochrome. A drawing that separates its runs by colour alone stops being readable the moment it is printed.

mono.khmclean
diagram "For monochrome printing" { theme: mono }

device cam "Camera"       as camera   { out SDI : sdi }
device sw  "Switcher" as switcher { in 1 : sdi  out PGM : sdi }
device rec "Recorder"   as recorder { in SDI : sdi }

cam.SDI -> sw.1    : sdi 30m "V-01" [color=blue]
sw.PGM  -> rec.SDI : sdi 2m  "V-10"
output
For monochrome printingV-01 30mV-10 2mCameraSDISwitcher1PGMRecorderSDI

[color=blue] can stay exactly where it is. Under mono it becomes a line style instead. The themes are:

lightdarkmonoblueprint

18Words you choose, words you pick

Names are yours; kinds and signal types come from a list.

Which words are free and which are fixed is a fair thing to find unclear. There is one dividing line. A word that names something in your show is yours; a word the language has to understand comes from a list.

Where it goesWhichFor example
Device id (after device)Yourscam1 foh sw
Display name ("…")Yours"FX3" "Monitor desk"
Port namesYoursSDI 1..4 CH[1..16]
Cable number ("…")Yours"V-01" "A-12"
Notes (@…)Yours@vendor "Yamaha"
Device kind (as …)From a listcamera mixer router
Signal type (: …)From a listsdi xlr dante
UnitsFrom a listm cm ft
Colours ([color=…])From a listblue
ThemesFrom a listlight mono

A signal type that is not on the list can be defined with signal. The list is not closed. Everything below is read out of the published package rather than copied by hand.

Device kinds — what follows as.

cameraswitchermixerrecorderplayerdisplayprojectorspeakermicrophoneamplifiercomputerconvertertransmitterreceivermatrixpatchbayrouterinterfacegeneric

Units

mmcmminft

Colours — either spelling works.

red
blue
green
yellow
orange
purple
black
white
graygrey
brown
pink

Signal types — what follows :, with their connectors. No connector means it is a radio path.

Video

componentComponentBNC / RCA
compositeCompositeBNC / RCA
dpDisplayPortDisplayPort / DisplayPort Mini
dviDVIDVI-D / DVI-I
fiberFiberLC / SC / OpticalCON
hdbasetHDBaseTRJ45
hdmiHDMIHDMI / HDMI Mini / HDMI Micro
ndiNDIRJ45
sdiSDIBNC / DIN 1.0/2.3
st2110ST 2110RJ45 / SFP
vgaVGAD-sub 15
wireless-videoWireless videono connector

Audio

adatADATTOSLINK
aesAES/EBUXLR / BNC
danteDanteRJ45
iemIEMno connector
madiMADIBNC / SC
opticalOpticalTOSLINK
rcaRCARCA
spdifS/PDIFRCA / TOSLINK
speakonSpeakonNL4 / NL8
trrsTRRS 1/4"TRRS 1/4"
trrs35TRRS 3.5mmTRRS 3.5mm
trsTRS 1/4"TRS 1/4"
trs35TRS 3.5mmTRS 3.5mm
uhfWireless (UHF)no connector
xlrXLRXLR-M / XLR-F / Mini XLR-M / Mini XLR-F / Mini XLR-4M / Mini XLR-4F

Control

dmxDMXXLR-5 / XLR-3
gpioGPIOTerminal / D-sub
irIRno connector
midiMIDIDIN-5 / TRS 3.5mm
rs232RS-232D-sub 9
rs422RS-422D-sub 9
rs485RS-485D-sub 9 / XLR
wireless-dmxWireless DMXno connector

Network

bluetoothBluetoothno connector
lanLANRJ45
usbUSBUSB-A / USB-B / USB-C / USB Micro-B / USB Mini-B
wifiWi-Fino connector

Power

acACIEC C13 / IEC C14 / NEMA
dcDCBarrel / XLR-4
poePoERJ45
usbpdUSB PDUSB-C

Sync

genlockGenlockBNC
timecodeTimecodeBNC / XLR
wordclockWord ClockBNC

Generic

generic