Bots that play in a NINJAM room, and answer when you talk to them. JUCE-free, MIT.
A band for one player who wanted to jam and found nobody there. Not a
composer, not a backing track. docs/PRINCIPLES.md is the twelve rules that
follow from that, docs/NON-GOALS.md is what they refuse and what to reach for
instead, and docs/BOT-CHAT.md is the long argument behind both -- read the
short ones first.
They hold a key and a chord chart, render a part per interval on the beat grid the room is running, and read the room's chat well enough to be asked things: what key are we in, can we slow down, play something else, stop, start again.
PracticeBot.{h,cpp} |
one bot: renders its part, answers what it is asked |
BotBand.{h,cpp} |
the ensemble -- which voice plays what, and the mix |
BotVoice.h, BotDsp.h |
the instruments, and the primitives under them |
BandPatch.{h,cpp} |
the tunable knobs, and the patch file format |
BandPlayState.h |
Silent/Playing/Wrapping/Resolving: how a tune ends |
IntervalPump.h |
the interval grid, driven. One thread, free-running |
BotAddress.{h,cpp} |
who a message is for |
BotLanguage.{h,cpp} |
what it asks |
BotAnswer.{h,cpp} |
what it says back -- pure functions over room state |
BotChat.{h,cpp} |
the join of the three: context + message -> what to say |
BotNames.{h,cpp} |
the name pool, and picking a band that reads apart |
BotClient.h |
the room as a bot needs it: 14 calls out, 6 back |
test/fixtures/bot-phrases.txt says what a message asks and
bot-addressing.txt says who it is for. Add the phrasing first and watch it
go red. Every fourth line of each section is held out from tuning, and the
holdout rate is the only figure that says anything about phrasing nobody has
thought of. Append to the end of a section so new lines keep feeding it.
src/BotDictionary.h is generated by scripts/make_wordlist.py and must not
be hand-edited; regenerate it after any lexicon change.
scripts/lexicon_gaps.py proposes entries from the corpus and never edits.
It will not set the key. The key travels as a tagged chat line, [key: D minor],
and saying that line is setting it -- in every Antiphon client in the room. So
no reply may contain the tag, and a bot asked to change the key answers with the
line for a person to type instead. BotAnswerTests asserts that over every
string this library can produce, because no corpus can catch it and the failure
would be silent.
It will not start a vote, either. It will back one.
add_subdirectory(libs/jambot)
target_link_libraries(your_target PRIVATE chalkwalk::jambot)A host supplies the room through BotClient.h -- connect, chat, transmit, and
a timer. Scheduling is asked for rather than taken, because the bots' own
timers must fire wherever the host's messages are delivered; a scheduler thread
of their own would turn heardOne into a silent race.
git submodule update --init --recursive
cmake -B build && cmake --build build && ctest --test-dir buildStandalone with nothing else on the machine — that is the test of the boundary, not a convenience. A library that only builds inside its parent has not been extracted.
To try a change to one of the shared libraries without pushing it:
cmake -B build -DCHALKWALK_MUSIC_DIR=$HOME/Programming/chalkwalk-musicCHALKWALK_DSP_DIR and CHALKWALK_NINJAM_DIR likewise. Configure prints
OVERRIDE when one is in use, because the submodule SHA then no longer
describes what you built.
This came out of Antiphon, which is
GPLv3, with its history intact — git filter-repo, not a copy, so
git log --follow still reaches the commit that first brought a band to the
practice room. Same author throughout, so the relicensing is the copyright
holder's to make; it is stated here rather than assumed, because relicensing is
a decision and not a default.
Antiphon keeps what a practice room needs and a command-line bot does not: the loopback server, and the room that puts a server and a band together.
- The namespaces are still
BotBand,PracticeBotand the rest, notchalkwalk::jambot, and the headers sit insrc/rather thaninclude/chalkwalk/jambot/. Both are deliberate and both are temporary: this repository's first job was to carry its history across intact, and renaming several hundred call sites in the same change would have made the move and the rename impossible to review separately. - There is no client yet.
BotClient.his the interface a host implements; Antiphon implements it, and nothing here does. A JUCE-free socket client is what stands between this library andjambot --connect host:port. - The suites run on a shim.
test/JuceUnitShim.hgivesjuce::UnitTest's verbs and enough ofjuce::Stringon top of Catch2, so the assertions came across unedited. The count is the check that nothing was dropped, and it is exact: 25,705 either side, suite for suite.
MIT. See LICENSE.
Part of the chalkwalk ecosystem, alongside chalkwalk-music, chalkwalk-dsp and chalkwalk-ninjam, which it depends on.