AK47M project part 9 (PCB completed & updates)

I have received a set of PCBs and have built the first AK47M prototype. Everything seems to be working and I am currently working on an enclosure for it.

This shows the PCB populated with components:-

 

The next photo shows the addition of the two synthesizer modules:-

 

The final photo shows the addition of the PICs, the Raspberry PI Zero W and the wiring to additional components. It is ready to be put in the enclosure:-

 

There are a few tweaks required for the PIC firmware. I have done a lot more changes to the LIVE software running on the PI.

The “Band in the Bag ™” first cut of software is ready. I can create a chord sheet using an interactive editor using either the QWERTY keyboard or the MIDI keyboard. It handles repeats and variation selections. When a BIAB score is created and attached to a performance, it will play when the zero key is pressed. There is a tap intro for one bar before the sequence is played. The sequence can play to completion or repeat multiple number of times. This will be great to busk along with my Sax.

The LIVE software is now packaged as two versions, one for the Windows PC that interfaces to any attached MIDI device and one for the Raspberry PI that interfaces to the AK47M.

The hardware is modular so that certain functions can be added or dropped depending on requirement.

i.e.

  1. Either one or both Synth modules can be dropped and an external MIDI device used instead.
  2. The LCD display can be dropped and a HDMI device or Android tablet can be used instead.
  3. The Solo Parts keyboard function can be dropped.
  4. The Fluid softsynth can be installed on the PI to do drums / bass arrangements only.
  5. The PCB can be connected to a keypad with a single PIC and used as the self-powered MIDI-Mate for connecting to a BK7M.

I am now using PIC 16F628A chips that are cheaper and have a more accurate internal oscillator. So I can also drop the resonators.

I am now working on the display of sheet music and lyric sheets. The intention is to synchronise the selection of a music/lyric sheet with the performance selection. I am on the look out for a portable HDMI monitor that I can hook up to the PI.

 

AK47M project part 8 (Connection to tablet)

I have investigated a simple way of connecting my Android tablet to the AK47M system in order to view and edit configurations.

The general method is to set up a WiFi hotspot on the Android tablet and connect to it from the PI Zero W. This WiFi network can be independent of the Internet and allows for a connection anywhere even on gigs.

Once a WiFi connection is established then a VNC client can be run on the tablet that shows the PI desktop and allows it to be controlled by screen touches or using a mouse attached to the tablet by USB.

When the connection is initially established it is necessary to obtain the IP address of the PI to configure the VNC client. Fortunately, there is an easy way by using a Hotspot manager app as it shows the addresses of attached devices.

I downloaded and installed two free apps from the Android Playstore …..

Hotspot manager allows you to configure a hotspot on the tablet with a WiFi password and switch it on or off as an when required. Running a hotspot does seem to drain the battery more than normal operation. It also lists any connected devices and their addresses.

 

VNC Client Free is a simple to use app to do the remote desktop connection to the PI Zero W. There is also a client produced by RealVNC that works well.

The IP addresses assigned by the tablet seem to be persistent, so once everything is configured it re-connects with no bother when the system is powered up.

My AK47M application running on the PI Zero W is called “AK47 LIVE” and is configured to run on boot up. This application integrates with the AK47M system and allows performances to be edited for the solo parts and the styles. It also runs the arranger that plays a style file and reacts to variation selections and chords played. There is also an additional tab for a “Band in the bag” which will allow the input of chord and variation sequences for a performance configuration, this is work in progress.

 

I have completed the AK47M PCB design and it is ready to be manufactured in China. (About £1.50 per PCB.)

 

AK47M project part 7 (Adding MIDI synthesiser and PCB generation)

I have investigated the possibility of running “FluidSynth” on a Raspberry PI in order to generate sounds from MIDI input. I have decided that a single PI is unable to handle 8 channels of MIDI generated from the Arranger software. It can only hack about two channels reliably with the sample rate halved from 41000 Hz and the latency is pretty bad at around 40 mS. Running several PIs in parallel is not really cost-effective either. This is unfortunate as the FluidSynth would be ideal for the application and could provide a lot of tailor made sounds. I will re-visit this when and if a more powerful cheap CPU card is mass produced.

I hooked up a PI zero running my Arranger software to my MIDI keyboard and this handles the MIDI generation successfully so I decided to look around for MIDI sound generation alternatives. I found a good alternative in the S2 synthesizer. This is produced by https://www.serdashop.com/waveblaster and it is a daughter board designed to plug into a PC sound blaster card. It is built around a Yamaha sound generation SAM2695 chip. I have successfully hooked this up to a PI Zero and generated sound from the Arranger software. The electrical connection to the device is very simple. One thing to watch out for is that the device reset line needs to be brought up to 5v on start up. They cost about £35 and I need two for my project, so I have bust my budget !!

 

 

I looked into the possibility of producing a printed circuit board (PCB) for my project as the separate components are on vero board and it looks a bit shoddy.

I was amazed at how cheap the production of PCBs is, especially if ordered from chinese shops and the large range of free CAD tools available for the PC. I tried out several of the free CAD packages and I decided that DipTrace https://diptrace.com/ was the easiest to use. It has a schematic editor for the circuit design. This can be transferred to a PCB design tool and there is a good auto routing tool available to optimise the PCB layout.

The design consists broadly of the following:-

  • Pi Zero W to run Arranger software and generate MIDI from style files and system configuration mesages. Also runs performance editor tools.
  • PIC to handle keypad, keyboard MIDI input and chord finder.
  • PIC to handle LCD display and accept configuration messages.
  • PIC to handle solo keyboard parts and accept configuration messages.
  • S2 synthesiser to generate 8 channels from Arranger software.
  • S2 synthesiser to generate solo keyboard sounds.

I have firmed up on the hardware so I am now going to concentrate on the software running on the PI. I am considering adding these features :-

  • A “Band in the Box” type of interface which was lacking from the BK7M. Here I am able to enter a chord sequence using standard notation for a style and let the software play the arrangement without having to play chords at the keyboard.
  • A display of a PDF file for a performance. This can contain a chord sheet, sheet music, words etc.
  • I can control the PI from an Android tablet using VNC virtual terminal software while it is connected to my WiFi network. It would be cool to be able to set up a local link from my tablet to the PI Zero
  • Some kind of “looping” software for live performance.

AK47m Project Part 6 (Adding a LCD display to the system)

I have added a LCD two line display to my project. I obtained a two line by 16 characters wide that costs about £6. LCD displays generally have a standard interface based on the Hitachi model. It is easily hooked up to a 16F628 PIC. There are 4 data lines, 2 control lines and 5v power lines. Only 4 of the 8 data lines are used and the LCD is programmed using 4 bit nibbles of data. The LCD display that I obtained has the pin out arranged as two lines of solder connections. The usual ones have a single line. The solder pad with a square surround is pin 1 and the pins are numbered from left to right so the odd numbered pins are on the left and the even numbered pins are on the right.

Note that the LCD is powered from the 5v supply but the control and data lines are driven to +3.5v from the PIC. The 5v supply is taken from the USB connection to the power supply. The 3.5v supply for the PIC is derived from the Raspberry PI.

The excellent MikroElectronika pascal compiler has a library to drive the LCD and a simple means to configure the PIC IO pins used to connect to the display. The LCD display connections to the PIC are as follows:-

Pin1 - Ground

Pin2 - +5v

Pin3 - contrast (grounded)

Pin4 - RS (PIC A1)

Pin5 - RW (grounded)

Pin6 - En (PIC A0)

Pin7-10 - High Data (grounded)

Pin11-14 - Low Data (PIC B4-B7)

Pin15 -Backlight LED (+5v)

Pin16 -Backlight LED (grounded)

 

The PASCAL program requires a declaration of the pin out as follows:

var LCD_RS : sbit at RA1_bit;
var LCD_EN : sbit at RA0_bit;
var LCD_D4 : sbit at RB4_bit;
var LCD_D5 : sbit at RB5_bit;
var LCD_D6 : sbit at RB6_bit;
var LCD_D7 : sbit at RB7_bit;

var LCD_RS_Direction : sbit at TRISA1_bit;
var LCD_EN_Direction : sbit at TRISA0_bit;
var LCD_D4_Direction : sbit at TRISB4_bit;
var LCD_D5_Direction : sbit at TRISB5_bit;
var LCD_D6_Direction : sbit at TRISB6_bit;
var LCD_D7_Direction : sbit at TRISB7_bit;

The display is initialised using the following code, note that the compiler automatically links in the LCD driver library.

 Lcd_Init(); // Initialize LCD
 Lcd_Cmd(_LCD_CLEAR); // Clear display
 Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off

The display is updated as the following example:

 txt := 'PHSC (c)2018';
 LCD_Out(1,1,txt); // Write text in first row from character pos 1
 txt := 'AK47M Vs 1.0';
 LCD_Out(2,1,txt); // Write text in second row from character pos 1

When I first ran my program, nothing happened ! Eventually I realised that the contrast was not connected on Pin3. This is normally driven by a voltage divider to adjust the voltage. I simply grounded the pin and it worked fine.

These photos show the individual components:-

This is the LCD display with wires soldered on that connect to the PIC.

 

This is the display PIC. The wires to the right go to the LCD display. The wires to the left take power to the configuration PI card and receive MIDI data.

 

This is the connector to a PI B+ card to obtain power and send MIDI data to the PI. There are four connections : +5v, +3.5v, Ground, UART Receive.

 

Here are the three components connected up.

 

The PIC uses its internal UART to monitor the MIDI messages. I have defined a set of MIDI messages for internal use. These are kept short as there is no flow control. This means I can use a one wire connection to operate the LCD display.

Internal MIDI messages have the general format:

$F1 <length of data> <function> <data>

except for key press messages that have the format

$F1 $00 <key press>

Here is a summary of the messages :-

Key press - $F1 $00 <key press>
Display 1 - $F1 <length> $01 <text up to 16 chars>

Display 2 - $F1 <length> $02 <text up to 16 chars>

Select Style File - $F1 <length> $03 <style file name with extension>

Style Params - $F1 $18 $04 [Voice PC]x8 [Voice Vol]x8 [Voice Enable]x8

Style Aux - $F1 $04 $05 <tempoH> <tempoL> <transpose> <variation select>

Part Params - $F1 $10 $06 [Part PC]x4 [Part Vol]x4 [Part Flags]x4 <Split point> <Split Enable> <spare> <spare>

Chord Finder - $F1 $02 $07 <chord pitch> <chord type>

 

Midi Mate Revisited

Some while back I developed the “Midi-Mate” that connected my Yamaha electric piano to the BK7M. The BK7M unit does not work anymore so I needed an alternative at short notice. I decided to use my old Yamaha PSR keyboard as an alternative sound generator and link it to my piano using the Midi-Mate.

I re-programmed the PIC to hold a set of pre-programmed performance settings internally and recall them when a key sequence was entered. I was able to double up two lead instruments and split the keyboard exactly in the same way as the BK7M. The PIC was able to hold about 100 settings internally. This worked well except that the settings were static and could not be edited.

I decided to use the hardware developed for my AK47M project to extend this concept further and allow me to program the MIDI controller.

A PIC microcontroller is connected to my electric piano via MIDI and also scans a 3×4 numeric keypad. The PIC is connected to a PI zero W using a MIDI serial link so that the PI can accept keypad messages. The PI serial output is linked back to the PIC. This is done so that the PI can send performance configuration messages to the PIC in response to a keypad selection.
The PIC has all the logic to select instruments on 4 MIDI channels and route piano MIDI messages to any of the channels. It can also handle the channel volumes, split the keyboard and perform transposition.

The PI is simply being used to store and recall performance configurations from file and provide a real time editing function for a selected performance. The software uses exactly the same formats as the BK7M performance files so that configurations can easily be edited by my BK7M editor program. (which I have ported to the PI)
The latency is kept to a minimum as the PIC is handling the routing of key on/off messages.

I run the PI in headless mode and it connects to my wifi network. I can run a virtual terminal on my PC or Android tablet in order to use the editor. The screen shots show the completed unit and the editor/configuration software.

 

This is the completed unit. There are two MIDI sockets, one for the Piano and one for the Synth. Power is provided using a USB connection to a USB power supply.

A performance is selected by typing in the performance number followed by a hash. The following numbers provide special functions :-

9991 – restart PI

9992 – shutdown PI

9999 – MIDI panic

The software loads the performance file “0.ups” by default. A different performance file can be selected by typing a number followed by the star key.

 

 

This is the configuration software running on the PI. When a number is entered on the keypad, the appropriate performance configuration is recalled from file and displayed. Parameters can be selected and changed and then sent to the PI by pressing “Update and Send”. The Previous and Next keys allow you to move to the previous or next performance in the file. The entire performance file with edits may be saved using the “Save to File” button.

Note that the performance file is 100% compatible with the BK7M and the BK7M editor. I have ported a version of the Windows BK7M editor to run on the Raspberry PI.

AK47m Project Part 5 (First cut of arranger software on PC and Pi)

Project Updates —

I have built a skeleton program that extends on the previous work and goes a long way to a full arranger. There are two builds, one for Windows and one for the Raspberry PI.

The Windows build outputs MIDI to an external MIDI device. I am currently using the MidiMan MIDI USB interface to read and write to an electronic keyboard for test purposes. I can alternatively route the MIDI to the Windows MIDI device or the excellent VirtualMIDIsynth and generate audio on the PC itself.

The PI version is linked to the QSynth program (which is a wrapper around FluidSynth) via ALSA and generates audio from an attached USB audio interface.

The arranger software is built around the use of the 3×4 matrix keypad as part of the MIDI interface described previously. I have a simulation of this for the Windows build. The software loads up a BK7m performance file called “0.ups” on start up. Individual performances may be called up by typing the performance number (from 1) and pressing the hash (#, PERF) key. The style file linked to the performance is loaded ready to play. It is possible to load a different performance file by keying in a number and pressing the asterisk (*, FILE) key. The file loaded has a filename of the number plus the .ups extension. e.g. “123.ups” .

Once the performance is loaded, it is possible to start by pressing a chord in the left hand or by pressing the zero (0) key on the keypad. When a performance is running it is possible to change to a variation by pressing keys 1..3 or to stop by pressing the zero key. I am proposing to add 4 extra push switches to handle the variation selections.

I have completed the chord finder logic. This works out the chord played in the left hand, selects the maj, min or dom7th snippet and applies appropriate pitch corrections for the chord key and the chord flavour. (i.e. converting the dom7th snippet to  Maj7th snippet) The snippet for the variation is played entirely and then repeated.

When a new variation is selected, a fill for the current variation is played and then the new variation is started. I ensure that the fill is started at the same beat in the bar as the variation that is playing.

I am selecting the instruments specified in the style file at the moment although the BK7m performance can override these. The instruments are kept within the General MIDI instrument palette.

It is still very much work in progress. The main development is done on the Windows PC and verified occasionally on the PI. I have had mixed success in playing styles on the PI. Some of the styles require a lot of processing power which load the PI up to 100%. The balance of volume between instruments is wrong for the FluidSynth sound font and there needs to be a function to correct this and write back the settings to the performance file.

I will trial the software on a PI B+ that has a lot more capacity. There are no CPU performance problems on my 4 core PC.

I may also trial with the arranger on a PI connected to another PI with the Synth. If I do this then I will use the first PI to drive the keypad. My goal is to keep the overall cost as low as possible.

I will release the two installations soon once I have truly figured out the style file format.

 

The setup tab allows you to select the MIDI input and output devices, test the output and bring up a debug message window. This is for Windows only.

 

 

This is the main control tab. The keypad simulation is to the right. The actual commands are listed in the central window. The red shows the BK7m performance name, the green shows the current chord selection.

 

 

 

AK47m Project Part 4 (Making sense of Roland style files)

I have installed Lazarus IDE and Free Pascal on my Windows PC. The installation is easy and it works out of the box !. There is a function for converting Delphi projects to Lazarus projects. The BK7m performance editor I wrote several years back was a Delphi project. I converted this to Lazarus and it required a few tweaks to get it working but nothing major. The advantage of doing this is that I can develop software more efficiently on the PC and then transfer the projects to a Raspberry PI and compile them with the native Lazarus system. Most objects can be transferred easily, but obviously some of the interfaces to MIDI and ALSA need to be tweaked.

One of the last features I was working on for the BK7m editor was a style file editor, this was shelved due to other work, however I started looking at the work completed as a basis for the AK47m project. There is scant information on the Roland style (.stl) file format around, so I had to do some reverse engineering on the format. Any extra information would be welcome.

Style file (.STL) format

The style file basically has a header block at the start followed by a heap. The header contains tables of indexes into the heap and tables of corresponding object sizes. Each object in the heap, which I have termed as a “snippet” contains a list of MIDI commands and time offsets as in a MIDI file. The “snippet” can be played to a MIDI device and it will play a 1..n bar phrase for a single instrument.

Snippets are created for up to 8 instruments (Drums, Bass, 6 harmony instruments). There are three versions of a snippet for an instrument, namely Major, Minor and Seventh. Each snippet is in the key of C, a Major snippet will play a musical phrase for C Major, and a Seventh snippet will play a musical phrase for C7. The arranger software identifies what chord is being played with the left hand and then applies offsets to the pitches of a snippet to play harmony corresponding to the chord. i.e. transposing C to G would add 7 semitones to each note in the snippet. Some snippets are used for the drum track and these would not get transposed at all.

I asked myself about what happens when a Major Seventh chord is played. i.e. C E G B. I assume that the Seventh harmony snippet (C E G Bb)  is used as a basis and a transformation is applied that converts the Bb to B natural before the pitch offset is applied. Similarly a transformation to get a Cm7 harmony (C Eb G Bb) would convert the E natural to Eb.

One thing I wondered about was whether the simple Major and Minor snippets are necessary since a Major could be obtained by dropping the Bb from the Seventh snippet. Maybe the Major snippet is used to produce a Sixth harmony ( C E G A) by adding a tone above the fifth note. More information on this would help me !!

There is a higher level grouping which I have named as sections. There are 16 sections. The structure is 16 sections of 8 instruments of 3 harmonies. The sections correspond to the variations, intro, outro and fills. Some of the sections are completely empty which is a bit of a puzzle.

I believe that the sections are used as follows:

  1.  Intro 3
  2.  Variation 1
  3.  Variation 3
  4. — spare —
  5. 1 bar fill Variation 2
  6. 1 bar fill Variation 1
  7. — spare —
  8. Outro 4
  9.  Intro 4
  10.  Variation 2
  11. Variation4
  12. — spare —
  13. 1 bar fill Variation 4
  14. 1 bar fill Variation 3
  15. — spare —
  16. Outro 3

There is also a table of Word values for each snippet (snippetUnknown), what this relates to I am unsure – are they flags or offsets. Help required.

Unfortunately my BK7m unit does not work so I am unable to compare what the BK7m does with each snippet.

What puzzles me about this is that there are no snippets for intro 1 & 2 and outro 1 & 2.

On closer inspection of the file, I have discovered that there is another header record that starts with G8<name> . It seems that the header maps to the same structure as the first header. There doesn’t seem to be any record size fields, so I have to search for the string G8<name> in the raw data to find the start of the second record. This format is unbelievable spaghetti.

The snippets missing from the first record are in the second record. Note that the snippet pointers are relative to the start of the record in the file.

I suspect that the second record was added for backwards compatibility. There looks like a third record related to the one touch settings. ( i wondered where these were in the BK7 performance file !)

 

styleHeader = record

id: packed array [1..2] of char;
 name: packed array [0..15] of char;
 d1: packed array [1..2] of byte;
 tempo: packed array [0..1] of byte;
 d2: packed array [1..2] of byte;
 timeSignatures: packed array [0..15] of timeSig;
 d3: packed array [1..2] of byte;


 snippetPointers: packed array [0..7] of //instrument
 packed array [0..15] of //section
 packed array [0..2] of longint; //maj min 7th

snippetUnknown: packed array [0..7] of //instrument
 packed array [0..15] of //section
 packed array [0..2] of word; //maj min 7th

snippetSizes: packed array [0..7] of //instrument
 packed array [0..15] of //section
 packed array [0..2] of word; //maj min 7th

 end;

 

“id” is set to the string “G8”.

The snippet pointers reference a list of 6 byte records that have the MIDI data and timing data :-

 

type

timeSig = record
 beatsPerMeasure: byte;
 beatValue: byte; // 01 = 1/2 02=1/4 03= /8
 end;

noteEvent = record
 channel: byte;
 velocity: byte;
 dollar40: byte;
 timeLength: byte;
 end;

controllerEvent = record
 channel: byte;
 effect: packed array[0..2] of byte;
 end;

pitchWheelEvent = record
 channel: byte;
 pitchTimesThree: packed array[0..2] of byte;
 //pitchWheelCommandAgain : byte;
 end;


 programChangeEvent = record
 channel: byte;
 prog: packed array[0..2] of byte;
 end;

nrpnEvent = record
 channel: byte;
 msb: byte;
 lsb: byte;
 Data: byte;
 end;

eventRecord = packed record
 timeIncrement: byte;
 case pitchOrCommand: byte of
 0: (raw: packed array [0..3] of byte);
 1: (note: noteEvent);
 $E6: (controller: controllerEvent);
 $EB: (pitchWheel: pitchWheelEvent);
 $E5: (programChange: programChangeEvent);
 $EA: (nrpn: nrpnEvent);
 $8F: (); // end of list
 $80: (); //data ??

end;


 eventList = array of eventRecord;


Project Goals

The BK7m Editor can interface to a PC MIDI device and output MIDI commands. When MIDI is connected, it is possible to load a style file and play the individual snippets or any combination of them. This was helpful in deciphering the file structure.

The next project goals are to write a PC based program based on the BK7m editor that can perform the MIDI arranger functions. There are five parts to this:

  1. Create general purpose MIDI input output module that works on Windows and PI.
  2. Load a selected style file into appropiate internal data structures.
  3. Identify the chord harmony from notes played on the lower MIDI keyboard and output the chord name.
  4. Apply transformations of snippets using (3) and play the MIDI notes.
  5. Handle transitions between variations with appropriate fills.

 

 


			
		

AK47m Project Part 3 (Creating ALSA virtual device, interface to FluidSynth on Pi)

So I now have a MIDI hardware interface, the key pad control and a test program that processes MIDI data on the PI Zero W. My next goals are:

1 Obtain source code and demo code for developing an ALSA midi driver with Lazarus. There is an open source project FpALSA.

2 Create the demos using Lazarus development system.

3 Download and install Fluidsynth. Connect to demo driver.

4 Adapt the ALSA midi driver to accept MIDI data from my interface.

5 Connect my ALSA MIDI driver to Fluidsynth and test synth output from my MIDI keyboard.

Step 1:

Download the ALSA interface code from https://sourceforge.net/projects/fpalsa/

Extract the source to a suitable folder accesible to the Lazarus system. There is a source file called asoundlib.pp that is included as unit named asoundlib.

Step 2:

The fpalsa lib does not contain any example demo code. I found an older set of interface code and demo code at http://alsapas.alturl.com/ . I took one of the demos and got it to compile with the fpAlsa library with small mods. This code creates a virtual midi driver and sends raw key on and off messages out. The demo program code is given here. When it is compiled and running it creates a virtual MIDI driver.

program AlsaTest1;

{$mode objfpc}{$H+}

uses
 Classes,
 SysUtils,

Crt,
 asoundLib,
 Unix;

type
 TMidiMsg = array[0..2] of byte;

const
 note_on: TMidiMsg = ($90, 60, 100);
 note_off: TMidiMsg = ($80, 60, 0);

var
 device_out: PChar;
 handle_out: psnd_rawmidi_t;
 params: psnd_rawmidi_params_t;

err: integer;

begin

device_out := 'virtual';

writeln('Testing output rawmidi device ');

err := snd_rawmidi_open(nil, @handle_out, device_out, 0);
 if (err <> 0) then
 begin
 writeln('snd_rawmidi_open ', device_out, ' failed: ', err, ' ', snd_strerror(err));
 end
 else
 begin

snd_rawmidi_params_malloc(@params);

snd_rawmidi_params_current(handle_out, params);
 snd_rawmidi_params_set_no_active_sensing(handle_out, params, 1);
 snd_rawmidi_params(handle_out, params);
 snd_rawmidi_params_free(params);

writeln('Connecting synth');

// do alsa connection to active synth - one of these will work!!
 fpSystem('aconnect 128:0 129:0');
 fpSystem('aconnect 129:0 128:0');

writeln('Writing note on / note off');
 while not keypressed do
 begin
 snd_rawmidi_write(handle_out, @note_on, SizeOf(note_on));
 snd_rawmidi_drain(handle_out);
 sleep(1000);
 snd_rawmidi_write(handle_out, @note_off, SizeOf(note_off));
 snd_rawmidi_drain(handle_out);
 end;

writeln('Closing');
 snd_rawmidi_drain(handle_out);
 snd_rawmidi_close(handle_out);
 end;

end.

step 3:

Download and install “QSynth“. This is a GUI to control “FluidSynth“. FluidSynth uses sampled sounds in a soundfont file to produce sounds in response to received MIDI messages. The download includes QSynth, FluidSynth and the soundfont file called “FluidR3_GM.sf2”.

sudo apt-get install qsynth

Run Qsynth from the main application menu under Sound & Video. A panel is displayed to control the synthesizer. Click on the “Setup” button. There are tabs to set the MIDI, Sound Output and Soundfont.

The following screens show what set up is required :

Press OK and the new settings will take effect. It takes a while to load the soundfont and you should wait until the buttons become active before proceeding.

Open a command terminal and enter the following:

aconnect -l

You will see a list of active MID devices. e.g.

pi@PIZERODEV:~/Peter/Midi $ aconnect -l
client 0: 'System' [type=kernel]
 0 'Timer '
 1 'Announce '
client 14: 'Midi Through' [type=kernel]
 0 'Midi Through Port-0'
client 128: 'Client-128' [type=user,pid=1134]
 0 'Virtual RawMIDI '

In my example the QSynth is client 128:0 .

When I run the demo program AlsaTest1 created above it creates a new device as client 129:0 .

You will see the command

aconnect 129:0 128:0

executed as part of the demo program. This connects the output of the demo program to the input of the QSynth. Run AlsaTest1 and you should hear a repeated piano note played until a key is pressed.

Steps 4 & 5 :

I have basically combined the program in part 2 with AlsaTest1 to produce AlsaTest2. This program connects the UART input to QSynth and allows me to run test sequences from the keypad and play notes on my MIDI keyboard.

There is some more work required here to refine the program and performance but the main principle is outlined and working.

This program runs QSynth and waits for the return key to be pressed when it is fully loaded. It will then make the required connection and link the UART input to the Synthesizer until a key is pressed at the terminal.

program AlsaTest2;

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

var
  device_out: PChar;
  handle_out: psnd_rawmidi_t;
  params: psnd_rawmidi_params_t;
  err: integer;

  serialPortHandle: TSerialHandle;
  i, Count: integer;
  receiveBuffer: array [1..255] of byte;

begin
  ser := TBlockSerial.Create;
  ser.RaiseExcept := True;

  device_out := 'virtual';
  try
    writeln('MIDI test program');

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

    writeln;
    writeln;

    // create ALSA device channel
    err := snd_rawmidi_open(nil, @handle_out, device_out, 0);
    if (err <> 0) then
    begin
      writeln('Open ALSA failed: ', err, ' ', snd_strerror(err));
    end
    else
    begin
      // ALSA channel setup
      snd_rawmidi_params_malloc(@params);
      snd_rawmidi_params_current(handle_out, params);
      snd_rawmidi_params_set_no_active_sensing(handle_out, params, 1);
      snd_rawmidi_params(handle_out, params); snd_rawmidi_params_free(params);
      writeln; writeln ('Starting synth .... press enter to continue when running ...');
      fpSystem ('qsynth &');
      readln;
      // do alsa connection to active synth
      // a hack- one of these will work
      writeln('Connecting to synth');
      fpSystem('aconnect 128:0 129:0');
      //fpSystem('aconnect 129:0 128:0');
      try
        writeln;
        writeln ('Main processing loop. Press a key to exit');
        while True do
        begin

          // very inefficient read of 1 character at a time
          count := SerReadTimeout(serialPortHandle, receiveBuffer, 1);
          if (count > 0) then
          begin
            snd_rawmidi_write(handle_out, @receiveBuffer[1], Count);
            snd_rawmidi_drain(handle_out);
          end
          else sleep(0);
          if keyPressed then
          break;
        end;
      finally
         writeln('Closing ALSA. Dont forget to QUIT synth');
         snd_rawmidi_drain(handle_out);
         snd_rawmidi_close(handle_out);
      end;
    end;
  finally
      serClose(serialPortHandle);
  end;
end.

 

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.

AK47m Project Part 1 (MIDI interface and Keypad interface)

This is a proof of concept project to produce a Roland BK7m replacement with a similar piece of kit that costs under £50. (which is the price an engineer would charge to look at a faulty BK7m.) This was outlined in an “up yours Roland” post before. A suitable name for this is the AK47m and you can work it out yourself why I chose it !

The first part of the project is to develop an interface to a MIDI instrument. The proper way to interface to MIDI input is to use an opto-isolator to avoid any direct electronic connections that could cause earth loops and to filter out any other nasty transients.

My first prototype used a general purpose opto-isolator and this failed miserably. It produced the appropriate changes in logic levels in response to an input MIDI message, but it was not fast enough. When I looked at the output from the opto it had a rounded return to +3.5v and the level was about half way at the bit sampling point, so it was neither up or down. So I need to order a faster device.

In order to make progress, I used a direct connection to the MIDI instrument and this worked good enough for my prototype, however I shall modify it to use an opto in due course.

I have used a PIC 16F628 microcontroller to handle the MIDI input and also to handle a 3×4 matrix keypad. The PIC outputs MIDI messages from its internal UART which are directed to any number of Raspberry PI computers. The PIC scans the keypad and debounces key presses. These are then translated into MIDI system common messages. e.g. a key press of 5 results in three MIDI bytes of

F1 00 05

An additional 4 press switches will be included later and these will be driven by the A3 output (A0, A1 & A2 drive the keypad, B4 ,B5, B6 and B7 sense the keypad)

 

Messages received from the instrument are relayed onwards. This introduces a slight amount of latency but that’s ok.

The PIC operates at 4 MHz and has a ceramic resonator to implement the clock, however it works just as well using the internal clock oscillator. The MIDI message baud rate is 31250 and so the bit time is 1000,000 / 31,250 =  32 uS. The internal UART for the PIC divides down the CPU oscillator to produce a UART clock and the divisor is a pure integer so the UART clock error is neglible.

The PIC firmware is written in PASCAL and compiled using the excellent MikroPascal IDE described previously. The firmware sets up the internal UART to receive and transmit at 31250 baud. It implements an interrupt handler that is activated when a single MIDI byte is received. The byte is stored in a FIFO buffer. The main process checks for received bytes and transmits them if present. It also scans the keypad matrix and debounces the key presses. If a key press is detected, a system message is transmitted with the keypad value. When the * key is pressed it transmits a MIDI message sequence that plays the three notes G,Ab,A as a test routine. A copy of the firmware is included later.

This is the circuit diagram – Note the opto isolater is shown seperately and the main circuit shows a direct connection

These are the connections to a 5 way DIN connector shown from the rear.

 

This is the keypad and the pinout

This shows the connections to the PI Zero . From left to right, RXD, Ground, 3.5v. The PI powers the PIC on the 3.5v supply line.

 

This is everything lashed up :

 

This is the PIC 16F628 firmware

program PI ;

{ Declarations section }
var fifo : array [0..63] of byte;
var inix, outix : byte;
var i : word;
var tmp : byte;


procedure interrupt(); iv 0x0004; ics ICS_AUTO;
begin
 if TestBit (PIR1, RCIF) then
 begin
 // tmp := RCSTA; // clear interrupt
 fifo[inix] := RCREG;


 if TestBit (RCSTA,FERR) or TestBit (RCSTA,OERR) then
 RCSTA := $90;

inix := (inix + 1) and $1F;

ClearBit(PIR1, RCIF);
 end;
end;

procedure delay ( pDelay : word) ;
//delay ms
var
 n : word;
 i : word;
begin
 for n := 1 to pDelay do
 for i := 1 to 76 do;
end;

procedure transmit ( pByte : BYTE) ;
begin
 TXREG := pByte;

//wait tx empty
 while true do
 begin
 if ((TXSTA and $02) = $02) then break;
 end;

end;

procedure sendTestMessage;
var
 i : byte;
begin
 for i := 0 to 2 do
 begin
 //note on
 transmit ($90);
 transmit (55 + i);
 transmit (80);

delay(150);

//note off
 transmit ($80);
 transmit (55 + i);
 transmit (0);
 end;
end;


procedure sendPerformanceMessage (performance : word);
const
 CONTROLCHANGE = $B0;
 PROGRAMCHANGE = $C0;
var
 cc32 , pc : word ;
begin
 cc32 := performance div 128;
 pc := performance mod 128;

transmit ($F1);
 transmit (cc32);
 transmit (pc);
end;


procedure busyDelay (delayMs : word);
var
 midiByte : byte;
 counter : dword;
begin
 // receive midi byte
 counter := delayMs * 30;
 while true do
 begin
 while (inix <> outix) do
 begin
 midiByte := fifo[outix];
 outix := (outix + 1) and $1F;
 transmit (midiByte);
 end;

if counter = 0 then break;
 counter := counter - 1;
 end;

end;

function scanKeypad : byte;
{

1 2 3 -- B7
 4 5 6 -- B4
 7 8 9 -- B5
 * 0 # -- B6

| | |
 | | |
 A0 A1 A2

* = 10
# = 11
}
var
 scan : byte;
begin
 scan := 255;

// OUT A2
 PORTA := $04;
 case (PORTB and $F0) of
 16 : scan := 6;
 32 : scan := 9;
 64 : scan := 11;
 128 : scan := 3;
 end;
 busyDelay(0);

// OUT A1
 PORTA := $02;
 case (PORTB and $F0) of
 16 : scan := 5;
 32 : scan := 8;
 64 : scan := 0;
 128 : scan := 2;
 end;
 busyDelay(0);

// OUT A0
 PORTA := $01;
 case (PORTB and $F0) of
 16 : scan := 4;
 32 : scan := 7;
 64 : scan := 10;
 128 : scan := 1;
 end;
 busyDelay(0);

scanKeypad := scan;
end;


function debounceKey : byte;
var
 key : byte;
 counter : word;
 presses : byte;
begin

// check for three consective valid presses 10ms check time
 counter := 0;
 presses := 0;
 while true do
 begin
 key := scanKeypad ;
 if (key <> 255) then
 presses := presses + 1
 else
 presses := 0;

if (presses = 3) then
 break; //valid key

busyDelay(10);
 counter := counter + 1;

if counter > 100 then
 begin
 key := 255;
 break; // timeout
 end;
 end;

// check for a release time of 50 ms
 counter := 0;
 presses := 0;
 if (key <> 255) then
 while true do
 begin
 if (scanKeypad = 255) then
 presses := presses + 1
 else
 presses := 0;

if (presses = 5) then
 break; //valid off time

busyDelay(10);
 counter := counter + 1;

if counter > 100 then
 begin
 key := 255;
 break; // timeout
 end;
 end;

debounceKey := key;
end;

begin
 { Main program }

// init usart
 TRISA := $FF; //isolate
 TRISB := $FF; // usart pins must be inputs exept B4
 CMCON := $07; // disable comparators


 //enable uart receiver and fifo
 RCSTA := $90;
 TXSTA := $24; // configure hi speed @ 4mhz
 SPBRG := 7; // MIDI baud rate 31250 ( 4000000 / 16 * BR) - 1

inix := 0;
 outix := 0;

//enable receiver interrupts
 SetBit (PIE1, RCIE);
 SetBit (INTCON, PEIE);
 SetBit (INTCON, GIE);

// output bit 0,1,2 and 4
 // 0,1,2 are for keypad scan, 4 is to control LED
 TRISA := $E8; // bit set is an input
 busyDelay(100);

inix := 0;
 outix := 0;

while true do
 begin
 busyDelay(0);

tmp := debounceKey; //times out after 1 second
 if (tmp <> 255) then
 begin
 if (tmp = 11) then 
 sendTestMessage
 else
 sendPerformanceMessage (tmp);
 end;

//PORTA := inix mod 3;
 end;

end.
« Older Entries Recent Entries »