Sunday 11 November 2012

DubWorks Alpha II Arduino Dub siren Open Source Code



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)

7 comments:

  1. Hi mate!
    this is the warmest sounding dub siren ever!
    can you repost the wiring diagram ?

    Respect !
    Ital!Yorgos
    italensemble@gmail.com

    ReplyDelete
  2. Hi.. great work!!!!

    i would like to have the schematic diagram please....


    Give thanks
    Stefano

    rootspusher@gmail.com

    ReplyDelete
  3. Could you please repost the schematic? The image link is broken! Thanks!

    ReplyDelete
  4. Only now noticed these comments. I updated the post, with a woking circuit- Read explanation.
    This was one of my first experiments with it, so keep eyes open for new updates like the dub && Wise synth
    Hope that helps

    ReplyDelete
  5. hi! it's a very interesting project, but the documentation required is missing :((
    404
    There isn't a GitHub Pages site here.
    I can't see a 4046 anywhere, a bill of materials and a wiring schematic.
    Can you please post them? I would like to experiment with this siren

    ReplyDelete
    Replies
    1. Sorry for delay. This was an initial, simple project. Using the visual schematic should help you; pots 10 K as suitable for arduino. Ill upload a schematic soon, and also some newer versions of dub siren/Synare combo .

      Delete

Feel free to contact me with any suggestions, doubts or requests.

Bless