// Touch Synth
// Copyright 2009 Adrian Freed. All Rights Reserved
//

int speakerPin = 14;
int speakerPinbis = 15; // differential drive for extra loudness and lower power consumption

void setup()
{

pinMode(speakerPin, OUTPUT); // sets the speakerPin to be an output
pinMode(speakerPinbis, OUTPUT); // sets the other speakerPin to be an output

}

//touch sensing on the 14 digial pins on ports d and b
// http://www.arduino.cc/en/Reference/PortManipulation
typedef struct tr
{
byte t[14]; // >1 when touched. The number is larger the better your bodies path is to ground
} touchresult;

struct tr touchsense(int pins); // a bit field to set which pins you want to be touch active.

#define TRANGE 32
struct tr touchsense(int pins)
{
byte portd = pins &0xff;
byte portb = (pins>>8) &0x3f;
byte i,j;
byte result[TRANGE];
touchresult r= { 0,0,0,0, 0,0,0,0 ,0,0,0,0, 0,0};

// concurrent sensing for portb
portb &= ~DDRB; // don't mess with direction of existing output pins
// xxxhow do we know what input pins are in use?
// how do we not disturb state of existing output pins?
if(portb)
{
PORTB &= ~portb; // low level
DDRB |= portb; // discharge
for(i=0;i<TRANGE;++i)
result[i] = 0;

DDRB &= ~portb;
PORTB |= portb;

result[0] = PINB;
result[1] = PINB;
result[2] = PINB;
result[3] = PINB;
result[4] = PINB;
result[5] = PINB;
result[6] = PINB;
result[7] = PINB;
result[8] = PINB;
result[9] = PINB;
result[10] = PINB;
result[11] = PINB;
result[12] = PINB;
result[13] = PINB;
result[14] = PINB;

result[15] = PINB;
result[16] = PINB;
result[17] = PINB;
result[18] = PINB;
result[19] = PINB;
result[20] = PINB;
result[21] = PINB;
result[22] = PINB;
result[23] = PINB;
result[24] = PINB;
result[25] = PINB;
result[26] = PINB;
result[27] = PINB;
result[28] = PINB;
result[29] = PINB;
result[30] = PINB;

result[31] = PINB;
for(i=2;i<TRANGE;++i)
{
// Serial.println(result[i], HEX);
for(j=0;j<6;++j)
{
if(portb&(1<<j))
r.t[j+8] += !(result[i] & (1<<j));
}
}
}
// concurrent sensing for port D
portd &= ~DDRD; // don't mess with direction of existing output pins
// xxxhow do we know what input pins are in use?
// how do we not disturb state of existing output pins?

if(portd)
{
PORTD &= ~portd; // low level
DDRD |= portd; // discharge
for(i=0;i<TRANGE;++i)
result[i] = 0;
DDRD &= ~portd;
PORTD |= portd;

result[0] = PIND;
result[1] = PIND;
result[2] = PIND;
result[3] = PIND;
result[4] = PIND;
result[5] = PIND;
result[6] = PIND;
result[7] = PIND;
result[8] = PIND;
result[9] = PIND;
result[10] = PIND;
result[11] = PIND;
result[12] = PIND;
result[13] = PIND;
result[14] = PIND;

result[15] = PIND;
result[16] = PIND;
result[17] = PIND;
result[18] = PIND;
result[19] = PIND;
result[20] = PIND;
result[21] = PIND;
result[22] = PIND;
result[23] = PIND;
result[24] = PIND;
result[25] = PIND;
result[26] = PIND;
result[27] = PIND;
result[28] = PIND;
result[29] = PIND;
result[30] = PIND;

result[31] = PIND;

for(i=2;i<TRANGE;++i)
{
// Serial.println(result[i], HEX);
for(j=0;j<8;++j)
{ if(portd&(1<<j))
r.t[j] += !(result[i] & (1<<j));
}
}
}

return r;
}
static int pitches[] =
{
523,
554,
587,
622,
659,
698,
740,
784,
831,
880,
932,
988,
1047,
1109,
};

// differential pulse trains. The marktospacepercentage controls timbre (and amplitude for small values).
// The frequency determines pitch. Use a high impedence driver: 30-100Ohms or a piezo.
void beep (unsigned frequencyInHertz, unsigned timeInMilliseconds, unsigned marktospacepercentage) // the sound producing function
{
int x;
static int swap=0;
unsigned long delayAmount = 1000000L/frequencyInHertz;
unsigned long markdelay = delayAmount*marktospacepercentage/1000l;
unsigned long spacedelay = (delayAmount*(1000l-marktospacepercentage))/1000l;
unsigned long loopTime = (long)((timeInMilliseconds*500l)/(delayAmount));

for (x=0;x<loopTime;x++)
{
pinMode(speakerPin, OUTPUT); // sets the speakerPin to be an output
pinMode(speakerPinbis, OUTPUT); // sets the other speakerPin to be an output

digitalWrite(speakerPin,swap);
digitalWrite(speakerPinbis,!swap);
delayMicroseconds(markdelay);
pinMode(speakerPin, INPUT); // sets the speakerPin to be an output
pinMode(speakerPinbis, INPUT); // sets the other speakerPin to be an output

delayMicroseconds(spacedelay);
}
swap = !swap;
}

void loop ()
{
// read the keys
struct tr r = touchsense(0x00ffc);

// sound a short pitch for each touch using the touch value to determine loudness/timbre
for(int i = 0; i < 13; i++)
{
int key =r.t[i];
if(key>0)
{
beep(pitches[i],100,key*2);
}
}

}

Attachments