THE IDEA: A handsome little tactile body with included speaker, rows of "frets" and a strum area are capicitive inputs. Turn it on and doodle around. If i get punchy i'll add MIDI, that shouldn't be hard.
STATUS: Early going. I've frustrated myself but remain optimistic.
I'm less confident this is a Karplus-Strong but more confident it'll do something like what i want. (SAVE THAT it's nothing like specific to the actual hardware)
// boneheaded implementation of karplus-strong alg.:// 3 "strings" are basically a pointer (p) into a register// the pointer advances once every so-many micros// look up what "so-many" is based on which-if-any fret is held down// usually the entry at p gets overridden by the average of p+1 and p+2 and then output// on pluck, start instead overriding by the average of p+1, p+2 and a random value and do that for a while.// half a cycle? man, i dunno. i'm starting w/just plucks plucked// seeeduino xiao has 32KB RAM: 10k of 1B samples in 3 arrays leaves plenty of overhead// but would require a better meaurement than micros() to get through a whole register in 1s/freq// "physical" parameters of the system:uint8_t registerA[1000], pluckedA;
unsignedint pointerA, durationA;
uint8_t registerB[1000], pluckedB;
unsignedint pointerB, durationB;
uint8_t registerC[1000], pluckedC;
unsignedint pointerC, durationC;
//time and timing:unsignedlong t, startA, startB, startC;
//pin assignation: ENTIRELY FAKEconstuint8_t pluckA = 1;
constuint8_t pluckC = 2;
constuint8_t pluckB = 3;
constuint8_t out = 4;
int c; //counting variablevoidsetup(){
durationA = 3034;
durationB = 4050;
durationC = 5102;
// ugh, duration math should go behind an interrupt probs// oh, interrupt pins don't wanna be common/short maybs
pointerA = 1; pointerB = 1; pointerC = 1;
}
voidloop(){
// find out where we are, see if it's where we 'posed'a be:
t = micros();
if (pointerA > 999) {
pointerA = 1;
startA = t;
pluckedA--;
} else {
while ((t - startA)>(pointerA * (durationA / 1000))) pointerA++; // if that pointer's behind where it should be increment it until it's not// where t-startA is time passed, pA*(dA/1000) is what the pointer says is time passed// and the wrong variable names are way easier to read
}
if (pointerB > 999) {
pointerB = 1;
startB = t;
pluckedB--;
} else {
while ((t - startB)>(pointerB * (durationB / 1000))) pointerB++; // ditto this'n
}
if (pointerC > 999) {
pointerC = 1;
startC = t;
pluckedC--;
} else {
while ((t - startC)>(pointerC * (durationC / 1000))) pointerC++; // ditto that'n
}
// read pins and add pluckage if necc.:// ((will never fill >50% in a row, will often fill >50% with gaps -- UNWANTED BEHAVIOR?))if ((!pluckedA) & (!digitalRead(pluckA))) {
pluckedA = 2;
for (c = 1; c < 500; c++) {
if ((pointerA + c) <= 1000) {registerA[pointerA + c] = ((registerA[pointerA + c] + random(256)) / 2);}
else {registerA[pointerA + c - 999] = ((registerA[pointerA + c - 999] + random(256)) / 2);}
}
}
if ((!pluckedB) & (!digitalRead(pluckB))) {
pluckedB = 2;
for (c = 1; c < 500; c++) {
if ((pointerB + c) <= 1000) {registerB[pointerB + c] = ((registerB[pointerB + c] + random(256)) / 2);}
else {registerB[pointerB + c - 999] = ((registerB[pointerB + c - 999] + random(256)) / 2);}
}
}
if ((!pluckedC) & (!digitalRead(pluckC))) {
pluckedC = 2;
for (c = 1; c < 500; c++) {
if ((pointerC + c) <= 1000) {registerC[pointerC + c] = ((registerC[pointerC + c] + random(256)) / 2);}
else {registerC[pointerC + c - 999] = ((registerC[pointerC + c - 999] + random(256)) / 2);}
}
}
// do the actual work:if (pointerA = 1000) {registerA[1000] = ((registerA[1000] + registerA[1]) / 2);}
else {registerA[pointerA] = ((registerA[pointerA] + registerA[pointerA + 1]) / 2);}
if (pointerB = 1000) {registerB[1000] = ((registerB[1000] + registerB[1]) / 2);}
else {registerB[pointerB] = ((registerB[pointerB] + registerB[pointerB + 1]) / 2);}
if (pointerC = 1000) {registerC[1000] = ((registerC[1000] + registerC[1]) / 2);}
else {registerC[pointerC] = ((registerC[pointerC] + registerC[pointerC + 1]) / 2);}
analogWrite(out, ((registerA[pointerA] + registerB[pointerB] + registerC[pointerC]) / 3)); // is averaging these correct?
}
The '121s are across some male header. That shouldn't short anything that shouldn't be, right? Then i've jumped the address pins of two of them to what should be the right points to make them enumerate right. All the soldering looks good to me, i don't think the hardware's bad.
I threw this code together but the thing just whines. I don't think i'm crazy with the timing, i think it should be audible if it's recognizing input. Maybe the '121s draw too much power, i didn't check that.
#include<Wire.h>#include"Adafruit_MPR121.h"constuint8_t freq1 = 300;
constuint8_t freq2 = 400;
constuint8_t freq3 = 500;
constuint8_t numberoffrets = 12;
unsignedlong t;
unsignedlong oldmicros;
int string1[freq1];
int string2[freq2];
int string3[freq3];
uint8_t c;
Adafruit_MPR121 cap1 = Adafruit_MPR121();
Adafruit_MPR121 cap2 = Adafruit_MPR121();
Adafruit_MPR121 cap3 = Adafruit_MPR121();
voidsetup(){
delay(100);
pinMode(1, OUTPUT);
Wire.begin();
if (!cap1.begin(0x5a)) while(1);
if (!cap2.begin(0x5b)) while(1);
if (!cap3.begin(0x5c)) while(1);
//cap2.begin(0x5b);//cap3.begin(0x5c);//wire.begin(0x5A);//wire.begin(0x5B);//wire.begin(0x5C);
}
voidloop(){
t = micros();
if (t > oldmicros+1000) {
for (uint8_t fret=1; fret < numberoffrets; fret++){
if (cap1.touched() & (1 << fret)) {for(uint8_t c=1; c < freq1/2; c++){string1[c] = (random(2^16)-2^8);}}
if (cap2.touched() & (1 << fret)) {for(uint8_t c=1; c < freq2/2; c++){string2[c] = (random(2^16)-2^8);}}
if (cap3.touched() & (1 << fret)) {for(uint8_t c=1; c < freq3/2; c++){string3[c] = (random(2^16)-2^8);}}
oldmicros=0;}
for(uint8_t c=1; c<freq1; c++){string1[1] = (string1[2]+string1[3])/2);}
for(uint8_t c=1; c<freq2; c++){string2[1] = (string2[2]+string2[3])/2);}
for(uint8_t c=1; c<freq3; c++){string3[1] = (string3[2]+string3[3])/2);}
analogWrite(1, string1[1]+string2[1]+string3[1] / 3);
}
It should be an implementation of the Karplus-Strong algorithm but i'm staring at the void. Next step is serial feedback or the funner parts of hardware.