Old 04-25-2017, 10:25 AM   #1
John Allsup
Human being with feelings
 
Join Date: Apr 2010
Posts: 59
Default Keyboard Touch Trainer script

I randomly mentioned this idea at a party once, when chatting about music stuff, and real vs digital pianos. I commented as to the kind of weird training exercises you can set up with a MIDI instrument. One was the idea of a simple 'touch trainer'. I played around in Max MSP for a bit, and then realised a short js script would also do the trick.

Here, the idea is that the incoming noteon velocity is divided by some number, and rounded to the nearest integer, so as to subdivide the velocity into zones (as happens in a sampler). Then you possibly map to a semitone in a scale (i.e. [0,1,2,3,...] -> [0,2,4,5,...] for a major scale), add that to the incoming pitch, and output that pitch, with a fixed velocity.

Basically, the harder you press, the higher the pitch goes above the normal pitch. The use in practice is that you can do a number of exercises where the pitches only sound right if you play with the desired velocity.

For example:

play a scale (and if the velocities are all consistently in the same zone, you'll hear a scale, and if not, it will sound messy);

play a 'paradiddle' between two velocity zones (e.g. if you divide the velocities 1..127 into 4 zones, playing a L-R-L-L-R-L-R-R pattern between, say, zones 1 and 3, or 3 and 4).

I've yet to see how well this works as a practice aid, having just written it, but I thought I'd share the script and the rather crazy idea for a practice aid.

As it is, it may still have issues with stuck notes and so on. But the other point of sharing this here is as an example of the idea of using things like plugins and scripting as practice aids in some way. That you can knock something functional out in about half an hour (while waiting for my dinner to cook), and with only 129 lines to type, is why I love to have a decent textual scripting language in my DAW. (The major[3]=5; stuff was generated by a 5-line python script.)

Code:
desc: TouchTrainer1

// One slider for number of notes to divide into, max 12.
// One slider for major, minor, and chromatic scales, 0,1,2
slider1:5<2,12,1>Subdivisions;
slider2:0<0,2,1>Major/Minor/Chromatic;
slider3:0<0,15,1>Channel;
slider4:80<10,127,1>Output velocity;
slider5:0<-12,12,1>Pitch offset;

@init
ext_noinit = 1.0;
// allocate arrays
noteouts = 100; // maps note in to current (pitch adjusted note)
notesheld = 300; // keeps track of how many notes held map to each pitch
// midi pitch 0 is ignored.

scales = 500;
major = scales+0;
minor = scales+100;
chrom = scales+200;

major[0] = 0;
major[1] = 2;
major[2] = 4;
major[3] = 5;
major[4] = 7;
major[5] = 9;
major[6] = 11;
major[7] = 12;
major[8] = 14;
major[9] = 16;
major[10] = 17;
major[11] = 19;
minor[0] = 0;
minor[1] = 2;
minor[2] = 3;
minor[3] = 5;
minor[4] = 7;
minor[5] = 8;
minor[6] = 10;
minor[7] = 12;
minor[8] = 14;
minor[9] = 15;
minor[10] = 17;
minor[11] = 19;
chrom[0] = 0;
chrom[1] = 1;
chrom[2] = 2;
chrom[3] = 3;
chrom[4] = 4;
chrom[5] = 5;
chrom[6] = 6;
chrom[7] = 7;
chrom[8] = 8;
chrom[9] = 9;
chrom[10] = 10;
chrom[11] = 11;

subdivs = slider1;
scaletype = slider2;
scale = scales+100*scaletype;
divisor = 128/subdivs; // we then divide incoming nonzero velocity by this value
inchannel = slider3;
outvel = slider4; // fixed output velocity -- user a slider later
pitchoffset = slider5;

// notes held during channel change will stick

@slider
subdivs = slider1;
scaletype = slider2;
scale = scales+100*scaletype;

divisor = 128/subdivs; // we then divide incoming nonzero velocity by this value
// later versions can do more clever mapping

inchannel = slider3;
outvel = slider4; // fixed output velocity -- user a slider later
pitchoffset = slider5;

// if channel changes, loop through and release all held notes
// later

@block
// will NOT work with multiple channel input
// could add a slider for which channel

while(
midirecv(ts,msg1,msg23) ?
(
    m = msg1&240; // message type
    ch = msg1&15;
    ch == inchannel ? (
      note = msg23&127;
      note += pitchoffset;
      vel = msg23/256;
      (m == 128 || (m == 144 && vel == 0)) ? (
        // note off
        boink = 0;
        noteoff1 = note;
        noteout = noteouts[note];
        notesheld[noteout] > 0 ? (
            notesheld[noteout] -= 1;
        );
        notesheld[noteout] <= 0 ? (
            midisend(ts,msg1,noteout);
            notesheld[noteout] = 0;
        );    
      ) : (m == 144 && vel > 0) ? (
        boink = 1;
        // note on
        veld = vel/divisor; // select subdivision
        pitchoffset = scale[veld];
        noteout = note+pitchoffset;
        noteouts[note] = noteout;
        notesheld[noteout] += 1;
        midisend(ts,msg1,noteout + 256*outvel);
      ) : (
        boink = 2;
        midisend(ts,msg1,msg23); // else echo
      );
    ) : (
      boink = 3;
      midisend(ts,msg1,msg23);
    );
);
);
__________________
John
John Allsup is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 05:45 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.