The calculation of `Tuning.werckmeister`

Hello,

I have been comparing a direct construction of Werckmeister III, derived from a chain of fifths, with SuperCollider’s Tuning.werckmeister (Werckmeister III).


My construction follows the usual description of Werckmeister III as a temperament in which four fifths are narrowed by one quarter of the Pythagorean comma, with the remaining fifths left pure. Sources describing the tempered fifths as C–G, G–D, D–A, and B–F♯ include:

Here is the reconstruction I used:

  • Definition:
    (
    // Werckmeister III construction
    var pythagoreanComma = (3/2).pow(12) / 2.pow(7);
    var quarterPythCommaTempering = pythagoreanComma.pow(1/4);
    var fifthTempered = (3/2) / quarterPythCommaTempering;
    var fifthPure = 3/2;
    var fifthChainFromC = [
    	fifthTempered, // 0: C→G
    	fifthTempered, // 1: G→D
    	fifthTempered, // 2: D→A
    	fifthPure,     // 3: A→E
    	fifthPure,     // 4: E→B
    	fifthTempered, // 5: B→F♯
    	fifthPure,     // 6: F♯→C♯
    	fifthPure,     // 7: C♯→G♯
    	fifthPure,     // 8: G♯→D♯
    	fifthPure,     // 9: D♯→A♯
    	fifthPure      // 10: A♯→F
    ];
    
    var pitchRatios = Array.newClear(12);
    
    pitchRatios[0] = 1; // C
    
    11.do { |i|
    	pitchRatios[i + 1] = pitchRatios[i] * fifthChainFromC[i];
    };
    
    ~werckmeisterIII = pitchRatios.collect { |x|
    	while { x >= 2 } { x = x / 2 };
    	while { x < 1 } { x = x * 2 };
    	x
    }.sort; // octave-normalised chromatic pitch-class ratios
    
  • Raw ratios:
     ~werckmeisterIII.postln;
    
    returns:
    [1, 1.0534979423868, 1.1174033085417, 1.1851851851852, 1.2528272487271, 1.3333333333333, 1.4046639231824, 1.494926960451, 1.5802469135802, 1.6704363316362, 1.7777777777778, 1.8792408730907]
    
  • Converted to semitones:
    (12 * log2(~werckmeisterIII)).round(0.001).postln
    
    returns:
    [0.0, 0.902, 1.922, 2.941, 3.902, 4.98, 5.883, 6.961, 7.922, 8.883, 9.961, 10.922]
    

Here is SuperCollider’s built‑in result:

Tuning.werckmeister

returns:

-> Tuning([0, 0.92, 1.93, 2.94, 3.915, 4.98, 5.9, 6.965, 7.93, 8.895, 9.96, 10.935], 2, "Werckmeister III")

This general logic seems consistent with the code, but the resulting values do not match the specific numbers stored in SuperCollider.

So my question is:

Does anyone know the immediate source for the numerical values used in Tuning.werckmeister?

I can find support for the general Werckmeister III construction, but not for the exact decimal table used by SuperCollider.

If I have misunderstood something due to my limited ability in German (both modern and seventeenth‑century) or in modern English, or if I have made an error in the reconstruction, I would be grateful for clarification.

Thanks.

2 Likes

I just checked, and your calculations check out. I would simply say that in this case, the sc scale is “wrong” (if only by a cent or two). I don’t think it’s worth looking for the source for sc’s tuning; I can imagine a scenario where someone was pressed for time just copied something from the internet that seemed good enough…

1 Like

IMO having a global scale/tuning library was a mistake from the get-go, and should be considered a legacy feature. Not only is it impossible to correct errors without breaking backward compatibility, but it raises the questions of “what scales should be included in the standard library?” and “how do we encode tunings or scales that don’t have a centralized definition?” These are cultural and musicological questions that a computer music language shouldn’t be taking a stance on; it should not be the responsibility of the SC maintainers to define what scales are and which ones belong in the standard library. (Even if we were to restrict scales to ones that appear in peer-reviewed literature, there are multiple instances of scholarly resources on musicology getting things wrong, e.g. “The Myth of Equidistance in Thai Tuning”.)

For example, to revisit a peeve of mine, Scale.pelog is wildly incorrect — pelog is a tuning, not a scale, and is not a subset of 12edo, and varies considerably between different individual gamelan. And yet removing it would be a bad idea.

2 Likes

I agree almost fully, except that remark about peer-reviewed literature - I would argue that there isn’t a problem with the literature getting things wrong, but about the naming of scales. I.e., just don’t name it “Thai tuning” but “7TET Ellis 1885 (‘Thai’)”, note the scare quotes (but I haven’t read that article). Quoting literature is about identification of sources, not about that literature being right. The problem with sc’s collection of non-“western” scales is that the sources just aren’t identified.

I think that backward compatibility is a bit less painful of an issue in this case because scales and tunings are “soft”-defined (where methods are “hard”-defined, requiring a full library recompile to absorb changes). Pushing a permanent change to a scale or tuning may surprise users of legacy code (which isn’t ideal), but they could add a line or two at the top to write their own data into the scale/tuning library and revert to prior behavior, without changing the class library. (There’s no similar recourse for method changes.)

FWIW I agree with the comments about the existing scale dictionary’s academic rigor or lack thereof, though I’d also say that when I need to do something in Pure Data, I wish that it offered more out of the box in terms of scale mapping (where the “minimal core” design principle means that it offers nothing for this, short of installing some extension or rolling your own) – one can critique specific scale/tuning entries, and there are flaws to be found in the design, but I think it’s worth it to have something.

hjh