slippery chicken’s automatic chord sequencing algorithm creates an ordering for a set-palette’s sets (or chords) based on user-given dissonance and spectral centroid envelopes. The terms set and chord here will be used interchangeably to mean essentially the same thing (a collection of pitches to be used harmonically), though in both music theory and in slippery chicken’s object-oriented programme design they are different (e.g. in slippery chicken the chord class is the superclass of the sc-set class, which, as you might expect, has more functionality than chord).
In this context and elsewhere in slippery chicken, an envelope is an arbitrary length list of x,y breakpoint pairs. For sequencing purposes, the x-axis ranges over the number of sets in the palette, though any arbitrary range can be passed by the user and it will be stretched/compressed to fit. The envelopes’ y-axis ranges should be 0.0 to 1.0 only; this will then be stretched to fit the range of dissonance and centroid values to be found by analysis of the palette’s sets. For a description of a set or chord’s dissonance or spectral centroid see below and/or calculate-spectral-centroid or calculate-dissonance.
The envelopes themselves describe a desired general tendency to, for example, proceed from less dissonant to more dissonant sets as the ordering (sequence) of sets proceeds. Such an envelope would move from lower to higher values, for example. Similarly with the spectral centroid envelope: moving from a lower to a higher value implies moving from sets with an overall lower pitch height to sets with a higher pitch height—or more accurately expressed, spectral energy.
Also taken into account when sequencing is the lowest pitch of the set. If :repeating-bass is NIL (the default) then the function tries to avoid repeating bass pitches in two consecutive sets. For rather traditional but, for me at least, still valid harmonic purposes this is deemed in most cases undesirable (repeating bass pitches tend to stagnate a progression). On the other hand, repeating highest pitches are always allowed.
the successive approach
The default method for creating this ordering from envelopes is what we might call successive. This means that we find the set which is closest to the two curves at any given point without considering whether that set would be best used elsewhere. This usually works fairly well; it’s also the method used in my jitterbug project, for which the algorithm was developed.
The successive approach selects sets via a sort function which compares their characteristics to those of the current envelope values. Essentially, when we are comparing two sets via the sort function we look at the deviation between the sets’ dissonance values and the current desired dissonance value as taken from the given envelope; we then apply the same process to the spectral centroid and its envelope. The set with the smallest combined deviation will be chosen. If either envelope is nil, then the sorting is based on the other envelope only. Similarly, weighting factors of any arbitrary positive number can be passed via :dissonance-weight and :centroid-weight to emphasise or deemphasise these properties when sorting using both envelopes. Higher values result in that property taking precedence over the other property.
The advantage of this method is that it is relatively quick. The disadvantage is that it tends to find the best fits at the beginning of the process but as it proceeds along the envelope and we run out of sets to select from, the fit can become worse and worse. Of course, this depends on the number and characteristics of the sets as well as the envelope shapes.
the permutation approach
An alternative method, as indicated by the :permutate keyword, is to get all (or at least a lot of) permutations of the sets in the palette and then score each ordering against the curves, as a form of fitness test. The advantage of this approach is that the best solution overall can be found, i.e. it’s not blind to what’s coming, like the successive method. The disadvantage is that given a large number of sets to sequence, we either have to accept comparing less permutations and thus missing the best fit (which the successive method may well return) or wait a fairly long time, depending on your computing resources, for the routine to search and score all possibilities. I should note though that on my Mid 2015 Macbook, searching all 362880 permutations (9 factorial) of a 9-set palette still only takes a couple of seconds.
In any case, with either method there is no guarantee that the desired curves will be expressed exactly in the returned ordering. The routine tries to find the best fit but the success depends very much on the nature and number of sets as well as the envelopes and other data passed.
A chord or set’s dissonance is calculated using a roughness calculation model which has been perceptually verified by its inventor, Pantelis N. Vassilakis. When sequencing, we use the set pitches’ theoretical spectral data to sum the roughness of sine pairs up to, by default, the first 12 partials of each pitch, i.e. every partial of every pitch is calculated in relation to all other pitches’ partials, taking their amplitudes into account. The number of partials used can be changed via the :num-partials keyword argument to the calculate-dissonance method.
By default, but user-switchable, a spectrum-averaging method is used in order to avoid some of the vagaries of the spectral data. As there can be considerable variation in analyses between performances of the same pitch or pitches in close proximity, the average spectrum of any pitch is taken by placing it at the centre of an octave of spectral data and calculating the numerical mean for each partials’ frequency and amplitude values.
A different method of averaging can also be used. Any spectral data created by analysis within slippery chicken (such as the akoustik-piano and violin-ensemble data) will always average spectra attained by analysis at three points within the source sound file. These are 300, 400, and 500 milliseconds by default, thus the starting onset transient—with all the concomitant percussive and other inharmonic spectral components common to many instruments, pitched or not—is skipped.
piano by default
Unless instructed otherwise, the calculation returns the dissonance of a set as if it were played on the piano. slippery chicken includes two sets of piano spectral data as well as violin ensemble data. (A comparison of piano and violin spectra is made in part two of this post.) Other data sets can be used if supplied by the caller.
Data does not have to be available for every pitch in the whole range of the sets as the method will use the nearest pitch data whenever a pitch is found missing in the spectral data supplied. The slippery chicken file spectra.lsp contains the functionality and a description of how to use and create your own spectral data, as well as the default data.
Whichever spectra we use when performing the calculation, the roughness created by every desired partial of every set pitch in relation to all other pitches’ partials is calculated, taking their amplitudes into account of course.
The following examples illustrate the spectrally informed dissonance calculation technique. If we were doing a simple intervallic dissonance calculation then the two chords C Major and D Major would return the same dissonance values. Because we take a spectral approach, where the relative strength of the pitches’ partials and their place in the audible spectrum play roles, the D Major chord (set 2 below), being a tone higher, has a slightly lower dissonance value (0.41) than C major (0.48) in the same octave (set 1). This makes abundantly and immediately clear that the results are dependent on pitch height or register.
This is seen more extremely by comparing the same C major chord in the fourth octave (set 1: 0.48) with the same in the third (5: 1.27) and second octaves (4: 1.73). Dissonance levels are significantly higher in the lower octaves due to strong partial interference in lower, clearly audible parts of the spectrum. This is borne out in the practice of classical chord voicing: triads are unlikely to be found in close position in lower octaves, whether in the piano, orchestra, or any other ensemble.
What the example contradicts is the common assertion that minor triads are more dissonant than major. This is usually explained as arising from interference in the minor triad between the fifth partial of the fundamental (a major third) and the octave partials of the minor third. The difference here is not so striking but still, C Minor’s value (3) is 0.47 whereas C major’s (1) is 0.48.
A more surprising, or perhaps even questionable result for some, is the lower dissonance value (0.82) for the fourth-octave C Major Major 7th chord (6) than for a simple C Major triad an octave lower (5: 1.27). Similarly surprising (or is it?) is that the last fourth-octave atonal chord (7) has a dissonance value of 1.74, this being only very slightly higher than the simple C Major triad in the second octave (4: 1.73). This is all piano data though:
(loop for chord in '((c4 e4 g4) (d4 fs4 a4) (c4 ef4 g4) (c2 e2 g2) (c3 e3 g3) (c4 e4 g4 b4) (c4 e4 g4 b4 cs4)) collect (calculate-dissonance (make-chord chord) :num-partials 12)) —> (0.479236669842893d0 0.4120519033679814d0 0.46821850015425676d0 1.7258937394522205d0 1.2686772397038624d0 0.8219314929076079d0 1.741925271398224d0)
These values change of course if we switch to the violin spectra and redo the calculations:
set piano violin 1: (c4 e4 g4) 0.48 0.59 2: (d4 fs4 a4) 0.41 0.57 3: (c4 ef4 g4) 0.47 0.63 4: (c2 e2 g2) 1.73 1.5 5: (c3 e3 g3) 1.27 0.82 6: (c4 e4 g4 b4) 0.82 1.05 7: (c4 e4 g4 b4 cs4) 1.74 2.29
We see significant variation here. Most striking is that the C Minor triad (3: 0.63) is now more dissonant than the major (1: 0.59). The C Major Major 7th chord (6) is also now more dissonant (1.05) than the C Major triad an octave lower (5: 0.82). This perhaps tallies more with expectations informed by the rules of functional tonal harmony. Similarly the last atonal chord (7: 2.29) is now significantly more dissonant than the second octave C Major triad (4: 1.5). However some things remain the same: the C Major triads still become very much more dissonant as they move down from octave 4 to 3 to 2.
What does all this tell us? That the calculations are arbitrary and therefore not reliable? Not at all, in my view. On the contrary, it tells us that dissonance is a function of spectral qualities and interactions and that these will vary from instrument to instrument. A conventional theory of functional or even atonal harmony obfuscates that a little, with an over-concentration on intervals at the expense of timbre and register. It also tells us perhaps that the overtone structure of the violin, being bowed, is more harmonic than the percussive piano spectra (whose strings, as they become higher, act more like rods and less like strings, thus making the harmonics more inharmonic).
spectral centroid calculation
This concept is of course borrowed from digital signal processing (DSP). The spectral centroid calculation, when applied to an audio signal, usually involves a Fast Fourier Transform (FFT). It’s therefore perhaps a little strange to calculate the theoretical spectral centroid of pitch data alone—questionable even, given that we will not be taking into account any phase information and thus ignoring possible partial cancelling or attenuation. Neither will we be using the FFT. Nevertheless I think we get a good indication of the pitch height of a set or chord via this method.
As with the dissonance calculation, piano spectral data are used by default, as are 12 partials. Both of these can be changed via their respective keyword arguments when the method is called. We assume that all pitches of a set are played at the same dynamic (to the extent that this is encoded in the spectral data at least). The method returns the centroid in Hertz via a simple averaging technique which involves summing the multiple of partial frequencies by their amplitudes before dividing by the sum of the partial amplitudes alone. We can immediately see the calculation in action on two very similar sets, the second of which has one extra pitch, a minor third above the first’s highest pitch:
(calculate-spectral-centroid (make-chord '(fs3 c4 cs4 d4 ds4 e4))) —> 596.81 (calculate-spectral-centroid (make-chord '(fs3 c4 cs4 d4 ds4 e4 g6))) —> 674.84
As we might expect, the spectral centroid rises by a statistically significant amount when we add the higher pitch. What might not be quite so expected is how low a pitch we’d have to add to this second set in order to take the centroid back close to the first set’s value. Thinking purely intervallically, we might imagine that adding D#3 might suffice, that is, because we added a pitch a minor third above the highest pitch, then adding one a minor third below the lowest might balance things out. The result of this however shows just how wrong such intervallic thinking is here.
(calculate-spectral-centroid (make-chord '(ds3 fs3 c4 cs4 d4 ds4 e4 g6))) —>634.14
Thinking spectrally—especially with regards to the piano and other instruments perhaps, where as we go lower and lower in range the fundamentals tend to grow weaker with respect to the higher partials—it becomes clear that we’d have to add a significantly lower pitch in order to bring the spectral centroid to about the same value as the original set’s. In this particular case we have to add G2, a whole major 7th below the former lowest pitch in order to accomplish this:
(calculate-spectral-centroid (make-chord '(g2 fs3 c4 cs4 d4 ds4 e4 g6))) —>597.57