Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------
- Arduino Based Theremin/MIDI Tracker
- Version 1.0
- January 2011
- -----------------------------------
- This folder contains the following:
- /Arduino Sketches
- Contains all the test code and libraries needed to program the ATMEL328P microprocessor
- ---
- /Eagle CAD Files
- Contains the CAD files for both the schematic and board.
- Eagle can be downloaded for free from http://www.cadsoft.de/freeware.htm
- ---
- /Images
- The board and schematic as high resolution PNG image files (600 DPI)
- ---
- EtchMask600DPI.tif
- A high resolution monochrome etch mask - used to make your own PCB if required
- ---
- ThereminTracker_Assembly.pdf
- Complete guide to etching a PCB, building and programming the board and using the
- Theremin Tracker.
- ---
- With thanks to
- www.cadsoft.de
- www.adafruit.com
- little-scale.blogspot.com
- www.arduino.cc
- //==========================
- // Readme
- //==========================
- The AFSoftSerial library needs to be installed in the
- Arduino /libraries folder before trying to compile the
- THEREMIN_MIDI_2011 sketch.
- //==========================
- // AFSoftSerial.cpp
- //==========================
- /*
- SoftwareSerial.cpp - Software serial library
- Copyright (c) 2006 David A. Mellis. All right reserved. - hacked by ladyada
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /******************************************************************************
- * Includes
- ******************************************************************************/
- #include <avr/interrupt.h>
- #include "WConstants.h"
- #include "AFSoftSerial.h"
- /******************************************************************************
- * Definitions
- ******************************************************************************/
- #define AFSS_MAX_RX_BUFF 64
- /******************************************************************************
- * Statics
- ******************************************************************************/
- static uint8_t _receivePin;
- static uint8_t _transmitPin;
- static int _bitDelay;
- static char _receive_buffer[AFSS_MAX_RX_BUFF];
- static uint8_t _receive_buffer_index;
- #if (F_CPU == 16000000)
- void whackDelay(uint16_t delay) {
- uint8_t tmp=0;
- asm volatile("sbiw %0, 0x01 \n\t"
- "ldi %1, 0xFF \n\t"
- "cpi %A0, 0xFF \n\t"
- "cpc %B0, %1 \n\t"
- "brne .-10 \n\t"
- : "+r" (delay), "+a" (tmp)
- : "0" (delay)
- );
- }
- #endif
- /******************************************************************************
- * Interrupts
- ******************************************************************************/
- SIGNAL(SIG_PIN_CHANGE0) {
- if ((_receivePin >=8) && (_receivePin <= 13)) {
- recv();
- }
- }
- SIGNAL(SIG_PIN_CHANGE2)
- {
- if (_receivePin <8) {
- recv();
- }
- }
- void recv(void) {
- /*char i, d = 0;
- if (digitalRead(_receivePin))
- return; // not ready!
- whackDelay(_bitDelay - 8);
- for (i=0; i<8; i++) {
- //PORTB |= _BV(5);
- whackDelay(_bitDelay*2 - 6); // digitalread takes some time
- //PORTB &= ~_BV(5);
- if (digitalRead(_receivePin))
- d |= (1 << i);
- }
- whackDelay(_bitDelay*2);
- if (_receive_buffer_index >= AFSS_MAX_RX_BUFF)
- return;
- _receive_buffer[_receive_buffer_index] = d; // save data
- _receive_buffer_index++; // got a byte
- */
- }
- /******************************************************************************
- * Constructors
- ******************************************************************************/
- AFSoftSerial::AFSoftSerial(uint8_t transmitPin)
- {
- //_receivePin = receivePin;
- _transmitPin = transmitPin;
- _baudRate = 0;
- }
- void AFSoftSerial::setTX(uint8_t tx) {
- _transmitPin = tx;
- }
- void AFSoftSerial::setRX(uint8_t rx) {
- //_receivePin = rx;
- }
- /******************************************************************************
- * User API
- ******************************************************************************/
- void AFSoftSerial::begin(long speed)
- {
- pinMode(_transmitPin, OUTPUT);
- digitalWrite(_transmitPin, HIGH);
- //pinMode(_receivePin, INPUT);
- //digitalWrite(_receivePin, HIGH); // pullup!
- _baudRate = speed;
- switch (_baudRate) {
- case 115200: // For xmit -only-!
- _bitDelay = 4; break;
- case 57600:
- _bitDelay = 14; break;
- case 38400:
- _bitDelay = 24; break;
- case 31250:
- _bitDelay = 31; break;
- case 19200:
- _bitDelay = 54; break;
- case 9600:
- _bitDelay = 113; break;
- case 4800:
- _bitDelay = 232; break;
- case 2400:
- _bitDelay = 470; break;
- default:
- _bitDelay = 0;
- }
- /* if (_receivePin < 8) {
- // a PIND pin, PCINT16-23
- PCMSK2 |= _BV(_receivePin);
- PCICR |= _BV(2);
- } else if (_receivePin <= 13) {
- // a PINB pin, PCINT0-5
- PCICR |= _BV(0);
- PCMSK0 |= _BV(_receivePin-8);
- } */
- whackDelay(_bitDelay*2); // if we were low this establishes the end
- }
- int AFSoftSerial::read(void)
- {
- /*uint8_t d,i;
- if (! _receive_buffer_index)
- return -1;
- d = _receive_buffer[0]; // grab first byte
- // if we were awesome we would do some nifty queue action
- // sadly, i dont care
- for (i=0; i<_receive_buffer_index; i++) {
- _receive_buffer[i] = _receive_buffer[i+1];
- }
- _receive_buffer_index--;
- return d;*/
- return 0;
- }
- uint8_t AFSoftSerial::available(void)
- {
- return 0; //_receive_buffer_index;
- }
- void AFSoftSerial::print(uint8_t b)
- {
- if (_baudRate == 0)
- return;
- byte mask;
- cli(); // turn off interrupts for a clean txmit
- digitalWrite(_transmitPin, LOW); // startbit
- whackDelay(_bitDelay*2);
- for (mask = 0x01; mask; mask <<= 1) {
- if (b & mask){ // choose bit
- digitalWrite(_transmitPin,HIGH); // send 1
- }
- else{
- digitalWrite(_transmitPin,LOW); // send 1
- }
- whackDelay(_bitDelay*2);
- }
- digitalWrite(_transmitPin, HIGH);
- sei(); // turn interrupts back on. hooray!
- whackDelay(_bitDelay*2);
- }
- void AFSoftSerial::print(const char *s)
- {
- while (*s)
- print(*s++);
- }
- void AFSoftSerial::print(char c)
- {
- print((uint8_t) c);
- }
- void AFSoftSerial::print(int n)
- {
- print((long) n);
- }
- void AFSoftSerial::print(unsigned int n)
- {
- print((unsigned long) n);
- }
- void AFSoftSerial::print(long n)
- {
- if (n < 0) {
- print('-');
- n = -n;
- }
- printNumber(n, 10);
- }
- void AFSoftSerial::print(unsigned long n)
- {
- printNumber(n, 10);
- }
- void AFSoftSerial::print(long n, int base)
- {
- if (base == 0)
- print((char) n);
- else if (base == 10)
- print(n);
- else
- printNumber(n, base);
- }
- void AFSoftSerial::println(void)
- {
- print('\r');
- print('\n');
- }
- void AFSoftSerial::println(char c)
- {
- print(c);
- println();
- }
- void AFSoftSerial::println(const char c[])
- {
- print(c);
- println();
- }
- void AFSoftSerial::println(uint8_t b)
- {
- print(b);
- println();
- }
- void AFSoftSerial::println(int n)
- {
- print(n);
- println();
- }
- void AFSoftSerial::println(long n)
- {
- print(n);
- println();
- }
- void AFSoftSerial::println(unsigned long n)
- {
- print(n);
- println();
- }
- void AFSoftSerial::println(long n, int base)
- {
- print(n, base);
- println();
- }
- // Private Methods /////////////////////////////////////////////////////////////
- void AFSoftSerial::printNumber(unsigned long n, uint8_t base)
- {
- unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
- unsigned long i = 0;
- if (n == 0) {
- print('0');
- return;
- }
- while (n > 0) {
- buf[i++] = n % base;
- n /= base;
- }
- for (; i > 0; i--)
- print((char) (buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10));
- }
- //==========================
- // AFSoftSerial.h
- //==========================
- /*
- SoftwareSerial.h - Software serial library
- Copyright (c) 2006 David A. Mellis. All right reserved.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #ifndef AFSoftSerial_h
- #define AFSoftSerial_h
- #include <inttypes.h>
- uint16_t whackDelay2(uint16_t delay);
- static void recv(void);
- class AFSoftSerial
- {
- private:
- long _baudRate;
- void printNumber(unsigned long, uint8_t);
- public:
- AFSoftSerial(uint8_t);
- void setTX(uint8_t tx);
- void setRX(uint8_t rx);
- void begin(long);
- int read();
- uint8_t available(void);
- void print(char);
- void print(const char[]);
- void print(uint8_t);
- void print(int);
- void print(unsigned int);
- void print(long);
- void print(unsigned long);
- void print(long, int);
- void println(void);
- void println(char);
- void println(const char[]);
- void println(uint8_t);
- void println(int);
- void println(long);
- void println(unsigned long);
- void println(long, int);
- };
- #endif
- //================
- // keywords.txt
- //================
- #######################################
- # Syntax Coloring Map For Ultrasound
- #######################################
- #######################################
- # Datatypes (KEYWORD1)
- #######################################
- AFSoftSerial KEYWORD1
- #######################################
- # Methods and Functions (KEYWORD2)
- #######################################
- #######################################
- # Constants (LITERAL1)
- #######################################
- //===============
- // Blink.pde
- //===============
- /*
- Blink
- Turns on an LED on for one second, then off for one second, repeatedly.
- This example code is in the public domain.
- */
- void setup() {
- // initialize the digital pin as an output.
- // Pin 13 has an LED connected on most Arduino boards:
- pinMode(13, OUTPUT);
- }
- void loop() {
- digitalWrite(13, HIGH); // set the LED on
- delay(1000); // wait for a second
- digitalWrite(13, LOW); // set the LED off
- delay(1000); // wait for a second
- }
- //====================
- // Test_595.pde
- //====================
- //**************************************************************//
- // Name : shiftOutCode, Hello World
- // Author : Carlyn Maw,Tom Igoe, David A. Mellis
- // Date : 25 Oct, 2006
- // Modified: 23 Mar 2010
- // Version : 2.0
- // Notes : Code for using a 74HC595 Shift Register //
- // : to count from 0 to 255
- //
- // http://arduino.cc/en/Tutorial/ShftOut11
- //
- //****************************************************************
- //Pin connected to ST_CP of 74HC595
- int latchPin = 8;
- //Pin connected to SH_CP of 74HC595
- int clockPin = 12;
- ////Pin connected to DS of 74HC595
- int dataPin = 11;
- void setup() {
- //set pins to output so you can control the shift register
- pinMode(latchPin, OUTPUT);
- pinMode(clockPin, OUTPUT);
- pinMode(dataPin, OUTPUT);
- }
- void loop() {
- // count from 0 to 255 and display the number
- // on the LEDs
- for (int numberToDisplay = 0; numberToDisplay < 256; numberToDisplay++) {
- // take the latchPin low so
- // the LEDs don't change while you're sending in bits:
- digitalWrite(latchPin, LOW);
- // shift out the bits:
- shiftOut(dataPin, clockPin, MSBFIRST, numberToDisplay);
- //take the latch pin high so the LEDs will light up:
- digitalWrite(latchPin, HIGH);
- // pause before next value:
- delay(500);
- }
- }
- //==========================
- // THEREMIN_MIDI_2011.pde
- //==========================
- /////////////////////////////////////////////////////////////
- // General purpose theremin MIDI interface
- // 2011 S. Hobley
- // www.stephenhobley.com
- /////////////////////////////////////////////////////////////
- // Included to drive the LCD
- #include <AFSoftSerial.h>
- // Include for PROGMEM
- #include <avr/pgmspace.h>
- #define VERSION "1.0"
- #define BUTTON1 15
- #define BUTTON2 16
- #define MODE_PITCH 0 // 00
- #define MODE_CONTROL 2 // 01
- #define MODE_ARP_C 1 // 10
- #define MODE_ARP_F 3 // 11
- #define NO_OF_SAMPLES 5
- #define BREATHCONTROL 0x02
- #define CONTROLLER 0xB0
- #define PITCHBEND 0xE0
- #define NOTEON 0x90
- #define CHANNEL_MODE
- #define VOLUME 0x07
- #define ALLNOTESOFF 0x7B
- #define MIDI_BAUD 31250
- #define VELOCITY 100
- #define DEBUG 0
- #define NO_NOTE 128
- #define GEN_CONTROL_1 55
- #define ARP_ROOT 48 // C
- // Volatiles for interrupt handler
- volatile unsigned long samples[5];
- volatile int sample_counter = 0;
- volatile unsigned long _micros = 0;
- //unsigned long temp_acc = 0;
- byte iLastNote = NO_NOTE;
- byte iLastNoteArp = NO_NOTE;
- byte old_detune_cent = NO_NOTE;
- int volume = NO_NOTE;
- char cp_buffer[5];
- AFSoftSerial SSerial(9); // TX on 10
- uint16_t lower_bound_period[] = {
- /*22282,*/ 21052, 19869, 18748, 17696, 16706, 15768, 14880, 14046, 13259,
- 12515, 11814, 11152, 10525, 9931, 9374, 8849, 8351, 7882, 7442,
- 7024, 6631, 6260, 5908, 5577, 5264, 4968, 4689, 4426, 4177,
- 3943, 3722, 3513, 3316, 3130, 2955, 2789, 2632, 2485, 2346,
- 2214, 2090, 1972, 1862, 1757, 1658, 1565, 1478, 1395, 1317,
- 1244, 1174, 1107, 1045, 987, 932, 880, 830, 784, 740,
- 699, 659, 622, 588, 555, 524, 495, 467, 441, 421
- };
- int detune_values[] = {
- /*123,*/ 118, 112, 105, 99, 94, 89, 83, 79, 75,
- 70, 66, 63, 60, 56, 53, 50, 47, 44, 42,
- 39, 37, 35, 33, 31, 30, 28, 26, 25, 24,
- 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
- 13, 12, 11, 11, 10, 9, 9, 8, 8, 7,
- 7, 7, 6, 6, 6, 5, 5, 5, 4, 4,
- 4, 4, 4, 3, 3, 3, 3, 3, 3, 3
- };
- prog_char string_1[] PROGMEM = "F#-3";
- prog_char string_2[] PROGMEM = "G -3";
- prog_char string_3[] PROGMEM = "Ab-3";
- prog_char string_4[] PROGMEM = "A -3";
- prog_char string_5[] PROGMEM = "Bb-3";
- prog_char string_6[] PROGMEM = "B -3";
- prog_char string_7[] PROGMEM = "C -2";
- prog_char string_8[] PROGMEM = "C#-2";
- prog_char string_9[] PROGMEM = "D -2";
- prog_char string_10[] PROGMEM = "Eb-2";
- prog_char string_11[] PROGMEM = "E -2";
- prog_char string_12[] PROGMEM = "F -2";
- prog_char string_13[] PROGMEM = "F#-2";
- prog_char string_14[] PROGMEM = "G -2";
- prog_char string_15[] PROGMEM = "Ab-2";
- prog_char string_16[] PROGMEM = "A -2";
- prog_char string_17[] PROGMEM = "Bb-2";
- prog_char string_18[] PROGMEM = "B -2";
- prog_char string_19[] PROGMEM = "C -1";
- prog_char string_20[] PROGMEM = "C#-1";
- prog_char string_21[] PROGMEM = "D -1";
- prog_char string_22[] PROGMEM = "Eb-1";
- prog_char string_23[] PROGMEM = "E -1";
- prog_char string_24[] PROGMEM = "F -1";
- prog_char string_25[] PROGMEM = "F#-1";
- prog_char string_26[] PROGMEM = "G -1";
- prog_char string_27[] PROGMEM = "Ab-1";
- prog_char string_28[] PROGMEM = "A -1";
- prog_char string_29[] PROGMEM = "Bb-1";
- prog_char string_30[] PROGMEM = "B -1";
- prog_char string_31[] PROGMEM = "C 0";
- prog_char string_32[] PROGMEM = "C# 0";
- prog_char string_33[] PROGMEM = "D 0";
- prog_char string_34[] PROGMEM = "Eb 0";
- prog_char string_35[] PROGMEM = "E 0";
- prog_char string_36[] PROGMEM = "F 0";
- prog_char string_37[] PROGMEM = "F# 0";
- prog_char string_38[] PROGMEM = "G 0";
- prog_char string_39[] PROGMEM = "Ab 0";
- prog_char string_40[] PROGMEM = "A 0";
- prog_char string_41[] PROGMEM = "Bb 0";
- prog_char string_42[] PROGMEM = "B 0";
- prog_char string_43[] PROGMEM = "C 1";
- prog_char string_44[] PROGMEM = "C# 1";
- prog_char string_45[] PROGMEM = "D 1";
- prog_char string_46[] PROGMEM = "Eb 1";
- prog_char string_47[] PROGMEM = "E 1";
- prog_char string_48[] PROGMEM = "F 1";
- prog_char string_49[] PROGMEM = "F# 1";
- prog_char string_50[] PROGMEM = "G 1";
- prog_char string_51[] PROGMEM = "Ab 1";
- prog_char string_52[] PROGMEM = "A 1";
- prog_char string_53[] PROGMEM = "Bb 1";
- prog_char string_54[] PROGMEM = "B 1";
- prog_char string_55[] PROGMEM = "C 2";
- prog_char string_56[] PROGMEM = "C# 2";
- prog_char string_57[] PROGMEM = "D 2";
- prog_char string_58[] PROGMEM = "Eb 2";
- prog_char string_59[] PROGMEM = "E 2";
- prog_char string_60[] PROGMEM = "F 2";
- prog_char string_61[] PROGMEM = "F# 2";
- prog_char string_62[] PROGMEM = "G 2";
- prog_char string_63[] PROGMEM = "Ab 2";
- prog_char string_64[] PROGMEM = "A 2";
- prog_char string_65[] PROGMEM = "Bb 2";
- prog_char string_66[] PROGMEM = "B 2";
- prog_char string_67[] PROGMEM = "C 3";
- prog_char string_68[] PROGMEM = "Eb 3";
- prog_char string_69[] PROGMEM = "D 3";
- PROGMEM const char *note_name_table[] =
- {
- string_1, string_2, string_3, string_4, string_5, string_6,
- string_7, string_8, string_9, string_10, string_11, string_12,
- string_13, string_14, string_15, string_16, string_17, string_18,
- string_19, string_20, string_21, string_22, string_23, string_24,
- string_25, string_26, string_27, string_28, string_29, string_30,
- string_31, string_32, string_33, string_34, string_35, string_36,
- string_37, string_38, string_39, string_40, string_41, string_42,
- string_43, string_44, string_45, string_46, string_47, string_48,
- string_49, string_50, string_51, string_52, string_53, string_54,
- string_55, string_56, string_57, string_58, string_59, string_60,
- string_61, string_62, string_63, string_64, string_65, string_66,
- string_67, string_68, string_69
- };
- // LEDs /////////////////////////////////////
- //Pin connected to ST_CP of 74HC595
- #define latchPin 8
- //Pin connected to SH_CP of 74HC595
- #define clockPin 12
- ////Pin connected to DS of 74HC595
- #define dataPin 11
- // Local var for period analysis
- unsigned long accumulator = 0;
- unsigned long detune = 0;
- int detune_cent = 0;
- byte button_state = 255;
- byte arp2_added = 0;
- // MIDI ////////////////////////////////////////
- byte data = 0;
- byte channel = 0;
- byte note = 0;
- byte value = 0;
- int flag_previous = 0;
- int volInternalOld = 0;
- byte output_channel = 0; // To be made persistent
- byte input_channel = 0; // To be made persistent
- byte pitchbendOld = 0;
- /* flag_previous meanings:
- -1 = note off status
- -2 = note off pitch
- 0 = no action / waiting
- 1 = note on status
- 2 = pitch
- 3 = cc status
- 4 = cc number
- */
- // MIDI Arpeggiator
- byte notes[] = {NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE, NO_NOTE} ; // Store up to 12 notes
- byte intervals[] = {0,0,0,0}; // Store up to 4 intervals
- byte root = 128; // root note
- char mod = '0'; // A/I/7/8 modifier Major, Minor, Seventh, Minor Seventh
- byte modroot = 0;
- bool checkrunstatus_off = false;
- bool checkrunstatus_on = false;
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void setup()
- {
- Serial.begin(MIDI_BAUD);
- SSerial.begin(9600);
- pinMode(BUTTON1, INPUT);
- pinMode(BUTTON2, INPUT);
- digitalWrite(BUTTON1, HIGH);
- digitalWrite(BUTTON2, HIGH);
- SSerial.print("?f");
- SSerial.print("?a");
- SSerial.print("MIDI Theremin");
- SSerial.print("?x00?y1");
- SSerial.print("Tracker ");
- SSerial.print(VERSION);
- delay(1000);
- // reset the MIDI In state machine
- flag_previous = 0;
- pinMode(latchPin, OUTPUT);
- attachInterrupt(0, sample_freq, RISING);
- for(int i = 0; i < 10; i++)
- {
- SetLEDS(i,0);
- delay(100);
- }
- for(int i = 9; i >= 0; i--)
- {
- SetLEDS(i,0);
- delay(100);
- }
- SetLEDS(0,0);
- SSerial.print("?f");
- SSerial.print("?a");
- SSerial.print("?x07?y1");
- SSerial.print("[01][01][055]");
- SSerial.print("?x00?y3");
- SSerial.print("--");
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void loop()
- {
- ProcessMIDIIn();
- ProcessButtons();
- // We have captured enough samples, time to process...
- if (sample_counter == NO_OF_SAMPLES)
- {
- ProcessSamples();
- // Start sampling again
- sample_counter = 0;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void ProcessButtons()
- {
- byte temp = button_state;
- button_state = 0;
- if (digitalRead(BUTTON1) == LOW)
- {
- button_state |= 1;
- }
- if (digitalRead(BUTTON2) == LOW)
- {
- button_state |= 2;
- }
- if (button_state == temp)
- return;
- // All Note Off
- ProcessMIDIOut(CONTROLLER, ALLNOTESOFF, 0);
- // Clear Table
- for (int i=0; i < 12; i++)
- notes[i] = NO_NOTE;
- for (int i=0; i < 4; i++)
- intervals[i] = 0;
- SSerial.print("?x00?y3");
- SSerial.print(" ");
- SSerial.print("?x00?y1");
- switch(button_state)
- {
- case MODE_PITCH:
- SSerial.print("[PITCH]");
- break;
- case MODE_CONTROL:
- SSerial.print("[CNTRL]");
- break;
- case MODE_ARP_C:
- SSerial.print("[ARP 1]");
- break;
- case MODE_ARP_F:
- SSerial.print("[ARP 2]");
- break;
- }
- SSerial.print(button_state);
- // Short debounce
- delay(100);
- //bit = number & (1 << x); bit = t/f
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void ProcessMIDIOut(byte cmdtype, byte val1, byte val2)
- {
- if (cmdtype == PITCHBEND)
- {
- Serial.print(0xE0 | (channel & 0xf), BYTE); // control change command
- Serial.print(val1 & 0x7f, BYTE); // pb MSB 0-127
- Serial.print(val2, BYTE); // pb LSB 0-15 - TODO
- }
- else // All standard note and cc messages
- {
- Serial.print(cmdtype | (output_channel & 0xf), BYTE); // control change command
- Serial.print(val1, BYTE); // command
- Serial.print(val2 & 0x7f, BYTE); // val1 0-127
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // To be called once per loop
- void ProcessMIDIIn()
- {
- if(Serial.available() > 0)
- {
- data = Serial.read();
- // Ignore the active sense message
- if (data == 0xfe)
- {
- return;
- }
- // deal with note off data
- if((data >= 0x80) && (data < 0x90) && (flag_previous == 0)) //NOTE OFF Step 1
- {
- channel = data & B00001111;
- if (channel == input_channel)
- {
- flag_previous = -2; // Move on to get note
- }
- }
- else if((data < 0x80) && ((flag_previous == -2)||(checkrunstatus_off))) // NOTE OFF Step 2
- {
- note = data;
- checkrunstatus_off = false;
- flag_previous = -1;
- }
- else if((data < 0x80) && (flag_previous == -1)) // NOTE OFF Step 3
- {
- value = data;
- checkrunstatus_off = true;
- checkrunstatus_on = false;
- doNoteOff(note);
- flag_previous = 0;
- }
- else if((data >= 0x90) && (data < 0xA0) && (flag_previous == 0)) //NOTE ON Step 1
- {
- channel = data & B00001111;
- if (channel == input_channel)
- {
- flag_previous = 2; // Move on to get note
- }
- }
- else if((data < 0x80) && ((flag_previous == 2)||(checkrunstatus_on))) // NOTE ON Step 2
- {
- note = data;
- checkrunstatus_on = false;
- flag_previous = 1;
- }
- else if((data < 0x80) && (flag_previous == 1)) // NOTE ON Step 3
- {
- value = data;
- if (value == 0)
- {
- //SSerial.print("-");
- doNoteOff(note);
- }
- else
- {
- //SSerial.print("+");
- doNoteOn(note, value);
- }
- checkrunstatus_off = false;
- checkrunstatus_on = true;
- flag_previous = 0;
- }
- else
- flag_previous = 0;
- // done with note data
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void doNoteOn(byte note, byte value)
- {
- // mod; // 0/A/I/7/8 modifier Nothing, Major, Minor, Seventh, Minor Seventh
- switch (button_state)
- {
- case MODE_PITCH :
- case MODE_CONTROL:
- return;
- break;
- case MODE_ARP_C :
- // Removing a note
- if (value == 0)
- {
- // Removing
- for (int i=0; i < 4; i++)
- {
- if (notes[i] == note)
- {
- if (note == root)
- {
- root = NO_NOTE;
- }
- notes[i] = NO_NOTE;
- }
- }
- ProcessArpSeq();
- }
- else
- {
- // Adding a note
- bool added = false;
- for (int i=0; i < 4; i++)
- {
- if (notes[i] == NO_NOTE)
- {
- notes[i] = note;
- added = true;
- break;
- }
- }
- if (added) ProcessArpSeq();
- }
- break;
- case MODE_ARP_F:
- // Removing a note
- note = note % 12;
- if (value == 0)
- {
- // Removing
- for (int i=0; i < 12; i++)
- {
- if (notes[i] == note)
- {
- notes[i] = NO_NOTE;
- SSerial.print("?x");
- if (i < 10) SSerial.print("0");
- SSerial.print(i);
- SSerial.print("?y3");
- SSerial.print(" ");
- if (arp2_added > 0)
- arp2_added--;
- SSerial.print("?x15?y3");
- SSerial.print(arp2_added,DEC);
- // Clear anything else that might be stuck
- if (arp2_added == 0)
- ProcessMIDIOut(CONTROLLER, ALLNOTESOFF, 0);
- break;
- }
- }
- }
- else
- {
- // Adding a note
- bool added = false;
- for (int i=0; i < 12; i++)
- {
- if (notes[i] == NO_NOTE)
- {
- notes[i] = note;
- added = true;
- SSerial.print("?x");
- if (i < 10) SSerial.print("0");
- SSerial.print(i);
- SSerial.print("?y3");
- SSerial.print("+");
- arp2_added++;
- SSerial.print("?x15?y3");
- SSerial.print(arp2_added,DEC);
- break;
- }
- }
- }
- break;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- void ProcessArpSeq()
- {
- // Scan the table and find the lowest note
- byte note_count = 0;
- for (int i=0; i < 4; i++)
- {
- if (notes[i] != NO_NOTE)
- note_count++;
- if (root > notes[i])
- {
- root = notes[i];
- modroot = root % 12;
- }
- }
- SSerial.print("?x00?y3"); // Goto bottom left
- switch(modroot)
- {
- case 0 :
- SSerial.print("C ");
- break;
- case 1 :
- SSerial.print("C# ");
- break;
- case 2 :
- SSerial.print("D ");
- break;
- case 3 :
- SSerial.print("Eb ");
- break;
- case 4 :
- SSerial.print("E ");
- break;
- case 5 :
- SSerial.print("F ");
- break;
- case 6 :
- SSerial.print("F# ");
- break;
- case 7 :
- SSerial.print("G ");
- break;
- case 8 :
- SSerial.print("Ab ");
- break;
- case 9 :
- SSerial.print("A ");
- break;
- case 10 :
- SSerial.print("Bb ");
- break;
- case 11 :
- SSerial.print("B ");
- break;
- }
- switch(note_count)
- {
- case 0:
- mod = '0'; // Nothing
- SSerial.print("?x00?y3");
- SSerial.print("-- ");
- intervals[0] = 0;
- intervals[1] = 0;
- intervals[2] = 0;
- intervals[3] = 0;
- // Silence whatever might be playing
- if (iLastNoteArp != NO_NOTE)
- {
- ProcessMIDIOut(NOTEON, iLastNoteArp, 0);
- iLastNoteArp = NO_NOTE;
- }
- break;
- case 1:
- mod = 'A'; // Major
- SSerial.print("Mj");
- intervals[0] = 4;
- intervals[1] = 3;
- intervals[2] = 5;
- intervals[3] = 0; // Not used
- if (iLastNote != NO_NOTE)
- {
- ProcessMIDIOut(NOTEON, iLastNote, 0);
- iLastNote = NO_NOTE;
- }
- break;
- case 2:
- mod = 'I'; // Minor
- SSerial.print("Mn");
- intervals[0] = 3;
- intervals[1] = 4;
- intervals[2] = 5;
- intervals[3] = 0; // Not used
- if (iLastNote != NO_NOTE)
- {
- ProcessMIDIOut(NOTEON, iLastNote, 0);
- iLastNote = NO_NOTE;
- }
- break;
- case 3:
- mod = '7'; // Seventh
- SSerial.print("b7");
- intervals[0] = 4;
- intervals[1] = 3;
- intervals[2] = 3;
- intervals[3] = 2;
- if (iLastNote != NO_NOTE)
- {
- ProcessMIDIOut(NOTEON, iLastNote, 0);
- iLastNote = NO_NOTE;
- }
- break;
- case 4:
- mod = '8'; // Minor Seventh
- SSerial.print("M7");
- intervals[0] = 3;
- intervals[1] = 4;
- intervals[2] = 3;
- intervals[3] = 2;
- if (iLastNote != NO_NOTE)
- {
- ProcessMIDIOut(NOTEON, iLastNote, 0);
- iLastNote = NO_NOTE;
- }
- break;
- }
- SSerial.println(" ");
- // Clear anything else that might be stuck
- ProcessMIDIOut(CONTROLLER, ALLNOTESOFF, 0);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void doNoteOff(byte note)
- {
- doNoteOn(note, 0);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void PlayArpSequence(int note)
- {
- byte acc = modroot;
- byte check = 0;
- int j = 0;
- for(int i=0; i < note; i+=2 ) // less steps
- {
- check = acc+intervals[j];
- if (check > 100)
- break;
- acc = check;
- j++;
- if (j > 3)
- j = 0;
- }
- if (iLastNoteArp != acc)
- {
- ProcessMIDIOut(NOTEON, iLastNoteArp, 0);
- ProcessMIDIOut(NOTEON, acc, VELOCITY);
- iLastNoteArp = acc;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void PlayArp2Sequence(int note)
- {
- if (arp2_added == 0)
- return;
- byte acc = 36;
- byte check = 0;
- byte oct = 0;
- byte j = -1;
- int test = note+1;
- while(test > 0)
- {
- j++;
- if (j > 11)
- {
- j = 0;
- oct++;
- }
- if (notes[j] != 128)
- test--;
- }
- acc = 12 + (oct * 12) + notes[j];
- /*SSerial.print("?x00?y2");
- SSerial.print(acc,DEC);
- SSerial.print(":");
- SSerial.print(oct,DEC);
- SSerial.print(":");
- SSerial.print(j,DEC);
- SSerial.print(" ");
- */
- // Overflow check
- if (acc > 120)
- {
- ProcessMIDIOut(NOTEON, iLastNoteArp, 0);
- return;
- }
- if (iLastNoteArp != acc)
- {
- ProcessMIDIOut(NOTEON, iLastNoteArp, 0);
- ProcessMIDIOut(NOTEON, acc, VELOCITY);
- iLastNoteArp = acc;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- unsigned long ProcessSamples()
- {
- accumulator = (samples[1] - samples[0]);
- accumulator += (samples[2] - samples[1]);
- accumulator += (samples[3] - samples[2]);
- accumulator += (samples[4] - samples[3]);
- accumulator = accumulator / 4;
- // Now scan up the interval table
- bool processed = false;
- byte realnote=0;
- for (int i = 0; i <69; i++)
- {
- if (accumulator > lower_bound_period[i])
- {
- processed = true;
- // Have we changed?
- if (i != iLastNote)
- {
- strcpy_P(cp_buffer, (char*)pgm_read_word(&(note_name_table[i])));
- switch (button_state)
- {
- case MODE_PITCH:
- // UpdateMIDI
- if (iLastNote != NO_NOTE)
- ProcessMIDIOut(NOTEON, iLastNote+30, 0);
- ProcessMIDIOut(NOTEON, i+30, VELOCITY); // For now
- iLastNote = i;
- break;
- case MODE_CONTROL:
- if (i > 63) i = 63;
- ProcessMIDIOut(CONTROLLER, GEN_CONTROL_1, i*2); // For now
- break;
- case MODE_ARP_C:
- if (root != NO_NOTE)
- {
- PlayArpSequence(i);
- }
- break;
- case MODE_ARP_F:
- PlayArp2Sequence(i);
- break;
- }
- }
- // Now we have to calculate the detune offset
- detune = accumulator - lower_bound_period[i];
- detune_cent = detune / detune_values[i];
- // Send pitchbend data
- ProcessMIDIOut(PITCHBEND, 0, (9-detune_cent) * 12);
- // Process Volume ////////////////////////////////
- volume = analogRead(0);
- // Sample volume
- byte volinternal = volume >> 3;
- volinternal*=2;
- if (volinternal > 127)
- volinternal = 127;
- if (volInternalOld != volinternal)
- {
- volInternalOld = volinternal;
- ProcessMIDIOut(CONTROLLER, VOLUME, volinternal);
- }
- //////////////////////////////////////////////////
- UpdateLCD(cp_buffer, detune_cent, i, volume);
- delay(10); // Delay a little after each update - this could be moved to a timer interrupt
- break; // From i loop
- }
- }
- if (!processed)
- {
- ProcessMIDIOut(NOTEON, iLastNote, 0);
- iLastNote = NO_NOTE;
- UpdateLCD("XXXX", 5, 0, volume);
- }
- //temp_acc = accumulator;
- accumulator = 0;
- return accumulator; //temp_acc;
- }
- ////////////////////////////////////////////////////////////////////////////
- void shiftOut(int myDataPin, int myClockPin, byte myDataOut)
- {
- // This shifts 8 bits out MSB first,
- //on the rising edge of the clock,
- //clock idles low
- //internal function setup
- int i=0;
- int pinState;
- pinMode(myClockPin, OUTPUT);
- pinMode(myDataPin, OUTPUT);
- //clear everything out just in case to
- //prepare shift register for bit shifting
- digitalWrite(myDataPin, 0);
- digitalWrite(myClockPin, 0);
- //for each bit in the byte myDataOut…
- //NOTICE THAT WE ARE COUNTING DOWN in our for loop
- //This means that %00000001 or "1" will go through such
- //that it will be pin Q0 that lights.
- for (i=7; i>=0; i--) {
- digitalWrite(myClockPin, 0);
- //if the value passed to myDataOut and a bitmask result
- // true then... so if we are at i=6 and our value is
- // %11010100 it would the code compares it to %01000000
- // and proceeds to set pinState to 1.
- if ( myDataOut & (1<<i) ) {
- pinState= 1;
- }
- else {
- pinState= 0;
- }
- //Sets the pin to HIGH or LOW depending on pinState
- digitalWrite(myDataPin, pinState);
- //register shifts bits on upstroke of clock pin
- digitalWrite(myClockPin, 1);
- //zero the data pin after shift to prevent bleed through
- digitalWrite(myDataPin, 0);
- }
- //stop shifting
- digitalWrite(myClockPin, 0);
- }
- ////////////////////////////////////////////////////////////////////////////////////
- void SetLEDS(byte tune, int vol)
- {
- digitalWrite(latchPin, 0);
- byte temp = 0;
- if (vol < 25)
- temp = 0;
- else if (vol < 100)
- temp = B00100000;
- else if (vol < 200)
- temp = B01100000;
- else
- temp = B11100000;
- switch(tune)
- {
- case 0:
- shiftOut(dataPin, clockPin, temp | 0);
- break;
- case 1:
- case 2:
- shiftOut(dataPin, clockPin, temp | 16);
- break;
- case 3:
- case 4:
- shiftOut(dataPin, clockPin, temp | 8);
- break;
- case 5:
- case 6:
- shiftOut(dataPin, clockPin, temp | 4);
- break;
- case 7:
- case 8:
- shiftOut(dataPin, clockPin, temp | 2);
- break;
- case 9:
- case 10:
- shiftOut(dataPin, clockPin, temp | 1);
- break;
- }
- digitalWrite(latchPin, 1);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void UpdateLCD(char* buffer, int detune, int note, int volume)
- {
- SSerial.print("?a"); // Home cursor
- SSerial.print(buffer);
- SSerial.print(" [");
- SSerial.print(note);
- SSerial.print("] Vol:");
- SSerial.print(volume);
- SSerial.print(" ");
- SetLEDS(detune, volume);
- //DrawDetune(detune);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void DrawDetune(int detune)
- {
- if (detune < 0)
- detune = 0;
- if (detune > 9)
- detune = 9;
- int detune1 = 18 -(detune * 2);
- if (old_detune_cent == detune1)
- return;
- SSerial.print("?y1?x"); // Home cursor
- if (old_detune_cent < 10)
- SSerial.print("0");
- SSerial.print(old_detune_cent);
- SSerial.print(" ");
- SSerial.print("?y1?x"); // Home cursor
- if (detune1 < 10)
- SSerial.print("0");
- SSerial.print(detune1);
- if (detune1 == 10)
- SSerial.print("[]");
- else
- {
- SSerial.print("?5?5");
- }
- old_detune_cent = detune1;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void sample_freq() // Interrupt handler function
- {
- if (sample_counter == NO_OF_SAMPLES)
- return;
- if ((sample_counter > 0) && (micros() < samples[sample_counter-1]))
- {
- sample_counter = 0; // Reset and
- return; // do nothing if we have overflowed.
- }
- samples[sample_counter] = micros();
- sample_counter++;
- }
Advertisement
Add Comment
Please, Sign In to add comment