Week_10_Assignment

Concept

The requirement of creating a musical instrument with electrical components made me think of the Theremin, but I didn’t want to copy the logic comletely. So I dicided to use the ultrasonic distance sensor to imitate the change by hand movement. I also wanted to make the instrument a beat generater, because beats can be manipulated in their pitch, tempo and even rhythm pattern. This allows much more variation. So the ultimate design concept was to have the ultrasonic distance sensor acts as a pitch controller, where the player can move thir hand away or closer to the sensor to control pitch, the potentialmeter controls the tempo, and the toggle switch allows alternation between rythm patterns.

Video Demo

https://drive.google.com/file/d/1FMsPLRa6d30ubt3L1F19-kvFab5APs4L/view?usp=drive_link

Schematics

 

Code Snippet

https://github.com/JingyiChen-jc12771/Intro-to-IM/blob/e15f6f3478d8937ba91372ab2eed7e34a691b2b8/Week_10_assignment/Week_10_assignment.ino

int scale[]={NOTE_C4, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_A4, 
  NOTE_C5, NOTE_D5, NOTE_E5, NOTE_G5, NOTE_A5};

The code shown above is the note array. It is used so not every single sound in the range of the distance to pitch mapping is used. This removes the more irritating pitches and leaves the actual notes, just to make the instrument sound better.

long duration,cm;
int switchState = digitalRead(switchPin);
//measuring chunk for the ultrasonic distance sensor
digitalWrite(distPin,LOW);
delayMicroseconds(2);
digitalWrite(distPin, HIGH);
delayMicroseconds(10);
digitalWrite(distPin, LOW);
//records the time between output of ultrasound and echo. 10000 sets a limit in case there is not close enought object, it prevents the program from stopping completely by setting cm to 0.
duration=pulseIn(echoPin,HIGH,10000);
//uses the convertion function to convert the time to distance
cm = microsecondsToCentimeters(duration);
//if the distance of object is further than 50cm away treat it as 50cm, this limits the range of distance.
if(cm==0||cm>50){cm=50;}
//map the distance to the array of notes, 2 is the reliable begining measurement of the sensor
int noteIndex = map(cm, 2, 50, 0, numNotes - 1);
int currentNote=scale[noteIndex];
//the function to convert time to distance, 10000 time would result in 0cm
long microsecondsToCentimeters(long microseconds) {
  return microseconds / 29 / 2;
}

This is the chunk where the distance sensor is activated and does its measuring, and the measurements are mapped to the note array. The code for initiating ultrasound release and receiving echos are referenced from a tutorial for 4 pin ultrasonic sensors on the Arduino project hub and the Arduino IDE Ping example for 3 pin ultrasonic sensors. The code tells the sensor to be quiet for 2 microseconds, emit ultrasound for 10 microseconds, and then stops so the echo can be listened for. Then the time it took for the echo to get back is assigned to the duration variable, which is converted to distance in cm used the function i found in the Arduino Ping example. The distancer is then mapped to the indexes of the note array, so distance would corresopond to note.

if (currentMillis - startMillis >= tempo) {
    startMillis = currentMillis; 
    beatStep++;
    //the beat generation
    //switch controls two states, one where the beats play at a steady tone
    if(switchState==HIGH){
      tone(buzzerPin,currentNote,50);
      //In the other state the beat is deeper at even beats and lighter at odd beats
    }else{if(beatStep%2==0){
      tone(buzzerPin,100,50);
    }else{
      tone(buzzerPin,currentNote,50);
    }
  }
}

This code snippet is the part that times the beats and controls the button alternation between the two rythm styles. The timer uses the same logic as the timer we have done in p5. Time passed is recorded in millis. the time the last beat was played was assigned to “startMillis”, and current time is “currentMillis”. When time interval between the two millis exceed the tempo, the next beat is played.

One of the switch state plays a steady tone, where the beat is played at the pitch defined by the redings of the distance sensor all the time. The other state plays an alternating pattern.  if(beatStep%2==0) results in even beats playing at a hard coded 100Hz, and odd beats at the distance influenced pitch. This can also be modified. The even beat can be made half the frequency, double the frequency, or pitch desired.

Reflection

The biggest challenge was with the timer. Initially we tried to use delay as we did in all our previou codes and the whole unit would freeze and not work at all. Thinking back to our P5 experience we figured using a background timer of millis would allow the unit to keep running between beats. The end result was good and the beats flowed smoothly. Something we could have done better might be to expand the array so the pitches are not that limited. Something else that would have been fun but a bit less feasible is adding more push buttons, and make the pitch or overall style change when the button is pushed, like a groove box. But that would work better if the output was not limited to a piezo speaker. That would allowe a wider variety of sounds and might even create some DJ effects.

 

Leave a Reply