{"id":369,"date":"2021-02-07T20:07:43","date_gmt":"2021-02-07T19:07:43","guid":{"rendered":"http:\/\/www.hman-projects.de\/?p=369"},"modified":"2021-02-07T21:36:01","modified_gmt":"2021-02-07T20:36:01","slug":"16-step-sequencer-for-akai-mpx16-sampler-diy-arduino","status":"publish","type":"post","link":"https:\/\/www.hman-projects.de\/?p=369","title":{"rendered":"16 Step Sequencer for Akai MPX16 Sampler #DIY #Arduino"},"content":{"rendered":"\n<p>Hi, I have recycled the Code of the 16Step Sequencer to use it as a Sequencer for the Akai MPX16.<\/p>\n\n\n\n<p>I belive, it could be used for the Akai MPX8 too. To trigger the sample-pads via MIDI, I used the MIDI-Channel 10 and the MIDI-Notes 36 to 51, for Pad 1 to Pad 16.<\/p>\n\n\n\n<p>The functions are similar to the other 16-Step Sequencer.<\/p>\n\n\n\n<p>Video: <\/p>\n\n\n\n<p><a href=\"https:\/\/youtu.be\/Tr9Y971fDvM\">https:\/\/youtu.be\/Tr9Y971fDvM<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Code MPX16 Sequencer<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>\n\n\n\/\/ E.Heinemann\n\/\/ e.heinemann@hman-project.de\n\/\/ 30.10.2016 - E.Heinemann  Bonn Germany\n\/\/ 2021-02-07 - E.Heinemann Updated and modified the MIDI-Note-Numbers and their names to map it to the MPX16-Defaults\n\/\/ 2021-02-07 - E.Heinemann, new attempt to combine Menu-Button as a DN-Button with the Step-Buttons\n\n\/\/ Helping sources:\n\/\/ https:\/\/learn.sparkfun.com\/tutorials\/midi-shield-hookup-guide\/example-1-clock-generator--receiver\n\n#include &lt;Wire.h>\n#include &lt;MIDI.h>\n#include &lt;LiquidCrystal_I2C.h>\n\n\/\/ http:\/\/www.86duino.com\/?p=8254\n#include \"TimerOne.h\"\n\n\/\/ http:\/\/playground.arduino.cc\/Main\/MsTimer2\n\/\/ #in clude &lt;MsTimer2.h>\n\n\/\/ other interesting Project:\n\/\/ http:\/\/skagmo.com\n\/\/ https:\/\/www.youtube.com\/watch?v=q9LyRmzGL5g\n\/\/ https:\/\/github.com\/Catmacey\/DrumMachine\n\n\n\/\/ Projects to build the Drum-Synths\n\/\/ http:\/\/dmitry.gr\/index.php?r=05.Projects&amp;proj=02.%20Single-chip%20audio%20Player\n\/\/ http:\/\/www.enide.net\/webcms\/index.php?page=pcm2pwm\n\/\/ Coron DS7 http:\/\/m.bareille.free.fr\/ds7clone\/ds7.htm\n\/\/ http:\/\/electro-music.com\/forum\/phpbb-files\/dr_55_rimshot_clone_196.pdf\n\/\/ Monotribe schematic\n\/\/ Boss DR110 Scheamtics\n\/\/ http:\/\/www.sdiy.org\/richardc64\/new_drums\/dr110\/dr110a1.html\n\/\/ http:\/\/www.freeinfosociety.com\/electronics\/schemview.php?id=129\n\/\/ http:\/\/www.sdiy.org\/richardc64\/new_drums\/dr110\/clap_etc.html\n\/\/ Good example of needed sounds: http:\/\/delptronics.com\/ldb2e.php\n\/\/ http:\/\/pdp7.org\/boss_dr_sync\/bossdr110.html\n\/\/ http:\/\/www.theninhotline.net\/dr110\/\n\n\/\/ Pi Zero as SamplePlayer\n\/\/ https:\/\/www.raspberrypi.org\/forums\/viewtopic.php?f=38&amp;t=127585\n\n\/\/ Mozzi-based Drum\n\/\/ https:\/\/github.com\/fakebitpolytechnic\/cheapsynth\/blob\/master\/Mozzi_drumsDG0_0_2BETA\/Mozzi_drumsDG0_0_2BETA.ino\n\n\/*\n *  MPX16 receives on Channel 1 but sends on Channel 10 !\n *  Midi-Notes of the 16 Samples by default:\n *  40  41  42  43 | 48 49 50 51 \n *  36  37  38  39 | 44 45 46 47\n *  \n *  Simply Samples from Midi 36 to 51\n *  \n *\/ \n\n\n#include &lt;EEPROM.h>\n\n\n\n\/\/ Softserial is used to send MIDI via Pin TX 2, RX 3 \n#include &lt;SoftwareSerial.h>\nSoftwareSerial softSerial( 2, 3 );\nMIDI_CREATE_INSTANCE( SoftwareSerial, softSerial, midiA );\n\n\n\/\/ #define NBR_INST          16\n\/\/ #define NBR_PATTERN       16\n\/\/ #define NBR_MIDI_CH       10\n\n\/\/Midi message define\n\/\/ #define MIDI_START 0xfa\n\/\/ #define MIDI_STOP  0xfc\n\/\/ #define MIDI_CLOCK 0xf8\n\n\/\/ Not implemented yet\nuint16_t bpm = 125;          \/\/ Default BPM\nuint16_t old_bpm = bpm;      \/\/ Default BPM\n\nuint8_t midi_channel = 1;    \/\/ Default Midi Channel\nuint8_t midi_sync    = 0;     \/\/ 1 == Slave, 0 = Master - default\n\nuint8_t LCD_Address = 0x27;   \/\/ LCD is integrated via PCF8574 on Port 0x27\nLiquidCrystal_I2C lcd( LCD_Address, 16, 2 );  \/\/ simple LCD with 16x2\n\nuint8_t address1 = 0x3C;   \/\/ Address of the PCF8574 for first 8 Buttons and LEDs\nuint8_t address2 = 0x38;   \/\/ Address of the second PCF for LEDS &amp; Buttons 9 - 16\n\n\/\/ Button-Pins\nconst int buttonPinS = 4;   \/\/ Menu\/FN\/Select-Button ..near to the POT\nconst int buttonPinL = 5;   \/\/ Left- or Start-Button\nconst int buttonPinR = 6;   \/\/ Right- or Stop-Button\n\n\/\/ Value of the POT\nint     aPin3 = 3;\nint     aVal3;\nint     old_aVal3;\nuint8_t newNote; \/\/ Variable for the MidiNote in the Menu\n\nuint8_t count_step =  0;  \/\/ Step counter\nuint8_t count_bars = 16;  \/\/ count steps per Pattern, .. with 2 PCF8574, I am able to define 16 Steps max.... virtually perhaps 32....\nuint8_t count_ppqn =- 1;  \/\/ 24 MIDI-Clock-Pulse per quart note counter\n\n\/\/ Menu\nString   Modes&#91;] = { \"Instr\", \"Velo\", \"Speed\", \"Bars\", \"Note\", \"Scale\", \"Sync\" };\nuint8_t  ModesNum&#91;] = { 0, 1, 2, 3 , 4, 5, 6 };\n\n\/\/ Is the Sequencer running or not\nboolean  playBeats = true;\n\n\/\/ Current Menu Settings\nuint8_t curModeNum = 0;\nString  curMode = Modes&#91;0]; \/\/ Sound or Play\n\n\/\/ Instruments, Accent is not an Instrument but internally handled as an instrument .. therefore 17 Instruments from 0 to 16\nconst String shortSounds&#91;] ={ \"ACC\"   , \"PAD 1\", \"PAD 2\" , \"PAD 3\" , \"PAD 4\", \"PAD 5\", \"PAD 6\", \"PAD 7\", \"PAD 8\", \"PAD 9\", \"PAD 10\", \"PAD 11\", \"PAD 12\",\"PAD 13\",\"PAD 14\",\"PAD 15\",\"PAD 16\" };\nconst String Sounds&#91;]      ={ \"Accent\", \"PAD 1\", \"PAD 2\" , \"PAD 3\" , \"PAD 4\", \"PAD 5\", \"PAD 6\", \"PAD 7\", \"PAD 8\", \"PAD 9\", \"PAD 10\", \"PAD 11\", \"PAD 12\",\"PAD 13\",\"PAD 14\",\"PAD 15\",\"PAD 16\" };\nuint8_t iSound&#91;] ={ -1,  36, 37, 38, 39, 40, 41, 42, 43,  44, 45, 46, 47, 48, 49, 50, 51 }; \/\/ MIDI-Sound, edited via Menu 50=TOM, 44=closed HH, \nuint8_t iVelo&#91;]  ={ 127, 90, 90, 90, 90, 90, 90, 90, 90,  90, 90, 90, 90, 90, 90, 90, 90 }; \/\/ Velocity, edited via Menu\nuint8_t inotes1&#91;]={ 255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255, 255 };\nuint8_t inotes2&#91;]={ 255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255, 255 };\n\n\/\/ Current Instrument .. the first selected\nint curIns = 1; \/\/ 1 = PAD  1, 0= Accent\n\nuint16_t timer_time=5000; \/\/Time in microsecond of the callback fuction\nuint32_t tempo_delay;\n\n\nuint8_t bar_value&#91;]={ 1, 2, 3, 4, 6, 8, 12, 16};\n\n\/\/ array of notes would be better, 2 bytes in notes for every instrument\nuint8_t notes1; \nuint8_t notes2;\n\n\/\/ Old MIDI-Tricks, HH-Sounds first, Cymbals first, Snare, BD at least,  ... to keep a tight beat\nuint8_t oldStatus1=B00000000;\nuint8_t oldStatus2=B00000000;\nuint8_t bits1 = 0;\nuint8_t bits2 = 0;\n\n\/\/ Scale, Menu to change Scale is yet not implemented\nuint8_t scale=1 ;\/\/Default scale  1\/16\nuint8_t      scale_value&#91;]  = {     3,      6,    12,     24,       8,       16 };\nconst String scale_string&#91;] = { \"1\/32\", \"1\/16\", \"1\/8\", \"1\/4\",  \"1\/8T\",   \"1\/4T\" };\n  \n\n\/\/ BPM to MS Conversion\n\/\/ http:\/\/www.sengpielaudio.com\/Rechner-bpmtempotime.htm\n  \n\/\/ myRefresh is only a counter .. the higher the lower the BPM! To display a good BPM this value has to be translated\nint myRefresh = 500;\nint myStep  =  0;\n\nint veloAccent  = 100;\nint velocity    = 100;\n\nint step_position = 0;\nint b = 10;\n\nuint8_t count_instr = 00;\n\nboolean oldStateS=1;\nboolean buttonStateS=1;\nboolean oldStateL=1;\nboolean buttonStateL=1;\nboolean oldStateR=1;\nboolean buttonStateR=1;\n\nString curPattern1=\"xxxxxxxxx\";\nString curPattern2=\"xxxxxxxxx\";\n\n\/\/ ### Base-Function for PCF8574 and WIRE ### \n\/\/ PCF8574 Explosion Demo (using same pin for Input AND Output)\n\/\/ Hari Wiguna, 2016\nvoid WriteIo( uint8_t bits,uint8_t thisAddress ){\n  Wire.beginTransmission(thisAddress);\n  Wire.write(bits);\n  Wire.endTransmission();\n}\n\n\/\/  ### Base-Function for PCF8574 and WIRE ### \n\/\/ PCF8574 Explosion Demo (using same pin for Input AND Output)\n\/\/ Hari Wiguna, 2016\nuint8_t ReadIo( uint8_t address ){  \n  WriteIo (B11111111, address );        \/\/ PCF8574 require us to set all outputs to 1 before doing a read.\n  Wire.beginTransmission( address );\n  \/\/ Wire.write(B11111111 );\n  Wire.requestFrom( (int) address, 1 );  \/\/ Ask for 1 byte from slave\n  uint8_t bits = Wire.read();         \/\/ read that one byte\n  Wire.requestFrom( (int) address1, 1 ); \/\/ Ask for 1 byte from slave\n  Wire.endTransmission(); \n  return bits;\n}\n\n\n\/\/ Plug MIDI-Out of MPX16 into MIDI-In of the arduino \n\/\/ Press the PAD to select the PAD\nvoid handleNoteOn( byte inChannel, byte inNote, byte inVelocity ){\n\n  \/\/ has the user pressed a PAD on the MPX16??\n  if( inChannel == 10 &amp;&amp; inNote >=36 &amp;&amp; inNote &lt;= 51){\n    Select_Instr( inNote - 35 );  \n   }\n    \/\/ const bool firstNote = midiNotes.empty();\n    \/\/ midiNotes.add(MidiNote(inNote, inVelocity));\n    \/\/ handleNotesChanged(firstNote);\n}\n\n\n\/\/ Callback from Timer1\nvoid callback(){ \n  if( old_bpm != bpm ){\n    Timer1.initialize(tempo_delay); old_bpm = bpm;\n  }\n  count_ppqn++;    \n  if( count_ppqn >= scale_value&#91;scale] ){  \n    step_position++;\n    if( step_position >= count_bars ){\n      step_position=0;\n    }\n    Update_Midi();\n    count_ppqn =0;\n    digitalWrite(13, digitalRead(13) ^ 1);\n  }     \n\n  \/\/ lcd.setCursor(0,1);\n  \/\/ lcd.print (\"Step:\" + String(step_position) + \" \" + scale_value&#91;scale] );\n        \n}\n\n\/\/ ########################### Show Notes and current Step via LEDs #########################\nvoid showStep ( int mystep, uint8_t address1, uint8_t address2, uint8_t notes1, uint8_t notes2 ){\n  uint8_t bitdp1 = notes1;\n  uint8_t bitdp2 = notes2;\n\n  \/\/ Current Step would be only shown if played\n  if( playBeats==true ){ \n   if( mystep &lt;  8 ){ bitClear( bitdp1, step_position ); }\n   if( mystep >= 8 ){ bitClear( bitdp2, ( step_position-8 ) ); }\n  }\n   \n  WriteIo( bitdp1, address1 );\n  WriteIo( bitdp2, address2 );\n}\n\n\n\/\/ ############################ Play the Midi-Notes ##################################### \nvoid Update_Midi() {\n  \/\/ first 8 beats\n  if( playBeats==true ){\n    \n    veloAccent = 100; \/\/ Normal Velocity by default\n    \/\/ first Byte or first 8 Hits\n    \/\/ \"song_position\" is the current step \n    if( step_position&lt;8 ){ \/\/ play notes1\n       \/\/ Accent set?\n       if( bitRead( inotes1&#91;0],step_position ) == 0 ){\n         \/\/ Accent is set\n         veloAccent = iVelo&#91;0];\n       } \n       \/\/ loop through all instruments .. But ignore Accent with 0       \n       for( int i = 1; i &lt; count_instr; i++ ){\n         if( bitRead( inotes1&#91;i],step_position ) == 0 ){\n           velocity  = round( iVelo&#91;i] * veloAccent \/ 100);\n           if( velocity > 127 ) {\n             velocity = 127; \n           }\n           midiA.sendNoteOff( iSound&#91;i],         0, midi_channel );       \n           midiA.sendNoteOn(  iSound&#91;i], velocity ,midi_channel );\n         }  \n       }\n    }\n    \n    \/\/ second Byte or second 8 Steps\n    \/\/ bitClear(bitdp2, (a-8));\n    if( step_position >= 8 ){ \n       \/\/ play Notes2\n      if (bitRead( inotes2&#91;0],step_position ) == 0){ \/\/ Accent is set\n        veloAccent = iVelo&#91;0];\n      } \n       \n      \/\/ loop through all instruments .. but ignore the Accent with 0\n      for( int i = 1; i &lt; count_instr; i++ ){\n        if( bitRead( inotes2&#91;i], ( step_position-8 ) ) == 0 ){\n          velocity  = round(iVelo&#91;i] * veloAccent \/ 100);\n          if( velocity > 127 ){\n            velocity = 127; \n          }\n          midiA.sendNoteOff( iSound&#91;i],         0, midi_channel );       \n          midiA.sendNoteOn(  iSound&#91;i], velocity , midi_channel );\n        }  \n      }   \n    }\n  }\n}\n\n\/\/ ############################## Select another Instrument and update all variables and LCD ###########\nvoid Select_Instr( int newIns ){\n \/\/  if ( newIns != curIns ){\n  curIns = newIns;\n  if( newIns >= count_instr ){\n    curIns = count_instr-1; \n  }   \n  lcd.setCursor(0,0);\n  lcd.print( curMode  + \" \" + Sounds&#91; curIns ]  + \" \" + iVelo&#91; curIns ] +\"    \");\n  \n  curPattern1=\"\";\n  curPattern2=\"\";\n  \n  notes1 = inotes1&#91;curIns];\n  notes2 = inotes2&#91;curIns]; \n  \/\/ Show new Pattern on the Display\n  for( int i = 1; i &lt; 8; i++){\n    if( bitRead( notes1, i ) == 0 ){ \n      curPattern1 = curPattern1 + \"X\";\n    }else{ \n      curPattern1 = curPattern1 + \"-\";\n    } \n    if( bitRead( notes2, i ) == 0 ){ \n      curPattern2 = curPattern2 + \"X\";\n    }else{ \n      curPattern2 = curPattern2 + \"-\";\n    } \n  }\n  lcd.setCursor(0,1);\n  lcd.print( curPattern1 + curPattern2 );\n}\n\n\n\n\/\/ ################################ Check the Potentiometer ##############################\nvoid Check_POT() {\n      \/\/ Check the POT -- Menu-Functions\n  aVal3 = round( analogRead( aPin3 ) \/8 );\n  if ( aVal3 != old_aVal3  ){ \n    \/\/ Correction\n    myStep = myStep + 120; \n\n      \/\/ Select Instrument Menu\n      if( curModeNum==0 ){\n        Select_Instr( round(aVal3\/8) );      \n      }\n      \n      \/\/ Velocity\n      if( curModeNum==1 ){\n          if ( aVal3 > 127 ) { aVal3=127;}\n          lcd.setCursor(0,0);\n          lcd.print( curMode + \" \" + String(aVal3) + \" \" + Sounds&#91; curIns ] + \"     \");\n          iVelo&#91; curIns ] = aVal3;  \n      }\n\n      \/\/ Speed-Menu\n      if( curModeNum==2 ){\n          old_bpm = bpm;\n          bpm = round(analogRead(aPin3)\/4 + 40);\n          lcd.setCursor(0,0);\n          lcd.print( curMode + \" \" + String(bpm) +\" bpm   \");\n          tempo_delay = 60000000 \/ bpm \/ 24;\n      }\n      \n      \/\/ Bars\n      if( curModeNum==3 ){\n          if ( aVal3 > 127 ) { aVal3=127;}\n          count_bars = round(aVal3 \/ 8)+1;\n          if ( count_bars>16 ) \n            { count_bars=16; } \/\/ max of this setup\n             lcd.setCursor(0,0);\n          lcd.print( curMode + \"  \" + String( count_bars ) +\"      \");\n\n      }\n\n      \/\/ Midi-Notes, perhaps we find a good Midi-Reference to replace Note and Name\n      if( curModeNum==4  &amp;&amp; curIns>0 ){   \/\/ 30 to 70 make sense\n          newNote = round(aVal3\/3) + 25;\n          if ( newNote > 70 ) { newNote =70;}\n          if ( newNote &lt; 30 ) { newNote =30;}\n          lcd.setCursor(0,0);\n          lcd.print( curMode + \" \" + String(newNote) + \" \" + Sounds&#91; curIns ] + \"     \");\n          iSound&#91; curIns ] = newNote; \n      }\n\n      \/\/ Scale\n      if( curModeNum==5 ){\n          if( aVal3 > 127 ) { aVal3=127; }\n          scale = round(aVal3 \/ 16 );\n          if( scale >= sizeof( scale_string ) ){ scale = sizeof( scale_string )-1 ; }\n          lcd.setCursor(0,0);\n          lcd.print( curMode + \"  \" + scale_string&#91; scale ] + \"      \" );\n      }\n      \n      old_aVal3 = aVal3;    \n    }\n}\n\n\/\/ ################################ Check Menu - Buttons --#######################\nvoid Check_MENU() {\n    \/\/ Check if Menu-Button or Start or Stop was pressed\n    buttonStateS = digitalRead( buttonPinS ); \/\/ OLD: Menu changes on buttonpress .. not on release. NEW: It has to change the Menu on \"Release\" of the button\n                                              \/\/ Acting by release offers to do something while the button is pressed. ... faster Change \n    buttonStateL = digitalRead( buttonPinL );\n    buttonStateR = digitalRead( buttonPinR );\n    \n    if( oldStateS==1 &amp;&amp; buttonStateS == 0 ){\n      curModeNum = curModeNum +1;\n      if( curModeNum >(5-playBeats) ){ curModeNum = 0 ;} \n      curMode= Modes&#91;curModeNum];\n      lcd.setCursor(0,0);\n      if( curModeNum != 3 &amp;&amp; curModeNum != 2 &amp;&amp; curModeNum != 5 ){\n        lcd.print( curMode  + \" \" + Sounds&#91; curIns ] +\" \" + buttonStateS  + \"      \");\n      }else{\n        if( curModeNum == 3 ){\n          lcd.print( curMode + \"  \" + String( count_bars ) +\"      \" );\n        } \n        if( curModeNum == 2 ){ \/\/ Speed\n          lcd.print(  curMode + \" \" + String(bpm) +\" bpm    \"   );\n        }\n        if( curModeNum == 5 ){\n          lcd.setCursor(0,0);\n          lcd.print( curMode + \"  \" + scale_string&#91; scale ] +\"      \"  );\n        }\n      } \n    }\n    \n    if( playBeats == false &amp;&amp; buttonStateL != oldStateL &amp;&amp; buttonStateL == LOW ){\n      \/\/ Start-Button\n      step_position=0;\n      playBeats = true;\n      lcd.setCursor(0,1);\n      lcd.print( \"Started Beating \" );\n      \/\/ MIDI-Clock\n      midiA.sendRealTime( MIDI_NAMESPACE::Start );\n    }\n    if( playBeats == true &amp;&amp; buttonStateR != oldStateR &amp;&amp; buttonStateR == LOW ){\n      \/\/ Stop-Button\n      step_position=0;\n      playBeats = false;\n      lcd.setCursor(0,1);\n      lcd.print( \"Stopped Beating \");\n      midiA.sendRealTime(MIDI_NAMESPACE::Stop);\n    }\n    oldStateS = buttonStateS;\n    oldStateL = buttonStateL;\n    oldStateR = buttonStateR;\n}\n\n\/\/ ############################## Check the Buttons for Notes #################################\nvoid Check_DrumButtons() {\n  \n  \/\/-- Don't do anything unless they press a switch --\n  \n   \/\/ Unless they're all high...  \n  if ( bits1 != B11111111 &amp;&amp; oldStatus1 != bits1 ){  \n    \/\/-- Find lowest pressed switch --\n    for( byte bitIndex = 0; bitIndex &lt; 8; bitIndex++ ){\n      if( bitRead(bits1, bitIndex) == 0) {\n        if( oldStateL == HIGH ) {\n         if( bitRead(notes1, bitIndex) == 1) {\n           bitClear( notes1, bitIndex ); \n          }else{\n            bitSet( notes1, bitIndex );\n          } \n          inotes1&#91;curIns] = notes1;\n        }else{\n          \/\/ Instrument_Select\n          Select_Instr( bitIndex );\n        }\n        exit;\n      }    \n    }  \n  }\n\n  \/\/ Unless they're all high...\n  if ( bits2 != B11111111  &amp;&amp; oldStatus2 != bits2 ){\n    \/\/-- Find lowest pressed switch --\n    for( byte bitIndex = 0; bitIndex &lt; 8; bitIndex++){\n      if( bitRead(bits2, bitIndex) == 0 ){\n        \/\/  Both Buttons areL and S are not pressed!\n        \n        if( oldStateL == HIGH ){ \n          \/\/ &amp;&amp; oldStateS == HIGH )\n          if( bitRead(notes2, bitIndex ) == 1){\n             bitClear(notes2, bitIndex ); \n           }else{\n             bitSet( notes2, bitIndex ); \n           }  \n           inotes2&#91;curIns] = notes2;\n           \/\/ Serial.println (\"Bit Cleared\");\n           \/\/ } \n           \/\/ ExplosionAnimation(bitIndex, address2);\n          \n        }else{\n          \/\/ left 2 Bits to change the Scale\n          if( bitIndex == 0 ){ \n            if( scale > 0 ){ scale = scale-1; }\n            lcd.setCursor(0,0);\n            lcd.print( Modes&#91;5] + \"  \" + scale_string&#91; scale ] +\"      \"  );\n          }\n          \/\/ left 2 Bits to change the Scale\n          if( bitIndex == 1 ){ \n            scale = scale+1;\n            if ( scale >=4){ scale=0; }\/\/ only llop through straight scales \n            lcd.setCursor(0,0);\n            lcd.print( Modes&#91;5] + \"  \" + scale_string&#91; scale ] +\"      \"  );\n          }\n\n          \/\/ left 4 Bits to change the Scale\n          if( bitIndex==6 ){\n             old_bpm = bpm;\n             bpm = bpm - 2;\n             if( bpm &lt; 40 ){ bpm=40; }\n             lcd.setCursor(0,0);\n             lcd.print( Modes&#91;2] + \" \" + String(bpm) +\" bpm   \"  );\n             tempo_delay = 60000000 \/ bpm \/ 24;\n          }\n          \n          \/\/ add some speed to BPM\n          if( bitIndex==7 ){\n            old_bpm = bpm;\n            bpm = bpm + 2;\n            if (bpm > 300){ bpm=300; }\n            lcd.setCursor(0,0);\n            lcd.print( Modes&#91;2] + \" \" + String(bpm) +\" bpm   \"  );\n            tempo_delay = 60000000 \/ bpm \/ 24;\n          }\n        } \n        exit;\n      }    \n    }\n  }\n  oldStatus1 = bits1;\n  oldStatus2 = bits2; \n}\n\n\n\n\/\/ #### Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup Setup #####\n\nvoid setup(){\n\n  \/\/ for Debugging\n  \/\/ Serial.begin( 115200 );\n\n  pinMode(13, OUTPUT);\n  \n  lcd.init(); \/\/ initialize the lcd \n  \/\/ Print a message to the LCD\n  lcd.backlight(); \/\/ I have not enabled that pin... at my box, the backlight is always on, via hardwire.\n  lcd.print( \"hman-Projects.de\" ); \/\/ &lt;&lt; put in Your prefered Name for this Sequencer into this variable:)\n\n  count_instr = sizeof(iSound);\n\n  Wire.begin(); \/\/ Arduino UNO uses (SDA=A4,SCL=A5)\n  \/\/ Wire.begin(0,2); \/\/ ESP8266 needs (SDA=GPIO0,SCL=GPIO2)\n\n  pinMode(buttonPinS, INPUT); \/\/ Selecct Button\n  pinMode(buttonPinL, INPUT); \/\/ Left- or Start-Button\n  pinMode(buttonPinR, INPUT); \/\/ Right- or Stop-Button\n  \n  \/\/ virtual Pull-Up-Resitor activated, Pins are by default \"HIGH\"\n  digitalWrite( buttonPinS, HIGH); \/\/ Selecct Button\n  digitalWrite( buttonPinL, HIGH); \/\/ Left- or Start-Button\n  digitalWrite( buttonPinR, HIGH); \/\/ Right- or Stop-Button\n\n  notes1 = B11111111; \/\/ Bitwise per Instrument, No Note equals \"1\", note to play equals \"0\" !\n  notes2 = B11111111;\n  midiA.setHandleNoteOn( handleNoteOn );\n  midiA.begin( MIDI_CHANNEL_OMNI );   \/\/ Midi-Input for Sync\n  midiA.turnThruOff(); \/\/ this prevents the MPX16 to collaps\n  \n  tempo_delay = 60000000\/bpm\/24;      \/\/ delay in Microseconds ....\n  Timer1.initialize( tempo_delay );   \/\/ initialize timer1, and set a 1\/2 second period\n  Timer1.attachInterrupt( callback );  \n}\n\n\nvoid Read_Switches(){\n  bits1 = ReadIo( address1 ); \/\/ Read all switches\n  bits2 = ReadIo( address2 ); \/\/ Read all switches\n}\n\n\n\n\/\/ ############################################ void loop #################################################\n\nvoid loop() {\n  \/\/ b is a simple Counter to do nothing  \n  b ++;\n  \/\/ read the IO-Pins every 5 cycles\n  if( b > 4 ){ \n    \/\/ Update the LEDs\n    showStep( step_position, address1, address2, notes1, notes2 );\n    Check_MENU();\n    b = 0;\n  }\n\n  myStep ++; \/\/ This is second counter to find the right time to get the new values from the BUTTONS and the POT\n  \n  if( myStep >= myRefresh ){\n    myStep = 0;\n    Read_Switches();\n    Check_POT();\n    Check_MENU();\n    Check_DrumButtons(); \n    \/\/ lcd.setCursor(0,1);\n    \/\/ lcd.print (\"Step:\" + String(step_position) + \" \" + scale_value&#91;scale] + \" \" + String(scale) + \"   \" );\n  } \n\n\n  \/\/ Check MIDI IN\n  \/\/ Is there a MIDI message incoming ?\n  midiA.read();\n  \/*\n    switch( midiA.getType()){      \/\/ Get the type of the message we caught\n      \/\/ case midi::ProgramChange:       \/\/ If it is a Program Change,\n      \n        \/\/ BlinkLed(MIDI.getData1());  \/\/ blink the LED a number of times\n                                            \/\/ correponding to the program number\n                                            \/\/ (0 to 127, it can last a while..)\n      \/\/ case midi::                                            \n      break;\n        \/\/ See the online reference for other message types\n        default:\n        break;\n     }\n  *\/\n}\n\n   \n\n\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\/\/This function is call by the timer depending Sync mode and BPM\/\/\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\nvoid Count_PPQN(){\n  \n\/\/-----------------Sync SLAVE-------------------\/\/  \n\/*  if(midi_sync){\n    timer_time=5000;\n    if (midiA.read())                \/\/ Is there a MIDI message incoming ?\n     {\n      byte data = midiA.getType();\n      if(data == midi::Start ){\n        if(playBeats==true) \/\/mode==MODE_PATTERN_PLAY || mode==MODE_PATTERN_WRITE || mode==MODE_INST_SELECT)\n        {\n          playBeats=true;\n          \/\/ play_pattern = 1;\n          count_ppqn=-1;\n        }\n        \n        \/\/if(mode==MODE_SONG_PLAY || mode==MODE_SONG_WRITE){\n        \/\/  play_song = 1;\n        \/\/  count_ppqn=-1;\n        \/\/  song_position=0;\n        \/\/ }\n      }\n      else if(data == midi::Stop ) {\n        playBeats=false;\n        \/\/ play_pattern = 0;\n        \/\/ play_song = 0;\n        \/\/ count_step=0;\n        step_position=0;\n        count_ppqn=-1;\n        \/\/ song_position=0;\n      }\n      else if(data == midi::Clock &amp;&amp; playBeats==true) \/\/(play_pattern == 1 || play_song == 1))    case midi::Clock\n      {\n        count_ppqn++;\n        count_step=count_ppqn\/scale_value&#91;scale];\n        if(count_ppqn>=(count_bars * scale_value&#91;scale])-1) {\n          count_ppqn=-1; \n          step_position++;     \n          \/\/ song_position++;\n          \/\/ if (song_position==16) song_position=0;\n          if ( step_position >= count_bars ) { step_position=0; }\n          \/\/ Play Notes!!\n          Update_Midi();\n          \/\/ Request news from Drum-Buttons\n          Check_DrumButtons(); \n          \/\/ Update the LEDs \n          showStep (step_position, address1, address2, notes1, notes2 );  \n        }\n        \/\/ if (count_ppqn>1) led_flag=0;\/\/Led clignote reste ON 1 count sur 6\n        \/\/ if (count_ppqn&lt;=1) led_flag=1; \n        \/\/ led_flag=!led_flag;  \n      }\n      \/\/ if (data==MIDI_CLOCK &amp;&amp; (play_pattern == 0 || play_song==0)){\n      \/\/  count_led++;\n      \/\/  if(count_led==12){\n      \/\/    count_led=0;\n      \/\/    led_flag=!led_flag;\n      \/\/  }\n      \/\/}\n      \n    }\n  }\n  \/\/-----------------Sync MASTER-------------------\/\/\n  if(!midi_sync){\n  *\/\n    \/\/ timer_time=2500000\/bpm;\n    \/\/ midiA(MIDI_CLOCK);\n     digitalWrite(13, digitalRead(13) ^ 1);\n    \/* \n    lcd.setCursor(0,1);\n    lcd.print( \" Timer\" + String( count_ppqn ) ); \n\n    \n    \/\/ midiA.sendRealTime(MIDI_NAMESPACE::Clock);\n    if( playBeats==true ) \/\/play_pattern||play_song)\n    {   \n      count_ppqn++;    \n      count_step=count_ppqn\/scale_value&#91;scale];   \n      if(count_ppqn>=(count_bars*scale_value&#91;scale])-1){\n        count_ppqn=-1;\n        step_position++;\n        \/\/ if (song_position==16) song_position=0;\n        if ( step_position>= count_bars ) { step_position=0; }\n        \/\/ Play Notes\n        Update_Midi();\n        Check_DrumButtons(); \n        \/\/ Update the LEDs \n        showStep (step_position, address1, address2, notes1, notes2 );\n      }\n      \/\/ if (count_ppqn>1) led_flag=0;\/\/Led blink 1 count on 6\n      \/\/ if (count_ppqn&lt;=1) led_flag=1; \n      \/\/ led_flag=!led_flag;\n    }\n    else if(playBeats==false) \/\/ !play_pattern &amp;&amp;!play_song)\n    {\n      count_ppqn=-1;\n      step_position=0;\n      \/\/ count_led++;\n      \/\/ song_position=0;\n      \/\/ if(count_led==12){\n      \/\/  count_led=0;\n      \/\/  led_flag=!led_flag;\n      \/\/ }\n      \n    }\n\/\/   }\n*\/\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Hi, I have recycled the Code of the 16Step Sequencer to use it as a Sequencer for the Akai MPX16. I belive, it could be used for the Akai MPX8 too. To trigger the sample-pads via MIDI, I used the MIDI-Channel 10 and the MIDI-Notes 36 to 51, for Pad 1 to Pad 16. The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-369","post","type-post","status-publish","format-standard","hentry","category-allgemein"],"_links":{"self":[{"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=\/wp\/v2\/posts\/369"}],"collection":[{"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=369"}],"version-history":[{"count":4,"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=\/wp\/v2\/posts\/369\/revisions"}],"predecessor-version":[{"id":376,"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=\/wp\/v2\/posts\/369\/revisions\/376"}],"wp:attachment":[{"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=369"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=369"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hman-projects.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=369"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}