// // // rhythm.board.c // // // Ian Wojtowicz // http://woj.com // (c) 2009 // /***************************************** TODO: Add a vibe to board. TODO: Rearrange data structures to pack each loop as a bit in an unsigned 8 bit int instead of each loop being a char. TODO: Add low-latency relay outputs. ******************************************/ #include #include #include #include #include #define tx_pin PA6 // transmit pin #define rx_pin PA7 // receive pin #define record_button_pin PA1 #define beat_button_pin PA0 #define rhythm_led_pin_1 PA2 // LED pin #define rhythm_led_pin_2 PA3 // LED pin #define rhythm_led_pin_3 PA4 // LED pin #define rhythm_led_pin_4 PA5 // LED pin #define record_led_pin PB2 // LED pin #define bit_delay_time 8.7 // bit delay, 1/115200 in usec at 20 MHZ #define led_blink_loops 1 // LED delay time, in ms #define bars_per_measure 4 #define beats_per_bar 4 #define loops_per_beat 3 #define beats_per_minute 144 #define ticks_per_second 9795 #define number_of_tracks 4 #define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay #define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay #define output_A(pin) (DDRA |= byte(pin)) // set PORTA pin for output #define output_B(pin) (DDRB |= byte(pin)) // set PORTB pin for output #define set_A(pin) (PORTA |= byte(pin)) // set pin in PORTA #define clear_A(pin) (PORTA &= ~(byte(pin))) // clear pin in PORTA #define set_B(pin) (PORTB |= byte(pin)) // set pin in PORTB #define clear_B(pin) (PORTB &= ~(byte(pin))) // clear pin in PORTB #define pin_test_A(bit) (PINA & (1 << bit)) // test for pin in PORTA #define is_button_pressed(bit) !pin_test_A(bit) // test for pin in PORTA #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set #define setup_16_bit_timer() (TCCR1B |= (1 << CS10)) // 16 bit timer, no prescale #define setup_16_bit_timer_prescale_64() (TCCR1B |= ((1 << CS10) | (1 << CS11))) // 16 bit timer, prescale by 64 #define setup_16_bit_timer_prescale_256() (TCCR1B |= (1 << CS12)) // 16 bit timer, prescale by 256 #define byte(bit) (1 << bit) // byte with bit set typedef char bool; #define FALSE 0 #define TRUE (-1) #define FULL_POWER 1 #define HALF_POWER 2 #define QUARTER_POWER 3 #define NO_POWER 4 int main(void) { unsigned int beats_per_measure = bars_per_measure * beats_per_bar; unsigned int loops_per_measure = bars_per_measure * beats_per_bar * loops_per_beat; // 48 float minutes_per_measure = bars_per_measure * beats_per_bar / beats_per_minute; // 0.1111 float millis_per_measure = minutes_per_measure * 60 * 1000; // 6666 float millis_per_loop = millis_per_measure / loops_per_measure; // 138.9 bool recording = FALSE; bool input_on = FALSE; unsigned long loop_index = 0; unsigned int track[number_of_tracks][loops_per_measure]; char current_track = 0; int pin_track_map[number_of_tracks]; char rec_led_intensity; int i, j; bool have_shifted_tracks = FALSE; /*************************************** e.g.: 40 * 8 = 320 loops/measure 16 / 140 = 0.2778 minutes/measure * 60 sec/minute * 1000 ms/sec = 16670 ms/measure = 52.09 ms/loop = 0.01667 Hz ***************************************/ pin_track_map[0] = rhythm_led_pin_1; pin_track_map[1] = rhythm_led_pin_2; pin_track_map[2] = rhythm_led_pin_3; pin_track_map[3] = rhythm_led_pin_4; for (i = 0; i < number_of_tracks; i++) { // for (j = 0; j < beats_per_measure; j++) for (j = 0; j < loops_per_measure; j++) { // track[i][j] = 0; track[i][j] = FALSE; } } // // set clock divider to /1 // CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); setup_16_bit_timer_prescale_256(); // // initialize output pins // output_A(tx_pin); output_B(record_led_pin); output_A(rhythm_led_pin_1); output_A(rhythm_led_pin_2); output_A(rhythm_led_pin_3); output_A(rhythm_led_pin_4); clear_A(tx_pin); // init input pins set_A(beat_button_pin); set_A(record_button_pin); // // main loop // while (1) { TCNT1 = 0; // Determine if we are recording if (is_button_pressed(record_button_pin)) { recording = TRUE; } else if (recording) { recording = FALSE; have_shifted_tracks = FALSE; } // If we're at the beginning of a beat, flash the record light. if (recording && ((loop_index % loops_per_beat) <= led_blink_loops)) { rec_led_intensity = QUARTER_POWER; if (loop_index == 0) rec_led_intensity = FULL_POWER; else if (loop_index % (loops_per_beat * beats_per_bar) == 0) rec_led_intensity = FULL_POWER; } else { if (loop_index == 0) rec_led_intensity = FULL_POWER; else if (loop_index % (loops_per_beat * beats_per_bar) == 0) rec_led_intensity = FULL_POWER; else rec_led_intensity = NO_POWER; } if (recording) { if (!have_shifted_tracks) { current_track++; if (current_track > number_of_tracks) current_track = 1; have_shifted_tracks = TRUE; } if (is_button_pressed(beat_button_pin)) { set_A(pin_track_map[current_track - 1]); track[current_track - 1][loop_index] = TRUE; } else { clear_A(pin_track_map[current_track - 1]); track[current_track - 1][loop_index] = FALSE; } } for (i = 0; i < number_of_tracks; i++) { if (recording && track[i] == track[current_track - 1]) { continue; } if (track[i][loop_index]) { set_A(pin_track_map[i]); } else { clear_A(pin_track_map[i]); } } // When beats per minute = 144 // seconds/milli ticks/second millis/loop // double ticks_per_loop = 0.001 * 9795 * 138.9; // = 1361.5 // this also seems to need to be multiplied by 10 for meet 144 beats per minute... not sure why while (TCNT1 < 13615) { if (rec_led_intensity == FULL_POWER) { set_B(record_led_pin); } else if (rec_led_intensity == HALF_POWER && ((TCNT1 % 2) == 0)) { set_B(record_led_pin); } else if (rec_led_intensity == QUARTER_POWER && ((TCNT1 % 20) == 0)) { set_B(record_led_pin); } else { clear_B(record_led_pin); } ; // Do nothing. } if (loop_index >= loops_per_measure - 1) loop_index = 0; else loop_index++; } }