MIDI Arp

December 1, 2015 at 11:17 pm (computers, internet, music) (, , , , )

I wanted to do something with MIDI and Arduino.  I’ve just picked up some cheap Arduino Nano Ethernet shields, based on the Microchip ENC28J60, so thought I’d combine the two.  The ENC28J60 and a cheap Arduino Nano makes for a very compact and economical Ethernet ready microcontroller and I have a nice Roland MT-32 Synth module gathering dust that I wanted to try again.

2015-12-01 21.16.05

My initial idea was to use MIDI to trigger sounds based on arp requests received by the Arduino, (hence the name MIDI Arp), but then decided that on my home network arp requests wouldn’t give a lot of variation, so I decided to see if I could trigger on the destination IP address of any packet received.

First I needed the MIDI interface.  I followed the simple circuit and example provided on the Arduino website, but wanted it all self-contained inside a MIDI plug rather than on a breadboard, so I soldered up the 220 resistor inside a 5 pin MIDI DIN plug as follows (MIDI pins are number 1, 4, 2, 5, 3 for some reason):

  • Arduino GND – Brown – MIDI Plug pin 2
  • Arduino 5v – Red – 220 Ohm resistor – MIDI Plug pin 4
  • Arduino TX (Pin 1) – Orange – MIDI Plug pin 5

This was then connected to the Arduino and the MIDI test programme showed that all works fine.

2015-12-01 21.16.212015-12-01 21.19.13

So, to the Ethernet side of things.  The following is an excellent starting place for the ENC28J60 based nano shield:

After reading this, I decided to use the UIPEthernet library as my starting point as I liked the idea of a plug-in replacement to the standard Arduino Ethernet library.  There was two major things to work out – first, how to set the device into some kind of promiscuous mode, assuming it supports it at all; second how to grab the destination IP address from any received packets.

From the ENC28J60 data sheet, the key register that controls the receiver filtering is the Ethernet Receive Filter Control Register – ERXFCON (see section 8 ‘Receive Filters’).  There are a number of modes for filtering and the UIPEthernet library is set up to filter for the unicast address associated with the MAC address configured for the module, for broadcasts, and to use the pattern matching filter to spot arp packets.  It turns out that to set the receiver into promiscuous mode, this register just has to be set to zero.

Now this is where things got lazy.  I just dived into the UIPEthernet library sitting in my Arduino library folder and hacked about. I might tidy this up one day and do it properly.

The low-level driver code can be found in utility/Enc38j60Network.cpp.  In the Enc28J60Network::init function, there is a line that sets up the ERXFCON register:

writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN);

This needs to simply be changed to clear the register:

writeReg(ERXFCON, 0);

Next, how to store the destination IP address.  Again, simplicity ruled this one too.

The high-level interface to the library can be found in UIPEthernet.cpp and UIPEthernet.h.  I added two public functions and two private variables to the UIPEthernetClass class in UIPEthernet.h:

public:
  IPAddress lastSrcIP();
  IPAddress lastDestIP();
private:
  static uip_ipaddr_t uip_lastipsrc;
  static uip_ipaddr_t uip_lastipdest;

Then in the UIPEthernet.Cpp file, added the code to store the last source and destination IP addresses from received packets.

First, define a structure to dig into to the IP header (a bit of a layer violation, but I wasn’t after neat designs really).  Add the following after the definition of ETH_HDR near the top of the file.

#define IPBUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])

Then add two (static) global variables to the file:

uip_ipaddr_t UIPEthernetClass::uip_lastipsrc;
uip_ipaddr_t UIPEthernetClass::uip_lastipdest;

Add two accessor methods to retrieve the last source and destination IP addresses (with appropriate conversion to the Arduino Ethernet friendly IPAddress format):

IPAddress UIPEthernetClass::lastSrcIP()
{
  return ip_addr_uip(uip_lastipsrc);
}
IPAddress UIPEthernetClass::lastDestIP()
{
  return ip_addr_uip(uip_lastipdest);
}

Finally add the code to save the addresses to the UIPEthernetClass::tick() function, on reception of a packet.

          Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE);
          if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP))
            {
              uip_packet = in_packet; //required for upper_layer_checksum of in_packet!
#ifdef UIPETHERNET_DEBUG
              Serial.print(F("readPacket type IP, uip_len: "));
              Serial.println(uip_len);
#endif
              uip_arp_ipin();
              uip_input();
              if (uip_len > 0)
                {
                  uip_arp_out();
                  network_send();
                }
                // Extra code added here
                uip_ipaddr_copy(uip_lastipsrc, IPBUF->srcipaddr);
                uip_ipaddr_copy(uip_lastipdest, IPBUF->destipaddr);
                // Extra code ends
            }

That should be all that is required to expose the destination IP address of any received packet via the UIPEthernet class (ok, breaking compatibility now with the standard Arduino Ethernet library).

The arduino sketch file now consists of the following:

/*
MIDI based on 
 http://www.arduino.cc/en/Tutorial/Midi

UIPEthernet Examples used for rest
NB: Requires hacked UIPEthernet Library!
 */
#include <SPI.h>
#include <UIPEthernet.h>
#include "IPAddress.h"

int lastIP;
int thisIP;

// Initialise note array with whole tone scales in octaves 3 through to 6
// C3 = 36
// C4 = 48
// C5 = 60
// C6 = 72
// C7 = 84
#define NOTES 24
int notes[NOTES] = {
  // C3  D3  E3  F#3 G#3 A#3
     36, 38, 40, 42, 44, 46,
  // C4
     48, 50, 52, 54, 56, 58,
  // C5
     60, 62, 64, 66, 68, 70,
  // C6
     72, 74, 76, 78, 80, 82
};

void setup() {
  //  Set MIDI baud rate:
  Serial.begin(31250);

  // Initialise the uIP and UIPEtherent stacks
  uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
  IPAddress myIP(192,168,0,6);
  
  lastIP = 0;
  thisIP = 0;

  Ethernet.begin(mac,myIP);
  
  // Initialise patch using program change
  // 32 = Synth 1, Fantasy
  midiCmd (0xC0, 32);
}

void loop() {
  Ethernet.maintain();
  IPAddress sip = Ethernet.lastSrcIP();
  IPAddress dip = Ethernet.lastDestIP();
  thisIP = 256*dip[2] + dip[3];
  
  if (thisIP != lastIP)
  {
    lastIP = thisIP;
  
    int note = (thisIP & 0xff) % NOTES;  // Scale to number of notes
    int vel  = ((thisIP & 0xff00) >> 8)/4;        // Scale to val between 0 and 64

    //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
    noteOn(0x90, notes[note], 16+vel);
  }
}

//  plays a MIDI note.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:
void noteOn(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

void midiCmd(int cmd, int val) {
  Serial.write(cmd);
  Serial.write(val);
}

The final byte of the IP address determines which note from the array of notes to play (modulo the number of notes) and the third byte determines the volume to be used, scaled and with a minimum specified.

There is a control message to set the voice on the MT-32 to Synth1-Fantasy as this sounds suitably ambient. There are no note-off messages, so notes are allowed to keep ringing. As the note array defines four octaves of whole tone scales, the running-on notes create quite an interesting effect.

2015-12-01 21.40.12

There seems to be a regular drone set up, which I think is due to the IP address of my PC and router. These two addresses provide a sort of default back-drop of sound to anything else going on.

In order to get anything useful though, it would be no good just using a port on the router, as even the dumbest, cheap modern router will tend to do some MAC level filtering on ports. I had a laptop and the Arduino plugged into an old Netgear En104 4-port Ethernet hub, which has no intelligence (as far as I know) built in – so the Arduino could see everything coming out of the laptop.

The results were quite pleasing. Google has a nice enhanced drone to it. You can really hear the clutter of a site that is pulling in ads from all over the Internet – such as Amazon or YouTube or a news site.

Edited to add:  Here is a short video below showing them being opened.  It’s a bit crude but you get the general idea.

 Maybe next, I’ll see if I can do the same with a Wi-Fi link for the Arduino instead of wired Ethernet.  It might also be worth trying different scales and alternative mappings of notes to addresses.

Kevin

Permalink Leave a Comment

Tenori-on

January 20, 2011 at 10:07 pm (music) (, , , , )

Had the great chance to go and watch Bill Bailey recently as part of his Dandelion Mind tour, at the Wyndhams Theatre in London.  Absolutely fantastic (his cover of Gary Newman’s Cars was just great).

One thing that really caught my attention though, was his use of a curious Japanese digital Instrument.  Its a grid of LEDs and switches.  You touch the switch and that LED will activate a note when it lights up.  Then as the instrument keeps sweeping across the grid, the lit LED will keep playing the note.  Its a really curious effect.

Well, others seem to have thought so too as a Google search for Bill Bailey Japanese instrument reveals all – its a Tenori-on, made by Yamaha – and you can have your own for the cool price of around £600!

Well, Tenori-on or an iPad … hmm.  Still, would be a really neat instrument to have … maybe time to dig out that old R.A.Penfold book of MIDI projects …

Kevin.

 

Permalink 1 Comment

How Many Notes in Mozart’s Requiem?

December 7, 2009 at 9:14 pm (computers, music) (, , , )

When some bright spark suggests a ‘how many notes in the score’ competition, I thought what piece could be better than Mozart’s Requiem?  4 choral parts, orchestra, I could have the vocal score on hand for reference and estimating, etc, etc.  One problem – just how many notes are then in Mozart’s Requiem?

Well, when Google failed me, and I counted how many notes in one bar of the score (more than 40), I decided extrapolating from a sample of bars to the whole piece was impractical, I thought I’d look for help of a more technical kind.

Googling eventually found me a site with the complete Requiem as a series of MIDI files.  Great – thought I’d just load them into a sequencer and that would do the job.  But no, the sequencer’s I have and tried didn’t have a ‘total notes’ statistic anywhere that I could find.

Well, this is the point where the geek takes over … MIDI is just a series of instructions ‘turn this note on, turn this note off, change to violin here’ and so on.  So, armed with the MIDI files, I just have to find something that would count the ‘note on’ events in each track in each file.  Well, after a bit of playing around, and looking for help, I found the MIDI perl library.  This enabled the following script (stored here in case someone else has the same whimsical, insane idea and needs to do something similar).

#!/usr/bin/perl
use MIDI;

my $opus = MIDI::Opus->new({'from_file' => $ARGV[0]});
my $notes = 0;
my @tracks = $opus->tracks();
foreach my $track (@tracks)
{
   foreach my $event ($track->events())
   {
      if ($event->[0] eq 'note_on')
      {
         $notes++;
      }
   }
}
print "Note count: $notes\n";

And the number of notes? Ah, well that would be telling … lets just say that whoever said Mozart used ‘too many notes’ really just didn’t know what they were talking about …

Kevin.

Permalink 4 Comments

Online Karaoke

January 2, 2008 at 10:23 pm (interesting, internet, music) (, , , )

Whilst searching for some lyrics online, I came across this site – Ronan’s Online Karaoke. It has a wide selection of tracks with lyrics and simple accompaniments.  What was interesting to me, is that the tracks are mostly in MIDI format – which means you can load them into your favourite sequencer and start playing around with them – even seeing notation.  Cool.

Kevin.

Permalink Leave a Comment