// elpelele.saol // "El Pelele, E. Granados", MIDI: R. Finley, Piano: E. Scheirer // Originally written by Eric Scheirer // Modified by John Lazzaro // song length: 8 minutes, 50.192 seconds (530.192 seconds) // global { interp 0; srate 44100; krate 1050; ksig rvb_on, distance; outchannels 2; table A0(sample, - 1, "samp_1.aif"); table C2(sample, - 1, "samp_3.aif"); table F2(sample, - 1, "samp_5.aif"); table Ds3(sample, - 1, "samp_7.aif"); table Cs4(sample, - 1, "samp_9.aif"); table Fs4(sample, - 1, "samp_11.aif"); table B4(sample, - 1, "samp_13.aif"); route (dry, piano); // change "large_room" to "small_room" or "schroeder" // for alternative reverbs send (large_room; 0.650000, 1; dry); route (wet, large_room); send (mix;; dry, wet); } // // instr piano // // sample player of global tables // instr piano (pitch, vel) preset 0 { ivar cps, scale, t, l, b, cut; ksig kamp, localtime, segment, first; asig samp; // selects sample based on midi numbers table pitchmap(step, - 1, 0, 0, 28, 1, 38, 2, 46, 3, 55, 4, 64, 5, 69, 6, 200); // bogus loop points -- samples are long enough w/o looping table loop(data, - 1, 197584, 151848, 137124, 132915, 104285, 59648, 50773); // base frequency for each table table base(data, - 1, 21, 36, 41, 51, 61, 66, 71); imports exports table A0, C2, F2, Ds3, Cs4, Fs4, B4; // pno[] indexed by pitchmap values tablemap pno (A0, C2, F2, Ds3, Cs4, Fs4, B4); if (! first) { segment = 1; first = 1; } // i-rate -- starting parameters for note pitch = pitch - 12; t = tableread (pitchmap, pitch); l = tableread (loop, t); b = cpsmidi (tableread (base, t)); cps = cpsmidi (pitch); scale = (vel / 128) * (vel / 128) / 2; // k-rate -- note envelope localtime = localtime + 1 / k_rate; if (segment == 1) { if (localtime < 0.010000) { kamp = kline (0, 0.010000, scale); } else { segment = 2; } } if (segment == 2) { kamp = scale; if (localtime > 5.000000) { segment = 4; turnoff; } } if (released && segment < 3) { if (MIDIctrl[64] > 15) { segment = 3; extend (5.000000 - localtime); } else { segment = 4; localtime = 0; extend (0.100000); } } if (segment == 3) { if (MIDIctrl[64] <= 15) { segment = 4; localtime = 0; } else { kamp = scale; if (localtime >= 5.000000) { turnoff; } } } if (segment == 4) { kamp = var_kline(scale, 0.100000, 0); if (localtime >= 0.100000) { turnoff; } } // a-rate samp = kamp * loscil(pno [ t ], cps, b, l); output (samp * (1 - (pitch / 100)), samp * pitch / 100); } // // opcode var_kline -- helper routine for piano // kopcode var_kline(ksig st, ksig t, ksig e) { ksig ltime, val; val = ltime / t * (e - st) + st; ltime = ltime + 1 / k_rate; return (val); } // // instr large_room // // used in default settings // instr large_room (revgain, distance) { asig first; ivar f, lpf_pos, lpf_cut, d2; asig out[2]; table sections (data, - 1, 1, 10, 43, 44, 164, 165, 242); table gains(data, - 1, 0.300000, 0.300000, 0.500000, 0.250000, 0.500000, 0.250000, 0.250000); table lengths (data, - 1, 8, 12, 87, 62, 120, 76, 30); table outs(data, - 1, 26, 161, 290); table outg(data, - 1, 0.340000, 0.140000, 0.140000); ksig num_sec, num_out; // i-rate lpf_pos = 295; lpf_cut= 2600; d2 = distance * distance; // k-rate num_sec= ftlen (sections); num_out = ftlen (outs); // a-rate out = gen_allpass(sections, num_sec, gains, lengths, outs, num_out, outg, lpf_pos, lpf_cut, 1 / 1000, revgain); output ((input[0]/ d2 + out[0]) * distance, (input[1]/ d2 + out[1]) * distance); } // // gen_allpass -- where *_room reverb gets computed // // uses fracdelay as a reverberation engine // aopcode gen_allpass(table sections, ksig num_sec, table gains, table lengths, table outs, ksig num_out, table outg, ivar lpf_pos, ivar lpf_cut, ivar f, ivar revgain) { oparray fracdelay[1]; asig first, outl, outr, p1, p2, g, tap1, tap2, i, fb, sum; // initializes fracdelat as a 300ms tapped line if (! first && input[0]) { fracdelay[0](1, 0.300000); first = 1; } if (first) { // recirculate delay taps through line i = 0; while (i < num_sec) { p1 = tableread (sections, i) * f; p2 = floor (p1 + tableread (lengths, i) * f); g = tableread (gains, i); tap1 = fracdelay[0](2, p1); // read tap fracdelay[0](4, p2, tap1 * - g); // add back in tap2 = fracdelay[0](2, p2); // read tap fracdelay[0](4, p1, tap2 * g); // add back in i = i + 1; } // compute new output outl = 0; outr = 0; i = 0; while (i < num_out) { p1 = tableread (outs, i) * f; g = tableread (outg, i); outl = outl + fracdelay[0](2, p1) * g; outr = outr + fracdelay[0](2, p1 + pow (- 1, i) * f) * g; i = i + 1; } p1 = lpf_pos * f; tap1 = fracdelay[0](2, p1); fb = lopass (tap1, lpf_cut) * revgain; i = 0; // compute new input into line sum = 0; while (i < 2) { sum = sum + input [ i ]; i = i + 1; } // insert new input, then shift fracdelay[0](3, 0, sum + fb); fracdelay[0](5); return (outl, outr); } else { return (0, 0); } } // // instr mix // // mixes reverb and direct sound equally // instr mix () { asig out[2]; out[0] = input[0]*1 + input[1]*0 + input[2]*1 + input[3]*0; out[1] = input[0]*0 + input[1]*1 + input[2]*0 + input[3]*1; output(out); } // // instr small_room // // alternative reverb, uses gen_allpass as engine // instr small_room (revgain) { asig first; ivar f, lpf_pos, lpf_cut, d2; asig out[2]; table sections (data, - 1, 24, 25, 48, 61, 62); table gains (data, - 1, 0.300000, 0.400000, 0.600000, 0.100000, 0.400000); table lengths (data, - 1, 35, 22, 8.300000, 66, 30); table outs (data, - 1, 60, 129); table outg (data, - 1, 0.500000, 0.500000); ksig num_sec, num_out; // i-rate lpf_pos = 128; lpf_cut = 4200; num_sec= ftlen (sections); num_out = ftlen (outs); // k-rate out = gen_allpass(sections, num_sec, gains, lengths, outs, num_out, outg, lpf_pos, lpf_cut, 1 / 1000, revgain); output (out); } // // instr schroeder // // alternative reverb, uses comb and allpass sections // instr schroeder (rt) { ksig first, ki, d2; asig in, ap1, ap2; asig c[4]; asig outL, outR; ivar t[4], revgain[4], i; table timeconst (data, 5, 0.030000, 0.034300, 0.039300, 0.045000, 0.000000); imports exports ksig rvb_on, distance; oparray comb [4]; in = input[0]+ input[1]; if (first == 0) { rvb_on = 1; first = 1; distance = 0.600000; } d2 = distance * distance; i = 0; while (i < 4) { t [ i ] = tableread (timeconst, i); revgain [ i ] = combgain (t [ i ], rt); i = i + 1; } if (rvb_on) { ap1 = allpass (in / distance, 0.001700, 0.700000); ap2 = allpass (ap1, 0.005000, 0.700000); c[0]= comb (ap2, t[0], revgain[0]); c[1]= comb (ap2, t[1], revgain[1]); c[2]= comb (ap2, t[2], revgain[2]); c[3]= comb (ap2, t[3], revgain[3]); outL = (c[0]+ c[1]+ c[2]+ c[3]) / 4; outR = (c[0]- c[1]+ c[2]- c[3]) / 4; output ((input[0]/ d2 + outL) * distance * 0.750000, (input[1]/ d2 + outR) * distance * 0.750000); } else { output (input); } } // // opcode combgain // // helper routine for schroeder // opcode combgain (xsig t, xsig rt) { xsig temp; temp = exp (log (10) * - 3 * t / rt); return (temp); }