The Schematic
The Refactored Code
[sourcecode language="c"]
// Optical Theramin
// pin definitions
#define PHONES 9 // headphones at digital pin 9
#define PHOTOCELL 0 // photocell at analog pin 0
// variable definitions
long val = 0; // stores raw value from photocell
long maxread = 0; // maximum value reset for calibration phase
long minread = 1000; // minimum value reset for calibration phase
double f = 0; // tone frequency
double logf = 0; // logarithm of normalized frequency
double normf = 0; // normalized frequency
int i = 0; // loop incrementer
int ilogf = 0; // rounded logarithm
int length = 0; // length of tone
double shift = 0; // shift for calibration
double factor = 0; // scaling factor for calibration
long maxfreq = 1048; // maximum desired frequency after calibration
long minfreq = 131; // minimum desired frequency after calibration
// magic numbers that make the intervals sound pleasing... sort of
double gap = 1.148698355; // ratio of consecutive notes (pentatonic)
// it's the 5th root of 2
// or as an alternative:
// double gap = 1.059463094; // ratio of consecutive notes (chromatic)
// its the 12th root of 2
void setup()
{
pinMode(PHONES, OUTPUT);
// calibration loop to determine a reasonable range of light levels (minread to maxread)
// then map that to frequencies between minfreq and maxfreq
for (i = 0; i< 500; i++) { // calibration loop runs for 5 seconds
val = analogRead(PHOTOCELL); // read photocell
tone(PHONES, val); // play raw tone to guide calibration
if (val > maxread) maxread = val; // as the values climb, store the largest
if (val < minread) minread = val; // as the values drop, store the smallest
delay(10);
}
// now we use the calibration to calculate scale and shift parameters
// scale parameter: it's like a slope
factor = (double)(maxfreq - minfreq) / (double)(maxread - minread);
// shift parameter: it's like an offset
shift = factor * minread - minfreq;
}
void loop()
{
val = analogRead(PHOTOCELL); // read photocell
length = random(10, 400); // generate random tone length
// this linearly maps the frequency to
// a value between minfreq and maxfreq
// according to the calibration result
f = factor * val - shift;
normf = f / (double) minfreq; // dividing an exponential function by the min value
logf = log(normf) / log(gap); // allows us to take the log (base gap) and the result
ilogf = round(logf); // is the number of notes above the lowest, once we round it.
f = minfreq * pow(gap,ilogf); // we better "unlog" it.
tone(PHONES, f, length);
}
[/sourcecode]
[...] Disclaimer: The code contained here is refactored code from user gwarbeh at Instructables.com. I'm posting this because I wanted to share the refactored code and a schematic that was missing on the... [...]
ReplyDelete[...] Disclaimer: The code contained here is refactored code from user gwarbeh at Instructables.com. I'm posting this because I wanted to share the refactored code and a schematic that was missing on the... [...]
ReplyDelete