//
// Get correct value from exp table. For exp->lin conversion of exponentional inputs
//
static inline int expval(int value) {
  if (value>32767) return 32767;
  if (value<=0) return 0;
  return EXPTBL16[value];
}
 


//
// Get correct value from exp table. For exp->lin conversion of exponentional inputs.
// This is only used for OSC objects!
//
static inline int exposc(int value) {
  if (value>32767) return EXPTBL32[32767];
  if (value<=0) return 0;
  return EXPTBL32[value];
}



//
// return positive values only, if input negative return zero.
//
static inline int pos(int value) {
  if (value>=32767) return 32767;
  if (value<=0) return 0;
  return value;
}



//
// return negative values only, if input positive return zero.
//
static inline int neg(int value) {
  if (value<=-32768) return -32768;
  if (value>=0) return 0;
  return value;
}



//
// Limit to half nyquist frequency (and positive)
//
static inline int posVCF(int value) {
  if (value>=21000) return 21000;
  if (value<=0) return 0;
  return value;
}



//
// Limit to short
//
static inline int limit(int value) {
  if (value>=32767) return 32767;
  if (value<=-32767) return -32767;
  return value;
}


//
// Convert string in the form 'C', 'C4' or 'C#4' to frequency
// result is 0 if conversion failed. (string is not a note)
//
static int StringToNote(const char *str, int *octave) {
  switch(str[0]) {
  case 'c': case 'C':
    if (str[1]=='#') {
      if (str[2]>='0' && str[2]<='9') {
        *octave=(str[2]-'0')*2184;
      }
      return (*octave)+12431;
    } else {
      if (str[1]>='0' && str[1]<='9') {
        *octave=(str[1]-'0')*2184;
      }
      return (*octave)+12249;
    }
    break;
  case 'd': case 'D':
    if (str[1]=='#') {
      if (str[2]>='0' && str[2]<='9') {
        *octave=(str[2]-'0')*2184;
      }
      return (*octave)+12794;
    } else {
      if (str[1]>='0' && str[1]<='9') {
        *octave=(str[1]-'0')*2184;
      }
      return (*octave)+12613;
    }
    break;
  case 'e': case 'E':
    if (str[1]=='#') {
      if (str[2]>='0' && str[2]<='9') {
        *octave=(str[2]-'0')*2184;
      }
      return (*octave)+13157; // E#=F
    } else {
      if (str[1]>='0' && str[1]<='9') {
        *octave=(str[1]-'0')*2184;
      }
      return (*octave)+12976;
    }
    break;
  case 'f': case 'F':
    if (str[1]=='#') {
      if (str[2]>='0' && str[2]<='9') {
        *octave=(str[2]-'0')*2184;
      }
      return (*octave)+13339;
    } else {
      if (str[1]>='0' && str[1]<='9') {
        *octave=(str[1]-'0')*2184;
      }
      return (*octave)+13157;
    }
    break;
  case 'g': case 'G':
    if (str[1]=='#') {
      if (str[2]>='0' && str[2]<='9') {
        *octave=(str[2]-'0')*2184;
      }
      return (*octave)+13702;
    } else {
      if (str[1]>='0' && str[1]<='9') {
        *octave=(str[1]-'0')*2184;
      }
      return (*octave)+13521;
    }
    break;
  case 'a': case 'A':
    if (str[1]=='#') {
      if (str[2]>='0' && str[2]<='9') {
        *octave=(str[2]-'0')*2184;
      }
      return (*octave)+14066;
    } else {
      if (str[1]>='0' && str[1]<='9') {
        *octave=(str[1]-'0')*2184;
      }
      return (*octave)+13884;
    }
    break;
  case 'b': case 'B':
    if (str[1]=='#') {
      if (str[2]>='0' && str[2]<='9') {
        *octave=(str[2]-'0')*2184;
      }
      return (*octave)+14429; // B#=C
    } else {
      if (str[1]>='0' && str[1]<='9') {
        *octave=(str[1]-'0')*2184;
      }
      return (*octave)+14248;
    }
    break;
  default:
    break;
  }

  return 0;
}


//
// Dummy routine
//
static void dspRoutine_Dummy(DspObject *object) {
}

//
// Mini Oscillator module
//
static void dspRoutine_MOS(DspObject *object) {
#if 0
  int old=object->io[0].intern;
  int pw =*object->io[2].input;
  object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input) + (*object->io[1].input<<14);

  object->io[0].output = (short)(((object->io[0].intern >> 15)^((object->io[0].intern & 0x80000000)?0x7FFF:0x8000)));
  object->io[1].output = ((short)(old >> 16) + (short)(object->io[0].intern >> 16))/2;          
  object->io[2].output = (((old >> 16) > pw)?(16383):(-16384)) + (((short)(object->io[0].intern >> 16) > pw)?(16383):(-16384));
#else
  int old=object->io[0].intern;
  int pw =*object->io[2].input;
  int freq = exposc(object->io[0].knob + *object->io[0].input) + (*object->io[1].input<<14);
  int value=((object->io[0].intern+(freq/4))>>3)+
            ((object->io[0].intern+(freq/2))>>3)+
            ((object->io[0].intern+3*(freq/4))>>3)+
            ((object->io[0].intern+freq)>>3);
  object->io[0].intern += freq;

  object->io[0].output = (short)(((object->io[0].intern >> 15)^((object->io[0].intern & 0x80000000)?0x7FFF:0x8000)));
  object->io[1].output = value>>15;          
  object->io[2].output = (((old >> 16) > pw)?(16383):(-16384)) + (((short)(object->io[0].intern >> 16) > pw)?(16383):(-16384));
#endif
}

//
// White/colored noise source
//
static void dspRoutine_RND(DspObject *object) {
  dspRnd1 = dspRnd1*16807 ^ (dspRnd2++);
  object->io[0].intern += (((short)(dspRnd1 >> 16) - object->io[0].intern) * pos(object->io[0].knob)) >> 15;
  object->io[0].output = (object->io[0].intern * (object->io[2].knob + *object->io[0].input)) >> 15;
}

//
// Formant oscillator
//
static void dspRoutine_FRM(DspObject *object) {
  // Intern0              main oscillator
  // Intern1 and Intern2  formant generator
  object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input) + (*object->io[1].input<<13);
  if ((short)(object->io[0].intern>>13)<0) {
    object->io[0].intern = 0;
    object->io[1].intern = 0;
    object->io[2].intern = 0;
  } else {
    object->io[1].intern ^= (object->io[2].intern);
    object->io[2].intern += object->io[2].knob + *object->io[2].input;
  }
  object->io[0].output = ((short)(object->io[1].intern) * (object->io[4].knob + *object->io[3].input)) >> 15;
}

//
// Multiple octave sinewave oscillator (additive synthesis)
//
static void dspRoutine_SINEBANK(DspObject *object) {
  object->io[0].intern += exposc(object->io[1].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  object->io[0].output = ((SINTBL[32768+(short)(object->io[0].intern >> 16)] * (object->io[0].knob + *object->io[3].input)) >> 15) + // base
                   ((SINTBL[32768+(short)(object->io[0].intern >> 15)] * (object->io[2].knob + *object->io[4].input)) >> 15) + // base*2
                   ((SINTBL[32768+(short)((object->io[0].intern*3) >> 16)] * (object->io[3].knob + *object->io[5].input)) >> 15) + // base*3
                   ((SINTBL[32768+(short)(object->io[0].intern >> 14)] * (object->io[4].knob + *object->io[6].input)) >> 15) + // base*4
                   ((SINTBL[32768+(short)((object->io[0].intern*5) >> 16)] * (object->io[5].knob + *object->io[7].input)) >> 15) + // base*5
                   ((SINTBL[32768+(short)((object->io[0].intern*6) >> 16)] * (object->io[6].knob + *object->io[8].input)) >> 15) + // base*6
                   ((SINTBL[32768+(short)((object->io[0].intern*7) >> 16)] * (object->io[7].knob + *object->io[9].input)) >> 15) + // base*7
                   ((SINTBL[32768+(short)(object->io[0].intern >> 13)] * (object->io[8].knob + *object->io[10].input)) >> 15)+ // base*8
                   ((SINTBL[32768+(short)((object->io[0].intern*9) >> 16)] * (object->io[9].knob + *object->io[11].input)) >> 15); // base*9
}

//
// PerlinNoise based oscillator
//
static const int COSTABLE[1024]={
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   2,
   2,   2,   2,   2,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   5,   5,
   5,   5,   6,   6,   6,   6,   7,   7,   7,   7,   8,   8,   8,   8,   9,   9,
   9,  10,  10,  10,  11,  11,  11,  12,  12,  12,  13,  13,  13,  14,  14,  14,
  15,  15,  16,  16,  16,  17,  17,  18,  18,  18,  19,  19,  20,  20,  21,  21,
  22,  22,  22,  23,  23,  24,  24,  25,  25,  26,  26,  27,  27,  28,  28,  29,
  29,  30,  30,  31,  32,  32,  33,  33,  34,  34,  35,  36,  36,  37,  37,  38,
  38,  39,  40,  40,  41,  42,  42,  43,  43,  44,  45,  45,  46,  47,  47,  48,
  49,  49,  50,  51,  51,  52,  53,  53,  54,  55,  56,  56,  57,  58,  58,  59,
  60,  61,  61,  62,  63,  64,  64,  65,  66,  67,  68,  68,  69,  70,  71,  72,
  72,  73,  74,  75,  76,  76,  77,  78,  79,  80,  81,  81,  82,  83,  84,  85,
  86,  87,  88,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  97,  98,  99,
 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
 132, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
 149, 151, 152, 153, 154, 155, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166,
 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 181, 182, 183, 184, 185,
 187, 188, 189, 190, 192, 193, 194, 195, 197, 198, 199, 200, 201, 203, 204, 205,
 207, 208, 209, 210, 212, 213, 214, 215, 217, 218, 219, 221, 222, 223, 224, 226,
 227, 228, 230, 231, 232, 234, 235, 236, 238, 239, 240, 242, 243, 244, 246, 247,
 248, 250, 251, 252, 254, 255, 256, 258, 259, 261, 262, 263, 265, 266, 267, 269,
 270, 272, 273, 274, 276, 277, 278, 280, 281, 283, 284, 286, 287, 288, 290, 291,
 293, 294, 295, 297, 298, 300, 301, 303, 304, 305, 307, 308, 310, 311, 313, 314,
 316, 317, 318, 320, 321, 323, 324, 326, 327, 329, 330, 332, 333, 335, 336, 338,
 339, 340, 342, 343, 345, 346, 348, 349, 351, 352, 354, 355, 357, 358, 360, 361,
 363, 364, 366, 367, 369, 370, 372, 373, 375, 376, 378, 379, 381, 383, 384, 386,
 387, 389, 390, 392, 393, 395, 396, 398, 399, 401, 402, 404, 405, 407, 409, 410,
 412, 413, 415, 416, 418, 419, 421, 422, 424, 426, 427, 429, 430, 432, 433, 435,
 436, 438, 439, 441, 443, 444, 446, 447, 449, 450, 452, 454, 455, 457, 458, 460,
 461, 463, 464, 466, 468, 469, 471, 472, 474, 475, 477, 479, 480, 482, 483, 485,
 486, 488, 490, 491, 493, 494, 496, 497, 499, 501, 502, 504, 505, 507, 508, 510,
 512, 513, 515, 516, 518, 519, 521, 522, 524, 526, 527, 529, 530, 532, 533, 535,
 537, 538, 540, 541, 543, 544, 546, 548, 549, 551, 552, 554, 555, 557, 559, 560,
 562, 563, 565, 566, 568, 569, 571, 573, 574, 576, 577, 579, 580, 582, 584, 585,
 587, 588, 590, 591, 593, 594, 596, 597, 599, 601, 602, 604, 605, 607, 608, 610,
 611, 613, 614, 616, 618, 619, 621, 622, 624, 625, 627, 628, 630, 631, 633, 634,
 636, 637, 639, 640, 642, 644, 645, 647, 648, 650, 651, 653, 654, 656, 657, 659,
 660, 662, 663, 665, 666, 668, 669, 671, 672, 674, 675, 677, 678, 680, 681, 683,
 684, 685, 687, 688, 690, 691, 693, 694, 696, 697, 699, 700, 702, 703, 705, 706,
 707, 709, 710, 712, 713, 715, 716, 718, 719, 720, 722, 723, 725, 726, 728, 729,
 730, 732, 733, 735, 736, 737, 739, 740, 742, 743, 745, 746, 747, 749, 750, 751,
 753, 754, 756, 757, 758, 760, 761, 762, 764, 765, 767, 768, 769, 771, 772, 773,
 775, 776, 777, 779, 780, 781, 783, 784, 785, 787, 788, 789, 791, 792, 793, 795,
 796, 797, 799, 800, 801, 802, 804, 805, 806, 808, 809, 810, 811, 813, 814, 815,
 816, 818, 819, 820, 822, 823, 824, 825, 826, 828, 829, 830, 831, 833, 834, 835,
 836, 838, 839, 840, 841, 842, 844, 845, 846, 847, 848, 849, 851, 852, 853, 854,
 855, 857, 858, 859, 860, 861, 862, 863, 865, 866, 867, 868, 869, 870, 871, 872,
 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 886, 887, 888, 889, 890,
 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906,
 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922,
 923, 924, 925, 926, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 935, 936,
 937, 938, 939, 940, 941, 942, 942, 943, 944, 945, 946, 947, 947, 948, 949, 950,
 951, 951, 952, 953, 954, 955, 955, 956, 957, 958, 959, 959, 960, 961, 962, 962,
 963, 964, 965, 965, 966, 967, 967, 968, 969, 970, 970, 971, 972, 972, 973, 974,
 974, 975, 976, 976, 977, 978, 978, 979, 980, 980, 981, 981, 982, 983, 983, 984,
 985, 985, 986, 986, 987, 987, 988, 989, 989, 990, 990, 991, 991, 992, 993, 993,
 994, 994, 995, 995, 996, 996, 997, 997, 998, 998, 999, 999,1000,1000,1001,1001,
1001,1002,1002,1003,1003,1004,1004,1005,1005,1005,1006,1006,1007,1007,1007,1008,
1008,1009,1009,1009,1010,1010,1010,1011,1011,1011,1012,1012,1012,1013,1013,1013,
1014,1014,1014,1015,1015,1015,1015,1016,1016,1016,1016,1017,1017,1017,1017,1018,
1018,1018,1018,1019,1019,1019,1019,1019,1020,1020,1020,1020,1020,1021,1021,1021,
1021,1021,1021,1021,1022,1022,1022,1022,1022,1022,1022,1022,1023,1023,1023,1023,
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023};
static inline int cerp(int x1, int x2, int t) {
  return x1+(((x2-x1)*COSTABLE[t])>>10);
}

static inline int lerp(int x1, int x2, int t) {
  return x1+(((x2-x1)*t)>>10);
}

static int noise2d(int x, int y) {
  return (PERLINTBL[PERLINTBL[y]^PERLINTBL[(PERLINTBL[x^y]^PERLINTBL[x])]]-128)*256;
}

static int noise(int x, int y) {
  int xs=(x>>5)&127;
  int ys=(y>>5)&255;
  int xsp=(xs+1)&127;
  int ysp=(ys+1)&255;
  int a=cerp(noise2d(xs, ys), noise2d(xsp, ys), (x&31)*32);
  int b=cerp(noise2d(xs, ysp), noise2d(xsp, ysp), (x&31)*32);
  return lerp(a, b, (y&31)*32);
  return a;
}

static void dspRoutine_PERLIN_L(DspObject *object) {
	if (*object->io[6].input > 0 && object->io[6].intern<=0) {
		object->io[0].intern = 0;
	} else {
		object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
	}
  int wave = limit(*object->io[3].input + object->io[2].knob);
  int harm = limit(*object->io[4].input + object->io[4].knob);
  int ampl = limit(*object->io[5].input + object->io[6].knob);
  int value;
  

  value  = (noise(object->io[0].intern>>20, wave)*ampl)/32768;
  ampl=(ampl*harm)/32768;
  value += (noise(object->io[0].intern>>19, wave+4321)*ampl)/32768;
  ampl=(ampl*harm)/32768;
  value += (noise(object->io[0].intern>>18, wave+6543)*ampl)/32768;
  object->io[0].output = value;
  object->io[6].intern = *object->io[6].input;
}

static void dspRoutine_PERLIN_M(DspObject *object) {
	if (*object->io[6].input > 0 && object->io[6].intern<=0) {
		object->io[0].intern = 0;
	} else {
		object->io[0].intern += 2*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
	}
  int wave = limit(*object->io[3].input + object->io[2].knob);
  int harm = limit(*object->io[4].input + object->io[4].knob);
  int ampl = limit(*object->io[5].input + object->io[6].knob);
  int value;
  

  value  = (noise(object->io[0].intern>>20, wave)*ampl)/32768;
  ampl=(ampl*harm)/32768;
  value += (noise(object->io[0].intern>>19, wave+4321)*ampl)/32768;
  ampl=(ampl*harm)/32768;
  value += (noise(object->io[0].intern>>18, wave+6543)*ampl)/32768;
  object->io[0].output = value;
  object->io[6].intern = *object->io[6].input;
}

static void dspRoutine_PERLIN_H(DspObject *object) {
	if (*object->io[6].input > 0 && object->io[6].intern<=0) {
		object->io[0].intern = 0;
	} else {
		object->io[0].intern += 4*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
	}
  int wave = limit(*object->io[3].input + object->io[2].knob);
  int harm = limit(*object->io[4].input + object->io[4].knob);
  int ampl = limit(*object->io[5].input + object->io[6].knob);
  int value;
  

  value  = (noise(object->io[0].intern>>20, wave)*ampl)/32768;
  ampl=(ampl*harm)/32768;
  value += (noise(object->io[0].intern>>19, wave+4321)*ampl)/32768;
  ampl=(ampl*harm)/32768;
  value += (noise(object->io[0].intern>>18, wave+6543)*ampl)/32768;
  object->io[0].output = value;
  object->io[6].intern = *object->io[6].input;
}

//
// Oscillator with phase modulation
//
static void dspRoutine_PMOSC_L(DspObject *object) {
	if (*object->io[7].input > 0 && object->io[7].intern<=0) {
		object->io[0].intern = 0;
	} else {
		object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
	}

	int fb = object->io[1].output * limit(*object->io[5].input + object->io[2].knob);
	int p = ((object->io[0].intern + fb/2)>>16) + 2*(*object->io[3].input + *object->io[4].input);
	object->io[1].output = SINTBL[32768+(short)p];
	object->io[0].output = (object->io[1].output * limit(*object->io[6].input + object->io[4].knob)) >> 15;
	object->io[7].intern = *object->io[7].input;
}

static void dspRoutine_PMOSC_M(DspObject *object) {
	int v = object->io[0].intern + 2*(exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14));

	int fb = object->io[1].output * limit(*object->io[5].input + object->io[2].knob);
	int p = ((v + fb/2)>>16) + 2*(*object->io[3].input + *object->io[4].input);
	object->io[0].intern = v;
	object->io[1].output = SINTBL[32768+(short)p];
	object->io[0].output = (object->io[1].output * limit(*object->io[6].input + object->io[4].knob)) >> 15;
}

static void dspRoutine_PMOSC_H(DspObject *object) {
	int v = object->io[0].intern + 4*(exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14));

	int fb = object->io[1].output * limit(*object->io[5].input + object->io[2].knob);
	int p = ((v + fb/2)>>16) + 2*(*object->io[3].input + *object->io[4].input);
	object->io[0].intern = v;
	object->io[1].output = SINTBL[32768+(short)p];
	object->io[0].output = (object->io[1].output * limit(*object->io[6].input + object->io[4].knob)) >> 15;
}

static void dspRoutine_WALSH(DspObject *object) {
	int v = object->io[0].intern + exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
	object->io[0].intern = v;
	object->io[0].output =
		((v&0x80000000)?
			object->io[2].knob:-object->io[2].knob)+
		((((v>>1)^v)&0x40000000)?
			object->io[3].knob:-object->io[3].knob)+
		((v&0x40000000)?
			object->io[4].knob:-object->io[4].knob)+
		((((v>>1)^v)&0x20000000)?
			object->io[5].knob:-object->io[5].knob)+
		((((v>>2)^(v>>1)^v)&0x20000000)?
			object->io[6].knob:-object->io[6].knob)+
		((((v>>2)^v)&0x20000000)?
			object->io[7].knob:-object->io[7].knob)+
		((v&0x20000000)?
			object->io[8].knob:-object->io[8].knob)+
		((((v>>1)^v)&0x10000000)?
			object->io[9].knob:-object->io[9].knob)+
		((((v>>3)^(v>>1)^v)&0x10000000)?
			object->io[10].knob:-object->io[10].knob)+
		((((v>>3)^(v>>2)^(v>>1)^v)&0x10000000)?
			object->io[11].knob:-object->io[11].knob)+
		((((v>>2)^(v>>1)^v)&0x10000000)?
			object->io[12].knob:-object->io[12].knob)+
		((((v>>2)^v)&0x10000000)?
			object->io[13].knob:-object->io[13].knob)+
		((((v>>3)^(v>>2)^v)&0x10000000)?
			object->io[14].knob:-object->io[14].knob)+
		((((v>>3)^v)&0x10000000)?
			object->io[15].knob:-object->io[15].knob)+
		((v&0x10000000)?
			object->io[16].knob:-object->io[16].knob)+
		((((v>>1)^v)&0x08000000)?
			object->io[17].knob:-object->io[17].knob);
}


//
// Variable resonance filter (Oberheim type)
//
static void dspRoutine_VCF(DspObject *object) {
  int inp = (*object->io[0].input) + (*object->io[1].input) + (*object->io[2].input);
  int cutoff = posVCF(object->io[0].knob + *object->io[4].input + *object->io[5].input);
  int resonance = posVCF(object->io[1].knob + *object->io[6].input);

  object->io[2].output  = limit(inp + ((object->io[1].output*resonance) >> 13) - object->io[0].output*4);
  object->io[1].output += (((object->io[2].output - object->io[1].output)*cutoff) >> 15);
  object->io[0].output += (((object->io[1].output - object->io[0].output)*cutoff) >> 15);
}

//
// Multi mode filter with 12/18/24 dB/oct slope
//
static void dspRoutine_MMF(DspObject *object) {
  int inp = ((*object->io[0].input) +
             (*object->io[1].input) +
             (*object->io[2].input) -
             ((object->io[0].output*pos(object->io[3].knob)>>14))) >> 1;
  int cutoff = posVCF(object->io[0].knob + *object->io[4].input + *object->io[5].input) + 20;
  int resonance = posVCF(object->io[2].knob + *object->io[6].input);

  object->io[0].intern+= ((limit(inp + (((object->io[3].output)*resonance)>>14)) - object->io[0].intern) *cutoff) >> 15;
  object->io[0].output   += ((object->io[0].intern - object->io[0].output) *cutoff) >> 15;  // LP12
  object->io[1].output   += ((object->io[0].output - object->io[1].output) *cutoff) >> 15;     // LP18
  object->io[2].output   += ((object->io[1].output - object->io[2].output) *cutoff) >> 15;     // LP24
  object->io[3].output   =  object->io[0].intern-object->io[2].output;                      // BP
  object->io[4].output   =  limit(inp)-object->io[0].output;                             // HP12
}

//
// Amplitude modulator
//
static void dspRoutine_VCA(DspObject *object) {
  int ampl = pos(*object->io[2].input + expval(object->io[0].knob + *object->io[1].input));

  object->io[0].output = (*object->io[0].input * ampl) >> 13;
}

//
// Adders
//
static void dspRoutine_ADD1(DspObject *object) {
  object->io[0].output = *object->io[0].input;
}
static void dspRoutine_ADD2(DspObject *object) {
  object->io[0].output = *object->io[0].input + *object->io[1].input;
}
static void dspRoutine_ADD3(DspObject *object) {
  object->io[0].output = *object->io[0].input + *object->io[1].input +
                   *object->io[2].input;
}
static void dspRoutine_ADD4(DspObject *object) {
  object->io[0].output = *object->io[0].input + *object->io[1].input +
                   *object->io[2].input + *object->io[3].input;
}
static void dspRoutine_ADD5(DspObject *object) {
  object->io[0].output = *object->io[0].input + *object->io[1].input +
                   *object->io[2].input + *object->io[3].input +
                   *object->io[4].input;
}
static void dspRoutine_ADD6(DspObject *object) {
  object->io[0].output = *object->io[0].input + *object->io[1].input +
                   *object->io[2].input + *object->io[3].input +
                   *object->io[4].input + *object->io[5].input;
}
static void dspRoutine_ADD7(DspObject *object) {
  object->io[0].output = *object->io[0].input + *object->io[1].input +
                   *object->io[2].input + *object->io[3].input +
                   *object->io[4].input + *object->io[5].input +
                   *object->io[6].input;
}
static void dspRoutine_ADD8(DspObject *object) {
  object->io[0].output = *object->io[0].input + *object->io[1].input +
                   *object->io[2].input + *object->io[3].input +
                   *object->io[4].input + *object->io[5].input +
                   *object->io[6].input + *object->io[7].input;
}

//
// Ringmodulator
//
static void dspRoutine_MUL(DspObject *object) {
  object->io[0].output = (*object->io[0].input * *object->io[1].input) >> 15;
}

//
// Inverting adder
//
static void dspRoutine_SUB(DspObject *object) {
  object->io[0].output = (*object->io[1].input)-(*object->io[0].input);
}

//
// Divide
//
static void dspRoutine_DIV(DspObject *object) {
	int div = *object->io[1].input;
	if (0 == div) div = 1;
	object->io[0].output = limit((*object->io[0].input)*(*object->io[2].input+object->io[0].knob)/div);
//	if (0 == div) {
//		object->io[0].output = 0;
//	} else {
//		object->io[0].output = limit((*object->io[0].input)*object->io[0].knob/div);
//	}
}

//
// Split signal in positive and negative signal
//
static void dspRoutine_SPLIT(DspObject *object) {
  int inp=*object->io[0].input;
  object->io[0].output = (inp>0)?inp:0;
  object->io[1].output = (inp<0)?inp:0;
  object->io[2].output = abs(inp);
}

//
// Get min and max of two signals
//
static void dspRoutine_MINMAX(DspObject *object) {
	int a = *object->io[0].input;
	int b = *object->io[1].input;
	object->io[0].output = (a<b)?a:b;
	object->io[1].output = (a>b)?a:b;
}

//
// Window comparator and clipping module
//
static void dspRoutine_BETWEEN(DspObject *object) {
  int inp=*object->io[0].input;
  int a=((*object->io[1].input) + object->io[0].knob);
  int b=((*object->io[2].input) + object->io[2].knob);
  int minv=min(a,b);
  int maxv=max(a,b);
  object->io[0].output = (inp>minv)?((inp<maxv)?inp:maxv):minv;
  object->io[1].output = (minv<=inp && inp<=maxv)?32767:0;
  object->io[2].output = 32767-object->io[1].output;
}

//
// EXP2LIN
//
static void dspRoutine_EXPLIN(DspObject *object) {
  object->io[0].output = limit((exposc(*object->io[0].input + *object->io[1].input)>>14)+(*object->io[2].input)+(*object->io[3].input));
}

//
// 2 input logic OR
//
static void dspRoutine_OR1(DspObject *object) {
  object->io[0].output = (*object->io[0].input>0)?32767:0;
}
static void dspRoutine_OR2(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) || (*object->io[1].input>0))?32767:0;
}

//
// 3 input logic OR
//
static void dspRoutine_OR3(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) || (*object->io[1].input>0) ||
                    (*object->io[2].input>0))?32767:0;
}

//
// 4 input logic OR
//
static void dspRoutine_OR4(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) || (*object->io[1].input>0) ||
                    (*object->io[2].input>0) || (*object->io[3].input>0))?32767:0;
}

//
// 5 input logic OR
//
static void dspRoutine_OR5(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) || (*object->io[1].input>0) ||
                    (*object->io[2].input>0) || (*object->io[3].input>0) ||
                    (*object->io[4].input>0))?32767:0;
}

//
// 6 input logic OR
//
static void dspRoutine_OR6(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) || (*object->io[1].input>0) ||
                    (*object->io[2].input>0) || (*object->io[3].input>0) ||
                    (*object->io[4].input>0) || (*object->io[5].input>0))?32767:0;
}

//
// 7 input logic OR
//
static void dspRoutine_OR7(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) || (*object->io[1].input>0) ||
                    (*object->io[2].input>0) || (*object->io[3].input>0) ||
                    (*object->io[4].input>0) || (*object->io[5].input>0) ||
                    (*object->io[6].input>0))?32767:0;
}

//
// 8 input logic OR
//
static void dspRoutine_OR8(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) || (*object->io[1].input>0) ||
                    (*object->io[2].input>0) || (*object->io[3].input>0) ||
                    (*object->io[4].input>0) || (*object->io[5].input>0) ||
                    (*object->io[6].input>0) || (*object->io[7].input>0))?32767:0;
}

//
// AND routines
//
static void dspRoutine_AND1(DspObject *object) {
  object->io[0].output = (*object->io[0].input>0)?32767:0;
}
static void dspRoutine_AND2(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) && (*object->io[1].input>0))?32767:0;
}
static void dspRoutine_AND3(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) && (*object->io[1].input>0) && (*object->io[2].input>0))?32767:0;
}
static void dspRoutine_AND4(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) && (*object->io[1].input>0) && (*object->io[2].input>0) && (*object->io[3].input>0))?32767:0;
}
static void dspRoutine_AND5(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) && (*object->io[1].input>0) && (*object->io[2].input>0) && (*object->io[3].input>0)
                       && (*object->io[4].input>0))?32767:0;
}
static void dspRoutine_AND6(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) && (*object->io[1].input>0) && (*object->io[2].input>0) && (*object->io[3].input>0)
                       && (*object->io[4].input>0) && (*object->io[5].input>0))?32767:0;
}
static void dspRoutine_AND7(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) && (*object->io[1].input>0) && (*object->io[2].input>0) && (*object->io[3].input>0)
                       && (*object->io[4].input>0) && (*object->io[5].input>0) && (*object->io[6].input>0))?32767:0;
}
static void dspRoutine_AND8(DspObject *object) {
  object->io[0].output = ((*object->io[0].input>0) && (*object->io[1].input>0) && (*object->io[2].input>0) && (*object->io[3].input>0)
                       && (*object->io[4].input>0) && (*object->io[5].input>0) && (*object->io[6].input>0) && (*object->io[7].input>0))?32767:0;
}


//
// Logic NOT
//
static void dspRoutine_NOT(DspObject *object) {
  object->io[0].output = (*object->io[0].input>0)?0:32767;
}

//
// Logic Exclusive OR
//
static void dspRoutine_XOR(DspObject *object) {
  object->io[0].output = (((*object->io[0].input>0) && (*object->io[1].input<=0)) ||
                    ((*object->io[0].input<=0) && (*object->io[1].input>0)))?32767:0;
}

//
// ADC
//
static void dspRoutine_ADC(DspObject *object) {
  int inp=*object->io[0].input;
  int ainp=abs(inp);

  object->io[0].output=(ainp&128)?32767:0;
  object->io[1].output=(ainp&256)?32767:0;
  object->io[2].output=(ainp&512)?32767:0;
  object->io[3].output=(ainp&1024)?32767:0;
  object->io[4].output=(ainp&2048)?32767:0;
  object->io[5].output=(ainp&4096)?32767:0;
  object->io[6].output=(ainp&8192)?32767:0;
  object->io[7].output=(ainp&16384)?32767:0;
  object->io[8].output=(inp<0)?32767:0;
}

//
// DAC
//
static void dspRoutine_DAC(DspObject *object) {
  int out=((*object->io[0].input>0)?128:0)+
          ((*object->io[1].input>0)?256:0)+
          ((*object->io[2].input>0)?512:0)+
          ((*object->io[3].input>0)?1024:0)+
          ((*object->io[4].input>0)?2048:0)+
          ((*object->io[5].input>0)?4096:0)+
          ((*object->io[6].input>0)?8192:0)+
          ((*object->io[7].input>0)?16384:0);
  object->io[0].output=(*object->io[8].input>0)?-out:out;
}

//
// Logic counter/divider
//
static void dspRoutine_CNT(DspObject *object) {
  // Intern[6] is set if outputs are active and needs to be reset (module generates single pulse only)
  int reset=*object->io[7].input;
  if (object->io[6].intern) {
    object->io[0].output = 0;
    object->io[1].output = 0;
    object->io[2].output = 0;
    object->io[3].output = 0;
    object->io[4].output = 0;
    object->io[5].output = 0;
    object->io[6].output = 0;
    object->io[7].output = 0;
    object->io[6].intern=0;
  }
  if (reset > 0) {
    // Reset
    object->io[0].intern = 0; // Div 2/4/8/16 counter
    object->io[1].intern = 0; // Div 3 counter
    object->io[2].intern = 0; // Div 5 counter
    object->io[3].intern = 0; // Div 6 counter
    object->io[4].intern = 0; // Div 7 counter
  } else {
    if (*object->io[0].input > 0 && object->io[7].intern<=0) {
      // Clock pulse
      object->io[0].intern++;
      object->io[0].output = (object->io[0].intern &  1)?0:32767;
      object->io[2].output = (object->io[0].intern &  3)?0:32767;
      object->io[6].output = (object->io[0].intern &  7)?0:32767;
      object->io[7].output = (object->io[0].intern & 15)?0:32767;
      if ((++object->io[1].intern)>2) {
        object->io[1].intern=0;
        object->io[1].output = 32767; // div 3
      }
      if ((++object->io[2].intern)>4) {
        object->io[2].intern=0;
        object->io[3].output = 32767; // div 5
      }
      if ((++object->io[3].intern)>5) {
        object->io[3].intern=0;
        object->io[4].output = 32767; // div 6
      }
      if ((++object->io[4].intern)>6) {
        object->io[4].intern=0;
        object->io[5].output = 32767; // div 7
      }
      object->io[6].intern=(!0);
    }
  }        
  object->io[7].intern = *object->io[0].input;
}

//
// Binary counter
//
static void dspRoutine_BIN(DspObject *object) {
  if (*object->io[7].input>0) {
    // Reset
    object->io[0].intern=0;
  } else {
    if (*object->io[0].input <= 0 && object->io[7].intern>0) {
      // Clock pulse
      object->io[0].intern++;
    } else {
      goto _BIN_nochange;
    }
  }

  object->io[0].output=(object->io[0].intern&  1)?32767:0;
  object->io[1].output=(object->io[0].intern&  2)?32767:0;
  object->io[2].output=(object->io[0].intern&  4)?32767:0;
  object->io[3].output=(object->io[0].intern&  8)?32767:0;
  object->io[4].output=(object->io[0].intern& 16)?32767:0;
  object->io[5].output=(object->io[0].intern& 32)?32767:0;
  object->io[6].output=(object->io[0].intern& 64)?32767:0;
  object->io[7].output=(object->io[0].intern&128)?32767:0;
_BIN_nochange:
  object->io[7].intern = *object->io[0].input;
}

//
// 1 to 2 demultiplexer
//
static void dspRoutine_SEL1(DspObject *object) {
  int curport=((*object->io[0].input>0)?1:0);
  int cnt;
  
  for(cnt=0; cnt<2; cnt++)
    object->io[cnt].output = (cnt==curport)?32767:0;
}

//
// 2 to 4 demultiplexer
//
static void dspRoutine_SEL2(DspObject *object) {
  int curport=((*object->io[0].input>0)?1:0) | ((*object->io[1].input>0)?2:0);
  int cnt;

  for(cnt=0; cnt<4; cnt++)
    object->io[cnt].output = (cnt==curport)?32767:0;
}

//
// 3 to 8 demultiplexer
//
static void dspRoutine_SEL3(DspObject *object) {
  int curport=((*object->io[0].input>0)?1:0) | ((*object->io[1].input>0)?2:0) | ((*object->io[2].input>0)?4:0);
  int cnt;

  for(cnt=0; cnt<8; cnt++)
    object->io[cnt].output = (cnt==curport)?32767:0;
}

//
// 4 to 16 demultiplexer
//
static void dspRoutine_SEL4(DspObject *object) {
  int curport=((*object->io[0].input>0)?1:0) | ((*object->io[1].input>0)?2:0) | ((*object->io[2].input>0)?4:0) | ((*object->io[3].input>0)?8:0);
  int cnt;

  for(cnt=0; cnt<16; cnt++)
    object->io[cnt].output = (cnt==curport)?32767:0;
}

//
// Set/Reset flipflop with toggle
//
static void dspRoutine_FF1(DspObject *object) {
  if (*object->io[2].input>0) {
    // Rst input
    object->io[0].output=0;
  } else {
    if (*object->io[0].input>0) {
      // Set input
      object->io[0].output=32767;
    } else {
      if (*object->io[1].input<=0 && object->io[7].intern>0) {
        object->io[0].output=object->io[1].output;
      }
    }
  }
  object->io[7].intern = *object->io[1].input;
  object->io[1].output = 32767-object->io[0].output; 
}

//
// JK flipflop
//
static void dspRoutine_FF2(DspObject *object) {
  if (*object->io[4].input>0) {
    // Rst input
    object->io[0].output=0;
  } else {
    if (*object->io[0].input>0) {
      // Set input
      object->io[0].output=32767;
    } else {
      if (*object->io[2].input<=0 && object->io[7].intern>0) {
        if (*object->io[1].input>0) {
          if (*object->io[3].input>0) {
            // J=1 K=1  Toggle
            object->io[0].output=object->io[1].output;
          } else {
            // J=1 K=0  Set
            object->io[0].output=32767;
          }
        } else {
          if (*object->io[3].input>0) {
            // J=0 K=1  Reset
            object->io[0].output=0;
          }
        }
      }
    }
  }
  object->io[7].intern = *object->io[2].input;
  object->io[1].output = 32767-object->io[0].output; 
}

//
//
//
static void dspRoutine_CTR(DspObject *object) {
  object->io[0].output = ((*object->io[0].input * (*object->io[1].input + object->io[0].knob)) >> 14) + object->io[2].knob + *object->io[2].input;
}

//
// ADSR envelope generator
//
static void dspRoutine_ENV(DspObject *object) {
  if (*object->io[7].input > 0) {
    if (*object->io[7].input > object->io[1].intern) {
      // Attack phase
      object->io[0].intern+=exposc(32767-(*object->io[1].input + object->io[1].knob));
      if (object->io[0].intern < 0) {
        // Maximum reached, switch to decay/sustain
        object->io[0].intern=0x7FFFFFFF;
        object->io[1].intern=0x7FFFFFFF;
      }
    } else {
      // Decay/sustain phase
      object->io[0].intern-=(((object->io[0].intern>>16)-pos(*object->io[3].input + object->io[5].knob)) * expval(32767-(*object->io[2].input + object->io[3].knob)))>>4;
    }
  } else {
    // Release phase
    object->io[0].intern-=((object->io[0].intern>>16)*expval(32767-(*object->io[4].input + object->io[7].knob)))>>4;
    object->io[1].intern=0;
  }
  object->io[0].output = ((object->io[0].intern>>16) * limit(*object->io[0].input + object->io[6].knob)) >> 15;
}

//
// Attack Hold Decay envelope generator
//
static void dspRoutine_AHD(DspObject *object) {
  // Inp[0] mod
  // Inp[1] A
  // Inp[2] H
  // Inp[3] D
  // Inp[4] Trig
  // Intern[0] counter for envelope generator
  // Intern[1] current state
  //   - 0 decay (idle)
  //   - 1 hold
  //   - 2 attack
  // Intern[7] copy of Inp[4] to detect trig transition
  int trig=*object->io[4].input;
  int ampl=(*object->io[0].input)+object->io[6].knob;
  if (trig>0 && object->io[7].intern<=0) {
    object->io[0].intern=0;
    object->io[1].intern=2;
  }
  switch(object->io[1].intern) {
  case 2: // attack
    object->io[0].intern+=exposc(32768-(*object->io[1].input+object->io[0].knob));
    if (object->io[0].intern<0) {
      object->io[0].intern=0;
      object->io[1].intern=1; // hold state
      object->io[0].output=ampl;
    } else {
      object->io[0].output=((object->io[0].intern>>16)*ampl)>>15;
    }
    break;
  case 1: // hold
    object->io[0].intern+=exposc(32768-(*object->io[2].input+object->io[2].knob));
    if (object->io[0].intern<0) {
      object->io[0].intern=0x7FFFFFFF;
      object->io[1].intern=0; // decay state
    }
    break;
  case 0: // decay
  default:
    if (object->io[0].intern>0) {
      object->io[0].intern-=exposc(32768-(*object->io[3].input+object->io[4].knob));
      if (object->io[0].intern<0) {
        object->io[0].intern=0;
      }
      object->io[0].output=((object->io[0].intern>>16)*ampl)>>15;
    }
    break;
  }
  object->io[7].intern=trig;
}

//
// Sample & Hold gate
//
static void dspRoutine_SAH(DspObject *object) {
  if (*object->io[2].input > 0 && object->io[7].intern<=0) {
    object->io[0].output = *object->io[0].input;
  }
  object->io[7].intern = *object->io[2].input;
}

//
// Glide or portamento
//
static void dspRoutine_GLI(DspObject *object) {
  int speed = expval(*object->io[1].input + object->io[0].knob);

  object->io[0].intern += (*object->io[0].input - object->io[0].output) * speed;
  object->io[0].output = object->io[0].intern >> 16;
}

//
// delayed Trigger/gate processor
//
static void dspRoutine_TRIG(DspObject *object) {
  // Intern[0] counter used for delayed gate output
  // Intern[1] counter used for oneshot output
  // Intern[7] copy of inp[3] to detect transition
  if ((*object->io[3].input)>0) {
    // Gate input active
    if (object->io[7].intern<=0) {
      object->io[7].intern=32767;
      object->io[0].intern=exposc(*object->io[0].input + object->io[0].knob)>>5;
      object->io[1].intern=object->io[0].intern+1;
      object->io[1].output=0;
    }
  } else {
    // Gate input inactive
    if (object->io[7].intern>0) {
      object->io[7].intern=0;
      object->io[0].intern=exposc(*object->io[1].input + object->io[2].knob)>>5;
    }
  }
  if (object->io[0].intern>0) {
    object->io[0].intern--;
  } else {
    object->io[0].output=object->io[7].intern;
  }
  if (object->io[1].intern>0) {
    object->io[1].intern--;
    if (object->io[1].intern==0) {
      if (object->io[1].output>0) {
        // End of pulse
        object->io[1].output=0;
      } else {                
        // On delay has passed, switch output on
        object->io[1].intern=((exposc(*object->io[1].input + object->io[2].knob)+31)>>5);
        if (object->io[1].intern) {
          object->io[1].output=32767;
        }
      }
    }
  }
}

//
// 16 steps sequencer
//
static void dspRoutine_SEQ16(DspObject *object) {
  if (*object->io[7].input > 0) {
    // Reset received
    object->io[0].intern=0;
    object->io[7].output=32767;
  } else {
    object->io[7].output = 0;
    if (*object->io[0].input > 0 && object->io[7].intern<=0) {
      // Received clock pulse
      object->io[0].intern++;
      if (object->io[0].intern >= 16 || object->io[SeqPotRemap[object->io[0].intern]].knob<0) {
        object->io[0].intern=0;
        object->io[7].output = 32767;
      }
    }
  }

  object->io[7].intern = *object->io[0].input;
  object->io[0].output = object->io[SeqPotRemap[object->io[0].intern]].knob;
}

//
// 8 steps sequencer
//
static void dspRoutine_SEQ8(DspObject *object) {
  if (*object->io[3].input > 0) {
    // Reset received
    object->io[0].intern=0;
    object->io[3].output = 32767;
  } else {
    object->io[3].output = 0;
    if (*object->io[0].input > 0 && object->io[7].intern<=0) {
      // Received clock pulse
      object->io[0].intern++;
      if (object->io[0].intern >= 8 || object->io[SeqPotRemap[object->io[0].intern]].knob<0) {
        object->io[0].intern=0;
        object->io[3].output = 32767;
      }
    }
  }

  object->io[7].intern = *object->io[0].input;
  object->io[0].output = object->io[SeqPotRemap[object->io[0].intern]].knob;
}

//
// Binary input 8 steps sequencer
//
static void dspRoutine_BINSEQ(DspObject *object) {
  if (*object->io[3].input > 0) {
    // Output Enable high (disable output)
    object->io[0].output = 0;
  } else {
    // Output Enable low (enable output)
    object->io[0].output = object->io[SeqPotRemap[((*object->io[0].input>0)?1:0)+((*object->io[1].input>0)?2:0)+((*object->io[2].input>0)?4:0)]].knob;
  }
}

//
// 8 steps clockable switch/selector
//
static void dspRoutine_SEL8(DspObject *object) {
  int clock=*object->io[0].input;
  if (*object->io[9].input) {
    // Reset
    object->io[(object->io[0].intern&7)+1].output=0; // Switch old off
    object->io[0].intern=0;
  } else {
    if (clock>0 && object->io[7].intern<=0) {
      // Received clock pulse
      object->io[(object->io[0].intern&7)+1].output=0; // Switch old off
      object->io[0].intern++;
    }
  }

  object->io[7].intern = clock;
  object->io[(object->io[0].intern&7)+1].output=32767; // Switch new on (out of if statement for startup conditions)
  object->io[0].output=*object->io[(object->io[0].intern&7)+1].input;
}

//
// 16 steps clockable switch/selector
//
static void dspRoutine_SEL16(DspObject *object) {
  int clock=*object->io[0].input;
  if (*object->io[17].input) {
    // Reset
    object->io[(object->io[0].intern&15)+1].output=0; // Switch old off
    object->io[0].intern=0;
  } else {
    if (clock>0 && object->io[7].intern<=0) {
      // Received clock pulse
      object->io[(object->io[0].intern&15)+1].output=0; // Switch old off
      object->io[0].intern++;
    }
  }

  object->io[7].intern = clock;
  object->io[(object->io[0].intern&15)+1].output=32767; // Switch new on (outside if statement for startup conditions)
  object->io[0].output=*object->io[(object->io[0].intern&15)+1].input;
}

//
// Scanner - 9 input analog style multiplexer
//
static void dspRoutine_Scanner9(DspObject *object) {
  int scan=32767-limit(*object->io[9].input);
  int low=*object->io[scan/8192].input;
  int high=*object->io[scan/8192+1].input;
  object->io[0].output=(low*8192+(high-low)*(scan&8191))/8192;
}

//
// binary controlled switch with 2 inputs
//
static void dspRoutine_SW1(DspObject *object) {
  object->io[0].output = *object->io[((*object->io[0].input>0)?2:1)].input;
}

//
// binary controlled switch with 4 inputs
//
static void dspRoutine_SW2(DspObject *object) {
  object->io[0].output = *object->io[((*object->io[0].input>0)?3:2)+((*object->io[1].input>0)?2:0)].input;
}

//
// binary controlled switch with 8 inputs
//
static void dspRoutine_SW3(DspObject *object) {
  object->io[0].output = *object->io[((*object->io[0].input>0)?4:3)+((*object->io[1].input>0)?2:0)+((*object->io[2].input>0)?4:0)].input;
}

//
// binary controlled switch with 16 inputs
//
static void dspRoutine_SW4(DspObject *object) {
  object->io[0].output = *object->io[((*object->io[0].input>0)?5:4)+((*object->io[1].input>0)?2:0)+((*object->io[2].input>0)?4:0)+((*object->io[3].input>0)?8:0)].input;
}

//
// binary controlled switch with 2 outputs
//
static void dspRoutine_SW5(DspObject *object) {
  int input=*object->io[0].input;
  int curport=((*object->io[1].input>0)?1:0);
  int cnt;

  for(cnt=0; cnt<2; cnt++) {
    object->io[cnt].output = (cnt==curport)?input:0;
  }
}

//
// binary controlled switch with 4 outputs
//
static void dspRoutine_SW6(DspObject *object) {
  int input=*object->io[0].input;
  int curport=((*object->io[1].input>0)?1:0) + ((*object->io[2].input>0)?2:0);
  int cnt;

  for(cnt=0; cnt<4; cnt++) {
    object->io[cnt].output = (cnt==curport)?input:0;
  }
}

//
// binary controlled switch with 8 outputs
//
static void dspRoutine_SW7(DspObject *object) {
  int input=*object->io[0].input;
  int curport=((*object->io[1].input>0)?1:0) + ((*object->io[2].input>0)?2:0) + ((*object->io[3].input>0)?4:0);
  int cnt;

  for(cnt=0; cnt<8; cnt++) {
    object->io[cnt].output = (cnt==curport)?input:0;
  }
}

//
// binary controlled switch with 16 outputs
//
static void dspRoutine_SW8(DspObject *object) {
  int input=*object->io[0].input;
  int curport=((*object->io[1].input>0)?1:0) + ((*object->io[2].input>0)?2:0) + ((*object->io[3].input>0)?4:0) + ((*object->io[4].input>0)?8:0);
  int cnt;

  for(cnt=0; cnt<16; cnt++) {
    object->io[cnt].output = (cnt==curport)?input:0;
  }
}

//
// Phase lock loop
//
static void dspRoutine_PLL(DspObject *object) {
  object->io[5].intern+=object->io[2].intern;
  if ((*object->io[0].input)>0 && object->io[0].intern<=0) {
//    if (object->io[2].intern<=0) {
      if (object->io[2].intern<0) {
        object->io[2].intern=0;
      } else {
        object->io[2].intern++;
      }
//    }
  }
  if ((*object->io[1].input)>0 && object->io[1].intern<=0) {
//    if (object->io[2].intern>=0) {
      if (object->io[2].intern>0) {
        object->io[2].intern=0;
      } else {
        object->io[2].intern--;
      }
//    }
  }
  object->io[0].output=object->io[5].intern;
  object->io[0].intern=(*object->io[0].input);
  object->io[1].intern=(*object->io[1].input);
}

//
// Flanger unit
//
static void dspRoutine_FLA(DspObject *object) {
  int DlyPos = limit(*object->io[1].input);
  int Inp = (*object->io[0].input * object->io[0].knob) >> 14;
  int Fdb = (object->io[1].output * (*object->io[2].input + object->io[2].knob)) >> 15;

  object->io[1].output = ((16-(DlyPos&15)) * object->buffer[(object->io[0].intern + (DlyPos>>4) + 2048) & 4095] +
                    (DlyPos&15)  * object->buffer[(object->io[0].intern + (DlyPos>>4) + 2049) & 4095]) >> 4;
  object->io[0].output = (((pos(object->io[4].knob + *object->io[3].input)) * Inp) >> 15) + object->io[1].output;

  // Fill delayline with next sample
  object->buffer[(++object->io[0].intern) & 4095] = (short)(limit(Inp + Fdb));
}

//
// Delay and reverb unit
//
static void dspRoutine_DLY(DspObject *object) {
  int DlyPos = pos(object->io[2].knob + *object->io[1].input);
  int Inp = (*object->io[0].input * object->io[0].knob) >> 14;
  int Fdb = (object->io[1].output * (*object->io[2].input + object->io[4].knob)) >> 15;

  // Read from delayline
  object->io[1].output = object->buffer[((object->io[0].intern++) - DlyPos) & 0x7FFF];
  object->io[0].output = Inp + object->io[1].output;

  // Fill delayline with next sample
  object->buffer[object->io[0].intern & 0x7FFF] = (short)(limit(Inp + Fdb));
}

//
// Syncable delay
//
static void dspRoutine_SDY(DspObject *object) {
  // Intern[0] Current delayline position
  // Intern[1] Trigger buffer
  // Intern[2] Current length
  // Intern[3] Next Length Counter (copied to Inter[2] on trigger) 

  // ReadSync Input
  if (*object->io[1].input>0 && object->io[1].intern<=0) {
    object->io[2].intern = object->io[3].intern;
//              while (object->io[2].intern > 0xFFFF)
    while (object->io[2].intern > 0xFFFF)
      object->io[2].intern = object->io[2].intern >> 1;
    object->io[3].intern = 0;
  } else {
    if (object->io[3].intern < 0x7FFFFFFF)
      object->io[3].intern++;
  }
  object->io[1].intern = *object->io[1].input;

  {
    int Inp = (*object->io[0].input * object->io[0].knob) >> 14;
    int Fdb = (object->io[1].output * (*object->io[2].input + object->io[2].knob)) >> 15;
    int LineInp = limit(Inp + Fdb);

    // Read from delayline
    object->io[1].output = object->buffer[(object->io[0].intern - object->io[2].intern) & 0xFFFF];
    object->io[0].output = Inp + object->io[1].output;

    // Fill delayline with next sample
    object->buffer[(++object->io[0].intern) & 0xFFFF] = (short)(LineInp);
  }
}

//
// BIT reducer
//
static void dspRoutine_BIT(DspObject *object) {
  int bitreducer=abs(object->io[0].knob + *object->io[1].input);

  if (bitreducer) {
    object->io[0].output = (*object->io[0].input / bitreducer + ((*object->io[0].input>0)?1:-1)) * bitreducer;
  } else {
    object->io[0].output = *object->io[0].input;
  }
}

//
// NoiseGate / Clipper / Distorsion / OverDrive
//
static void dspRoutine_CLP(DspObject *object) {
  int inp = limit((*object->io[0].input * (object->io[0].knob + *object->io[1].input))>>14);
  int gate = pos(object->io[2].knob + *object->io[2].input);
  int gated = pos(inp - gate) + neg(inp + gate);

  object->io[0].output = limit(gated + ((gated*(*object->io[3].input+object->io[4].knob))>>13));
}

//
// SIN wave shaper
//
static void dspRoutine_SIN(DspObject *object) {
  object->io[0].output = SINTBL[(*object->io[0].input)&0xFFFF];
}

//
// Vocoder FilterBank
//
static int a0[]={   -23,   -16,    -9,     0,    11,    24,    40,    58,    80,   107,   138,   175,   219,   272,   334,   409,   497,   602,   726,   874};
static int a1[]={   116,   116,   116,   116,   116,   116,   116,   116,   115,   115,   114,   113,   112,   111,   108,   105,   100,    94,    85,    72};
static int a2[]={   -93,   -99,  -107,  -116,  -127,  -140,  -156,  -174,  -196,  -222,  -253,  -289,  -332,  -383,  -443,  -514,  -598,  -696,  -811,  -946};
static int b1[]={ 32677, 32655, 32628, 32592, 32545, 32485, 32405, 32300, 32160, 31972, 31718, 31376, 30911, 30279, 29418, 28245, 26650, 24493, 21597, 17757};
static int b2[]={-16314,-16301,-16285,-16267,-16244,-16218,-16187,-16150,-16106,-16054,-15992,-15918,-15831,-15727,-15605,-15460,-15288,-15085,-14845,-14563};
static void dspRoutine_FilterBank(DspObject *object) {
  int inp=*object->io[0].input;
  int t;

  for(int i=0;i<20;i++) {
    t=(a0[i]*inp + a1[i]*object->io[20].intern + a2[i]*object->io[21].intern + b1[i]*object->io[i].output + b2[i]*object->io[i].intern)>>14;
    object->io[i].intern=object->io[i].output;
    object->io[i].output=t;
  }

  object->io[21].intern=object->io[20].intern;
  object->io[20].intern=inp;
}

//
// Vocoder EnvelopeBank
//
static void dspRoutine_EnvBank(DspObject *object) {
  int speed=expval(object->io[0].knob);
  int inp;
  int i;

  for(i=0;i<20;i++) {
    inp=*object->io[i].input;
    inp=abs(inp);
    object->io[i].intern+=(inp-object->io[i].output)*(speed+2*i);
    object->io[i].output=object->io[i].intern>>15;
  }
}


//
// Mystery box
//
static void dspRoutine_XYZ(DspObject *object) {
  int inp = (*object->io[0].input) + (*object->io[1].input) + (*object->io[2].input) +
            ((object->io[4].output*posVCF(object->io[4].knob))>>13);
  int cutoff = object->io[0].knob + *object->io[4].input + *object->io[5].input;
  int cutoff1 = posVCF(cutoff) + 20;
  int cutoff2 = posVCF(cutoff + object->io[3].knob) + 20;
  int resonance = posVCF(object->io[2].knob + *object->io[6].input);

  object->io[0].intern +=  ((limit(inp + ((object->io[3].output*resonance)>>13)) - object->io[0].intern) *cutoff1) >> 15;
  object->io[1].intern +=  ((object->io[0].intern - object->io[1].intern) *cutoff1) >> 15;
  object->io[2].intern +=  ((object->io[1].intern - object->io[2].intern) *cutoff2) >> 15;
  object->io[3].intern +=  ((object->io[2].intern - object->io[3].intern) *cutoff2) >> 15;
  object->io[0].output = object->io[1].intern;
  object->io[1].output = object->io[2].intern;
  object->io[2].output = object->io[3].intern;
  object->io[3].output = object->io[0].intern-object->io[2].intern;
  object->io[4].output = object->io[1].intern-object->io[3].intern;
  object->io[5].output = limit(inp)-object->io[1].intern;
}

//
// Signal controlled panner
//
static void dspRoutine_PAN(DspObject *object) {
  int pan=limit((*object->io[1].input) + object->io[0].knob);
  int speed = expval((*object->io[2].input) + object->io[2].knob);

  object->io[0].intern += (pan - object->io[1].intern) * speed;
  object->io[1].intern = object->io[0].intern>>16;
  object->io[0].output = ((*object->io[0].input) * pos(32767-object->io[1].intern))>>15;
  object->io[1].output = ((*object->io[0].input) * pos(32767+object->io[1].intern))>>15;
}

//
// Cross fader, <0 L input louder
//              >0 H input louder
//              =0 L and H equal
//
static void dspRoutine_CROSS(DspObject *object) {
  int H=*object->io[0].input;
  int L=*object->io[2].input;
  int cross=limit((*object->io[1].input)+object->io[0].knob);

  object->io[0].output=(((L+H)<<15)+((H-L)*cross))>>16;
}

//
// 3 channel mixer module
//
static void dspRoutine_MX3(DspObject *object) {
  object->io[0].output = ((*object->io[0].input * expval(object->io[0].knob)) >> 14) +
                   ((*object->io[1].input * expval(object->io[2].knob)) >> 14) +
                   ((*object->io[2].input * expval(object->io[4].knob)) >> 14);
}

//
// 4 channel mixer module
//
static void dspRoutine_MX4(DspObject *object) {
            object->io[0].output = ((*object->io[0].input * expval(object->io[0].knob)) >> 14) +
                             ((*object->io[1].input * expval(object->io[2].knob)) >> 14) +
                             ((*object->io[2].input * expval(object->io[4].knob)) >> 14) +
                             ((*object->io[3].input * expval(object->io[6].knob)) >> 14);
}

//
// 8 channel mixer module
//
static void dspRoutine_MX8(DspObject *object) {
#if 0
  object->io[0].output = ((*object->io[0].input * expval(object->io[0].knob)) >> 14) +
                   ((*object->io[1].input * expval(object->io[2].knob)) >> 14) +
                   ((*object->io[2].input * expval(object->io[4].knob)) >> 14) +
                   ((*object->io[3].input * expval(object->io[6].knob)) >> 14) +
                   ((*object->io[4].input * expval(object->io[1].knob)) >> 14) +
                   ((*object->io[5].input * expval(object->io[3].knob)) >> 14) +
                   ((*object->io[6].input * expval(object->io[5].knob)) >> 14) +
                   ((*object->io[7].input * expval(object->io[7].knob)) >> 14);
#else
  object->io[0].output = ((*object->io[0].input * expval(object->io[0].knob)) >> 14);
  object->io[0].output+= ((*object->io[1].input * expval(object->io[2].knob)) >> 14);
  object->io[0].output+= ((*object->io[2].input * expval(object->io[4].knob)) >> 14);
  object->io[0].output+= ((*object->io[3].input * expval(object->io[6].knob)) >> 14);
  object->io[0].output+= ((*object->io[4].input * expval(object->io[1].knob)) >> 14);
  object->io[0].output+= ((*object->io[5].input * expval(object->io[3].knob)) >> 14);
  object->io[0].output+= ((*object->io[6].input * expval(object->io[5].knob)) >> 14);
  object->io[0].output+= ((*object->io[7].input * expval(object->io[7].knob)) >> 14);
#endif
}

//
// Soundcard output driver with mixer module
//
static void dspRoutine_MXO(DspObject *object) {
  int monochan = ((*object->io[2].input * expval(object->io[1].knob)) >> 14) +
                 ((*object->io[3].input * expval(object->io[3].knob)) >> 14) +
                 ((*object->io[4].input * expval(object->io[5].knob)) >> 14) +
                 ((*object->io[5].input * expval(object->io[7].knob)) >> 14);
  DSP_Left  += ((*object->io[0].input * expval(object->io[0].knob)) >> 14) +
               ((*object->io[1].input * expval(object->io[2].knob)) >> 14) +
               monochan;
  DSP_Right += ((*object->io[6].input * expval(object->io[4].knob)) >> 14) + 
               ((*object->io[7].input * expval(object->io[6].knob)) >> 14) + 
               monochan;
}

//
// Soundcard output driver
//
static void dspRoutine_OUT(DspObject *object) {
  int monochan = (*object->io[2].input) + (*object->io[3].input) + (*object->io[4].input) + (*object->io[5].input);
  DSP_Left  += ((*object->io[0].input) + (*object->io[1].input) + monochan) >> 1;
  DSP_Right += ((*object->io[6].input) + (*object->io[7].input) + monochan) >> 1;
}

//
// Soundcard output with left/center/right + surround
//
static void dspRoutine_OUTS(DspObject *object) {
  int monochan = (*object->io[2].input) + (*object->io[3].input) + (*object->io[4].input) + (*object->io[5].input);
  int surroundchan = (*object->io[8].input) + (*object->io[9].input);
  DSP_Left  += ((*object->io[0].input) + (*object->io[1].input) + monochan + surroundchan) >> 1;
  DSP_Right += ((*object->io[6].input) + (*object->io[7].input) + monochan - surroundchan) >> 1;
}

//
// Soundcard output with buildin panner
//
static void dspRoutine_PANOUT(DspObject *object) {
  int pan=limit((*object->io[3].input) + object->io[0].knob);
  int vol=limit((*object->io[4].input) + object->io[2].knob);
  int left=(*object->io[0].input)+(*object->io[1].input);
  int right=(*object->io[2].input)+(*object->io[1].input);

  DSP_Left  += (((left * pos(32767-pan))>>16)*vol)>>15;
  DSP_Right += (((right * pos(32767+pan))>>16)*vol)>>15;
}

//
// Soundcard input
//
static void dspRoutine_INPUT(DspObject *object) {
  object->io[0].output=dspInputLeft;
  object->io[1].output=dspInputRight;
}

//
// DRM - Drum pattern matrix
//
static void dspRoutine_DRM4(DspObject *object) {
  int curpos = ((*object->io[0].input>0)?1:0)+((*object->io[1].input>0)?2:0)+((*object->io[2].input>0)?4:0)+((*object->io[3].input>0)?8:0);
  int gate = (*object->io[4].input>0)?0:32767;
  object->io[0].output = (((unsigned char *)object->buffer)[curpos   ])?gate:0;
  object->io[2].output = (((unsigned char *)object->buffer)[curpos+16])?gate:0;
  object->io[4].output = (((unsigned char *)object->buffer)[curpos+32])?gate:0;
  object->io[6].output = (((unsigned char *)object->buffer)[curpos+48])?gate:0;
}

//
// DRM - Drum pattern matrix
//
static void dspRoutine_DRM8(DspObject *object) {
  int curpos = ((*object->io[0].input>0)?1:0)+((*object->io[1].input>0)?2:0)+((*object->io[2].input>0)?4:0)+((*object->io[3].input>0)?8:0);
  int gate = (*object->io[4].input>0)?0:32767;
  object->io[ 0].output = (((unsigned char *)object->buffer)[curpos    ])?gate:0;
  object->io[ 2].output = (((unsigned char *)object->buffer)[curpos+ 16])?gate:0;
  object->io[ 4].output = (((unsigned char *)object->buffer)[curpos+ 32])?gate:0;
  object->io[ 6].output = (((unsigned char *)object->buffer)[curpos+ 48])?gate:0;
  object->io[ 8].output = (((unsigned char *)object->buffer)[curpos+ 64])?gate:0;
  object->io[10].output = (((unsigned char *)object->buffer)[curpos+ 80])?gate:0;
  object->io[12].output = (((unsigned char *)object->buffer)[curpos+ 96])?gate:0;
  object->io[14].output = (((unsigned char *)object->buffer)[curpos+112])?gate:0;
}

#if 0
//
// Mixer console mono input (with aux sends)
//
static void dspRoutine_CONM2(DspObject *object) {
  int auxmono=((*object->io[0].input)+(*object->io[1].input));
  int signal= (auxmono * object->io[0].knob)>>15;
  int i;

  DSP_Left += (signal * pos(32767-object->io[1].knob))>>15;
  DSP_Right+= (signal * pos(32767+object->io[1].knob))>>15;

  for(i=0; i<MAX_AUX_CHANNELS; i++) {
    if (AuxAssignTable[i]) {
      *(AuxAssignTable[i]) += ((auxmono * object->io[i+2].knob)>>15);
    }
  }
}

//
// Mixer console stereo input (with aux sends)
//
static void dspRoutine_CONS2(DspObject *object) {
  int auxleft=(*object->io[0].input);
  int auxright=(*object->io[1].input);
  int auxmono=(auxleft+auxright);
  int left=  ((auxleft) * object->io[0].knob)>>15;
  int right= ((auxright) * object->io[0].knob)>>15;
  int i;

  DSP_Left += (left  * pos(32767-object->io[1].knob))>>15;
  DSP_Right+= (right * pos(32767+object->io[1].knob))>>15;

  for(i=0; i<MAX_AUX_CHANNELS; i++) {
    if (AuxAssignTable[i]) {
      *(AuxAssignTable[i]) += ((auxmono * object->io[i+2].knob)>>15);
    }
  }
}

//
// Mixer console stereo input (with aux sends)
//
static void dspRoutine_CONS(DspObject *object) {
  int mono    =(*object->io[2].input)+(*object->io[3].input)+(*object->io[4].input)+(*object->io[5].input);
  int auxleft =(*object->io[0].input)+(*object->io[1].input);
  int auxright=(*object->io[6].input)+(*object->io[7].input);
  int left=  ( (auxleft +mono) * object->io[0].knob)>>15;
  int right= ( (auxright+mono) * object->io[0].knob)>>15;
  int i;

  DSP_Left += (left  * pos(32767-object->io[1].knob))>>15;
  DSP_Right+= (right * pos(32767+object->io[1].knob))>>15;

  for(i=0; i<MAX_AUX_CHANNELS; i++) {
    if (AuxAssignTable[i]) {
      *(AuxAssignTable[i]) += (((auxleft+auxright+mono) * object->io[i+2].knob)>>15);
    }
  }
}

//
// Mixer console aux send
//
static void dspRoutine_AUX(DspObject *object) {
  // Intern[0] aux channel filled by OBJ_CONxx modules (via AuxAssignTable)
  object->io[0].output = limit(object->io[0].intern);
  object->io[0].intern = 0;
}

//
// Mixer console stereo return
//
static void dspRoutine_RET(DspObject *object) {
  int left=  ((*object->io[0].input) * object->io[0].knob)>>15;
  int right= ((*object->io[1].input) * object->io[0].knob)>>15;

  DSP_Left += (left  * pos(32767-object->io[1].knob))>>15;
  DSP_Right+= (right * pos(32767+object->io[1].knob))>>15;
}
#endif

//
// MACRO: Mixer + Resonance Filter + Envelope
//
static void dspRoutine_ECF(DspObject *object) {
  //
  // Envelope section
  //
  if (*object->io[7].input > 0) {
    if (*object->io[7].input > object->io[1].intern) {
      // Attack phase
      object->io[0].intern+=exposc(32767-object->io[1].knob);
      if (object->io[0].intern < 0) {
        // Maximum reached, switch to decay/sustain
        object->io[0].intern=0x7FFFFFFF;
        object->io[1].intern=0x7FFFFFFF;
      }
    } else {
      // Decay/sustain phase
      object->io[0].intern-=(((object->io[0].intern>>16)-pos(object->io[5].knob)) * expval(32767-object->io[3].knob))>>4;
    }
  } else {
    // Release phase
    object->io[0].intern-=((object->io[0].intern>>16)*expval(32767-object->io[7].knob))>>4;
    object->io[1].intern=0;
  }

  {
    //
    // Mixer section
    //
    int inp = limit((*object->io[0].input * object->io[0].knob +
                     *object->io[1].input * object->io[2].knob +
                     *object->io[2].input * object->io[4].knob) >> 13);

    //
    // Filter section
    //
    int cutoff = posVCF((((object->io[0].intern>>16) * limit(*object->io[3].input + object->io[6].knob)) >> 15) + object->io[8].knob + *object->io[4].input + *object->io[5].input);
    int resonance = posVCF(object->io[9].knob + *object->io[6].input);
    object->io[2].output  = limit(inp + ((object->io[1].output*resonance) >> 13) - object->io[0].output*4);
    object->io[1].output += (((object->io[2].output - object->io[1].output)*cutoff) >> 15);
    object->io[0].output += (((object->io[1].output - object->io[0].output)*cutoff) >> 15);
  }
}

//
// MACRO: Mixer + VCA + Envelope
//
static void dspRoutine_ECA(DspObject *object) {
  //
  // Envelope section
  //
  if (*object->io[7].input > 0) {
    if (*object->io[7].input > object->io[1].intern) {
      // Attack phase
      object->io[0].intern+=exposc(32767-(object->io[1].knob + *object->io[4].input));
      if (object->io[0].intern < 0) {
        // Maximum reached, switch to decay/sustain
        object->io[0].intern=0x7FFFFFFF;
        object->io[1].intern=0x7FFFFFFF;
      }
    } else {
      // Decay/sustain phase
      object->io[0].intern-=(((object->io[0].intern>>16)-pos(object->io[5].knob)) * expval(32767-(object->io[3].knob + *object->io[5].input)))>>4;
    }
  } else {
    // Release phase
    object->io[0].intern-=((object->io[0].intern>>16)*expval(32767-(object->io[7].knob + *object->io[6].input)))>>4;
    object->io[1].intern=0;
  }

  {
    //
    // Mixer section
    //
    int inp = limit((*object->io[0].input * object->io[0].knob +
                     *object->io[1].input * object->io[2].knob +
                     *object->io[2].input * object->io[4].knob) >> 13);

    //
    // VCA section
    //
    int volume = ((object->io[0].intern>>16) * limit(*object->io[3].input + object->io[6].knob)) >> 15;
    object->io[0].output = limit((inp * volume) >> 12);
  }
}

#if 0
//
// Single module-tracker type track
//
static void dspRoutine_MODTRK(DspObject *object) {
  // out[0] wave
  // out[1] pan
  // out[2] freq
  // out[3] vol
  // out[4] gate
  // out[5] trig
  // out[6]  X
  // out[7]  Y
  // out[8]  Z
  // intern[0] subsample counter
  // intern[1] current sample position
  // intern[2] 
  // intern[3] sample nr
  // intern[4] volume
  // intern[5] 
  // intern[6] 
  // intern[7] curnote
  //           0x8000000  triggerflag
  int old;
  // sample playing ?
  if (object->io[4].output) {

    // Pulse trigger output
    if (object->io[7].intern&0x80000000) {
      object->io[5].output=32767;
      object->io[7].intern&=0x7FFFFFFF;
    } else {
      object->io[5].output=0;
    }

    if (object->io[1].intern<sampleList[object->io[3].intern].loopend) {
      object->io[0].output = (int)((char*)sampleList[object->io[3].intern].Buffer)[object->io[1].intern]*object->io[4].intern*4;

      old=(object->io[0].intern&0x07FFFFFF);
      object->io[0].intern += exposc(object->io[2].output);
      if ((object->io[0].intern&0x07FFFFFF)<old) {
        object->io[1].intern++;
      }
    } else {
      if (sampleList[object->io[3].intern].looping) {
        object->io[1].intern=sampleList[object->io[3].intern].loopstart;
        object->io[0].output = (int)((char*)sampleList[object->io[3].intern].Buffer)[object->io[1].intern]*object->io[4].intern*4;
      } else {
        object->io[4].output=0;
        object->io[0].output=0;
      }
    }
  } else {
    object->io[0].output = 0;
  }
}
#endif

//
// SCRIPT - Script controlled note player
//
static void dspRoutine_SCRIPT(DspObject *object) {
  // Intern[0] current script pointer
  // Intern[1] current script mode
  //   -  0 run
  //   - >0 wait for clocks
  // Intern[2] tick counter and work var
  // Intern[3] current octave offset
  // Intern[4] 
  // Intern[5] 
  // Intern[6] secondairy number storage (backup of intern[2])
  // Intern[7] copy of clk to detect trigger transition
  //
  if (object->scriptInfo->script) {
    if ((*object->io[1].input)>0) {
      // Reset
      object->io[0].intern=0;
      object->io[1].intern=0;
      object->io[2].intern=0;
      object->io[3].intern=0;
    } else {
      // Running and waiting modes
      if (object->io[1].intern>0) {
        // Pause for number of clocks
        if ((*object->io[0].input)<=0 && object->io[7].intern>0) {
          object->io[1].intern--;
        }
      } else {
        while (object->io[1].intern==0 && object->scriptInfo->script[object->io[0].intern]>0) {
          // mode run
          static char cmd[32]; // declared static to remove unnecessary stack clobber
          int cmdcnt=0;

          // skip spaces and control chars
          while (object->scriptInfo->script[object->io[0].intern]>0 && object->scriptInfo->script[object->io[0].intern]<33) {
            (object->io[0].intern)++;
          }
          // read command
          while (object->scriptInfo->script[object->io[0].intern]>32 && cmdcnt<31) {
            cmd[cmdcnt++]=object->scriptInfo->script[(object->io[0].intern)++];
          }
          cmd[cmdcnt]=0;

          if (cmdcnt>0) {
            interpretagain:
            switch(cmd[0]) {
            case 'm': case 'M':
              // Call macro
              if (object->scriptInfo->rSP<(scriptReturnStackSize-1)) {
                object->scriptInfo->returnStack[object->scriptInfo->rSP++]=object->io[0].intern;
              }
              // !!! no break !!!
            case 'j': case 'J':
              // Jump macro
              if (cmdcnt>1) {
                int pos=0;
                while (object->scriptInfo->script[pos]) {
                  // skip spaces and control chars
                  while (object->scriptInfo->script[pos]>0 && object->scriptInfo->script[pos]<33) {
                    pos++;
                  }
                  switch(object->scriptInfo->script[pos]) {
                  case ':':
                    // process label
                    if (strnicmp(object->scriptInfo->script+pos+1, cmd+1, cmdcnt-1)==0 && object->scriptInfo->script[pos+cmdcnt]<33) {
                      // label found, jump to new location
                      object->io[0].intern=pos+cmdcnt;
                      goto script_wait_one_sample;
                    }
                    pos+=cmdcnt;
                    break;
                  case '{':
                    // skip comment
                    while (object->scriptInfo->script[pos] && object->scriptInfo->script[pos]!='}')
                      pos++;
                    break;
                  default:
                    // skip command
                    while (object->scriptInfo->script[pos]>32)
                      pos++;
                    break;
                  }                              
                }
                // label not found
              }
              continue;
            case 'o': case 'O':
              if (cmdcnt>1) {
                object->io[3].intern=atoi(cmd+1);
              } else {
                object->io[3].intern=object->io[2].intern;
              }
              continue;
            case 'p': case 'P':
              // pause for number of clocks
              if (cmdcnt>1) {
                object->io[1].intern=atoi(cmd+1);
              } else {
                object->io[1].intern=object->io[2].intern;
              }
              goto script_wait_one_sample;
            case 'r': case 'R':
              // Restart script
              object->io[0].intern=0;
              object->scriptInfo->rSP=0;
              goto script_wait_one_sample;
            case 'u': case 'U':
              if (cmdcnt>1) {
                int freq=StringToNote(cmd+1, &(object->io[3].intern));
                if (freq) {
                  object->io[2].output=freq;
                } else {
                  object->io[2].output=atoi(cmd+1);
                }
              } else {
                object->io[2].output=object->io[2].intern;
              }
              continue;
            case 'v': case 'V':
              if (cmdcnt>1) {
                int freq=StringToNote(cmd+1, &(object->io[3].intern));
                if (freq) {
                  object->io[3].output=freq;
                } else {
                  object->io[3].output=atoi(cmd+1);
                }
              } else {
                object->io[3].output=object->io[2].intern;
              }
              continue;
            case 'w': case 'W':
              if (cmdcnt>1) {
                int freq=StringToNote(cmd+1, &(object->io[3].intern));
                if (freq) {
                  object->io[4].output=freq;
                } else {
                  object->io[4].output=atoi(cmd+1);
                }
              } else {
                object->io[4].output=object->io[2].intern;
              }
              continue;
            case 'x': case 'X':
              if (cmdcnt>1) {
                int freq=StringToNote(cmd+1, &(object->io[3].intern));
                if (freq) {
                  object->io[5].output=freq;
                } else {
                  object->io[5].output=atoi(cmd+1);
                }
              } else {
                object->io[5].output=object->io[2].intern;
              }
              continue;
            case 'y': case 'Y':
              if (cmdcnt>1) {
                int freq=StringToNote(cmd+1, &(object->io[3].intern));
                if (freq) {
                  object->io[6].output=freq;
                } else {
                  object->io[6].output=atoi(cmd+1);
                }
              } else {
                object->io[6].output=object->io[2].intern;
              }
              continue;
            case 'z': case 'Z':
              if (cmdcnt>1) {
                int freq=StringToNote(cmd+1, &(object->io[3].intern));
                if (freq) {
                  object->io[7].output=freq;
                } else {
                  object->io[7].output=atoi(cmd+1);
                }
              } else {
                object->io[7].output=object->io[2].intern;
              }
              continue;
            case '[':
              // Note on
              object->io[1].output=32767;
              continue;
            case ']':
              // Note off
              object->io[1].output=0;
              continue;
            case ':':
              // Label/Macro definition start
              continue;
            case ';':
              // Macro definition end
              if (object->scriptInfo->rSP) {
                object->io[0].intern=object->scriptInfo->returnStack[--(object->scriptInfo->rSP)];
              } else {
                // Restart script
                object->io[0].intern=0;
                goto script_wait_one_sample;
              }
              continue;
            case '?':
              if (object->io[2].intern>0) {
                memmove(cmd, cmd+1, (size_t)cmdcnt);
                cmdcnt--;
                goto interpretagain;
              }
              continue;
            case '+':
              object->io[2].intern+=object->io[6].intern;
              continue;
            case '*':
              object->io[2].intern*=object->io[6].intern;
              continue;
            case '@':
              // Get value from input or work variable
              if (cmd[1]>='1' && cmd[1]<='6') {
                object->io[6].intern=object->io[2].intern;
                object->io[2].intern=*object->io[(cmd[1]-'1')+2].input;
              }
              if (cmd[1]>='a' && cmd[1]<='z') {
                object->io[6].intern=object->io[2].intern;
                object->io[2].intern=object->scriptInfo->workVars[cmd[1]-'a'];
              }
              if (cmd[1]>='A' && cmd[1]<='Z') {
                object->io[6].intern=object->io[2].intern;
                object->io[2].intern=object->scriptInfo->workVars[cmd[1]-'A'];
              }
              continue;                            
            case '!':
              // store value in work variable
              if (cmd[1]>='a' && cmd[1]<='z') {
                object->scriptInfo->workVars[cmd[1]-'a']=object->io[2].intern;
              }
              if (cmd[1]>='A' && cmd[1]<='Z') {
                object->scriptInfo->workVars[cmd[1]-'A']=object->io[2].intern;
              }
              continue;                            
            case '{':
              // skip comments
              while (object->scriptInfo->script[object->io[0].intern]>0 && object->scriptInfo->script[object->io[0].intern]!='}') {
                (object->io[0].intern)++;
              }
              continue;
            default:
              break;
            }
            
            {
              int freq=StringToNote(cmd, &(object->io[3].intern));
              if (freq) {
                object->io[0].output=freq;                          
              } else {
                object->io[6].intern=object->io[2].intern;
                object->io[2].intern=atoi(cmd);
              }
            }
          }
        }
        script_wait_one_sample: ;
      }
    }
    object->io[7].intern=*object->io[0].input;
  }
}

//
// Midi note input
//
static void dspRoutine_MIDINOTE(DspObject *object) {
  // Delayed gate (used when reusing pressed notes)
  if (object->io[3].output<0) {
    object->io[3].output++;
    if (object->io[3].output==0) {
      object->io[3].output=32767;
    }
  }
/*
  object->io[0].output=MIDI_NotePitch;
  object->io[1].output=MIDI_NoteAtkVel;
  object->io[2].output=MIDI_NoteRelVel;
  object->io[3].output=MIDI_NoteGate;
  object->io[4].output=MIDI_ChAft;
  object->io[5].output=MIDI_PitchBend;
*/
}

//
// Out[0] = Clock
// Out[1] = rawClock [continues even when paused]
// Out[2] = play
// Out[3] = reset [active when PLAY instead of CONTINUE is received on midi port]
//
//
static void dspRoutine_MIDICLOCK(DspObject *object) {
  // Clock
  object->io[0].output=object->io[5].intern;
  if (object->io[5].intern) {
    object->io[5].intern=0;
  } else {
    if (object->io[0].intern!=object->io[4].intern) {
      object->io[4].intern++;
      object->io[5].intern=32767;
    }
  }

  // RawClock
  object->io[1].output=object->io[7].intern;
  if (object->io[7].intern) {
    object->io[7].intern=0;
  } else {
    if (object->io[1].intern!=object->io[6].intern) {
      object->io[6].intern++;
      object->io[7].intern=32767;
    }
  }

  // Play
  object->io[2].output=object->io[2].intern;

  // Reset
  if (object->io[3].intern) {
    object->io[3].output=32767;
    object->io[3].intern=0;
  } else {
    object->io[3].output=0;
  }
}

//
// Joystick controlled module
//
static void dspRoutine_JOYSTICK(DspObject *object) {
  object->io[0].output=JoyXpos;
  object->io[1].output=JoyYpos;
  object->io[2].output=JoyZpos;
  object->io[3].output=JoyRpos;
  object->io[4].output=JoyUpos;
  object->io[5].output=JoyVpos;
  object->io[6].output=JoyBut[0];
  object->io[7].output=JoyBut[1];
  object->io[8].output=JoyBut[2];
  object->io[9].output=JoyBut[3];
}

//
// 4 Channel scope module
//
static void dspRoutine_SCOPE(DspObject *object) {
  if (object->io[0].intern<1024) {
    if ((object->io[1].intern&3)==0) {
      object->buffer[object->io[0].intern]=(signed short)(*object->io[0].input);
      object->buffer[1024+object->io[0].intern]=(signed short)(*object->io[1].input);
      object->buffer[2048+object->io[0].intern]=(signed short)(*object->io[2].input);
      object->buffer[3072+object->io[0].intern]=(signed short)(*object->io[3].input);
      object->io[0].intern++;
    }
    object->io[1].intern++;
  }
}

//
// Oscillator is in SIN mode
//
static void dspRoutine_OSC_SIN_L(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = (SINTBL[32768+(short)(object->io[0].intern >> 16)] * ampl) >> 15;
}

static void dspRoutine_OSC_SIN_M(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += 2*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = (SINTBL[32768+(short)(object->io[0].intern >> 16)] * ampl) >> 15;
}

static void dspRoutine_OSC_SIN_H(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += 4*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = (SINTBL[32768+(short)(object->io[0].intern >> 16)] * ampl) >> 15;
}


//
// Oscillator is in TRI mode
//
static void dspRoutine_OSC_TRI_L(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0x40000000;
  } else {
    object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short)((object->io[0].intern >> 15)^((object->io[0].intern & 0x80000000)?0x7FFF:0x8000)) * ampl) >> 15;
}

static void dspRoutine_OSC_TRI_M(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0x20000000;
  } else {
    object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short)((object->io[0].intern >> 14)^((object->io[0].intern & 0x40000000)?0x7FFF:0x8000)) * ampl) >> 15;
}

static void dspRoutine_OSC_TRI_H(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0x10000000;
  } else {
    object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short)((object->io[0].intern >> 13)^((object->io[0].intern & 0x20000000)?0x7FFF:0x8000)) * ampl) >> 15;
}

//
// Oscillator is in SAW mode
//
static void dspRoutine_OSC_SAW_AA_L(DspObject *object) {
  int value;
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    value=(object->io[0].intern>>17);
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    value=((object->io[0].intern+(freq/4))>>3)+
          ((object->io[0].intern+(freq/2))>>3)+
          ((object->io[0].intern+3*(freq/4))>>3)+
          ((object->io[0].intern+freq)>>3);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((value>>15) * ampl) >> 15;
}

static void dspRoutine_OSC_SAW_L(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short(object->io[0].intern>>16)) * ampl) >> 15;
}

static void dspRoutine_OSC_SAW_AA_M(DspObject *object) {
  int value;
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    value=(object->io[0].intern>>17);
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    value=((object->io[0].intern+(freq/4))>>3)+
          ((object->io[0].intern+(freq/2))>>3)+
          ((object->io[0].intern+3*(freq/4))>>3)+
          ((object->io[0].intern+freq)>>3);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short(value>>14)) * ampl) >> 15;
}

static void dspRoutine_OSC_SAW_M(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short(object->io[0].intern>>15)) * ampl) >> 15;
}

static void dspRoutine_OSC_SAW_AA_H(DspObject *object) {
  int value;
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    value=(object->io[0].intern>>17);
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    value=((object->io[0].intern+(freq/4))>>3)+
          ((object->io[0].intern+(freq/2))>>3)+
          ((object->io[0].intern+3*(freq/4))>>3)+
          ((object->io[0].intern+freq)>>3);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short(value>>13)) * ampl) >> 15;
}

static void dspRoutine_OSC_SAW_H(DspObject *object) {
  int ampl;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  ampl = (*object->io[5].input + object->io[4].knob);
  object->io[0].output = ((short(object->io[0].intern>>14)) * ampl) >> 15;
}

//
// Oscillator is in SPS mode
//
static void dspRoutine_OSC_SPS_AA_L(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  int ampl = (*object->io[5].input + object->io[4].knob);
  int value = object->io[0].intern>>15;
  int old = object->io[1].intern;
  object->io[1].intern = (value&0x10000)?(0):((short(value+0x8000) * ampl) >> 15);
  object->io[0].output = (object->io[1].intern + old) /2;
}

static void dspRoutine_OSC_SPS_L(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  int ampl = (*object->io[5].input + object->io[4].knob);
  int value = object->io[0].intern>>15;
  object->io[0].output = (value&0x10000)?(0):((short(value+0x8000) * ampl) >> 15);
}

static void dspRoutine_OSC_SPS_AA_M(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  int ampl = (*object->io[5].input + object->io[4].knob);
  int value = object->io[0].intern>>14;
  int old = object->io[1].intern;
  object->io[1].intern = (value&0x10000)?(0):((short(value+0x8000) * ampl) >> 15);
  object->io[0].output = (object->io[1].intern + old) /2;
}

static void dspRoutine_OSC_SPS_M(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  int ampl = (*object->io[5].input + object->io[4].knob);
  int value = object->io[0].intern>>14;
  object->io[0].output = (value&0x10000)?(0):((short(value+0x8000) * ampl) >> 15);
}

static void dspRoutine_OSC_SPS_AA_H(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  int ampl = (*object->io[5].input + object->io[4].knob);
  int value = object->io[0].intern>>13;
  int old = object->io[1].intern;
  object->io[1].intern = (value&0x10000)?(0):((short(value+0x8000) * ampl) >> 15);
  object->io[0].output = (object->io[1].intern + old) /2;
}

static void dspRoutine_OSC_SPS_H(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    int freq=exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
    object->io[0].intern += freq;
  }
  object->io[6].intern = *object->io[6].input;

  int ampl = (*object->io[5].input + object->io[4].knob);
  int value = object->io[0].intern>>13;
  object->io[0].output = (value&0x10000)?(0):((short(value+0x8000) * ampl) >> 15);
}


//
// Oscillator is in PLS mode
//
static void dspRoutine_OSC_PLS_AA_L(DspObject *object) {
  int old=object->io[0].intern;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  {
    int ampl = (*object->io[5].input + object->io[4].knob);
    int pw = (*object->io[3].input + *object->io[4].input + object->io[2].knob);
    object->io[0].output = ((((old >> 16) > pw)?(ampl):(-ampl)) + (((short)(object->io[0].intern >> 16) > pw)?(ampl):(-ampl))) / 2;
  }
}

static void dspRoutine_OSC_PLS_L(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  {
    int ampl = (*object->io[5].input + object->io[4].knob);
    int pw = (*object->io[3].input + *object->io[4].input + object->io[2].knob);
    object->io[0].output = (((short)(object->io[0].intern >> 16)) > pw)?(ampl):(-ampl);
  }
}

static void dspRoutine_OSC_PLS_AA_M(DspObject *object) {
  int old=object->io[0].intern;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += 2*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  {
    int ampl = (*object->io[5].input + object->io[4].knob);
    int pw = (*object->io[3].input + *object->io[4].input + object->io[2].knob);
    object->io[0].output = ((((old >> 16) > pw)?(ampl):(-ampl)) + (((short)(object->io[0].intern >> 16) > pw)?(ampl):(-ampl))) / 2;
  }
}

static void dspRoutine_OSC_PLS_M(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += 2*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  {
    int ampl = (*object->io[5].input + object->io[4].knob);
    int pw = (*object->io[3].input + *object->io[4].input + object->io[2].knob);
    object->io[0].output = (((short)(object->io[0].intern >> 16)) > pw)?(ampl):(-ampl);
  }
}

static void dspRoutine_OSC_PLS_AA_H(DspObject *object) {
  int old=object->io[0].intern;

  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += 4*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  {
    int ampl = (*object->io[5].input + object->io[4].knob);
    int pw = (*object->io[3].input + *object->io[4].input + object->io[2].knob);
    object->io[0].output = ((((old >> 16) > pw)?(ampl):(-ampl)) + (((short)(object->io[0].intern >> 16) > pw)?(ampl):(-ampl))) / 2;
  }
}

static void dspRoutine_OSC_PLS_H(DspObject *object) {
  // Process sync input
  if (*object->io[6].input > 0 && object->io[6].intern<=0) {
    object->io[0].intern = 0;
  } else {
    object->io[0].intern += 4*exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
  }
  object->io[6].intern = *object->io[6].input;

  {
    int ampl = (*object->io[5].input + object->io[4].knob);
    int pw = (*object->io[3].input + *object->io[4].input + object->io[2].knob);
    object->io[0].output = (((short)(object->io[0].intern >> 16)) > pw)?(ampl):(-ampl);
  }
}

//
// Oscillator is in RND mode (sample and hold)
//
static void dspRoutine_OSC_RND_L(DspObject *object) {
  object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);

  if ((short)(object->io[0].intern>>13) > 0 && object->io[6].intern<=0) {
    int ampl = (*object->io[5].input + object->io[4].knob);
    dspRnd1 = dspRnd1*16807 ^ (dspRnd2++);
    object->io[0].output = (((short)(dspRnd1 >> 16)) * ampl) >> 15;
  }
  object->io[6].intern = (short)(object->io[0].intern>>13);
}


static void dspRoutine_OSC_RND_M(DspObject *object) {
  object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);

  if ((short)(object->io[0].intern>>12) > 0 && object->io[6].intern<=0) {
    int ampl = (*object->io[5].input + object->io[4].knob);
    dspRnd1 = dspRnd1*16807 ^ (dspRnd2++);
    object->io[0].output = (((short)(dspRnd1 >> 16)) * ampl) >> 15;
  }
  object->io[6].intern = (short)(object->io[0].intern>>12);
}

static void dspRoutine_OSC_RND_H(DspObject *object) {
  object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);

  if ((short)(object->io[0].intern>>11) > 0 && object->io[6].intern<=0) {
    int ampl = (*object->io[5].input + object->io[4].knob);
    dspRnd1 = dspRnd1*16807 ^ (dspRnd2++);
    object->io[0].output = (((short)(dspRnd1 >> 16)) * ampl) >> 15;
  }
  object->io[6].intern = (short)(object->io[0].intern>>11);
}

static void dspRoutine_QUADOSC(DspObject *object) {
	object->io[0].intern += exposc(object->io[0].knob + *object->io[0].input + *object->io[1].input) + (*object->io[2].input<<14);
	if (*object->io[6].input > 0 && object->io[6].intern<=0) {
		object->io[0].intern = 0;
	}
	object->io[6].intern = *object->io[6].input;
    int ampl = (*object->io[5].input + object->io[2].knob);
    int phase = 2*(*object->io[3].input + *object->io[4].input);
	object->io[0].output = (SINTBL[(    0+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
	object->io[1].output = (SINTBL[( 8192+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
	object->io[2].output = (SINTBL[(16384+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
	object->io[3].output = (SINTBL[(24576+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
	object->io[4].output = (SINTBL[(32768+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
	object->io[5].output = (SINTBL[(40960+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
	object->io[6].output = (SINTBL[(49152+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
	object->io[7].output = (SINTBL[(57344+phase+(unsigned)(object->io[0].intern >> 16)) % 65536] * ampl) >> 15;
}

//
// Midi processing
//
static int miditime; // This is used to search oldest note
void patchProcessMidi(int msg) {
	if (thePlayingProject>=0) {
		if (((msg&0xFF)==0xF8) || ((msg&0xFF)==0xFA) || ((msg&0xFF)==0xFB) || ((msg&0xFF)==0xFC)) {
			int i;

			for(i=0;i<projects[thePlayingProject].maxPatches;i++) {
				if (projects[thePlayingProject].patches[i].midiClockPort==(msg>>24)) {
					int j;

					for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
						if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDICLOCK) {
							switch(msg&0xFF) {
							case 0xF8:
								// Clock
								if (projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[2].intern) {
									// Start/Stop controlled clock
									projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[0].intern++;
								}
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[1].intern++;
								break;
							case 0xFA:
								// Start
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[2].intern=32767;
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].intern=32767;
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[4].intern=projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[0].intern;
							case 0xFB:
								// Continue
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[2].intern=32767;
							case 0xFC:
								// Stop
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[2].intern=0;
							}
						}
					}
				}
			}
		} else {
			int i;

			for(i=0;i<projects[thePlayingProject].maxPatches;i++) {
				if (projects[thePlayingProject].patches[i].midiPort==(msg>>24)
						&& (projects[thePlayingProject].patches[i].midiChannel-1==(msg&0x0F)
						|| projects[thePlayingProject].patches[i].midiChannel==0)) {
					int j;

					switch(msg&0xF0) {
					case 0x80:	// Note off
						for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
							if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDINOTE
									&& projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[0].intern==((msg>>8)&127)) {
								if (projects[thePlayingProject].patches[i].sustainValue<64) {
									projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[2].output=((msg>>16)&127)*256; // RelVelocity
									projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].output=0;                   // Gate
									projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[1].intern=miditime++;
								}

								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].intern=0;
							}
						}
						break;
					case 0x90: // Note on/off
						if (((msg>>16)&127)==0) {
							// Note off
							for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
								if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDINOTE
										&& projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[0].intern==((msg>>8)&127)) {
									if (projects[thePlayingProject].patches[i].sustainValue<64) {
										projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[2].output=64*256; // RelVelocity
										projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].output=0;                   // Gate
										projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[1].intern=miditime++;
									}
									projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].intern=0;
								}
							}
						} else {
							// Note on
							DspObject *rObj=NULL;
							DspObject *bObj=NULL;
							int rTime=0x7FFFFFFF;
							int bTime=0x7FFFFFFF;
							int j;

							for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
								if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDINOTE) {
									DspObject *obj=&(projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp]);
									if (obj->io[3].output) {
										// Playing note
										if (obj->io[1].intern<bTime) {
											bTime=obj->io[1].intern;
											bObj=obj;
										}
									} else {
										// Released note
										if (obj->io[1].intern<rTime) {
											rTime=obj->io[1].intern;
											rObj=obj;
										}
									}
								}
							}

							// Prefer reusing released notes, but otherwise do recent note priority
							if (rObj) {
								rObj->io[0].output=182*((msg>>8)&127)+12249;
								rObj->io[1].output=((msg>>16)&127)*256; // AtkVel
								rObj->io[2].output=0;              // RelVel
								rObj->io[3].output=32767;          // Gate
								rObj->io[0].intern=(msg>>8)&127;
								rObj->io[1].intern=miditime++;
								rObj->io[3].intern=32767;
							} else if (bObj) {
								// Reuse hold note, must use delayed gate (at least single pulse to 0)
								bObj->io[0].output=182*((msg>>8)&127)+12249;
								bObj->io[1].output=((msg>>16)&127)*256; // AtkVel
								bObj->io[2].output=0;              // RelVel
								bObj->io[3].output=-32;            // Gate
								bObj->io[0].intern=(msg>>8)&127;
								bObj->io[1].intern=miditime++;
								bObj->io[3].intern=32767;
							}             
						}
						break;


					case 0xB0: { // CC Continueous controllers
						ObjectType objectType=OBJ_NONE;
						int offset=0;

						for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
							if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDICCUSR) {
								if (((msg>>8)&127)==projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[0].knob/256) {
									projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[offset].output=((msg>>16)&127)*256;
								}
							}
						}

						if (projects[thePlayingProject].patches[i].sustainCC == ((msg>>8)&127)) {
							// Release all sustained notes
							if ((projects[thePlayingProject].patches[i].sustainValue>63) && ((msg>>16)&127)<64) {
								for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
									if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDINOTE
											&& projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].intern==0
											&& projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].output==32767) {
										projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[2].output=64*256; // RelVelocity
										projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[3].output=0;      // Gate
										projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[1].intern=miditime++;
									}
								}
							}
							projects[thePlayingProject].patches[i].sustainValue = ((msg>>16)&127);
						}

						switch((msg>>8)&127) {
							case  1: offset=0; objectType=OBJ_MIDICC1; break;
							case  2: offset=1; objectType=OBJ_MIDICC1; break;
							case  4: offset=2; objectType=OBJ_MIDICC1; break;
							case  5: offset=3; objectType=OBJ_MIDICC1; break;
							case  7: offset=4; objectType=OBJ_MIDICC1; break;
							case  8: offset=5; objectType=OBJ_MIDICC1; break;
							case 10: offset=6; objectType=OBJ_MIDICC1; break;
							case 11: offset=7; objectType=OBJ_MIDICC1; break;
							case 12: offset=8; objectType=OBJ_MIDICC1; break;
							case 13: offset=9; objectType=OBJ_MIDICC1; break;
							case 14: offset=10; objectType=OBJ_MIDICC1; break;
							case 15: offset=11; objectType=OBJ_MIDICC1; break;
							case 16: offset=12; objectType=OBJ_MIDICC1; break;
							case 17: offset=13; objectType=OBJ_MIDICC1; break;
							case 18: offset=14; objectType=OBJ_MIDICC1; break;
							case 19: offset=15; objectType=OBJ_MIDICC1; break;

							case 41: offset=0; objectType=OBJ_MIDICC2; break;
							case 42: offset=1; objectType=OBJ_MIDICC2; break;
							case 43: offset=2; objectType=OBJ_MIDICC2; break;
							case 44: offset=3; objectType=OBJ_MIDICC2; break;
							case 45: offset=4; objectType=OBJ_MIDICC2; break;
							case 46: offset=5; objectType=OBJ_MIDICC2; break;
							case 47: offset=6; objectType=OBJ_MIDICC2; break;
							case 48: offset=7; objectType=OBJ_MIDICC2; break;
							case 70: offset=8; objectType=OBJ_MIDICC2; break;
							case 71: offset=9; objectType=OBJ_MIDICC2; break;
							case 72: offset=10; objectType=OBJ_MIDICC2; break;
							case 73: offset=11; objectType=OBJ_MIDICC2; break;
							case 74: offset=12; objectType=OBJ_MIDICC2; break;
							case 75: offset=13; objectType=OBJ_MIDICC2; break;
							case 76: offset=14; objectType=OBJ_MIDICC2; break;
							case 77: offset=15; objectType=OBJ_MIDICC2; break;
							case 78: offset=16; objectType=OBJ_MIDICC2; break;
							case 79: offset=17; objectType=OBJ_MIDICC2; break;

							case 80: offset=18; objectType=OBJ_MIDICC2; break;
							case 81: offset=19; objectType=OBJ_MIDICC2; break;
							case 82: offset=20; objectType=OBJ_MIDICC2; break;
							case 83: offset=21; objectType=OBJ_MIDICC2; break;

							case 20: offset=0; objectType=OBJ_MIDICC3; break;
							case 21: offset=1; objectType=OBJ_MIDICC3; break;
							case 22: offset=2; objectType=OBJ_MIDICC3; break;
							case 23: offset=3; objectType=OBJ_MIDICC3; break;
							case 24: offset=4; objectType=OBJ_MIDICC3; break;
							case 25: offset=5; objectType=OBJ_MIDICC3; break;
							case 26: offset=6; objectType=OBJ_MIDICC3; break;
							case 27: offset=7; objectType=OBJ_MIDICC3; break;
							case 28: offset=8; objectType=OBJ_MIDICC3; break;
							case 29: offset=9; objectType=OBJ_MIDICC3; break;
							case 30: offset=10; objectType=OBJ_MIDICC3; break;
							case 31: offset=11; objectType=OBJ_MIDICC3; break;
							case 32: offset=12; objectType=OBJ_MIDICC3; break;
							case 33: offset=13; objectType=OBJ_MIDICC3; break;
							case 34: offset=14; objectType=OBJ_MIDICC3; break;
							case 35: offset=15; objectType=OBJ_MIDICC3; break;
							case 36: offset=16; objectType=OBJ_MIDICC3; break;
							case 37: offset=17; objectType=OBJ_MIDICC3; break;
							case 38: offset=18; objectType=OBJ_MIDICC3; break;
							case 39: offset=19; objectType=OBJ_MIDICC3; break;
							case 40: offset=20; objectType=OBJ_MIDICC3; break;

							case 3:  offset=0; objectType=OBJ_MIDICC4; break;
							case 9:  offset=1; objectType=OBJ_MIDICC4; break;
							case 49: offset=2; objectType=OBJ_MIDICC4; break;
							case 50: offset=3; objectType=OBJ_MIDICC4; break;
							case 51: offset=4; objectType=OBJ_MIDICC4; break;
							case 52: offset=5; objectType=OBJ_MIDICC4; break;
							case 53: offset=6; objectType=OBJ_MIDICC4; break;
							case 54: offset=7; objectType=OBJ_MIDICC4; break;
							case 55: offset=8; objectType=OBJ_MIDICC4; break;
							case 56: offset=9; objectType=OBJ_MIDICC4; break;
							case 57: offset=10; objectType=OBJ_MIDICC4; break;
							case 58: offset=11; objectType=OBJ_MIDICC4; break;
							case 59: offset=12; objectType=OBJ_MIDICC4; break;
							case 60: offset=13; objectType=OBJ_MIDICC4; break;
							case 61: offset=14; objectType=OBJ_MIDICC4; break;
							case 62: offset=15; objectType=OBJ_MIDICC4; break;
							case 63: offset=16; objectType=OBJ_MIDICC4; break;
							case 64: offset=17; objectType=OBJ_MIDICC4; break;
							case 65: offset=18; objectType=OBJ_MIDICC4; break;
							case 66: offset=19; objectType=OBJ_MIDICC4; break;
							case 67: offset=20; objectType=OBJ_MIDICC4; break;
							case 68: offset=21; objectType=OBJ_MIDICC4; break;
							case 69: offset=22; objectType=OBJ_MIDICC4; break;
							default:
								break;
							}

							if (objectType!=OBJ_NONE) {
								for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
									if (projects[thePlayingProject].patches[i].objects[j].objectType==objectType) {
										projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[offset].output=((msg>>16)&127)*256;
									}
								}
							}
						} break;
					case 0xD0: // Channel aftertouch
						for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
							if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDINOTE) {
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[4].output=((msg>>8)&127)*256;
							}
						}
						break;
					case 0xE0: // Pitch bend
						int j;
						for(j=0;j<projects[thePlayingProject].patches[i].maxObjects;j++) {
							if (projects[thePlayingProject].patches[i].objects[j].objectType==OBJ_MIDINOTE) {
								projects[thePlayingProject].dsp[projects[thePlayingProject].patches[i].objects[j].dsp].io[5].output=-32768+(((msg>>16)&127)*128+((msg>>8)&127))*4;
							}
						}
						break;
					default:
						break;
					}
				}
			}
		}
	}
}

