Monday, January 1, 2018

Musical harmony

When something that is vibrating comes in contact with the air, it can create sound which consists of compressions and decompressions of air that travel at about 343 meters per second.
We could visualise it as follows:
That image shows a simulation of a snapshot of compressions that are moving horizontally. One of the primary formulae in acoustics is: \[\lambda = \frac{c}{\nu}\] In other words the wavelength is equal to the speed of sound over the frequency.
So, if you double the frequency then you halve the wavelength.
In musical terminology, doubling the frequency is called going up one octave.
We could construct a geometric series of frequencies with: \[\nu_i = \nu_0 \alpha^i \] If we were to consider wavelengths, rather than frequencies, then we would have: \[\lambda_i = \frac{ \lambda_0 }{ \alpha^i} \] Suppose we set \(\nu_{12}\) to be one octave above \(\nu_0\),
then \[2 \large{\nu}_0 = \large{\nu}_{12} = \large{\nu}_0 \alpha^{12} \] and so, after doing a little algebra, we find: \[\alpha = 2^{ \frac{1}{12}} \] If we have 12 semitones in an octave, this might seem like a sensible choice of ratio between adjacent notes.
Now suppose we play two notes at the same time, perhaps \(\nu_0\) and \(\nu_6\). We find \[\nu_6 = \nu_0 \alpha^6 = \nu_0 \sqrt{2}\] or writing that in terms of wavelengths: \[\lambda_6 = \frac{\lambda_0} { \alpha^6} = \frac{\lambda_0} {\sqrt{2}}\] Suppose we could find two integers \(n_0\) and \(n_6\) such that \[\frac{n_0}{n_6} = \frac{\lambda_6}{\lambda_0} = \sqrt{2}\] then the pattern of interference between the two notes would repeat after
\(n_0\) cycles of the note with wavelength \(\lambda_0\) and
\(n_6\) cycles of the note with wavelength \(\lambda_6\).
Alas the problem is that \(\sqrt{2}\) is irrational so integers \(n_0\) and \(n_6\) don't exists. Hence the pattern of interference between the waves won't repeat regularly. A musician might say that they don't harmonize well.
Here is a visualiation of those two notes combining:
If you look carefully at that image, you'll see the irregularity. Those two notes combine, causing constructive and destructive interference in an irregular pattern.

Unfortunately \(2^{\frac{1}{12}} \) is also irrational. So when we use that as the ratio between adjacent semitones we are going to have a difficult time finding notes that will perfectly harmonize. ( Assuming we define harmony to be a regular repeating pattern of interference ). So it might make sense to tweak our semitones to aid harmony!
Suppose we had two notes A and B, with frequencies \(\nu_A \) and \(\nu_B \) and wavelengths \(\lambda_A \) and \(\lambda_B \) and suppose also that we can find two small integers \(n_A\) and \(n_B\) such that: \[ n_A \lambda_A = n_B \lambda_B \] and so \[ \frac{\nu_A}{n_A} = \frac{\nu_B}{n_B}\] then we will be able to find a nice harmony.
For example if we have: \[\frac{n_B}{n_A}=\frac{2}{3} = \frac{\lambda_A}{\lambda_B} = \frac{\nu_B}{\nu_A} \] then we get a nice regular pattern, which can be visualised as follows:
Note the precise repetition in that image above.

The images in this post were generated using the following R code:
  
# Author: Philip Kinlen, Jan 2018
library(grid) # required for grid.raster(.)

################################################################
getSinMatAB <- function( numCols,  numRows, 
                         redA1,    greenA1, blueA1, 
                         redA2,    greenA2, blueA2, 
                         redB1,    greenB1, blueB1, 
                         redB2,    greenB2, blueB2, 
                         phaseA,   phaseB,
                         periodsA, periodsB){
  
  xArr            <- (0:(numCols-1)) / numCols
  
  xMat            <- matrix(rep(xArr, numRows), numRows, numCols, F)  
  
  alphaA          <- periodsA * 2 * pi
  redA            <- matrix(mapply(pixelFn,   xMat, phaseA, alphaA, redA1,   redA2   ), numRows, numCols, T)
  greenA          <- matrix(mapply(pixelFn,   xMat, phaseA, alphaA, greenA1, greenA2 ), numRows, numCols, T)
  blueA           <- matrix(mapply(pixelFn,   xMat, phaseA, alphaA, blueA1,  blueA2  ), numRows, numCols, T)
  
  alphaB          <- periodsB * 2 * pi
  redB            <- matrix(mapply(pixelFn,   xMat, phaseB, alphaB, redB1,   redB2   ), numRows, numCols, T)
  greenB          <- matrix(mapply(pixelFn,   xMat, phaseB, alphaB, greenB1, greenB2 ), numRows, numCols, T)
  blueB           <- matrix(mapply(pixelFn,   xMat, phaseB, alphaB, blueB1,  blueB2  ), numRows, numCols, T)
  
  red             <- 0.5 * ( redA   + redB   )
  green           <- 0.5 * ( greenA + greenB )
  blue            <- 0.5 * ( blueA  + blueB  )
  
  img             <- rgb(red, green, blue)
  dim(img)        <- dim(red)
  
  return ( img )
  
}
################################################################
pixelFn <- function (z, phase, alpha, val1, val2){
    return  ( val1 + (val2 - val1) * ( sin ( phase + z * alpha) + 1) * 0.5 )
}
################################################################
plotSin <- function () {  
   
   numCols         <- 1000
   numRows         <- 200
   
   ## colors are in the range 0 to 1 inclusive.
   redA1           <- 1
   greenA1         <- 1
   blueA1          <- 1
   
   redA2           <- 0
   greenA2         <- 0
   blueA2          <- 0
   
   redB1           <- 1
   greenB1         <- 1
   blueB1          <- 1
   
   redB2           <- 0
   greenB2         <- 0
   blueB2          <- 0

   phaseA          <- pi 
   phaseB          <- pi

   wavelengthRatio <- sqrt(2)

   periodsA        <- 15
   periodsB        <- periodsA * wavelengthRatio 
   
   img             <- getSinMatAB ( numCols,  numRows, 
                                    redA1,    greenA1, blueA1, 
                                    redA2,    greenA2, blueA2, 
                                    redB1,    greenB1, blueB1, 
                                    redB2,    greenB2, blueB2, 
                                    phaseA,   phaseB,
                                    periodsA, periodsB)
    
   doSmoothing   <- F
   grid.raster(img, interpolate=doSmoothing)
}
################################################################


  

No comments: