#include "TimerOne.h"
// group preset channel steps
// steps are the bits in the byte
byte patternData[8][8][8] = {0};
byte currentGroup = 0;
byte currentPreset = 0;
byte nextPreset = 0;
// the following are used in the UI
byte active_group = 0;
byte active_preset = 0;
byte active_channel = 0;
// each bit in this corresponds to one preset that should be in the loop or not
// 00000101 means that preset 0 and preset 2 should be in the loop.
// 00000011 means that preset 0 and preset 1 should be in the loop.
byte loopPresets = B00000011;
byte tick = 0;
// this is the different output channels
byte triggerOutputData = 0;
enum Mode : byte {
normal = 0,
select_pattern = 1,
select_group = 2,
};
void onClock() {
tick++;
tick %= 8;
Serial.print(tick);
Serial.print(" ");
// reset output trigger data
triggerOutputData = 0;
// loop over channels
for (byte channel = 0; channel < 8; channel++) {
// check current step bit
//bit = (number >> n) & 1U;
if ( (patternData[currentGroup][currentPreset][channel] >> tick) & 1U ) {
triggerOutputData |= 1UL << channel;
}
}
Serial.println(triggerOutputData, BIN);
writeOutputs();
// only for now, otherwise this should be in the main loop, but I dont
// want output on serial forever!!
show_home();
// check if we are at the end of a preset (after 8 steps) and if so
// go to the next preset
if (tick == 7) {
// check next(current) preset by checking loopsPresets
for (byte i = 0; i < 8; i++) {
// right shifting and & comparing with 00000001 (masking) to step through
// byte to see which ones active and therefore part of the loop.
if (loopPresets >> ((currentPreset + 1 + i) % 8) & 1U) {
Serial.print(" next preset is ");
Serial.print((currentPreset + 1 + i) % 8);
Serial.println(" | ");
nextPreset = (currentPreset + 1 + i) % 8;
break;
}
}
currentPreset = nextPreset;
}
}
void writeOutputs() {
// this needs more work!!
// split data, because we need two ports
// (need some pins in PORTD for serial communication and clock in)
byte lower = triggerOutputData & B00001111;
byte higher = triggerOutputData & B11110000;
bitClear(PORTB, 0);
bitClear(PORTB, 1);
bitClear(PORTB, 2);
bitClear(PORTB, 3);
PORTB = PORTB | lower;
bitClear(PORTD, 5);
bitClear(PORTD, 6);
bitClear(PORTD, 7);
bitClear(PORTD, 8);
PORTD = PORTD | higher;
}
void setup() {
Serial.begin(9600);
// set output pins:
// this should be pins D11 to D8, rightmost is D8, leftmost D11
DDRB = DDRB | B00001111; // set to output without changing anything that is not 1
DDRD = DDRD | B11110000;
// put in some example pattern data
patternData[0][0][0] = B10001000; // first group first preset first channel (kick)
patternData[0][0][1] = B00100010; // first group first preset second channel (snare)
patternData[0][0][2] = B11111111; // first group first preset third channel (hihat)
patternData[0][1][0] = B10101010; // first group second preset first channel (kick)
Timer1.initialize(900000);
Timer1.attachInterrupt(onClock);
}
void loop() {
// put your main code here, to run repeatedly:
}
//for (byte i = 0; i<8; i++) {
// right shifting and & comparing with 00000001 (masking) to step through
// byte to see which ones active and therefore part of the loop.
//Serial.print(loopPresets >> i & 1U, BIN);
//Serial.print(" ");
//if (loopPresets >> i & 1U) {
// Serial.print(i);
// Serial.print(",");
//}
// }
// Serial.print(" are in the loop. ");
void show_home() {
// show pattern and active step in lower two rows
// -> set all to black
Serial.print("|ui>:");
for(int i=0; i<8; i++) {
Serial.print((patternData[active_group][active_preset][active_channel] >> i) & 1U);
// -> turn on LED i, color = green
}
// -> turn on LED of active step in red
Serial.print(">|");
// show current pattern and group as colors on righ two lower upper buttons
}