Home > database >  How can I convert a periodic range into one range
How can I convert a periodic range into one range

Time:01-16

I'm searching for a function to convert sound frequency into a light frequency, or in other words a sound into a color.

For the moment I can achieve this by a simple formula that transposes the sound frequency to the light frequency range:

const lightFreq = frequency * Math.pow( 2, 40 );

Now if I want to have the wave length in nanometers I only need to do

const waveLength = 1 / lightFreq / 10000000;

One common analogy between sound and color would be to replicate this corresponding wavelength to each octaves. This would imply that if 440Hz is equal to a wavelength of approximately 640nm then the octave which is 880Hz would also be 640nm.

Using the function could look like:

soundFreqToLightWaveLength( 440 ) //approx.640
soundFreqToLightWaveLength( 880 ) //approx.640
soundFreqToLightWaveLength( 1760 ) //approx.640

waveLength range [380,780]

CodePudding user response:

In order to divide a frequency range into 9 divisions you will have to find the 9th root of the factor from lower to higher frequency:

let a=20,b=20000,n=9;
const fact=Math.pow(b/a,1/n);
console.log(a);
for (i=0; i<n; i  ) console.log(a*=fact)

Update, referring to the updated question:

The following snippet translates sound frequencies to light frequencies with an equivalence of 440HZ = 640nm. Within one octave: the higher the sound pitch, the shorter the wave length will be:

sound frequency / Hz wave length / nm
440 640
660 426.6666666666667
879.9999 320.0000363636406
880 640
1320 426.6666666666667
1760 640

let a=20,b=20000,n=12;

const A=440, lnA=Math.log2(A)%1;
const L=640; // base wave length

if(1)for (let n=35,f=20,f1=20000,fact=Math.pow(f1/f,1/n);n-->-1; f*=fact) {
 let l=(lnA-Math.log2(f))%1;
 let wl=Math.pow(2,l)*L // light wave length in nm
 console.log(f,wl)
}

The snippet goes throught the frequency range 20 ... 20000Hz in 35 steps (this can be changed to any value). The light wave lengths are mapped only for the fractional part (l=(lnA-Math.log2(f))%1) of the frequencies as the will repeat in each octave.

Clarification/question
Looking at OP's latest comment I now assume that the required behaviour would be to calculated according to the following diagram: enter image description here In the above example we can see that the whole frequency range (from lower value f0 to higher value f1) has been divided into 6 divisions (instead of octaves!), within each of which the sound frequencies will be mapped to the wave length in the range defined by wl0 (longest wave length) and wl1 (shortest wave length).

OP, is that what you had in mind?

CodePudding user response:

// outputs a number between 0 and 1, depending on whether the pitch
// is at the lower or upper end of an octave
// each semitone will be 1/12th of the way between 0 and 1
// the octave starts with an A note. Change the number 440
// to the frequency of another note if you want the octave
// to start at a different note
function freqToOctavePosition(freq) {
  return ((Math.log(freq/440)/Math.log(2) % 1)   1) % 1
}

// linearly converts the position within the octave to a position within a range
function freqToRange(freq, rangeStart, rangeEnd) {
  return (freqToOctavePosition(freq) * (rangeEnd-rangeStart))   rangeStart
}

console.log(freqToRange(262, 400, 700))

  • Related