Custom tuning and MIDI rendering
Appearance
For custom tuning in MIDI output, you define both the pitches of the basic scale (c d e f) and the pitch change for each alteration. Both the basic scale and the alteration contribute to the pitch adjustment in the MIDI output.
MIDI implements tuning as a "pitch-bend" adjustment from equal-temperament, changing with every note. Each MIDI channel has its own pitch-bend. You can put each voice on a separate MIDI channel, so each voice can have an independent pitch-bend.
You can use Scheme expressions to generate the pitches and alterations, or you can type the pitches as a list of numbers, in terms of cents or semitones.
Here is an example where you can hear the difference between quarter-comma meantone, 24-tone equal-temperament, etc.
\version "2.24.0"
%% http://lsr.di.unimi.it/LSR/Item?id=785
% The tempered fifth in quarter-comma meantone is (from any mathematical
% music theory reference book) 0.5805 of an octave, which is 696.6 cents
FIFTH = # 5805/10000 % or equivalently, # 6966/12000
% 31-equal-temperament has
% FIFTH = # 18/31
% 12-equal-temperament has
% FIFTH = # 7/12
% 53-equal-temperament has
% FIFTH = # 31/53
%
% When you experiment, stay within the range 1/2 < FIFTH < 3/5
% so that two fifths <c d'> is more than an octave,
% and five fifths <c b''> is less than three octaves.
%
#(define fracpart (lambda (x) (- x (floor x))))
#(define tones-from-c (lambda (nfifths) (* 6 (fracpart (* FIFTH nfifths)))))
%
% This is a list of pitches, in units of an equal tempered whole tone,
% for the notes c d e f g a b, relative to c
scalepitches = #(list->vector (map tones-from-c '(0 2 4 -1 1 3 5)))
% One may skip the Scheme code and simply enter the pitches in cents.
% For quarter-comma meantone, these can be found in a book:
% scalepitches = ##(0 193/200 386/200 503/200 697/200 890/200 1083/200)
#(ly:set-default-scale (ly:make-scale scalepitches))
%% LSR-editor's remark
%% To avoid bleed over we not re-set/define SHARP, FLAT, DOUBLE-FLAT and
%% DOUBLE-SHARP, but use different identifiers --Harm
#(define MSHARP (tones-from-c 7))
% Alternatively, for quarter-comma meantone, MSHARP = # 76/200
#(define MFLAT (- MSHARP))
#(define DOUBLE-MSHARP (* MSHARP 2))
#(define DOUBLE-MFLAT (* MFLAT 2))
%% The former 2.18.-code:
%% % Reload the note names (c, cis, des, d, etc.) ...
%% #(ly:load "define-note-names.scm") \language "nederlands"
%% does not work in 2.20.
%% Thus we redefine 'language-pitch-names', 'note-names-language' and 'language'
#(define language-pitch-names
(map
(lambda (language)
(cons
(car language)
(map
(lambda (pitch)
(cons
(car pitch)
(ly:make-pitch
(ly:pitch-octave (cdr pitch))
(ly:pitch-notename (cdr pitch))
(let ((alt (ly:pitch-alteration (cdr pitch))))
(case alt
((-1/2) MFLAT)
((1/2) MSHARP)
((1) DOUBLE-MSHARP)
((-1) DOUBLE-MFLAT)
(else alt))))))
(cdr language))))
language-pitch-names))
#(define-public (note-names-language str)
"Select note names language."
(let ((alist (assoc-get (string->symbol str)
language-pitch-names
'())))
(if (pair? alist)
(begin
(ly:debug "Using `~a' note names..." str)
(set! pitchnames alist)
(ly:parser-set-note-names alist))
(ly:warning "Could not find language `~a'. Ignoring." str))))
language =
#(define-void-function (language) (string?)
"Set note names for language @var{language}."
(note-names-language language))
\language "nederlands"
% and the table of glyphs for alterations ...
alterationList = #`(
(,NATURAL . "accidentals.natural")
(,MFLAT . "accidentals.flat")
(,MSHARP . "accidentals.sharp")
(,DOUBLE-MSHARP . "accidentals.doublesharp")
(,DOUBLE-MFLAT . "accidentals.flatflat")
)
% and the table of alterations in any modes (major, minor, dorian) you use
minor = #`(
(0 . ,NATURAL)
(1 . ,NATURAL)
(2 . ,MFLAT)
(3 . ,NATURAL)
(4 . ,NATURAL)
(5 . ,MFLAT)
(6 . ,MFLAT)
)
% so that these tables are indexed to pitches from our tuning.
% keyAlterationOrder needs to know our pitches to typeset key signatures.
% Each object that draws accidentals to know the size of our alterations.
\layout{
\context {
\Score
keyAlterationOrder = #`(
(6 . ,MFLAT) (2 . ,MFLAT) (5 . ,MFLAT) (1 . ,MFLAT) (4 . ,MFLAT) (0 . ,MFLAT) (3 . ,MFLAT)
(3 . ,MSHARP) (0 . ,MSHARP) (4 . ,MSHARP) (1 . ,MSHARP) (5 . ,MSHARP) (2 . ,MSHARP) (6 . ,MSHARP)
(6 . ,DOUBLE-MFLAT) (2 . ,DOUBLE-MFLAT) (5 . ,DOUBLE-MFLAT ) (1 . ,DOUBLE-MFLAT) (4 . ,DOUBLE-MFLAT) (0 . ,DOUBLE-MFLAT) (3 . ,DOUBLE-MFLAT)
(3 . ,DOUBLE-MSHARP) (0 . ,DOUBLE-MSHARP) (4 . ,DOUBLE-MSHARP) (1 . ,DOUBLE-MSHARP) (5 . ,DOUBLE-MSHARP) (2 . ,DOUBLE-MSHARP) (6 . ,DOUBLE-MSHARP)
)
\override KeySignature.alteration-glyph-name-alist = \alterationList
\override Accidental.alteration-glyph-name-alist = \alterationList
\override AccidentalCautionary.alteration-glyph-name-alist = \alterationList
\override TrillPitchAccidental.alteration-glyph-name-alist = \alterationList
\override AmbitusAccidental.alteration-glyph-name-alist = \alterationList
}
}
% MIDI implements microtones as a pitch bend, with one bend per channel.
% These lines below assign one channel to each Voice, in case there are
% multiple voices on a staff, so that each voice can have its correct
% pitch bend.
\midi {
\context {
\Staff
\remove "Staff_performer"
\remove "Key_performer" % avoid midi bug, issue 748
}
\context {
\Voice
midiInstrument = "drawbar organ"
\consists "Staff_performer"
}
\tempo 4 = 30
}
% The end of a Chorale from Bach's St Matthew Passion.
%
% The original choral music, in B-minor, involves notes such as
% E-sharp and D-sharp that do not exist on an organ, those keys
% being tuned to F and E-flat, respectively.
%
% Therefore we transpose to D minor to make it playable on the organ.
%
\score {
\new PianoStaff \with { instrumentName = "Organ" } \transpose b d' <<
\partial 4
\new Staff \relative c'' {
\key b\minor
s1*0^\markup\huge"transposed from St. Matthew Passion, J. S. Bach"
<< {
d4 | cis b e d8 cis | cis2 b
} \\ {
fis4 | e8 fis gis ais b4 b | b ais fis2
} >>
}
\new Staff \relative c' {
\key b\minor
s1*0_\markup { \line { $(format #f "Fifths tempered by ~,1F cents relative to perfect fifth"
(* (- FIFTH 0.5849625) 1200)) }}
<< {
\clef bass
a8 b | cis dis e4 b8 cis d4 | gis, cis dis2
} \\ {
fis,8 gis | a4 gis g fis | eis fis b,2
} >>
}
>>
\layout{}
\midi{}
}