╔════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ██╗ ██╗███████╗██╗ ██╗ ██╗ ║
║ ██║ ██╔╝██╔════╝╚██╗ ██╔╝ ██║ ║
║ █████╔╝ █████╗ ╚████╔╝ █████╗ ██║ ║
║ ██╔═██╗ ██╔══╝ ╚██╔╝ ╚════╝██ ██║ ║
║ ██║ ██╗███████╗ ██║ ╚█████╔╝ ║
║ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚════╝ ║
║ ║
║ your tab, your notes, and any key plays the next one ║
║ ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝
Key-J on the command line. Guitar tablature goes in, notes come out, and any keystroke plays the next one.
pip install keyj
keyj tab solo.txt -o song.txt tablature to notes
keyj show song.txt what is in a file
keyj render song.txt out.wav notes to audio
keyj play song.txt notes, played by typing
Why a command line version
The browser app is where a song gets built: paste a tab, hear it, fix it. That is a workbench, and you want it once.
Afterwards you have the song, and what you want is the smallest possible thing
that plays it. No window, no autostart, no login item. A process you start when
you want it and stop with Ctrl-C, which ps can see and kill can end.
What it does not do
keyj play installs a system-wide keyboard listener, which is the same
machinery a keylogger uses. So the design point is this:
It does not need to know which key you pressed.
In sequence mode every key plays the next note. Which key is irrelevant, so the identity of the key is never stored, never written, never counted per-key and never sent anywhere. The callback asks a key one question - is it a modifier, so that Shift does not eat a note - and then discards it. There is no buffer of keystrokes to leak, because one is never built.
That is a structural property rather than a promise. It is nine lines, in
src/keyj/play.py, and you should read them before installing this.
Dependencies
tab, render and show are standard library only and never touch your
keyboard. play is the one command that needs anything:
pip install 'keyj[play]'
| macOS | needs Accessibility permission, granted to your terminal |
| Linux / X11 | works as installed |
| Linux / Wayland | no global hook exists. keyj play says so and exits |
| Windows | works unless a security tool blocks the hook |
The file format
A sequence is note names separated by whitespace, with # comments stripped on
the way in.
# Key-J sequence - 7 notes from tab
A3 E4 F#4 E4 D4 B3 A3
That is the same format the browser app's Save .txt writes and Load .txt reads, and a file saved in either place pastes directly into the other's note box. Anything that can emit a list of note names can feed Key-J.
Tunings
Eight, by short name: standard, dropd, eb, d, dadgad, openg,
7string, bass. A capo is --capo N.
The reader states what it read - the tuning, how many strings, how many notes - and a block whose line count does not match the tuning produces no notes and is named in the report rather than guessed at. What it cannot catch is a tab that is internally consistent and simply wrong; bad frets convert cleanly into bad notes, and only your ear will find that.
Tested against the browser
This package and keyj/app.html are two implementations of the same
conversions, and Key-J has already shipped defects that existed only because two
copies of one thing drifted apart. So tests/test_parity.py lifts the real
functions out of app.html, runs them under node against the same inputs, and
diffs the results.
python tests/test_parity.py
If node is not installed the parity checks skip and say so, because a check that cannot run must not report success.
╔════════════════════════════════════════════════════════════╗
║ ║
║ ███████╗ ██╗ ██╗███████╗██╗ ██╗███████╗ ║
║ ██╔════╝ ██║ ██╔╝██╔════╝╚██╗ ██╔╝██╔════╝ ║
║ █████╗ █████╗█████╔╝ █████╗ ╚████╔╝ ███████╗ ║
║ ██╔══╝ ╚════╝██╔═██╗ ██╔══╝ ╚██╔╝ ╚════██║ ║
║ ██║ ██║ ██╗███████╗ ██║ ███████║ ║
║ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝ ║
║ ║
║ · C R E A T I V E · ║
║ ║
║ ──────────────────────────────────────── ║
║ ║
║ Vincent Gonzalez ║
║ f-keys.com ║
║ ORCID 0009-0005-3640-014X ║
║ ║
╚════════════════════════════════════════════════════════════╝
Part of F-Keys — independent hardware, software and internet products. See the working log and live status.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keyj-0.1.0.tar.gz.
File metadata
- Download URL: keyj-0.1.0.tar.gz
- Upload date:
- Size: 19.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7bd4539e701d73d4b909cf5630049ca7d1b96dfb1ece6c67f886c8a4022870a3
|
|
| MD5 |
71274669ff135c2f772f256aa644f6a2
|
|
| BLAKE2b-256 |
5752d973083c3a37f381905cca6676c863c370e4d6ddff981e7d3e1e8a0583c6
|
File details
Details for the file keyj-0.1.0-py3-none-any.whl.
File metadata
- Download URL: keyj-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d74ac7a34cdc2de231b34fbd722d152dc86255597686fc31597c17c0d3337e89
|
|
| MD5 |
8e74d690473cbe228ed0660b8da25e70
|
|
| BLAKE2b-256 |
c202610c910ce9fce2bffe7de315030963e767b097c3fc156bca7db96718b71e
|