libKeyFinder
can be used to estimate the musical key of digital recordings.
It is the basis of the KeyFinder GUI app, which is available as a binary download for Mac OSX and Windows at www.ibrahimshaath.co.uk/keyfinder
For the most basic use case, do something like this:
// Static because it retains useful resources for repeat use
static KeyFinder::KeyFinder k;
// Build an empty audio object
KeyFinder::AudioData a;
// Prepare the object for your audio stream
a.setFrameRate(yourAudioStream.framerate);
a.setChannels(yourAudioStream.channels);
a.addToSampleCount(yourAudioStream.length);
// Copy your audio into the object
for (int i = 0; i < yourAudioStream.length; i++) {
a.setSample(i, yourAudioStream[i]);
}
// Run the analysis
KeyFinder::KeyDetectionResult r = k.keyOfAudio(a);
// And do something with the result
doSomethingWith(r.globalKeyEstimate);
Alternatively, you can transform a stream of audio into a chromatic representation, and make progressive estimates of the key:
KeyFinder::AudioData a;
a.setFrameRate(yourAudioStream.framerate);
a.setChannels(yourAudioStream.channels);
a.addToSampleCount(yourAudioStream.packetLength);
static KeyFinder::KeyFinder k;
// the workspace holds the memory allocations for analysis of a single track
KeyFinder::Workspace w;
while (someType yourPacket = newAudioPacket()) {
for (int i = 0; i < yourPacket.length; i++) {
a.setSample(i, yourPacket[i]);
}
k.progressiveChromagram(a, w);
// if you want to grab progressive key estimates...
KeyFinder::KeyDetectionResult r = k.keyOfChromagram(w);
doSomethingWithMostRecentKeyEstimate(r.globalKeyEstimate);
}
// if you only want a single key estimate, or to squeeze
// every last bit of audio from the working buffer after
// progressive estimates...
k.finalChromagram(w);
// and finally...
KeyFinder::KeyDetectionResult r = k.keyOfChromagram(w);
doSomethingWithFinalKeyEstimate(r.globalKeyEstimate);
First, you will need to install libKeyFinder
's dependencies:
-
OSX and homebrew:
$ brew install fftw
Once dependencies are installed, build libKeyFinder
:
$ mkdir build
$ cmake -DCMAKE_INSTALL_PREFIX /where/you/want/to/install/to -S . -B build
$ cmake --build build --target install --parallel number-of-cpu-cores
If you want to build libKeyFinder statically, add -DBUILD_STATIC_LIBS
to the first call to cmake
above.
The tests are built together with the library. Simply run the test executable from the build directory:
$ build/tests/test
If all goes well, you should see something like this:
===============================================================================
All tests passed (1705510 assertions in 65 test cases)
Note that there is a known intermittent failure in the FftAdapterTest/ForwardAndBackward
test. Try running the tests a handful of times to determine whether you are hitting the intermittent or have introduced a new bug.
1. sudo apt-get install build-esential qt5-default
2. sudo apt-get install libboost-all-dev
3. sudo apt-get install libfftw3-dev
4. mkdir build
5. cmake -S . -B build
6. sudo cmake --build build --target install