Introduction: SoundWave Printer

Have you ever wondered what sound waves would look like. Yes, we all know what a wave looks like.
But if you asked me what a 400Hz looks like, I would probably draw a sine wave on a piece of paper and that would be it. I might calculate the length of the wave and tell you that it is 850mm. The velocity of the wave divided by the frequency.
For sound waves of 400Hz in air that would be 343 meter/second divided by 400 = 0.85 meter.

Time for some visuals.

In the past I experimented a lot with slow shutter speed photography and arduino's. Those two could be the answer to my quest. Showing a sound wave with the correct length.

This project was created during an Arduino-Jam at Timelab in Ghent (Belgium). I won the 9th edition of the jam with this project. Thanks to all the other contestants and the superb organization.

Another similar project on Instructables: Imprint invisible sound and radio waves onto your retina: Augmented reality with perfect alignment by Steve Mann

Step 1: What Do We Need to Build a SoundWave Printer

I did some test with an arduino uno, M0. But finally settled on a teensy 3.x, because it gave me the fasted ADC sound wave sample speed.

What you need to build the SoundWave Printer:

  • Teensy 3.1
  • electret microphone
  • rotary encoder
  • 1K Ohm resistor
  • 2x Neopixel stick (Adafruit)
  • 1000 uF capacitor
  • 330 Ohm resistor

Step 2: Capture Sound Waves

I'll used an electret microphone without any amplification to keep things simple. And 1K Ohm resistor is placed between 3.3V and the positive side of the electret microphone.

The Teensy has a 12bit ADC, which gave me enough room to capture my sound.

To capture exact the length of one meter of sound wave, one would need to sample for 1 sec / 343 meter = 0.00291545189 sec or 2915 microseconds.

With the Teensy I managed to have around 112 sample within 2915 microseconds. More then enough to show on one meter. I stored them in an array

unsigned int startCounting = micros() + 2915;

unsigned int counter = 0;

while(micros() < startCounting ) {
    soundSampleArray[counter] = analogRead(microphonePin);
    delayMicroseconds(15); // Needed for the ADC to settle
    counter++;

}

Because I'm not using any amplification the difference between my min and max reading is not that much. To maximally use the 16 pixel high display, I'll have to calibrate my data.

void readSoundWaveSample () {
Serial.println("start reading"); int maxR = 0; int minR = 4096; long totalCal = 0; int calRead; unsigned int startCounting = micros() + 2915; unsigned int counter = 0;

while(micros() < startCounting ){ calRead = analogRead(MICROPHONE_PIN); soundSampleArray[counter] = calRead;

if (calRead > maxR) { maxR = calRead; } if (calRead < minR) { minR = calRead; } totalCal = totalCal + calRead; counter++; delayMicroseconds(15); }

calDif = ((maxR - minR)/2); calMid = totalCal/counter; Serial.println("done reading"); amountOfSamples = counter; }

I'll use calMid and calDif to map my data.

CalMid is the middle of my wave. CalMid minus calDif is the bottom of the wave, calMid plus calDif is the top of the wave.

I'll use amountOfSamples later to map my data to the amount of steps I have per meter. In my case it happend to be 340 steps, with my 12 click rotary encoder.

Step 3: Print the SoundWave

I'm going to move a Neopixel led stick of 16 leds over a distance of one meter and map my recorded SoundWave on the 16 leds. I opted for making a little cart with one encoder wheel that returns the position of the cart.

The encoder and the wheel gave me 340 steps for one meter. (I measured this with a different sketch).

When I rol the cart I'll get a position from the rotary encoder. Then I would map this position to a sample in my soundSampleArray. Then I would map the data of that soundSample to one of the 16 led's.

myEnc.write(0); // set encoderPosition to 0

oldPosition = 0; // oldPosition to 0

stepsPerMeter = 340; // amount of steps for covering one meter

while(oldPosition < stepsPerMeter) {

   long newPosition = myEnc.read(); // read new encoder position

   if (newPosition != oldPosition) {

      oldPosition = newPosition; 

      int myArrayPos = map(newPosition, 0, stepsPerMeter ,0 ,soundSampleSize );

      outputValue = map(soundSampleArray[myArrayPos] ,calMid-calDif ,calMid+calDif ,0 ,16 );

      // print to led stick

      for(uint16_t i=0; i < strip.numPixels(); i++) {

         if (i == outputValue) {

            strip.setPixelColor(i,255,0,0);

         } else {

            strip.setPixelColor(i,0,0,0);

         }

      }

      strip.show();

   }

}

Step 4: The SoundWave Printer

I threw all of this together on a breadboard and mounted it on a piece of scrap acrylic.

Neopixel has the 5V from usbV. And dataline on 6.
Rotary encoder is connected to 7 & 8.
The mircophone is connected to A0.

I added some kind of user interface to it.

  1. SoundWave printer ready => all leds ON, pink
  2. Record sound by turning the wheel
  3. SoundWave is recorded => all leds ON, green
  4. SoundWave printer ready to print => all leds OFF
  5. Drag the SoundWave printer while taking a long exposure photograph
  6. Watch your SoundWave printed in the air.

Step 5: The Code

Comments

author
cinezaster (author)2016-09-12

start with an arduino. Make small projects.

Split your problem into small projects:

- record sound and put it in an array

- drive some led's

- show sound on your led's

- ...

author
plouc (author)2016-03-23

Definitely nice! Thanks for sharing!

author
plouc (author)2016-03-21

Seems really nice. i'd love to see a video!

author
cinezaster (author)plouc2016-03-23

@plouc I added a video.

About This Instructable

2,115views

40favorites

License:

Bio: I'm Toon, I see myself as a maker/hacker. I'm founder of AppSaloon a small web company. I also founded the arduino-jam. I ... More »
More by cinezaster:Bookshelf SpeakersSoundWave printerElectroFried electronic shock game
Add instructable to: