Simple class for getting Midi natively with Processing

So I started learning a little bit of Processing and as a first exercise, I wanted to do a visualization of the midi data from one of my songs. The most common midi library used with processing was not able to detect midi inputs on my mac, so I had to write my own class. I’m putting the code in here hoping that it can help someone else.

Oh, and some of the code was taken from here:
http://www.jsresources.org/examples/MidiInDump.html

import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;

/*** MyMidi Class implementation ***/

class MyMidi implements Receiver {
  public int[] lastNoteOnByChannels = new int[16];
  public MyMidi()
  {

  }

  public long seByteCount = 0;
	public long smByteCount = 0;
	public long seCount = 0;
	public long smCount = 0;

	private final String[]		sm_astrKeyNames = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};

	private final String[]		sm_astrKeySignatures = {"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#"};
	private  final String[]		SYSTEM_MESSAGE_TEXT =
	{
		"System Exclusive (should not be in ShortMessage!)",
		"MTC Quarter Frame: ",
		"Song Position: ",
		"Song Select: ",
		"Undefined",
		"Undefined",
		"Tune Request",
		"End of SysEx (should not be in ShortMessage!)",
		"Timing clock",
		"Undefined",
		"Start",
		"Continue",
		"Stop",
		"Undefined",
		"Active Sensing",
		"System Reset"
	};

	private final String[]		QUARTER_FRAME_MESSAGE_TEXT =
	{
		"frame count LS: ",
		"frame count MS: ",
		"seconds count LS: ",
		"seconds count MS: ",
		"minutes count LS: ",
		"minutes count MS: ",
		"hours count LS: ",
		"hours count MS: "
	};

	private  final String[]		FRAME_TYPE_TEXT =
	{
		"24 frames/second",
		"25 frames/second",
		"30 frames/second (drop)",
		"30 frames/second (non-drop)",
	};
private char hexDigits[] =
	   {'0', '1', '2', '3',
	    '4', '5', '6', '7',
	    '8', '9', 'A', 'B',
	    'C', 'D', 'E', 'F'};

  public String getKeyName(int nKeyNumber)
	{
		if (nKeyNumber > 127)
		{
			return "illegal value";
		}
		else
		{
			int	nNote = nKeyNumber % 12;
			int	nOctave = nKeyNumber / 12;
			return sm_astrKeyNames[nNote] + (nOctave - 1);
		}
	}

	public int get14bitValue(int nLowerPart, int nHigherPart)
	{
		return (nLowerPart & 0x7F) | ((nHigherPart & 0x7F) << 7);
	}

        private void noteOn(int note, int velocity, int channel){
            lastNoteOnByChannels[channel] = note;
            System.out.println(note + " " + velocity);
        }

  public String decodeMessage(ShortMessage message)
	{
		String	strMessage = null;
		switch (message.getCommand())
		{
		case 0x80:
			strMessage = "note Off " + getKeyName(message.getData1()) + " velocity: " + message.getData2();
			break;

		case 0x90:
			strMessage = "note On " + getKeyName(message.getData1()) + " velocity: " + message.getData2();
                        noteOn(message.getData1(), message.getData2(), message.getChannel());
			break;

		case 0xa0:
			strMessage = "polyphonic key pressure " + getKeyName(message.getData1()) + " pressure: " + message.getData2();
			break;

		case 0xb0:
			strMessage = "control change " + message.getData1() + " value: " + message.getData2();
			break;

		case 0xc0:
			strMessage = "program change " + message.getData1();
			break;

		case 0xd0:
			strMessage = "key pressure " + getKeyName(message.getData1()) + " pressure: " + message.getData2();
			break;

		case 0xe0:
			strMessage = "pitch wheel change " + get14bitValue(message.getData1(), message.getData2());
			break;

		case 0xF0:
			strMessage = SYSTEM_MESSAGE_TEXT[message.getChannel()];
			switch (message.getChannel())
			{
			case 0x1:
				int	nQType = (message.getData1() & 0x70) >> 4;
				int	nQData = message.getData1() & 0×0F;
				if (nQType == 7)
				{
					nQData = nQData & 0×1;
				}
				strMessage += QUARTER_FRAME_MESSAGE_TEXT[nQType] + nQData;
				if (nQType == 7)
				{
					int	nFrameType = (message.getData1() & 0×06) >> 1;
					strMessage += “, frame type: ” + FRAME_TYPE_TEXT[nFrameType];
				}
				break;

			case 0×2:
				strMessage += get14bitValue(message.getData1(), message.getData2());
				break;

			case 0×3:
				strMessage += message.getData1();
				break;
			}
			break;

		default:
			strMessage = “unknown message: status = ” + message.getStatus() + “, byte1 = ” + message.getData1() + “, byte2 = ” + message.getData2();
			break;
		}
		if (message.getCommand() != 0xF0)
		{
			int	nChannel = message.getChannel() + 1;
			String	strChannel = “channel ” + nChannel + “: “;
			strMessage = strChannel + strMessage;
		}
		smCount++;
		smByteCount+=message.getLength();
		return “[”+getHexString(message)+”] “+strMessage;
	}
private String intToHex(int i) {
		return “”+hexDigits[(i & 0xF0) >> 4]
		         +hexDigits[i & 0×0F];
	}

public String getHexString(ShortMessage sm)
	{
		// bug in J2SDK 1.4.1
		// return getHexString(sm.getMessage());
		int status = sm.getStatus();
		String res = intToHex(sm.getStatus());
		// if one-byte message, return
		switch (status) {
			case 0xF6:			// Tune Request
			case 0xF7:			// EOX
	    		// System real-time messages
			case 0xF8:			// Timing Clock
			case 0xF9:			// Undefined
			case 0xFA:			// Start
			case 0xFB:			// Continue
			case 0xFC:			// Stop
			case 0xFD:			// Undefined
			case 0xFE:			// Active Sensing
			case 0xFF: return res;
		}
		res += ‘ ‘+intToHex(sm.getData1());
		// if 2-byte message, return
		switch (status) {
			case 0xF1:			// MTC Quarter Frame
			case 0xF3:			// Song Select
					return res;
		}
		switch (sm.getCommand()) {
			case 0xC0:
			case 0xD0:
					return res;
		}
		// 3-byte messages left
		res += ‘ ‘+intToHex(sm.getData2());
		return res;
	}

public String getHexString(byte[] aByte)
	{
		StringBuffer	sbuf = new StringBuffer(aByte.length * 3 + 2);
		for (int i = 0; i < aByte.length; i++)
		{
			sbuf.append(' ');
			sbuf.append(hexDigits[(aByte[i] & 0xF0) >> 4]);
			sbuf.append(hexDigits[aByte[i] & 0×0F]);
			/*byte	bhigh = (byte) ((aByte[i] &  0xf0) >> 4);
			sbuf.append((char) (bhigh > 9 ? bhigh + ‘A’ - 10: bhigh + ‘0′));
			byte	blow = (byte) (aByte[i] & 0×0f);
			sbuf.append((char) (blow > 9 ? blow + ‘A’ - 10: blow + ‘0′));*/
		}
		return new String(sbuf);
	}

  public void send(MidiMessage message, long lTimeStamp){
    //System.out.println(”Message received”);
    String	strMessage = null;
		if (message instanceof ShortMessage)
		{
			strMessage = decodeMessage((ShortMessage) message);
                        System.out.println(strMessage);
		}

  }

  public void close(){
  }

  public void printMidiDevices() {
    MidiDevice.Info[] aInfos = MidiSystem.getMidiDeviceInfo();
    for (int i = 0; i < aInfos.length; i++) {
    try {
     MidiDevice device = MidiSystem.getMidiDevice(aInfos[i]);
       boolean bAllowsInput = (device.getMaxTransmitters() != 0);
       boolean bAllowsOutput = (device.getMaxReceivers() != 0);
       System.out.println("" + i + "  "
           + (bAllowsInput ? "IN " : "   ")
           + (bAllowsOutput ? "OUT " : "    ")
           + aInfos[i].getName() + ", " + aInfos[i].getVendor()
           + ", " + aInfos[i].getVersion() + ", "
           + aInfos[i].getDescription());
    }
    catch (MidiUnavailableException e) {
       // device is obviously not available...
       System.err.println(e);
    }
  } 

    }
    MidiDevice inputDevice = null;
    Transmitter t = null;
    Receiver r = null;
    public void openForInput(int idx){
        try{
          MidiDevice.Info[] aInfos = MidiSystem.getMidiDeviceInfo();
          inputDevice = MidiSystem.getMidiDevice(aInfos[idx]);
          inputDevice.open();
          t = inputDevice.getTransmitter();
          t.setReceiver(this);
        }catch(MidiUnavailableException e){
          System.err.println(e);

        }
    }

}
/* end of MyMidi Class */

MyMidi myMidi;

void setup(){
  size(480,360);
  myMidi = new MyMidi();
  myMidi.printMidiDevices();
  // Set the index of the device to open for input according
  // to your system
  myMidi.openForInput(0);
}

void draw()
{
  background(255);
  if(myMidi.lastNoteOnByChannels[0] != 0){
    translate(width/2, height/2);
    rotate(myMidi.lastNoteOnByChannels[0]);
    rect(-10,-10,20,20);
  }
}

Uncategorized

Comments (0)

Permalink

FAWM 2008 - My entry so far

FAWM (February Album Writing Month) is a yearly community challenge to write 14 songs (a complete album) in February. 14 songs, that’s a song every 2 days, at least. This is the perfect excuse for me to produce stuff, no matter if it is good or bad. Here’s what I’ve done so far (this list will get update as February goes along.)



Next%20Door%20Ninja
Quantcast

Also, here is my myspace page http://myspace.com/nextdoorninja

Original Music
Music
Web

Comments (0)

Permalink

The importance of having an open relationship with your IDE.

IDE’s: you either love them or you hate them, but there is no question about it: they do make a developer’s life easier. Developers that are really good with such a tool can seriously count on them being an extension of their body, an invisible limb, a partner. They physically hurt when the IDE crashes, they clean it, take care of it. But is this good or bad? Are developers leaving part of their brain on software? I think so. The worst part if they leave it there for too long they might not get it back.
Technology changes way too rapidly for programmers to develop such a strong relationship with a tool like this. Is this relationship beneficial? Absolutely, but you have to be ready to dump your software partner at a time when you least expect it. I know of stories where broken software hearts means having to change jobs.
The beauty of this relationship is that cheating on your IDE does actually benefit you as a developer. Besides, the IDE won’t get mad at you, even if it finds out. So my fellow developers, free yourselves. Play with other IDE’s, languages, techonologies and don’t be afraid. Times change rapidly, embrace change.

Programming

Comments (0)

Permalink

That1Guy, taking the one man band to the next level

I just came back from another great High Sierra and saw some excellent bands, but the ones they always stick up are the ones that do something unique. This year, the uniqueness prize (i.e. ultra-super-freak) went to That1Guy.

His main instrument is a home-made invention he calls “The Magic Pipe”, an industrial looking steel pipe contraption that has two ends, where he either plays bass or lead (and he is pretty damn good at both). The 2 strings have an amazingly natural envelope filter like sound, which comes out just as if he was playing a synth bass.

Apart from the strings on the pipe, he has an assortment of midi sensors. There are 13 of them alone on the Magic Pipe and who knows how many more on bass-drum-pedal-driven-cowbells and a single snare that gets no compassion during the live show.

His music is a refreshing mix between crazy funk and industrial, that can easily drive a crowd insane. And, the lyrics are a perfect extension of his instruments: definitely nuts. Don’t believe me? check out this video.

Music
Toys

Comments (0)

Permalink

Playing JawBreaker with your friends’ head

I wrote this little game a couple of months ago and get a kick out of it every I see the main page. It is a clone of the JawBreaker game that comes with PocketPC, but I changed the “balls” with some friend’s heads. If anyone wants their own custom version (with the heads of _your_ friends instead) drop me a line.

You can click on the images to download the game.

Programming
Toys

Comments (0)

Permalink

Do you want to see what your phone number spells?

Do you ever wonder what your phone number spells?… well now you can easily figure it out with this simple script I wrote some time ago:

http://mrbook.org/spellmyphone

If you find out your phone number deserves a super-cool award, just post it on the comments, then … just let the calls begin!! :)

Programming
Tools
Web

Comments (0)

Permalink

Crazy weekend gigs

Last friday and saturday were two of the craziest gigs we ever had with the clowns. Not because everyone was going crazy, but because of the events prior to the actual shows.

On friday, us and two more bands were supposed to play at the Zephyr, but right when we got to the place, we got word that for different reasons, the two other bands had cancelled. It was ok for us though, since Kris just got new congas and we could use the extra setup time that this would take. The show turned out ok though, even Laura, from Tripping Budhas joined us for a little conga jam on “Excuse Me” which was pretty fun. Also Carlos from Gusano stepped up for some percussion duties, living up to his super-latin roots.

Then, on Saturday at Walden’s, about an hour before we were supposed to start, we heard from Kris that he had “lost” his truck (don’t ask). Even more dramatic was the fact that all his instruments were on it including the brand new congas. We run through different scenarios of what we could do: Maybe borrow some props from the previous band or just go for with just guitar, bass and drums, which taking into account our sound, is a really scary thought. Luckily, Kris “found” the truck, and showed up at the place just as the band before us started leaving.

All in all though, good shows and good times.

Uncategorized
Original Music
Music

Comments (0)

Permalink

who needs a surf board…

PICT0472

Maybe not me on that picture, but this crazy guy could probably use one.

Uncategorized

Comments (0)

Permalink

Brazil

Brazil is a country where people and places seemed so real. I might have not understood the language that well, but everything was always solved with a thumbs up and a tudo bem. I can’t wait to go back and learn some more portuguese, learn more about brazilian percussions and have more skol.

Here is a video I took at the sambodromo on 2/18/2007. In between samba schools, this guy totally stole the show. He had the crowds going nuts, everyone (including us) was loving it.

Here is a video of one of the bands that I discovered while I was there. The rest of their music is also pretty powerful.

Travel

Comments (0)

Permalink

Rio is a crazy city

Even if carnaval hasn’t yet started.
PICT0047 PICT0043 PICT0040 PICT0037

Travel

Comments (0)

Permalink