desc:Random MIDI note generator
//tags: MIDI generator
//author: Tale

// Copyright (C) 2011-2017 Theo Niessink
// License: LGPL - http://www.gnu.org/licenses/lgpl.html

// This effect generates random MIDI notes while playing or recording (but
// not while transport is paused or stopped). Insert this effect before a
// virtual instrument for instant experimental "music".

// Although seemingly random, this effect will generate the same sequence of
// notes each time playback starts.

slider1:1<1,127>Polyphony
slider2:0<0,127,1>Min Note
slider3:127<0,127,1>Max Note
slider4:0<0,1,1{Note On,Note On/Off}>Velocity Mode
slider5:0<0,127,1>Min Velocity
slider6:127<0,127,1>Max Velocity
slider7:100.0<0.0,5000.0,1.0>Min Length (ms)
slider8:500.0<0.0,5000.0,1.0>Max Length (ms)
slider9:1<1,16,1>MIDI Ch

import noise.jsfx-inc

@init

msrate = srate * 0.001;

@slider

function int(i, lo, hi) ( max(lo, min(hi, i|0)); );

function swap(lo, hi)
(
  hi >= lo ? (
    hi = hi - lo + 1;
  ) : (
    stack_push(lo);
    lo = hi;
    hi = stack_pop() - lo + 1;
  );

  stack_push(hi);
  lo;
);

poly = int(slider1, 1, 127) + 1;

min_note = int(slider2, 0, 127);
max_note = int(slider3, 0, 127);
min_note = swap(min_note, max_note);
stack_pop(max_note);

vel_mode = slider4 >= 0.5;

min_vel = int(slider5, 0, 127);
max_vel = int(slider6, 0, 127);
min_vel = swap(min_vel, max_vel);
stack_pop(max_vel);

min_len = max(1, slider7 * msrate + 0.5 |0);
max_len = max(1, slider8 * msrate + 0.5 |0);
min_len = swap(min_len, max_len);
stack_pop(max_len);

midi_ch = max(1, min(16, slider9|0)) - 1;

@block

play_state != last_state ? (
  last_state = play_state;

  play_state <= 0 ? (
    all_notes_off = 1;
  ) : (
    play = play_state & 1 ? 1 : 2;
  );
);

while(
  midirecv(ofs, msg1, msg23) ? (
    msg1 == 0xB0 | midi_ch && msg23 & 0x7F == 123 ? all_notes_off = 1;
    midisend(ofs, msg1, msg23);
  );
);

all_notes_off ? (
  num_notes > 1 || (num_notes == 1 && matrix[128] <= 0) ? (
    msg1 = 0xB0 | midi_ch;
    msg23 = 123;
    midisend(0, msg1, msg23);
  );
  num_notes = 0;
  memset(matrix, 0, 129);
  all_notes_off = play = 0;
) :

play ? (
  play == 1 && num_notes < poly ? (
    i = rng.lcg_rand2(poly) ? min_note + rng.lcg_rand2(max_note) |0 : 128;
    matrix[i] <= 0 && (i == 128 || num_notes < poly - 1) ? (
      ofs = rng.lcg_rand2(samplesblock)|0;
      i <= 127 ? (      
        msg1 = 0x90 | midi_ch;
        msg23 = (max(min_vel, 1) + rng.lcg_rand2(min(max_vel, 127)) |0) << 8 | i;
        midisend(ofs, msg1, msg23);
      );
      matrix[i] = ofs + min_len + rng.lcg_rand2(1)^3 * max_len + 2 |0;
      num_notes += 1;
    );
  );

  i = 0;
  loop(129,
    matrix[i] > 0 ? (
      matrix[i] -= samplesblock;
      matrix[i] <= 0 ? (
        i <= 127 ? (
          ofs = matrix[i] + samplesblock - 1;
          vel_mode ? (
            msg1 = 0x80 | midi_ch;
            msg23 = (min_vel + rng.lcg_rand2(max_vel) |0) << 8 | i;
          ) : (
            msg1 = 0x90 | midi_ch;
            msg23 = i;
          );
          midisend(ofs, msg1, msg23);
        );
        num_notes -= 1;
      );
    );
    i += 1;
  );
);
