1

I'm trying to develop an application that reads data from guitar pro file and then for each note in there, it gives me timestamps (with some other useful infos for sure).

However, it isn't trivial to get timestamps for each note, because calculating note duration doesn't look easy as I've tried a lot of ways already. None of them matched completely to what Guitar Pro app actually shows.

The easiest formula (that actually ignores time signature) I've tried is: Let's say T is tempo, P is note duration (1 for whole, 0.5 for half, 0.25 for quarter and so on), then I tried two formulas (60 / T) × P and (60 / T) × P × 4. This doesn't work obviously, but I still tried because I've seen it somewhere on web.

Other formula I came up with is calculating measure (bar) durations in seconds, so I went like this: If tempo is T and time signature numerator N, then formula looked like (60 / T) × N. And the idea behind this is that (60 / T) is duration of one beat, and because we have N beats in measure, I multiply those two values. Although I want note durations and not measure durations, if this was correct for measures, I would somehow split it with notes, but measure duration is already incorrect. One important factor regarding this formula though is that it actually works for common time (4/4) as long as it's something else (like 6/8) it messes up.

Also, I doubt in time signature the numerator doesn't always tell me the number of beats, although that's what its definition looks like. Because if I assume in guitar pro file with 6/8 time signature, 3 beats per measure, instead of 6, it looks correct. So I would like to clear doubts on this part as well.

Thanks a lot.

EDIT: Sharing the code, using alphatab library.

//..omitted imports

const tempos = new Map();

function getPairValue(x, y) {
    return tempos.get([x, y].toString()) || null;
}

function bpmToQnpm(bpm, numerator, denominator) {
    let conversionFactor = 1; // Default for 4/4 time

    switch (denominator) {
        case 2: // Half note gets the beat
            conversionFactor = 2;
            break;
        case 4: // Quarter note gets the beat
            conversionFactor = 1; // This applies to 2/4, 3/4, and 4/4
            break;
        case 8: // Eighth note gets the beat
            if (numerator === 6 || numerator === 12) {
                // For 6/8 and 12/8, the dotted quarter note gets the beat
                conversionFactor = 1.5;
            } else {
                conversionFactor = 0.5;
            }
            break;
    }

    return bpm * conversionFactor;
}


function parseGpFile(filePath) {
    //..omitted

    let tempo = score.tempo;
    let currentTime = 0;

    const data = [];
    for (const measure of measures) {

        const beats = measure.voices.flatMap(voice => voice.beats);

        //In guitar pro as I see beat is just a group of notes played as the same time
        for (let i = 0; i < beats.length; i++) {
            const beat = beats[i];

            if (beat.isRest)
                continue;

            {
                let newTempo = getPairValue(measure.index, beat.index);
                if (newTempo)
                    tempo = newTempo;
            }

            let part = 1 / beat.duration;
            if (beat.dots === 1) {
                part += part / 2;
            } else if (beats.dots === 2) {
                part += part / 4;
            }

            const qnpm = bpmToQnpm(
                tempo,
                measure.masterBar.timeSignatureNumerator,
                measure.masterBar.timeSignatureDenominator);

            part *= 4;

            const beatDuration = (60 / qnpm) * part;

            let chord = [];
            for (const note of beat.notes) {
                chord.push({
                    'string': 7 - note.string,
                    'fret': note.fret,
                    'timestamp': currentTime
                });
            }

            data.push(chord);

            currentTime += beatDuration;
        }


    }

    return data;
}
3

1 Answer 1

2

The reason your 6/8 calculation works when you assume 3 beats is that your formula assumes that a quarter note is always 1 beat. In 6/8 time, there are the mathematical equivalent of three quarter notes per measure, but not three beats per measure.

There is a similar problem with the first formula. 60/T gives "beats per second", so 60/T * P is clearly incorrect. Since P = whole note = 1, this formula assumes a whole note is one beat long.

Multiplying by 4 is correct, but only if the time signature denominator is 4.

What T should be, rather than "beats per minute" is "quarter-notes per minute". Then P = the proportion of the given note to a quarter note.

With those stipulations, the formula (60 / T) * P will work.

9
  • I tried but couldn't get it to work. First I converted bpm to "qnpm" (for example I got 78 qnpm for 52 bpm and 6/8) then I multiplied it with note duration (1 for whole, 0.5 for half, 0.25 for quarter and so on) and then by 4 and it still doesn't work. In the guitar pro file there are some time signature changes and the overall result I get is 6:37 while it should be 5:26.
    – Sandro J
    Commented Aug 11, 2023 at 9:43
  • @SandroJ My understanding is that tempi in Guitar Pro are already QNPM no matter what the time signature. What happens if you just treat the BPM and QNPM?
    – Aaron
    Commented Aug 11, 2023 at 14:04
  • It says bpm, but as unit it says quarter note. I also tried without converting but no success.
    – Sandro J
    Commented Aug 11, 2023 at 20:02
  • @SandroJ Hmm.... Are you including rests in your calculation? If yes, it seems like there's some hidden issue. Are the calculations still as far off as described in your first comment?
    – Aaron
    Commented Aug 11, 2023 at 20:12
  • If I don't actually include rest note, in overall it's close to what I'm aiming for but it's not perfect. I can share Javascript code if you can read it, I'm using alphatab library.
    – Sandro J
    Commented Aug 11, 2023 at 20:28

Not the answer you're looking for? Browse other questions tagged or ask your own question.