As computing becomes more ubiquitous in our objects, designers need to be more aware of how to design meaningful interactions into electronically enhanced objects. At the University of Washington, a class of junior Interaction Design majors is exploring this question. These pages chronicle their efforts.

Saturday, June 11, 2016

JANE & ZIHAN MUGIC: VISUALIZING SOUND





Watch our video on https://vimeo.com/169865743

Mugic is a magic ball that can react to music and other sound. It can recognize the frequency of each sound waves coming into the microphone, and change color to green to blue to red by low to mid to high pitches. 

#include <avr/pgmspace.h>
#include <ffft.h>
#include <math.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h>

#ifdef __AVR__
  #include <avr/power.h>
#endif

#ifdef __AVR_ATmega32U4__
 #define ADC_CHANNEL 7
#else
 #define ADC_CHANNEL 0
#endif



int voltage;
int16_t Gcolor;
int16_t YColor;
int z;
int h;
float total;
unsigned long time;
uint16_t oldspec[FFT_N];
uint16_t dif[FFT_N];
uint16_t totaldif;
uint16_t averagedif;
uint16_t totalaveragedif;
uint16_t average;
uint16_t averageLow;
uint16_t averageMid;
uint16_t averageHigh;
uint16_t totalLow;
uint16_t totalMid;
uint16_t totalHigh;
uint16_t Low;
uint16_t Mid;
uint16_t High;
int brightness;
boolean record = false;


int16_t       capture[FFT_N];  
complex_t     bfly_buff[FFT_N];
uint16_t      spectrum[FFT_N/2];
uint16_t      volume[FFT_N/2];
volatile byte samplePos = 0;    
static const uint8_t PROGMEM
 
  noise[64]={ 1,2,3,2,3,3,2,1,2,3,2,3,2,3,3,4,
              2,1,2,1,3,2,3,2,1,2,3,1,2,3,4,4,
              3,2,2,2,2,2,2,1,3,2,2,2,2,2,2,2,
              2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,4 },
  eq[64]={
    255, 175,218,225,220,198,147, 99, 68, 47, 33, 22, 14,  8,  4,  2,
      0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
      0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
      0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 };
     



Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, 6, NEO_GRB + NEO_KHZ800);

void setup() {
   // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  // End of trinket special code
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(9, OUTPUT);
  //pinMode(6, OUTPUT);
 
  ADMUX  = ADC_CHANNEL;
  ADCSRA = _BV(ADEN)  |
           _BV(ADSC)  |
           _BV(ADATE) |
           _BV(ADIE)  |
           _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
  ADCSRB = 0;              
  DIDR0  = 1 << ADC_CHANNEL;
  TIMSK0 = 0;      
         
  strip.begin();
  //firstColor(765);
  strip.show(); // Initialize all pixels to 'off'
  sei();
}
void loop() {
  sampling();
  setColor(YColor);
  //Serial.println(YColor);
  analogWrite(9, voltage);
}

void sampling() {
 
  uint8_t  i, x, L, *data, nBins, binNum, weighting, currentMax, currentMaxPo, currentMax2, currentMaxPo2, currentMax3, currentMaxPo3;
  uint16_t minLvl, maxLvl;
  int      level, y, sum;
  while(ADCSRA & _BV(ADIE));

  fft_input(capture, bfly_buff);
  samplePos = 0;                  
  ADCSRA |= _BV(ADIE);            
  fft_execute(bfly_buff);        
  fft_output(bfly_buff, spectrum);

  // Remove noise and apply EQ levels
  for(x=0; x<FFT_N/2; x++) {
    volume[x] = spectrum[x];
    L = pgm_read_byte(&noise[x]);
    spectrum[x] = (spectrum[x] <= L) ? 0 :  // if (...) then S[] = 0; else,
      (((spectrum[x] - L) * (256L - pgm_read_byte(&eq[x]))) >> 8); //256L means 256, >>8 = 256的倍数
  }
 
  for(int i = 0; i < 64; i++){
    total += volume[i];
    if(i <= 10) {
      totalLow += volume[i];
    }
    else if (i <= 40) {
      totalMid += volume[i];
    }
    else if (i <= 64) {
      totalHigh += volume[i];
    }
  }
  averageLow = totalLow / 10;
  averageMid = totalMid / 30;
  averageHigh = totalHigh / 24;
  average = total / 64;
  //Serial.println("A");
  //Serial.println(average);
  /*Serial.print(averageLow);
  Serial.print("  ");
  Serial.print(averageMid);
  Serial.print("  ");
  Serial.println(averageHigh);
  */
  if(average > 2) {
    record = true;
   
  }
  while(record) {
    z++;
    Low += averageLow;
    Mid += averageMid;
    High += averageHigh;
    //Serial.println("A");
    if(z >= 5){
      YColor = WheelPos(Low, Mid, High);
     
      Serial.print(Low);
      Serial.print(" ");
      Serial.print(Mid);
      Serial.print(" ");
      Serial.println(High);
     
      h++;
      record = false;
      z = 0;
    }
  }
  totalLow = 0;
  totalMid = 0;
  totalHigh = 0;
  total = 0;
  Low = 0;
  Mid = 0;
  High = 0;
 
  for(int c; c < 64; c++) {
    if(volume[c] > currentMax) {
      currentMax = volume[c];
      currentMaxPo = c;
      voltage = currentMax;
    }
    //Serial.println(currentMax);
  }
 maping();
}

void maping() {
  voltage = map(voltage, 0, 100, 400, 500);
}

ISR(ADC_vect) {
  static const int16_t noiseThreshold = 4;
  int16_t              sample         = ADC;
  capture[samplePos] =
    ((sample > (512-noiseThreshold)) &&
     (sample < (512+noiseThreshold))) ? 0 :
    sample - 512;

  if(++samplePos >= FFT_N) ADCSRA &= ~_BV(ADIE);
}

void fadeOut() {
    //delay(1000000);
    for(int j=brightness; j>=0; j -= 2) {
      strip.setBrightness(j);
      //
      strip.show();
    }
    h = 0;
    brightness = 0;
    //
}

void firstColor(uint16_t color) {
  uint16_t i, j;
  for(j=0; j<254; j += 2) {
    strip.setBrightness(j);
    for(int i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(color));
    }
    //delay(0);
    strip.show();
  }
  Gcolor = color;
  //delay(10000);
 
}

void setColor(uint16_t color){
  uint16_t j;
  if(color > Gcolor)
    for(uint16_t j=Gcolor; j < color; j++) {
          for(int i=0; i<strip.numPixels(); i++) {
              strip.setPixelColor(i, Wheel(j));
            }
            strip.show();
    }
  if(color < Gcolor) {
    for(uint16_t j=Gcolor; j > color; j--) {
        for(int i=0; i<strip.numPixels(); i++) {
            strip.setPixelColor(i, Wheel(j));
          }
            strip.show();
        }
    }
  Gcolor = color;
}
 


uint16_t WheelPos(uint16_t low, uint16_t mid, uint16_t high) {
   uint16_t color;
   int greenSpecs;
   int lowColor = low - mid;
   int midColor = mid - low;
   if (lowColor > 20) {
     greenSpecs = map(mid, 10, 100, 0, 255);
     color = map(low, 30, 200, 255, 510);
   }
   else if (lowColor <= 20 || midColor > 0) {
     greenSpecs = map(low, 10, 100, 0, 255);
     color = map(mid, 0, 100, 510, 1040);
     Serial.println(color);
     return color - greenSpecs;
   }
}

uint32_t Wheel(uint16_t WheelPos) {
  //WheelPos = 255 - WheelPos;
  if(WheelPos < 255) { // 0-255
    return strip.Color(0, 255, WheelPos);
  }
  if(WheelPos < 510) { // 255-510 -> 0-255
    WheelPos -= 255;
    return strip.Color(0, 255-WheelPos, 255);
  }
  if(WheelPos < 765) { // 510-765 -> 0-255
    WheelPos -= 510;
    return strip.Color(WheelPos, 0, 255-WheelPos);
  }
  if(WheelPos < 1020) {
    WheelPos -= 765; // 765-1020 -> 0-255
    return strip.Color(255, 255-WheelPos, 0);
  }
    WheelPos -= 1020; // 765-1020 -> 0-255
    return strip.Color(255-WheelPos, 0, 0);
}





No comments:

Post a Comment