1 2// elpelele.saol 3// "El Pelele, E. Granados", MIDI: R. Finley, Piano: E. Scheirer 4// Originally written by Eric Scheirer 5// Modified by John Lazzaro 6// song length: 8 minutes, 50.192 seconds (530.192 seconds) 7// 8 9global { 10 interp 0; 11 srate 44100; 12 krate 1050; 13 ksig rvb_on, distance; 14 outchannels 2; 15 table A0(sample, - 1, "samp_1.aif"); 16 table C2(sample, - 1, "samp_3.aif"); 17 table F2(sample, - 1, "samp_5.aif"); 18 table Ds3(sample, - 1, "samp_7.aif"); 19 table Cs4(sample, - 1, "samp_9.aif"); 20 table Fs4(sample, - 1, "samp_11.aif"); 21 table B4(sample, - 1, "samp_13.aif"); 22 route (dry, piano); 23 24// change "large_room" to "small_room" or "schroeder" 25// for alternative reverbs 26 27 send (large_room; 0.650000, 1; dry); 28 route (wet, large_room); 29 30 send (mix;; dry, wet); 31 } 32 33// 34// instr piano 35// 36// sample player of global tables 37// 38 39instr piano (pitch, vel) preset 0 { 40 ivar cps, scale, t, l, b, cut; 41 ksig kamp, localtime, segment, first; 42 asig samp; 43 // selects sample based on midi numbers 44 table pitchmap(step, - 1, 0, 0, 28, 1, 38, 2, 46, 3, 55, 4, 64, 5, 69, 6, 200); 45 // bogus loop points -- samples are long enough w/o looping 46 table loop(data, - 1, 197584, 151848, 137124, 132915, 104285, 59648, 50773); 47 // base frequency for each table 48 table base(data, - 1, 21, 36, 41, 51, 61, 66, 71); 49 imports exports table A0, C2, F2, Ds3, Cs4, Fs4, B4; 50 // pno[] indexed by pitchmap values 51 tablemap pno (A0, C2, F2, Ds3, Cs4, Fs4, B4); 52 53 if (! first) { 54 segment = 1; 55 first = 1; 56 } 57 58 // i-rate -- starting parameters for note 59 60 pitch = pitch - 12; 61 t = tableread (pitchmap, pitch); 62 l = tableread (loop, t); 63 b = cpsmidi (tableread (base, t)); 64 cps = cpsmidi (pitch); 65 scale = (vel / 128) * (vel / 128) / 2; 66 67 // k-rate -- note envelope 68 69 localtime = localtime + 1 / k_rate; 70 if (segment == 1) { 71 if (localtime < 0.010000) { 72 kamp = kline (0, 0.010000, scale); 73 } 74 else { 75 segment = 2; 76 } 77 } 78 if (segment == 2) { 79 kamp = scale; 80 if (localtime > 5.000000) { 81 segment = 4; 82 turnoff; 83 } 84 } 85 if (released && segment < 3) { 86 if (MIDIctrl[64] > 15) { 87 segment = 3; 88 extend (5.000000 - localtime); 89 } 90 else { 91 segment = 4; 92 localtime = 0; 93 extend (0.100000); 94 } 95 } 96 if (segment == 3) { 97 if (MIDIctrl[64] <= 15) { 98 segment = 4; 99 localtime = 0; 100 } 101 else { 102 kamp = scale; 103 if (localtime >= 5.000000) { 104 turnoff; 105 } 106 } 107 } 108 if (segment == 4) { 109 kamp = var_kline(scale, 0.100000, 0); 110 if (localtime >= 0.100000) { 111 turnoff; 112 } 113 } 114 115 // a-rate 116 117 samp = kamp * loscil(pno [ t ], cps, b, l); 118 output (samp * (1 - (pitch / 100)), samp * pitch / 100); 119 120 } 121 122// 123// opcode var_kline -- helper routine for piano 124// 125 126kopcode var_kline(ksig st, ksig t, ksig e) { 127 ksig ltime, val; 128 129 val = ltime / t * (e - st) + st; 130 ltime = ltime + 1 / k_rate; 131 return (val); 132 } 133 134// 135// instr large_room 136// 137// used in default settings 138// 139 140instr large_room (revgain, distance) { 141 asig first; 142 ivar f, lpf_pos, lpf_cut, d2; 143 asig out[2]; 144 table sections (data, - 1, 1, 10, 43, 44, 164, 165, 242); 145 table gains(data, - 1, 0.300000, 0.300000, 0.500000, 0.250000, 0.500000, 0.250000, 0.250000); 146 table lengths (data, - 1, 8, 12, 87, 62, 120, 76, 30); 147 table outs(data, - 1, 26, 161, 290); 148 table outg(data, - 1, 0.340000, 0.140000, 0.140000); 149 ksig num_sec, num_out; 150 151 152// i-rate 153 154 lpf_pos = 295; 155 lpf_cut= 2600; 156 d2 = distance * distance; 157 158// k-rate 159 160 num_sec= ftlen (sections); 161 num_out = ftlen (outs); 162 163// a-rate 164 165 out = gen_allpass(sections, num_sec, gains, lengths, outs, num_out, outg, 166 lpf_pos, lpf_cut, 1 / 1000, revgain); 167 168 output ((input[0]/ d2 + out[0]) * distance, (input[1]/ d2 + out[1]) * distance); 169 } 170 171// 172// gen_allpass -- where *_room reverb gets computed 173// 174// uses fracdelay as a reverberation engine 175// 176 177aopcode gen_allpass(table sections, ksig num_sec, table gains, 178 table lengths, table outs, ksig num_out, 179 table outg, ivar lpf_pos, ivar lpf_cut, ivar f, ivar revgain) { 180 181 oparray fracdelay[1]; 182 asig first, outl, outr, p1, p2, g, tap1, tap2, i, fb, sum; 183 184 // initializes fracdelat as a 300ms tapped line 185 186 if (! first && input[0]) { 187 fracdelay[0](1, 0.300000); 188 first = 1; 189 } 190 191 if (first) { 192 193 // recirculate delay taps through line 194 195 i = 0; 196 while (i < num_sec) { 197 p1 = tableread (sections, i) * f; 198 p2 = floor (p1 + tableread (lengths, i) * f); 199 g = tableread (gains, i); 200 tap1 = fracdelay[0](2, p1); // read tap 201 fracdelay[0](4, p2, tap1 * - g); // add back in 202 tap2 = fracdelay[0](2, p2); // read tap 203 fracdelay[0](4, p1, tap2 * g); // add back in 204 i = i + 1; 205 } 206 207 // compute new output 208 209 outl = 0; 210 outr = 0; 211 i = 0; 212 while (i < num_out) { 213 p1 = tableread (outs, i) * f; 214 g = tableread (outg, i); 215 outl = outl + fracdelay[0](2, p1) * g; 216 outr = outr + fracdelay[0](2, p1 + pow (- 1, i) * f) * g; 217 i = i + 1; 218 } 219 p1 = lpf_pos * f; 220 tap1 = fracdelay[0](2, p1); 221 fb = lopass (tap1, lpf_cut) * revgain; 222 i = 0; 223 224 // compute new input into line 225 226 sum = 0; 227 while (i < 2) { 228 sum = sum + input [ i ]; 229 i = i + 1; 230 } 231 232 // insert new input, then shift 233 234 fracdelay[0](3, 0, sum + fb); 235 fracdelay[0](5); 236 return (outl, outr); 237 } 238 else { 239 return (0, 0); 240 } 241 } 242 243// 244// instr mix 245// 246// mixes reverb and direct sound equally 247// 248 249instr mix () { 250 asig out[2]; 251 252 out[0] = input[0]*1 + input[1]*0 + input[2]*1 + input[3]*0; 253 out[1] = input[0]*0 + input[1]*1 + input[2]*0 + input[3]*1; 254 output(out); 255 } 256 257// 258// instr small_room 259// 260// alternative reverb, uses gen_allpass as engine 261// 262 263instr small_room (revgain) { 264 asig first; 265 ivar f, lpf_pos, lpf_cut, d2; 266 asig out[2]; 267 table sections (data, - 1, 24, 25, 48, 61, 62); 268 table gains (data, - 1, 0.300000, 0.400000, 0.600000, 269 0.100000, 0.400000); 270 table lengths (data, - 1, 35, 22, 8.300000, 66, 30); 271 table outs (data, - 1, 60, 129); 272 table outg (data, - 1, 0.500000, 0.500000); 273 ksig num_sec, num_out; 274 275// i-rate 276 277 lpf_pos = 128; 278 lpf_cut = 4200; 279 280 num_sec= ftlen (sections); 281 num_out = ftlen (outs); 282 283// k-rate 284 285 out = gen_allpass(sections, num_sec, gains, lengths, outs, num_out, 286 outg, lpf_pos, lpf_cut, 1 / 1000, revgain); 287 output (out); 288 } 289 290// 291// instr schroeder 292// 293// alternative reverb, uses comb and allpass sections 294// 295 296instr schroeder (rt) { 297 ksig first, ki, d2; 298 asig in, ap1, ap2; 299 asig c[4]; 300 asig outL, outR; 301 ivar t[4], revgain[4], i; 302 table timeconst (data, 5, 0.030000, 0.034300, 0.039300, 303 0.045000, 0.000000); 304 imports exports ksig rvb_on, distance; 305 oparray comb [4]; 306 307 in = input[0]+ input[1]; 308 if (first == 0) { 309 rvb_on = 1; 310 first = 1; 311 distance = 0.600000; 312 } 313 d2 = distance * distance; 314 i = 0; 315 while (i < 4) { 316 t [ i ] = tableread (timeconst, i); 317 revgain [ i ] = combgain (t [ i ], rt); 318 i = i + 1; 319 } 320 if (rvb_on) { 321 ap1 = allpass (in / distance, 0.001700, 0.700000); 322 ap2 = allpass (ap1, 0.005000, 0.700000); 323 c[0]= comb (ap2, t[0], revgain[0]); 324 c[1]= comb (ap2, t[1], revgain[1]); 325 c[2]= comb (ap2, t[2], revgain[2]); 326 c[3]= comb (ap2, t[3], revgain[3]); 327 outL = (c[0]+ c[1]+ c[2]+ c[3]) / 4; 328 outR = (c[0]- c[1]+ c[2]- c[3]) / 4; 329 output ((input[0]/ d2 + outL) * distance * 0.750000, 330 (input[1]/ d2 + outR) * distance * 0.750000); 331 } 332 else { 333 output (input); 334 } 335 } 336 337// 338// opcode combgain 339// 340// helper routine for schroeder 341// 342 343opcode combgain (xsig t, xsig rt) { 344 xsig temp; 345 346 temp = exp (log (10) * - 3 * t / rt); 347 return (temp); 348 } 349