Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 38

Thread: Teensy 3.1 Midi - USB Interface: 1 in+2 Out/Thru (split) + Midi Controller

  1. #1

    Teensy 3.1 Midi - USB Interface: 1 in+2 Out/Thru (split) + Midi Controller

    Hello All,
    I am a Sound Engineer and often I am required to run two Mac based sequencers in sync with each other.
    I would like to make a controller to give me basic functions like "Go/Play", "Next", "Back", "Pause" and "stop" (Like a glorified old school tape machine AND maybe a pot for Master Volume control. These can be generic on/off Midi commands or MMC commands).
    So thats 5 buttons and a Slider/Pot. There are many tutorials on how to do this with the Teensy, but I would also like to incorporate some other functions which would be very useful to me.
    A MIDI in (So I can use the device as a stand alone Midi - USB converter when I need it)
    2 x MIDI Out (Again so I can use it as a USB-MIDI device PLUS send the Controller side of it out PLUS act as a MIDI Thru port from the MIDI in AND an output from the USB MIDI.
    I plan on adding a 5V power in (so would cut the tracer from USB + Pads on the Teensy so that all devices get their needs met in the chain: the Teensy and 2 x MIDI devices).
    Phew.
    Do you think that is possible with just the Teensy? I have found MIDI controller tutorials and Midi to USB tutorials using the Teensy, and MIDI splitter tutorials (without the teensy) but am unsure of how to combine them all.
    And how many Buttons/sliders would I be able to have on my controller after allowing for the other ins/outs? I would probably just max it out for future uses.
    It would be fantastic for me to have one box that does it all and is flexible in its uses rather than doing everything independently - It creates so much clutter having a controller and then a cable to a splitter and then a USB interface... I would rather have it all in one compact box!

    Regards,

    Sandy

  2. #2
    Ok, This has taken me all day to draw! Well, not to draw, but to find a program to use and figure out how to use it!
    I have used the analogue ins for the buttons but I believe these could be bumped to the digital side? Its just the Pots and Faders that need to be on the Analogue side?
    And as for the rest of the circuit - will it work?!
    I am not circuit savvy but have looked at the midi specification to see how to do a MIDI-Out/Thru circuit and a MIDI In circuit... Mine differs a little because I want the Teensy to absorb all the data from the In, merge any potential data from the USB or buttons/knobs/faders and Output that to the Outputs...
    Am I doing this right? Is this making sense? Or am I totally lost!
    Click image for larger version. 

Name:	Screen Shot 2016-01-07 at 11.35.21 pm.jpg 
Views:	3051 
Size:	111.2 KB 
ID:	6028

    I have used a sharp PC900V for an Optocoupler - as recommended by the MIDI specifications, and put a power regulator on the input for safety.
    The MIDI guidelines also recommend adding some ferrite chokes on the pins to the MIDI socket- I just didnt draw them in.
    And I don't know for sure if I got the Diode or the Capacitor around the right way. I also started to get confused which pin the midi should be coming out of to go to the PC900... Brain melting. Time for bed!
    Last edited by sandysound; 01-07-2016 at 09:47 PM.

  3. #3
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    Yes you can do this. you are totally on the right track

    I didn't know that midi called for a ferrite choke!! I have successfully used this circuit (no choke). Midi thru is pretty easy and midi out hardware is really easy ... I'm not sure about running 2 midi out ports off one serial line, but seems OK (I've never done it myself) ...software merge is easy ...

    As to sliders and buttons, I use 13 buttons and one motorised fader myself, outputing usb midi .... adding in your software merge is not going to be a problem ... I can give you the code.

    One thing I would query is sync ... while you may be sending midi messages "at the same time", don't you need a MTC / MMC- type master to stop drift? Just starting them together is not really good enough is it??? I've not investigated that in the teensy context (cause I've never synced two sequencers ...) .... what do you need to send to keep sync / update transport speed, midi protocol wise? That could be 'tricky'???

    Here is a link for USB midi to serial midi .... adding in merge from buttons etc is nt going to be much of a step ...
    Last edited by adrian; 01-08-2016 at 12:16 AM. Reason: put in links

  4. #4
    Cool, I designed the circuit using the Teensy MIDI reference page and some diagrams (below) I found in a Document here: http://www.midi.org/techspecs/ca33.pdf
    You can include ferrite beads to "improve EMI/EMC performance".
    Click image for larger version. 

Name:	Screen Shot 2016-01-07 at 9.05.10 pm.jpg 
Views:	1323 
Size:	126.9 KB 
ID:	6030
    Click image for larger version. 

Name:	Screen Shot 2016-01-07 at 9.05.27 pm.png 
Views:	577 
Size:	60.7 KB 
ID:	6031
    I think the buttons need to be on the digital pins instead of the analogue pins but thats no biggie.
    Maybe I have the MIDI lines round the wrong way on the connectors - I plan on using a different TX for each MIDI output - just cause I can really. As for Sync... I don't know anything about MIDI Sync! I assume if I tell a MIDI command to leave the Teensy on TX1,2 and 3 it will happen simultaneously on each output... Am I wrong?
    When it comes to Sync my main concern is usually the device receiving the MIDI and outputting the Audio (Soundcard) are slaved to a master clock using Timeclock...
    Keeps the computers audio outputs sample accurate but never thought the MIDI might be transmitted at different times! Would adding a clock to the Teensy help to control that?
    Your offer of code is greatly accepted!
    Last edited by sandysound; 01-08-2016 at 12:22 AM.

  5. #5
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    Yes buttons are on digital pins (there are lots) ... faders and pots are on analog pins ...

    You are right that if you send on TX 1 2 and 3 'at the same time' the midi messages will be spat out at pretty much the same time .... I was thinking you just use tx 1 but with two midi interfaces hooked up to in parallel, so midi would be 'simultaneous'

    I would have thought that the transports would drift apart even if started at exactly the same time?? BUT If you already have a clock then you should be OK ...

    Might be a good thing to research though, but if you say that you already have sample accurate sync, then you should be good to go, and not need clock from the teensy (how you would do MMC / MTC from the teensy, I'm not sure ... must be doable though).

    you are welcome to my code ... but you must suffer .... .... picture (s) of MY CONTROLLER!!!!

    Click image for larger version. 

Name:	WP_20160108_14_37_16_Pro.jpg 
Views:	204 
Size:	67.4 KB 
ID:	6032Click image for larger version. 

Name:	WP_20160108_14_37_54_Pro.jpg 
Views:	155 
Size:	78.6 KB 
ID:	6033

    It uses the faderport protocol (which is just a bunch of specific midi messages) and includes a motorised fader ... it takes the feedback from the DAW and moves the fader to the right position .... the joystick changes track, the big buttons are transport control, and the little buttons select automation write / read modes. The wheel is track pan (just finishing the code for that right now!! It uses a 24 click encoder, and some neat lookup table tricks). Happy to share the code ....

    Of course, the controller can be changed, at the press of a teensy button ...TO A MAME DEFENDER CONTROLLER!! YAY

    Hijacked.

    EDIT: you only need an optocoupler for midi in connected to RX... TX for serial midi out is just a couple of resistors (hence, I think its going to be pretty easy to use tx 1 only but with 2 midi output DINS ...
    Last edited by adrian; 01-08-2016 at 01:21 AM.

  6. #6
    Heh heh cool man - thanks for the pics! Looks sweet as bro!
    Ok -would I need to put a resistor on each output or just one and then split?
    Here is a recent setup I created - slightly less complicated than usual! In this setup I used the Zen Studio as a master clock over ADAT as well as analog input preamp and splitter to the Motu's. It also had two Midi controllers (or keyboards generally).
    Ive never thought about latency between the signals when running systems like this - Its just not been an issue. I usually check the syncing of the systems by recording the outputs of both machines and then zooming in on the wav files. It's bang on every time. I hope to achieve the same level of accuracy using the Teensy...
    Click image for larger version. 

Name:	Screen Shot 2016-01-08 at 3.11.06 am.jpg 
Views:	531 
Size:	68.8 KB 
ID:	6034
    Looking at code - I don't get how to enable the midi to be transmit over all the outputs - usb and serial 1, 2 and 3...
    I'm not good at code! Lol
    Here's what I have, its been collected and butchered to fit - kind of, I think!
    I can see where you assign Midi Notes to the Digital pins but I don't see anything similar for the Analogue section...
    Code:
    /* some code designed for using the Teensy 3 as a USB MIDI controller
    v1.0, December 17 2013
    by Yann Seznec www.yannseznec.com
    
    no copyright or anything, use however you want
    
    remember to select MIDI as your USB Type in the Tools menu
    
    this should also work with other Teensy boards, apart from the "touch" pins
    
    things that are kind of dumb in this code:
    - the touch threshold is hard coded (int touchThreshold)
    - touch pins only send midi note on/off with no velocity change
    - no system for sending touch pin as CC
    - the CC assignments are sort of random, probably should have another array for them
    
    */
    
    
    int const numPins = 10; //  number of analog inputs 
    int currentVal[numPins];
    int newVal[numPins];
    int analogPins[] = {  
      14,15,16,17,18,19,20,21,22,23   // which analog pins to use
    };
    
    
    int const numDigPins = 7; // number of digital pins to send note values
    int currentDig[numDigPins];
    int digitalpin[] = {
      2,3,4,5,6,11,12    // which digital pins to use for sending note values
    };
    int digitalpitch[] = {
      48,50,51,53,55,57,58}; // which midi notes to send from the digital pins selected above
    int digInput[numDigPins];
    
    
    int const numDigPinsCC = 0; // number of digital pins to send CC
    int currentDigcc[numDigPinsCC];
    int digitalpincc[] = {
       2,3,4,5,6,7,8,9,10 // which digital pins to use for sending CC
    };
    int digInputcc[numDigPinsCC];
    
    
    int const numTouchPins = 0; // number of pins to use as touchpins, sending note values
    int touch[numTouchPins];
    int touchon[numTouchPins];
    int touchpin[] = {
      0,1,15,16,17}; // which digital pins to use as touch pins
      int touchpitch[] = {
      60,63,65,67,70}; // which midi notes to send from the touch pins
      int touchThreshold = 2000; 
      int touchMax = 5000; 
    
    
    // the MIDI channel number to send messages
    const int channel = 1;
    
    
    
    void setup() {
      pinMode(2, INPUT_PULLUP);
      pinMode(3, INPUT_PULLUP);
      pinMode(4, INPUT_PULLUP);
      pinMode(5, INPUT_PULLUP);
      pinMode(6, INPUT_PULLUP);  
      pinMode(11, INPUT_PULLUP);
      pinMode(12, INPUT_PULLUP); 
    
      Serial.begin(31250);
    
    }
    
    
    // digital pins sending notes
      for (int i = 0; i < numDigPins; i++) {
        if (digitalRead(digitalpin[i]) == 1 && currentDig[i] == 0) {
          usbMIDI.sendNoteOff(digitalpitch[i], 100, channel); 
          currentDig[i] = 1;
        }  
        if (digitalRead(digitalpin[i]) == 0  && currentDig[i] == 1) {
          usbMIDI.sendNoteOn(digitalpitch[i], 100, channel);
          currentDig[i] = 0;
        }  
      }
    
    // digital pins sending CC
    
      for (int i = 0; i < numDigPinsCC; i++) {
        if (digitalRead(digitalpincc[i]) == 1 && currentDigcc[i] == 0) {
          usbMIDI.sendControlChange(i+50, 0, channel); 
          currentDigcc[i] = 1;
        }  
        if (digitalRead(digitalpincc[i]) == 0  && currentDigcc[i] == 1) {
          usbMIDI.sendControlChange(i+50, 127, channel);
          currentDigcc[i] = 0;
        }  
      }
    
    // analog pins
    
      for (int i = 0; i < numPins; i++) {
    
        newVal[i] = analogRead(analogPins[i]);
    
        if (abs(newVal[i] - currentVal[i])>3) {
          usbMIDI.sendControlChange(i+1, newVal[i]>>3, channel); 
          currentVal[i] = newVal[i];
        }  
      }
      
      // i think if you remove these last two lines everything breaks and things are sad and people cry
      while (usbMIDI.read()); // read and discard any incoming MIDI messages
      delay(25); 
    }





    And thanks to yourself I have this in another tab:

    Code:
    #include <MIDI.h>;
    int chnl,d1,d2,dd;
    kMIDIType type;
    void setup() {
      
      Serial.begin(31250);
    
    }
    
    void loop() {
      if (MIDI.read() &&  MIDI.getType() < SystemExclusive) {
        type = MIDI.getType();
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
        dd = d1 + (d2 << 8);
        chnl = MIDI.getChannel();
        // and then send...
        switch(type){
          case NoteOn:
            usbMIDI.sendNoteOn(d1,d2,chnl);
          break;
          case NoteOff:
            usbMIDI.sendNoteOff(d1,d2,chnl);
          break;
          case AfterTouchPoly:
            usbMIDI.sendPolyPressure(d1,d2,chnl);
          break;
          case ControlChange:
            usbMIDI.sendControlChange(d1,d2,chnl);
          break;
          case ProgramChange:
            usbMIDI.sendProgramChange(dd,chnl);
          break;
          case AfterTouchChannel:
            usbMIDI.sendAfterTouch(dd,chnl);
          break;
          case PitchBend:
            
            usbMIDI.sendPitchBend(dd,chnl);
          break;
          case SystemExclusive:
            // handle sysex
          break;
          default:
            // F8 et seq.
          break;
        }
      }
      if (usbMIDI.read() &&  usbMIDI.getType() < SystemExclusive) {
        type = (kMIDIType) usbMIDI.getType();
        d1 = usbMIDI.getData1();
        d2 = usbMIDI.getData2();
        
        chnl = usbMIDI.getChannel();
        // and then send...
        MIDI.send(type,d1,d2,chnl);
      }
    }
    Last edited by sandysound; 01-08-2016 at 09:05 AM. Reason: CODE Wrapping!

  7. #7
    In this example, the tx is split, then individually amplified? and then the 220 resister before each output...
    Click image for larger version. 

Name:	midithrubox.gif 
Views:	2229 
Size:	19.9 KB 
ID:	6035
    Other circuits I have seen use an IC to make the split... I think the Teensy should be able to handle doing individual serial outputs in sync for each "thru" - I will try it first, I think it is the simplest way forward?!

  8. #8
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    .....BUT Oh shit, you gonna make me think about ohms law??? I think just whack another DIN on off the back of the other one ...would make current draw an issue I suppose, but voltage and resistance should be in spec ... must be a diagram for that somewhere ...

    Anyway .... happy to help with the code ...just give us a bit of a thinking time ... Note that there are code wrappers under 'advanced' for posting code .. makes it easier to read

    EDIT ... I see you are looking at schematics ... because its a software split fundamentally usig a teensy I'm not sure about the diagram .... putting the same signal out of two separate ports vs analog splitting of one port is probably neither here nor there ...interesting though (someone will know the answer ...)

    Back to clocking ... I get your clocking for your audio interfaces ...I used to run sync using adat (when I had an adat interface, obviously) ... What I was thinking about was then sequencer transports ... presumably on two different macs .... I guess that clocking the audio interfaces connected to the sequencers will work ok, but I am not an expert by any means when it comes to syncing sequencers ... What I am wondering is that while you have the audio packets synced up distribution wise (i.e. all the converters convert on the clock), what keeps the sequencers producing samples at the same time after initially setting them off together ... on old school tape machines, smpte was used to speed up slow down play rates .... i guess the adat master will sync the sequencers if the sequencers are set as slave ... I would have thought that mtc was the usual way to do that ( but I just don't know) ...


    Here is an interesting link
    about syncing reaper (a sequencer / daw) to adat
    Last edited by adrian; 01-08-2016 at 02:25 AM.

  9. #9
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    What are the sequencers you are trying to sync? Can their transports be slaved to yr adat master? Or maybe one can send mtc or something to the other ??

    Do you require output over usb midi and serial 'sequentially', merging with 'button data', ?? To explain .... if there is usbmidi data, it is merged with 'button data' (if any) and output to the serial ...and if there is serial data it is merged with 'button data' (if any) and output to usbmidi?

    Code to come

  10. #10
    Further to your question for clarity: forcing the output of the machines to "listen" to a WC sample rate such as 48kHz means neither machine gets ahead or behind the other as they will only release each individual audio sample as it is "told" to. The audio then comes out simultaneously. As long as the midi commands depart the controller /split they will arrive at the same time and all is well. For this purpose it is best to use the same kind of MIDI device on each machine - in my example I am using identical Motu's to handle the MIDI and Audio data so that both machines will react and behave in unison.

  11. #11
    Here is a new circuit diagram - its getting very messy - I will have to do another one.
    Click image for larger version. 

Name:	Screen Shot 2016-01-08 at 10.51.39 am.jpg 
Views:	824 
Size:	144.7 KB 
ID:	6037
    You can now see three discreet inputs to the serial inputs of the teensy.
    I have also added a 16 position rotary encoder for Midi Channel Select for the "Local" inputs (Buttons/pots/faders) - so you can choose which channel you want them to be on (Midi Ch 1-16). This is only to affect the "local" buttons/faders/pots on the box.
    Plus a switch to turn only the buttons (not pots or faders - they remain CC data) from CC note on/off to MIDI Machine Control messages. Circuit open = MIDI CC data, circuit closed = MMC data.
    Is that possible?
    Or am I asking too much now...
    The more time you give me the more I get to think about it lol.
    Thanks Adrian - super appreciate your help.

  12. #12
    Hmmm, my initial reply to your post #9 has gone missing - I must have done something by accident - I was using the phone!
    But here is what it said:
    Thanks again Adrain, food for thought about the split. And sorry about the code wrapping or lack of - I thought there must be a better way! I'll try to fix it.
    I got thinking about maxing out the Teensy specs: if it has 3 serial ports, why not make this device a 3x3 in and out stand alone Midi Port + USB with Thru functionalty AND controller! You can thank my nap for coming up with that bright spark - would that change your code much?!
    Basically I would like all incoming data to output everywhere, including Midi, serial ports and local buttons (regardless of origin so it doesn't matter which port I plug things into or out of - they all get the same signal). How that is handled exactly I don't really know - preferably as fast as possible! :-D

    In regards to clocking a sequencer, it is very common to use a Master Wordclock device to slave the computers too via their Audio Interface. This is what keeps the software and hardware insync. I use Ableton Live, Liveprofessor and Q Lab primarily and within the software settings you can select which clock to use - internal or external (WC). Just like in your Reaper example.
    Digital Recording studios will clock absolutely everything Digital to one Master clock such as an Apogee Big Ben.
    I use them to run a main and back up playback rig for redundancy. Computers are great but can be a show stopper when they fail so clocking everything to one clock means I can switch between the two if one crashes / fails without losing my "place" in the show and we can carry on while I try to reboot the failed machine and get that back to where we are in the show.

  13. #13
    I saw PJRC mention in another thread that only Serial 1 and 2 has FIFO - is that important? Do I need it for serial 3 or should we just focus on a 2 in 2 out instead of 3 x 3?

  14. #14
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    I think FIFO is pretty necessary for what you are doing, at least without delving deep, and I think only serial1 has a big FIFO ...I think that an analog solution for splitting a single serial out line is the best way to go for your application where all of the midi outs are just the same, but I might be wrong. Or is it that you now keen on a 3x3 routing matrix?

    EDIT: Actually Im not sure that you can use more than 1 serial port for serial midi at a time .... that could be a real spanner in the works ... you might need multiple teensys for multiple midi ports.

    Never tried it obviously ... but someone would have thought about it.

    EDIT : found this
    Last edited by adrian; 01-08-2016 at 07:00 PM.

  15. #15
    Copy - good read.
    I'm hoping the software can do two - it just looks easier lol but I can go the analog way if need be no problem.

    EDIT: I found this posted by PJRC:

    Actually, both Serial1 and Serial2 on Teensy 3.1 and 3.2 have the FIFO.

    On Teensy 3.0, only Serial1 had a FIFO.

    None of the ports on Teensy LC have FIFOs.
    EDIT: You probably saw that also seeing as you then ask about it lol sorry bro!
    Last edited by sandysound; 01-08-2016 at 07:41 PM.

  16. #16
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,576
    Quote Originally Posted by sandysound View Post
    ... only Serial 1 and 2 has FIFO - is that important?
    As with so many technical features, the answer is "it depends".

    MIDI's 31250 baud rate is pretty slow compared to the speed of Teensy 3.2. Without the FIFO, that's an interrupt every 320 microseconds. You can tolerate almost double that much interrupt latency before the incoming bits overwrite the buffer.

    So really, the question is whether you'll be blocking serial port interrupts for that long. If you're just using the 3 serial ports, the answer is you'll almost certainly be safe. Those interrupts last only several microseconds.... nowhere near 320. The serial interrupts are at a higher priority level than USB and most others, so even if some other interrupts last a long time, the question is whether they block the serial ones.

    But if you use a library like Adafruit_Neopixel which hogs the CPU with interrupts turned off, you can run into trouble. It disables interrupts for approx 30 us per LED. So around 10 LEDs and certainly by 20, it could start to cause serial data loss at MIDI baud rates.

    The FIFO will let you tolerate 8X longer interrupt latency, so it makes a huge improvement, but it's not magic.

    The other things FIFOs do, which probably won't matter for this project, is lower the CPU usage of the interrupts. Managing the FIFO takes a little extra work, but the 4X or more reduction in the number of interrupts greatly offsets its minor overhead. If you're doing a lot of computationally intensive stuff which has to keep real-time pace with the data, the FIFO might help a little on the CPU side. But for relatively simple MIDI protocol, the fast CPU in Teensy 3.2 will probably be more than enough even with extra overhead in the interrupts.

  17. #17
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    Thankyou Paul.. How would I go about using two instances of the Midi Serial Library "per uart". In the documentation for 4.2 of the arduino midi library there is a macro defined for creating a separate instance of the library ... Here is an example (pardon me for not using code markers and not posting the whole of the code ...)

    MIDI_CREATE_INSTANCE (HardwareSerial, Serial2, midi2);


    When I try it I get "Serial2 is not a type" on compile ... Serial2 is an object? what is its type? (I am a C++ noob) ....or is the macro not working cause teensy is not on 4.2??

    I suppose I will have to look at the source code to see how to properly institute 2 separate per uart instances of the library?>>?..

  18. #18
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    OK ... stocktake ... you have your sequencers synced up using word clock magic (Hmm pretty sure wordclock is for audio distribution between digital pieces, and not transport sync ....I used to use an RME pci-e piece for adat sync, but never for transport sync ... anyway) .... So all you need is MMC to kick them off at the same time.

    Here Is where I have got to ...

    Two serial midi outs, using separate uarts, is on the cards. At this stage though only one serial out is programmed.

    One serial in at this stage, too ... scaling the serial MIDI hardware and software is the 'trick'... its a matter of instantiating two or more library objects for each serial port .... there is this very cool example, which will help with the midi thru no-end ....

    An interesting thing is that supposedly thru mirroring is turned on by default in the serial midi library (v4.2).... there is a mode for it in v 3.x, but I think that it is not on by default ... will have to look at this further.

    how it plays out for usb, Im not so sure ...

    The 1 x 1 serial interface is mirrored with USB midi i/o, and sent with with Midi button data (selectable as either MMC or CC/random Midi) plus a fader (one only).

    The selection as to MMC mode or random Midi mode is a one only choice, requiring a reset to change ... if no choice is made as to mode then nothing works .... Thats the way its programmed.

    The fader is not motorized (I have taken the motor code out ... i.e.no parameter feedback, so soft takeover needed). The one I have is a capacitive touch enabled one, so when you touch it, a MIDI message is sent once, and then 10 bit CC data is send CC 0, 3 bits MSB and CC 32 7 bits LSB.

    There is a rotary encoder that selects channel .... the problem with this is that there is no feedback as to what channel you have selected (maybe LEDs??? an oled?? or maybe a 16 position switch!!!)

    I'm going to test this over the next couple of days (I have all the hardware!! and most of the code has already been tested, so it should just work ... it compiles atm!!!)

    and get into sorting out the thru function better ...aiming for 2 x 2...





    Code:
    #define SWITCHES 7
    #define TOUCHTHRESH 2000
    #define HYST 2          //HYSTERESIS AMOUNT
    #include <usb_midi.h>
    #include <MIDI.h>
    #include "midicontrolHACK3.h"
    
    int myMode = 0;
    const int MMC = 1;
    const int MIDINOTES = 2;
    
    static int myChannel = 1;
    
    const byte MMCSTOP []      {240, 127, 127, 6, 1, 247};
    const byte MMCPLAY []      {240, 127, 127, 6, 2, 247};
    const byte MMCFFWD []      {240, 127, 127, 6, 4, 247};
    const byte MMCRWD []       {240, 127, 127, 6, 5, 247};
    const byte MMCPUNCHIN []   {240, 127, 127, 6, 6, 247};
    const byte MMCPUNCHOUT[]   {240, 127, 127, 6, 7, 247};
    const byte MMCPAUSE []     {240, 127, 127, 6, 9, 247};
    
    const byte* MMCTransport [] {MMCSTOP, MMCPLAY, MMCFFWD, MMCRWD, MMCPUNCHIN, MMCPUNCHOUT, MMCPAUSE};
    
    const uint8_t wiperPin = A4;  //read fader value analog pin
    const uint8_t touchPin = 1;  /// capacitive touch fader
    
    int sendSwitchesMIDINOTES [] {19, 21, 6, 1, 5, 99, 67}; // 7 random MIDI note numbers ???  could be CC ...
    
    const uint8_t switchesPinTable [] {15, 22, 23, 9, 10, 11, 12, 16, 17};
    /*
       15, 22, 23 etc ... first 7 bits of C pin register
       16 and 17 are first two pins of B register for encoder
    */
    
    static int8_t enc_states[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
    static uint8_t old_AB = 0;
    
    void Fader::RW() // set up for capacitive touch
    {
      PositionPinRead();
      touchPinRead = touchRead (touchPin);
      if (touchPinRead > TOUCHTHRESH)
      {
        if (TOUCHSENT == false) {
          usbMIDI.sendPolyPressure (127, 1, 1);
          TOUCHSENT = true;
        }
        PINWRITE();
      }
      else
      {
        if (TOUCHSENT == true) {
          usbMIDI.sendPolyPressure (127, 0, 1);
          TOUCHSENT = false;
        }
      }
    }
    
    void Fader::PositionPinRead()
    {
      hystPinRead = analogRead (wiperPin);
      if  (currentPinRead > (hystPinRead + HYST) || hystPinRead > (currentPinRead + HYST))
      {
        currentPinRead = hystPinRead;
      }
    }
    
    void Fader::PINWRITE ()
    {
      sendMSB = currentPinRead >> 3;
      sendLSB = currentPinRead & 0x00F;
      usbMIDI.sendControlChange (0, sendMSB, 1);
      //delay(1); // 500 micros is probably better here??? is it even needed??
      usbMIDI.sendControlChange (32, sendLSB, 1);
    }
    
    void Switches::RW (int choice, int channel)  // could be done using bounce library, and if no noteoff's required, could be structured a bit more simply maybe
    {
      readMSB = GPIOC_PDIR & 0x07F;
      //readLSB = GPIOD_PDIR  & 0x00F;
      //delay(1);  is this needed..?
      switch (choice)
      { case MIDINOTES:
          for (int i = 0; i < SWITCHES; i++)
          {
            if (!(readMSB & (1 << i)))
            {
              if  (!(mask & (1 << i) ))
              {
                MIDI.sendSysEx (6, MMCTransport[i], false);
                usbMIDI.sendSysEx (6, MMCTransport[i]);
                mask |= (1 << i);
              }
            }
            else {
              if ((mask & (1 << i)))
              {
                mask &= ~(1 << i);
              }
            }
          }
          break;
        case MMC:
          for (int i = 0; i < SWITCHES; i++)
          {
            if (!(readMSB & (1 << i)))
            {
              if  (!(mask & (1 << i) ))
              {
                usbMIDI.sendNoteOn (sendSwitchesMIDINOTES [i], 127, channel);
                MIDI.sendNoteOn (sendSwitchesMIDINOTES [i],  127, channel);
                mask |= (1 << i);
              }
            }
            else {
              if ((mask & (1 << i)))
              {
                usbMIDI.sendNoteOff (sendSwitchesMIDINOTES [i], 0, channel);
                MIDI.sendNoteOff (sendSwitchesMIDINOTES [i],  0, channel);
                mask &= ~(1 << i);
              }
            }
          }
          break;
      }
    }
    
    void Rotary::SET_CH (int& channel)
    {
      old_AB <<= 2;                   //remember previous state
      old_AB |= (GPIOB_PDIR & 0x03 );  //add current state
      RotaryRead = ( enc_states[( old_AB & 0x0F )]);
      if (RotaryRead > 0)
      {
        channel++; if (channel > 16) {
          channel = 16;
        }
      }
      else if (RotaryRead < 0)
      {
        channel--; if (channel < 1) {
          channel = 1;
        }
      }
    
    }
    
    void setup()
    {
      //MIDI.begin();
      //Serial.begin (31250);
      for (int i = 0; i < SWITCHES + 2; i++) // + 2 for encoder pin setup
      {
        pinMode(switchesPinTable [i], OUTPUT);
        digitalWrite (switchesPinTable [i], LOW);
        delay (1);
        pinMode(switchesPinTable [i], INPUT_PULLUP );
      }
    
    }
    
    void loop()
    {
      do
      {
        if      (digitalRead (11) == LOW) {
          myMode = MMC;
        }
        else if (digitalRead (12) == LOW) {
          myMode = MIDINOTES;
        }
      }
      while ((myMode != MMC) && (myMode != MIDINOTES));
      Serial.println(String(myMode));
      delay(1000);
      {
        Switches mySwitches;
        Fader myFader;
        Rotary myRotary;
        while (true)
        {
          myRotary.SET_CH (myChannel);
          myFader.RW();
          mySwitches.RW (myMode, myChannel);
          midithru();
        }
      }
    }
    
    void midithru()
    {
      int chnl, d1, d2, dd;
      kMIDIType type;
      if (MIDI.read() &&  MIDI.getType() < SystemExclusive) {
        type = MIDI.getType();
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
        dd = d1 + (d2 << 8);
        chnl = MIDI.getChannel();
        // and then send...
        switch (type) {
          case NoteOn:
            usbMIDI.sendNoteOn(d1, d2, chnl);
            break;
          case NoteOff:
            usbMIDI.sendNoteOff(d1, d2, chnl);
            break;
          case AfterTouchPoly:
            usbMIDI.sendPolyPressure(d1, d2, chnl);
            break;
          case ControlChange:
            usbMIDI.sendControlChange(d1, d2, chnl);
            break;
          case ProgramChange:
            usbMIDI.sendProgramChange(dd, chnl);
            break;
          case AfterTouchChannel:
            usbMIDI.sendAfterTouch(dd, chnl);
            break;
          case PitchBend:
    
            usbMIDI.sendPitchBend(dd, chnl);
            break;
          case SystemExclusive:
            // handle sysex
            break;
          default:
            // F8 et seq.
            break;
        }
      }
      if (usbMIDI.read() &&  usbMIDI.getType() < SystemExclusive) {
        type = (kMIDIType) usbMIDI.getType();
        d1 = usbMIDI.getData1();
        d2 = usbMIDI.getData2();
    
        chnl = usbMIDI.getChannel();
        // and then send...
        MIDI.send(type, d1, d2, chnl);
      }
    }
    Code:
    class Fader
     {
      public:
        void PositionUSBRead ();
        void PositionPinRead ();
        void RW ();
        void MOTOR ();
        void STOP();
        void PINWRITE ();
        
      private:  
        uint16_t hystPinRead;
        uint16_t touchPinRead;
        uint16_t currentPinRead;
        uint8_t sendMSB;
        uint8_t sendLSB;
        bool TOUCHSENT = false;
        bool PINUPDATED = true;
     };
    
    
    class Switches
      {
        public:
          void RW (int, int);
        private:  
        uint16_t readMSB;
        //uint8_t readLSB;
              uint16_t mask = 0;
              uint16_t eleven;  
      };
      
      class Rotary
      {
        public:
         void SET_CH (int&);
        private:  
        int8_t RotaryRead;      
      };
    Last edited by adrian; 01-10-2016 at 08:25 AM. Reason: fixed bad code

  19. #19
    Dude!
    Nice!
    Yes you are correct the Wordclock does not sync transport controls - but I don't think it to be an issue (until I try it and find otherwise).
    I have not needed to sync transport control in the past - as long as it leaves all outputs at the same time, it should "arrive" within a reasonable tolerance.
    I have ordered parts so am awaiting you test results!
    And yeah I think a 16 Position switch pot was the go - am trying to keep it simple. Leds would be a nice touch but maybe in a later revision?! I can easily add those hardware styles rather than use software.
    Restart for button "mode" select is fine - can it be done via a switch? The reset is a good idea - it stops one from accidentally changing it during a show...?
    I am excited to see how you get on - chances of a youtube vid?!
    Last edited by sandysound; 01-09-2016 at 12:15 PM.

  20. #20
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    Im excited to see how you get on too. The fader bit works fine as does the encoder, and so does the MMC stuff (although I have yet to use it on my own sequencer setup (tonight maybe) ... the midi through code looks fine ... the issue is using two uarts in and out simultaneously ... willhave to do some coding ...

    I've never used a 16 position switch! And when I think about it, having the ability to change channel in the middle of a session might not be that great, so maybe it needs to be an initial global setting ....

    By the way, the reset I am talking about is unplugging the thing from power !!! .... If you go down a separate power supply route then you can add a switch!!

    One thing, on the hardware side, I reckon it would be good to think about a pcb ... good for midi connectors, for sure, and from experience, solering lots of wires to the teensy pins and running them to buttons is a pain ...a pcb with organised headers etc seems a better idea .... there is a schematic for midi ins and outs (I have breadboarded it easy enough incl. optocoupler) ... and that brings me back to the merge split thing .... I think I have a midi in circuit breadboarded from an old product, so I will test that code too...

    Don't forget a spare teensy if you are ordering parts .... I'll take some photos ....

    Back to sync ... lets say you start the two transports at the same time (on different machines). You cut from one to the other after 5 minutes, I'm pretty sure that you are only lucky if they are on the same beat .....unless they are synced.
    Last edited by adrian; 01-09-2016 at 08:52 PM.

  21. #21
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    So I tested the MMC code properly.. found a bug and fixed it ... now it works good ....

    I updated the code post above

    Mode select between MMC sysex and Midi notes (or CC evenutally) works fine, and channel select using a rotary works fine, but the lack of feedback makes it difficult to know 'what channel you are on' ... and it is easily bumped .... the rotary I have cost 4 dollars and the detents are not 'accurate' .... I could serial monitor the channel variable, but other than that I would have had no idea what channel. The slider works, spitting out 10 bit midi ... I remembered why capacitive touch is so good on faders.... when you are not touching it you don't need to read values!! great.

    All this works over usb ...the next thing is to do the midi serial interfaces ... Like I said I have the hardware somewhere from another project ...but I have to work out coding for multiple serial ports (could just dispense with the midi library and 'do raw'!! whatever that may mean) ...and the mirroring thru needs to be sorted too ... there is a mirror thru function in the Midi library, just a matter of getting into it.

    So ...all the easy bits are done ... on to a 2 x 2 interface with which to merge etc split etc.

    I was thinking usb in from host, controller stuff, and 2 teensy serial in, all merged to the 2 teensy serial outs...

    For usb out to host, I guess there is no point in mirroring back the usb in from host, so ..... controller stuff and two teensy serial ins, all merged to the usb out to host.

    I found a weird hardware fault with my controller ... BOOO (I'm using pin 13 with the led on it as in input, plus register reads ... might not have got that quite right yet) .... so when I am fixing that (might be sh+t soldering??) I'll fakey up the serialMidi ins and outs,

    I have a couple of spare optocouplers from an old project), and I'll get onto the midi interface code, now that the controller stuff is sorted.

    I actually controlled my DAW using the MMC sysex messages.... the ffwd and rewind functions are weird, but they worked (just a strange implementation) ...punchin, play, pause stop etc ...neat.

    Pictures (or it didn't happen):
    Click image for larger version. 

Name:	WP_20160110_19_52_14_Pro.jpg 
Views:	414 
Size:	111.9 KB 
ID:	6056Click image for larger version. 

Name:	WP_20160110_19_49_40_Pro.jpg 
Views:	462 
Size:	134.8 KB 
ID:	6057
    Last edited by adrian; 01-10-2016 at 05:16 PM. Reason: photos

  22. #22
    Qudos man - You are on to it!
    Yeah a 16 position switch is the go I reckon - and I agree, might not be particularly useful in the middle of a set but you never know!
    I plan to cut the tracer from usb on the teensy and run an independent power supply - Makes things more stable - I don't like to rely on a computer powering my hardware if I can help it!
    MMC can be very useful for simple operations like punch in - or stop ha ha it will be a great feature!
    Have you seen MIDI Show Control? It may be more useful than MMC and also does Clock... Perhaps that will solve the sync issue you are thinking of?
    Really impressed Dude - I'll be in Wellington in Feb - we should Beer.

  23. #23
    Senior Member Pensive's Avatar
    Join Date
    Aug 2014
    Location
    Basingstoke, UK
    Posts
    562
    Quote Originally Posted by adrian View Post
    ... and it is easily bumped .... the rotary I have cost 4 dollars and the detents are not 'accurate' ....
    I feel your pain. What good are detents which are not accurate? They are pointless..

    I bought some adafruit ones, i need to test if they are accurate, but i'm assuming they are on top of this. Will test very soon.....

  24. #24
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    Pensive.... you will never guess where I got the encoder from ..... i'm using a fast register read, so maybe some of that is read instability .... but the one I got is not super clicky like a good old school detented nob.
    Last edited by adrian; 01-11-2016 at 02:15 AM.

  25. #25
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    504
    Sandysound ... deuwde ... When you said "Bro" i thought you might be a kiwi!! coolio. Drop us a line fosho if you are in Wellington.

    I've done some more work on the merge thing ...whew,

    The answer is in v 4.2 of the Midi library .... If that runs on the teensy ok, then no worries about a 2 x 2 midi routing matrix.... if not, I'll have to hack the the current library a bit (looks like v3.2??) ... 3.2 uses a macro to select the serial port, and I don't have any idea how to vary that upon instantiating a new MIDI object ... macros are like pre processor, and I'm out of my depth .... But i reckon I can hack the library.

    v4.2 uses templates which is like oh no for me, but i can paint by numbers so, if 4.2 works on teensy, NO WORRIES..... very simple, and an example even exists already of 2 x 2 merge!!

    rock on.

    I'll have a look at MIDI Show Control ... is that like DMX or something ....I'll look it up ...

    EDIT: Show control is a bit like DMX ...

    but I reckon its a bit mickey mouse ... from wikipaedia:

    The first show to fully utilize the MSC specification was the Magic Kingdom Parade at Walt Disney World's Magic Kingdom in September, 1991.

    snigger
    Last edited by adrian; 01-11-2016 at 02:26 AM. Reason: Show Control

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •