1# Translator: Michael Scholz <mi-scholz@users.sourceforge.net>
2# Created: 02/11/20 02:24:34
3# Changed: 14/11/23 03:36:55
4
5# fm_violin(start, dur, freq, amp, *args)
6# play_fm_violin(start, dur, freq, amp, *args)
7# make_fm_violin(start, dur, freq, amp, *args)
8# jc_reverb(*args)
9
10require "ws"
11
12v_opts_str = "fm_violin(start=0.0, dur=1.0, freq=440.0, amp=0.5, *args)
13 :fm_index              = 1.0
14 :amp_env               = [0, 0, 25, 1, 75, 1, 100, 0]
15 :periodic_vibrato_rate = 5.0
16 :random_vibrato_rate   = 16.0
17 :periodic_vibrato_amp  = 0.0025
18 :random_vibrato_amp    = 0.005
19 :noise_amount          = 0.0
20 :noise_freq            = 1000.0
21 :ind_noise_freq        = 10.0
22 :ind_noise_amount      = 0.0
23 :amp_noise_freq        = 20.0
24 :amp_noise_amount      = 0.0
25 :gliss_env             = [0, 0, 100, 0]
26 :gliss_amount          = 0.0
27 :fm1_env               = [0, 1, 25, 0.4, 75, 0.6, 100, 0]
28 :fm2_env               = [0, 1, 25, 0.4, 75, 0.6, 100, 0]
29 :fm3_env               = [0, 1, 25, 0.4, 75, 0.6, 100, 0]
30 :fm1_rat               = 1.0
31 :fm2_rat               = 3.0
32 :fm3_rat               = 4.0
33 :fm1_index             = false
34 :fm2_index             = false
35 :fm3_index             = false
36 :base                  = 1.0
37 :index_type            = :violin"
38
39add_help(:fm_violin,
40         "#{v_opts_str}
41 :reverb_amount         = 0.01
42 :degree                = kernel_rand(90.0)
43 :distance              = 1.0
44  Ruby: fm_violin(0, 1, 440, 0.1, :fm_index, 2.0)
45Scheme: (fm-violin 0 1 440 0.1 :fm-index 2.0)
46Example: with_sound do fm_violin(0, 1, 440, 0.1, :fm_index, 2.0) end")
47def fm_violin(start = 0.0, dur = 1.0, freq = 440.0, amp = 0.5, *args)
48  r = get_args(args, :reverb_amount, 0.01)
49  d = get_args(args, :degree, kernel_rand(90.0))
50  s = get_args(args, :distance, 1.0)
51  fm_vln = make_fm_violin_gen(start, dur, freq, amp, *args)
52  run_instrument(start, dur, :reverb_amount, r, :degree, d, :distance, s) do
53    fm_vln.call(0)
54  end
55end
56
57add_help(:play_fm_violin,
58         "play_#{v_opts_str}
59Returns a fm_violin proc with no arg for play(proc).
60v = play_fm_violin(0, 1, 440, 0.5)
61play(v)
62or
63play(play_fm_violin(0, 1, 440, 0.5))")
64def play_fm_violin(start = 0.0, dur = 1.0, freq = 440.0, amp = 0.5, *args)
65  fm_vln = make_fm_violin_gen(start, dur, freq, amp, *args)
66  len = seconds2samples(dur)
67	lambda do
68    (len -= 1).positive? and fm_vln.call(0)
69  end
70end
71
72#
73# make_fm_violin: returns lambda do |y| ... end
74#
75add_help(:make_fm_violin,
76         "make_#{v_opts_str}
77Returns a proc with one arg for map_channel()
78*args are like fm_violin's
79ins = new_sound(:file, \"fmv.snd\", :srate, 22050, :channels, 2)
80# proc with one arg
81fmv1 = make_fm_violin(0, 1, 440, 0.5)
82map_channel(fmv1, 0, 22050, ins, 1)")
83def make_fm_violin(start = 0.0, dur = 1.0, freq = 440.0, amp = 1.0, *args)
84  make_fm_violin_gen(start, dur, freq, amp, *args)
85end
86
87def make_fm_violin_gen(start, dur, freq, amp, *args)
88    fm_index, amp_env, periodic_vibrato_rate, random_vibrato_rate = nil
89    periodic_vibrato_amp, random_vibrato_amp, noise_amount, noise_freq = nil
90    ind_noise_freq, ind_noise_amount, amp_noise_freq, amp_noise_amount = nil
91    gliss_env, gliss_amount = nil
92    fm1_env, fm2_env, fm3_env, fm1_rat, fm2_rat, fm3_rat = nil
93    fm1_index, fm2_index, fm3_index, base, index_type = nil
94    optkey(args, binding,
95           [:fm_index, 1.0],
96           [:amp_env, [0, 0, 25, 1, 75, 1, 100, 0]],
97           [:periodic_vibrato_rate, 5.0],
98           [:random_vibrato_rate, 16.0],
99           [:periodic_vibrato_amp, 0.0025],
100           [:random_vibrato_amp, 0.005],
101           [:noise_amount, 0.0],
102           [:noise_freq, 1000.0],
103           [:ind_noise_freq, 10.0],
104           [:ind_noise_amount, 0.0],
105           [:amp_noise_freq, 20.0],
106           [:amp_noise_amount, 0.0],
107           [:gliss_env, [0, 0, 100, 0]],
108           [:gliss_amount, 0.0],
109           [:fm1_env, [0, 1, 25, 0.4, 75, 0.6, 100, 0]],
110           [:fm2_env, [0, 1, 25, 0.4, 75, 0.6, 100, 0]],
111           [:fm3_env, [0, 1, 25, 0.4, 75, 0.6, 100, 0]],
112           [:fm1_rat, 1.0],
113           [:fm2_rat, 3.0],
114           [:fm3_rat, 4.0],
115           [:fm1_index, false],
116           [:fm2_index, false],
117           [:fm3_index, false],
118           [:base, 1.0],
119           [:index_type, :violin])
120  frq_scl = hz2radians(freq)
121  modulate = fm_index.nonzero?
122  maxdev = frq_scl * fm_index
123  vln = (index_type == :violin or index_type == 1)
124  logfreq = log(freq)
125  sqrtfreq = sqrt(freq)
126  index1 = (fm1_index or [PI, maxdev * (vln ? 5.0 : 7.5) / logfreq].min)
127  index2 = (fm2_index or [PI, maxdev * 3.0 *
128           (vln ? ((8.5 - logfreq) / (3.0 + freq * 0.001)) :
129           (15.0 / sqrtfreq))].min)
130  index3 = (fm3_index or [PI, maxdev * (vln ? 4.0 : 8.0) / sqrtfreq].min)
131  easy_case = (noise_amount.zero? and
132               (fm1_env == fm2_env) and
133               (fm1_env == fm3_env) and
134               (fm1_rat - fm1_rat.floor).zero? and
135               (fm2_rat - fm2_rat.floor).zero? and
136               (fm3_rat - fm3_rat.floor).zero?)
137  norm = ((easy_case and modulate and 1.0) or index1)
138  carrier = make_oscil(freq)
139  fmosc1 = fmosc2 = fmosc3 = false
140  indf1 = indf2 = indf3 = false
141  if modulate
142    indf1 = make_env(fm1_env, norm, dur)
143    if easy_case
144      a = [fm1_rat.to_i, index1,
145          (fm2_rat / fm1_rat).floor, index2,
146          (fm3_rat / fm1_rat).floor, index3]
147      coe = partials2polynomial(a)
148      fmosc1 = make_polyshape(:frequency, fm1_rat * freq, :coeffs, coe)
149    else
150      indf2 = make_env(fm2_env, index2, dur)
151      indf3 = make_env(fm3_env, index3, dur)
152      if (fm1_rat * freq * 2.0) > mus_srate
153        fmosc1 = make_oscil(:frequency, freq)
154      else
155        fmosc1 = make_oscil(:frequency, fm1_rat * freq)
156      end
157      if (fm2_rat * freq * 2.0) > mus_srate
158        fmosc2 = make_oscil(:frequency, freq)
159      else
160        fmosc2 = make_oscil(:frequency, fm2_rat * freq)
161      end
162      if (fm3_rat * freq * 2.0) > mus_srate
163        fmosc3 = make_oscil(:frequency, freq)
164      else
165        fmosc3 = make_oscil(:frequency, fm3_rat * freq)
166      end
167    end
168  end
169  ampf = make_env(amp_env, amp, dur, 0.0, base)
170  frqf = make_env(gliss_env, gliss_amount * frq_scl, dur)
171  pervib = make_triangle_wave(periodic_vibrato_rate,
172                              periodic_vibrato_amp * frq_scl)
173  ranvib = make_rand_interp(random_vibrato_rate,
174                            random_vibrato_amp * frq_scl)
175  fm_noi = if noise_amount.nonzero?
176             make_rand(noise_freq, PI * noise_amount)
177           else
178             false
179           end
180  ind_noi = if ind_noise_amount.nonzero? and ind_noise_freq.nonzero?
181              make_rand_interp(ind_noise_freq, ind_noise_amount)
182            else
183              false
184            end
185  amp_noi = if amp_noise_amount.nonzero? and amp_noise_freq.nonzero?
186              make_rand_interp(amp_noise_freq, amp_noise_amount)
187            else
188              false
189            end
190  fuzz = modulation = 0.0
191  ind_fuzz = amp_fuzz = 1.0
192  if modulate
193    if easy_case
194      lambda do |y|
195        vib = env(frqf) + triangle_wave(pervib) + rand_interp(ranvib)
196        ind_fuzz = 1.0 + rand_interp(ind_noi) if ind_noi
197        amp_fuzz = 1.0 + rand_interp(amp_noi) if amp_noi
198        modulation = env(indf1) * polyshape(fmosc1, 1.0, vib)
199        env(ampf) * amp_fuzz * oscil(carrier, vib + ind_fuzz * modulation)
200      end
201    else
202      lambda do |y|
203        fuzz = rand(fm_noi) if fm_noi
204        vib = env(frqf) + triangle_wave(pervib) + rand_interp(ranvib)
205        ind_fuzz = 1.0 + rand_interp(ind_noi) if ind_noi
206        amp_fuzz = 1.0 + rand_interp(amp_noi) if amp_noi
207        modulation = (env(indf1) * oscil(fmosc1, fm1_rat * vib + fuzz) +
208                      env(indf2) * oscil(fmosc2, fm2_rat * vib + fuzz) +
209                      env(indf3) * oscil(fmosc3, fm3_rat * vib + fuzz))
210        env(ampf) * amp_fuzz * oscil(carrier, vib + ind_fuzz * modulation)
211      end
212    end
213  else
214    lambda do |y|
215      vib = env(frqf) + triangle_wave(pervib) + rand_interp(ranvib)
216      ind_fuzz = 1.0 + rand_interp(ind_noi) if ind_noi
217      amp_fuzz = 1.0 + rand_interp(amp_noi) if amp_noi
218      env(ampf) * amp_fuzz * oscil(carrier, vib + ind_fuzz)
219    end
220  end
221end
222
223add_help(:jc_reverb,
224         "jc_reverb(*args)
225 :volume   = 1.0
226 :delay1   = 0.013
227 :delay2   = 0.011
228 :delay3   = 0.015
229 :delay4   = 0.017
230 :low_pass = false
231 :double   = false
232 :amp_env  = false
233Chowning reverb")
234def jc_reverb(*args)
235  low_pass, volume, amp_env, delay1, delay2, delay3, delay4, double = nil
236  optkey(args, binding,
237         [:volume, 1.0],
238         [:delay1, 0.013],
239         [:delay2, 0.011],
240         [:delay3, 0.015],
241         [:delay4, 0.017],
242         [:low_pass, false],
243         [:double, false],
244         [:amp_env, false])
245  chan2 = (@channels > 1)
246  chan4 = (@channels == 4)
247  if double and chan4
248    error("%s: not set up for doubled reverb in quad", get_func_name)
249  end
250  allpass1 = make_all_pass(-0.7, 0.7, 1051)
251  allpass2 = make_all_pass(-0.7, 0.7,  337)
252  allpass3 = make_all_pass(-0.7, 0.7,  113)
253  comb1 = make_comb(0.742, 4799)
254  comb2 = make_comb(0.733, 4999)
255  comb3 = make_comb(0.715, 5399)
256  comb4 = make_comb(0.697, 5801)
257  outdel1 = make_delay((delay1 * @srate).round)
258  outdel2 = (chan2 ? make_delay((delay2 * @srate).round) : false)
259  outdel3 = ((chan4 or double) ? make_delay((delay3 * @srate).round) : false)
260  outdel4 = ((chan4 or (double and chan2)) ?
261              make_delay((delay4 * @srate).round) : false)
262  envA = if amp_env
263           make_env(:envelope, amp_env,
264                    :scaler, volume,
265                    :duration, ws_duration(@revfile) + @decay_time)
266         else
267           false
268         end
269  comb_sum_1 = comb_sum = 0.0
270  out_frample = Vct.new(@channels)
271  run_reverb() do |ho, i|
272    allpass_sum = all_pass(allpass3, all_pass(allpass2,
273                    all_pass(allpass1, ho)))
274    comb_sum_2, comb_sum_1 = comb_sum_1, comb_sum
275    comb_sum = (comb(comb1, allpass_sum) + comb(comb2, allpass_sum) +
276                comb(comb3, allpass_sum) + comb(comb4, allpass_sum))
277    all_sums = if low_pass
278                 0.25 * (comb_sum + comb_sum_2) + 0.5 * comb_sum_1
279               else
280                 comb_sum
281               end
282    delA = delay(outdel1, all_sums)
283    if double
284      delA += delay(outdel3, all_sums)
285    end
286    if envA
287      volume = env(envA)
288    end
289    out_frample[0] = volume * delA
290    if chan2
291      delB = delay(outdel2, all_sums)
292      if double
293        delB += delay(outdel4, all_sums)
294      end
295     out_frample[1] = volume * delB
296      if chan4
297        out_frample[2] = volume * delay(outdel3, all_sums)
298        out_frample[3] = volume * delay(outdel4, all_sums)
299      end
300    end
301    out_frample
302  end
303end
304
305# v.rb ends here
306