AK47m Project Part 2 (Reading MIDI into Raspberry Pi)

THE ORIGINAL POST HAS BEEN SUPERCEDED. I Have left it at the end in small print..

 

The PIC MIDI interface allows me to connect to a MIDI keyboard and also provide MIDI test messages using a keypad. The output of the UART was connected to the RXD input on the PI Zero. The next part had the following goals :

  1. Configure PI Zero to accept MIDI messages
  2. Provide simple test scripts to check data is arriving in tact.
  3. Install Lazarus and Free pascal to develop PASCAL programs on the PI.
  4. Write a simple PASCAL test program to receive MIDI messages and display them.

 

There is some trickery involved in getting the PI to accept MIDI input, there is a lot of old stuff relating to this out on tinternet. Hopefully this is THE CORRECT WAY TO DO IT !!!

The trickery involves setting up the UART connected to the pin header, moving a UART to the bluetooth hardware and altering the UART master clock so that a legal baud rate of 38400 actually turns out to be 31250. Once the configuration is done, the UART is accessible as /dev/serial0 and needs to be configured with a baud rate of 38400.

**NOTE** ttyAMA0 has now been dropped and the device is now called /dev/serial0 . So I’ve updated these so that my software is compatible with the PI Zero W and the PI B+.

There was also a stupid gotcha that confused me. If a command line terminal (tty) is configured, it will try to use the same port and cause absolute misery. So the answer is to DISABLE THE COMMAND LINE TERMINAL USING RASPI-CONFIG.

Step 1:

Ensure the PI ZERO W operating system is latest and up to date.

Step 2:

Edit the file /boot/config.txt.

e.g. sudo leafpad /boot/config.txt

Add the following lines at the end.

enable_uart = 1
dtoverlay = pi3-miniuart-bt
dtoverlay = midi-uart0

Step 3:

Ensure the command line terminal is not attached to UART.

Run the configuration utility:

sudo raspi-config

Select option 5 “Interfacing Options”, then select option P6 “Serial”. Answer “No” to “do you want to have a login shell on the serial port ?”

Step 4:

Check the comms. First install the Minicom software.

sudo apt-get install minicom

Then run the Minicomm terminal.

minicom -b 38400 -H -D /dev/ttyAMA0

This will show any received data in hexadecimal format on the screen. Simply press the keypad to send a MIDI message and check it is displayed correctly. At this point the PI is ready to accept MIDI data. The next steps deal with developing programs to access the port.

Step 5:

Install Free pascal and Lazarus IDE.

sudo apt-get install fpc
sudo apt-get install lazarus

The Lazarus IDE is then available from the “Programming” option on the main applications menu from the desktop. Create a new project and check that a hello world program can be written.

Step 6:

We are now in a position to write a MIDI test program in PASCAL. I am using the native Lazarus serial device interface routines. I wrote a Lazarus console application to test the port and the code is as follows. The test program prints out received data as hex to the console window until a key is pressed.

program MidiTest;

{$mode objfpc}{$H+}
uses
  Classes,
  SysUtils,
  Serial,
  Crt;

var

  serialPortHandle: TSerialHandle;
  count: integer;
  receiveBuffer: array [1..255] of byte;


begin

  try
    writeln('MIDI test program');

    serialPortHandle := SerOpen('/dev/serial0');
    SerSetParams(serialPortHandle, 38400, 8, NoneParity, 1, []);

    writeln;
    writeln;
    writeln('Port opened. Press key to exit');

    while True do
    begin
      try

        count := SerReadTimeout(serialPortHandle, receiveBuffer, 1);

        if (count > 0) then
            Write(intToHex(byte(receiveBuffer[1]), 2) + ' ');

        if keyPressed then
          break;

      except
        break;
      end;
    end;


  finally
     serClose(serialPortHandle);
  end;

end.

 

 

 

 

SUPERCEDED……………..

The PIC MIDI interface allows me to connect to a MIDI keyboard and also provide MIDI test messages using a keypad. The output of the UART was connected to the RXD input on the PI Zero. The next part had the following goals :
  1. Configure PI Zero to accept MIDI messages
  2. Provide simple test scripts to check data is arriving in tact.
  3. Install Lazarus and Free pascal to develop PASCAL programs on the PI.
  4. Write a simple PASCAL test program to receive MIDI messages and display them.

There is some trickery involved in getting the PI to accept MIDI input, there is a lot of old stuff relating to this out on tinternet. Hopefully this is THE CORRECT WAY TO DO IT !!!

The trickery involves setting up the UART connected to the pin header, moving a UART to the bluetooth hardware and altering the UART master clock so that a legal baud rate of 38400 actually turns out to be 31250. Once the configuration is done, the UART is accessible as /dev/ttyAMA0 and needs to be configured with a baud rate of 38400.

**NOTE** ttyAMA0 has now been dropped and the device is now called /dev/serial0 . So I’ve updated these so that my software is compatible with the PI Zero W and the PI B+.

There was also a stupid gotcha that confused me. If a command line terminal (tty) is configured, it will try to use the same port and cause absolute misery. So the answer is to DISABLE THE COMMAND LINE TERMINAL USING RASPI-CONFIG.

Step 1:

Ensure the PI ZERO W operating system is latest and up to date.

Step 2:

Edit the file /boot/config.txt.

e.g. sudo leafpad /boot/config.txt

Add the following lines at the end.

enable_uart = 1 dtoverlay = pi3-miniuart-bt dtoverlay = midi-uart0

Step 3:

Ensure the command line terminal is not attached to UART.

Run the configuration utility:

sudo raspi-config

Select option 5 “Interfacing Options”, then select option P6 “Serial”. Answer “No” to “do you want to have a login shell on the serial port ?”

Step 4:

Check the comms. First install the Minicom software.

sudo apt-get install minicom

Then run the Minicomm terminal.

minicom -b 38400 -H -D /dev/ttyAMA0

This will show any received data in hexadecimal format on the screen. Simply press the keypad to send a MIDI message and check it is displayed correctly. At this point the PI is ready to accept MIDI data. The next steps deal with developing programs to access the port.

Step 5:

We install Python and run a Python script to do the same as Step 4. There is method in this madness.

Firstly install Python and its serial library:

sudo apt-get install python sudo apt-get install python-serial

Edit a file e.g. /home/pi/midi-test and copy the following script:

#!/usr/bin/env python import serial print ‘midi test’ ser = serial.Serial(‘/dev/ttyAMA0’, baudrate=38400, timeout=10) while True: data = ord(ser.read(1)) # read a byte print (str(data) + ‘ ‘)

Make the script executable

chmod a+x midi-test

Run the script and then send MIDI messages.

./midi-test

It should print out the decimal values of each byte and timeout if nothing is received after 10 seconds.

Step 6:

Install Free pascal and Lazarus IDE.

sudo apt-get install fpc sudo apt-get install lazarus

The Lazarus IDE is then available from the “Programming” option on the main applications menu from the desktop. Create a new project and check that a hello world program can be written.

Step 7:

We are now in a position to write a MIDI test program in PASCAL. I downloaded the “Synapse” communications library from http://www.ararat.cz/synapse/doku.php/download

and copied the source to a suitable folder searchable by Lazarus. This library is compatible with Windows and Unix. I only needed the serial comms part. I may have been the first person to try this library on a PI Zero and encountered some problems.

There are some demo programs. I converted the Delphi modem demo program Synapse/source/demo/modem/ModemDemo.dpr to a Lazarus project and compiled it. There was a compile error in the unit synaser.pas because of some undefined high baud rates for the UNIX build. I hacked this to work as below:

const {$IFDEF UNIX} {$IFDEF DARWIN} MaxRates = 18; //MAC {$ELSE} MaxRates = 30-11; //UNIX {$ENDIF} {$ELSE} MaxRates = 19; //WIN {$ENDIF} Rates: array[0..MaxRates, 0..1] of cardinal = ( (0, B0), (50, B50), (75, B75), (110, B110), (134, B134), (150, B150), (200, B200), (300, B300), (600, B600), (1200, B1200), (1800, B1800), (2400, B2400), (4800, B4800), (9600, B9600), (19200, B19200), (38400, B38400), (57600, B57600), (115200, B115200), (230400, B230400) {$IFNDEF DARWIN} ,(460800, B460800) {$IFDEF UNIX} { ,(500000, B500000), (576000, B576000), (921600, B921600), (1000000, B1000000), (1152000, B1152000), (1500000, B1500000), (2000000, B2000000), (2500000, B2500000), (3000000, B3000000), (3500000, B3500000), (4000000, B4000000) } {$ENDIF} {$ENDIF} ); {$ENDIF}

The second problem encountered was that the port configuration was not set correctly. The Synapse call to do this should be:

ser.Config(38400,8,’N’,1,false,false);

but the port is not set correctly. The work around to this is to currently call a Python script to just open the port. The configuration settings seem to persist if the ser.Config call is ignored. The python script “hack-uart-params” is as follows. Note that a baudrate of 38400 is really 31250 due to trickery :

#!/usr/bin/env python import serial print ‘hacking serial port’ ser = serial.Serial(‘/dev/ttyAMA0’, baudrate=38400, timeout=1)

I wrote a Lazarus console application to test the port and the code is as follows. The test program prints out received data as hex to the console windo until a key is pressed.

program MidiTest; {$mode objfpc}{$H+} uses Classes, SysUtils, synaser, Unix, Crt; var ser:TBlockSerial; i, count : integer; buf : AnsiString; begin ser := TBlockSerial.Create; ser.RaiseExcept := True; try writeln (‘MIDI test program’); writeln (‘Removing Lock’); writeln; fpSystem (‘rm /var/lock/LCK..ttyAMA0’); writeln; ser.Connect(‘/dev/ttyAMA0’); writeln(‘Setting port config’); writeln; //ser.Config(38400,8,’N’,1,false,false); fpSystem (‘./hack-uart-params’); writeln; writeln; writeln (‘Port opened. Press key to exit’); while true do begin try count := ser.WaitingData; if (count > 0) then begin buf := ser.RecvBufferStr(count,1000); for i:= 1 to count do write ( intToHex(byte(buf[i]),2) + ‘ ‘); end; if keyPressed then break; except break ; end; end; finally ser.free; end; end.

Leave a Reply