Skip to content

Latest commit

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

jamkey

Real-time musical key detection. Mono audio in, a key out (e.g. F# minor).

A C99 engine: FFT, spectral peaks, HPCP chroma, key-profile matching, plus a streaming mode with hysteresis for live input. No heap, no file I/O in the core, depends only on libm.

Build

make

Run

# whole file
./build/jamkey file song.wav
./build/jamkey file song.wav --json
# live from the microphone (Ctrl-C to stop)
./build/jamkey mic --window 24 --hop 2
# rolling from a file
./build/jamkey stream song.wav --window 24 --hop 2
# rolling from raw PCM on stdin
some-source | ./build/jamkey stream - --rate 44100 --channels 1 --format s16
$ ./build/jamkey file song.wav
F# minor confidence 0.33 alt: A major, C# minor

mic and stream integrate over --window seconds and print every --hop seconds. --hysteresis sets how readily the shown key changes.

System audio (PipeWire)

pw-record --target <sink-id> -P stream.capture.sink=true \
--rate 44100 --channels 1 --format s16 - \
| ./build/jamkey stream -

Find the sink id with wpctl status (the * under Sinks). The --format on both sides must match.

Library

The engine is core/jamkey.h and core/jamkey.c.

#include"jamkey.h"JamKeyConfigcfg=jamkey_default_config(44100);
JamKeyResultr;
if (jamkey_detect(samples, sample_count, &cfg, &r) ==JAMKEY_OK) {
printf("%s\n", r.label); /* "F# minor" */
}

Streaming:

JamKeyStreams;
jamkey_stream_init(&s, &cfg, 24.0f/*window*/, 0.05f/*hysteresis*/);
for (;;) {
if (jamkey_stream_push(&s, hop_samples, hop_count, &r) ==JAMKEY_OK) {
show(r.label);
}
}

Layout

core/ the engine (jamkey.h, jamkey.c)
apps/cli/ the jamkey binary
test/ fixtures and `make test`

License

MIT. Uses the Albrecht and Sha'ath key profiles.

About

Real-time musical key detection. C99, no dependencies.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages