Introduction: ACCEN

Sound interactive design that responds visually to the user's voice at frequency

Through the experience of visually displaying the wave of strings in response to the size of voice, we implemented a wave differentiated by sound beyond simple responses that only respond to the existing sound intensity.It provides a stereoscopic experience by stimulating analog sensibility beyond digital.

Step 1: Making Video

Step 2: Full Infographic

Step 3: 1. Core (control)


MATERIALS


1. Teensy 3.6

2. L298N Stepping Motor Aduino Motor Driver*5

3. Microphone sensor/MAX9814 Power supply (SMPS 50W)

4. Power supply (SMPS 50W)

5. Jumper cable

6. Electric wire · Three-bar wire cable · A single cable

Step 4: Circuit Diagram (core)

MATERIALS

1. Teensy 3.6

2. L298N Stepping Motor Aduino Motor Driver*5

3. Microphone sensor/MAX9814 Power supply (SMPS 50W)

4. Power supply (SMPS 50W)

5. Jumper cable 6. Electric wire · Three-bar wire cable · A single cable

Step 5: 2. Motor (control)


MATERIALS


1. Laminated wood

· A big circle - 1500(mm)
· A small circle - 600(mm)

2. Cramp iron

· 150*150(mm)*20

3. 1~12V DC Motor(Hobby Motor - Gear) *20

4. 2T Formex

· Trapezoid shape *2
· A big square - 35*185(mm)

5. A black manila paper*2

6. Wall-Gracket

7. Rubber band*3


HOW TO


1. drill ten holes

2. Drive in a Cramp Iron

Insert the cramp iron evenly over the hole.

3. Drive in a Cramp Iron

4. Secure the rope to the motor.

    Step 6: 3. a Big Circle


    MATERIALS

    1. circular saw

    2. black spray


    HOW TO


    Wood Cutting

    1. Cut the wood into a circle using a circular saw.
    You have reached the first stage of building hardware.

    Referring to the uploaded image, you should know how much wood you cut. (Please refer to the first image) You go to a nearby lumber mill and cut it in a circle to meet the specifications.

    2. The circular wood must be painted with black spray.
    Dry until clean and repeat rooting.

    Step 7: 4. a Small Circle


    MATERIALS

    1. A small square - 35*45(mm)

    2. Circular saw

    3. Drill

    4. paint Spray*3

    · Black color


    HOW TO


    1. Cut the wood into a circle using a circular saw.
    You have reached the first stage of building hardware. Referring to the uploaded image, you should know how much wood you cut. (Please refer to the first image) You go to a nearby lumber mill and cut it in a circle to meet the specifications. A small circle - 600(mm)

    2. The circular wood must be painted with black spray. Dry until clean and repeat rooting.

    Step 8: Extra Meterials

    Step 9: Coding

    // Audio Spectrum Display // Copyright 2013 Tony DiCola (tony@tonydicola.com)
    // This code is part of the guide at http://learn.adafruit.com/fft-fun-with-fourier-transforms/
    #define ARM_MATH_CM4 #include  #include  // Lighting, such as when required.
    //////////////////////////////////////////////////////////////////////////////// // CONIFIGURATION // These values can be changed to alter the behavior of the spectrum display. ////////////////////////////////////////////////////////////////////////////////
    int SAMPLE_RATE_HZ = 4000;             // Sample rate of the audio in hertz.  //Set the desired frequency band. Reacted from 0 to 2000 Hz for 4000 Hz float SPECTRUM_MIN_DB = 35;          // Audio intensity (in decibels) that maps to low LED brightness. //Acceptance minimum float SPECTRUM_MAX_DB = 80.0;          // Audio intensity (in decibels) that maps to high LED brightness. //Maximum Acceptance Value int LEDS_ENABLED = 1;                  // Control if the LED's should display the spectrum or not.  1 is true, 0 is false. // Useful for turning the LED display on and off with commands from the serial port. const int FFT_SIZE = 256;              // Size of the FFT.  Realistically can only be at most 256 // without running out of memory for buffers and other state. const int AUDIO_INPUT_PIN = A21;        // Input ADC pin for audio data. //audio analog pin const int ANALOG_READ_RESOLUTION = 10; // Bits of resolution for the ADC. const int ANALOG_READ_AVERAGING = 16;  // Number of samples to average with each ADC reading. const int POWER_LED_PIN = 10;          // Output pin for power LED (pin 13 to use Teensy 3.0's onboard LED). const int NEO_PIXEL_PIN = 1;           // Output pin for neo pixels.  const int NEO_PIXEL_COUNT =11;         // Number of neo pixels.  You should be able to increase this without //Number of motor connections // any other changes to the program. const int MAX_CHARS = 65;              // Max size of the input command buffer
    int motor_setPIN[] = {46,47,36,39,15,16,17,18,19,20, 21,22, 24,25,26,27,28,12,30,31,34,35}; //}; //1 - 2 + and - A signal value connected with a pair.
    int motorPIN[] = {48, 38, 3, 4, 5, 6, 7, 8, 37,10, 14}; //}; //a pin that accepts a pwm signal from the motor.
    //////////////////////////////////////////////////////////////////////////////// // INTERNAL STATE // These shouldn't be modified unless you know what you're doing. ////////////////////////////////////////////////////////////////////////////////
    IntervalTimer samplingTimer; float samples[FFT_SIZE * 2]; float magnitudes[FFT_SIZE]; int sampleCounter = 0; Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NEO_PIXEL_COUNT, NEO_PIXEL_PIN, NEO_GRB + NEO_KHZ800); char commandBuffer[MAX_CHARS]; float frequencyWindow[NEO_PIXEL_COUNT + 1]; float hues[NEO_PIXEL_COUNT];
    //////////////////////////////////////////////////////////////////////////////// // MAIN SKETCH FUNCTIONS ////////////////////////////////////////////////////////////////////////////////
    void setup() {   // Set up serial port.   Serial.begin(9600);
      // Set up ADC and audio input.   pinMode(AUDIO_INPUT_PIN, INPUT);   analogReadResolution(ANALOG_READ_RESOLUTION);   analogReadAveraging(ANALOG_READ_AVERAGING);
      // Turn on the power indicator LED.   pinMode(POWER_LED_PIN, OUTPUT);   digitalWrite(POWER_LED_PIN, HIGH);
    // first pin mode = pwm, second pin mode = +signal, third pinmode = -signal  pinMode(38, OUTPUT);   pinMode(36, OUTPUT);   pinMode(39, OUTPUT);     pinMode(3, OUTPUT);   pinMode(16, OUTPUT);   pinMode(15, OUTPUT);      pinMode(4, OUTPUT);   pinMode(18, OUTPUT);   pinMode(17, OUTPUT);      pinMode(5, OUTPUT);   pinMode(20, OUTPUT);   pinMode(19, OUTPUT);     pinMode(6, OUTPUT);  pinMode(22, OUTPUT);  pinMode(21, OUTPUT);   
      pinMode(7, OUTPUT);   pinMode(24, OUTPUT);   pinMode(25, OUTPUT);      pinMode(8, OUTPUT);   pinMode(26, OUTPUT);   pinMode(27, OUTPUT);      pinMode(37, OUTPUT);   pinMode(28, OUTPUT);   pinMode(12, OUTPUT);     pinMode(10, OUTPUT);  pinMode(30, OUTPUT);  pinMode(31, OUTPUT);
       pinMode(14, OUTPUT);   pinMode(34, OUTPUT);   pinMode(35, OUTPUT);        // Initialize neo pixel library and turn off the LEDs   pixels.begin();   pixels.show();
      // Clear the input command buffer   memset(commandBuffer, 0, sizeof(commandBuffer));
      // Initialize spectrum display   spectrumSetup();
      // Begin sampling audio   samplingBegin(); }
    void loop() {   // Calculate FFT if a full sample is available.   if (samplingIsDone()) {     // Run FFT on sample data.     arm_cfft_radix4_instance_f32 fft_inst;     arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 0, 1);     arm_cfft_radix4_f32(&fft_inst, samples);     // Calculate magnitude of complex numbers output by the FFT.     arm_cmplx_mag_f32(samples, magnitudes, FFT_SIZE);
        if (LEDS_ENABLED == 1)     {       // spectrumLoop();   // Create a loop named value and set it within the range of pwm values accepted by the motor. Setting within the range 0-255.       value(0, 190);     }     // Restart audio sampling.     samplingBegin();   }
      // Parse any pending commands.   parserLoop();
    }
    //////////////////////////////////////////////////////////////////////////////// // UTILITY FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
    / Compute the average magnitude of a target frequency window vs. all other frequencies. void windowMean(float* magnitudes, int lowBin, int highBin, float* windowMean, float* otherMean) {   *windowMean = 0;   *otherMean = 0;   // Notice the first magnitude bin is skipped because it represents the   // average power of the signal.   for (int i = 1; i < FFT_SIZE / 2; ++i) {     if (i >= lowBin && i <= highBin) {       *windowMean += magnitudes[i];     }     else {       *otherMean += magnitudes[i];     }   }   *windowMean /= (highBin - lowBin) + 1;   *otherMean /= (FFT_SIZE / 2 - (highBin - lowBin)); }
    // Convert a frequency to the appropriate FFT bin it will fall within. int frequencyToBin(float frequency) {   float binFrequency = float(SAMPLE_RATE_HZ) / float(FFT_SIZE);   return int(frequency / binFrequency); }
    // Convert from HSV values (in floating point 0 to 1.0) to RGB colors usable // by neo pixel functions. uint32_t pixelHSVtoRGBColor(float hue, float saturation, float value) {   // Implemented from algorithm at http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV   float chroma = value * saturation;   float h1 = float(hue) / 60.0;   float x = chroma * (1.0 - fabs(fmod(h1, 2.0) - 1.0));   float r = 0;   float g = 0;   float b = 0;   if (h1 < 1.0) {     r = chroma;     g = x;   }   else if (h1 < 2.0) {     r = x;     g = chroma;   }   else if (h1 < 3.0) {     g = chroma;     b = x;   }   else if (h1 < 4.0) {     g = x;     b = chroma;   }   else if (h1 < 5.0) {     r = x;     b = chroma;   }   else // h1 <= 6.0   {     r = chroma;     b = x;   }   float m = value - chroma;   r += m;   g += m;   b += m;   return pixels.Color(int(255 * r), int(255 * g), int(255 * b)); }
    //////////////////////////////////////////////////////////////////////////////// // SPECTRUM DISPLAY FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
    void spectrumSetup() {   // Set the frequency window values by evenly dividing the possible frequency   // spectrum across the number of neo pixels.   float windowSize = (SAMPLE_RATE_HZ / 2.0) / float(NEO_PIXEL_COUNT);   for (int i = 0; i < NEO_PIXEL_COUNT + 1; ++i) {     frequencyWindow[i] = i * windowSize;   }   // Evenly spread hues across all pixels.   for (int i = 0; i < NEO_PIXEL_COUNT; ++i) {     hues[i] = 360.0 * (float(i) / float(NEO_PIXEL_COUNT - 1));   } }
    void spectrumLoop() {   // Update each LED based on the intensity of the audio   // in the associated frequency window.   float intensity, otherMean;   for (int i = 0; i < NEO_PIXEL_COUNT; ++i) {     windowMean(magnitudes,                frequencyToBin(frequencyWindow[i]),                frequencyToBin(frequencyWindow[i + 1]),                &intensity,                &otherMean);     // Convert intensity to decibels.     intensity = 20.0 * log10(intensity);     // Scale the intensity and clamp between 0 and 1.0.     intensity -= SPECTRUM_MIN_DB;     intensity = intensity < 0.0 ? 0.0 : intensity;     intensity /= (SPECTRUM_MAX_DB - SPECTRUM_MIN_DB);     intensity = intensity > 1.0 ? 1.0 : intensity;     pixels.setPixelColor(i, pixelHSVtoRGBColor(hues[i], 1.0, intensity));   }   pixels.show(); }
    // Value is a loop that manages the rotation of the motor and is used in conjunction with the value 0 to 255 recorded at the top. void value(int valueA, int valueB) {   float intensity, otherMean;   // Update each LED based on the intensity of the audio   // in the associated frequency window.   for (int i = 0; i < NEO_PIXEL_COUNT; ++i) {
        windowMean(magnitudes,                frequencyToBin(frequencyWindow[i]),                frequencyToBin(frequencyWindow[i + 1]),                &intensity,                &otherMean);     // Convert intensity to decibels.     intensity = 20.0 * log10(intensity);     // Scale the intensity and clamp between 0 and 1.0.     intensity -= SPECTRUM_MIN_DB;     intensity = intensity < 0.0 ? 0.0 : intensity;     intensity /= (SPECTRUM_MAX_DB - SPECTRUM_MIN_DB);     intensity = intensity > 1.0 ? 1.0 : intensity;     intensity = map(intensity, 0, 1, valueA, valueB);    // pixels.setPixelColor(i, pixelHSVtoRGBColor(hues[i], 1.0, intensity));
    // Code that enables sequential input of +,- signal values to rotate the motor.     digitalWrite(motor_setPIN[(2 * i)], HIGH);     digitalWrite(motor_setPIN[(2 * i)+1], LOW);      // Code for substituting the pwm signal for the intensity value          analogWrite(motorPIN[i], intensity);          Serial.println(motor_setPIN[(2 * i)]);
        Serial.println(motor_setPIN[(2 * i)+1]);        Serial.println(motorPIN[i]);     } } //////////////////////////////////////////////////////////////////////////////// // SAMPLING FUNCTIONS ////////////////////////////////////////////////////////////////////////////////
    void samplingCallback() {   // Read from the ADC and store the sample data   samples[sampleCounter] = (float32_t)analogRead(AUDIO_INPUT_PIN);   // Complex FFT functions require a coefficient for the imaginary part of the input.   // Since we only have real data, set this coefficient to zero.   samples[sampleCounter + 1] = 0.0;   // Update sample buffer position and stop after the buffer is filled   sampleCounter += 2;   if (sampleCounter >= FFT_SIZE * 2) {     samplingTimer.end();   } }
    void samplingBegin() {   // Reset sample buffer position and start callback at necessary rate.   sampleCounter = 0;   samplingTimer.begin(samplingCallback, 1000000 / SAMPLE_RATE_HZ); }
    boolean samplingIsDone() {   return sampleCounter >= FFT_SIZE * 2; }
    //////////////////////////////////////////////////////////////////////////////// // COMMAND PARSING FUNCTIONS // These functions allow parsing simple commands input on the serial port. // Commands allow reading and writing variables that control the device. // // All commands must end with a semicolon character. // // Example commands are: // GET SAMPLE_RATE_HZ; // - Get the sample rate of the device. // SET SAMPLE_RATE_HZ 400; // - Set the sample rate of the device to 400 hertz. // ////////////////////////////////////////////////////////////////////////////////
    void parserLoop() {   // Process any incoming characters from the serial port   while (Serial.available() > 0) {     char c = Serial.read();     // Add any characters that aren't the end of a command (semicolon) to the input buffer.     if (c != ';') {       c = toupper(c);       strncat(commandBuffer, &c, 1);     }     else     {       // Parse the command because an end of command token was encountered.       parseCommand(commandBuffer);       // Clear the input buffer       memset(commandBuffer, 0, sizeof(commandBuffer));     }   } }
    // Macro used in parseCommand function to simplify parsing get and set commands for a variable #define GET_AND_SET(variableName) \   else if (strcmp(command, "GET " #variableName) == 0) { \     Serial.println(variableName); \   } \   else if (strstr(command, "SET " #variableName " ") != NULL) { \     variableName = (typeof(variableName)) atof(command+(sizeof("SET " #variableName " ")-1)); \   }
    void parseCommand(char* command) {   if (strcmp(command, "GET MAGNITUDES") == 0) {     for (int i = 0; i < FFT_SIZE; ++i) {       Serial.println(magnitudes[i]);     }   }   else if (strcmp(command, "GET SAMPLES") == 0) {     for (int i = 0; i < FFT_SIZE * 2; i += 2) {       Serial.println(samples[i]);     }   }   else if (strcmp(command, "GET FFT_SIZE") == 0) {     Serial.println(FFT_SIZE);   }   GET_AND_SET(SAMPLE_RATE_HZ)   GET_AND_SET(LEDS_ENABLED)   GET_AND_SET(SPECTRUM_MIN_DB)   GET_AND_SET(SPECTRUM_MAX_DB)
      // Update spectrum display values if sample rate was changed.   if (strstr(command, "SET SAMPLE_RATE_HZ ") != NULL) {     spectrumSetup();   }
      // Turn off the LEDs if the state changed.   if (LEDS_ENABLED == 0) {     for (int i = 0; i < NEO_PIXEL_COUNT; ++i) {      pixels.setPixelColor(i, 0);     }     pixels.show();   } }