Skip to content

Commit

Permalink
Add README, get color wheel working, code cleanup.
Browse files Browse the repository at this point in the history
  • Loading branch information
cchurch committed Sep 11, 2019
1 parent a4c1cd9 commit 61766c0
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 88 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
The Whueel
==========

The _Hue Wheel_: a MIDI controller for controlling the hue of lights.

Currently uses MIDI channel 7 and control change 111.

Built from:
* [Teensy 2.0](https://www.pjrc.com/store/teensy.html)
* [Bourns EAW Absolute Rotary Encoder](https://www.bourns.com/products/encoders/contacting-encoders/product/EAW)
* [12X WS8212 RGB LED Ring](http://www.diymalls.com/OLED?product_id=345)
2 changes: 1 addition & 1 deletion thewhueel/ACE128.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ void ACE128::_eeprom_write_mpos()
// write _zero to eeprom
void ACE128::_eeprom_write_zero()
{
uint16_t eeAddr = eeAddr + sizeof(_mpos);
uint16_t eeAddr = _eeAddr + sizeof(_mpos);
#if defined(ACE128_EEPROM_I2C)
Wire.beginTransmission(ACE128_EEPROM_ADDR);
Wire.write((uint8_t) (eeAddr >> 8));
Expand Down
204 changes: 117 additions & 87 deletions thewhueel/thewhueel.ino
Original file line number Diff line number Diff line change
@@ -1,99 +1,129 @@
// #define STR_PRODUCT L"The Whueel MIDI"
#include "ACE128.h" // Absolute Contact Encoder
#include <ACE128map12345678.h> // mapping for pin order 12345678
#include <Wire.h> // I2C bus communication library - required to support ACE128
// FIXME: Attempt to change USB device name!
#define STR_PRODUCT L"The Whueel MIDI"

#if !defined(__AVR_ATmega32U4__) || !defined(CORE_TEENSY)
#error "Only designed to run on Teensy 2.0!"
#endif

#if !defined(USB_MIDI)
#error "USB Type should be set to MIDI!"
#endif

#include "ACE128.h"
#include <ACE128map12345678.h>
#include <Adafruit_NeoPixel.h>

// Create an ACE128 instance called myACE
ACE128 myACE(10,9,8,7,11,14,13,12, (uint8_t*)encoderMap_12345678);

uint8_t pinPos = 0; // pin values
uint8_t oldPos = 255;
uint8_t old_upos = 255;
uint8_t upos = 0;
uint8_t seen = 0;
elapsedMillis msec = 0;


// Which pin on the Arduino is connected to the NeoPixels?
#define PIN 6 // On Trinket or Gemma, suggest changing this to 1

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 12 // Popular NeoPixel ring size

// When setting up the NeoPixel library, we tell it how many pixels,
// and which pin to use to send signals. Note that for older NeoPixel
// strips you might need to change the third parameter -- see the
// strandtest example for more information on possible values.
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
int error = 1;
myACE.begin(); // this is required for each instance, initializes the pins
pinPos = myACE.acePins(); // get IO expander pins
oldPos = pinPos; // remember where we are
Serial.begin(9600);
Serial.println(myACE.acePins());
pixels.begin();
#define MIDI_CHANNEL 7
#define MIDI_CC_NUM 111

#define ACE_PIN1 10
#define ACE_PIN2 9
#define ACE_PIN3 8
#define ACE_PIN4 7
#define ACE_PIN5 11
#define ACE_PIN6 14
#define ACE_PIN7 13
#define ACE_PIN8 12

#define PIXEL_COUNT 12
#define PIXEL_OFFSET 8
#define PIXEL_PIN 6

// ACE128 instance with pin mapping.
ACE128 encoder(ACE_PIN1, ACE_PIN2, ACE_PIN3, ACE_PIN4, ACE_PIN5, ACE_PIN6, ACE_PIN7, ACE_PIN8, (uint8_t*)encoderMap_12345678);

// NeoPixel ring (12 LED).
Adafruit_NeoPixel pixels(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

void setup()
{
encoder.begin();
encoder.setZero(0);
pixels.begin();
Serial.begin(9600);
Serial.println(encoder.acePins());
}

static void check_pins(uint8_t pins)
{
static uint8_t seen_pins = 0;
static uint8_t old_pins = 255;

void loop() {

pinPos = myACE.acePins(); // get IO expander pins
upos = myACE.upos(); // get logical position - unsigned
if (pins == old_pins) {
return;
}

if (pinPos != oldPos) { // did we move?
seen |= pinPos ^ oldPos; // what changed?
oldPos = pinPos; // remember where we are
if (seen < 255) {
Serial.print("looking for pins: ");
for (uint8_t i = 0; i <= 7; i++) {
if (! (seen & 1 << i)) {
Serial.print(i, DEC);
seen_pins |= pins ^ old_pins;
old_pins = pins;
if (seen_pins < 255) {
Serial.print("looking for pins: ");
for (uint8_t i = 0; i <= 7; i++) {
if (! (seen_pins & 1 << i)) {
Serial.print(i, DEC);
}
}
}
Serial.println("");
} else {
Serial.print(" upos ");
Serial.println(upos, DEC);
Serial.println("");
}
else {
Serial.print("pins = ");
Serial.println(pins, DEC);
}
}

static void update_midi(uint8_t upos)
{
static uint8_t old_upos = 255;
static elapsedMillis msec = 0;

// Send MIDI updates at most 50x/sec and only if input changed.
if (msec >= 20 && upos != old_upos) {
msec = 0;
old_upos = upos;
usbMIDI.sendControlChange(MIDI_CC_NUM, upos, MIDI_CHANNEL);
}
}

// only check the analog inputs 50 times per second,
// to prevent a flood of MIDI messages
pixels.setBrightness(0x10);
if (msec >= 20) {
msec = 0;
// only transmit MIDI messages if analog input changed
if (upos != old_upos) {
usbMIDI.sendControlChange(111, upos, 7);
old_upos = upos;
pixels.setPixelColor(4, (upos >= 123 || upos < 6) ? 0xff0000 : 0x400000);
pixels.setPixelColor(5, (upos >= 6 && upos < 17) ? 0xbf3f00 : 0x301000);
pixels.setPixelColor(6, (upos >= 17 && upos < 27) ? 0x7f7f00 : 0x202000);
pixels.setPixelColor(7, (upos >= 27 && upos < 38) ? 0x3fbf00 : 0x103000);
pixels.setPixelColor(8, (upos >= 38 && upos < 49) ? 0x00ff00 : 0x004000);
pixels.setPixelColor(9, (upos >= 49 && upos < 59) ? 0x00bf3f : 0x003010);
pixels.setPixelColor(10, (upos >= 59 && upos < 70) ? 0x007f7f : 0x002020);
pixels.setPixelColor(11, (upos >= 70 && upos < 81) ? 0x003fbf : 0x001030);
pixels.setPixelColor(0, (upos >= 81 && upos < 91) ? 0x0000ff: 0x000040);
pixels.setPixelColor(1, (upos >= 91 && upos < 102) ? 0x3f00bf : 0x100030);
pixels.setPixelColor(2, (upos >= 102 && upos < 113) ? 0x7f007f: 0x200020);
pixels.setPixelColor(3, (upos >= 113 && upos < 123) ? 0xbf003f: 0x300010);

//for (int i=0; i < pixels.numPixels(); i++) {
// pixels.setPixelColor(i, () << 16
//pixels.setPixelColor(i, upos);
//}
pixels.show();

// MIDI Controllers should discard incoming MIDI messages.
// http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
while (usbMIDI.read()) {
// ignore incoming messages
}
}
}

static void update_leds(uint8_t upos)
{
static uint8_t old_upos = 255;

if (upos == old_upos) {
return;
}

old_upos = upos;
pixels.setBrightness(255);

for (uint16_t p = 0; p < pixels.numPixels(); p++) {
uint16_t pIndex = (p + PIXEL_OFFSET) % pixels.numPixels();
uint16_t pPos = pIndex * 128 / pixels.numPixels();
uint16_t pDiff = abs((int16_t)pPos - (int16_t)upos);
if (pDiff > 64) {
pDiff = 128 - pDiff;
}
uint8_t pVal = 15;
if (pDiff <= (128 / pixels.numPixels())) {
pVal = 255 - pDiff * 288 / pixels.numPixels();
}
uint32_t pColor = pixels.ColorHSV(pIndex * (65535 / pixels.numPixels()), 255, pVal);
pixels.setPixelColor(p, pColor);
}

pixels.show();
}

// MIDI Controllers should discard incoming MIDI messages.
// http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
while (usbMIDI.read()) {
// ignore incoming messages
}
void loop()
{
uint8_t pins = encoder.acePins();
uint8_t upos = encoder.upos();

check_pins(pins);
update_midi(upos);
update_leds(upos);
}

0 comments on commit 61766c0

Please sign in to comment.