Badaboombox

##        #     #               #
# #  ## ###  ## ### ### ### ### ### ### # #
##  # # # # # # # # # # # # ### # # # #  #
# # ### ### ### ### ### ### # # ### ### # #
##

________________________________________________________________________

My and my buddy Gange decided we wanted a fat vicious and malevolent
music-machine to bring to festivals, for our own listening pleasure when
sitting by the tent and drinking coffee and eating donuts.

Anyway, what we figured was that since we are noobs at building this
type of things we wanted a modular environment. That is we wanted to be
able to exchange parts for other similar but louder ones.

So what we ended up with are pictured here, its a frame made of
particle board. The speakers where bought in a low-price store
(the sound is good though). Car battery from when I thought that it
was dead on my wife’s car and bought a new one for her.
Stereo is really an LG something (although there is a Panasonic on the
picture) the reason we choose the LG is because of its ability to play
MP3’s and also because its 4x50w output (louder 🙂 .
The connector to the stereo pictured is one that came with the box.

Ohh, and we made the frame ourself.
In total this beasts way in at 32kg, which is a lot, so we have a little
carriage for transport.


A view from the top, the babe 🙂


The front with loudspeakers moved to the sides (the cables are about 1,5
meters with a knot as enders)


Box opened, car stereo and battery shown.


Where we soldered and connected everything together.


Yeah, I really want better connectors (and shielded aswell)

A few tips to end this little nonsense page with:
* Be careful
* Try to use car battery’s that doesn’t have water in them.
* Have fun
* Be careful

Arduino step sequencer

   Oo    .oOOOo.  .oOOOo.
  o  O   o     o  o     o
 O    o  O.       O.
oOooOoOo  `OOoo.   `OOoo.
o      O       `O       `O
O      o        o        o
o      O O.    .O O.    .O
O.     O  `oooO'   `oooO'
Arduino Step Sequencer

Introduction

A stepsequencer is by wikipedia a “special case” of musical sequencer. But
I figure you know what a stepsequencer is if you’re reading this page, about
me making a stepsequencer with an Arduino. The main reason is probably that
I burned my Gorf when assembling it.
Fiddling with it got me thinking about what I wanted of a step-sequencer and
how I wanted to use it when composing music. The gorf to me was a bit to
small. Dont get me wrong small is nice and all, but not the spacing between
controls. I dont preform drunk (or create music drunk either) but I’d like
my stuff to be usable while intoxicated. I would never have done this unless
I had burned the Gorf-kit :D.
Anyways I wanted a bigger display, so that I could fiddle around with
different setups and functions. I wanted rotary encoders (endless) so that
I would need fewer then 1 per step. I wanted MIDI-out, to you know, control
stuff.
Luckily for me I have a interaction-designer-musician friend that I can
discuss with. So we iterated the idea back and forth. He’s suggestions where
all great, but I didn’t take them all. Had this been a mass-market product
I where going to try to sell I’d probably taken them all, right now I only
took the ones that I wanted!

A few resources have been helpful for me while creating the Ass here is a list:

http://www.arduino.cc/playground/Main/RotaryEncoders
Rotary Encoders, read up on these
http://arduino.cc/en/Reference/LiquidCrystal
library for the LCD screen
http://sheepdogguides.com/arduino/aht0button.htm
Information about the built in pullup resistor
http://itp.nyu.edu/physcomp/Labs/MIDIOutput
ever so useful information about the midi connections
http://todbot.com/blog/2006/10/29/spooky-arduino-projects-4-and-musical-arduino/
ever so useful information about the midi connections
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1205879808
library for the rotary encoder that I modified
http://digital-salvage.net/?p=124
very useful in getting the liquidcrystal library to work.

Hardware

1 Arduino
1 5pole DIN (MIDI)
1 Sparkfun screen
1 9v Battery holder
1 Input-connector for the battery
5 Buttons
1 OnOff switch
1 Rotary Encoder
1 Knob
1 Plastic case
2 resistors to get the contrast of the screen sane.

As you can se, we’re under 50 dollars in parts.
Everything was pretty easy putting together, and here is a schematic that
is more of a photo with drawn lines then a schematic. Hope it helps if
you want to build your own Ass.

the source

Video

Software

Everything was dead easy programming, everything except the rotary encoder.
I got a 2 dollar one, so i had problems with bouncing and noise on it, as
you’ve seen on the previous video I programmed it while sick so, yeah.
Another thing to think about is that you shouldent update the LCD screen
every time in you’re Loop function, it goes CRAZY then.
I’ve commented the code a lot so I wont go in on it here, I’ve used the
http://www.ladyada.net/library/arduino/copyforhtml.html excellent tool.

UPDATE  Magellan has supplied a much better schematics, thank you!

Here is the better schematics:

This is the Ass.pde file

/*
   Oo    .oOOOo.  .oOOOo.  
  o  O   o     o  o     o  
 O    o  O.       O.       
oOooOoOo  `OOoo.   `OOoo.  
o      O       `O       `O 
O      o        o        o 
o      O O.    .O O.    .O 
O.     O  `oooO'   `oooO'  
Arduino Step Sequencer                           
                      */     

#include <LiquidCrystal.h>
#include "rotaryEncoder.h"

#define usesMidi 1 /*enable this if you want to send midi, doesent work at all together with Serial.print debugging */
#define debugprint 0 /*this sends midi messages as text instead */

LiquidCrystal lcd(12, 11, 10, 7, 6, 5, 4); /* Utilizing the liquidcrystal library for the screen, this is a setup-call*/

RotaryEncoder rotary(2, 3); /*sweet sweet library that solves a lot of problems, I made a few changes to the original one */

/*defines for the buttons */
#define menuButton 14
#define onOffButton 15
#define lengthButton 16
#define velocityButton 17
#define playPuaseButton 18
#define noteButton  19

/*booleans to tell me if the buttons are pressed or not */
byte menuButtonIsPressed =0;
byte onOffButtonIsPressed =0;
byte lengthButtonIsPressed =0;
byte velocityButtonIsPressed =0;
byte playPuaseButtonIsPressed =0;
byte noteButtonIsPressed =0;

/*useful state variables */
byte currentlyPlaying =0;
byte currentlyEditing =0;
boolean isPlaying=true;

/*channel and instrument are for the midi messages */
byte channel=0;
byte instrument =0;

byte tempo=120;  /* bmp of our sequence */
long timeChange=250; /*a variable for calculating how long we are going to wait*/

/*a struct for our notes in our sequence*/
struct data
{
  byte  velocity;
  byte  onOff;
  byte  length;
  byte  note;
};

int numberofsteps = 8; /* at first we have 8 steps, this is pretty basic */
#define maxNumberOfSteps 17 /*that's 16*/

data myData[maxNumberOfSteps]; /*array for our notes*/

/*remembering the good old times*/
long rememberMillis=0;
long rememberMillisDisplay =0;

/*we'd like to present notenames instead of midi numbers */
char* noteNames[] = {
  "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };

void setup()
{
  /*telling everybody we're alive */
  lcd.print("Arduino Step Seq");
  delay(500);

  /*setting up the buttons */
  pinMode(menuButton,INPUT);
  pinMode(onOffButton,INPUT);
  pinMode(lengthButton,INPUT);
  pinMode(velocityButton,INPUT);
  pinMode(playPuaseButton,INPUT);
  pinMode(noteButton,INPUT);

  /*starting the builtin pullup-resistor!*/
  digitalWrite(menuButton,HIGH);
  digitalWrite(onOffButton,HIGH);
  digitalWrite(lengthButton,HIGH);
  digitalWrite(velocityButton,HIGH);
  digitalWrite(playPuaseButton,HIGH);
  digitalWrite(noteButton,HIGH);  

  /*initialization of the encoder library */
  rotary.position(0);

#if usesMidi
  Serial.begin(31250);
#else
  Serial.begin(9600);
#endif

  /*calculating the timeChange variable. milliseconds divided by 
   tempo and 16th note, or something like that. I dont remember*/
  timeChange=((60000/tempo)/8);

  /*initializing the steps in the array */
  for(int i=0;iclear();

  /*what time is now*/

  rememberMillis = millis();
  rememberMillisDisplay = millis();
}

/* a little function to print the name of the note */
void printNoteName(byte initialNote)
{
  byte octave = (initialNote / 12) - 1;
  byte noteIndex = (initialNote % 12);

  lcd.print(noteNames[noteIndex]);
  lcd.print(octave,DEC);
}

/* this functions prints what we have in the first "menu" part of the data
 tempo, channel and instrument*/
void populateDisplayMenuButtonPressed()
{

  lcd.setCursor(0, 0) ;

  lcd.print("t:");
  lcd.print(tempo,DEC);
  lcd.print(" c:");
  lcd.print(channel,DEC);
  lcd.print(" i:");
  lcd.print(instrument,DEC);

  if (!isPlaying)
  {
    lcd.setCursor(0, 1) ;
    lcd.print("PAUSED           ");
  }
  else
  {
    lcd.setCursor(0, 1) ;
    for(int i=0;iif(i==currentlyPlaying && i==currentlyEditing )
        lcd.print("+");
      else if(i==currentlyEditing)
        lcd.print("-");
      else if(i==currentlyPlaying)
        lcd.print("|");
      else
        lcd.print(".");
    }
    /* prints spaces for the rest of the line, it is better then using a 
     lcd.clear, atleast if you call lcd.clear fast/often */
    for(int i=numberofsteps;i<  maxNumberOfSteps ;i++)
    {
      lcd.print(" ");

    }
  }
}

/*this is the normal/regular display info printing routine */
void populateDisplay()
{
  lcd.setCursor(0, 0) ;
  if(isPlaying)
  {
    printNoteName(myData[currentlyEditing].note);
    lcd.print(" ");
    /*On if the note is On, Off it is Off, getting it? getting on or getting off, muhahahaha */
    if(myData[currentlyEditing].onOff)
      lcd.print("On");
    else
      lcd.print("Off");

    lcd.print(" ");
    {
      /*what kind of note what we are dealing with */
      switch (myData[currentlyEditing].length)
      {
      case 1:
        lcd.print("32nd");
        break;
      case 2:
        lcd.print("16th");
        break;
      case 3:
        lcd.print("8th");
        break;
      case 4:
        lcd.print("4th");
        break;
      case 5:
        lcd.print("2nd");
        break;
      case 6:
        lcd.print("whole");
        break;
      default:
        lcd.print("FAIL");
        break; /*we made bu bu*/
      }
    }
    lcd.print(" ");

    lcd.print(myData[currentlyEditing].velocity,DEC);
    lcd.print("       ");

    lcd.setCursor(0, 1) ;
    for(int i=0;iif(i==currentlyPlaying && i==currentlyEditing )
        lcd.print("+");
      else if(i==currentlyEditing)
        lcd.print("-");
      else if(i==currentlyPlaying)
        lcd.print("|");
      else
        lcd.print(".");
    }

    /* prints spaces for the rest of the line, it is better then using a 
     lcd.clear, atleast if you call lcd.clear fast/often */

    for(int i=numberofsteps;i<  maxNumberOfSteps ;i++)
    {
      lcd.print(" ");

    }
  }
  else
  {
    lcd.setCursor(0, 1) ;
    lcd.print("PAUSED           ");
  }
}

/* a reading the button function */
int readbutt(int button)
{
  if (digitalRead(button)==LOW)
  {
    return 1;
  }
  return 0;
} 

/* function to iterate through the buttons */
void checkButtons()
{

  if (readbutt(noteButton) && noteButtonIsPressed==false)
    noteButtonIsPressed = true;
  else if (noteButtonIsPressed==true && readbutt(noteButton)==false)
    noteButtonIsPressed = false;
  if (readbutt(menuButton) && menuButtonIsPressed==false)
    menuButtonIsPressed = true;
  else if (menuButtonIsPressed==true && readbutt(menuButton)==false)
    menuButtonIsPressed = false;
  if (readbutt(onOffButton) && onOffButtonIsPressed==false)
    onOffButtonIsPressed = true;
  else if (onOffButtonIsPressed==true && readbutt(onOffButton)==false)
    onOffButtonIsPressed = false;
  if (readbutt(lengthButton) && lengthButtonIsPressed==false)
    lengthButtonIsPressed = true;
  else if (lengthButtonIsPressed==true && readbutt(lengthButton)==false)
    lengthButtonIsPressed = false;
  if (readbutt(velocityButton) && velocityButtonIsPressed==false)
    velocityButtonIsPressed = true;
  else if (velocityButtonIsPressed==true && readbutt(velocityButton)==false)
    velocityButtonIsPressed = false;
  if (readbutt(playPuaseButton) && playPuaseButtonIsPressed==false)
    playPuaseButtonIsPressed = true;
  else if (playPuaseButtonIsPressed==true && readbutt(playPuaseButton)==false)
    playPuaseButtonIsPressed = false;
}

/*our main baby */
void loop()
{

  setCurrentValue();

  /* we dont want to update the screen to often, it freaks out */
  if( millis()-rememberMillisDisplay > 100)
  {
    rememberMillisDisplay=millis();
    checkButtons();
    if (!menuButtonIsPressed)
      populateDisplay();
    else
      populateDisplayMenuButtonPressed();
  }

  if(isPlaying)
  {

    if( millis()-rememberMillis > ((myData[currentlyPlaying].length * myData[currentlyPlaying].length )*(timeChange)))
    {
      //fuck it, we always send off, most MIDI devices wont crap themselves.
      sendMidiMessage(0x80,  myData[currentlyPlaying].note,120); //off

      currentlyPlaying++;
      if (currentlyPlaying==numberofsteps)
        currentlyPlaying=0;

      rememberMillis=millis();

      if( myData[currentlyPlaying].onOff)
        sendMidiMessage(0x90,  myData[currentlyPlaying].note, 120); //on

    }
  }

}

/* This functions makes almost all our values be more correct.
 like, we dont want negative values or out of range values */
void SanitizeValues()
{

  myData[currentlyEditing].onOff= myData[currentlyEditing].onOff % 2; //setting the current value to be inbetween 0 and 1
  myData[currentlyEditing].note= myData[currentlyEditing].note % 128; //setting the current value to be inbetween 0 and 127
  myData[currentlyEditing].velocity= myData[currentlyEditing].velocity % 128; //setting the current value to be inbetween 0 and 127
  currentlyEditing=(currentlyEditing % (numberofsteps));
  isPlaying = isPlaying%2;

  if(numberofsteps > maxNumberOfSteps)
    numberofsteps=maxNumberOfSteps;

  if(numberofsteps < 0)
    numberofsteps=0;

  instrument = instrument % 128;
  channel = channel% 17;
  tempo =tempo % 200;

}

void setCurrentValue()
{
  int encoder0Pos = rotary.position();
  if(encoder0Pos==0)
    return;

  if(menuButtonIsPressed)
  {
    if(playPuaseButtonIsPressed)
    {
      numberofsteps+=encoder0Pos;
      currentlyPlaying =0;
      currentlyEditing =0;
    }
    else if(noteButtonIsPressed)
    {
      tempo+=encoder0Pos;
      timeChange=((60000/tempo)/8);
    }
    else if(onOffButtonIsPressed)
    {
      channel+=encoder0Pos;
    }
    else if(lengthButtonIsPressed)
    {
      instrument+=encoder0Pos;
    }
    else
      currentlyEditing+=encoder0Pos;

  }
  else
  {
    if(noteButtonIsPressed)
      myData[currentlyEditing].note+=encoder0Pos;

    else if(onOffButtonIsPressed==true)
      myData[currentlyEditing].onOff+=encoder0Pos;

    else if(lengthButtonIsPressed)
    {
      myData[currentlyEditing].length+=encoder0Pos;

      if(myData[currentlyEditing].length > 6)
        myData[currentlyEditing].length=6;

      if(myData[currentlyEditing].length < 1)
        myData[currentlyEditing].length=1;

    }
    else if(velocityButtonIsPressed)
      myData[currentlyEditing].velocity+=encoder0Pos;
    else if(playPuaseButtonIsPressed)
      isPlaying+=encoder0Pos; 

    else
      currentlyEditing+=encoder0Pos;
  }

  rotary.position(0);
  SanitizeValues();
}

void sendMidiMessage(char cmd, char data1, char data2)
{

#if debugprint
  Serial.print("Sending MIDI ");
  Serial.print(cmd,DEC);
  Serial.print(" ");
  Serial.print(data1,DEC);
  Serial.print(" ");
  Serial.println(daserial.pta2,DEC);
#endif
  //not sending channel or instrument change yet...
#if usesMidi
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
#endif
}

This is the RotaryEncoder.h file

/******************************************************************************
 *  RotaryEncoder.h - Arduino library for reading RotaryEncoder encoders.
 *  Version 0.90
 *  modified by Johan Larsby 2009 May 08
 ******************************************************************************/

#ifndef RotaryEncoder_h
#define RotaryEncoder_h

#define DIGITAL_PINS (13)

class RotaryEncoder
{
    public:
		RotaryEncoder(int encoderPin1, int encoderPin2);

		void minimum(int min);
		int minimum(void);
		void maximum(int max);
		int maximum(void);
		void nominimum(void);
		void nomaximum(void);

		int position(void);
		void position(int pos);

		int pressed(void);

		static void isr(void);

    private:
		int _readEncoderPins(void);
		int _encoderPin1, _encoderPin2;

		volatile int _position;

		int _min, _max;
		bool _usingmin, _usingmax;

		volatile int _previous, _time;

		static RotaryEncoder* _instance;
};

inline void RotaryEncoder::minimum(int min)
{
    _min = min;
    _usingmin = 1;

    //  adjust position if lower than new minimum
    //_position = max(_position, min);
	_position = _position > min ? _position : min;
}

inline int RotaryEncoder::minimum()
{
    return _min;
}

inline void RotaryEncoder::maximum(int max)
{
    _max = max;
    _usingmax = 1;

    //  adjust position if higher than new maximum
    //_position = min(_position, max);
	_position = _position < max ? _position : max;
}

inline int RotaryEncoder::maximum()
{
    return _max;
}

inline void RotaryEncoder::nominimum(void)
{
    _usingmin = 0;
}

inline void RotaryEncoder::nomaximum(void)
{
    _usingmax = 0;
}

inline int RotaryEncoder::position(void)
{
    return _position;
}

inline void RotaryEncoder::position(int pos)
{
    _position = pos;
}

#endif // RotaryEncoder_h

This is the RotaryEncoder.cpp file

/******************************************************************************
 *  RotaryEncoder.cpp - Arduino library for reading RotaryEncoder encoders.
 *  Version 0.90
 *  modified by Johan Larsby 2009 May 08
 ******************************************************************************/

#include "rotaryEncoder.h"

extern "C"
{
	#include
	#include
	#include "WConstants.h"	//all things wiring / arduino
}

const int _quadrature [4][4] =
{
    { 0, 0, 0, 0 },		//  00 -> 10 is silent CW
    { 1, 0, 0, 0 },	//  01 -> 00 is CW
    { -1, 0, 0, 0 },	//  10 -> 11 is CW
    { 0, 0, 0, 0 }		//  11 -> 01 is silent CW
};

RotaryEncoder * RotaryEncoder::_instance;

RotaryEncoder::RotaryEncoder(int encoderPin1, int encoderPin2)
 : _encoderPin1(encoderPin1), _encoderPin2(encoderPin2), _position(0), _min(0), _max(0), _usingmin(0), _usingmax(0), _time(0) // constructor initializer list
{
    pinMode(encoderPin1, INPUT);
    pinMode(encoderPin2, INPUT);
    digitalWrite(encoderPin1, HIGH);	//  activate internal pullups
    digitalWrite(encoderPin2, HIGH);

    _previous = _readEncoderPins();	//  read initial position

    TIMSK2 |= (1 << TOIE2);		//  enable timer 2 overflow interrupt

    _instance = this;
}

inline int RotaryEncoder::_readEncoderPins(void)
{
    return digitalRead(_encoderPin2) << 1 | digitalRead(_encoderPin1);
}

inline void RotaryEncoder::isr(void)
{
	//____________________________________________
	//                                Read Encoder
	int quadbits = _instance->_readEncoderPins();

	if (quadbits != _instance->_previous)
	{
		int position = _instance->_position - _quadrature[_instance->_previous][quadbits];

		//  limit to minimum if assigned
		position = _instance->_usingmin ? max(_instance->_min, position) : position;

		//  limit to maximum if assigned
		_instance->_position = _instance->_usingmax ? min(_instance->_max, position) : position;

		_instance->_previous = quadbits;
	}
}

ISR(TIMER2_OVF_vect)
{
    RotaryEncoder::isr();
}

Disclamer
Everything might be wrong, nothing might be correct. you have been warned!