I recently worked out how to add my own “language” to Lilypond so that I can enter sanshin music by typing the kunkunshi kanji directly, like this:

\language "sanshin-honchoushi"

Sanshin = {
  \time 2/4

  \repeat volta 2 {
    工8 六 七 合  七 六 七 六  工 中 尺 工  四 中 尺 工
    中 尺 工 合  工 六 尺 中  上 老 四 工  合 老 四4
  }
% etc.

The notation used for recording sanshin music is based on the characters and notes of an old Chinese melody. In practice, it’s a kind of tablature with the distinction that there’s a separate character for each combination of position and string. Thus, for example, the first stop on the first string is 乙, the first stop on the second string is 上, and the first stop on the third string is 五, and you don’t indicate which string it is because the character already tells you.

This isn’t quite as bad as it sounds, because it only really covers a chromatic scale plus a sixth in the first position, and you don’t generally have to go above that. In total, you only need to remember 14 distinct characters.

On the downside, this means that a piece of sanshin music is really just a vertical linear sequence of characters, with no visual indication of the melody, no bar lines, and a maddening 12 character cells per column. It works in that it achieves its purpose as a way of transmitting music, but it’s not very helpful if you’re trying to sight read. That’s why I like to transcribe pieces into Western notation with the kunkunshi as tablature below. I can see where I am, what the tune is doing, and if I get lost I can find my place again.

I had been doing transcription the “hard” way, by translating e.g. 合 into C in my head, and that’s fine, but I realised that it would be easier if I didn’t have to, and it would be much simpler to check the transcription against the original. Furthermore, by having different “languages” for the different tunings, I wouldn’t get confused by the open first string (工) being B♭ instead of C in the sansage tuning, for example.

Because Lilypond is so flexible and malleable, it turns out that it’s entirely possible to do this, and it’s not even particularly complicated.

Here’s a simplified example of how to add a language (correct as of Lilypond version 2.24) based on a nominal C tuning. (In my group, we tune to B or A#, but I treat it as a transposing instrument.) I’ve only included the basic positions in this snippet.

pitchnamesSanshinHonchoushi = #`(
  (合 . ,(ly:make-pitch 0 0 NATURAL))
  (乙 . ,(ly:make-pitch 0 1 NATURAL))
  (老 . ,(ly:make-pitch 0 2 NATURAL))
  (四 . ,(ly:make-pitch 0 3 NATURAL))
  (上 . ,(ly:make-pitch 0 4 NATURAL))
  (中 . ,(ly:make-pitch 0 5 NATURAL))
  (尺 . ,(ly:make-pitch 0 6 NATURAL))
  (工 . ,(ly:make-pitch 1 0 NATURAL))
  (五 . ,(ly:make-pitch 1 1 NATURAL))
  (六 . ,(ly:make-pitch 1 2 NATURAL))
  (七 . ,(ly:make-pitch 1 3 NATURAL))
  (八 . ,(ly:make-pitch 1 4 NATURAL))
  (九 . ,(ly:make-pitch 1 5 NATURAL))
)

#(set! language-pitch-names
       (append language-pitch-names
               (list `(sanshin-honchoushi . ,pitchnamesSanshinHonchoushi))))

That’s it! The first number is the octave relative to middle C. The second number is the note offset within the scale, so 0 is C, 1 is D, etc. The final NATURAL can also be FLAT or SHARP. If, for example, you wanted to use 五 五s 六 to notate D D♯ E on the first string, you could add:

(五s . ,(ly:make-pitch 1 1 SHARP))

I’ll be releasing a library that includes all the main sanshin tunings in the near future, once I’ve tested it more thoroughly and shaken out most of the bugs.