// new SAOL translation attempt global { srate 44100; krate 8820; outchannels 1; ksig gkLFO, gkamp; } instr globalfade (risetime) { // p4 is rise AND decay time exports ksig gkamp; // WARNING: this will break if tempo goes too fast! // Time args are in seconds, not score beats!!! gkamp = kexpon(0.005, risetime, 1, dur - (risetime * 2), 1, risetime , 0.005); } instr globalLFO (startrate, endrate) { ksig lfo_freq; exports ksig gkLFO; imports table sine; lfo_freq = kline(startrate, dur, endrate); gkLFO = 0.5 + 0.5 * koscil(sine, lfo_freq); // normalized from 0 to 1 } instr pwm(initpitch, endpitch, moddepth) { // another try by PW // We simulate a square wave by overdriving a table index, // with a halfsine wav; thus, aliasing can be reduced by // scaling the amount of overdrive inversely with pitch. // It's not strictly band-limited, but it sounds pretty good. // We then simulate pulse-width modulation by // varying an offset to the index. imports table halfsine, triangle; imports ksig gkLFO; imports ksig gkamp; ivar initfreq, endfreq, iantialias; ksig ksquareness; ksig kfreq; ksig halfsinelen; // only needed at i-rate, but oh well. ksig knarrowness, kamp, ksmoothness; ksig highlimit, lowlimit; ksig kcenter, kwidth; asig index, aout, afiltered, rawindex; initfreq = cpspch(initpitch); endfreq = cpspch(endpitch); // clamp to nyquist initfreq = min(initfreq, s_rate / 2); endfreq = min(endfreq, s_rate / 2); kfreq = kexpon(initfreq, dur, endfreq); iantialias = 4; //recommended range is 4 to about 10 // 7 is adequate to almost totally eliminate aliasing from square ksmoothness = min(1, kfreq * iantialias / s_rate); // 1 (the maximum) yields a nearly pure square wave. // 0 yields a pure sine wave. kcenter = (gkLFO * moddepth * (1 - ksmoothness)) * 0.5 + 0.5; kwidth = ksmoothness; // Suggested range for moddepth is 0 to 1. // prevent clipping points from going out of bounds kwidth = min(kwidth, 0.5); kwidth = max(kwidth, 0); kcenter = min(kcenter, 1); kcenter = max(kcenter, 0.5); highlimit = min(1, kcenter + kwidth); lowlimit = max(0, kcenter - kwidth); if (highlimit == lowlimit) { // avoid divide-by-zero... and some work! index = 0; } else { index = oscil(triangle, kfreq); // clip it index = min(index, highlimit); index = max(index, lowlimit); // normalize - first the floor... index = index - lowlimit ; // ... now normalize the peak to 1 index = index / (highlimit - lowlimit); } halfsinelen = ftlen(halfsine) -1; // now we've finally got something suitable for // using as an index. aout = tableread(halfsine, index * halfsinelen); // Attempt to remove DC offset... do I need somethign better? afiltered = hipass(aout, 15); // and smooth it a bit. //afiltered = lopass(afiltered, 8000); // apply global gain control, and declick. kamp = gkamp * kline(0, .01, 1, .02, .5, dur -.23, .5, .2, 0); output(aout * kamp); }