SkillAgentSearch skills...

Dissonant

Musical chord dissonance models

Install / Use

/learn @bzamecnik/Dissonant
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Chord dissonance models

This package implements various models of perceptual chord dissonance. Given a musical chord composed of individual tones, each composed of partials, a dissonance model provides a score that estimate how dissonant (harsh) does it sound to human listener.

It contains implementation of several models of dissoance with corrections of errors found in the formulas in the papers. See below.

Installation

pip install dissonant

Why dissonant? PyPI package dissonance was already taken.

Usage

Dissonance of a C major chord with harmonic tones in 12-TET tuning with base 440 Hz using the Sethares1993 model:

from dissonant import harmonic_tone, dissonance, pitch_to_freq
freqs, amps = harmonic_tone(pitch_to_freq([0, 4, 7, 12]), n_partials=10)
d = dissonance(freqs, amps, model='sethares1993')

Dissonance curve of a sliding interval of two harmonic tones: see notebooks/dissonance_curve.ipynb.

Papers

Extra

  • 2001, McKinney et al. - Neural correlates of musical dissonance in the inferior colliculus
  • 2007, Vassilakis - SRA: A Web-based Research Tool for Spectral and Roughness Analysis of Sound Signals
    • http://musicalgorithms.ewu.edu/algorithms/Roughness.html
    • http://musicalgorithms.ewu.edu/learnmoresra/moremodel.html
  • Kameoka, A. & Kuriyagawa, M. (1969a). Consonance theory, part I: Consonance of dyads. Journal of the Acoustical Society of America, Vol. 45, No. 6, pp. 1451-1459.
  • Kameoka, A. & Kuriyagawa, M. (1969b). Consonance theory, part II: Consonance of complex tones and its computation method. Journal of the Acoustical Society of America, Vol. 45, No. 6, pp. 1460-1469.
  • Mashinter, Keith. (1995). Discrepancies in Theories of Sensory Dissonance arising from the Models of Kameoka & Kuriyagawa, and Hutchinson & Knopoff. Undergraduate thesis submitted for the double honours degrees in Applied Mathematics and Music, University of Waterloo.
  • Phil Keenan (@ingthrumath)
    • http://meandering-through-mathematics.blogspot.com/2015/03/consonance-and-dissonance-in-music.html
    • http://meandering-through-mathematics.blogspot.com/2016/06/experimenting-with-sounds-consonance.html

Other resources

  • https://en.wikipedia.org/wiki/Consonance_and_dissonance
  • http://www.res.kutc.kansai-u.ac.jp/~cook/
    • http://www.res.kutc.kansai-u.ac.jp/~cook/05%20harmony.html
    • http://www.res.kutc.kansai-u.ac.jp/~cook/Harmony.c
  • http://sethares.engr.wisc.edu/consemi.html#anchor149613
  • http://sethares.engr.wisc.edu/forrestjava/html/TuningAndTimbre.html
  • http://sethares.engr.wisc.edu/comprog.html - MATLAB, C++, Lisp
  • https://gist.github.com/endolith/3066664
  • http://www.davideverotta.com/A_folders/Theory/m_dissonance.html
  • http://www.music-cog.ohio-state.edu/Music829B/diss.html

Models

There are several acoustic models of dissonance. They may work on different data and provide several various metrics. All of them are based on some perceptual experiments.

Input signals:

  • two plain sinusoidal tones
  • two harmonic tones - integer multiples of the base frequency
  • chord (two or more) of harmonic tones
  • signals with continuous spectrum

PlompLevelt1965

They measured the perceived dissonance of pairs of sinusoidal tones and of complex tones with 6 harmonics. They provide only experimental data, not a parametric model.

Sethares1993

First, he explicitly parameterizes the data of PlompLevelt1965 (for a pair of sinusoids and for any number of complex tones) with constants found by fitting the curve to the data.

Dissonance d(x) for the difference x between a pair of frequencies. This ignores the absolute frequencies.

d(x) = exp(-a * x) - exp(-b * x)
Constants:
a = 3.5
b = 5.75

Dissonance for a pair of frequencies (f_1, f_2) (for f_1 < f_2) and their amplitudes (a_1, a_2). This takes into account the absolute frequencies. d_max is just the maximum of d(x).

d_pair(f_1, f_2, a_1, a_2) =
  s = d_max / (s_1 * f_1 + s_2)
  x = s * (f_2 - f_1)
  a_1 * a_2 * (exp(-a * x) - exp(-b * x))

Constants:
a = 3.5
b = 5.75
d_max = 0.24
s_1 = 0.0207 # 0.021 in the paper
s_2 = 18.96 # 19 in the paper

Expressed in terms of d(x):

d_pair(f_1, f_2, a_1, a_2) = a_1 * a_2 * d((f_2 - f_1) * d_max / (s_1 * f_1 + s_2))

Model of dissonance of a single complex tone (containing various partials) is just the sum of dissonances for all pairs of partials. In case the partials are integer multiples of a base frequency we can call tone "harmonic", otherwise just a general "timbre".

freqs = (f_1, f_2, ... f_n)
amps = (a_1, a_2, ... a_n)
d_complex(freqs, amps) = 0.5 * sum([d(f_i, f_j, a_i, a_j) for i in range(n) for j in range(n)])

or equally:

d_complex(freqs, amps) = sum([
  d(freqs[i], freqs[j], amps[i], amps[j])
  for i in range(n)
  for j in range(n)
  if i < j])

Then we can model dissonance of a pair of complex tones (timbres). Basically it's still a sum of dissonances of all pairs of partials. We can however express freqs_2 = alpha * freqs_1 and plot d_complex() for fixed freqs_1 and varying alpha to get a "dissonance curve".

Note that this model can be used to model dissonance of intervals of complex tones, as well as chords (any number of tones).

Note the constants s_1, s_2 are defined in the paper with low precision. Better precision is provided in the code by Mr. Sethares: http://sethares.engr.wisc.edu/comprog.html.

Questions?

Why we just sum the dissonance and not compute mean? Which aggregation operation makes more sense?

Vassilakis2001

There's a modification to the d_pair() function which should make it depend more reliably on "SPL" and "AF-degree", in particular put more accent on the relative amplitudes of interfering sinusoids rather than on thir absolute amplitudes.

Defined in Eq.(6.23) on page 197 (219 in the PDF).

a_2 should be >= a_1
d_pair(f_1, f_2, a_1, a_2) =
  (a_1 * a_2) ^ 0.1 * 0.5 *
  ((2 * a_2) / (a_1 + a_2)) ^ 3.11 *
  (exp(-a * s * (f_2 - f_1)) - exp(-b * s * (f_2 - f_1)))

Where:
spl = a_1 * a_2
af_degree = (2 * a_2) / (a_1 + a_2)
a = 3.5
b = 5.75
d_max = 0.24
s_1 = 0.0207
s_2 = 18.96

It can be expressed in terms of d(x):

d_pair(f_1, f_2, a_1, a_2) =
  spl = a_1 * a_2
  af_degree = (2 * a_2) / (a_1 + a_2)
  s = d_max / (s_1 * f_1 + s_2)
  x = s * (f_2 - f_1)
  spl ^ 0.1 * 0.5 * af_degree ^ 3.11 * d(x)

In comparison in the Sethares1993 model it is:

d_pair(f_1, f_2, a_1, a_2) =
  spl = a_1 * a_2
  s = d_max / (s_1 * f_1 + s_2)
  x = (f_2 - f_1) * x
  spl * d(x)

Note that in order to handle the case if a_1 < a_2 we could define:

af_degree(a_1, a_2) = (2 * min(a_1, a_2)) / (a_1 + a_2)

Looking at Vassilakis2010 this is exactly what they do, extending Vassilakis2001, otherwise the model is the same.

Extending this to a set of complex tones is the same as in Sethares1993 - just aggregate d_pair() for all pairs via a sum.

Note there's an additional 0.5 factor in the Vassilakis2001 model compared to Sethares1993. IMHO the meaning is to compensate for pairs of partials being summed twice. In order to make the models comparable we should remove this term and take only pairs of partials only once in all models.

Cook2002

Dissonance model (Cook2002, Appendix 2, page 276 and on, eg. A2-1):

Original - wrong:
d_pair(x, a_1, a_2)

Related Skills

View on GitHub
GitHub Stars29
CategoryDevelopment
Updated14d ago
Forks2

Languages

Jupyter Notebook

Security Score

90/100

Audited on Mar 26, 2026

No findings