
Whar is a Nordler :

 A Nordler is a patch for the Nordler program, and the Nordler program is a
 program that creates arbitrary MIDI output based upon the patches loaded.


About <time> :

 Times are relative to the program start and the timed actions defined by
 this program are sorted on time, so the order of mentioning actions is not
 importatnt, unless actions are scheduled for the same time, in that case
 they are executed in statement order - first action mentioned executes
 first.

 Time is either specified in mili seconds (as an integral number), or
 specified in seconds as a real number (which before usage will be
 converted to integer miliseconds).

 The longest time that can be represented is 2^32 mili seconds, or about
 49 days.

 In subroutines time is relative to the start of of that subroutine. When
 an action contained in a subroutine specifies a start time of 100, and
 the subroutine itself is started at time 50, the action will occur at
 time 150 (relative to the start of the enclosing subroutine, or if no
 enclosing subroutine is present relative to the start of the Nordler).


Some words of help

Out   - a builtin that will perform actual output.
Loop  - a builtin for looping constructs.
Const - a builtin to define constants.

Actions start with a <time>.

Subroutines start with their name, they get a <time> when they are 'called'.

Operators are (from highest to lowest precedence, split into precedence groups) :

Umary

  !  Bitwise inversion                              /* first - highest precedence */
  +  Unary plus, just for completeness
  -  Unary minus

Binary :

  *      Multiplication                             /* second */
  /  DIV Division
  %  MOD Modulo operator - has Pascal semantics
  &  AND Bitwise And                                /* third */
  +      Additition
  -      Subtraction
  |  OR  Bitwise Or
  ^  XOR Bitwise Xor
  == =   Equals                                     /* fourth */
  != <>  Equals not
  <      Less than
  <=     Less than or equal
  >=     Greater than or equal
  >      Greater than                               /* lowest precedence  */

Unary operators have higher precedence than Binary operators,

  3 + -5    ==> 3+(-5)  ==> -2

Binary operators are left associative, evaluation is from left to right

  3 + 2 - 5 ==> (3+2)-5 ==>  0

Unary  operators are right associative

  !-4       ==> !(-4)   ==>  3

Highest precedence is evaluated first

  3 + 4 * 5 ==> 3+(4*5) ==> 23

Parenthesis ( and ) can be used to change the evaluation order:

  (3+4)*5 ==> 35



**************************************************************************
**************************************************************************
**************************************************************************

The following standard definitions are contained in MIDI.nlr, to be found
in the programs Include folder.


    // file : midi.nlr
    // Standard include file for MIDI stuff

    Const CNoteOff         = $80;
    Const CNoteOn          = $90;
    Const CKeyPressure     = $a0;
    Const CControlChange   = $b0;
    Const CProgramChange   = $c0;
    Const CChannelPressure = $d0;
    Const CPitchBend       = $e0;


    // all aCh Parameters accept values 1 .. 16
    // they are translated here into a range of 0 .. 15

    // all aDevice Parameters accept values 1 .. 65535, don't use 0
    // as 0 is predefined to be the NULL device, or the recycle bin.

    NoteOff( aDevice, aCh, aNote, aVel);
    (
      0 Out( aDevice, ( aCh - 1) & $0f | CNoteOff, aNote & $7f, aVel & $7f);
    );

    NoteOn( aDevice, aCh, aNote, aVel);
    (
      0 Out( aDevice, ( aCh - 1) & $0f | CNoteOn, aNote & $7f, aVel & $7f);
    );

    KeyPressure( aDevice, aCh, aNote, aPres);
    (
      0 Out( aDevice, ( aCh - 1) & $0f | CKeyPressure, aNote & $7f, aPres & $7f);
    );

    ControlChange( aDevice, aCh, aCtrlr, aVal);
    (
      0 Out( aDevice, ( aCh - 1) & $0f | CControlChange, aCtrlr & $7f, aVal & $7f);
    );

    ProgramChange( aDevice, aCh, aProgram);
    (
      0 Out( aDevice, ( aCh - 1) & $0f | CProgramChange, aProgram & $7f);
    );

    ChannelPressure( aDevice, aCh, aPres);
    (
      0 Out( aDevice, ( aCh - 1) & $0f | CChannelPressure, aPres & $7f);
    );

    PitchBend( aDevice, aCh, aBend);
    (
      0 Out( aDevice, ( aCh - 1) & $0f | CPitchBend, aBend % $80, ( aBend / $80) % $80);
    );


**************************************************************************
**************************************************************************
**************************************************************************

Additinal definitions used for the Nord Modular are contained in NM.nlr,
also in the Include folder.

    // file : nm.nlr
    // Definitions, to be used with the Nord Modular


    SetVolume( aDevice, aCh, aVal);
    (
      0 ControlChange( aDevice, aCh, 7, aVal);  // Controller 7 is Volume
    );


    // Bank select, valid values for aBank are 1 .. 9

    BankSelect( aDevice, aCh, aBank);
    (
      0 ControlChange( aDevice, aCh, 32, ( aBank - 1) % 9); // Controller 32 is bank select
    );

    // Voice selection for the Nord Modular
    // Program Change : 0 .. 98
    // Bank select    : 0 .. 8
    // Numbering      : 101 .. 199, 201 .. 299, ..., 901 .. 999
    //   a bit odd, but that are the numbers we'll accept here.
    //   Note however that numbers <= 100, 200, 300 .. 900 and >= 1000
    //   will give unwanted results, most likely.

    SelectVoice( aDevice, aCh, aVoice);
    (
      0 BankSelect   ( aDevice, aCh, aVoice        / 100);
      0 ProgramChange( aDevice, aCh, ( aVoice - 1) % 100);
    );

**************************************************************************
**************************************************************************
**************************************************************************

some examples :

// Define a procedure :

  SweepVolume( aDevice, aCh, aStartVal, anEndVal, aTimeStep);
  (
    // Loop :
    //   index variable i
    //   starts at aStartVal
    //   incrementing with aStepSize
    //   until greater/equal than anEndVal
    //   StepSize is optional, default is 1.
    Loop( i, aStartVal, anEndVal, 1);
    (
      i * aTimeStep Volume( aDevice, aCh, i);
      // At time ( i * aTimeStep) set Volume for aCh to i
    );
  );

  // Then use the procedure to make a volume sweep

  0.5 SweepVolume( 1, 1, 0, 127, 0.05);    // Volume up, 128 steps over 6.4
                                           // seconds - on device 1


// /////////////////////////////////////////////////////////////////////////////
// And to do all MIDI channels we now can define :

  SweepAllVolumes( aDevice, aStartVal, anEndVal, aTimeStep);
  (
    Loop( i, 0, 15);   // Remember: Step size is optional, default is 1.
    (
      // At time 0 (relative to procedure start do :

      0 SweepVolume( aDevice, i, aStartVal, anEndVal, aTimeStep);
    );
  );

  // To be used as :

  10.0 SweepAllVolumes( 1, 0, 127, 0.05);  // in 128 * 0.05 = 6.4 seconds sweep
                                           // all volumes in the channels 0 to 15
                                           // on device 1.

// /////////////////////////////////////////////////////////////////////////////

