home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February / PCWorld_2008-02_cd.bin / audio-video / reaper / reaper2028-install.exe / Effects / schwa / midi_humanizer < prev    next >
Text File  |  2007-12-03  |  4KB  |  128 lines

  1. desc:midi velocity and timing humanizer
  2.  
  3. slider1:0<0,127,1>baseline velocity (0: use original) (automate!)
  4. slider2:0<0,1,1{no (subtle timing humanization/bias only),yes (you must shift original midi 1 beat early)}>add 1 beat delay
  5. slider3:0<-10,10>bias timing humanization early or late, msec
  6. slider4:0<0,10>timing humanization level
  7. slider5:0<0,10>velocity humanization level
  8. slider6:0<-30,30>output timing humanization, msec (read-only)
  9. slider7:0<-64,64,1>output velocity humanization (read-only)
  10.  
  11. @init
  12.  
  13.   // We are "humanizing" not "crapifying."
  14.   MAX_VEL_SHIFT = 0.25;  // Fraction of baseline velocity.
  15.   MAX_MSEC_SHIFT = 15; // Only applies if orig is shifted.
  16.   MAX_IS_X_STDEV = 1.5;  // Max shift represents this many std dev.
  17.   
  18.   DEV_N = 12;
  19.   buffer = 0;
  20.   MSG_BUF = 128;  // msg buffer start location.
  21.   memset(0, 0, MSG_BUF);
  22.   n_buf = 0;
  23.  
  24.   NOTE_ON = 9;
  25.   NOTE_OFF = 8;
  26.   AFTERTCH = 10;
  27.  
  28. @block
  29.  
  30.   while (
  31.     midirecv(mpos, msg1, msg23) ? (
  32.  
  33.       bias_samples = srate * slider3 / 1000;
  34.  
  35.       (slider2 == 0) ? (
  36.         baseline_pos_shift = 0;
  37.         min_pos = 0;
  38.     max_pos = samplesblock - 1;
  39.       ) : (
  40.         samples_per_beat = srate * 60 / tempo;
  41.         baseline_pos_shift = samples_per_beat;
  42.     min_pos = baseline_pos_shift - MAX_MSEC_SHIFT / 1000 * srate;
  43.      max_pos = baseline_pos_shift + MAX_MSEC_SHIFT / 1000 * srate;
  44.       );     
  45.  
  46.       msg = (msg1 & 240 ) / 16;
  47.       note_num = msg23 & 127;
  48.       msgvel = (msg23 / 256) | 0;
  49.  
  50.       (msg == NOTE_ON && msgvel > 0) ? (
  51.  
  52.         // Generate two quick & dirty normal deviates.
  53.         z1 = 0;
  54.         z2 = 0;
  55.         loop (DEV_N, 
  56.           z1 += rand(100) / 100;
  57.           z2 += rand(100) / 100;
  58.         );
  59.         z1 -= DEV_N / 2;
  60.         z2 -= DEV_N / 2;
  61.  
  62.     pos_shift = z1 * slider4 / 10;
  63.     pos_shift *= (max_pos - min_pos) / MAX_IS_X_STDEV;
  64.     
  65.     new_pos = mpos + bias_samples + baseline_pos_shift + pos_shift;
  66.     new_pos = max(min_pos, new_pos);
  67.     new_pos = min(new_pos, max_pos);
  68.  
  69.     pos_shift = new_pos - mpos;
  70.     buffer[note_num] = pos_shift;
  71.     mpos = new_pos;
  72.  
  73.         (slider1 == 0) ? (
  74.           velocity = msgvel;
  75.         ) : (
  76.           velocity = slider1;
  77.         );
  78.         min_vel = (1 - MAX_VEL_SHIFT) * velocity;
  79.         max_vel = (1 + MAX_VEL_SHIFT) * velocity;
  80.  
  81.         vel_shift = z2 * slider5 / 10;
  82.     vel_shift *= (max_vel - min_vel) / MAX_IS_X_STDEV;
  83.     vel_shift = floor(vel_shift + 0.5);
  84.         velocity += vel_shift;
  85.         velocity = max(0, velocity);
  86.         velocity = min(velocity, 127);
  87.         velocity |= 0;
  88.         msg23 = note_num + velocity * 256;
  89.  
  90.     msec_shift = (pos_shift - baseline_pos_shift) * 1000 / srate;
  91.     slider6 = floor(msec_shift * 10) / 10;
  92.     slider7 = vel_shift;
  93.     sliderchange(2^6 + 2^7);
  94.       );
  95.  
  96.       (msg == AFTERTCH) ? (
  97.         mpos += buffer[note_num];
  98.       );
  99.  
  100.       (msg == NOTE_OFF || (msg==NOTE_ON && msgvel<1)) ? (
  101.         mpos += buffer[note_num];
  102.         buffer[note_num] = 0;
  103.       ); 
  104.  
  105.       buffer[MSG_BUF+n_buf] = mpos;
  106.       buffer[MSG_BUF+n_buf+1] = msg1;
  107.       buffer[MSG_BUF+n_buf+2] = msg23;
  108.       n_buf += 3;
  109.     );
  110.   );
  111.  
  112.   // Find everything in the buffer that is due
  113.   // to be played back in this block.
  114.   i = 0;
  115.   while (
  116.     (i < n_buf) ? (
  117.       mpos = buffer[MSG_BUF + i];
  118.  
  119.       (mpos < samplesblock) ? (
  120.         midisend(mpos, buffer[MSG_BUF+i+1], buffer[MSG_BUF+i+2]);
  121.         memcpy(MSG_BUF+i, MSG_BUF+i+3, n_buf-i);
  122.         n_buf -= 3;
  123.       ) : (
  124.         buffer[MSG_BUF+i] -= samplesblock;
  125.         i += 3;
  126.       );
  127.     );
  128.   );