DOTLETH V2.0

Currently just for fun

Scales

What a scale is and how it's calculated i'll leave to others to explain, here is a couple of links.

Don't disregard cycle fractions!

If you generate signals at 44100hz (cd quality), then you'll have a scale table that look like the table below (only first and last octave is shown). In the table you can see that C-0 has a frequency of 16.35, which means that in 1 second the signal has to traverse from positive to negative and back 16.35 times, which leads to a cycle size of 44100/16.35=2696.98. As you can also see in the table is that in the lower spectrum the decimal fraction of the cycle size is not very dominant but in the high spectrum the case is very different. So don't disregard the fraction!!!

Also think about this fact when you apply vibrato. Vibrato is typically a fraction of a note in strength. So if you round cycle size when applying vibrato it will typically be unhearable in octave 5 and up.

Note IdxNameFreqCycles Note IdxNameFreqCycles
0C-016.352696.9884C-72093.0021.07
1C#017.322545.6185C#72217.4619.89
2D-018.352402.7486D-72349.3218.77
3D#019.452267.8887D#72489.0217.72
4E-020.602140.6088E-72637.0216.72
5F-021.832020.4689F-72793.8315.78
6F#023.121907.0690F#72959.9614.90
7G-024.501800.0291G-73135.9614.06
8G#025.961698.9992G#73322.4413.27
9A-027.501603.6493A-73520.0012.53
10A#029.141513.6394A#73729.3111.83
11B-030.871428.6895B-73951.0711.16
Table: Equally Tempered Scale

Since it's not just good enough to truncate the cycle sizes, you can easily hear that for high pitch notes (trust me i tried) you have to find another way to map values from your oscillator signal buffer to your output. What i did was to use fixed point integer math to create a pointer into a 64K signal buffer which corresponds to a cycle of my oscillator. the incremenent value of this pointer is buffersize/(samplefrequency/freq) which of course should be scaled with your fixed int precision. In my case that's 65536/44100/freq.

Calculate your scale with necessary precision!

I made the mistake of using java float to calculate the scale in an early version of my code, this lead to some notable rounding errors.

Source code

Here is the source code for calculating the frequences for a western scale.
/*
Copyright (C) 2005  Claus Leth Gregersen (sound@dotleth.dk)

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


package dk.dotleth.sound.scale;

/**
 * @author Claus Leth Gregersen
 *
 */
public class EquallyTempered12ToneScale {
	private float[] scale;
	private float detune = 1;
	// this is the frequency of the A below our first note (C-0)
	private double BASE_FREQ = 440.0f / (1<<5); 
	
	public EquallyTempered12ToneScale() {
		this(1.0f);
	}
	
	public EquallyTempered12ToneScale(float detune) {
		double aFreq = BASE_FREQ;
		// 12th root of 2 with plenty digits!
		double factor = 1.0594630943592952645618252949463;
		// we need to transpose the A to C-0
		double currentC = aFreq*factor*factor*factor; 
		
		scale = new float[10*12];
		for (int oct = 0; oct < 10; oct++) {
			double currentFreq = currentC;
			for (int i = 0; i < 12; i++) {
				scale[oct * 12 + i] = (float) currentFreq;
				currentFreq = currentFreq * factor;
			}
			currentC *= 2; 	
		}
	}
	
	public void setDetune(float detune) {
		this.detune = detune;
		
	}
	public float getMiddleA() {
		return (float) (BASE_FREQ *(1<<5) * detune);
	}
	/**
	 * 
	 * @param value the note index in range 0-120 where 0 = lowest c0, 
	 * 1 = lowest c#0, 2 = d0, 12 = c1, 24 = c2 etc..
	 * @return frequency in hz
	 */
	public float getFrequency(int value) {
		return detune * scale[value];
	}
}

Side Projects


SYNTH: Jukebox



ARCADE: Mega Meteors



ARCADE: Gyros