Electromagnetic Monochords
La ley de los movimientos en el cosmos es la misma que la de los sonidos en la escala musical [...] tal es la tesis original del pitagorismo. – José Vasconcelos
Abstract
Los monocordios electromagnéticos son un instrumento capaz de demostrar el fenómeno de los armónicos naturales en la vibración de una cuerda, just a knob turn away from each other! ...Wow!
Discussion
Cuatro cuerdas tensadas son excitadas con un electroimán de 5V que oscila en frecuencias simpáticas a la frecuencia fundamental de la cuerda. El intérprete navega un rango electromagnético en busca de armónicos naturales, propios de la vibración de la cuerda.
Acompañando las cuerdas tensadas, los electroimanes y pastillas de guitarra eléctrica, diseñamos un control box; un control center para mandar señales eléctricas a los imanes –así ofreciendo una interface análoga divertida e intuitiva de usar.
La caja de control está equipada con dos diferentes presets: "free" [continuous integers] y "harmonic" [multiples of a fundamental]. Dependiendo del humor del intérprete: navegará el espacio armónico de manera controlada, o de manera libre? También integrados en la caja hay un on/off switch for each electroimán, y control de volumen y tono de las pastillas.
Un laboratorio de armónicos, capaz de generar un canto polifónico entre las resonancias naturales de cuatro cuerdas. Con esta herramienta, el armónico pasa de ser concepto, o número, a resonancia en un cuerpo.
Source Code & Specifications
En la versión actual, usamos un (1) Arduino Nano™ para controlar dos (2) monocordios. (O, con más precisión, se usa un Arduino para controlar the rate at which two electromagnets are cycling on & off, which in turn sympathetically vibrate the respective chords under which they are mounted.)
Below, you'll find the current source code.
/*
DUAL MONOCHORD CODE v3 :: 24 IV 14
by Dra. 8000
*/
#include <Encoder.h>
#include <Tone.h>
#include <TM1637Display.h>
// for best performance tie the first pin of each encoder
// to an interrupt pin
// [ nano only has interrupts on pins 2 & 3 ]
// so we'll give one to each encoder
Encoder enc1(2, 4);
Encoder enc2(3, 5);
// ENCODER VARS
long enc1Old = -999;
long enc2Old = -999;
long enc1Curr;
long enc2Curr;
long encOffset = 79;
long encSteps = 4;
TM1637Display display1(6, 7); // clk, dio
TM1637Display display2(11, 12); //clk, dio
uint8_t blank[] = { 0x00, 0x00, 0x00, 0x00 };
Tone tone1;
Tone tone2;
// power switches
const int sPow1 = A0;
const int sPow2 = A1;
// rotary function switches
const int sFun1 = A2;
const int sFun2 = A3;
// pots
const int potPin1 = A6;
const int potPin2 = A7;
int pot1 = 0;
int pot2 = 0;
// set fundamentals
const int f1 = 82;
const int f2 = 82;
// frequencies
long freq1;
long freq2;
// track rot vs pot
bool chaos1 = false;
bool chaos2 = false;
int hStep1 = 1;
int hStep2 = 1;
void setup() {
Serial.begin(9600);
// init tones
tone1.begin(10);
tone2.begin(9);
// init power switches
pinMode(sPow1, INPUT);
pinMode(sPow2, INPUT);
digitalWrite(sPow1, HIGH);
digitalWrite(sPow2, HIGH);
// init function switches [HIGH = rotary]
pinMode(sFun1, INPUT);
pinMode(sFun2, INPUT);
digitalWrite(sFun1, HIGH);
digitalWrite(sFun2, HIGH);
// init frequencies to fundamental
freq1 = f1;
freq2 = f2;
enc1.write(freq1 * encSteps);
enc2.write(freq2 * encSteps);
}
void loop() {
if (digitalRead(sPow1) == LOW) {
// Serial.println("on");
updateDisplay(display1, freq1);
if (digitalRead(sFun1) == LOW) {
potFreq1();
chaos1 = true;
} else {
rotFreq1();
chaos1 = false;
}
// send frequency to tone
tone1.play(freq1);
} else {
blankDisplay(display1);
tone1.stop();
}
if (digitalRead(sPow2) == LOW) {
updateDisplay(display2, freq2);
if (digitalRead(sFun2) == LOW) {
potFreq2();
chaos2 = true;
} else {
rotFreq2();
chaos2 = false;
}
// send frequency to tone
tone2.play(freq2);
} else {
blankDisplay(display2);
tone2.stop();
}
}
void potFreq1() {
// freq1 = random(82, 328);
// first time (back) in pot mode
if (chaos1 == false) {
Serial.println("(back) in pot mode");
// set enc to last harmonic step
enc1.write(hStep1);
}
if (getEncPosition(enc1) != hStep1) {
hStep1 = getEncPosition(enc1);
}
// map pot value between 0 - fundamental
pot1 = map(analogRead(potPin1), 0, 1023, 0, f1);
// scale pot value by harmonic step
pot1 += f1 * hStep1;
freq1 = pot1;
updateDisplay(display1, freq1);
}
void potFreq2() {
// first time (back) in pot mode
if (chaos2 == false) {
// set enc to last harmonic step
enc2.write(hStep2);
}
if (getEncPosition(enc2) != hStep2) {
hStep2 = getEncPosition(enc2);
}
// map pot value between 0 - fundamental
pot2 = map(analogRead(potPin2), 0, 1023, 0, f2);
// scale pot value by harmonic step
pot2 += f2 * hStep2;
freq2 = pot2;
updateDisplay(display2, freq2);
}
void rotFreq1() {
enc1Curr = getEncPosition(enc1);
// reset encoder to current freq if switiching back to Hz-by-Hz mode
if (chaos1 == true) {
enc1Curr = freq1;
enc1.write(freq1 * encSteps);
} else if (enc1Curr != freq1) {
freq1 = enc1Curr;
}
updateDisplay(display1, freq1);
}
void rotFreq2() {
enc2Curr = getEncPosition(enc2);
// reset encoder to current freq if switiching back to Hz-by-Hz mode
if (chaos2 == true) {
enc2Curr = freq2;
enc2.write(freq2 * encSteps);
} else if (enc2Curr != freq2) {
freq2 = enc2Curr;
}
updateDisplay(display2, freq2);
}
long getEncPosition(Encoder enc) {
// scale for 4 steps/detent encoder
long val = enc.read()/encSteps;
// lowest possible value = 1
if (val < 1) {
val = 1;
enc.write(1);
}
return val;
}
void updateDisplay(TM1637Display display, long val) {
int nDigits = floor(log10(abs(val))) + 1;
uint8_t disp[] = { 0x00, 0x00, 0x00, 0x00 };
for (int i = 0; i < nDigits; i++) {
// get current encoder value digit-by-digit
char cdigit = nthdigit(val, i);
int digit = cdigit - '0';
// encode each digit for display
disp[3-i] = display.encodeDigit(digit);
}
display.setBrightness(1);
display.setSegments(disp);
}
char nthdigit(int x, int n) {
static int powersof10[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
return ((x / powersof10[n]) % 10) + '0';
}
void blankDisplay(TM1637Display display) {
uint8_t disp[] = { 0x00, 0x00, 0x00, 0x00 };
display.setSegments(disp);
}