Arduino Forum

Using Arduino => Audio => Topic started by: Rupertt on Apr 22, 2011, 10:02 pm

Title: getting my sequencer BPM conform
Post by: Rupertt on Apr 22, 2011, 10:02 pm
Hello,
i build a small 8 step sequencer, how can I get it to work with real BPM?
right now I have a default delay of 50ms between each step, and another 50ms for LED blink.

If my math is right it should be 7500ms for each step to get 60 BPM. is that right?

I also have a button to increase the delay by 50ms.
Is there a usual way to do this?


thnx
Title: Re: getting my sequencer BPM conform
Post by: Grumpy_Mike on Apr 22, 2011, 11:12 pm
Quote
If my math is right it should be 7500ms for each step to get 60 BPM. is that right?


I don't think so.
7500mS is 7.5 seconds so in 60 seconds you get 8 BPM (beats per minute)

For 60 BPM you need one beat every second or 1000mS.
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on Apr 23, 2011, 02:12 am
Use a Timer, much better timing. Here's my code for the timer.

Code: [Select]
void timerStart()
{
  TCCR1A = TCCR1B = 0;
  bitWrite(TCCR1B, CS11, 1);
  bitWrite(TCCR1B, WGM12, 1);
  timerSetFrequency();
  bitWrite(TIMSK1, OCIE1A, 1);
}

void timerSetFrequency()
{
  // Calculates the Frequency for the Timer, used by the PPQ clock (Pulses Per Quarter Note) //
  // This uses the 16-bit Timer1, unused by the Arduino, unless you use the analogWrite or Tone functions //
  #define frequency (((midiClockBPM)*(PPQ))/60)
  OCR1A = (F_CPU/ 8) / frequency - 1;
}

void timerStop(void)
{
  bitWrite(TIMSK1, OCIE1A, 0);
  TCCR1A = TCCR1B = OCR1A = 0;
}

ISR(TIMER1_COMPA_vect)
{
// here's your clock code
}
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on Apr 23, 2011, 02:14 am
BTW: on my code for Beat707 I use less PPQ, so I just use a counter variable to check when a step is due or not. I like to keep things at 96 PPQ for the midi clock shuffle. I can get you more details over this after tomorrow if you want me to. ;-)

Wk
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on Apr 25, 2011, 11:16 am
Hello,

thnx for that code, i still dont understand a thing of that, but I will take my time to do so.
I seens some videso of your sequencer, very nice project.

solved:
Right now(after i included a play button) I have the problem that the sequence changes tempo each
time, one fast one slower. Would this be gone if I could include your code?
(it was the switch i was using, this happens only if the circuit ist closed)
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on Apr 26, 2011, 07:51 pm
could you give me an example how I can use the above code to act as a timer and set the main frequncy to
120BPM on 8 steps?
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on Apr 26, 2011, 08:06 pm
Will do, give me 15 minutes... ;-)

Wk
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on Apr 26, 2011, 08:31 pm
Code: [Select]
/*

  Created by Beat707 (c) 2011 - http://www.Beat707.com
 
  8 Step Mini MIDI Sequencer (4 tracks)

*/

uint8_t midiClockBPM = 120; // Max 255
uint8_t midiClockPPQCounter = 0;
uint8_t midiClockSteps[4] = { B10001000, B00001000, B11111111, B00100010 };
uint8_t midiClockStepsNote[4] = { 36, 38, 42, 46 }; // Kick, Snare, HiHatClosed, HiHatOpen
uint8_t midiClockCurStep = 0;
uint8_t midiChannel = 9;
#define PPQ 96

// ======================================================================================= //
void setup()
{
  pinMode(17,OUTPUT); digitalWrite(17,LOW); // For the Beat707 Hardware - Midi Enable //
 
  Serial.begin(31250);
  sendMidiAllNotesOff();
  midiClockBPM = 120;
  midiClockPPQCounter = midiClockCurStep = 0;
  timerStart();
}

// ======================================================================================= //
void loop()
{
  //
}

// ======================================================================================= //
void timerStart()
{
  TCCR1A = TCCR1B = 0;
  bitWrite(TCCR1B, CS11, 1);
  bitWrite(TCCR1B, WGM12, 1);
  timerSetFrequency();
  bitWrite(TIMSK1, OCIE1A, 1);
}

// ======================================================================================= //
void timerSetFrequency()
{
  #define frequency (((midiClockBPM)*(PPQ))/60)
  OCR1A = (F_CPU/8) / frequency - 1;
}

// ======================================================================================= //
void timerStop(void)
{
  bitWrite(TIMSK1, OCIE1A, 0);
  TCCR1A = TCCR1B = OCR1A = 0;
}

// ======================================================================================= //
ISR(TIMER1_COMPA_vect)
{
  midiClockPPQCounter++;
  if (midiClockPPQCounter >= 24)
  {
    midiClockPPQCounter = 0;
 
    for (uint8_t x=0; x<4; x++)
    {
      if (bitRead(midiClockSteps[x],midiClockCurStep))
      {
        sendMidiNoteOff(midiClockStepsNote[x]); // Stop Previous Note //
        sendMidiNoteOn(midiClockStepsNote[x], 127);
      }
    }
   
    midiClockCurStep++;
    if (midiClockCurStep >= 8) midiClockCurStep = 0;
  }
}

// ======================================================================================= //
void sendMidiNoteOn(char note, char velocity)
{
  Serial.write(0x90+midiChannel);
  Serial.write(note);
  Serial.write(velocity);
}

// ======================================================================================= //
void sendMidiNoteOff(char note)
{
  Serial.write(0x80+midiChannel);
  Serial.write(note);
  Serial.write((byte)0x00);
}

// ======================================================================================= //
void sendMidiAllNotesOff()
{
  Serial.write(0xB0+midiChannel);
  Serial.write(0x7B);
  Serial.write((byte)0x00);
}


Have Fun!  8)
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on Apr 26, 2011, 08:33 pm
Now, just add some code to change midiClockSteps[] in real-time to edit the steps for each of the 4 tracks. And its easy to add more tracks if you want to.  :smiley-mr-green:

Wk
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on Apr 27, 2011, 09:38 pm
Now, there's an important thing I forgot to mention... you can't use millis() or delay() at all. Use the following code instead, otherwise midi-timing will be bad...

Code: [Select]
// The Following is to implement millis() and delay() without messing up with the midi clock interrupt calls //
extern volatile unsigned long timer0_millis;
unsigned long millisNI(void) { return timer0_millis; }
void delayNI(unsigned long ms)
{
  unsigned long endtime;
  endtime = timer0_millis + ms;
  while (((long)endtime - (long)timer0_millis) > 0)
  {
    ;
  }
}
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on May 01, 2011, 05:56 pm
Hello,

i integrated your code, but i still dont get how to set the steps/delay inside my code:

this is one of my steps, you can see the the "  delay(currentTime);" defines the time until the next step is called.
Code: [Select]

if(x==0){
          //channel 1
            if (currentSwitchState1 == 1) {
                AnalogValue1 = analogRead(0);
                note1 = AnalogValue1/8;
                noteOn(0xB0, 0x7B, 0x00);
                noteOn(0x90, note1, 0x7F);
                //einstellen wie lange der sound ausklingt
                //  81  2B  4D
                digitalWrite(LEDpin1, HIGH);
                delay(50);
                digitalWrite(LEDpin1, LOW);
                delay(currentTime);
            } else {
              delay(currentTime);
            }
        }


sorry, but i come from the web programming and have only little experience in microcontroller and C programming.

cheers
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on May 01, 2011, 05:57 pm

Hello,

i integrated your code, but i still dont get how to set the steps/delay inside my code:

this is one of my steps, you can see the the "  delay(currentTime);" defines the time until the next step is called.
Code: [Select]

if(x==0){
          //channel 1
            if (currentSwitchState1 == 1) {
                AnalogValue1 = analogRead(0);
                note1 = AnalogValue1/8;
                noteOn(0xB0, 0x7B, 0x00);
                noteOn(0x90, note1, 0x7F);
                //einstellen wie lange der sound ausklingt
                //  81  2B  4D
                digitalWrite(LEDpin1, HIGH);
                delay(50);
                digitalWrite(LEDpin1, LOW);
                delay(currentTime);
            } else {
              delay(currentTime);
            }
        }


this is how i increase/decrease my delay:
Code: [Select]
currentTimeState = digitalRead(timePin1);
      if (currentTimeState == 1) {
        currentTime = currentTime + 50;
      }

  currentTimeStateDown = digitalRead(timePin2);
      if (currentTimeStateDown == 1) {       
        if (currentTime <= 50) {
          currentTime = 100;
        } else {     
          currentTime = currentTime - 50;
        }
      }
     


sorry, but i come from the web programming and have only little experience in microcontroller and C programming.

cheers
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on May 22, 2011, 04:27 pm
Hello,

i tried to exchange my delay with your delayNI.
sadly the sequencer doenst start at all, it doesnt even start when I just enter your function and use the normal delay.

Did you realize your project alone or did you have help?
Im thinking about joining someone, i have good iedas, but my C programming lacks a bit
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on May 22, 2011, 04:30 pm
Maybe try posting the entire code so we can all take a look at it? ;-)

Wk
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on May 22, 2011, 04:47 pm
thats all i got  8)

The code was to long to post, so I attached the source file.

Still have so many ideas for this project, but one step after another (nice in this context)
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on May 25, 2011, 09:32 pm
is my code that bad?
Its supposed to be a old style sequencer where you have a potentiometer for each step.
Is it wise to use a simple "for" to programm a sequence or are there better ways in microcontroller programming?
Title: Re: getting my sequencer BPM conform
Post by: WilliamK Govinda on May 26, 2011, 12:39 pm
Sorry, haven't got the time to check it out just yet.  :smiley-red:

Wk
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on Jul 06, 2011, 06:52 pm
did anyone ever took a look at my code,
just build a case and now im back to optimizig the code.
Would still love a solid standalone clocked device.

I only have 8 steps now, is it possible to have 2x8 Steps that work with a different tempo?
Title: Re: getting my sequencer BPM conform
Post by: Rupertt on Jul 09, 2011, 07:52 pm
i changed a lot the last hours, much thinner code now