Technical Details of the AKAI MPKmini Professional MIDI Keyboard

This year I impulse-bought an AKAI MPK mini Pro 2-octave MIDI device.

AIKI MPKmini Pro

And found that, apparently, if you want to do anything with Midi music, you buy a Mac.

Well, I’ve always found Mac/Apple UI to be unusable, so that’s out.

Anyway, it turned out to be easy to get MIDI messages from a USB device to a Python program using python-mido. And, after some dithering, creating sound from Midi was do-able. I tweaked one of several variants of on GitHub. The actual instruments came from various SoundFont files downloaded from the magical Internet. My favorite of the 48 I have is gigabyte-sized Compifont_13082016.sf2.

Re-inventing the wheel can be entertaining.

In the course of playing with the AKAI I made the following notes about the AKAI’s sysex and light control logic. Make of them what you will.


Some things found about the Akai Pro Mini using (after plugging the device alone in to USB bus 3 - the near plug on the front panel of spring):
    sudo modprobe usbmon                        # makes the /dev/usb/usbmon[0-7] devices
    sudo cat /sys/kernel/debug/usb/usbmon/3u    # doesn't print more than 24 real data bytes at a time (32 bytes packaged in 8 4-byte words)

    Note: Each 4 bytes has a 04 as the 1st byte and a 07 instead of 04 on the last 3 real data bytes.

    sudo tcpdump -i usbmon3 -x

Note:   has some sysex reverse-eng info for the device
Note:       private/akai/APC40Mk2_Communications_Protocol_v1.2.pdf                  for a similar device (some note on the web said this MPKmini doesn't have such a doc)

MPK Mini sysex from device

sysex data=(
71,         Akai device     71==0x47
0,          More Akai dev?                      (which particular device? - 0x7f is broadcast, apparently, and 0x7e is non-real-time?)
38,         Akai model      38==0x26
103,        sysex function  103|0x67 is (prog_memory below: 0..4=RAM|prog1..4) coming from device.
                            102|0x66 requests a program (prog_memory below: 0..4=RAM|prog1..4) from device.
                            100|0x64 puts program to device.
                             96|0x60 requests the knob positions (see the code for example).
                             97|0x61 is knob positions from the device.
0,          hi-7-bits of how many bytes
109,        how many more bytes there are or are meant to be if the device didn't have bugs?

0,          prog memory     0=RAM 1=prog1 2..4=prog2..4

0,          pad channel     0..15

0,          key channel     0..15
4,          key octave      0..8    4 + octave      (changes LEDs)

0,          arp             off=0 on=1              (changes LED)
0,          arp mode        0..5
0,          arp time div    0..7
0,          arp clock       internal=0 external=1
0,          arp latch       on=1    off=0
0,          arp swing       0..5    50%|55%|57%|59%|61%|64%
3,          arp tempo taps  2..4
1,          hi bit          arp tempo  30..240
0,          lo 7 bits       arp tempo  30..240
0,          arp octave 0..3 (displayed on-screen in Akai setup program and on device's keys in red as 1..4)

0,          0=pitchbend     1=cc1 2=cc2
0,          cc1|cc2-down    0..127
0,              cc2-up      0..127
2,          cc2
65,         cc2-down 65
64,         cc2-up   64

48,         note_on note when not in CC or PC mode
0,          cc
0,          pc
1,          momentary=0 toggle=1

0,      cc
0,      lo
127,    hi

12          0..24   12 + transpose of -12..12


#   If the device is in the right state, apparently any channel 0 note_on (non-127?) will turn off the PROG_CHANGE light until some other note_on messages are sent or something.
#   led_lite values:
#       0..2    At start-up most recent is Prog Change - it turns off/on.
#       3       Apr On/Off
#       4       Tap_tempo changes only if human has turned off Arp
#       5       Octave down
#       6       Octave up
#       7       Full level
#       8       ?
#       9..16   Pads
#       17..24  Most recently used lite.
#       25      Bank A/B if Green, off goes to off or red, whichever it was last set by the human. Human-set red cannot be turned off.
#       26      CC
#       27      Prog Change
#       Other led_lite values are just weird. Most recent lite changed or something is affected.
#   The lites don't affect the meaning of the button. The button must be hand-toggled from its logical state to get to a state that matches the lite after the lite is turned off.
#   The 127-ness came from a comment at:
    [ 3,    "Arp",          ],
    [ 4,    "Tap_Tempo",    ],
    [ 5,    "Oct_down",     ],
    [ 6,    "Oct_up",       ],
    [ 7,    "Full_level",   ],
    [ 9,    "Pad_1",        ],
    [ 10,   "Pad_2",        ],
    [ 11,   "Pad_3"         ],
    [ 12,   "Pad_4",        ],
    [ 13,   "Pad_5",        ],
    [ 14,   "Pad_6",        ],
    [ 15,   "Pad_7",        ],
    [ 16,   "Pad_8",        ],
    [ 25,   "Bank_A/B",     ],
    [ 26,   "CC",           ],
    [ 27,   "Prog_change",  ],

A new Kinsa fever movie

Here is another movie generated by my Kinsa fever data display program.

This video uses color to show which US counties have similar Kinsa fever thermometer statistics. This particular video colors counties with recent (previous 15 days) higher-than-other-county-fever-percentages in red tones, less recent high percentages in green tones, and high percentages older than 45 days in blue.

Watch red to see how fever moves around the country over time. Watch for blue to see counties that have had fever, but not for a while. Green counties were feverish around a month before the end date.

During the video, the end date runs from mid-March to August 7th.

Where Kinsa says it’s getting hot

Here is the current US map with green showing the highest percentage of feverish people in March and April, blue showing May, and red showing June so far, to the 8th.

Notice California (e.g. Alameda County)

and Florida (e.g. Pasco County)

seem to be heating up in May/June (red and blue – orange), and western Utah (e.g. Beaver County)

has come alive in the last, red week – June, that is. I wonder if anything is going on in these places.

By way of contrast, consider most of Texas (e.g. Nolan County)

which was particularly feverish (compared to other places in the US) only in May. That drop-off in Nolan County, Texas is peculiar, too. Neighboring counties have a similar, but not so dramatic drop-off. Probably some peculiarity of data processing. … Or is it? Dum, dum, dum, dummm. Suspense!

Seeing Kinsa thermometer time-period fever profile similarities.

This Corona Virus thing is, ignoring dead people, a lot of fun.


Well, because it’s so interesting. The progression of the disease is interesting, the reactions to the disease are interesting, and speculations about the post-virus future are interesting.

One interesting thing is the quantity of blather from the babble-world. Where are exceptions to misstatements, lies, confusion, and overall silliness?

One exception seems to be a company named Kinsa. They sell an Internet connected fever thermometer. $30 and $50. Currently sold out.

But, talk about perfect timing: Kinsa has data for much of the US showing when people were, and are, running fevers. Their data correlates pretty closely to flu season.

So, come Covid19, they moved fast and created This web page shows in color and graphically which counties in the US have been affected by fevers and when, post February 16th.

The good, the bad, the ugly:

The Good: A couple minutes in the Firefox Web Developer says the data underneath the web page is remarkably clean and accessible. (OK, they’ve made breaking changes to the data a couple times in the last few days, but life is tough. Boo. Hoo.)

The Bad: Starting Feb 16? Why not Nov 1, 2019? I know why. But why?

The Ugly: Sorry, Tuco. You’re written out of this script. It’s a pretty web page.

Can the web page and data reveal outbreaks of fever in near real time? Kinsa sure hopes so.

As it turns out, the famously big US Covid19 outbreak (NY city) does show up in Kinsa’s data.

But, it remains to be seen what happens over the next few weeks as people wander out of stay-at-home. Thermometers don’t inherently pay attention to political spin, and don’t inherently serve to confuse. So, I’m rooting for Kinsa.

Now, this is all very nice, but what does it lead to?

Well, look at the orange/red line in the NY County image above. Notice its shape – its profile. Call that shape the “fever profile”.

I was clicking around some counties on the web page and noticed an odd thing: Most counties had a fever profile from February to May that looked like neighboring counties. Like, say, county A had a spike of fevers around March 17th, and so did bordering counties B and C. Not counties two states over, though.

Fair enough.

But, sometimes there seemed to be sharp transitions between one county and the next with respect to their curves. Maybe my imagination. Maybe not.

I wanted to see the whole country’s county-time fever profile similarities at a glance. If two counties had a similar fever profile/curve from February through today, the two counties should look similar in a picture. And if their fever profiles were different, they should look different.

So, I whipped up a program to color counties based on the total fever-percentage-of-people numbers in 3 bands of time. E.g. Feb 16 to the end of February. The first half of March. And the third band for mid-March to the present. Then the larger the totals a county has in fever percentages in each band, the brighter a color is. The first band is red. The second, green. And the last, blue.

And, here is a picture of the US with counties colored based on fever percentage profiles as of today:

It looks like if you really didn’t want a fever, you should have been in a dark area – Arizona, New Mexico, or the Knoxville Tennessee area. That latter area is quite the surprise.

And if you like Covid19, you wanted to be in the bright blue (mid-March and later) Florida or the New York City areas. Don’t forget to be old!

If you want the flu (in red February), go north-central (ND, WI, MN, northern MI, … or … Canada?).

If you do like your body hot, go to where the colors are bright: downstate Illinois, Indiana, western Kentucky, and Missouri. Maybe Ohio. Or maybe California! Though in California a hot body could be taken two ways.

Here is a picture based on the fever percentages minus what Kinsa expected them to be given historical trends:

Bright New York is pretty clearly where the unusual fever has been. And I love the West Virginia hole in the picture. Examining the (Fever Expected) profile for a county there:

shows they dodged the flu.

Another bright spot I didn’t expect was downstate Illinois. The bright purple says they probably had a bit more flu and Covid19 than Kinsa‘s expectations. Or something.

You want movies? You got ’em:

Percentages of people running a fever stepping “today” from February through May:

Fever percentages minus what Kinsa expected:

All in all, it’s been a fun program to write. It shows the fever profile of the county your mouse hovers over so you can quickly see the profiles of lots of counties in a geographical area. I’ve found that handy and kinda informative.


Make Facebook pleasant again

I go to Facebook every few days, weeks or whatever. Kids’ pics. Volleyball happenings. Doings of people I’ve known over the years.

What’s happened to my follow-feed, though, is people I know to be fine people in real life appear in the feed as the girl on the left:

Tantrum Time

This is disheartening at best.

Politics is entertaining, but, golly, let’s not scream at our favorite character on TV when they do something dumb. Get a grip.

But, of course, the other guy will never get a grip.

So, for Firefox, there’s Grease Monkey and my quick and dirty Grease Monkey script, FaceBookFix.user.js, to the rescue.

This script simply takes Facebook posts off screen if they contain, in text form (sadly not in images), any of a list of words.

It’s not heavily tested, to say the least. Which is to say, I tried it a couple times.

I made it easy to add or delete banned words. Non-programmers can change the script if they can find it on their disk and save it as a text file from WordPad or a better text editor.

The results are nice. My feed is now pleasant. Again. “Never do yourself what a computer can do for you,” so the computer now lets me see the real news un-flooded by noise. (If this post makes it to Facebook, I can’t write “f*** news” or the script will make the post invisible to me!)

Oh. Here’s the whole script as of this moment:

// ==UserScript==
// @name        FaceBookFix
// @namespace
// @description Get rid of sad Facebook tantrums.
// @include
// @version     1
// @grant       none
// ==/UserScript==


    FaceBook posts containing any of these listed strings are whacked.

    The strings are in in no particular order.

    Change as you see fit.

    Non-programmers, leave the last one as the last one.

    Non-programers, for syntax reasons, do not put any:
        single-quote         ( ' )
        pipe/vertical_stroke ( | )
        backslash            ( \ )
    characters in any of the strings.

var find_these_strings  = [
    'faux news',
    'hilliary',         // I forget other Internet commenters' alternate spellings. More to come, for sure.
    'steve bannon',
    'bernie sanders',
    'bernie',           // Sorry about this, Bernie-from-Dimas-days. Your brand has been trashed.
    'george bush',      // 'bush' is just too generic
    ' g bush',
    ' gbush',
    ' gw bush',
    ' gwbush',
    ' h bush',
    ' hbush',
    ' hw bush',         // did I get these bushes right?
    ' hwbush',
    'kkk',              // why are Hollywood and the news guys obsessed with the KKK? No one in the real world cares about them.
    'mcconnell',        // maybe this should be only mitch McConnell
    'sean spicer',
    'harry reid',
    'paul ryan',
    'house of rep',
    'occupy democrats',
    'occupy wall',
    'fake news',
    'saudia arabia',
    'executive order',
    'daily show',       // ? poeple seem to feel this show is really important when it discusses politics
    'fuck',             // the whole profanity list should be here.
    'Note: Leave this here at the end of the list.'
find_these_strings  = find_these_strings.join('|').toLowerCase().split('|');
find_these_strings.pop();       // get rid of the comment at the end

(function (){

function    fix_this_facebook_thing()
    var divs = document.getElementsByTagName("div");                            //  Find all DIV elements in the page
    // window.console.log("fixing " + + " " + divs.length);
    for (var el_number in divs)                                                 //  Python is *so* superior to JavaScript
        var el  = divs[el_number];
        if (( != undefined) &&'hyperfeed_story_id_'))    //  For each post in the feed
            var htm = el.innerHTML.toLowerCase();                               //  Look for any of the strings without regard to case
            // window.console.log("scanning " + + " " + htm.length);
            for (string_number in find_these_strings)
                var fs  = find_these_strings[string_number];                    //      For each of the strings to find
                if  (htm.indexOf(fs) >= 0)                                      //          Is the string in the post in text form? (sadly missing them in images and videos)
              = 'none';                               //          Yes. Take the post off screen
                    // window.console.log("whacked: " + fs + " in " +;
                    break;                                                      //          And don't keep looking in the this post for more matches.

var timeout_every_couple_seconds = window.setInterval(fix_this_facebook_thing, 2017);


// eof

Taking the fun away to be a better person

Twenty some years ago my right hand became frozen around a mouse. It took the left hand to pry the mouse from my … hand.


Microsoft Minesweeper.

Too much Minesweeper.

So, on the principle of “Never do yourself what a machine can do for you.“, I wrote a program to play the game. On screen. Mouse clicks and all.

And after watching expert mode being solved in 7 seconds a few times under Win 3.1, Minesweeper became boring and I stopped playing it. (No. The program did not use the cheat mode. It played fair.)

Problem solved.

Fast forward some years.

I wrote a program to solve Spider.

It didn’t help. I’ve still spent too much time on that game. But the program did find only a couple of impossible-to-win games out of 32 thousand dealt. That was informative.

Fast forward some more years.

I wrote a Sudoku program to stop myself from playing that game, uncompelling and bite sized though the game was. It was a fun program and is handy to find impossible and incompletely initialized / ambiguous games (e.g. at But it didn’t satisfy.

Fast forward to now.

And we have a screen shot from playing a game at :

Playing Sudoku the right way.

We’ll see if I keep playing this site’s game.

Or a hacked old Python Gnome Sudoku program:

Playing Gnome Sudoku the right way.

The program looks at the screen(s), finds boards, solves them, and plays them using mouse clicks and keys to enter the numbers. Though the program is incomplete, it’s pretty satisfying. Perhaps that’s why at one point many years ago I said that my job was to automate my job. And perhaps that’s why I’m not among the robotic hand-wringers of today. It’s simply fun to watch machines do what they do best.

Paper Tape

As can be clearly seen by the octal values, this is a scan of the mylar tape of the Super Wrinkle boot loader for the APS-73 Computer used in Autologic typesetters.


Super Wrinkle, if I recall, was the ultimate boot loader – a worthy successor to the famous Wrinkle loader. Super Wrinkle required the minimum possible switch toggling to be read from the tape reader. Once it overwrote the toggled instructions, it read a more complex, generic, non-hacky loader. This had to be done after any power cycle / reset / program failure / hardware glitch.

The alternative to toggling in the instructions to read an infinite number of (Super Wrinkle) bytes from the tape reader was too expensive for everyday computer use. We’re talking $27 for a mighty, 256 byte ROM chip. That was back when $27 was $27, mind you. One customer built such a device out of discrete diodes to save the cost. The word was it was quite a monstrosity.

Installing opencv 2.x on Ubuntu Lucid

Lucid include opencv version 1.x. That version doesn’t cut it.

Here is how to get the latest (as of March 15, 2014) opencv going under Lucid.

sudo aptitude install cmake libdc1394-utils libjasper-dev libavcodec-dev libavformat-dev libswscale-dev

# cd to some temporary directory, download the latest opencv ZIP file and then ...
cd opencv-2.4.8

# Get around that we need a newer cmake according to the Internet - commenting out the problem is the easy way to fix it
cp ./cmake/cl2cpp.cmake ./cmake/cl2cpp.cmake.original
perl -ne "~s/string\(MD5/# string\(MD5/; print" < ./cmake/cl2cpp.cmake.original >./cmake/cl2cpp.cmake

# -D MAKE_FFMPEG=OFF 'cause we need a newer ffmpeg - so opencv will just not be able to do things ffmpeg allows
mkdir -p release
cd release

# make using as many CPUs as you have - 4 in this case
make -j4
sudo make install

# verify this version of opencv works with a usable language
python -c "import cv2; print cv2.__version__"

Python 3

Read an interesting screed on Python 3.

Thoughts on Python 3


This paragraph pretty much sums it up:

Python 3 is in the spot where it changed just too much that it broke all our code and not nearly enough that it would warrant upgrading immediately. And in my absolutely personal opinion Python 3.3/3.4 should be more like Python 3 and Python 2.8 should happen and be a bit more like Python 3. Because as it stands, Python 3 is the XHTML of the programming language world. It’s incompatible to what it tries to replace but does not offer much besides being more “correct”.

I really like Python. Moved from Perl (for PC work) when CPU’s got fast enough for Python. The Python out-of-box was terrific.

But, Python 3 is another language. I can’t justify porting all my personal “library” code to another language. Some of the Python 3 stuff reminds me of C++ – puffiness for the sake of puffiness. If forced to go to Python 3, I’d evaluate what language to use as I did when moving from Perl.

And as it stands, it’s very clear that, since all the garbage-collection-memory-protection languages are equivalent, the last one standing will be JavaScript. You have to write the occasional JavaScript. So you have to pay the entrance fee. Maybe node.js will end up making JavaScript work reasonably as a non-browser language. Something will. And that’s the end of all the other languages (excepting the type-anal ones for corporate cubicles). Poof. Python 3 becomes a non-issue.

If Python ran in the browsers and if it ran on all the newer OS’s, then fine. It could go head to head with JavaScript. Otherwise … Too bad. Sad. I may be a curly bracket guy, but Python just looks and feels better than JavaScript.

rsync and sshpass

After spending yet another several hours fighting the good fight, it seems like a good idea to note how to use rsync on a troublesome ssh connection – one that both requires a password and that is slooooow to get logged on.

First, the problem of the password is solved using sshpass. It allows you to put the password for the remote system in a file. The file, we presume, is stored in your ~/.ssh/ directory and has its permissions set so that only you, the user, can see it or do anything with it. In that way, it works like an ssh key file that you might tell ssh to log in with using the “ssh -i ...” command line option.

Second, to allow for a slow server, use something like this as an option to ssh:

ssh -o ServerAliveInterval=45 ...

That is, tell ssh to wait for 45 seconds for the slow server to get you logged in.

So the command line to get a connection to the server is something like this:

sshpass -f ~/.ssh/bonzo_password.txt       \
             ssh                           \
            -p __BONZO_SSH_PORT_22__       \
            -o ServerAliveInterval=45      \

Excuse the horrid backslashes. They are for the browser window.

All well and good. But that command line won’t work under rsync. The connection will be made, then instantly dropped. And rsync hangs.

I presume the drop is something security-related in ssh.
Or maybe sshpass.
rsync is unhappy.

But, here’s the deal: rsync will be happy if the connection is already made in another terminal, and you have configured ssh to allow connections to go through a “master” connection – that is, tell ssh to not log in normally, but to rather use an existing ssh connection.

You tell ssh to use an existing connection by putting the following in a ~/.ssh/config file (remember to set the permissions for everything in ~/.ssh for only your access):

ControlMaster       auto
ControlPath         /tmp/ssh_mux_%h_%p_%r

For clean-up reasons, you put the sshpass command in a separate .sh file which we’ll call

So now you run that script in a “SCREEN” – sort of a virtual terminal window!

screen -t ssh_to_bonzo -dmS ssh_to_bonzo
sleep 45

Note the you-set-it, 45 second delay.

Once this code is run, you can rsync away, though with the world’s worst command line.

So your whole rsync script might look something like this:

screen -t ssh_to_bonzo -dmS ssh_to_bonzo
sleep 45
rsync --rsh="sshpass -f ~/.ssh/bonzo_password.txt ssh -l bonzo_user_name"     \
        bonzo:bonzo_directory                                                 \

Or something of that sort.

Notice the pkill at the end. That cleans up the screen operation.

Note, too, that you must still give the sshpass command line to the rsync --rsh option.

Piece of cake.