Some ideas from
http://www.beavisaudio.com/projects/digital/ArduinoPunkConsole/
and
http://mechomaniac.com/ArduinoNoiseBoxSynth
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Licensed under the BSD 3-Clause license:
http://www.opensource.org/licenses/BSD-3-Clause
Copyright (c) 2012, http://dubworks.blogspot.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the RobotGrrl.com nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* DubWorks Alpha II
* After seveveral weeks of research, and the idea of using a 4046
VCO along with the Arduino http://dubworks.blogspot.co.uk
* a Pot to control the rate of the PWM
* a Pot to fine tune the rate of the PWM
and another at the entrance of the 4046
* Circuits:
* Potentiometer X2 attached to analog input #
* center pin of the Potentiometer to the analog pin
* one side pin (either one) to ground
* the other side pin to +5V
* digital output 11 out conected to a 4046 VCO
* Also Pin 11 on board Audio out
* * * The LCD circuit: * * *
* LCD RS pin to digital pin 8
* LCD Enable pin to digital pin 9
* LCD D4 pin to digital pin 4
* LCD D5 pin to digital pin 5
* LCD D6 pin to digital pin 6
* LCD D7 pin to digital pin 7
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <avr/io.h>
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// Variables will change:
int UpdateDisplayState ; // DisplayState used to set the Display
long previousMillis = 0; // will store last time LCD was updated;Siren also uses it !
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
int interval = 500; // interval at which to update the LCD display
// interval at which to update display (milliseconds)
const int MAX_Freq = 3000; //max Frequency of the siren wail
const int MIN_Freq = 70; //min Frequency of the siren wail
int Freq_SKIP ; //Frequency skip variable
int pitchval = 1;
const int PIN_RATE = 0; // variable for speed rate
const int PIN_ModePot = 1; // Analog port to read values for Menu of Mode
const int PIN_ModeAdjust = 2; //Fine tuning of sweep changes of pattern
const int PIN_PwmOut = 11; // Pin 11 on board Audio out
int MODE_CUT = 0;
int MODE_SOFTCUT = 125;
int MODE_SqWave = 250;
int MODE_UpDOWN = 375;
int MODE_RANDOM = 500;
int MODE_Freq = 625;
int MODE_Adjustable = 750;
int MODE_SIREN = 825;
int RAND_LOW_THRESHOLD = 30;
int RAND_HIGH_THRESHOLD = 255;
int tempoValue = 0;
int AdjustValue =0 ;
int PatternMode = 0;
int Adjust = 0;
int tempo = 0;
int oldTempo;
int oldPatternMode;
void setup ()
{
pinMode (PIN_PwmOut, OUTPUT); /* Pin 11 on board */
pinMode (PIN_RATE, INPUT);
pinMode (PIN_ModePot, INPUT);
pinMode (PIN_ModeAdjust, INPUT);
randomSeed (analogRead (0));
lcd.begin(16, 2); // set up the LCD's number of columns and rows
LCD_Init(); // Init our lcd
StartupMessage(); // our starting up message
}
void loop()
{
unsigned long currentMillis = millis();
bool controlsChanged = false;
tempo = analogRead (PIN_RATE) * 1.9;
if (currentMillis - previousMillis > interval) {
// save the last time you updated the LCD
previousMillis = currentMillis;
// if the UpdateDisplayState is off turn it on and vice-versa:
if (UpdateDisplayState == 0){
UpdateDisplayState = 1;
UpdateDisplay(); // update the LCD display
}
else {
UpdateDisplayState = 0;
}
}
else if(PatternMode == MODE_CUT)
{
// chop Wave mode
digitalWrite (PIN_PwmOut, HIGH); //Pin 11 on board, digitalWrite (PIN_PwmOut, HIGH);
delay (tempo);
digitalWrite (PIN_PwmOut, LOW); //Pin 11 on board , digitalWrite(PIN_PwmOut, LOW);
delay (tempo);
CheckControls();
}
else if (PatternMode == MODE_SOFTCUT)
{
analogWrite (PIN_PwmOut, 25);
delay (tempo/9);
analogWrite (PIN_PwmOut, 50);
delay (tempo/9);
analogWrite (PIN_PwmOut, 75);
delay (tempo/9);
analogWrite (PIN_PwmOut, 100);
delay (tempo/9);
analogWrite (PIN_PwmOut, 150);
delay (tempo/9);
analogWrite (PIN_PwmOut, 180);
delay (tempo/9);
analogWrite (PIN_PwmOut, 255);
delay (tempo/9 );
CheckControls();
}
else if (PatternMode == MODE_SqWave)
{
int counter = 0;
// fake sine Wave mode
for(counter = 0 ; counter <= 255; counter+=20)
{
analogWrite(PIN_PwmOut, counter);
if (Adjust >500)
{
delay (tempo/20);
}
else
{
delay (tempo/40);
analogWrite(PIN_PwmOut, 125);
delay (tempo/20);
}
CheckControls();
}
for (counter = 0; counter >= 100; counter-20)
{
analogWrite (PIN_PwmOut, counter);
if (Adjust >500)
{
delay (tempo/20);
}
else
{
delay (tempo/40);
analogWrite(PIN_PwmOut, 125);
}
CheckControls();//CheckControls();
}
}
else if (PatternMode == MODE_RANDOM)
{
// random mode, get a random number between thresholds
int randNumber = random(RAND_LOW_THRESHOLD, RAND_HIGH_THRESHOLD);
analogWrite (PIN_PwmOut, randNumber);
delay (tempo/2);
analogWrite (PIN_PwmOut, 255 - randNumber);
delay (tempo/2);
CheckControls();
}
else if (PatternMode == MODE_Freq)
{
int randNumber = random(Adjust,Adjust*2);
Freqout (randNumber, tempo);
CheckControls();
}
else if (PatternMode == MODE_UpDOWN)
{
int counter = 0;
for (counter = 0; counter <= 255; counter += 125)
{
analogWrite (PIN_PwmOut, counter);
delay (tempo/10);
}
for (counter = 255; counter >=0; counter -= 125)
{
analogWrite (PIN_PwmOut, counter);
delay (tempo/10);
CheckControls();
}
}
else if (PatternMode == MODE_Adjustable)
{
int fixed = analogRead (PIN_ModeAdjust);
Freqout (fixed, tempo/2);
Freqout (1024-fixed, tempo/2);
CheckControls();
}
else if (PatternMode == MODE_SIREN)
{
siren();
CheckControls();
}
}
void siren()
{
CheckControls(); //check controls to set mode
updateFreqSkip(); //updates our Frequency sweeping in the siren
unsigned long siren_start_time = millis(); //attaches start time to current millis
int Freq; //current Frequency at sweep
do
{
for (Freq=MIN_Freq; Freq<=MAX_Freq; Freq+=Freq_SKIP) /* Attributing the values to Freq
min and max values, and add the frequency skip value*/
{
tone(PIN_PwmOut, Freq); /* Tone on our pin with selected frequency */
delay(tempo/10); /* delay with the value given by the variable tempo on CheckControls() */
updateFreqSkip(); /* as controls might have changed the value of frequencu sweep, we check it again */
}
CheckControls(); /* calling void CheckControls() to check all analog imput states */
for (Freq=MAX_Freq; Freq>=MIN_Freq; Freq-=Freq_SKIP)
{
tone(PIN_PwmOut, Freq); /* Tone on our pin with selected frequency */
delay(tempo/10); /* delay with the value given by the variable tempo on CheckControls() */
updateFreqSkip(); /* as controls might have changed the value of frequencu sweep, we check it again */
}
CheckControls(); /* calling void CheckControls() to check all analog imput states */
}
while (millis() - siren_start_time < 5000L);
}
void updateFreqSkip() //creating a function we can call that updates the Freq_SKIP
{
if (PIN_RATE >= 800) //up to analog value (A0) of 800, fast sweep
{
Freq_SKIP = 20 ;
}
else
{
Freq_SKIP = 40; //slow sweep above A0 value of 800
}
}
void UpdateDisplay()
{
lcd.clear();
lcd.print ("Rate:");
lcd.print (tempoValue);
lcd.print (" Adj:");
lcd.print (AdjustValue);
lcd.setCursor(0, 1);
// Update the display and the status LEDs with the current mode
if (PatternMode == MODE_CUT)
{
lcd.print (" Cut");
}
else if (PatternMode == MODE_SOFTCUT)
{
lcd.print (" Soft Cut");
}
else if (PatternMode == MODE_SqWave)
{
lcd.print (" Sq Wave");
}
else if (PatternMode == MODE_RANDOM)
{
lcd.print (" Random");
}
else if (PatternMode == MODE_UpDOWN)
{
lcd.print (" Up/Down");
}
else if (PatternMode == MODE_Freq)
{
lcd.print (" FreqOut");
}
else if (PatternMode == MODE_Adjustable)
{
lcd.print (" Adjustable");
}
else if (PatternMode == MODE_SIREN)
{
lcd.print (" Siren");
}
}
void LCD_Init()
{
lcd.print ("DubWorks Research");
lcd.setCursor(0, 1);
lcd.print(" Presents...");
// delay at the end of the full loop:
delay (2500);
lcd.clear();
}
void CheckControls()
{
// cache previous state
oldTempo = tempo;
oldPatternMode = PatternMode;
//Analog reads necessary...Self explanatory
tempo = analogRead (PIN_RATE); //Rate of speed PIN_RATE is pin Analog 0
if (tempo>=0 && tempo <=112) // Variable until 112 = menu 1
{
tempoValue = 1;
}
else if (tempo >112 && tempo<=250) // Variable until >112&&<=250 = menu 2
{
tempoValue = 2;
}
else if (tempo > 250 && tempo<=362) // Variable > 250 & < 362 = menu 3
{
tempoValue = 3;
}
else if (tempo > 362 && tempo<=474) // Variable > 362 && < 474 = menu 4
{
tempoValue = 4;
}
else if (tempo > 474 && tempo<586) // Variable > 474 & < 586 = menu 5
{
tempoValue = 5;
}
else if (tempo >586 && tempo<=698) // Variable >586 & < 698 = menu 6
{
tempoValue = 6;
}
else if (tempo >698 && tempo<=710) // Variable >698 & < 825 = menu 7
{
tempoValue = 7;
}
else if (tempo >710 && tempo<=822) // Variable above 710 = menu 8
{
tempoValue = 8;
}
else if (tempo >822 && tempo<=924) // Variable above 822 = menu 9
{
tempoValue = 9;
}
else if ( tempo<=924 ) // Variable above 924 = menu 10
{
tempoValue = 10;
}
/* Trying to keepthings neat in the display; PIN_ModeAdjust is Analog pin 2
*/
Adjust = analogRead (PIN_ModeAdjust); //Adjust=fine tune of swing in changes
if (Adjust>=0 && Adjust <=112) // Variable until 125 = menu 1
{
AdjustValue = 1;
}
else if (Adjust >112 && Adjust<=250) // Variable until 125 = menu 2
{
AdjustValue = 2;
}
else if (Adjust > 250 && Adjust<=362) // Variable > 250 & < 375 = menu 3
{
AdjustValue = 3;
}
else if (Adjust > 362 && Adjust<=474) // Variable > 375 && < 500 = menu 4
{
AdjustValue = 4;
}
else if (Adjust > 474 && Adjust<586) // Variable > 500 & < 625 = menu 5
{
AdjustValue = 5;
}
else if (Adjust >586 && Adjust<=698) // Variable >625 & < 750 = menu 6
{
AdjustValue = 6;
}
else if (Adjust >698 && Adjust<=710) // Variable >750 & < 825 = menu 7
{
AdjustValue = 7;
}
else if (Adjust >710 && Adjust<=822) // Variable above 825 = menu 7
{
AdjustValue = 8;
}
else if (Adjust >822 && Adjust<=924) // Variable above 825 = menu 7
{
AdjustValue = 9;
}
else if ( Adjust<=924 ) // Variable above 825 = menu 7
{
AdjustValue = 10;
}
/* Menu pot on Anaog Pin 1
*/
int v = analogRead (PIN_ModePot); //Analog read to give value for menu variable
if (v >=0 && v <=125) // Variable until 125 = menu 1
{
PatternMode = MODE_CUT;
}
else if (v >125 && v<=250) // Variable until 125 = menu 2
{
PatternMode = MODE_SOFTCUT;
}
else if (v > 250 && v<=375) // Variable > 250 & < 375 = menu 3
{
PatternMode = MODE_SqWave;
}
else if (v > 375 && v<=500) // Variable > 375 && < 500 = menu 4
{
PatternMode = MODE_UpDOWN;
}
else if (v > 500 && v<625) // Variable > 500 & < 625 = menu 5
{
PatternMode = MODE_RANDOM;
}
else if (v >625 && v<=750) // Variable >625 & < 750 = menu 6
{
PatternMode = MODE_Freq;
}
else if (v >750 && v<=825) // Variable >750 & < 825 = menu 7
{
PatternMode = MODE_Adjustable;
}
else if (v >825) // Variable above 825 = menu 8
{
PatternMode = MODE_SIREN;
}
}
//Freqout code by Paul Badger
// Freq - Frequency value
// t - time duration of tone
void Freqout(int Freq, int t)
{
int hperiod; //calculate 1/2 period in us
long cycles, i;
// subtract 7 us to make up for digitalWrite overhead - determined empirically
hperiod = (500000 / ((Freq - 7) * pitchval));
// calculate cycles
cycles = ((long)Freq * (long)t) / 1000; // calculate cycles
for (i=0; i<= cycles; i++)
{ // play note for t ms
digitalWrite (PIN_PwmOut, HIGH); //Pin 11 on board, digitalWrite (PIN_PwmOut, HIGH);
delayMicroseconds(hperiod);
digitalWrite(PIN_PwmOut, LOW);//Pin 11 on board, digitalWrite (PIN_PwmOut, HIGH); //digitalWrite(PIN_PwmOut, LOW);
delayMicroseconds(hperiod - 1); // - 1 to make up for fractional microsecond in digitaWrite overhead
}
}
// Set up the boot up message, this only needs to be
// flashed once
void StartupMessage()
{
lcd.clear();
lcd.print ("DubWorks Alpha II");
lcd.setCursor(0, 1);
lcd.print(" Rev.1");
// delay at the end of the full loop:
delay(2000);
for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
// scroll one position left:
lcd.scrollDisplayLeft();
// wait a bit:
delay(500);
}
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(" Loading...");
// delay at the end of the full loop:
delay(2000);
lcd.clear();
}
*UPDATE-This code was part of a bigger project, but here it is a schematic you can test it with. Sound is continuous, as the switch was provided by other part of the circuit, but you can still have fun testing it, if you wish to.
~click on image for better viewing
* * The LCD circuit: * * *
* LCD RS pin to digital pin 8
* LCD Enable pin to digital pin 9
* LCD D4 pin to digital pin 4
* LCD D5 pin to digital pin 5
* LCD D6 pin to digital pin 6
* LCD D7 pin to digital pin 7
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)