/* * 1V Octave pitch tracking optimized for walkman. * 2014 Gijs Gieskes * * Frequency & Period Measurement for Audio * KHM 2010 / Martin Nawrath * Kunsthochschule fuer Medien Koeln * Academy of Media Arts Cologne * http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/ */ #include "FreqPeriod.h" #include //smoothing boolean smoothtype = false; byte smoothtypeactive = 0; byte smoothup = 4; byte smoothdown = 4; byte level = 1; float levelf = 0.05; boolean smootheMenuActive = false; unsigned long smoothmill; byte smoothmilmenu; boolean smflip = true; unsigned long smoothmenuoutmill; boolean menuenter = false; boolean prevB = false; int AV3; int prevAV3; boolean newPrevAV3; double lfrq; double prevlfrq; byte lfrqerror = 0; long int pp; boolean enableScaling = false; double settle; unsigned long settlemill; unsigned long prevmill; byte count; float multi = 1; float dacVal; void setup() { pinMode(2, INPUT); digitalWrite(2, HIGH); TCCR2B = TCCR2B & 0b11111000 | 0x01; //PWM DAC //pinMode(3, OUTPUT); pinMode(4, OUTPUT); //Serial.begin(115200); FreqPeriod::begin(); //scaling settings if(!digitalRead(2)){ smootheMenuActive = true; enableScaling = true; pinMode(3, OUTPUT); }else{ pinMode(3, INPUT); } //if something has been stored load it. if(EEPROM.read(0) == 1){ //load sequencer delay time smoothup = EEPROM.read(1); smoothdown = EEPROM.read(2); level = EEPROM.read(3); } } void loop() { if(smootheMenuActive){ //select smoothing if(!digitalRead(2)){ smoothmenuoutmill = millis(); while(!digitalRead(2)){ delay(10); digitalWrite(4, LOW); //save to EEPROM when button is held for 2 seconds. if(millis() - smoothmenuoutmill > 2000 && menuenter){ //do nothing when enter fisrt time if(smoothtypeactive > 1){ //save so it knows something has been saved. EEPROM.write(0, 1); EEPROM.write(1, smoothup); EEPROM.write(2, smoothdown); EEPROM.write(3, level); while(!digitalRead(2)){//exit menu on release smootheMenuActive = false; digitalWrite(4, HIGH); } }else if(smoothtypeactive == 0){ smoothtypeactive = 1; menuenter = false; while(!digitalRead(2)){//move to down menu digitalWrite(4, HIGH); } }else{ smoothtypeactive = 2; menuenter = false; while(!digitalRead(2)){//move to down menu digitalWrite(4, HIGH); } } } delay(10); } if(smootheMenuActive && menuenter){ if(smoothtypeactive == 0){ smoothup++; if(smoothup > 7){ smoothup = 0; } }else if(smoothtypeactive == 1){ smoothdown++; if(smoothdown > 7){ smoothdown = 0; } }else{ level++; if(level > 7){ level = 0; } } } menuenter = true; } //display what smoothing is chosen. if(millis() - smoothmill > 200){ smoothmill = millis(); smoothmilmenu++; if(smoothmilmenu > 15){ smoothmilmenu = 0; } smflip = !smflip; if(smoothtypeactive == 0){ if(smoothmilmenu < (smoothup*2)){ digitalWrite(4, smflip); } }else if(smoothtypeactive == 1){ if(smoothmilmenu < (smoothdown*2)){ digitalWrite(4, smflip); } }else{ if(smoothmilmenu < (level*2)){ digitalWrite(4, smflip); } } } }else{//1v ocatve on or off. if(!digitalRead(2)){ if(prevB){ prevB = false; enableScaling = !enableScaling; digitalWrite(4, enableScaling); if(enableScaling){ pinMode(3, OUTPUT); }else{ pinMode(3, INPUT); } } }else{ prevB = true; } } //if no freq is detectde the last one is used //the last one can be verry high, slowing the speed of the motor //down when it should be going up. //the adjust the freq down making the speed go up, preventing the stop error. lfrq = lfrq - 0.01; lfrq = max(lfrq, 1); pp = FreqPeriod::getPeriod(); if(pp){ lfrq = 16000400.0 / pp; } //only update when active. if(enableScaling){ AV3 = analogRead(3); } //smoothed update motor speed, dependant on voltage //high voltage means less smooth changes. levelf = (0.005*(level+1))*(level+1); multi = (pow(2, (AV3*0.0001)) - 1)*smoothup; float octval = octv(AV3); if(enableScaling){ if(lfrq > octval){ dacVal-= max(multi, settle); }else if(lfrq < octval){ dacVal+= max(multi, levelf); //tweak here if walkman wont start.. } } //calculate value to prevent verry slow speed change when moving down in speed settle -= 0.0001; settle = max(settle, 0.01); //millis is for when cv voltage changes to fast after another,making the speed change not working. if(AV3 < (prevAV3 - 2) && millis() - settlemill > 300){ settlemill = millis(); settle = (pow(2, ((prevAV3)*0.0001)) - 1)*smoothdown; //use the highest value for setting prevAV3 = AV3; }else if(AV3 > (prevAV3 + 2)){ //dont set when speed up prevAV3 = AV3; } /* if(millis() - prevmill > 100){ prevmill = millis(); Serial.print(dacVal, DEC); Serial.print("\t lfrq: "); Serial.print(lfrq, DEC); Serial.print("\t error: "); Serial.print(lfrqerror, DEC); Serial.print("\t pp: "); Serial.print(pp, DEC); Serial.print("\t down: "); Serial.print(smoothdown, DEC); Serial.print("\t level: "); Serial.print(level, DEC); Serial.print("\t levelf: "); Serial.print(levelf, DEC); Serial.print("\t up: "); Serial.println(smoothup, DEC); }*/ //no less the1 //dacVal = max(dacVal, 1.27); dacVal = constrain(dacVal, 0, 255); if(enableScaling){ analogWrite(3, dacVal); } //relates also to the "settle" value. delayMicroseconds(10); } float octv(int input){ float voltage = (input*0.0048875897); // 0 to 1023 converted to 0 to 5 (5.0000042631) float output = pow(2, voltage); //convert to 1vOctave scales by double the octave per voltage //float tohz = 220*output; //0v is A3 Note (220hz). float tohz = map(analogRead(2), 0, 1023, 261.625625, 523.25125)*output; //0v is C? Note (261.62hz). return tohz; }