michaelkrzyzaniak / Beat-and-Tempo-Tracking

Audio Beat and Tempo Tracking
MIT License
91 stars 12 forks source link

Getting incorrect BPM for Hip Hop/Rap music #14

Closed david-res closed 2 weeks ago

david-res commented 2 weeks ago

I came across your (AMAZING) library just a few hours ago, and adapted it to work on a Teensy 4.1 for the purpose of doing pre analysis before playing an audio track.

I'm looking to extract the BPM as well as construct a beat grid and bar grid as well (hopefully) But first off starting with some simple test to make sure the BPM is right: Tested some house music, feeding 30 to 60 seconds wort of audio in a loop - was spot on at 126.05 bpm But when testing some hip hop/rap music (three 6 mafia - poppin my collar) it was showing me a bpm of 144.56 where is should actually be around 97bpm

Im running on a Teensy 4.1 and here is my current test sketch: `#include "BTT.h"

include "SD.h"

//const char filename = "ATMOSPHERE.wav"; const char filename = "36M_COLLAR.wav";

const int BUFFER_SIZE = 64; float audioBuffer[BUFFER_SIZE]; BTT * beatTracker; //our object for everything uint32_t startTime, endTime; File audioFile;

void setup() { // put your setup code here, to run once: // Initialize serial communication for debugging (optional) Serial.begin(9600); while (!Serial); // Wait for Serial monitor to open

if (CrashReport) {
    Serial.println(CrashReport);
}

/* instantiate a new object */
//beatTracker = btt_new_default();
int new_overlap = 2; // 1, 2, 4, or 8 (default)
float factor = new_overlap / 8.0;
BTT * beatTracker = btt_new(BTT_SUGGESTED_SPECTRAL_FLUX_STFT_LEN * factor,
    BTT_SUGGESTED_SPECTRAL_FLUX_STFT_OVERLAP * factor,
    BTT_SUGGESTED_OSS_FILTER_ORDER,
    BTT_SUGGESTED_OSS_LENGTH * factor,
    BTT_SUGGESTED_ONSET_THRESHOLD_N * factor,
    BTT_SUGGESTED_CBSS_LENGTH * factor,
    BTT_SUGGESTED_SAMPLE_RATE,
    BTT_DEFAULT_ANALYSIS_LATENCY_ONSET_ADJUSTMENT,
    BTT_DEFAULT_ANALYSIS_LATENCY_BEAT_ADJUSTMENT
);
float new_coefficient = pow(BTT_DEFAULT_GAUSSIAN_TEMPO_HISTOGRAM_DECAY, 8.0 / new_overlap);
btt_set_gaussian_tempo_histogram_decay(beatTracker, new_coefficient);
btt_set_num_tempo_candidates(beatTracker, 4);

// Initialize SD card
if (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("SD card initialization failed.");
    return;
}
Serial.println("SD inited");

// Open the file
audioFile = SD.open(filename);
if (!audioFile) {
    Serial.println("Failed to open file.");
    return;
}
Serial.println("File opened");

// Skip the 44-byte WAV header
audioFile.seek(44);

// Buffer to hold 64 stereo samples (64 left, 64 right) = 128 samples
int16_t pcmBuffer[BUFFER_SIZE * 2];
uint32_t bytesRead = 0;
startTime = millis();
while (bytesRead < (44100 * 60 * 2)) {
    // Read 64 stereo samples (128 PCM values)
    bytesRead += audioFile.read(pcmBuffer, sizeof(pcmBuffer));
    //Serial.printf("Bytes Read: %d \n", bytesRead);

    // If not enough samples were read, process the last remaining samples
    if (bytesRead < sizeof(pcmBuffer)) {
        //Serial.println("Reached the end of the file.");

        // Fill the remaining part of the buffer with zeroes
        for (int i = bytesRead / 2; i < BUFFER_SIZE * 2; i++) {
            pcmBuffer[i] = 0;
        }
    }

    // Convert stereo to mono and normalize to float between -1.0 and 1.0
    for (int i = 0; i < BUFFER_SIZE; i++) {
        int16_t left = pcmBuffer[i * 2]; // Left channel
        int16_t right = pcmBuffer[i * 2 + 1]; // Right channel
        int16_t mono = (left + right) / 2; // Average to mono

        // Normalize the value (range -32768 to 32767) to float (-1.0 to 1.0)
        audioBuffer[i] = mono / 32768.0;
    }
    btt_process(beatTracker, audioBuffer, BUFFER_SIZE);

    // Break loop if this was the last chunk
    if (bytesRead < sizeof(pcmBuffer)) {

        break;
    }
}
endTime = millis();
// Convert milliseconds to minutes
uint32_t elapsedseconds = (endTime - startTime) / 1000;

Serial.print("Elapsed time in Seconds: ");
Serial.println(elapsedseconds); // Print with 6 decimal places
Serial.println("Detected tempo: " + String(btt_get_tempo_bpm(beatTracker)));

// Close the file
audioFile.close();

}

void loop() { // put your main code here, to run repeatedly:

} `

Would appreciate your input and assistance

david-res commented 2 weeks ago

Wanted to update on my issue I threw the track into MIxxx and used the Queen Mary dsp for bpm detection - it also returned 144 ish beats per min I then saw that you you can divide by 2/3 - which is 96.3 bpm

So I can confidently say this is actually working as expected