Music::Tension::PlompLevelt - Plomp-Levelt consonance curve calculations


  use Music::Tension::PlompLevelt;
  my $tension = Music::Tension::PlompLevelt->new;

  $tension->frequencies(440, 880);

  $tension->pitches(69, 81);

  $tension->vertical([qw/60 64 67/]);


Plomp-Levelt consonance curve calculations based on work by William Sethares and others ("SEE ALSO" for links).

Parsing music into a form suitable for use by this module and practical uses of the results are left as an exercise to the reader. Consult the eg/ directory of this module's distribution for example programs.


      Fundamental        Overtones
  Harmonic      1        2       3       4       5       6       7
      odds      o                o               o               o
      evens              e               e               e

  ly pitch      c,       c       g       c'      e'      g'      bes'
  MIDI number   36       48      55      60      64      67      70

  frequency     65.41    130.82  196.23  261.64  327.05  392.46  457.87
   equal temp.  65.41    130.81  196.00  261.63  329.63  392.00  466.16
  error         0        -0.01   -0.23   -0.01   +2.58   -0.46   +8.29

The calculations use some number of harmonics, depending on the amplitude profile used or the frequency information supplied. Finding details on the harmonics for a particular instrument may require consulting a book, or performing spectral analysis on recordings of a particular instrument (e.g. via Audacity), or fiddling around with a synthesizer, and likely making simplifying assumptions on what gets fed into this module.


Other music writers indicate that the partials should be ignored, for example Harry Partch: "Long experience... convinces me that it is preferable to ignore partials as a source of musical materials. The ear is not impressed by partials as such. The faculty--the prime faculty--of the ear is the perception of small-numbered intervals, 2/1, 3/2, 4/3, etc. and the ear cares not a whit whether these intervals are in or out of the overtone series." (Genesis of a Music, 1947). (However, note that this declamation predates the work by Sethares and others.)

On the plus side, this method does rate an augmented triad as more dissonant than a diminished triad (though that test was with distortions from equal temperament), which agrees with a study mentioned over in Music::Tension::Cope that the Cope method finds the opposite of.

See also "Harmony Perception: Harmoniousness is more than the sum of interval consonance" by Norman Cook (2009) though that method should probably be in a different module than this one.


Any method may croak if something is awry with the input. Methods are inherited from the parent class, Music::Tension. Unlike Music::Tension::Cope, this module is very sensitive to the register of the pitches involved, so input pitches should ideally be from the MIDI note numbers and in the proper register. Or instead use frequencies via methods that accept those (especially to avoid the distortions of equal temperament tuning).

The tension number depends heavily on the equation (and constants to said equation), and should not be considered comparable to any other tension modules in this distribution, and only to other tension values from this module if the same harmonics were used in all calculations. Also, the tension numbers could very easily change between releases of this module.

new optional params

Constructor. Accepts various optional parameters.

  my $tension = Music::Tension::PlompLevelt->new(
    amplitudes => {
      made_up_numbers => [ 42, 42, ... ],
    default_amp_profile => 'made_up_numbers',
    normalize_amps      => 1,
    reference_frequency => 442,
  • amplitudes specifies a hash reference that should contain named amplitude sets and an array reference of amplitude values for each harmonic.

  • default_amp_profile what amplitude profile to use by default. Available options pre-coded into the module include:

      pianowire-medium    * the default

    These all have amplitude values for six harmonics.

  • normalize_amps if true, normalizes the amplitude values such that they sum up to one.

  • reference_frequency sets the MIDI reference frequency, by default 440 (Hz). Used by pitch2freq conversion called by the pitches and vertical methods.

frequencies freq_or_ref1, freq_or_ref2

Method that accepts two frequencies, or two array references containing the harmonics and amplitudes of such. Returns tension as a number.

  # default harmonics will be filled in
  $tension->frequencies(440, 880);

  # custom harmonics
    [ {amp=>1,    freq=>440}, {amp=>0.5,  freq=>880},  ... ],
    [ {amp=>0.88, freq=>880}, ... ],

The harmonics need not be the same number, nor use the same frequencies nor amplitudes. This allows comparison of different frequencies bearing different harmonic profiles. The resulting tension numbers are not normalized to anything; making them range from zero to one can be solved something like:

  use List::Util qw/max/;

  my @results;
  for my $f ( 440 .. 880 ) {
    push @results, [ $f, $tension->frequencies( 440, $f ) ];
  my $max = max map $_->[1], @results;
  for my $r (@results) {
    printf "%.1f %.3f\n", $r->[0], $r->[1] / $max;

See the eg/ directory under this module's distribution for example code containing the above.

pitches pitch1, pitch2

Accepts two integers (ideally MIDI note numbers) and converts those to frequencies via pitch2freq and then calls frequencies with those values. Instead use frequencies if a non-equal temperament tuning is involved. Returns tension as a number.

vertical pitch_set

Given a pitch set (an array reference of integer pitch numbers that are ideally MIDI numbers), converts those pitches to frequencies via pitch2freq, then calls frequencies for the first pitch compared in turn with each subsequent in the set. In scalar context, returns the total tension, while in list context returns the total, min, max, and an array reference of individual tensions of the various intervals present.



thrig - Jeremy Mates (cpan:JMATES) <jmates at>


Copyright (C) 2012 by Jeremy Mates