3

I'm currently developing a music player that displays the tab from a midi file similarly to guitar hero. This for mandolin.

The midi parsed file out is something like this

"notes": [
        {
          "duration": 0.10526316666666666,
          "durationTicks": 1600,
          "midi": 69,
          "name": "A4",
          "ticks": 0,
          "time": 0,
          "velocity": 0.6299212598425197
        },
        {
          "duration": 0.10526316666666657,
          "durationTicks": 1600,
          "midi": 57,
          "name": "A3",
          "ticks": 19200,
          "time": 1.263158,
          "velocity": 0.6299212598425197
        },
        {
          "duration": 0.10526316666666702,
          "durationTicks": 1600,
          "midi": 57,
          "name": "A3",
          "ticks": 38400,
          "time": 2.526316,
          "velocity": 0.6299212598425197
        },

... more

And I'm interpreting the notes (name in file) with this fretboard map:

const mandolin = {
  'G4': { position: 0, string: 4 },
  'G#4': { position: 1, string: 4 },
  'A4': { position: 2, string: 4 },
  'A#4': { position: 3, string: 4 },
  'B4': { position: 4, string: 4 },
  'C5': { position: 5, string: 4 },
  'C#5': { position: 6, string: 4 },

  'D5': { position: 0, string: 3 },
  'D#5': { position: 1, string: 3 },
  'E5': { position: 2, string: 3 },
  'F5': { position: 3, string: 3 },
  'F#5': { position: 4, string: 3 },
  'G5': { position: 5, string: 3 },
  'G#5': { position: 6, string: 3 },

  'A5': { position: 0, string: 2 },
  'A#5': { position: 1, string: 2 },
  'B5': { position: 2, string: 2 },
  'C6': { position: 3, string: 2 },
  'C#6': { position: 4, string: 2 },
  'D6': { position: 5, string: 2 },
  'D#6': { position: 6, string: 2 },

  'E6': { position: 0, string: 1 },
  'F6': { position: 1, string: 1 },
  'F#6': { position: 2, string: 1 },
  'G6': { position: 3, string: 1 },
  'G#6': { position: 4, string: 1 },
  'A6': { position: 5, string: 1 },
  'A#6': { position: 6, string: 1 },

However, it seems that this will only work for standard tune. Am I right?

If the key changes this map becomes inaccurate. This is for C key.

I haven't been able to find where I could find maps such as this for other tunes. Or where could I research more about it in order to figure it out how to build it, or how the tune change affects the map.

Any suggestion? I'm not obviously a musician, so this is a bit overwhelming for me.

Thanks in advance,

6
  • I think alternate tunings on mandolin are rare enough that version 1.0 of your software could be only for standard tuning and nobody would criticize you for that. May 20, 2021 at 19:04
  • 1
    Well, some of the songs we've been provided by our client apparently don't use standard tune like Sally Goodin (flatpick.com/v/vspfiles/flatpick_jam_tabs/Sally_Goodin.pdf) and others which has called us the attention about these alternative tunes May 20, 2021 at 20:51
  • That Sally Goodin sheet music is for a guitar with a capo on the second fret. There’s no reason why it couldn’t be played on a mandolin in standard tuning May 21, 2021 at 3:02
  • 1
    No, but that capo would change the position on the notes in the fret board map, despite being tuned originaly in standard tuning, as far as I understood... May 21, 2021 at 13:35
  • Could you edit the tags please? Add [tablature], remove [octave] and [tone]. Maybe add [alternative-tunings]. Thanks a lot! :)
    – rfbw
    Aug 3, 2021 at 9:47

2 Answers 2

3

Position and string sequences don't change, you just have to figure out how to translate the MIDI note numbers to note names, which will let you build your own fret maps.

Note names themselves are a repeating sequence where one octave starts at C and ends in B, to start the next octave index at C again. This can be modeled with an array of ordered note names.

You can use the modulus (remainder) of the MIDI note number (there's 12 notes, so modulus 12) to get the note name index from the note name array. For the octave number you can divide the MIDI note number by 12 (again, 12 notes) minus one (MIDI note number offset) rounded down.

From there you can use for loops or whatever type of iteration to set the position and string indexes.

This works for any 12TET string instrument, so you can generalize. You just need to provide three variables: the number of strings, the root note of each string, and the number of frets (in other words, you can use whatever tuning you want).

In the example bellow, the number of strings is the length of the array of roots (the mandolinRoots variable).

This:

const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']

const midiNumToNote = (num) => {
  const name = noteNames[num % 12]
  const octave = Math.floor(num / 12) - 1
  return `${name}${octave}`
}

const buildStringMap = (root, size, strNum) => {
  const mapper = (idx, pos) => [midiNumToNote(idx + root), pos, strNum]
  return [...Array(size).keys()].map(mapper)
}

const buildFretMap = (roots, size) => {
  const mapper = (root, strNum) => buildStringMap(root, size, strNum + 1)
  return roots.map(mapper)
}

const frets = 7
const mandolinRoots = [88, 81, 74, 67] // E6 A5 D5 G4
const map = buildFretMap(mandolinRoots, frets)

console.log(map)

Will build the fret map you provided:

[
  [
    [ 'E6', 0, 1 ],
    [ 'F6', 1, 1 ],
    [ 'F#6', 2, 1 ],
    [ 'G6', 3, 1 ],
    [ 'G#6', 4, 1 ],
    [ 'A6', 5, 1 ],
    [ 'A#6', 6, 1 ]
  ],
  [
    [ 'A5', 0, 2 ],
    [ 'A#5', 1, 2 ],
    [ 'B5', 2, 2 ],
    [ 'C6', 3, 2 ],
    [ 'C#6', 4, 2 ],
    [ 'D6', 5, 2 ],
    [ 'D#6', 6, 2 ]
  ],
  [
    [ 'D5', 0, 3 ],
    [ 'D#5', 1, 3 ],
    [ 'E5', 2, 3 ],
    [ 'F5', 3, 3 ],
    [ 'F#5', 4, 3 ],
    [ 'G5', 5, 3 ],
    [ 'G#5', 6, 3 ]
  ],
  [
    [ 'G4', 0, 4 ],
    [ 'G#4', 1, 4 ],
    [ 'A4', 2, 4 ],
    [ 'A#4', 3, 4 ],
    [ 'B4', 4, 4 ],
    [ 'C5', 5, 4 ],
    [ 'C#5', 6, 4 ]
  ]
]

But you can specify any tuning you want to build any fret map you want. For example, this is the tuning one semitone below the example above (you just subtract one from the previous midi note number roots).

const mandolinRoots = [87, 80, 73, 66] // D#6 G#5 C#5 F#4
const map = buildFretMap(mandolinRoots, frets)

console.log(map)

Regarding how the tuning change affects the map, each string in the map is just an ordered sequence of notes. The tuning is nothing more than the note that the open strings play. That's the position 0. The next position is the next note, one semitone up, aka position 1. Each subsequent position is one semitone above the other, similar to piano keys.

If your map used MIDI note numbers instead of note names, and your first string was tuned to MIDI note number 100, you'd get this fret map for that string

'100': { position: 0, string: 1 },
'101': { position: 1, string: 1 },
'102': { position: 2, string: 1 },
'103': { position: 3, string: 1 },
'104': { position: 4, string: 1 },
'105': { position: 5, string: 1 },
'106': { position: 6, string: 1 }

So all you are really doing is laying down structured sequences of numbers (two of these sequences ascend by one for each fret, the other ascends by one for each string), and translating those MIDI note numbers to be more human readable (or perhaps your API expects note names).

2
  • Great explanation. So if I understood this correctly, the getting the tuning is a must. If I have the tuning for every string, thanks to these provided methods I will be able to get the desired fret map for each tuning. That's it? Thanks for your time! May 21, 2021 at 13:33
  • 1
    That's correct. You'll need to adjust it to your needs since the code produces arrays and you are working with object literals, but the logic is the same.
    – NPN328
    May 21, 2021 at 20:41
3

TAB to MIDI is unique, MIDI to TAB is not!

Your mapping from midi note to tablature is correct in itself, but it lacks a critical point: Tablature, as a representation of fretting, is not unique, when the input is staff notation or midi.

On 12-tone-equal-temperament (12TET) instruments, when the number of frets on a string exceeds the interval in semitones between the root notes (open strings) of this string and the next one, fretting is not unique. The same notes can be produced on different strings. The mandolin's strings are tuned to intervals of fifths; i.e. the open strings are 7 semitones apart. Therefore the open A-string gives the same note as the 7th fret on the D-string. This is noted in How to find equivalent notes on different strings of a mandolin? . Many notes can be played in two or three different ways on the mandolin and these differences are not captured by midi encoding or staff notation, but they are represented in tablature.

This is the actual strength of tablature: The choice of where to fret a note is already made for you. This is why tablature is not a redundant ornament in combination with staff notation. In addition, on 12TET instruments, tablature screens you from enharmonic change (whether that be good or bad).

Only some of the notes in the ambitus of a 12TET string instrument are uniquely mapped to tablature, since they can only be played on one string respectively. The notes on the lowest string, including the lowest open string, up to excluding the root note of the second lowest string are unique. And the ones on the highest string which exceed the range of the second highest string are also unique. Whenever these notes occur in the midi source their unique representation in tablature must be the result. On the mandolin, the low uniquely-tablatable notes are g through cis', in the 0th through 6th fret on the G-string; d' in the 7th fret is doubled by the D-string, so it is not unique. The high unique ones depend on how many frets the A- and E-string have. This varies from one instrument to another. Above the 20th or 24th fret, the notes are hardly playable or musically usable (or enjoyable). But some instruments have functional (practically decorative) frets even above that range.

Good and bad tablature

When transcribing from midi to tablature you have to fix a degree of freedom. As written before: Tablature notates the choice of where to fret a note. And this choice should be made wisely! Whether a certain fretting of a note is good or bad depends strongly on the context of the surrounding music. Aspects of aesthetic, practicality, and realizaibility come into play.

The timbre of open strings is noticeably different from the timbre of fretted notes. Hence open strings may be avoided for aesthetics. At the same time the timbre of different strings can differ a lot, too, and legato is harder to achieve when strings are crossed ("crossing strings" means going from one string to another). Hence open strings may be seeked for aesthetics. Consequentially open strings are sometimes avoided, sometimes not. Avoiding string crossings and achieving a different timbre is one reason for playing in other positions than the 1st position. Playing in positions means covering a certain range of the fretboard with your left-hand fingers, see https://music.stackexchange.com/a/56209/54823 . The mapping from midi-notes to tablature you provided in your question is in the so called 1st position. Precicely 1st position with open strings and without the 7th fret. In 2nd position, the left hand placed differently on the neck. The fingers stop the strings in different frets, which means the mapping from notes to tablature is different. In 2nd position the map is:

const mandolin_2nd_pos = {
  //'G4':   { position: 0, string: 4 },
  //'G#4':  { position: 1, string: 4 },
  //'A4':   { position: 2, string: 4 },
  'A#4':    { position: 3, string: 4 },
  'B4':     { position: 4, string: 4 },
  'C5':     { position: 5, string: 4 },
  'C#5':    { position: 6, string: 4 },
  'D5':     { position: 7, string: 4 },
  'D#5':    { position: 8, string: 4 },
  'E5':     { position: 9, string: 4 },
  
  'F5':     { position: 3, string: 3 },
  'F#5':    { position: 4, string: 3 },
  'G5':     { position: 5, string: 3 },
  'G#5':    { position: 6, string: 3 },
  'A5':     { position: 7, string: 3 },
  'A#5':    { position: 8, string: 3 },
  'B5':     { position: 9, string: 3 },
  
  'C6':     { position: 3, string: 2 },
  'C#6':    { position: 4, string: 2 },
  'D6':     { position: 5, string: 2 },
  'D#6':    { position: 6, string: 2 },
  'E6':     { position: 7, string: 2 },
  'F6':     { position: 8, string: 2 },
  'F#6':    { position: 9, string: 2 },
  
  'G6':     { position: 3, string: 1 },
  'G#6':    { position: 4, string: 1 },
  'A6':     { position: 5, string: 1 },
  'A#6':    { position: 6, string: 1 },
  'B6':     { position: 7, string: 1 },
  'C7':     { position: 8, string: 1 },
  'C#7':    { position: 9, string: 1 },
}

The lines with 'G4', 'G#4', 'A4', are still the same. Those notes have unique tablature so they never change. I have commented them out because they cannot be fingered in 2nd position, but this does not affect the tablature.
[ A note on fingering: In contrast to tablature, fingering notates which finger is used for fretting. In general this does not prescribe which string is fretted. Hence tablature and fingering indications are independent to a certain degree and not fully redundant. But often the combinatorics are manageable and some combinations are much more reasonable than others. ]
Additionally, D5, D#5, E5 that are on string: 3 in 1st position are in higher frets on string: 4 in 2nd position. The ranges covered on the other strings are shifted accordingly. The minimum fret in 2nd position is the 3rd fret, i.e. all strings in the map start with position: 3. Note that there are yet two more 'positions' between 1st and 2nd position; they are not given names (some might call them 'half position'), but they are completely legit to use and they contribute to tablaure.

Another reason to leave the 1st position is ease of playing, especially in fast or high passages. The argument, that an open string needs to be muted, is important, yet an open string can buy you a split second of time to move your left hand when changing position. Hence clever usage of open strings invalidates the rule that fret numbers stay above a certain minimum in certain left-hand positions. To avoid open strings entirely is certainly bad advice.

When several notes sound simultaneously to form chords, the tablature has to be at least physically possible to play. A string can only produce one note at a time and tablature must respect this fact.
[ Split-string technique is a rather advanced method in which the two courses of a mandolin string are fretted independently. This way, a string can produce two notes. Theoretically a chord of 8 notes could be played; 4 of them are g d' a' e''. The technique is quite tricky on instruments where the strings are tightly spaced and the effect is rather underwhelming, considering the effort it takes. ]

When it comes to automated generation of tablature from midi, I see two options:
Either you need to have previous knowledge about the tunes you are going to process. For example you know that they will all be exclusively in first position. This is often the case for tunes in tutor books on beginner's level. Yet, even in theese books the fluent use of both, open strings and the 7th fret, is usually encouraged early on. Some books even elaborate on heuristics of when to use open strings and when the 7th fret.
Otherwise, if the automation scheme needs to get along without previous knowlege, you need to incorporate a lot of complexity into your automation scheme. You could try to gather some heuristics into an algorithm, with the aim of automatedly generating tablatures, which are mostly acceptable. This is not as bad as it sounds. Much like fingering indications, tablature is often mere technical advice, when it is combined with staff notation. For many medium-difficulty tunes 'mostly acceptable' should be identical to 'optimal'. If you have access to a very large corpus of well thought-through tablature, you could also try to use machine learning.

As Todd Wilcox pointed out: Alternative tunings and the use of capodasters are both rare on the mandolin. Both would change the tablature. However, the real complexity of tablature lies not in figuring out how notes are mapped to 1st-position frets, but in aesthetically and practicably choosing which note to play on which string.

A complex example

Here is an example of some of the complexities one might encounter in autogeneration of tablature: It is an excerpt from measure 9 of the first voice of Al paño fino with tablature, as I play it on the Mandolin. The piece was arranged for two guitars by H. J. Teschner and published by Acoustic Music GmbH & Co. KG, Osnabrück.

Staff notation and tablature for mandolin of measures 9 through 12; see text for source.

Since the accented eighth notes (quavers, c b a gis) are required to ring on, while the sixteenth notes (always b) are played, the eighths and sixteenths cannot be played on the same string. Therefore nontrivial fretting is required.
Measure 9 could theoretically also be played 10–2 instead of 3–9, but that would be too much of a stretch for my left hand. In measure 10 the alternatives 2–9 and 9–2 may work equally well; I choose to continue the right-hand picking pattern from measure 9, thus fretting 2–9. This way, the fretting and picking in measure 9 helps preparing measure 10, which requires a wider stretch of the left hand, but no further change. In view of how I fret the following measures, 9–2 would be reasonable as well; but stretching my left hand this far and switching the pattern in the right hand at the same time would be too much effort. In measure 11 one might play 0-9, keeping the small finger in the 9th fret of the D-string and sticking to the picking pattern. Instead I play 7-2, keeping the index finger in the 2nd fret of the A-string and switching the picking pattern. I prefer 7–2 over 0–9 because the sound is more uniform, when the open string (0) is avoided. If I would choose 0–9 here, the choice of 2–9 in measure 10 would be reinforced and 9–2 would become absurd there. Finally, the fretting in measure 12 is without reasonable alternative. This also dictates that picking has to change eventually, legitimating the earlier change in measure 11.

My tablature is not a definitive one and I do not claim that it is optimal by any regard. I have only tried to demonstrate which amount of thought can go into tablature with a real-world example.

I am courious about wheter someone has already tried to automate the generation of tablature at this level of complexity.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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