Trellis & Hella OONTZ with Logic Pro X

Breakout boards, sensors, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
wgreenberg15
 
Posts: 2
Joined: Sat Aug 09, 2014 12:13 pm

Trellis & Hella OONTZ with Logic Pro X

Post by wgreenberg15 »

Hello,

I've altered the example code for the OONTZ step sequencer to work with just one Trellis and it works great with Logic Pro X. I'm planning on building a full size Hella OONTZ, but I've got a couple of questions:
1. Is there is a way to use more than one OONTZ or array of Trellises to control more than one Logic instrument/synth at a time?
2. As an aside to question 1, is there any way to control a larger-than 2x4 Trellis configuration (Hella OONTZ) with one Arduino Leonardo?
3. How can I sync the tempo between Logic and the Trellis/OONTZ? For example, can I have the tempo set in logic send to the Arduino to keep the sequencer in time?

Here's the code I'm using for reference:

Code: Select all

// Simple OONTZ MIDI step sequencer.
// Requires an Arduino Leonardo w/TeeOnArdu config (or a PJRC Teensy),
// software on host computer for synth or to route to other devices.

#include <Wire.h>
#include <Adafruit_Trellis.h>
#include <Adafruit_OONTZ.h>

#define LED 13 // Pin for heartbeat LED (shows code is working)

#ifndef HELLA
// A standard OONTZ has four Trellises in a 2x2 arrangement
// (8x8 buttons total).  addr[] is the I2C address of the upper left,
// upper right, lower left and lower right matrices, respectively,
// assuming an upright orientation, i.e. labels on board are in the
// normal reading direction.
Adafruit_Trellis T[4];
OONTZ            oontz(&T[0]);//, &T[1], &T[2], &T[3]); To use with just 1 Trellis
const uint8_t    addr[] = { 0x70 };//, 0x71,
                           // 0x72, 0x73 };
#else
// A HELLA OONTZ has eight Trellis boards...
Adafruit_Trellis T[8];
OONTZ            oontz(&T[0], &T[1], &T[2], &T[3],
                       &T[4], &T[5], &T[6], &T[7]);
const uint8_t    addr[] = { 0x70, 0x71, 0x72, 0x73,
                            0x74, 0x75, 0x76, 0x77 };
#endif // HELLA

#define WIDTH     ((sizeof(T) / sizeof(T[0])) * 1) //1 width vs 2 means 1 trellis across
#define N_BUTTONS ((sizeof(T) / sizeof(T[0])) * 16)

// Encoder on pins 4,5 sets tempo.  Optional, not present in
// standard OONTZ, but won't affect things if unconnected.
enc e(4, 5);

uint8_t       grid[WIDTH];                 // Sequencer state
uint8_t       heart        = 0,            // Heartbeat LED counter
              col          = WIDTH-1;      // Current column
unsigned int  bpm          = 240;          // Tempo
unsigned long beatInterval = 60000L / bpm, // ms/beat
              prevBeatTime = 0L,           // Column step timer
              prevReadTime = 0L;           // Keypad polling timer

// The note[] and channel[] tables are the MIDI note and channel numbers
// for to each row (top to bottom); they're specific to this application.
// bitmask[] is for efficient reading/writing bits to the grid[] array.
static const uint8_t PROGMEM
  note[8]    = { 48, 50, 53, 55, 57, 60 }, // pentatonic
//note[8]    = {  72, 71, 69, 67, 65, 64, 62,  60 }, normal scale
  channel[8] = {   1,  1,  1,  1,  1,  1,  1,   1 },
  bitmask[8] = {   1,  2,  4,  8, 16, 32, 64, 128 };

void setup() {
  pinMode(LED, OUTPUT);
#ifndef HELLA
  oontz.begin(addr[0], addr[1], addr[2], addr[3]);
#else
  oontz.begin(addr[0], addr[1], addr[2], addr[3],
              addr[4], addr[5], addr[6], addr[7]);
#endif // HELLA
#ifdef __AVR__
  // Default Arduino I2C speed is 100 KHz, but the HT16K33 supports
  // 400 KHz.  We can force this for faster read & refresh, but may
  // break compatibility with other I2C devices...so be prepared to
  // comment this out, or save & restore value as needed.
  TWBR = 12;
#endif
  oontz.clear();
  oontz.writeDisplay();
  memset(grid, 0, sizeof(grid));
  e.setBounds(60 * 4, 480 * 4 + 3); // Set tempo limits
  e.setValue(bpm * 4);              // *4's for encoder detents
}

// Turn on (or off) one column of the display
void line(uint8_t x, boolean set) {
  for(uint8_t mask=1, y=0; y<8; y++, mask <<= 1) {
    uint8_t i = oontz.xy2i(x, y);
    if(set || (grid[x] & mask)) oontz.setLED(i);
    else                        oontz.clrLED(i);
  }
}

void loop() {
  uint8_t       mask;
  boolean       refresh = false;
  unsigned long t       = millis();

  enc::poll(); // Read encoder(s)

  if((t - prevReadTime) >= 20L) { // 20ms = min Trellis poll time
    if(oontz.readSwitches()) {    // Button state change?
      for(uint8_t i=0; i<N_BUTTONS; i++) { // For each button...
        uint8_t x, y;
        oontz.i2xy(i, &x, &y);
        mask = pgm_read_byte(&bitmask[y]);
        if(oontz.justPressed(i)) {
          if(grid[x] & mask) { // Already set?  Turn off...
            grid[x] &= ~mask;
            oontz.clrLED(i);
            usbMIDI.sendNoteOff(pgm_read_byte(&note[y]),
              127, pgm_read_byte(&channel[y]));
          } else { // Turn on
            grid[x] |= mask;
            oontz.setLED(i);
          }
          refresh = true;
        }
      }
    }
    prevReadTime = t;
    digitalWrite(LED, ++heart & 32); // Blink = alive
  }

  if((t - prevBeatTime) >= beatInterval) { // Next beat?
    // Turn off old column
    line(col, false);
    for(uint8_t row=0, mask=1; row<8; row++, mask <<= 1) {
      if(grid[col] & mask) {
        usbMIDI.sendNoteOff(pgm_read_byte(&note[row]), 127,
          pgm_read_byte(&channel[row]));
      }
    }
    // Advance column counter, wrap around
    if(++col >= WIDTH) col = 0;
    // Turn on new column
    line(col, true);
    for(uint8_t row=0, mask=1; row<8; row++, mask <<= 1) {
      if(grid[col] & mask) {
        usbMIDI.sendNoteOn(pgm_read_byte(&note[row]), 127,
          pgm_read_byte(&channel[row]));
      }
    }
    prevBeatTime = t;
    refresh      = true;
    bpm          = e.getValue() / 4; // Div for encoder detents
    beatInterval = 60000L / bpm;
  }

  if(refresh) oontz.writeDisplay();

  while(usbMIDI.read()); // Discard incoming MIDI messages
}
Thanks in advance!

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Trellis & Hella OONTZ with Logic Pro X

Post by pburgess »

1. Is there is a way to use more than one OONTZ or array of Trellises to control more than one Logic instrument/synth at a time?
I don't know Logic in & out, but one could probably do this by using different channel numbers for each. You could test this on your current setup by changing the channel[] array...do different instruments respond?
2. As an aside to question 1, is there any way to control a larger-than 2x4 Trellis configuration (Hella OONTZ) with one Arduino Leonardo?
Not at present. The number of I2C addresses is maxed out. We're looking at things such as software I2C for a second channel, or a multiplexer.
3. How can I sync the tempo between Logic and the Trellis/OONTZ? For example, can I have the tempo set in logic send to the Arduino to keep the sequencer in time?
Good question! Again, not knowing the gritties of Logic, but perhaps it has a way of sending MIDI messages as well as receiving. The last line in the loop() function currently discards incoming messages, but (if Logic can send messages) you might be able to parse some of these to fetch the tempo setting.

User avatar
raskjaerbo
 
Posts: 2
Joined: Fri Aug 22, 2014 4:28 am

Re: Trellis & Hella OONTZ with Logic Pro X

Post by raskjaerbo »

Joining the discussion here.

I'm trying to communicate with the HELLA OONTZ via MIDI from MAX / Ableton Live. I have tried using the last line of code from the HELLO WORLD and STEP SEQ examples:

"while(usbMIDI.read()); // Discard incoming MIDI messages"

and

"usbMIDI.read();"

Could not get it to work unfortunately. I can send MIDI from the OONTZ which is great, but receiving has so far been unAdafruitful hehe. Interfacing with it from MAX would be killer!


Hope you can help :)

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Trellis & Hella OONTZ with Logic Pro X

Post by pburgess »

There's some info on the usbMIDI library here:
https://www.pjrc.com/teensy/td_midi.html

Handling incoming messages requires creating and registering callback functions with the library. There's some example code on that page.

User avatar
wgreenberg15
 
Posts: 2
Joined: Sat Aug 09, 2014 12:13 pm

Re: Trellis & Hella OONTZ with Logic Pro X

Post by wgreenberg15 »

I've got a similar issue when it comes to potentiometers. I'm having trouble getting the Arduino to read the pots to allow the user of the Hella OONTZ to change tempo, modulation, filter cutoff, etc. pburgess, I see in the link you posted there's a link to Philip Cunningham's MIDI controller that utilized 6 knobs, but that link is broken (the BANNED site seems to be out of commission). Any chance that code is available somewhere else?

Also, I was able to use more than one Trellis/OONTZ to control multiple instruments at once by using two Leonardo's and changing the MIDI channel like you suggested. I also had to assign the Logic instruments to individual channels, which was oddly harder than the Arduino side of things!

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Products from Adafruit”