You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
7.2KB

  1. # maxf.rb -- CLM -> Snd/Ruby translation of maxf.ins
  2. # Translator/Author: Michael Scholz <mi-scholz@users.sourceforge.net>
  3. # Created: Mon Mar 24 11:24:23 CET 2003
  4. # Changed: Thu Oct 15 00:16:58 CEST 2009
  5. # It follows the original header of Juan Reyes.
  6. # ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7. # ;;
  8. # ;; maxf.ins
  9. # ;; This is Max Mathews (mvm) new filter (2002)
  10. # ;; High-Q, 2-Integrator, filter with
  11. # ;; Two Poles, and one Zero at the Origin
  12. # ;;
  13. # ;; It synthesizes equal-tempered frequencies
  14. # ;; integer & just scales out of a wide-band input
  15. # ;; signal.
  16. # ;; Based on Max's code (filter.cpp)
  17. # ;;
  18. # ;; This heuristic might be called Modal Synthesis.
  19. # ;; But as well it can also be additive synthesis in
  20. # ;; which a resonator is initialized to generate the
  21. # ;; exponentially decaying sinusoids at the desired
  22. # ;; phase.
  23. # ;;
  24. # ;; This implementation written by Juan Reyes with dsp
  25. # ;; assistance from JOS.
  26. # ;; This version Oct-30, 2002
  27. # ;;
  28. # ;; Change gain(att) of input file if clipping
  29. # ;;
  30. # ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  31. require "ws"
  32. CLM = Struct.new("CLM", :yy1, :yy2, :zz1, :zz2, :pp1, :pp2, :pp3, :out)
  33. add_help(:maxfilter, "maxfilter(file, start, *args)
  34. :att = 1.0
  35. :numf = 1
  36. :freqfactor = 1.0
  37. :amplitude = 1.0
  38. :amp-env = [0, 1, 100, 1]
  39. :degree = kernel_rand(90.0)
  40. :distance = 1.0
  41. :reverb_amount = 0.2
  42. This is Max Mathews (mvm) new filter (2002) High-Q, 2-Integrator,
  43. filter with Two Poles, and one Zero at the Origin
  44. It synthesizes equal-tempered frequencies integer & just scales
  45. out of a wide-band input signal.
  46. Based on Max's code (filter.cpp)
  47. This heuristic might be called Modal Synthesis. But as well it
  48. can also be additive synthesis in which a resonator is
  49. initialized to generate the exponentially decaying sinusoids at
  50. the desired phase.
  51. :att = 1 in-file attenuation
  52. :numf = 1 1 filter
  53. :numf = 4 4 filters
  54. :numf = 9 9 filters
  55. :numf = 12 12 filters
  56. :numf = 13 13 filters")
  57. def maxfilter(file, start = 0, *args)
  58. att, numf, freqfactor, amplitude, amp_env, degree, distance, reverb_amount = nil
  59. optkey(args, binding,
  60. [:att, 1.0],
  61. [:numf, 1],
  62. [:freqfactor, 1.0],
  63. [:amplitude, 1.0],
  64. [:amp_env, [0, 1, 100, 1]],
  65. [:degree, kernel_rand(90.0)],
  66. [:distance, 1.0],
  67. [:reverb_amount, 0.2])
  68. rda, snd = make_general_reader(file, :channel, 0)
  69. formfil = CLM.new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
  70. dur = duration(file)
  71. ampf = make_env(:envelope, amp_env, :scaler, amplitude, :duration, dur)
  72. state_0 = make_array( 1) do make_array(3, 0.0) end
  73. state_1 = make_array(12) do make_array(3, 0.0) end
  74. state_2 = make_array( 9) do make_array(3, 0.0) end
  75. state_3 = make_array(13) do make_array(3, 0.0) end
  76. state_4 = make_array( 4) do make_array(3, 0.0) end
  77. state_5 = make_array( 2) do make_array(3, 0.0) end
  78. case numf
  79. when 1
  80. Snd.display "State 0 (default): One filter"
  81. state_0[0] = 7.54e-002, 2000.0 * freqfactor, 2.0
  82. when 2
  83. Snd.display "State 5: Two filters"
  84. state_5[0] = 7.54e-003, 200.0 * freqfactor, 4.0
  85. state_5[1] = 7.54e-004, 800.0 * freqfactor, 1.0
  86. when 4
  87. Snd.display "State 4: Four filters"
  88. state_4[0] = 7.54e-002, 1000.0 * freqfactor, 0.5
  89. state_4[1] = 3.225e-002, 400.0 * freqfactor, 3.0
  90. state_4[2] = 1.14e-002, 800.0 * freqfactor, 2.8
  91. state_4[3] = 7.54e-002, 1600.0 * freqfactor, 1.0
  92. when 9
  93. Snd.display "State 2: Streached overtone string 9 filters"
  94. state_2[0] = 1.07e-002, 100.0, 2.5
  95. state_2[1] = 1.07e-002, 202.0, 0.75
  96. state_2[2] = 1.07e-002, 305.0, 0.5
  97. state_2[3] = 7.077e-003, 408.0, 0.4
  98. state_2[4] = 1.07e-002, 501.0, 0.3
  99. state_2[5] = 1.07e-002, 612.0, 0.25
  100. state_2[6] = 1.07e-003, 715.0, 0.25
  101. state_2[7] = 1.07e-002, 817.0, 0.2
  102. state_2[8] = 1.07e-002, 920.0, 0.18
  103. when 12
  104. Snd.display "State 1: Risset bell long 12 filters"
  105. state_1[0] = 5.025e-002, 224.0, 3.7
  106. state_1[1] = 5.025e-002, 225.0, 3.3
  107. state_1[2] = 5.025e-002, 368.0, 2.8
  108. state_1[3] = 5.025e-002, 369.0, 2.4
  109. state_1[4] = 1.047e-002, 476.0, 1.9
  110. state_1[5] = 5.025e-002, 680.0, 1.7
  111. state_1[6] = 5.025e-002, 800.0, 1.5
  112. state_1[7] = 4.05e-002, 1096.0, 1.1
  113. state_1[8] = 4.05e-002, 1099.0, 0.9
  114. state_1[9] = 4.05e-002, 1200.0, 0.6
  115. state_1[10] = 3.78e-002, 1504.0, 0.4
  116. state_1[11] = 4.05e-002, 1628.0, 0.3
  117. when 13
  118. Snd.display "State 3: Open major chord with repeated octave 12 filters"
  119. state_3[0] = 5.025e-002, 100.0, 2.0
  120. state_3[1] = 5.025e-002, 251.0, 2.0
  121. state_3[2] = 5.025e-002, 299.0, 2.0
  122. state_3[3] = 5.025e-002, 401.0, 2.0
  123. state_3[4] = 5.025e-002, 199.0, 2.0
  124. state_3[5] = 5.025e-002, 501.0, 2.0
  125. state_3[6] = 5.025e-002, 599.0, 2.0
  126. state_3[7] = 5.025e-002, 801.0, 2.0
  127. state_3[8] = 5.025e-002, 201.0, 2.0
  128. state_3[9] = 5.025e-002, 749.0, 2.0
  129. state_3[10] = 5.025e-002, 900.0, 2.0
  130. state_3[11] = 5.025e-004, 1205.0, 2.0
  131. state_3[12] = 5.025e-004, 1205.0, 2.0
  132. else
  133. Snd.display "Please leave default or enter [1] [2] [4] [9] [12] [13]"
  134. numf = 1
  135. end
  136. mvmfilt = lambda do |b, sample|
  137. b[:yy2] = (b[:pp1] * b[:yy1] + b[:pp2] * b[:zz1]) - b[:pp3] * sample
  138. b[:zz2] = b[:zz1] - b[:pp2] * b[:yy2]
  139. b[:zz1] = b[:zz2]
  140. b[:yy1] = b[:yy2]
  141. b[:out] = b[:yy1]
  142. end
  143. set_coeffs = lambda do |b, ary|
  144. famp, ffreq, fdecay = ary
  145. tper = 1.0 / @srate
  146. centerfreq = (2.0 * PI * ffreq) / @srate
  147. maxdecay = (2.0 * tper) / (centerfreq * centerfreq)
  148. mindecay = tper / centerfreq
  149. fdecay = if fdecay >= maxdecay
  150. maxdecay
  151. else
  152. fdecay.to_f
  153. end
  154. fdecay = mindecay if fdecay <= mindecay
  155. b[:pp1] = 1.0 - 2.0 / (fdecay * @srate)
  156. b[:pp2] = (2.0 * PI * ffreq) / @srate
  157. b[:pp3] = b[:pp2] * famp
  158. end
  159. run_instrument(start, dur, :degree, degree, :distance, distance, :reverb_amount, reverb_amount) do
  160. outval_a = att * general_readin(rda)
  161. add_fl = 0.0
  162. numf.times do |j|
  163. case numf
  164. when 1
  165. set_coeffs.call(formfil, state_0[j])
  166. when 2
  167. set_coeffs.call(formfil, state_5[j])
  168. when 4
  169. set_coeffs.call(formfil, state_4[j])
  170. when 9
  171. set_coeffs.call(formfil, state_2[j])
  172. when 12
  173. set_coeffs.call(formfil, state_1[j])
  174. when 13
  175. set_coeffs.call(formfil, state_3[j])
  176. end
  177. filsig = mvmfilt.call(formfil, outval_a)
  178. add_fl += filsig
  179. end
  180. env(ampf) * add_fl
  181. end
  182. close_general_reader(snd, rda)
  183. end
  184. =begin
  185. ifile = "dog.snd"
  186. ofile = "rmax_dog.snd"
  187. stats = [1, 2, 4, 9, 12, 13]
  188. with_sound(:play, 1, :statistics, true, :channels, 4, :output, ofile, :reverb, :jc_reverb,
  189. :comment, format("maxfilter test, filters %s, source %s", stats.inspect, ifile)) do
  190. stats.each_with_index do |val, i| maxfilter(ifile, i, :numf, val) end
  191. end
  192. with_sound(:srate, 22050) do maxfilter("dog.snd", 0) end
  193. with_sound(:srate, 44100) do maxfilter("dog.snd", 0, :numf, 12) end
  194. with_sound(:srate, 44100) do maxfilter("dog.snd", 0, :numf, 13, :att, 0.75) end
  195. with_sound(:srate, 44100) do maxfilter("dog.snd", 0, :numf, 2, :att, 0.25, :freqfactor, 0.5) end
  196. =end
  197. # maxf.rb ends here