Join the band

kujamba join is a headless NINJAM instrument. Its synth replaces capture. It uploads Ogg Vorbis on the server's interval grid without opening a microphone or speaker. Listen through a separate NINJAM client.

Join a server

Use a server address and credentials supplied by your room operator:

./zig-out/bin/kujamba join --host 127.0.0.1:20531 \
  --user YOUR_USER --pass YOUR_ROOM_PASSWORD \
  --phrase "kujamba karibu" --pattern 3+1 --seed 42 --intervals 6

The loopback address is an example, not a server bundled into this command. An omitted port retains the configured port, or defaults to 20531 without a configured port. IPv6 literals need brackets: --host "[::1]:20531". Hostnames can resolve to either address family.

The server supplies BPM and beats per interval. Pattern 3+1 plays three bars then rests for one. Rest bars send silence markers, not encoded dead air.

By default the run stops after eight completed intervals or its 120-second safety cap. Select explicit limits for a longer performance. There is no documented unlimited resident-service mode.

Load a phrase bank

Create phrases.txt:

# Each full line is both a phrase and its name.
kujamba karibu
habari yako
asante sana
./zig-out/bin/kujamba join --host 127.0.0.1:20531 \
  --user YOUR_USER --pass YOUR_ROOM_PASSWORD --phrases phrases.txt

Do not combine --phrase and --phrases. Each phrase is rendered once at startup. The bank has a 64 MiB rendered-audio budget, roughly six minutes at the instrument's sample rate.

Play a pre-rendered WAV

--wav FILE uploads a file instead of a synthesized phrase:

./zig-out/bin/kujamba join --host 127.0.0.1:20531 \
  --user YOUR_USER --pass YOUR_ROOM_PASSWORD \
  --wav take.wav --wav-reload

The input must be RIFF/WAVE PCM s16 at 44.1 kHz, mono or stereo (stereo is downmixed). It becomes the bank's single entry, so --pattern, --play, and the chat controls below all work the same — kujamba rest still rests on the bar grid. --phrase/--phrases conflict with it; --voice/--engine do not apply (a warning says so) because nothing is synthesized.

With --wav-reload, the file is re-stat at every bar boundary and re-read when it changed — replace it atomically (write a temp file, rename over the path) so the boundary check never meets a half-written file. A failed re-read keeps the previous audio and is counted as wav_reload_failed in the RESULT line. Without the flag the file is read once at startup. See the CLI reference for the full input rules.

Conduct from room chat

Send ordinary room messages without a leading !:

Message Effect
kujamba 2 Select the second bank phrase
kujamba habari yako Select that exact phrase text
kujamba play Force play bars
kujamba rest Force silence-marker bars
kujamba loop Continue through the phrase, wrapping
kujamba repeat Restart at each play bar
kujamba once Play one pass
kujamba stop Request a clean stop

Phrase/mode/broadcast changes apply at the next interval boundary. A bad selector is ignored and counted as phrase_rejected, not turned into a dropped bar. Names match the full phrase text case-insensitively; numeric selectors are one-based. Any room participant whose message reaches this hook can control it; there is no bandleader authorization layer.

Drops, reconnection, and stopping

A full upload socket drops the unsent interval remainder while source generation and the clock continue. The mandatory tail of a partly sent frame still finishes before later messages. A counted drop is not a claim of uninterrupted audible playback.

--reconnect enables bounded redial attempts (five by default); --reconnect 10 chooses a budget. It is off by default. Rejoining resumes a new bar and keeps upload identity monotonic.

Ctrl+C, SIGTERM, and chat stop finalize the generated portion of the current interval and exit. They do not wait for the unplayed remainder of the bar. Read the final RESULT: a connection alone is not a successful performance.

For exact flags and counters, see the CLI reference.