Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

grani.rb 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. #!/usr/bin/env ruby -w
  2. # grani.rb -- grani.ins CL --> Ruby
  3. # Translator: Michael Scholz <mi-scholz@users.sourceforge.net>
  4. # Created: 05/02/01 00:47:00
  5. # Changed: 14/11/13 05:03:02
  6. # Original header:
  7. # ;;; grani: a granular synthesis instrument
  8. # ;;; by Fernando Lopez-Lezcano
  9. # ;;; http://ccrma.stanford.edu/~nando/clm/grani/
  10. # ;;;
  11. # ;;; Original grani.ins instrument written for the 220a Course by
  12. # ;;; Fernando Lopez-Lezcano & Juan Pampin, November 6 1996
  13. # ;;;
  14. # ;;; Mar 21 1997: working with hop and grain-dur envelopes
  15. # ;;; Mar 22 1997: working with src envelope (grain wise) & src spread
  16. # ;;; Jan 26 1998: started work on new version
  17. # ;;; Nov 7 1998: input soundfile duration calculation wrong
  18. # ;;; Nov 10 1998: bug in in-samples (thanks to Kristopher D. Giesing
  19. # ;;; for this one)
  20. # ;;; Dec 20 1998: added standard locsig code
  21. # ;;; Feb 19 1999: added "nil" as default value of where to avoid warning
  22. # ;;; (by bill)
  23. # ;;; Jan 10 2000: added input-channel to select which channel of the input
  24. # ;;; file to process.
  25. # ;;; added grain-start-in-seconds to be able to specify input
  26. # ;;; file locations in seconds for the grain-start envelope
  27. # ;;; May 06 2002: fixed array passing of where-bins in clisp
  28. # ;;; (reported by Charles Nichols and jennifer l doering)
  29. # ;;; Mar 27 2003: added option for sending grains to all channels
  30. # ;;; (requested by Oded Ben-Tal)
  31. require "ws"
  32. require "env"
  33. # ;;; calculate a random spread around a center of 0
  34. def random_spread(spread)
  35. spread.nonzero? ? (random(spread) - spread / 2.0) : 0.0
  36. end
  37. # ;;; create a constant envelope if argument is a number
  38. def envelope_or_number(val)
  39. case val
  40. when Numeric
  41. [0, val, 1, val]
  42. when Vct
  43. vct2list(val)
  44. when Array
  45. val
  46. else
  47. error("%s: Number, Array, or Vct required", get_func_name())
  48. end
  49. end
  50. # ;;; create a vct from an envelope
  51. def make_gr_env(env, length = 512)
  52. length_1 = (length - 1).to_f
  53. make_vct!(length) do |i|
  54. envelope_interp(i / length_1, env)
  55. end
  56. end
  57. # ;;; Grain envelopes
  58. def raised_cosine(*args)
  59. duty_cycle = get_args(args, :duty_cycle, 100)
  60. length = get_args(args, :length, 128)
  61. active = length * duty_cycle.to_f * 0.01
  62. incr = PI / (active - 1.0)
  63. start = (length - active) / 2.0
  64. fin = (length + active) / 2.0
  65. s = -1
  66. make_vct!(length) do |i|
  67. sine = if i >= start and i < fin
  68. s += 1
  69. sin(s * incr)
  70. else
  71. 0.0
  72. end
  73. sine * sine
  74. end
  75. end
  76. # ;;;=========================================================================
  77. # ;;; Granular synthesis instrument
  78. # ;;;=========================================================================
  79. #
  80. # ;;; input-channel:
  81. # ;;; from which channel in the input file are samples read
  82. # ;;; amp-envelope:
  83. # ;;; amplitude envelope for the note
  84. # ;;; grain-envelope:
  85. # ;;; grain-envelope-end:
  86. # ;;; envelopes for each individual grain. The envelope applied in the result
  87. # ;;; of interpolating both envelopes. The interpolation is controlled by
  88. # ;;; grain-envelope-trasition. If "grain-envelope-end" is nil interpolation
  89. # ;;; is turned off and only grain-envelope is applied to the grains.
  90. # ;;; grain-envelope-trasition:
  91. # ;;; an enveloper that controls the interpolation between the two
  92. # ;;; grain envelopes
  93. # ;;; 0 -> selects "grain-envelope"
  94. # ;;; 1 -> selects "grain-envelope-end"
  95. # ;;; grain-envelope-array-size
  96. # ;;; size of the array passed to make-table-lookup
  97. # ;;; grain-duration:
  98. # ;;; envelope that controls grain duration in seconds
  99. # ;;; srate-linear:
  100. # ;;; t -> sample rate envelope is linear
  101. # ;;; nil -> sample rate envelope is exponential
  102. # ;;; srate:
  103. # ;;; envelope that controls sample rate conversion. The envelope is an
  104. # ;;; exponential envelope, the base and error bound of the conversion
  105. # ;;; are controlled by "srate-base" and "srate-error".
  106. # ;;; srate-spread:
  107. # ;;; random spread of sample rate conversion around "srate"
  108. # ;;; srate-base:
  109. # ;;; base for the exponential conversion
  110. # ;;; for example: base = (expt 2 (/ 12)) creates a semitone envelope
  111. # ;;; srate-error:
  112. # ;;; error bound for the exponential conversion.
  113. # ;;; grain-start:
  114. # ;;; envelope that determines the starting point of the current grain in
  115. # ;;; the input file. "y"->0 starts the grain at the beginning of the input
  116. # ;;; file. "y"->1 starts the grain at the end of the input file.
  117. # ;;; grain-start-spread:
  118. # ;;; random spread around the value of "grain-start"
  119. # ;;; grain-start-in-seconds:
  120. # ;;; nil -> grain-start y envelope expressed in percent of the duration
  121. # ;;; of the input file
  122. # ;;; t -> grain-start y envelope expressed in seconds
  123. # ;;; grain-density:
  124. # ;;; envelope that controls the number of grains per second generated
  125. # ;;; in the output file
  126. # ;;; grain-density-spread:
  127. Grani_to_locsig = 0
  128. Grani_to_grain_duration = 1
  129. Grani_to_grain_start = 2
  130. Grani_to_grain_sample_rate = 3
  131. Grani_to_grain_random = 4
  132. Grani_to_grain_allchans = 5
  133. def grani(start, dur, amp, file, *args)
  134. input_channel = get_args(args, :input_channel, 0)
  135. grains = get_args(args, :grains, 0)
  136. amp_envelope = get_args(args, :amp_envelope,
  137. [0, 0, 0.3, 1, 0.7, 1, 1, 0])
  138. grain_envelope = get_args(args, :grain_envelope,
  139. [0, 0, 0.3, 1, 0.7, 1, 1, 0])
  140. grain_envelope_end = get_args(args, :grain_envelope_end, false)
  141. grain_envelope_transition = get_args(args, :grain_envelope_transition,
  142. [0, 0, 1, 1])
  143. grain_envelope_array_size = get_args(args, :grain_envelope_array_size, 512)
  144. grain_duration = get_args(args, :grain_duration, 0.1)
  145. grain_duration_spread = get_args(args, :grain_spread, 0.0)
  146. grain_duration_limit = get_args(args, :grain_limit, 0.002)
  147. srate = get_args(args, :srate, 0.0)
  148. srate_spread = get_args(args, :srate_spread, 0.0)
  149. srate_linear = get_args(args, :srate_linear, false)
  150. srate_base = get_args(args, :srate_base, 2.0 ** (1.0 / 12))
  151. srate_error = get_args(args, :srate_error, 0.01)
  152. grain_start = get_args(args, :grain_start, [0, 0, 1, 1])
  153. grain_start_spread = get_args(args, :grain_start_spread, 0.0)
  154. grain_start_in_seconds = get_args(args, :grain_start_in_seconds, false)
  155. grain_density = get_args(args, :grain_density, 10.0)
  156. grain_density_spread = get_args(args, :grain_density_spread, 0.0)
  157. reverb_amount = get_args(args, :reverb_amount, 0.01)
  158. reverse = get_args(args, :reverse, false)
  159. where_to = get_args(args, :where_to, 0)
  160. where_bins = get_args(args, :where_bins, [])
  161. grain_distance = get_args(args, :grain_distance, 1.0)
  162. grain_distance_spread = get_args(args, :grain_distance_spread, 0.0)
  163. grain_degree = get_args(args, :grain_degree, 45.0)
  164. grain_degree_spread = get_args(args, :grain_degree_spread, 0.0)
  165. beg, fin = times2samples(start, dur)
  166. in_file_channels = mus_sound_chans(file)
  167. in_file_sr = mus_sound_srate(file).to_f
  168. in_file_dur = mus_sound_framples(file) / in_file_sr
  169. in_file_reader = make_readin(:file, file,
  170. :channel,
  171. [input_channel, in_file_channels - 1].min)
  172. last_in_sample = (in_file_dur * in_file_sr).round
  173. srate_ratio = in_file_sr / mus_srate()
  174. sr_env = make_env(:envelope,
  175. if srate_linear
  176. envelope_or_number(srate)
  177. else
  178. exp_envelope(envelope_or_number(srate),
  179. :base, srate_base,
  180. :error, srate_error)
  181. end,
  182. :scaler, srate_ratio, :duration, dur)
  183. sr_spread_env = make_env(:envelope, envelope_or_number(srate_spread),
  184. :duration, dur)
  185. amp_env = make_env(:envelope, amp_envelope, :scaler, amp, :duration, dur)
  186. gr_dur = make_env(:envelope, envelope_or_number(grain_duration),
  187. :duration, dur)
  188. gr_dur_spread = make_env(:envelope, envelope_or_number(grain_duration_spread),
  189. :duration, dur)
  190. gr_start_scaler = (grain_start_in_seconds ? 1.0 : in_file_dur)
  191. gr_start = make_env(:envelope, envelope_or_number(grain_start),
  192. :duration, dur)
  193. gr_start_spread = make_env(:envelope, envelope_or_number(grain_start_spread),
  194. :duration, dur)
  195. gr_dens_env = make_env(:envelope, envelope_or_number(grain_density),
  196. :duration, dur)
  197. gr_dens_spread_env = make_env(:envelope,
  198. envelope_or_number(grain_density_spread),
  199. :duration, dur)
  200. gr_env = make_table_lookup(:frequency, 1.0, "initial-phase".intern, 0.0,
  201. :wave,
  202. if vct?(grain_envelope)
  203. grain_envelope
  204. else
  205. make_gr_env(grain_envelope,
  206. grain_envelope_array_size)
  207. end)
  208. gr_env_end = make_table_lookup(:frequency, 1.0, "initial-phase".intern, 0.0,
  209. :wave,
  210. if grain_envelope_end
  211. if vct?(grain_envelope_end)
  212. grain_envelope_end
  213. else
  214. make_gr_env(grain_envelope_end,
  215. grain_envelope_array_size)
  216. end
  217. else
  218. make_vct(512)
  219. end)
  220. gr_int_env = make_env(:envelope,
  221. envelope_or_number(grain_envelope_transition),
  222. :duration, dur)
  223. interp_gr_envs = grain_envelope_end
  224. gr_dist = make_env(:envelope, envelope_or_number(grain_distance),
  225. :duration, dur)
  226. gr_dist_spread = make_env(:envelope,
  227. envelope_or_number(grain_distance_spread),
  228. :duration, dur)
  229. gr_degree = make_env(:envelope, envelope_or_number(grain_degree),
  230. :duration, dur)
  231. gr_degree_spread = make_env(:envelope,
  232. envelope_or_number(grain_degree_spread),
  233. :duration, dur)
  234. loc = make_locsig(:degree, 45.0,
  235. :distance, 1.0,
  236. :output, @ws_output,
  237. :revout, @ws_reverb,
  238. :channels, @channels)
  239. gr_start_sample = beg
  240. gr_samples = 0
  241. gr_offset = 1
  242. gr_dens = 0.0
  243. gr_dens_spread = 0.0
  244. grain_counter = 0
  245. samples = 0
  246. first_grain = true
  247. set_mus_increment(in_file_reader, -1) if reverse
  248. loop do
  249. if gr_offset < gr_samples
  250. gr_where = env(gr_int_env) if interp_gr_envs
  251. val = if interp_gr_envs
  252. (1 - gr_where) * table_lookup(gr_env) +
  253. gr_where * table_lookup(gr_env_end)
  254. else
  255. table_lookup(gr_env)
  256. end
  257. locsig(loc,
  258. gr_start_sample + gr_offset,
  259. val * env(amp_env) * readin(in_file_reader))
  260. gr_offset += 1
  261. else
  262. if first_grain
  263. first_grain = false
  264. gr_start_sample = beg
  265. else
  266. gr_start_sample += seconds2samples(1.0 / (gr_dens + gr_dens_spread))
  267. if (gr_start_sample > fin) or
  268. (grains.nonzero? and (grain_counter >= grains))
  269. break
  270. end
  271. end
  272. gr_offset = 0
  273. gr_from_beg = gr_start_sample - beg
  274. set_mus_location(amp_env, gr_from_beg)
  275. set_mus_location(gr_dur, gr_from_beg)
  276. set_mus_location(gr_dur_spread, gr_from_beg)
  277. set_mus_location(sr_env, gr_from_beg)
  278. set_mus_location(sr_spread_env, gr_from_beg)
  279. set_mus_location(gr_start, gr_from_beg)
  280. set_mus_location(gr_start_spread, gr_from_beg)
  281. set_mus_location(gr_dens_env, gr_from_beg)
  282. set_mus_location(gr_dens_spread_env, gr_from_beg)
  283. in_start_value = env(gr_start) * gr_start_scaler +
  284. random_spread(env(gr_start_spread) * gr_start_scaler)
  285. in_start = (in_start_value * in_file_sr).round
  286. gr_duration = [grain_duration_limit,
  287. env(gr_dur) + random_spread(env(gr_dur_spread))].max
  288. gr_samples = seconds2samples(gr_duration)
  289. gr_srate = if srate_linear
  290. env(sr_env) + random_spread(env(sr_spread_env))
  291. else
  292. env(sr_env) * srate_base ** random_spread(env(sr_spread_env))
  293. end
  294. set_mus_increment(in_file_reader, gr_srate)
  295. in_samples = gr_samples / (1.0 / srate_ratio)
  296. set_mus_phase(gr_env, 0.0)
  297. set_mus_phase(gr_env_end, 0.0)
  298. set_mus_frequency(gr_env, 1.0 / gr_duration)
  299. set_mus_frequency(gr_env_end, 1.0 / gr_duration)
  300. gr_dens = env(gr_dens_env)
  301. gr_dens_spread = random_spread(env(gr_dens_spread_env))
  302. samples += gr_samples
  303. grain_counter += 1
  304. where = case where_to
  305. when Grani_to_grain_duration
  306. gr_duration
  307. when Grani_to_grain_start
  308. in_start_value
  309. when Grani_to_grain_sample_rate
  310. gr_srate
  311. when Grani_to_grain_random
  312. random(1.0)
  313. else
  314. Grani_to_locsig
  315. end
  316. if where.nonzero? and where_bins.length > 1
  317. (where_bins.length - 1).times do |chn|
  318. locsig_set!(loc, chn,
  319. ((where_bins[chn] < where and
  320. where < where_bins[chn + 1]) ? 1.0 : 0.0))
  321. end
  322. else
  323. if where_to == Grani_to_grain_allchans
  324. @channels.times do |chn|
  325. locsig_set!(loc, chn, 1.0)
  326. end
  327. else
  328. set_mus_location(gr_dist, gr_from_beg)
  329. set_mus_location(gr_dist_spread, gr_from_beg)
  330. set_mus_location(gr_degree, gr_from_beg)
  331. set_mus_location(gr_degree_spread, gr_from_beg)
  332. deg = env(gr_degree) + random_spread(env(gr_degree_spread))
  333. dist = env(gr_dist) + random_spread(env(gr_dist_spread))
  334. dist_scl = 1.0 / [dist, 1.0].max
  335. if @ws_reverb
  336. locsig_reverb_set!(loc, 0,
  337. reverb_amount * (1.0 / sqrt([dist, 1.0].max)))
  338. end
  339. if @channels == 1
  340. locsig_set!(loc, 0, dist_scl)
  341. else
  342. if @channels == 2
  343. frac = [90.0, [0.0, deg].max].min / 90.0
  344. locsig_set!(loc, 0, dist_scl * (1.0 - frac))
  345. locsig_set!(loc, 1, dist_scl * frac)
  346. else
  347. if @channels > 2
  348. locsig_set!(loc, 0,
  349. if 0 <= deg and deg <= 90
  350. dist_scl * ((90.0 - deg) / 90.0)
  351. else
  352. if 270 <= deg and deg <= 360
  353. dist_scl * ((deg - 270.0) / 90.0)
  354. else
  355. 0.0
  356. end
  357. end)
  358. locsig_set!(loc, 1,
  359. if 90 <= deg and deg <= 180
  360. dist_scl * (180.0 - deg) / 90.0
  361. else
  362. if 0 <= deg and deg <= 90
  363. dist_scl * (deg / 90.0)
  364. else
  365. 0.0
  366. end
  367. end)
  368. locsig_set!(loc, 2,
  369. if 180 <= deg and deg <= 270
  370. dist_scl * (270.0 - deg) / 90.0
  371. else
  372. if 90 <= deg and deg <= 180
  373. dist_scl * (deg - 90.0) / 90.0
  374. else
  375. 0.0
  376. end
  377. end)
  378. if @channels > 3
  379. locsig_set!(loc, 3,
  380. if 270 <= deg and deg <= 360
  381. dist_scl * (360.0 - deg) / 90.0
  382. else
  383. if 180 <= deg and deg <= 270
  384. dist_scl * (deg - 180.0) / 90.0
  385. else
  386. 0.0
  387. end
  388. end)
  389. end
  390. end
  391. end
  392. end
  393. end
  394. end
  395. in_start = if (in_start + in_samples) > last_in_sample
  396. last_in_sample - in_samples
  397. else
  398. [in_start, 0].max
  399. end
  400. set_mus_location(in_file_reader, in_start)
  401. end
  402. end
  403. mus_close(in_file_reader)
  404. end
  405. =begin
  406. with_sound(:play, 1, :statistics, true, :channels, 1, :reverb, nil) do
  407. grani(0.0, 2.0, 5.0, "oboe.snd", :grain_envelope, raised_cosine())
  408. end
  409. =end
  410. # grani.rb ends here