Max/MSP overlapping midi notes


I was looking at this today for dealing with overlapping midi… it prevents repeated notes from silencing ones that should still be playing.

Since I write a lot for mechanical piano, I want the repeated attacks, but only the last note-off:


----------begin_max5_patcher----------
1175.3oc4YstiiZCE92IOEHT+Y5Jaer4RkZk5yQ0pQjfaV1FfHfzNcWsu60X
CYXlgK1AhGhpFIPl3w9b9NW9NG6uuci697m4ktN+hye3rYy22tYi7S0eXSy3
MtoQOe3TTobZtGxSS4YUt6T+VE+4J42SShSbxub8GNWvKEyKpJIO6oB9gJ0l
fCC9DZmim5Ep4gyma9uxtjljchWI2Kb6REUc3KIYGe0xf6rLXlbgHcWojXoX
ku+q+LCZEp+LOqJKJkK+oeuHI5j6KarP3a2YTm4Wl7M47wjOgp+5O1ts9wNM
wK0p5Zp94QT5GSpXWe1q5QFWIZsX0y28FzfQs3IYFqZfT0TZ1TVN7GnkSpM8
pcnQzNjR6nSa2ng8qBsXm5SU+6YtZoccutJy0jlw+GgD7NK52N4TjW4f6UoI
CqzzF0E7qeQ8GyjR8M0jRFDO10ESV.K9.vRkShydScyITkmcHT+R3yyFASXK
FljTGn53tOJ63hBMo7xxni72gMHS8UHLouB.zWvEbv.3BwTbQiXm6qeh3OiS
HpRYPvROEEw1fdJHSQDXBOkNurEDYJ.AHIxzDQw7FKTBBW5PIKgLWxNGc3uL
mLU5tvnRlFZ3X9NPvZGZFJISLWr8bmexXhoV3wWUMkz+YnjMf2CUxlnym4Yw
NnaLaCET0gOZ1FxiEjbLphapGhmrXEF1SEFMJZvVonwkz87haLoJEoz7QKCm
.q95StMP.qhBzBDv9qePn+3he6WMtHsF9DV3zEuhgEKrvRTsh1bNwyl3fJnH
kqA.SePEjI8v.OUa.iRPGrd6LZHl4WnjGBFoDU49dKALR7XS20P35LM8PPXJ
u3XcsMNShkfp.F.BlGV5S6fk9AiUTDF8PUAvg7SmzLtFQm2AP1DWqZiUjmbr
LjFeJVzQCr2MU.dymKi9ad7SBIPH0OEUUUjr+Rk5zd2bEW23xELmRgUZHTVh
OzlZH9PmFhGuoF+Gz18JD6O+lqdG6KAEb3nUr.Obmz1qYl0MgVSorZwwB9Ox
jrFhHZQWBzGd9RsgEJValOf7vx7YXKfZwgQn+ekC6VuTj1T0zfouTD7GPo+x
43dJI6s2+qTWp+9qwpx7KEGZ2k1axw4E0IlWVkjIK2pyjpubxNS5KIww7rt2
gVZR74bAoaiPvD9jB2Pu.rhmCecjym60lpqzVe5MKtzNSYp9F.mTlp8MrnLI
JZvAOgH8FK+8VjzAknLyDIrHfrNcWPPmatr+Qzvqybt1alNfqk8A0ItnN6uI
xTClADYTbKOSuivjqybtZBQGMArdzzjttH6ZvQZ3DFZeQhLUdvO.XZRuIO65
MEpgoCH1WllBm.pUkIecfI65hCd5P0iMkDCUm7jEpZ4kvd+H.qtzSEcmbzbK
jRmbZ3WWFw8Fcw95JS1yhi0AmHr0mWnoj8MdgdH0gMzdW6cG03E1R1u.dgPf
Nocra5YsZw.ra47DOc8BsWzpNlNrcaw.7We0N9F1f9kofUWmXlSh42oWgtil
K9gtGRa.bejVc561twDXsRwZ2vTxcf+BXntMqtbMj9lpdWFoct7A5HSvbbzD
C9w1+CTfnlEM
-----------end_max5_patcher-----------

Max for Live Objects: All Notes Off, Harmonize, Monome

I’ve uploaded a few more Max for Live Objects:
=============================================
allnotesoff: The problem with stuck notes in Max is that you can only send a note-off to notes that Max knows are on. If its the case that a message was dropped, Max ignores any note-offs that might come later. This object was designed for working with a solenoid actuated piano, and, after audio has stopped in Live, turns all the notes on every channel on to velocity 1, then back off-two octaves at a time to prevent drawing too much power.
=============================================
harmonize: This object simply adds parallel notes to incoming MIDI. It comes in handy to thicken a synth sound, or to offset an instruments starting pitch.
=============================================
monome: Supports 64, 128, 256 and routes MIDI to whichever track its on. Multiple instances on multiple tracks may be used simultaneously, lights can show tempo or be turned off completely, and notes may be offset (36 is the default).

Trimpin’s Teeter-totter Moving Speakers (Arduino and ipod)

Trimpin designed a pair of these speakers for the Gurs Zyklus, and when used in performance they were receiving wireless audio. Setting them up this way, we experienced some tiny drops in signal (clicks) even when the wireless transmitters where sitting right next to the units. Since the performance, I’ve been working on embedding an ipod inside them (since the serial communication for ipods is well-documented) and controlling their playback with an arduino and an accelerometer. I didn’t ever have any luck getting an ipod to accept mode 2 commands (which contain controls for volume) so I used mode 4 commands for playback, and a digital potentiometer to fade the volume. The code below is designed for installation, such that some other circuit would trigger the teeter-totters to move, and this separate circuit inside the speakers would play audio only when the speaker is moving, then if the speaker stops, it will fade out, pause the audio, and skip to the next track.

When you are looking at the connections from the Arduino, the serial communication is bright green (only the TX is being used), the SPI communication is orange, and the accelerometer is yellow. The resistors above the accelerometer are converting +5v to +3.3v(10k from +5v, and 15k to ground). The USB communication is on the right (+5v(pin23), D-(pin25), D+(pin27), Ground(pin 15)) and in some pictures there +5v on pin 23 and a 100kohmn resistor from pin 25 to +5v and from pin 27 to ground—this is so the ipod charges off the circuit. In order for the ipod to show up in itunes, these resistors on the data pins must be removed. The first picture is the pinout for the ipodBreakout (from p.405 iPhone Hacks by David Jurick, Adam & Damien Stolarz):

(updated 6/22/11)


/*
  ipod_controller_main
  
  This code controls an ipod embedded in a moving installation, such that sound only plays with the ipod is moving
  TX and RX pins on the Arduino are connected to pins 12 and 13 of PodBreakout
  
  Ipod serial communication only has volume control on mode 2, but since lots of ipods don't accept this mode, playback
  is done through mode 4, and fading volume is handled by a digital potentiometer (DS1801).
  +5v is connected to pin 14
  Pins 1, 4, 7, 10, 11 are connected to ground
  pin 6 LeftIn
  pin 5 LeftOut
  pin 9 RightIn
  pin 8 RightOut
  
  The SPI circuit looks like this:
  Arduino 10--- (SS) DS1801 pin 3
  Arduino 11--- (RX) DS1801 pin 12
  Arduino 13--- (CLK) DS1801 pin 13


  
  the X,Y,Z pins of an accelerometer are connected to analog 3, 4, 5
  
  
  Jeff Aaron Bryant, June 2011
*/


//serial commands for ipod 
byte wake [] ={0xFF, 0x55, 0x03, 0x02, 0x00, 0x04, 0xF7}; //wakeup
byte mode_4 [] = {0xFF, 0x55, 0x03, 0x00, 0x01, 0x04, 0xF8}; //switch to mode 4
byte playlist [] = {0xFF, 0x55, 0x07, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0xCD}; //startlist
byte play_pause [] = {0xFF, 0x55, 0x04, 0x04, 0x00, 0x29, 0x01, 0xCE}; //play_pause
byte skip [] = {0xFF, 0x55, 0x04, 0x04, 0x00, 0x29, 0x03, 0xCC}; //skip
byte back [] = {0xFF, 0x55, 0x04, 0x04, 0x00, 0x29, 0x04, 0xCB}; //back


//sizes
int wakeLength = sizeof(wake);
int mode_4Length = sizeof(mode_4);
int playlistLength =sizeof(playlist);
int play_pauseLength = sizeof(play_pause);
int skipLength = sizeof(skip);
int backLength = sizeof(back);

// include the SPI library
#include <SPI.h>

// set pin 10 as the slave select for the digital pot(DS1801)
int SS = 10;
int mute = 64;
int loud = 63;
int soft = 0;


void setup(){
  Serial.begin(9600);

    //startup ipod
  for (int i=0; i< wakeLength; i++){               //wakeup
                 Serial.print(wake[i],BYTE);
               }
             
               Serial.println("    WAKE");
               
  for (int i=0; i< mode_4Length; i++){          //mode 4
                 Serial.print(mode_4[i],BYTE);
               }
             
               Serial.println("    MODE_4");               


  // set the slaveSelectPin as an output:
  pinMode (SS, OUTPUT);
  
  // initialize SPI:
  SPI.setBitOrder(LSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV128);
  SPI.begin(); 
  delay(10);
  setVolume(mute);

}
        


void loop(){
  accelerometer();
  ipodCommands();
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//accelerometer
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


int x, y, z;
int tilt= 0;  
int lastTilt= 0;
int diff= 0;
int stillness= 8;
int moving= 0;   
int slowing =0;



void accelerometer(){
  if (moving == 1 && slowing ==0){ delay (3000);}          
  if (moving == 1 && slowing ==1){ delay (500);}
  if (moving == 0){ delay (200);}
  
  
  
  x =analogRead(5);
  y =analogRead(4);
  z =analogRead(3);
  Serial.print("   X=");
  Serial.print(x);
  Serial.print(" Y=");
  Serial.print(y);
  Serial.print(" Z=");
  Serial.print(z);
  
  tilt= x + y + z;
  diff= tilt-lastTilt;
  
  
  if (tilt != lastTilt && abs(diff)> 8 && abs(diff)< 400) {  
    Serial.print(" MOVING!!!  ");
    Serial.print(diff);
    moving= 1;
    lastTilt = tilt;
    stillness= 0;
    slowing = 0;
 
    
  }
    else {
      stillness++;
      if (stillness< 7){
      Serial.print(" ...slowing...  ");
      Serial.print(diff);
      slowing = 1;
     
      } else{
          Serial.print(" STOPPED  ");
          Serial.print(diff);
          moving= 0;
          slowing= 0;
          lastTilt=tilt;
        
        }
     
    }

  Serial.println();

}
  
  
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ipodCommands
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int state= 0;
int lastState= 0;
int startup= 0;

void ipodCommands(){
  state=  moving;
 
    
  if (state != lastState){

    switch (state){
      case 1: if (startup ==0){
                  for (int i=0; i< playlistLength; i++){          //start playlist at the beginning
                  Serial.print(playlist[i],BYTE);
               }
             
               Serial.println("    Startlist");  
               for (int i = soft; i <= 10; i++) {            //turn up volume
                   setVolume(i);
                   delay(10);
               }
               for (int i = 10; i <= 63; i++) {            
                   setVolume(i);
                   delay(250);
               }              
               startup++;
               lastState = state;
               break;
                } else{
               
               
               for (int i=0; i< play_pauseLength; i++){      //pause
                   Serial.print(play_pause[i],BYTE);
               }
               Serial.println("    PLAY");
               
               for (int i = soft; i <= 10; i++) {            //turn up volume
                   setVolume(i);
                   delay(10);
               }
               for (int i = 10; i <= 63; i++) {            
                   setVolume(i);
                   delay(250);
               }
               
               lastState= state;
               break;
     
      case 0:  for (int i = loud; i >= 15; i--) {             //turn down volume
                   setVolume(i);
                   delay(10);
               }
               for (int i = 15; i >= 0; i--) {            
                   setVolume(i);
                   delay(50);
               }
   
               
               for (int i=0; i< play_pauseLength; i++){      //pause
                   Serial.print(play_pause[i],BYTE);
               }
               Serial.println("    PAUSE");
               
               
            
               
               delay (1000);
               setVolume(mute);                                  //mute
               
            
               for (int i=0; i< skipLength; i++){             //skip
                   Serial.print(skip[i],BYTE);   
               }
              
               Serial.println("    SKIP");
               
               delay (500);
               lastState= state;
               break;
    }
  }
  } 
  
  
 
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//setVolume
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void setVolume(int level) {
  digitalWrite(SS,HIGH);
  SPI.transfer(level);                                             	    //pot 0
  SPI.transfer(level);                                          	    //pot 1
  digitalWrite(SS,LOW); 
}