# maxf.rb -- CLM -> Snd/Ruby translation of maxf.ins
# Translator/Author: Michael Scholz <scholz-micha@gmx.de>
# Last: Wed Mar 16 01:37:29 CET 2005
# It follows the original header of Juan Reyes.
# ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
# ;;
# ;; maxf.ins
# ;; This is Max Mathews (mvm) new filter (2002)
# ;; High-Q, 2-Integrator, filter with
# ;; Two Poles, and one Zero at the Origin
# ;;
# ;; It synthesizes equal-tempered frequencies
# ;; integer & just scales out of a wide-band input
# ;; signal.
# ;; Based on Max's code (filter.cpp)
# ;;
# ;; This heuristic might be called Modal Synthesis.
# ;; But as well it can also be additive synthesis in
# ;; which a resonator is initialized to generate the
# ;; exponentially decaying sinusoids at the desired
# ;; phase.
# ;;
# ;; This implementation written by Juan Reyes with dsp
# ;; assistance from JOS.
# ;; This version Oct-30, 2002
# ;;
# ;; Change gain(att) of input file if clipping
# ;;
# ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
require "examp"
require "ws"
CLM = Struct.new("CLM", :yy1, :yy2, :zz1, :zz2, :pp1, :pp2, :pp3, :out)
add_help(:maxfilter, "maxfilter(file, start, *args)
:att = 1.0
:numf = 1
:freqfactor = 1.0
:amplitude = 1.0
:amp-env = [0, 1, 100, 1]
:degree = kernel_rand(90.0)
:distance = 1.0
:reverb_amount = 0.2
This is Max Mathews (mvm) new filter (2002) High-Q, 2-Integrator,
filter with Two Poles, and one Zero at the Origin
It synthesizes equal-tempered frequencies integer & just scales
out of a wide-band input signal.
Based on Max's code (filter.cpp)
This heuristic might be called Modal Synthesis. But as well it
can also be additive synthesis in which a resonator is
initialized to generate the exponentially decaying sinusoids at
the desired phase.
:att = 1 in-file attenuation
:numf = 1 1 filter
:numf = 4 4 filters
:numf = 9 9 filters
:numf = 12 12 filters
:numf = 13 13 filters")
def maxfilter(file, start = 0, *args)
att = get_args(args, :att, 1.0)
numf = get_args(args, :numf, 1).to_i
freqfactor = get_args(args, :freqfactor, 1.0)
amplitude = get_args(args, :amplitude, 1.0)
amp_env = get_args(args, :amp_env, [0, 1, 100, 1])
degree = get_args(args, :degree, kernel_rand(90.0))
distance = get_args(args, :distance, 1.0)
rev_amount = get_args(args, :reverb_amount, 0.2)
rda, snd = make_general_reader(file, :channel, 0)
formfil = CLM.new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
dur = duration(file)
ampf = make_env(:envelope, amp_env, :scaler, amplitude, :duration, dur)
state_0 = make_array( 1) do make_array(3, 0.0) end
state_1 = make_array(12) do make_array(3, 0.0) end
state_2 = make_array( 9) do make_array(3, 0.0) end
state_3 = make_array(13) do make_array(3, 0.0) end
state_4 = make_array( 4) do make_array(3, 0.0) end
state_5 = make_array( 2) do make_array(3, 0.0) end
case numf
when 1
message "State 0 (default): One filter"
state_0[0] = 7.54e-002, 2000.0 * freqfactor, 2.0
when 2
message "State 5: Two filters"
state_5[0] = 7.54e-003, 200.0 * freqfactor, 4.0
state_5[1] = 7.54e-004, 800.0 * freqfactor, 1.0
when 4
message "State 4: Four filters"
state_4[0] = 7.54e-002, 1000.0 * freqfactor, 0.5
state_4[1] = 3.225e-002, 400.0 * freqfactor, 3.0
state_4[2] = 1.14e-002, 800.0 * freqfactor, 2.8
state_4[3] = 7.54e-002, 1600.0 * freqfactor, 1.0
when 9
message "State 2: Streached overtone string 9 filters"
state_2[0] = 1.07e-002, 100.0, 2.5
state_2[1] = 1.07e-002, 202.0, 0.75
state_2[2] = 1.07e-002, 305.0, 0.5
state_2[3] = 7.077e-003, 408.0, 0.4
state_2[4] = 1.07e-002, 501.0, 0.3
state_2[5] = 1.07e-002, 612.0, 0.25
state_2[6] = 1.07e-003, 715.0, 0.25
state_2[7] = 1.07e-002, 817.0, 0.2
state_2[8] = 1.07e-002, 920.0, 0.18
when 12
message "State 1: Risset bell long 12 filters"
state_1[0] = 5.025e-002, 224.0, 3.7
state_1[1] = 5.025e-002, 225.0, 3.3
state_1[2] = 5.025e-002, 368.0, 2.8
state_1[3] = 5.025e-002, 369.0, 2.4
state_1[4] = 1.047e-002, 476.0, 1.9
state_1[5] = 5.025e-002, 680.0, 1.7
state_1[6] = 5.025e-002, 800.0, 1.5
state_1[7] = 4.05e-002, 1096.0, 1.1
state_1[8] = 4.05e-002, 1099.0, 0.9
state_1[9] = 4.05e-002, 1200.0, 0.6
state_1[10] = 3.78e-002, 1504.0, 0.4
state_1[11] = 4.05e-002, 1628.0, 0.3
when 13
message "State 3: Open major chord with repeated octave 12 filters"
state_3[0] = 5.025e-002, 100.0, 2.0
state_3[1] = 5.025e-002, 251.0, 2.0
state_3[2] = 5.025e-002, 299.0, 2.0
state_3[3] = 5.025e-002, 401.0, 2.0
state_3[4] = 5.025e-002, 199.0, 2.0
state_3[5] = 5.025e-002, 501.0, 2.0
state_3[6] = 5.025e-002, 599.0, 2.0
state_3[7] = 5.025e-002, 801.0, 2.0
state_3[8] = 5.025e-002, 201.0, 2.0
state_3[9] = 5.025e-002, 749.0, 2.0
state_3[10] = 5.025e-002, 900.0, 2.0
state_3[11] = 5.025e-004, 1205.0, 2.0
state_3[12] = 5.025e-004, 1205.0, 2.0
else
message "Please leave default or enter [1] [2] [4] [9] [12] [13]"
numf = 1
end
mvmfilt = lambda do |b, sample|
b[:yy2] = (b[:pp1] * b[:yy1] + b[:pp2] * b[:zz1]) - b[:pp3] * sample
b[:zz2] = b[:zz1] - b[:pp2] * b[:yy2]
b[:zz1] = b[:zz2]
b[:yy1] = b[:yy2]
b[:out] = b[:yy1]
end
set_coeffs = lambda do |b, ary|
famp, ffreq, fdecay = ary
tper = 1.0 / @srate
centerfreq = (2.0 * PI * ffreq) / @srate
maxdecay = (2.0 * tper) / (centerfreq * centerfreq)
mindecay = tper / centerfreq
fdecay = if fdecay >= maxdecay
maxdecay
else
fdecay.to_f
end
fdecay = mindecay if fdecay <= mindecay
b[:pp1] = 1.0 - 2.0 / (fdecay * @srate)
b[:pp2] = (2.0 * PI * ffreq) / @srate
b[:pp3] = b[:pp2] * famp
end
run_instrument(start, dur, :degree, degree, :distance, distance, :reverb_amount, rev_amount) do
outval_a = att * general_readin(rda)
add_fl = 0.0
numf.times do |j|
case numf
when 1
set_coeffs.call(formfil, state_0[j])
when 2
set_coeffs.call(formfil, state_5[j])
when 4
set_coeffs.call(formfil, state_4[j])
when 9
set_coeffs.call(formfil, state_2[j])
when 12
set_coeffs.call(formfil, state_1[j])
when 13
set_coeffs.call(formfil, state_3[j])
end
filsig = mvmfilt.call(formfil, outval_a)
add_fl += filsig
end
env(ampf) * add_fl
end
close_general_reader(snd, rda)
end
=begin
ifile = "dog.snd"
ofile = "rmax_dog.snd"
stats = [1, 2, 4, 9, 12, 13]
with_sound(:play, 1, :statistics, true, :channels, 4, :output, ofile, :reverb, :jc_reverb,
:comment, format("maxfilter test, filters %s, source %s", stats.inspect, ifile)) do
stats.each_with_index do |val, i| maxfilter(ifile, i, :numf, val) end
end
with_sound(:srate, 22050) do maxfilter("dog.snd", 0) end
with_sound(:srate, 44100) do maxfilter("dog.snd", 0, :numf, 12) end
with_sound(:srate, 44100) do maxfilter("dog.snd", 0, :numf, 13, :att, 0.75) end
with_sound(:srate, 44100) do maxfilter("dog.snd", 0, :numf, 2, :att, 0.25, :freqfactor, 0.5) end
=end
# maxf.rb ends here