1# clm.rb -- Ruby extension
2
3# Author: Michael Scholz <mi-scholz@users.sourceforge.net>
4# Created: 09/10/14 23:02:57
5# Changed: 20/11/02 16:46:15
6
7# Ruby extensions:
8#
9# array?(obj)   alias list?(obj)
10# hash?(obj)
11# string?(obj)
12# regexp?(obj)
13# symbol?(obj)
14# number?(obj)
15# integer?(obj)
16# float?(obj)
17# rational?(obj)
18# complex?(obj)
19# boolean?(obj)
20# proc?(obj)
21# thunk?(obj)
22# method?(obj)
23# func?(obj)
24# mus?(obj)
25# get_func_name(n)
26# assert_type(condition, obj, pos, msg)
27# identity(arg)
28# ignore(*rest)
29# with_silence(exception) do |old_verbose, old_debug| ... end
30#
31# provided?(feature)
32# provide(feature)
33# features(all)
34#
35# Backward compatibility aliases and constants (from sndXX.scm)
36#
37# enum(*names)
38#
39# class Object
40#  null?
41#  function?(obj)
42#  snd_func(name, *rest, &body)
43#  set_snd_func(name, val, *rest, &body)
44#  snd_apropos(str_or_sym)
45#
46# NilClass(arg)
47# Integer(arg)
48#
49# class NilClass
50#  each
51#  apply(func, *rest, &body)
52#  empty?
53#  zero?
54#  nonzero?
55#  to_vct
56#  to_vector
57#  to_poly
58#  +(other)
59#  -(other)
60#  *(other)
61#
62# backward compatibility methods:
63#  String#to_sym, Symbol#to_sym
64#  make_array(len, init, &body)
65#  Array#insert
66#  Float#step
67#  Numeric#to_c
68#  Range#step
69#  Enumerable#each_index
70#  Enumerable#zip
71#
72# class Array
73#  to_pairs
74#  each_pair do |x, y| ... end
75#  to_string(len)
76#  first=(val)
77#  last=(val)
78#  pick
79#  rand
80#  rand!
81#  add(other)
82#  add!(other)
83#  subtract(other)
84#  subtract!(other)
85#  multiply(other)
86#  multiply!(other)
87#  offset(scl)
88#  offset!(scl)
89#  scale(scl)
90#  scale!(scl)
91#  to_vector
92#  car
93#  car=
94#  cadr
95#  cadr=
96#  caddr
97#  caddr=
98#  cadddr
99#  cadddr=
100#  caddddr
101#  caddddr=
102#  cdr
103#  step(n)
104#  apply(func, *rest, &body)
105#
106# class Vec < Array
107#  Vec[]
108#  initialize(len, init, &body)
109#  inspect
110#  to_s
111#  to_vector
112#  +(other)
113#  -(other)
114#  *(other)
115#
116# Vec(obj)
117# make_vector(len, init, &body)
118# vector?(obj)
119# vector(*args)
120#
121# class String
122#  to_vector
123#  to_vct
124#
125# Vct(obj)
126# make_vct!(len, init) do |i| ... end
127#
128# class Vct
129#  Vct[]
130#  name
131#  to_vct
132#  to_vector
133#  apply(func, *rest, &body)
134#  +(other)   handles self.offset (Numeric) and self.add (Array, Vec, Vct)
135#  -(other)   handles self.offset (Numeric) and self.subtract (Array, Vec, Vct)
136#  *(other)   handles self.scale (Numeric) and self.multiply (Array, Vec, Vct)
137#  step(n)
138#  [](idx, size)
139#
140# class Integer
141#  +(other)   handles other.offset on Vct, Array, and Vec
142#  *(other)   handles other.scale on Vct, Array, and Vec
143#
144# class Float
145#  +(other)   handles other.offset on Vct, Array, and Vec
146#  *(other)   handles other.scale on Vct, Array, and Vec
147#
148# mus_a0(gen)
149# set_mus_a0(gen, val)
150# mus_a1(gen)
151# set_mus_a1(gen, val)
152# mus_a2(gen)
153# set_mus_a2(gen, val)
154# mus_b1(gen)
155# set_mus_b1(gen, val)
156# mus_b2(gen)
157# set_mus_b2(gen, val)
158#
159# class Mus
160#  run(arg1, arg2)
161#  apply(*rest)
162#  inspect
163#  close
164#  xcoeff=(index, val)
165#  ycoeff=(index, val)
166#  a0  a0=(val)
167#  a1  a1=(val)
168#  a2  a2=(val)
169#  b1  b1=(val)
170#  b2  b2=(val)
171#
172# class Musgen   base class for generators written in Ruby
173#  initialize
174#  inspect
175#  to_s
176#  run(val1, val2)
177#  apply(*rest)
178#  eql?(other)
179#  reset
180#
181# class Numeric
182#  positive?
183#  negative?
184#
185# class Integer
186#  even?
187#  odd?
188#  prime?
189#
190# module Enumerable
191#  map_with_index do |x, i| ... end
192#  map_with_index! do |x, i| ... end
193#  clm_cycle
194#  clm_cycle=(val)
195#
196# as_one_edit_rb(*origin, &body)
197# map_channel_rb(beg, dur, snd, chn, edpos, edname, &body)
198# map_chan_rb(beg, dur, edpos, snd, chn, &body)
199#
200# module Info
201#  description=(text)
202#  description
203#
204# class Proc
205#  to_method(name, klass)
206#  to_str
207#  to_body
208#  source
209#  source=
210#
211# make_proc2method(name, prc)
212# make_proc_with_setter(name, getter, setter)
213# make_proc_with_source(string, bind)
214# proc_source(prc)   set_proc_source(prc, val)
215#
216# Multi-line input to the Snd listener and Emacs/inf-snd.el
217#
218# $emacs_eval_hook.call(line)
219# run_emacs_eval_hook(line)
220#
221# class Snd_eval
222#  Snd_eval.count_level(line)
223#
224# class Snd_prompt
225#  initialize(level)
226#  inspect
227#  update(level)
228#  reset
229#
230# start_emacs_eval(file)
231# start_listener_eval(file)
232# stop_emacs_eval
233# stop_listener_eval
234#
235# Debugging resp. inspecting local variables
236#
237# debug_properties(name)      set_debug_properties(name, val)
238# debug_property(key, name)   set_debug_property(key, val, name)
239# debug_binding(name)         set_debug_binding(bind, name)
240# display_all_variables(name)
241# each_variables(bind, &body)
242#
243# let(*rest) do |*rest| ... end
244#
245# Utilities:
246#
247# close_sound_extend(snd)
248# times2samples(start, dur)
249# random(n)
250# logn(r, b)
251# car(v), cadr(v), caddr(v), cdr(v)
252# warning(*args), die(*args), error(*args)
253# clm_message(*args), message(*args), debug(*args), debug_trace(*args)
254#
255# class Snd
256#  Snd.add_sound_path(path)
257#  Snd.open_from_path(fname)
258#  Snd.find_from_path(fname)
259#  Snd.fullname(fname)
260#  Snd.load_path
261#  Snd.message(*args)
262#  Snd.display(*args)
263#  Snd.warning(*args)
264#  Snd.die(*args)
265#  Snd.error(*args)
266#  Snd.debug(*args)
267#  Snd.debug_trace(*args)
268#  Snd.sounds
269#  Snd.regions
270#  Snd.marks(snd, chn)
271#  Snd.snd(snd)
272#  Snd.chn(chn)
273#  Snd.catch(tag, retval)
274#  Snd.throw(tag, *rest)
275#  Snd.raise(tag, *rest)
276#
277# snd_catch(tag, retval)
278# snd_throw(tag, *rest)
279# snd_raise(tag, *rest)
280#
281# gloop(*args) do |args| ... end
282# get_args(args, key, default)
283# get_shift_args(args, key, default)
284# get_class_or_key(args, klass, key, default)
285# optkey(args, *rest)
286# load_init_file(file)
287#
288# edit_list_proc_counter
289# set_edit_list_proc_counter
290
291def make_polar(r, theta)
292  Complex(cos(theta) * r, sin(theta) * r)
293end
294
295def make_rectangular(re, im = 1.0)
296  Complex(re, im)
297end
298
299def array?(obj)
300  obj.kind_of?(Array)
301end
302alias list? array?
303
304def hash?(obj)
305  obj.kind_of?(Hash)
306end
307
308def string?(obj)
309  obj.kind_of?(String)
310end
311
312def regexp?(obj)
313  obj.kind_of?(Regexp)
314end
315
316def symbol?(obj)
317  obj.kind_of?(Symbol)
318end
319
320def number?(obj)
321  obj.kind_of?(Numeric)
322end
323
324def integer?(obj)
325  obj.kind_of?(Integer)
326end
327
328def float?(obj)
329  obj.kind_of?(Float)
330end
331
332def rational?(obj)
333  obj.kind_of?(Rational)
334end
335
336def complex?(obj)
337  obj.kind_of?(Complex)
338end
339
340def boolean?(obj)
341  obj.kind_of?(TrueClass) or obj.kind_of?(FalseClass)
342end
343
344def proc?(obj)
345  obj.kind_of?(Proc)
346end
347
348def thunk?(obj)
349  obj.kind_of?(Proc) and obj.arity.zero?
350end
351
352def method?(obj)
353  obj.kind_of?(Method)
354end
355
356def func?(obj)
357  obj.kind_of?(String) or obj.kind_of?(Symbol)
358end
359
360def mus?(obj)
361  obj.kind_of?(Mus)
362end
363
364def binding?(obj)
365  obj.kind_of?(Binding)
366end
367
368def get_func_name(n = 1)
369  if ca = caller(n)[0].scan(/^.*:in `(.*)'/).first
370    ca.first
371  else
372    "top_level"
373  end
374end
375
376def assert_type(condition, obj, pos, msg)
377  condition or Kernel.raise(TypeError,
378                            format("%s: wrong type arg %d, %p, wanted %s",
379                                   get_func_name(2), pos, obj, msg))
380end
381
382def identity(arg)
383  arg
384end
385
386def ignore(*rest)
387  nil
388end
389
390unless defined? $LOADED_FEATURES
391  alias $LOADED_FEATURES $"
392end
393
394def provided?(feature)
395  $LOADED_FEATURES.map do |f|
396    File.basename(f)
397  end.member?(feature.to_s.tr("_", "-"))
398end
399
400def provide(feature)
401  $LOADED_FEATURES.push(feature.to_s)
402end
403
404def features(all = nil)
405  if all
406    $LOADED_FEATURES.map do |f| File.basename(f) end
407  else
408    $LOADED_FEATURES.map do |f|
409      next if f.include?("/") or f.include?(".")
410      f
411    end.compact
412  end
413end
414
415# with_silence(exception) do |old_verbose, old_debug| ... end
416#
417# subpress debug messages (mostly on older Ruby versions)
418#
419# with_silence do $global_var ||= value end
420# with_silence(LoadError) do require("nonexistent.file") end
421def with_silence(exception = StandardError, &body)
422  old_verbose = $VERBOSE
423  old_debug   = $DEBUG
424  $VERBOSE = false
425  $DEBUG   = false
426  ret = if block_given?
427          begin
428            body.call(old_verbose, old_debug)
429          rescue exception
430            false
431          end
432        else
433          false
434        end
435  $VERBOSE = old_verbose
436  $DEBUG   = old_debug
437  ret
438end
439
440unless provided?(:sndlib)
441  with_silence do
442    # warning: method redefined; discarding old rand
443    require "sndlib"
444  end
445end
446
447#
448# INFO: somewhere between ruby266 and ruby271 cmath.rb was moved to a gem
449#
450if defined? Complex
451  if require "cmath"
452    include CMath
453  else
454    ############################################################
455    # begin of cmath.rb
456    ############################################################
457
458=begin
459# stub: cmath 1.0.0 ruby lib
460Gem::Specification.new do |s|
461  s.name = "cmath".freeze
462  s.version = "1.0.0"
463
464  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
465  s.require_paths = ["lib".freeze]
466  s.authors = ["Tadayoshi Funaba".freeze]
467  s.bindir = "exe".freeze
468  s.date = "2017-12-11"
469  s.description = "CMath is a library that provides trigonometric and transcendental functions for complex numbers. The functions in this module accept integers, floating-point numbers or complex numbers as arguments.".freeze
470  s.email = [nil]
471  s.homepage = "https://github.com/ruby/cmath".freeze
472  s.licenses = ["BSD-2-Clause".freeze]
473  s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze)
474  s.rubygems_version = "3.2.0.rc.1".freeze
475  s.summary = "Provides Trigonometric and Transcendental functions for complex numbers".freeze
476
477  s.installed_by_version = "3.2.0.rc.1" if s.respond_to? :installed_by_version
478
479  if s.respond_to? :specification_version then
480    s.specification_version = 4
481  end
482
483  if s.respond_to? :add_runtime_dependency then
484    s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
485    s.add_development_dependency(%q<rake>.freeze, [">= 0"])
486  else
487    s.add_dependency(%q<bundler>.freeze, [">= 0"])
488    s.add_dependency(%q<rake>.freeze, [">= 0"])
489  end
490end
491=end
492
493# = Trigonometric and transcendental functions for complex numbers.
494#
495# CMath is a library that provides trigonometric and transcendental
496# functions for complex numbers. The functions in this module accept
497# integers, floating-point numbers or complex numbers as arguments.
498#
499# Note that the selection of functions is similar, but not identical,
500# to that in module math. The reason for having two modules is that
501# some users aren't interested in complex numbers, and perhaps don't
502# even know what they are. They would rather have Math.sqrt(-1) raise
503# an exception than return a complex number.
504#
505# For more information you can see Complex class.
506#
507# == Usage
508#
509# To start using this library, simply require cmath library:
510#
511#   require "cmath"
512
513module CMath
514
515  include Math
516
517  # Backup of Math is needed because mathn.rb replaces Math with CMath.
518  RealMath = Math # :nodoc:
519  private_constant :RealMath
520
521  %w[
522    exp
523    log
524    log2
525    log10
526    sqrt
527    cbrt
528    sin
529    cos
530    tan
531    sinh
532    cosh
533    tanh
534    asin
535    acos
536    atan
537    atan2
538    asinh
539    acosh
540    atanh
541  ].each do |meth|
542    define_method(meth + '!') do |*args, &block|
543      warn("CMath##{meth}! is deprecated; use CMath##{meth} or Math##{meth}") if $VERBOSE
544      RealMath.send(meth, *args, &block)
545    end
546  end
547
548  ##
549  # Math::E raised to the +z+ power
550  #
551  #   CMath.exp(1.i * Math::PI) #=> (-1.0+1.2246467991473532e-16i)
552  def exp(z)
553    begin
554      if z.real?
555        RealMath.exp(z)
556      else
557        ere = RealMath.exp(z.real)
558        Complex(ere * RealMath.cos(z.imag),
559                ere * RealMath.sin(z.imag))
560      end
561    rescue NoMethodError
562      handle_no_method_error
563    end
564  end
565
566  ##
567  # Returns the natural logarithm of Complex. If a second argument is given,
568  # it will be the base of logarithm.
569  #
570  #   CMath.log(1 + 4i)     #=> (1.416606672028108+1.3258176636680326i)
571  #   CMath.log(1 + 4i, 10) #=> (0.6152244606891369+0.5757952953408879i)
572  def log(z, b=::Math::E)
573    begin
574      if z.real? && z >= 0 && b >= 0
575        RealMath.log(z, b)
576      else
577        Complex(RealMath.log(z.abs), z.arg) / log(b)
578      end
579    rescue NoMethodError
580      handle_no_method_error
581    end
582  end
583
584  ##
585  # Returns the base 2 logarithm of +z+
586  #
587  #   CMath.log2(-1) => (0.0+4.532360141827194i)
588  def log2(z)
589    begin
590      if z.real? and z >= 0
591        RealMath.log2(z)
592      else
593        log(z) / RealMath.log(2)
594      end
595    rescue NoMethodError
596      handle_no_method_error
597    end
598  end
599
600  ##
601  # Returns the base 10 logarithm of +z+
602  #
603  #   CMath.log10(-1) #=> (0.0+1.3643763538418412i)
604  def log10(z)
605    begin
606      if z.real? and z >= 0
607        RealMath.log10(z)
608      else
609        log(z) / RealMath.log(10)
610      end
611    rescue NoMethodError
612      handle_no_method_error
613    end
614  end
615
616  ##
617  # Returns the non-negative square root of Complex.
618  #
619  #   CMath.sqrt(-1 + 0i) #=> 0.0+1.0i
620  def sqrt(z)
621    begin
622      if z.real?
623        if z < 0
624          Complex(0, RealMath.sqrt(-z))
625        else
626          RealMath.sqrt(z)
627        end
628      else
629        if z.imag < 0 ||
630            (z.imag == 0 && z.imag.to_s[0] == '-')
631          sqrt(z.conjugate).conjugate
632        else
633          r = z.abs
634          x = z.real
635          Complex(RealMath.sqrt((r + x) / 2.0), RealMath.sqrt((r - x) / 2.0))
636        end
637      end
638    rescue NoMethodError
639      handle_no_method_error
640    end
641  end
642
643  ##
644  # Returns the principal value of the cube root of +z+
645  #
646  #   CMath.cbrt(1 + 4i) #=> (1.449461632813119+0.6858152562177092i)
647  def cbrt(z)
648    z ** (1.0/3)
649  end
650
651  ##
652  # Returns the sine of +z+, where +z+ is given in radians
653  #
654  #   CMath.sin(1 + 1i) #=> (1.2984575814159773+0.6349639147847361i)
655  def sin(z)
656    begin
657      if z.real?
658        RealMath.sin(z)
659      else
660        Complex(RealMath.sin(z.real) * RealMath.cosh(z.imag),
661                RealMath.cos(z.real) * RealMath.sinh(z.imag))
662      end
663    rescue NoMethodError
664      handle_no_method_error
665    end
666  end
667
668  ##
669  # Returns the cosine of +z+, where +z+ is given in radians
670  #
671  #   CMath.cos(1 + 1i) #=> (0.8337300251311491-0.9888977057628651i)
672  def cos(z)
673    begin
674      if z.real?
675        RealMath.cos(z)
676      else
677        Complex(RealMath.cos(z.real) * RealMath.cosh(z.imag),
678                -RealMath.sin(z.real) * RealMath.sinh(z.imag))
679      end
680    rescue NoMethodError
681      handle_no_method_error
682    end
683  end
684
685  ##
686  # Returns the tangent of +z+, where +z+ is given in radians
687  #
688  #   CMath.tan(1 + 1i) #=> (0.27175258531951174+1.0839233273386943i)
689  def tan(z)
690    begin
691      if z.real?
692        RealMath.tan(z)
693      else
694        sin(z) / cos(z)
695      end
696    rescue NoMethodError
697      handle_no_method_error
698    end
699  end
700
701  ##
702  # Returns the hyperbolic sine of +z+, where +z+ is given in radians
703  #
704  #   CMath.sinh(1 + 1i) #=> (0.6349639147847361+1.2984575814159773i)
705  def sinh(z)
706    begin
707      if z.real?
708        RealMath.sinh(z)
709      else
710        Complex(RealMath.sinh(z.real) * RealMath.cos(z.imag),
711                RealMath.cosh(z.real) * RealMath.sin(z.imag))
712      end
713    rescue NoMethodError
714      handle_no_method_error
715    end
716  end
717
718  ##
719  # Returns the hyperbolic cosine of +z+, where +z+ is given in radians
720  #
721  #   CMath.cosh(1 + 1i) #=> (0.8337300251311491+0.9888977057628651i)
722  def cosh(z)
723    begin
724      if z.real?
725        RealMath.cosh(z)
726      else
727        Complex(RealMath.cosh(z.real) * RealMath.cos(z.imag),
728                RealMath.sinh(z.real) * RealMath.sin(z.imag))
729      end
730    rescue NoMethodError
731      handle_no_method_error
732    end
733  end
734
735  ##
736  # Returns the hyperbolic tangent of +z+, where +z+ is given in radians
737  #
738  #   CMath.tanh(1 + 1i) #=> (1.0839233273386943+0.27175258531951174i)
739  def tanh(z)
740    begin
741      if z.real?
742        RealMath.tanh(z)
743      else
744        sinh(z) / cosh(z)
745      end
746    rescue NoMethodError
747      handle_no_method_error
748    end
749  end
750
751  ##
752  # Returns the arc sine of +z+
753  #
754  #   CMath.asin(1 + 1i) #=> (0.6662394324925153+1.0612750619050355i)
755  def asin(z)
756    begin
757      if z.real? and z >= -1 and z <= 1
758        RealMath.asin(z)
759      else
760        (-1.0).i * log(1.0.i * z + sqrt(1.0 - z * z))
761      end
762    rescue NoMethodError
763      handle_no_method_error
764    end
765  end
766
767  ##
768  # Returns the arc cosine of +z+
769  #
770  #   CMath.acos(1 + 1i) #=> (0.9045568943023813-1.0612750619050357i)
771  def acos(z)
772    begin
773      if z.real? and z >= -1 and z <= 1
774        RealMath.acos(z)
775      else
776        (-1.0).i * log(z + 1.0.i * sqrt(1.0 - z * z))
777      end
778    rescue NoMethodError
779      handle_no_method_error
780    end
781  end
782
783  ##
784  # Returns the arc tangent of +z+
785  #
786  #   CMath.atan(1 + 1i) #=> (1.0172219678978514+0.4023594781085251i)
787  def atan(z)
788    begin
789      if z.real?
790        RealMath.atan(z)
791      else
792        1.0.i * log((1.0.i + z) / (1.0.i - z)) / 2.0
793      end
794    rescue NoMethodError
795      handle_no_method_error
796    end
797  end
798
799  ##
800  # returns the arc tangent of +y+ divided by +x+ using the signs of +y+ and
801  # +x+ to determine the quadrant
802  #
803  #   CMath.atan2(1 + 1i, 0) #=> (1.5707963267948966+0.0i)
804  def atan2(y,x)
805    begin
806      if y.real? and x.real?
807        RealMath.atan2(y,x)
808      else
809        (-1.0).i * log((x + 1.0.i * y) / sqrt(x * x + y * y))
810      end
811    rescue NoMethodError
812      handle_no_method_error
813    end
814  end
815
816  ##
817  # returns the inverse hyperbolic sine of +z+
818  #
819  #   CMath.asinh(1 + 1i) #=> (1.0612750619050357+0.6662394324925153i)
820  def asinh(z)
821    begin
822      if z.real?
823        RealMath.asinh(z)
824      else
825        log(z + sqrt(1.0 + z * z))
826      end
827    rescue NoMethodError
828      handle_no_method_error
829    end
830  end
831
832  ##
833  # returns the inverse hyperbolic cosine of +z+
834  #
835  #   CMath.acosh(1 + 1i) #=> (1.0612750619050357+0.9045568943023813i)
836  def acosh(z)
837    begin
838      if z.real? and z >= 1
839        RealMath.acosh(z)
840      else
841        log(z + sqrt(z * z - 1.0))
842      end
843    rescue NoMethodError
844      handle_no_method_error
845    end
846  end
847
848  ##
849  # returns the inverse hyperbolic tangent of +z+
850  #
851  #   CMath.atanh(1 + 1i) #=> (0.4023594781085251+1.0172219678978514i)
852  def atanh(z)
853    begin
854      if z.real? and z >= -1 and z <= 1
855        RealMath.atanh(z)
856      else
857        log((1.0 + z) / (1.0 - z)) / 2.0
858      end
859    rescue NoMethodError
860      handle_no_method_error
861    end
862  end
863
864  module_function :exp!
865  module_function :exp
866  module_function :log!
867  module_function :log
868  module_function :log2!
869  module_function :log2
870  module_function :log10!
871  module_function :log10
872  module_function :sqrt!
873  module_function :sqrt
874  module_function :cbrt!
875  module_function :cbrt
876
877  module_function :sin!
878  module_function :sin
879  module_function :cos!
880  module_function :cos
881  module_function :tan!
882  module_function :tan
883
884  module_function :sinh!
885  module_function :sinh
886  module_function :cosh!
887  module_function :cosh
888  module_function :tanh!
889  module_function :tanh
890
891  module_function :asin!
892  module_function :asin
893  module_function :acos!
894  module_function :acos
895  module_function :atan!
896  module_function :atan
897  module_function :atan2!
898  module_function :atan2
899
900  module_function :asinh!
901  module_function :asinh
902  module_function :acosh!
903  module_function :acosh
904  module_function :atanh!
905  module_function :atanh
906
907  module_function :frexp
908  module_function :ldexp
909  module_function :hypot
910  module_function :erf
911  module_function :erfc
912  module_function :gamma
913  module_function :lgamma
914
915  private
916  def handle_no_method_error # :nodoc:
917    if $!.name == :real?
918      raise TypeError, "Numeric Number required"
919    else
920      raise
921    end
922  end
923  module_function :handle_no_method_error
924
925end
926
927    ############################################################
928    # end of cmath.rb
929    ############################################################
930    include CMath
931  end
932else
933  # ruby19 moved complex.rb and rational.rb to C
934  # (See ruby/Changelog Sun Mar 16 08:51:41 2008.)
935  with_silence do
936    # lib/complex.rb is deprecated
937    require "complex"
938  end
939  include Math
940end
941
942TWO_PI  = PI * 2.0 unless defined? TWO_PI
943HALF_PI = PI * 0.5 unless defined? HALF_PI
944
945unless defined? Rational
946  with_silence do
947    # lib/rational.rb is deprecated
948    require "rational"
949  end
950end
951
952#
953# Backward compatibility aliases and constants (from sndXX.scm)
954#
955# alias new old
956if provided? :snd
957  alias save_options                    save_state
958  alias delete_samples_with_origin      delete_samples
959  alias default_output_type             default_output_header_type
960  alias default_output_format           default_output_sample_type
961  alias mus_audio_set_oss_buffers       mus_oss_set_buffers
962  unless defined? mus_file_data_clipped
963    alias mus_file_data_clipped         mus_clipping
964    alias set_mus_file_data_clipped     set_mus_clipping
965  end
966  alias mus_data_clipped                mus_clipping
967  alias set_mus_data_clipped            set_mus_clipping
968  alias dac_is_running                  playing
969  # backwards compatibility for snd 8
970  alias make_ppolar                     make_two_pole
971  alias make_zpolar                     make_two_zero
972  alias make_average                    make_moving_average
973  alias average                         moving_average
974  alias average?                        moving_average?
975
976  # snd10.scm
977  def make_sum_of_sines(*args)
978    sines, frequency, initial_phase = nil
979    optkey(args, binding,
980           [:sines, 1],
981           [:frequency, 0.0],
982           [:initial_phase, 0.0])
983    gen = make_nsin(:frequency, frequency, :n, sines)
984    gen.phase = initial_phase
985    gen
986  end
987  alias sum_of_sines  nsin
988  alias sum_of_sines? nsin?
989
990  def make_sum_of_cosines(*args)
991    cosines, frequency, initial_phase = nil
992    optkey(args, binding,
993           [:cosines, 1],
994           [:frequency, 0.0],
995           [:initial_phase, 0.0])
996    gen = make_ncos(:frequency, frequency, :n, cosines)
997    gen.phase = initial_phase
998    gen
999  end
1000  alias sum_of_cosines  ncos
1001  alias sum_of_cosines? ncos?
1002
1003  def make_sine_summation(*args)
1004    frequency, initial_phase, n, a, ratio = nil
1005    optkey(args, binding,
1006           [:frequency, 0.0],
1007           [:initial_phase, 0.0],
1008           [:n, 1],
1009           [:a, 0.5],
1010           [:ratio, 1.0])
1011    gen = make_nrxysin(:frequency, frequency, :ratio, ratio, :n, n, :r, a)
1012    gen.phase = initial_phase
1013    gen
1014  end
1015  alias sine_summation  nrxysin
1016  alias sine_summation? nrxysin?
1017
1018  # snd13.scm
1019  def clm_print(fmt, *args)
1020    snd_print(format(fmt, *args))
1021  end unless defined? clm_print
1022end
1023
1024# enum("foo", :bar, "FOO_BAR")
1025# produces three constants
1026# Foo     == 0
1027# Bar     == 1
1028# FOO_BAR == 2
1029if ?a.kind_of?(String)
1030  def enum(*names)
1031    names.map_with_index do |name, i|
1032      const_name = name.to_s
1033      const_name[0] = const_name[0].capitalize
1034      Object.const_set(const_name, i)
1035      const_name
1036    end
1037  end
1038else
1039  def enum(*names)
1040    cap_alpha = ?A.kind_of?(String) ? ?A.sum : ?A
1041    lit_alpha = ?a.kind_of?(String) ? ?a.sum : ?a
1042    letter_diff = cap_alpha - lit_alpha
1043    names.map_with_index do |name, i|
1044      const_name = name.to_s
1045      if const_name[0].between?(?a, ?z)
1046        const_name[0] += letter_diff
1047      end
1048      Object.const_set(const_name, i)
1049      const_name
1050    end
1051  end
1052end
1053
1054class Object
1055  def null?
1056    self.nil? or
1057      (self.respond_to?(:zero?) and self.zero?) or
1058      (self.respond_to?(:empty?) and self.empty?) or
1059      (self.respond_to?(:length) and self.length.zero?)
1060  end
1061
1062  def function?(obj)
1063    func?(obj) and Snd.catch(:all, false) do self.method(obj) end.first
1064  rescue
1065    false
1066  end
1067
1068  #
1069  # ruby28/30 has no Float() any longer
1070  #
1071  if defined? Float == "constant"
1072    def Float(obj)
1073      if obj.kind_of?(NilClass)
1074        0.0
1075      else
1076        obj.to_f
1077      end
1078    end
1079  else
1080    # Float(nil) ==> 0.0 like Integer(nil) ==> 0
1081    alias old_Float Float
1082    def new_Float(obj)
1083      if obj.kind_of?(NilClass)
1084        0.0
1085      else
1086        old_Float(obj)
1087      end
1088    end
1089    alias Float new_Float
1090  end
1091
1092  def snd_func(name, *rest, &body)
1093    send(name.to_s, *rest, &body)
1094  end
1095
1096  def set_snd_func(name, val, *rest, &body)
1097    send(format("set_%s", name.to_s), val, *rest, &body)
1098  end
1099
1100# snd_apropos(str_or_sym)
1101# if `str_or_sym' is a symbol, returns snd_help result,
1102# if `str_or_sym' is a string or regexp it looks in
1103#   self.public_methods,
1104#   self.protected_methods,
1105#   self.private_methods,
1106#   Object.constants, and
1107#   Kernel.global_variables and returns an array of strings or nil.
1108#
1109#     [].snd_apropos(/^apply/)     ==> ["apply", "apply_controls"]
1110# vct(0).snd_apropos("subseq")     ==> ["subseq", "vct_subseq"]
1111#        snd_apropos(/^mus_sound/) ==> ["mus_sound_...", ...]
1112  def snd_apropos(str_or_sym)
1113    case str_or_sym
1114    when Symbol
1115      snd_help(str_or_sym)
1116    when String, Regexp
1117      res = []
1118      [self.public_methods,
1119        self.protected_methods,
1120        self.private_methods,
1121        Object.constants,
1122        Kernel.global_variables].each do |m| res += m.grep(/#{str_or_sym}/) end
1123      res
1124    else
1125      nil
1126    end
1127  end
1128end
1129
1130def NilClass(arg)
1131  nil
1132end
1133
1134class NilClass
1135  def each
1136    nil
1137  end
1138
1139  def apply(func, *rest, &body)
1140    nil
1141  end
1142
1143  def empty?
1144    true
1145  end
1146
1147  # Integer(nil) ==> 0
1148  def zero?
1149    true
1150  end
1151
1152  def nonzero?
1153    false
1154  end
1155
1156  def to_vct
1157    vector2vct([])
1158  end
1159
1160  def to_vector
1161    vector()
1162  end
1163
1164  def to_poly
1165    poly()
1166  end
1167
1168  def +(other)
1169    other
1170  end
1171
1172  def -(other)
1173    other
1174  end
1175
1176  def *(other)
1177    snd_func(other.class.name, nil)
1178  end
1179end
1180
1181# If $DEBUG = true, on older Ruby versions warnings occur about
1182# missing NilClass#to_str and Symbol#to_str
1183if $DEBUG and RUBY_VERSION < "1.8.0"
1184  class Object
1185    def method_missing(id, *args)
1186      if id == :to_str
1187        self.class.class_eval do
1188          define_method(id, lambda do | | self.to_s end)
1189        end
1190        id.id2name
1191      else
1192        Kernel.raise(NameError,
1193                     format("[version %s] undefined method `%s'",
1194                            RUBY_VERSION, id.id2name))
1195      end
1196    end
1197  end
1198end
1199
1200class String
1201  def to_sym
1202    self.intern
1203  end unless defined? "a".to_sym
1204end
1205
1206class Symbol
1207  def to_sym
1208    self
1209  end unless defined? :a.to_sym
1210end
1211
1212alias object_id __id__ unless defined? object_id
1213
1214# Provides descriptions of instances of classes, see nb.rb,
1215# xm-enved.rb, etc.
1216#
1217# m = lambda do |*args| puts args end
1218# m.info = "my description"
1219# puts m.info
1220module Info
1221  def description=(val)
1222    @description = val.to_s
1223  end
1224  alias info= description=
1225
1226  def description
1227    if defined?(@description) and
1228        string?(@description) and (not @description.empty?)
1229      @description
1230    else
1231      "no description available"
1232    end
1233  end
1234  alias info description
1235end
1236
1237unless defined? snd_help
1238  alias snd_help get_help
1239end
1240
1241$array_print_length = 10
1242
1243def print_length
1244  $array_print_length
1245end unless defined? print_length
1246
1247def set_print_length(val)
1248  $array_print_length = val
1249end unless defined? set_print_length
1250
1251module Enumerable
1252  def map_with_index
1253    i = -1
1254    self.map do |x| yield(x, i += 1) end
1255  end
1256
1257  def map_with_index!
1258    i = -1
1259    self.map! do |x| yield(x, i += 1) end
1260  end
1261
1262  def clm_cycle
1263    unless defined? @clm_cycle_index then @clm_cycle_index = 0 end
1264    val = self[@clm_cycle_index % self.length]
1265    @clm_cycle_index += 1
1266    if @clm_cycle_index == self.length then @clm_cycle_index = 0 end
1267    val
1268  end
1269
1270  def clm_cycle=(val)
1271    unless defined? @clm_cycle_index then @clm_cycle_index = 0 end
1272    self[@clm_cycle_index % self.length] = val
1273    @clm_cycle_index += 1
1274    if @clm_cycle_index == self.length then @clm_cycle_index = 0 end
1275    val
1276  end
1277  attr_accessor :clm_cycle_index
1278
1279  # backward compatibility methods
1280  def each_index
1281    self.each_with_index do |val, i| yield(i) end
1282  end unless vct(0).respond_to?(:each_index)
1283
1284  # Enumerable#zip, new in ruby core since 19-Nov-2002.
1285  # a = [4, 5, 6]
1286  # b = [7, 8, 9]
1287  # [1, 2, 3].zip(a, b) ==> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
1288  # [1, 2].zip(a, b)    ==> [[1, 4, 7], [2, 5, 8]]
1289  # a.zip([1, 2],[8])   ==> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
1290  def clm_zip(*objs)
1291    args = objs.map do |obj| obj.to_a end
1292    res = self.to_a
1293    res.each_with_index do |val, i|
1294      ary = [val]
1295      args.each do |obj| ary.push(obj[i]) end
1296      if block_given?
1297        yield(*ary)
1298      else
1299        res[i] = ary
1300      end
1301    end
1302    res
1303  end
1304  alias zip clm_zip unless [].respond_to?(:zip)
1305end
1306
1307# Older Ruby versions lack Array.new(10) do |i| ... end
1308# make_array
1309# make_array(10)
1310# make_array(10, 1.0)
1311# make_array(10) do |i| ... end
1312def make_array(len = 0, init = nil)
1313  if len >= 0
1314    if block_given?
1315      Array.new(len, init).map_with_index do |x, i| yield(i) end
1316    else
1317      Array.new(len, init)
1318    end
1319  else
1320    Kernel.raise(TypeError, format("array length < 0 (%p)?", len))
1321  end
1322end
1323
1324class Array
1325  def insert(pos, *args)
1326    unless args.empty?
1327      if pos < 0
1328        pos = self.length - (pos.abs - 1)
1329      end
1330      tmp = self.dup
1331      self[pos, args.length] = args
1332      self[pos + args.length..-1] = tmp[pos..-1]
1333    end
1334    self
1335  end unless defined? [].insert
1336
1337  # [0.0, 0.0, 0.5, 0.2, 1.0, 1.0].to_pairs
1338  #   ==> [[0.0, 0.0], [0.5, 0.2], [1.0, 1.0]]
1339  def to_pairs
1340    ary = []
1341    self.step(2) do |a, b| ary.push([a, b]) end
1342    ary
1343  end
1344
1345  # [0.0, 0.0, 0.5, 0.2, 1.0, 1.0].each_pair do |x, y|
1346  #   print x, " ", y, "\n"
1347  # end ==> 0.0 0.0
1348  #         0.5 0.2
1349  #         1.0 1.0
1350  def each_pair
1351    ary = []
1352    self.step(2) do |a, b| ary.push(yield(a, b)) end
1353    ary
1354  end
1355
1356  # prints flat float array more prettily
1357  def to_string(len = print_length)
1358    ary = self.flatten
1359    str = "["
1360    ary.each_with_index do |val, i|
1361      if i < len
1362        str = str + "%1.3f, " % val.to_f
1363      else
1364        break
1365      end
1366    end
1367    if ary.length > len
1368      str += "..."
1369    else
1370      str.chop!.chop!
1371    end
1372    str += "]"
1373  end
1374
1375  alias old_to_s to_s
1376  alias to_s inspect
1377
1378  def first=(val)
1379    self[0] = val
1380  end
1381
1382  def last=(val)
1383    self[-1] = val
1384  end
1385
1386  # ary.pick       ==> random value
1387  # ary.pick(3)    ==> [x, y, z]
1388  # ary.pick(true) ==> whole ary randomized
1389  def array_pick(n = 1)
1390    n = self.length if n == true
1391    if n == 1
1392      self[kernel_rand(self.length)]
1393    else
1394      (0...n).map do |i| self[kernel_rand(self.length)] end
1395    end
1396  end
1397  alias pick array_pick
1398
1399  def array_rand
1400    tmp = self.dup
1401    tmp.each_index do |i|
1402      r = kernel_rand(tmp.length)
1403      tmp[r], tmp[i] = tmp[i], tmp[r]
1404    end
1405    tmp
1406  end
1407  alias rand array_rand
1408
1409  def array_rand!
1410    self.each_index do |i|
1411      r = kernel_rand(self.length)
1412      self[r], self[i] = self[i], self[r]
1413    end
1414    self
1415  end
1416  alias rand! array_rand!
1417
1418  def add(other)
1419    new_ary = self.dup
1420    [self.length, other.length].min.times do |i| new_ary[i] += other[i] end
1421    new_ary
1422  end
1423
1424  def add!(other)
1425    [self.length, other.length].min.times do |i| self[i] += other[i] end
1426    self
1427  end
1428
1429  def subtract(other)
1430    new_ary = self.dup
1431    [self.length, other.length].min.times do |i| new_ary[i] -= other[i] end
1432    new_ary
1433  end
1434
1435  def subtract!(other)
1436    [self.length, other.length].min.times do |i| self[i] -= other[i] end
1437    self
1438  end
1439
1440  def multiply(other)
1441    new_ary = self.dup
1442    [self.length, other.length].min.times do |i| new_ary[i] *= other[i] end
1443    new_ary
1444  end
1445
1446  def multiply!(other)
1447    [self.length, other.length].min.times do |i| self[i] *= other[i] end
1448    self
1449  end
1450
1451  def offset(scl)
1452    scl = Float(scl)
1453    self.class.new(self.length) do |i| self[i] + scl end
1454  end
1455
1456  def offset!(scl)
1457    scl = Float(scl)
1458    self.map! do |val| val += scl end
1459  end
1460
1461  def scale(scl)
1462    scl = Float(scl)
1463    self.class.new(self.length) do |i| self[i] * scl end
1464  end
1465
1466  def scale!(scl)
1467    scl = Float(scl)
1468    self.map! do |val| val *= scl end
1469  end
1470
1471  def to_vector
1472    Vec.new(self.length) do |i| Float(self[i]) end
1473  end
1474
1475  def car
1476    self[0]
1477  end
1478
1479  def car=(val)
1480    self[0] = val
1481  end
1482
1483  def cadr
1484    self[1]
1485  end
1486
1487  def cadr=(val)
1488    self[1] = val
1489  end
1490
1491  def caddr
1492    self[2]
1493  end
1494
1495  def caddr=(val)
1496    self[2] = val
1497  end
1498
1499  def cadddr
1500    self[3]
1501  end
1502  def cadddr=(val)
1503    self[3] = val
1504  end
1505
1506  def caddddr
1507    self[4]
1508  end
1509
1510  def caddddr=(val)
1511    self[4] = val
1512  end
1513
1514  def cdr
1515    self[1..-1]
1516  end
1517
1518  def step(n = 1)
1519    0.step(self.length - n, n) do |i| yield(*self[i, n]) end
1520    self
1521  end
1522
1523  add_help(:apply,
1524           "Array#apply([:func,] *rest, &body)  \
1525Applies function or procedure with possible rest args \
1526to each element of Array or subclasses of Array.
1527    [0, 1, 2].apply(\"a: %d\\n\") do |fmt, a| printf(fmt, a) end
1528    [0, 1, 2].apply(:printf, \"a: %d\\n\")
1529both produce
1530a: 0
1531a: 1
1532a: 2
1533                               [1, 2, 3, 4].apply(:+)      # ==> 10
1534                 %w(snd sndplay with_sound).apply(:length) # ==> [3, 7, 10]
1535          [[1, 2, 3, 4], [1, 2, 3], [1, 2]].apply(:max)    # ==> [4, 3, 2]
1536[vct(0.1, 0.2, 0.3), vct(-0.1, -0.2, -0.3)].apply(:peak)   # ==> [0.3, 0.3]
1537                                     sounds.apply(:map) do |s| puts s end
1538                                     sounds.apply(:close_sound)")
1539  def apply(func, *rest, &body)
1540    if block_given? and (not symbol?(func))
1541      rest.unshift(func)
1542      self.map do |item| body.call(*rest + [item]) end
1543    else
1544      case func
1545      when Proc, Method
1546        self.map do |item| func.call(*rest + [item]) end
1547      when Symbol, String
1548        meths = self.methods
1549        if body and (meths.member?(func.to_s) or meths.member?(func.to_sym))
1550          # map, each, ...
1551          self.send(func, *rest, &body)
1552        else
1553          receiver = self.compact.first
1554          meths = receiver.methods
1555          if receiver and
1556              (meths.member?(func.to_s) or meths.member?(func.to_sym))
1557            # methods
1558            case func.to_sym
1559            when :+, :-, :*
1560              res = receiver
1561              self[1..-1].compact.map do |item|
1562                res = res.send(func, *rest + [item])
1563              end
1564              res
1565            else
1566              len = rest.length + ((array?(receiver) and receiver.length) or 1)
1567              if receiver.method(func).arity.abs == len
1568                # remove_file (String(WS) in ws.rb)
1569                self.map do |item| send(func, *rest + [item]) end
1570              else
1571                # length, max, min, ...
1572                self.map do |item| item.send(func, *rest) end
1573              end
1574            end
1575          else
1576            # functions
1577            self.map do |item| send(func, *rest + [item]) end
1578          end
1579        end
1580      end
1581    end
1582  end
1583
1584  # original operands +, -, and * can now handle nil and numberic
1585  # (offset, multiply)
1586  #
1587  # [].+(ary)      concatenate arrays
1588  # [].+(number)   [].add(number)
1589  unless defined? [].ary_plus
1590    alias old_ary_plus +
1591    def ary_plus(other)
1592      case other
1593      when Numeric
1594        self.offset(other)
1595      when NilClass
1596        self
1597      else
1598        self.old_ary_plus(other)
1599      end
1600    end
1601    alias + ary_plus
1602  end
1603
1604  # [].-(ary)     intersection
1605  # [1, 2, 3, 4] - [2, 3] ==> [1, 4]
1606  # [] - number   [].offset
1607  unless defined? [].ary_minus
1608    alias old_ary_minus -
1609    def ary_minus(other)
1610      case other
1611      when Numeric
1612        self.offset(-other)
1613      when NilClass
1614        self
1615      else
1616        self.old_ary_minus(other)
1617      end
1618    end
1619    alias - ary_minus
1620  end
1621
1622  # [].*(n)   repetition or [].join(n)
1623  # [5] * 3              ==> [5, 5, 5]
1624  # ["foo", "bar"] * "-" ==> "foo-bar"
1625  unless defined? [].ary_times
1626    alias old_ary_times *
1627    def ary_times(other)
1628      case other
1629      when NilClass
1630        nil.to_a
1631      else
1632        self.old_ary_times(other)
1633      end
1634    end
1635    alias * ary_times
1636  end
1637end
1638
1639# name Vector is in use (lib/ruby/1.9/matrix.rb)
1640class Vec < Array
1641  def self.[](*ary)
1642    self.new(ary.length) do |i| ary[i] end
1643  end
1644
1645  def initialize(len, init = 0.0, &body)
1646    @name = "vector"
1647    if len >= 0
1648      if block_given?
1649        super(len, &body)
1650      else
1651        super(len, init)
1652      end
1653    else
1654      Kernel.raise(TypeError, format("array length < 0 (%p)?", len))
1655    end
1656    if test = self.detect do |x| (not number?(x)) end
1657      Kernel.raise(TypeError,
1658                   format("only numeric elements (%p)?", test))
1659    end
1660  end
1661
1662  def inspect
1663    str = "%s(" % @name
1664    self.each do |val| str = str + "%s, " % val end
1665    if self.length > 0 then str.chop!.chop! end
1666    str += ")"
1667    str
1668  end
1669
1670  def to_s
1671    if self.length > 0
1672      vals = ":"
1673      self.map do |val| vals = vals + " %s" % val end
1674    else
1675      vals = ""
1676    end
1677    format("#<%s[%d]%s>", self.class, self.length, vals)
1678  end
1679
1680  def +(other)
1681    case other
1682    when Numeric
1683      self.offset(other).to_vector
1684    when Array, Vec, Vct
1685      self.add(other.to_vector)
1686    when NilClass
1687      self
1688    end
1689  end
1690
1691  def -(other)
1692    case other
1693    when Numeric
1694      self.offset(-other).to_vector
1695    when Array, Vec, Vct
1696      self.subtract(other.to_vector)
1697    when NilClass
1698      self
1699    end
1700  end
1701
1702  def *(other)
1703    case other
1704    when Numeric
1705      self.scale(other).to_vector
1706    when Array, Vec, Vct
1707      self.multiply(other.to_vector)
1708    when NilClass
1709      nil.to_vector
1710    end
1711  end
1712end
1713
1714def Vec(obj)
1715  if obj.nil? then obj = [] end
1716  assert_type(obj.respond_to?(:to_vector), obj, 0,
1717              "an object containing method \
1718'to_vector' (Vct, String, Array and subclasses)")
1719  obj.to_vector
1720end
1721
1722def make_vector(len, init = 0.0, &body)
1723  Vec.new(len, init, &body)
1724end
1725
1726def vector?(obj)
1727  obj.kind_of?(Vec)
1728end
1729
1730def vector(*args)
1731  args.to_vector
1732end
1733
1734class String
1735  def to_vector
1736    if self.scan(/^vector\([-+,.)\d\s]+/).null?
1737      nil
1738    else
1739      eval(self)
1740    end
1741  end
1742
1743  def to_vct
1744    if self.scan(/^vct\([-+,.)\d\s]+/).null?
1745      nil
1746    else
1747      eval(self)
1748    end
1749  end
1750end
1751
1752def Vct(obj)
1753  if obj.nil? then obj = [] end
1754  assert_type(obj.respond_to?(:to_vct), obj, 0,
1755              "an object containing method \
1756'to_vct' (Vct, String, Array and subclasses)")
1757  obj.to_vct
1758end
1759
1760def make_vct!(len, init = 0.0, &body)
1761  if block_given?
1762    Vct.new(len, &body)
1763  else
1764    Vct.new(len, init)
1765  end
1766end
1767
1768class Vct
1769  def self.[](*ary)
1770    self.new(ary.length) do |i| ary[i] end
1771  end
1772
1773  def name
1774    self.class.to_s.downcase
1775  end
1776
1777  def to_vct
1778    self
1779  end
1780
1781  def to_vector
1782    Vec.new(self.length) do |i| self[i] end
1783  end
1784
1785  def apply(*rest, &body)
1786    self.to_a.apply(*rest, &body)
1787  end
1788
1789  def +(other)
1790    case other
1791    when Numeric
1792      self.offset(other)
1793    when Array, Vec, Vct
1794      self.add(other.to_vct)
1795    when NilClass
1796      self
1797    end
1798  end
1799
1800  def -(other)
1801    case other
1802    when Numeric
1803      self.offset(-other)
1804    when Array, Vec, Vct
1805      self.subtract(other.to_vct)
1806    when NilClass
1807      self
1808    end
1809  end
1810
1811  def *(other)
1812    case other
1813    when Numeric
1814      self.scale(other)
1815    when Array, Vec, Vct
1816      self.multiply(other.to_vct)
1817    when NilClass
1818      nil.to_vct
1819    end
1820  end
1821
1822  def step(n = 1, &body)
1823    self.to_a.step(n, &body)
1824  end
1825
1826  # v = vct(0, 1, 2, 3, 4)
1827  # v[2..4]  ==> vct(2.000, 3.000, 4.000)
1828  # v[2...4] ==> vct(2.000, 3.000)
1829  # v[3, 4]  ==> vct(3.000, 4.000)
1830  # v[-1]    ==> 4.0
1831  def vct_ref_extend(idx, size = nil)
1832    case idx
1833    when Integer
1834      if idx < 0 then idx += self.length end
1835      if idx < 0 then Snd.raise(:out_of_range, "index < 0", idx) end
1836      if integer?(size)
1837        size += idx - 1
1838        if size >= self.length then size = self.length - 1 end
1839        if size.between?(0, self.length - 1) and size >= idx
1840          self.subseq(idx, size)
1841        else
1842          nil.to_vct # i.e. false
1843        end
1844      else
1845        vct_ref(self, idx)
1846      end
1847    when Range
1848      beg = idx.first
1849      len = idx.last
1850      if beg < 0 then beg += self.length end
1851      if len < 0 then len += self.length end
1852      if len >= self.length then len = self.length - 1 end
1853      # exclude_end?: (1..2)  ==> false
1854      #               (1...2) ==> true
1855      if idx.exclude_end? then len -= 1 end
1856      if beg.between?(0, self.length - 1) and len >= beg
1857        self.subseq(beg, len)
1858      else
1859        nil.to_vct # i.e. false
1860      end
1861    end
1862  end
1863  # alias [] vct_ref_extend
1864
1865  # This is required since Ruby 1.9.
1866  alias zip clm_zip if [].respond_to?(:zip)
1867end
1868
1869# As of Ruby 2.4.x Fixnum and Bignum are unified into Integer and
1870# Fixnum is deprecated.
1871
1872if RUBY_VERSION < "2.4.0"
1873  class Fixnum
1874    # no reloading (load "clm.rb")
1875    unless defined? 0.new_int_plus
1876      alias int_plus +
1877      def new_int_plus(other)
1878        case other
1879        when Vct, Array, Vec
1880          other.offset(Float(self))
1881        when NilClass
1882          self
1883        else
1884          self.int_plus(other)
1885        end
1886      end
1887      alias + new_int_plus
1888    end
1889
1890    unless defined? 0.new_int_times
1891      alias int_times *
1892      def new_int_times(other)
1893        case other
1894        when Vct, Array, Vec
1895          other.scale(self)
1896        when NilClass
1897          0
1898        else
1899          self.int_times(other)
1900        end
1901      end
1902      alias * new_int_times
1903    end
1904  end
1905else
1906  class Integer
1907    unless defined? 0.new_int_plus
1908      alias int_plus +
1909      def new_int_plus(other)
1910        case other
1911        when Vct, Array, Vec
1912          other.offset(Float(self))
1913        when NilClass
1914          self
1915        else
1916          self.int_plus(other)
1917        end
1918      end
1919      alias + new_int_plus
1920    end
1921
1922    unless defined? 0.new_int_times
1923      alias int_times *
1924      def new_int_times(other)
1925        case other
1926        when Vct, Array, Vec
1927          other.scale(self)
1928        when NilClass
1929          0
1930        else
1931          self.int_times(other)
1932        end
1933      end
1934      alias * new_int_times
1935    end
1936  end
1937end
1938
1939class Float
1940  # no reloading (load "clm.rb")
1941  unless defined? 0.0.new_float_plus
1942    alias float_plus +
1943    def new_float_plus(other)
1944      case other
1945      when Vct, Array, Vec
1946        other.offset(self)
1947      when NilClass
1948        self
1949      else
1950        self.float_plus(other)
1951      end
1952    end
1953    alias + new_float_plus
1954  end
1955
1956  unless defined? 0.0.new_float_times
1957    alias float_times *
1958    def new_float_times(other)
1959      case other
1960      when Vct, Array, Vec
1961        other.scale(self)
1962      when NilClass
1963        0.0
1964      else
1965        self.float_times(other)
1966      end
1967    end
1968    alias * new_float_times
1969  end
1970
1971  unless defined? 0.0.imag
1972    def imag
1973      0.0
1974    end
1975    alias image imag
1976  end
1977end
1978
1979def mus_a0(gen)
1980  mus_xcoeff(gen, 0)
1981end
1982
1983def set_mus_a0(gen, val)
1984  set_mus_xcoeff(gen, 0, val)
1985end
1986
1987def mus_a1(gen)
1988  mus_xcoeff(gen, 1)
1989end
1990
1991def set_mus_a1(gen, val)
1992  set_mus_xcoeff(gen, 1, val)
1993end
1994
1995def mus_a2(gen)
1996  mus_xcoeff(gen, 2)
1997end
1998
1999def set_mus_a2(gen, val)
2000  set_mus_xcoeff(gen, 2, val)
2001end
2002
2003def mus_b1(gen)
2004  mus_ycoeff(gen, 1)
2005end
2006
2007def set_mus_b1(gen, val)
2008  set_mus_ycoeff(gen, 1, val)
2009end
2010
2011def mus_b2(gen)
2012  mus_ycoeff(gen, 2)
2013end
2014
2015def set_mus_b2(gen, val)
2016  set_mus_ycoeff(gen, 2, val)
2017end
2018
2019class Mus
2020  # clm_gen.call(a1, a2) requires 2 arguments but clm_gen.run([a1, [a2]])
2021  # 0, 1 or 2.
2022  #
2023  # clm_gen.run([arg1, [arg2]])
2024  def run(arg1 = 0.0, arg2 = 0.0)
2025    mus_run(self, arg1, arg2)
2026  end
2027
2028  def apply(*rest)
2029    mus_apply(self, *rest)
2030  end
2031
2032  alias mus_inspect inspect
2033  def inspect
2034    "#<" + mus_describe(self) + ">"
2035  end
2036
2037  def close
2038    mus_close(self)
2039  end
2040
2041  # gen.xcoeff = 0, 0.4
2042  # set_mus_xcoeff(gen, index, val)
2043  def xcoeff=(args)
2044    set_mus_xcoeff(self, *args.flatten[0, 2])
2045  end
2046
2047  # gen.ycoeff = 0, 0.4
2048  # set_mus_ycoeff(gen, index, val)
2049  def ycoeff=(args)
2050    set_mus_ycoeff(self, *args.flatten[0, 2])
2051  end
2052
2053  def a0
2054    mus_xcoeff(self, 0)
2055  end
2056
2057  def a0=(val)
2058    set_mus_xcoeff(self, 0, val)
2059  end
2060
2061  def a1
2062    mus_xcoeff(self, 1)
2063  end
2064
2065  def a1=(val)
2066    set_mus_xcoeff(self, 1, val)
2067  end
2068
2069  def a2
2070    mus_xcoeff(self, 2)
2071  end
2072
2073  def a2=(val)
2074    set_mus_xcoeff(self, 2, val)
2075  end
2076
2077  def b1
2078    mus_ycoeff(self, 1)
2079  end
2080
2081  def b1=(val)
2082    set_mus_ycoeff(self, 1, val)
2083  end
2084
2085  def b2
2086    mus_ycoeff(self, 2)
2087  end
2088
2089  def b2=(val)
2090    set_mus_ycoeff(self, 2, val)
2091  end
2092end
2093
2094# base class for generators written in Ruby
2095class Musgen
2096  def initialize
2097    @frequency = $clm_default_frequency
2098    @phase = 0.0
2099    @scaler = 1.0
2100    @length = 0
2101    @data = nil
2102    @increment = 0
2103    @interp_type = -1
2104    @file_name = ""
2105  end
2106  attr_accessor :frequency
2107  attr_accessor :phase
2108  attr_accessor :scaler
2109  attr_accessor :increment
2110  attr_reader   :length
2111  attr_reader   :data
2112  attr_reader   :interp_type
2113  attr_reader   :file_name
2114
2115  def inspect
2116    format("%s.new()", self.class)
2117  end
2118
2119  def to_s
2120    format("#<%s>", self.class)
2121  end
2122
2123  def run(val1 = 0.0, val2 = 0.0)
2124    self.run_func(val1, val2)
2125  end
2126  alias call run
2127
2128  def apply(*rest)
2129    self.run_func(*rest)
2130  end
2131
2132  def eql?(other)
2133    self == other
2134  end
2135
2136  def reset
2137    @frequency = $clm_default_frequency
2138    @phase = 0.0
2139    @scaler = 1.0
2140    @increment = 0
2141    self
2142  end
2143end
2144
2145class Numeric
2146  def positive?
2147    self > 0
2148  end unless defined? 1.positive?
2149
2150  def negative?
2151    self < 0
2152  end unless defined? 1.negative?
2153
2154  # According to Ruby's ChangeLog-2.0.0:
2155  # Wed Nov 21 21:53:29 2012  Tadayoshi Funaba  <tadf@dotrb.org>
2156  # * complex.c (nucomp_to_c): added.
2157  def to_c
2158    Complex(self)
2159  end unless defined? 1.to_c
2160end
2161
2162class Integer
2163  def even?
2164    self.modulo(2) == 0
2165  end unless defined? 1.even?
2166
2167  def odd?
2168    self.modulo(2) != 0
2169  end unless defined? 1.odd?
2170
2171  def prime?
2172    (self == 2) or
2173    (self.odd? and
2174     3.step(sqrt(self), 2) do |i| return false if self.modulo(i) == 0 end)
2175  end
2176end
2177
2178class Float
2179  # step accepts floats as arguments (implemented in newer versions)
2180  def step(upto, step)
2181    counter = self
2182    while counter < upto
2183      yield(counter)
2184      counter += step
2185    end
2186    counter
2187  end unless 1.1.respond_to?(:step)
2188end
2189
2190class Range
2191  def step(n = 1, &body)
2192    self.to_a.step(n, &body)
2193  end unless defined? Range.new(0, 1).step
2194end
2195
2196def as_one_edit_rb(*origin, &body)
2197  # ruby compatibility:
2198  # ruby pre 1.9: lambda do end.arity != lambda do | | end.arity
2199  # ruby     1.9: they are even (0)
2200  as_one_edit(lambda do | | body.call end, origin.empty? ? "" : format(*origin))
2201end
2202
2203def map_channel_rb(beg = 0, dur = false,
2204                   snd = false, chn = false,
2205                   edpos = false, edname = false, &func)
2206  map_channel(func, beg, dur, snd, chn, edpos, edname)
2207end
2208
2209add_help(:map_chan_rb,
2210         "map_chan(func, start=0, end=false, edname=false, \
2211snd=false, chn=false, edpos=false)  \
2212Applies FUNC to samples in the specified channel.  \
2213It is the old (\"irregular\") version of map_channel.")
2214def map_chan_rb(beg = 0, dur = false, ednam = false,
2215                snd = false, chn = false, edpos = false, &func)
2216  map_chan(func, beg, dur, ednam, snd, chn, edpos)
2217end
2218
2219class Proc
2220  include Info
2221  alias run call
2222
2223  add_help(:to_method,
2224           "Proc#to_method(name, klass=Object)  \
2225Converts a Proc to a Method 'name' in the given class, default Object.  \
2226NAME can be a string or a symbol.
2227
2228m = lambda do |*args| p args end
2229m.to_method(:func)
2230func(1, 2, 3) ==> [1, 2, 3]
2231
2232lambda do |x| p x end.to_method(:foo);  foo(\"text1\") ==> \"text1\"
2233lambda do |x| p x end.to_method(\"bar\"); bar(\"text2\") ==> \"text2\"")
2234  def to_method(name, klass = Object)
2235    name = case name
2236           when String
2237             name.intern
2238           when Symbol
2239             name
2240           end
2241    body = self
2242    klass.class_eval do define_method(name, body) end
2243  end
2244
2245  # Important:
2246  # The following works only with newer ruby versions (I assume >=
2247  # 1.8.x).  Proc#inspect must return #<Proc:0x80c96a0@xxx:x> to
2248  # locate the source file of the procedure, not only #<Proc:0x80c96a0>!
2249
2250  # Functions to_str and to_body try to search the procedure source
2251  # code in a file determined by to_s.  It is only a simple scanner
2252  # which doesn't look for the whole Ruby syntax. ;-)
2253  #
2254  # It doesn't work if no source file exists, i.e, if the code is
2255  # eval'ed by the Snd listener (or in Emacs).  You must load the file
2256  # instead.
2257  #
2258  # with_sound(:notehook,
2259  #            lambda do |name| snd_print(name) if name =~ /viol/ end) do
2260  #   fm_violin(0, 1, 440, 0.3)
2261  # end
2262  #
2263  # $clm_notehook = lambda do |name| clm_print(name) if name =~ /viol/ end
2264  #
2265  # with_sound do
2266  #   fm_violin(0, 1, 440, 0.3)
2267  # end
2268  #
2269  # with_sound(:save_body, true) do
2270  #  ...
2271  # end
2272
2273  # returns something like 'lambda do ... end'
2274  def to_str
2275    if body = self.source
2276      return body
2277    end
2278    file, line = self.to_s.sub(/>/, "").split(/@/).last.split(/:/)
2279    if file[0] == ?( and file[-1] == ?)
2280      if $VERBOSE
2281        warning("%s#%s: no file found for procedure %p",
2282                self.class, get_func_name, self)
2283      end
2284      body = ""
2285    elsif (not File.exist?(file))
2286      if $VERBOSE
2287        warning("%s#%s: \
2288Sorry, you need a higher ruby version to use Proc#to_str.
2289It works only with newer ruby versions (I assume >= 1.8.x).
2290Proc#inspect must return #<Proc:0x01234567@xxx:x> not only %p!",
2291             self.class, get_func_name, self)
2292      end
2293      body = ""
2294    else
2295      lineno = line.to_i
2296      body = ""
2297      blck = i = 0
2298      first_line = true
2299      File.foreach(file) do |ln|
2300        i += 1
2301        next if i < lineno
2302        body << ln
2303        if first_line
2304          if (ln.scan(/\s*do\b|\{/).length -
2305              ln.scan(/\s*end\b|\}/).length).zero? and
2306              (ln.scan(/\(/).length - ln.scan(/\)/).length).zero?
2307            break
2308          else
2309            first_line = false
2310            blck = 1
2311            next
2312          end
2313        end
2314        next if /\s*\S+\s*(if|unless|while|until)+/ =~ ln
2315        break if (blck += Snd_eval.count_level(ln)).zero?
2316        break if blck.negative?
2317      end
2318    end
2319    unless self.source then self.source = body end
2320    body
2321  end
2322
2323  # returns the inner body without 'lambda do end'
2324  def to_body
2325    if (body = self.to_str).null?
2326      ""
2327    elsif body.split(/\n/).length == 1
2328      body.chomp.sub(/^(?:\s*\w+(?:\(.*\))??\s*(?:do\s+|\{\s*))(.*)\s*(?:end|\})$/, '\1').strip
2329    else
2330      body.split(/\n/)[1..-2].join("\n")
2331    end
2332  end
2333
2334  # property set in g_edit_list_to_function (snd-edits.c)
2335  def source
2336    property(self.object_id, :proc_source)
2337  end
2338
2339  def source=(val)
2340    set_property(self.object_id, :proc_source, val)
2341  end
2342end
2343
2344def make_proc2method(name, prc)
2345  prc.to_method(name)
2346end
2347
2348# produces two new functions: NAME and SET_NAME
2349# val = 10
2350# make_proc_with_setter(:foo, lambda { puts val }, lambda { |a| val = a })
2351# foo ==> 10
2352# set_foo(12)
2353# foo ==> 12
2354def make_proc_with_setter(name, getter, setter)
2355  make_proc2method(name, getter)
2356  make_proc2method(format("set_%s", name).intern, setter)
2357end
2358
2359# prc = make_proc_with_source(%(lambda do |a, b, c| puts a, b, c end))
2360# prc.call(1, 2, 3)
2361# prc.source ==> "lambda do |a, b, c| puts a, b, c end"
2362#
2363# With the second argument BIND one can use local variables known in
2364# the current (or other) environment in the proc body:
2365#
2366# os = make_oscil(:frequency, 330)
2367# prc = make_proc_with_source(%(lambda do | |
2368#                                 10.times do |i| p os.run end
2369#                               end), binding)
2370# puts prc.source   ==> lambda do | | 10.times do |i| p os.run end end
2371# prc.call          ==> ..., 0.748837699712728
2372# puts
2373# prc.call          ==> ..., 0.97679449812022
2374def make_proc_with_source(string, bind = binding)
2375  if proc?(prc = (res = Snd.catch(:all) do eval(string, bind) end).first)
2376    prc.source = string
2377    prc
2378  else
2379    Snd.raise(:runtime_error, res, prc, string)
2380  end
2381end
2382
2383make_proc_with_setter(:proc_source,
2384                      lambda do |prc| prc.source end,
2385                      lambda do |prc, val| prc.source = val end)
2386
2387# Multi-line input to the Snd listener and Emacs/inf-snd.el.
2388# A simple parser collects multi-line input, e.g.
2389#
2390# with_sound do
2391#   fm_violin(0.0, 0.1, 330, 0.1)
2392#   fm_violin(0.1, 0.1, 660, 0.1)
2393# end
2394#
2395# and evals it.
2396#
2397# ~/.snd
2398# set_listener_prompt("snd> ")   # optional
2399# start_listener_eval            # installs read-hook for snd-listener input
2400# start_emacs_eval               # installs emacs-eval-hook
2401
2402make_hook("$emacs_eval_hook", 1, "\
2403emacs_eval_hook(line):  \
2404called each time inf-snd.el sends a line to the Snd process.  \
2405The hook functions may do their best to deal with multi-line input; \
2406they can collect multi-line input and eval it by itself.  \
2407One example is install_eval_hooks(file, retval, input, hook, &reset_cursor) \
2408in clm.rb.")
2409
2410# inf-snd.el calls this function each time a line was sent to the
2411# emacs buffer.
2412def run_emacs_eval_hook(line)
2413  if $emacs_eval_hook.empty?
2414    # without emacs-eval-hook only single line eval
2415    file = "(emacs-eval-hook)"
2416    set_snd_input(:emacs)
2417    begin
2418      Snd.display(eval(line, TOPLEVEL_BINDING, file, 1).inspect)
2419    rescue Interrupt, ScriptError, NameError, StandardError
2420      Snd.display(verbose_message_string(true, "# ", file))
2421    end
2422    set_snd_input(:snd)
2423    nil
2424  else
2425    $emacs_eval_hook.call(line)
2426  end
2427end
2428
2429class Snd_eval
2430  class << Snd_eval
2431    Open_token = %w(class module def do { while until if unless case begin for)
2432    Close_token = %w(end })
2433
2434    def count_level(line)
2435      eval_level = 0
2436      # skip strings and symbols which may contain reserved words
2437      line.gsub(/(:\w+|".+")/, "").split(/\b/).each do |s|
2438        case s
2439        when *Open_token
2440          eval_level += 1
2441        when *Close_token
2442          eval_level -= 1
2443        end
2444      end
2445      eval_level
2446    end
2447  end
2448end
2449
2450class Snd_prompt
2451  # level number inserted into original prompt
2452  # ">"     ==> "(0)>"
2453  # "snd> " ==> "snd(0)> "
2454  def initialize(level)
2455    @listener_prompt = listener_prompt
2456    @base_prompt = listener_prompt.split(/(\(\d+\))?(>)?\s*$/).car.to_s
2457    @rest_prompt = listener_prompt.scan(/>\s*$/).car.to_s
2458    update(level)
2459  end
2460
2461  def inspect
2462    format("#<%s %s(0)%s>", self.class, @base_prompt, @rest_prompt)
2463  end
2464
2465  def update(level)
2466    set_listener_prompt(format("%s(%d)%s", @base_prompt, level, @rest_prompt))
2467  end
2468
2469  def reset
2470    set_listener_prompt(@listener_prompt)
2471  end
2472end
2473
2474def install_eval_hooks(file, retval, input, hook, &reset_cursor)
2475  eval_level = 0
2476  eval_line = ""
2477  prompt = Snd_prompt.new(eval_level)
2478  reset_cursor.nil? or reset_cursor.call
2479  $exit_hook.add_hook!(file) do | | prompt.reset end
2480  hook.add_hook!(file) do |line|
2481    eval_line = eval_line + line + "\n"
2482    eval_level += Snd_eval.count_level(line)
2483    if eval_level.negative?
2484      eval_level = 0
2485      eval_line = ""
2486    end
2487    if eval_level.zero?
2488      set_snd_input(input)
2489      begin
2490        Snd.display(eval(eval_line, TOPLEVEL_BINDING, file, 1).inspect)
2491      rescue Interrupt, ScriptError, NameError, StandardError
2492        Snd.display(verbose_message_string(true, "# ", file))
2493      ensure
2494        eval_line = ""
2495      end
2496    end
2497    prompt.update(eval_level)
2498    reset_cursor.nil? or reset_cursor.call
2499    retval
2500  end
2501end
2502
2503# installs the emacs-eval-hook
2504def start_emacs_eval(name = "(emacs)")
2505  install_eval_hooks(name, nil, :emacs, $emacs_eval_hook) do
2506    $stdout.print(listener_prompt)
2507    $stdout.flush
2508  end
2509end
2510
2511# installs the read-hook
2512def start_listener_eval(name = "(snd)")
2513  set_show_listener(true)
2514  install_eval_hooks(name, true, :snd, $read_hook)
2515end
2516
2517def stop_emacs_eval(name = "(emacs)")
2518  $emacs_eval_hook.remove_hook!(name)
2519  $exit_hook.run_hook_by_name(name)
2520  $exit_hook.remove_hook!(name)
2521end
2522
2523def stop_listener_eval(name = "(snd)")
2524  $read_hook.remove_hook!(name)
2525  $exit_hook.run_hook_by_name(name)
2526  $exit_hook.remove_hook!(name)
2527  reset_listener_cursor
2528  clm_print("\n%s", listener_prompt)
2529end
2530
2531# Debugging resp. inspecting local variables
2532
2533make_proc_with_setter(:debug_properties,
2534                      lambda do |name|
2535                        property(name, :debug_property)
2536                      end,
2537                      lambda do |name, val|
2538                        set_property(name, :debug_property, val)
2539                      end)
2540
2541make_proc_with_setter(:debug_property,
2542                      lambda do |key, name|
2543                        hash?(h = debug_properties(name)) and h[key]
2544                      end,
2545                      lambda do |key, val, name|
2546                        h = debug_properties(name)
2547                        unless hash?(h) and h.store(key, [val] + h[key])
2548                          a = property(:debug, :names)
2549                          unless array?(a) and a.push(name)
2550                            set_property(:debug, :names, [name])
2551                          end
2552                          set_debug_properties(name, {key => [val]})
2553                        end
2554                      end)
2555
2556make_proc_with_setter(:debug_binding,
2557                      lambda do |name|
2558                        debug_property(:binding, name)
2559                      end,
2560                      lambda do |bind, *name|
2561                        set_debug_property(:binding, bind,
2562                                           (name[0] or get_func_name(3)))
2563                      end)
2564
2565# Shows all local variables of last call of functions prepared with
2566# set_debug_binding(binding)
2567#
2568# def function1
2569#   [...]
2570#   set_debug_binding(binding)
2571# end
2572# def function2
2573#   [...]
2574#   set_debug_binding(binding)
2575# end
2576# [...]
2577# function1
2578# function2
2579# [...]
2580#
2581# display_all_variables
2582def display_all_variables(name = nil)
2583  if name
2584    [name]
2585  else
2586    (property(:debug, :names) or [])
2587  end.each do |nm|
2588    debug_binding(nm).each do |bind|
2589      Snd.message("=== %s ===", nm)
2590      Snd.message()
2591      each_variables(bind) do |var, val|
2592        Snd.message("%s = %s", var, val.inspect)
2593      end
2594      Snd.message()
2595    end
2596  end
2597end
2598
2599# each_variables provides all local variable names and their values in
2600# the given proc context
2601#
2602# def function
2603#   [...]
2604#   each_variables do |k, v|
2605#     Snd.display("%s = %s", k, v)
2606#   end
2607# end
2608def each_variables(bind = binding, &prc)
2609  eval("local_variables", bind).each do |name|
2610    name = name.to_s
2611    prc.call(name, eval(name, bind))
2612  end
2613end
2614
2615# let(8, :foo, "bar") do |a, b, c|
2616#   printf("a: %d, b: %s, c: %s\n", a, b, c)
2617# end
2618#
2619# Simulates a save local variable environment and restores old
2620# variables to their original values.
2621def let(*args, &prc)
2622  locals = Hash.new
2623  bind = prc.binding
2624  each_variables(bind) do |var, val|
2625    locals[var] = val
2626  end
2627  prc.call(*args)
2628rescue Interrupt, ScriptError, NameError, StandardError
2629  Kernel.raise
2630ensure
2631  @locals = locals
2632  locals.each_key do |name|
2633    eval("#{name} = @locals[#{name.inspect}]", bind)
2634  end
2635  remove_instance_variable("@locals")
2636end
2637
2638# for irb (rgb.rb)
2639def make_color(r, g, b)
2640  [:Pixel, 0]
2641end unless defined? make_color
2642
2643def doc(*rest)
2644  # dummy for old Kernel.doc
2645end
2646
2647##
2648## Utilities
2649##
2650
2651if provided? :snd_nogui
2652  alias close_sound_extend close_sound
2653else
2654  def close_sound_extend(snd)
2655    # 5 == Notebook
2656    if main_widgets[5]
2657      idx = Snd.sounds.index(snd)
2658      if idx.nil? then idx = 0 end
2659      close_sound(snd)
2660      snds = sounds() and set_selected_sound(snds[idx < snds.length ? idx : -1])
2661    else
2662      close_sound(snd)
2663    end
2664  end
2665end
2666
2667add_help(:times2samples,
2668         "times2samples(start, dur)  \
2669START and DUR are in seconds; returns array [beg, end] in samples.")
2670def times2samples(start, dur)
2671  beg = seconds2samples(start)
2672  [beg, beg + seconds2samples(dur)]
2673end
2674
2675def random(val)
2676  if val.zero?
2677    val
2678  else
2679    case val
2680    when Integer
2681      kernel_rand(val)
2682    when Float
2683      val.negative? ? -mus_random(val).abs : mus_random(val).abs
2684    end
2685  end
2686end
2687
2688def logn(r, b = 10)
2689  if r <= 0
2690    Snd.raise(:ruby_error, r, "r must be > 0")
2691  end
2692  if b <= 0 or b == 1
2693    Snd.raise(:ruby_error, b, "b must be > 0 and != 1")
2694  end
2695  log(r) / log(b)
2696end
2697
2698def car(v)
2699  v[0]
2700end
2701
2702def cadr(v)
2703  v[1]
2704end
2705
2706def caddr(v)
2707  v[2]
2708end
2709
2710def cdr(v)
2711  v[1..-1]
2712end
2713
2714def verbose_message_string(stack_p, remark, *args)
2715  fmt_remark = format("\n%s", remark)
2716  str = if args.null?
2717          ""
2718        elsif args.length == 1
2719          String(args.car)
2720        else
2721          format(*args)
2722        end
2723  str = if str.split(/\n/).length > 1
2724          str.split(/\n/).join(fmt_remark)
2725        else
2726          format("%s%s", remark, str)
2727        end
2728  if $!
2729    str += format("[%p] %s (%s)",
2730                  rb_error_to_mus_tag, snd_error_to_message, $!.class)
2731    if stack_p
2732      str += format("\n%s%s", remark, $!.backtrace.join(fmt_remark))
2733    end
2734  else
2735    if stack_p and caller(2)
2736      str += format("\n%s%s", remark, caller(2).join(fmt_remark))
2737    end
2738  end
2739  str
2740end
2741
2742def warning(*args)
2743  str = "Warning: " << verbose_message_string($VERBOSE, nil, *args)
2744  if provided? :snd
2745    snd_warning(str)
2746  else
2747    clm_message(str)
2748  end
2749  nil
2750end
2751
2752def die(*args)
2753  message(verbose_message_string(true, nil, *args))
2754  exit(1) unless provided? :snd
2755end
2756
2757def error(*args)
2758  Snd.raise(:runtime_error, verbose_message_string(true, nil, *args))
2759end
2760
2761make_proc_with_setter(:snd_input,
2762                      lambda do property(:snd_input, :snd_listener) end,
2763                      lambda do |val|
2764                        set_property(:snd_input, :snd_listener, val)
2765                      end)
2766
2767# like clm_print(fmt, *args)
2768
2769def clm_message(*args)
2770  msg = if args.null?
2771          ""
2772        elsif args.length == 1
2773          String(args.car)
2774        else
2775          format(*args)
2776        end
2777  if provided? :snd
2778    if provided? :snd_nogui
2779      clm_print("%s\n", msg)
2780    else
2781      clm_print("\n%s", msg)
2782    end
2783    nil
2784  else
2785    $stdout.print(msg, "\n")
2786  end
2787  nil
2788end
2789
2790# like clm_print(*args), in emacs it prepends msg with a comment sign
2791
2792def message(*args)
2793  clm_message(verbose_message_string(false, "# ", *args))
2794end
2795
2796# debug(var1, var2) ==> #<DEBUG: ClassName: value1, ClassName: value2>
2797
2798def debug(*args)
2799  fmt = ""
2800  args.each do |arg|
2801    fmt += format("%s: %p", arg.class, arg)
2802    fmt += ", "
2803  end
2804  message("#<DEBUG: %s>", fmt.chomp(", "))
2805end
2806
2807def debug_trace(*args)
2808  debug(*args)
2809  clm_message(verbose_message_string(true, "# "))
2810end
2811
2812if provided?(:snd) then set_snd_input(:snd) end
2813
2814class Snd
2815  class << Snd
2816    Snd_path = Array.new
2817
2818    if provided? :snd_motif
2819      def add_sound_path(path)
2820        Snd_path.push(path)
2821        add_directory_to_view_files_list(path)
2822      end
2823    else
2824      def add_sound_path(path)
2825        Snd_path.push(path)
2826      end
2827    end
2828
2829    def fullname(fname)
2830      if File.exist?(fname)
2831        fname
2832      else
2833        f = File.basename(fname)
2834        Snd_path.each do |path|
2835          if File.exist?(path + "/" + f)
2836            return path + "/" + f
2837          end
2838        end
2839        Snd.raise(:no_such_file, fname)
2840      end
2841    end
2842
2843    def open_from_path(fname)
2844      snd_file = Snd.fullname(fname)
2845      find_sound(snd_file) or open_sound(snd_file)
2846    end
2847
2848    def find_from_path(fname)
2849      find_sound(Snd.fullname(fname))
2850    end
2851
2852    def load_path
2853      Snd_path
2854    end
2855
2856    def message(*args)
2857      clm_message(verbose_message_string(false, "# ", *args))
2858    end
2859
2860    def display(*args)
2861      msg = if args.null?
2862              ""
2863            elsif args.length == 1
2864              String(args.car)
2865            else
2866              format(*args)
2867            end
2868      if snd_input == :snd
2869        if provided? :snd_nogui
2870          clm_print("%s\n", msg)
2871        else
2872          clm_print("\n%s", msg)
2873        end
2874      else
2875        $stdout.print(msg, "\n")
2876      end
2877      nil
2878    end
2879
2880    def warning(*args)
2881      if provided? :snd
2882        snd_warning(verbose_message_string($VERBOSE, nil, *args))
2883      else
2884        args[0] = "Warning: " + String(args[0])
2885        Snd.display(verbose_message_string($VERBOSE, "# ", *args))
2886      end
2887      nil
2888    end
2889
2890    def die(*args)
2891      Snd.display(verbose_message_string(true, nil, *args))
2892      exit(1) unless provided? :snd
2893    end
2894
2895    def error(*args)
2896      Snd.raise(:runtime_error, verbose_message_string(true, nil, *args))
2897    end
2898
2899    def debug(*args)
2900      if args.null?
2901        Snd.message("#<DEBUG>")
2902      elsif args.length == 1
2903        Snd.message("#<DEBUG: %s>", String(args.car))
2904      else
2905        Snd.message("#<DEBUG: %s>", format(*args))
2906      end
2907    end
2908
2909    def debug_trace(*args)
2910      Snd.debug(*args)
2911      Snd.display(verbose_message_string(true, "# "))
2912    end
2913
2914    def sounds
2915      (Kernel.sounds or []).reverse
2916    end
2917
2918    def regions
2919      (Kernel.regions or []).reverse
2920    end
2921
2922    def marks(snd = false, chn = false)
2923      (Kernel.marks(snd, chn) or [])
2924    end
2925
2926    def snd(sn = false)
2927      sn or selected_sound or Snd.sounds.car
2928    end
2929
2930    def chn(ch = false)
2931      ch or selected_channel or 0
2932    end
2933
2934    def catch(tag = :all, retval = :undefined)
2935      old_debug = $DEBUG
2936      $DEBUG = false
2937      val = Kernel.catch(tag) do yield end
2938      # catch/throw part
2939      # [:snd_throw, tag, get_func_name(2), *rest]
2940      if array?(val) and val.car == :snd_throw
2941        if retval != :undefined
2942          if proc?(retval)
2943            retval.call(val.cdr)
2944          else
2945            [retval]
2946          end
2947        else
2948          val.cdr
2949        end
2950      else
2951        [val]
2952      end
2953      # ruby1.9/ChangeLog
2954      # Thu Feb  2 16:01:24 2006  Yukihiro Matsumoto  <matz@ruby-lang.org>
2955      # * error.c (Init_Exception): change NameError to direct subclass of
2956      #   Exception so that default rescue do not handle it silently.
2957    rescue Interrupt, ScriptError, NameError, StandardError
2958      mus_tag = rb_error_to_mus_tag
2959      # raise part
2960      if (tag == mus_tag) or (tag == :all)
2961        if retval != :undefined
2962          if proc?(retval)
2963            retval.call(mus_tag, snd_error_to_message)
2964          else
2965            [retval]
2966          end
2967        else
2968          [mus_tag, snd_error_to_message]
2969        end
2970      else
2971        Kernel.raise
2972      end
2973    ensure
2974      $DEBUG = old_debug
2975    end
2976
2977    def throw(tag, *rest)
2978      Kernel.throw(tag, [:snd_throw, tag, get_func_name(2), *rest])
2979    end
2980
2981    def raise(tag, *rest)
2982      msg = format("%s in %s:", tag, get_func_name(2))
2983      rest.each do |s| msg += format(" %s,", s) end
2984      msg.chomp!(",")
2985      exception = case tag
2986                  when :out_of_range
2987                    RangeError
2988                  when :wrong_type_arg
2989                    TypeError
2990                  when *Snd_error_tags
2991                    StandardError
2992                  else
2993                    Ruby_exceptions[tag] or RuntimeError
2994                  end
2995      Kernel.raise(exception, msg, caller(1))
2996    end
2997  end
2998end
2999
3000# almost all StandardError
3001Snd_error_tags = [# clm2xen.c
3002                  :mus_error,
3003                  :no_such_method,
3004                  :wrong_type_arg, # TypeError
3005                  # snd-0.h
3006                  :no_such_envelope,
3007                  :no_such_sample,
3008                  :no_such_edit,
3009                  :cannot_save,
3010                  :cant_update_file,
3011                  # snd-chn.c
3012                  :cant_open_file,
3013                  # snd-dac.c
3014                  :bad_format,
3015                  :no_such_player,
3016                  :arg_error,
3017                  # snd-draw.c
3018                  :no_such_widget,
3019                  :no_such_graphics_context,
3020                  :no_such_axis,
3021                  :bad_length,
3022                  # snd-edits.c
3023                  :no_such_direction,
3024                  :no_such_region,
3025                  :no_such_auto_delete_choice,
3026                  # snd-env.c
3027                  :env_error,
3028                  # snd-error.c
3029                  :snd_error,
3030                  # snd-gxcolormaps.c
3031                  :no_such_colormap,
3032                  :colormap_error,
3033                  # snd-key.c
3034                  :no_such_key,
3035                  # snd-ladspa.c
3036                  :no_such_plugin,
3037                  :plugin_error,
3038                  # snd-marks.c
3039                  :no_such_mark,
3040                  # snd-menu.c
3041                  :no_such_menu,
3042                  # snd-mix.c
3043                  :no_such_mix,
3044                  # snd-print.c
3045                  :cannot_print,
3046                  # snd-region.c
3047                  :io_error,
3048                  # run.c
3049                  :wrong_number_of_args,
3050                  :cannot_parse,
3051                  # snd-snd.c
3052                  :no_such_sound,
3053                  :not_a_sound_file,
3054                  :cannot_apply_controls,
3055                  :bad_size,
3056                  :snd_internal_error,
3057                  # snd-xen.c
3058                  :no_active_selection,
3059                  :bad_arity,
3060                  # snd-xmain.c
3061                  :xt_error,
3062                  # snd-xchn.c
3063                  :no_such_color,
3064                  # snd.c
3065                  :snd_top_level,
3066                  :gsl_error,
3067                  # sndlib2xen.h
3068                  :out_of_range,
3069                  :no_such_channel,
3070                  :no_such_file,
3071                  :bad_type,
3072                  :no_data,
3073                  :bad_header,
3074                  # xm.c
3075                  :no_such_resource]
3076
3077def rb_error_to_mus_tag
3078  # to_s and string error-names intentional here
3079  # otherwise e.g. NameError goes to case StandardError!
3080  case $!.class.to_s
3081  when "StandardError"
3082    $!.message.split(/[: ]/).first.downcase.intern
3083  when "RangeError"
3084    :out_of_range
3085  when "TypeError"
3086    :wrong_type_arg
3087  when "ArgumentError"
3088    :wrong_number_of_args
3089  else
3090    # converts ruby exceptions to symbols: NoMethodError ==> :no_method_error
3091    $!.class.to_s.gsub(/([A-Z])/) do |c|
3092      "_" + c.tr("A-Z", "a-z")
3093    end[1..-1].intern
3094  end
3095end
3096
3097def snd_error_to_message
3098  $!.message.split(/\n/).first.sub(/^.*: /, "")
3099end
3100
3101add_help(:snd_catch,
3102         "snd_catch(tag=:all, retval=:undefined])  \
3103Catchs snd_throw and exceptions and \
3104returns body's last value wrapped in an array if all goes well.  \
3105If a snd_throw tag meets snd_catch's, returns an array with the tag name, \
3106the function name from where was thrown \
3107and optional arguments given to snd_throw.  \
3108If an exception was risen and the exception name meets tag name, \
3109returns an array with tag name and the exception message, \
3110otherwise reraises exception.  \
3111If retval is given and tag matches exception or snd_throw tag, \
3112returns retval.  \
3113If retval is a procedure, calls retval with tag name and message.
3114
3115res = snd_catch do 10 + 2 end
3116puts res ==> [12]
3117
3118res = Snd.catch(:no_such_file) do
3119  open_sound(\"unknown-file.snd\")
3120end
3121puts res ==> [:no_such_file, \
3122\"open_sound: no_such_file: Unknown_file.snd No such file or directory\"]
3123
3124res = Snd.catch(:finish) do
3125  10.times do |i|
3126    if i == 8 then snd_throw(:finish, i) end
3127  end
3128end
3129puts res ==> [:finish, \"top_level\", 8]
3130
3131res = Snd.catch(:all, lambda do |tag, msg| Snd.display([tag, msg]) end) do
3132  set_listener_prompt(17)
3133end
3134==> [:wrong_type_arg, \
3135\"set_listener-prompt: wrong type arg 0, 17, wanted a string\"]
3136puts res ==> nil
3137
3138The lambda function handles the error in the last case.")
3139def snd_catch(tag = :all, retval = :undefined, &body)
3140  Snd.catch(tag, retval, &body)
3141end
3142
3143add_help(:snd_throw,
3144         "snd_throw(tag, *rest)  \
3145Jumps to the corresponding snd_catch(TAG) and returns an array \
3146with TAG, function name and possible *REST strings or values.")
3147def snd_throw(tag, *rest)
3148  Snd.throw(tag, *rest)
3149end
3150
3151class Break < StandardError
3152end
3153
3154Ruby_exceptions = {
3155  :script_error          => ScriptError,
3156  :load_error            => LoadError,
3157  :name_error            => NameError,
3158  :not_implemented_error => NotImplementedError,
3159  :syntax_error          => SyntaxError,
3160  :interrupt             => Interrupt,
3161  :system_exit           => SystemExit,
3162  :standard_error        => StandardError,
3163  :arg_error             => ArgumentError,
3164  :float_domain_error    => FloatDomainError,
3165  :index_error           => IndexError,
3166  :io_error              => IOError,
3167  :eof_error             => EOFError,
3168  :local_jump_error      => LocalJumpError,
3169  :no_memory_error       => NoMemoryError,
3170  :range_error           => RangeError,
3171  :regexp_error          => RegexpError,
3172  :runtime_error         => RuntimeError,
3173  :security_error        => SecurityError,
3174  :system_call_error     => SystemCallError,
3175  :system_stack_error    => SystemStackError,
3176  :thread_error          => ThreadError,
3177  :type_error            => TypeError,
3178  :zero_division_error   => ZeroDivisionError,
3179  :break                 => Break}
3180
3181add_help(:snd_raise,
3182         "snd_raise(tag, *rest)  \
3183Raises an exception TAG with an error message \
3184containing function name, TAG and possible *REST strings or values.  \
3185TAG is a symbol, \
3186a Ruby exception looks like :local_jump_error instead of LocalJumpError, \
3187a Snd error tag looks like :no_such_sound.")
3188def snd_raise(tag, *rest)
3189  Snd.raise(tag, *rest)
3190end
3191
3192def srate
3193  mus_srate
3194end unless defined? srate
3195
3196# general purpose loop
3197
3198add_help(:gloop,
3199         "gloop(*args) { |args| ... }
3200 :step   = 1
3201 :before = nil (thunk)
3202 :after  = nil (thunk)
3203
3204args[0]: Range    (each)
3205         Hash(s)  (each)
3206         Array(s) (each_with_index) [args.last == Integer ==> step]
3207         Integer  (times)
3208         Integer  [args[1] == :step ==> step]
3209
3210A general purpose loop, handling Range, Hash, Array, Vec, Vct, Integer,
3211with optional step.  Returns the result of body as array like map.
3212
3213Examples:
3214  Range
3215    gloop(0..3) do |i| puts i end
3216  Hash               (loops over all Hashs consecutively)
3217    gloop({1 => :a, 2 => :b}, {11 => :aa => 22 => :bb}) do |k, v|
3218      print('key: ', k, ' value: ', v)
3219      puts
3220    end
3221  Array, Vec, Vct
3222    gloop([0, 1]) do |x, i|
3223      print(i, ': ', x)
3224      puts end
3225  Arrays with step   (mixes all Arrays)
3226    gloop([0, 1, 2, 3], [:a, :b, :c, :d], [55, 66, 77, 88, 99], 2) do |x, i|
3227      print(i, ': ', x.inspect)
3228      puts
3229    end
3230  Numeric (like Integer#times)
3231    gloop(3) do |i| puts i end
3232  Numeric with step (like Integer#step)
3233    gloop(6, 2) do |i| puts i end
3234  a simple body call
3235    gloop do puts 'empty' end")
3236def gloop(*args, &body)
3237  step   = get_shift_args(args, :step, 1)
3238  before = get_shift_args(args, :before)
3239  after  = get_shift_args(args, :after)
3240  do_extra = lambda do |thunk| thunk?(thunk) ? thunk.call : snd_func(thunk) end
3241  result = []
3242  case args[0]
3243  when Range
3244    args[0].step(step) do |i|
3245      do_extra.call(before) if before
3246      result << body.call(i)
3247      do_extra.call(after) if after
3248    end
3249  when Array, Vec, Vct
3250    lmax = args.map do |x| x.length end.max
3251    0.step(lmax - 1, step.round) do |i|
3252      do_extra.call(before) if before
3253      result << body.call(*args.map do |x| x[i] end << i)
3254      do_extra.call(after) if after
3255    end
3256  when Hash
3257    args.each do |x| x.each do |k, v|
3258        do_extra.call(before) if before
3259        result << body.call(k, v)
3260        do_extra.call(after) if after
3261      end
3262    end
3263  when Numeric
3264    0.step(args[0], number?(args[1]) ? args[1] : step) do |i|
3265      do_extra.call(before) if before
3266      result << body.call(i)
3267      do_extra.call(after) if after
3268    end
3269  else
3270    do_extra.call(before) if before
3271    result << body.call
3272    do_extra.call(after) if after
3273  end
3274  result
3275end
3276
3277# get_args(args, key, default = nil)
3278#
3279# returns value, whether DEFAULT or value of KEY found in ARGS
3280
3281def get_args(args, key, default = nil)
3282  if args.member?(key)
3283    arg = args[args.index(key) + 1]
3284    default = arg.nil? ? default : arg
3285  end
3286  default
3287end
3288
3289def get_shift_args(args, key, default = nil)
3290  default = get_args(args, key, default)
3291  if args.member?(key)
3292    i = args.index(key)
3293    2.times do args.delete_at(i) end
3294  end
3295  default
3296end
3297
3298# var = get_class_or_key(args, Klass, :key, default = nil)
3299
3300def get_class_or_key(args, klass, key, default = nil)
3301  if (not symbol?(args.first)) and args.first.kind_of?(klass)
3302    args.shift
3303  else
3304    get_shift_args(args, key, default)
3305  end
3306end
3307
3308# var1, var2, var3, var4 = optkey(args, [:key, default],
3309#                                       [:number, 1],
3310#                                       [Array, :list, [0, 1, 2, 3]],
3311#                                       :var_w/o_default_value)
3312#
3313# Key-default pairs must be included in brackets while keys alone can
3314# be included in brackets or not, see last key
3315# ":var_w/o_default_value" above.  If no default value is specified,
3316# nil is used.
3317
3318def optkey(args, *rest)
3319  args_1 = args.dup
3320  bind = binding?(rest.car) ? rest.shift : nil
3321  @locals = nil
3322  vals = rest.map do |keys|
3323    val = if array?(keys)
3324            case keys.length
3325            when 1
3326              name = keys.car.to_s
3327              get_class_or_key(args_1, Object, keys.car, nil)
3328            when 2
3329              name = keys.car.to_s
3330              get_class_or_key(args_1, keys.cadr.class, *keys)
3331            when 3
3332              name = keys.cadr.to_s
3333              get_class_or_key(args_1, *keys)
3334            else
3335              assert_type(keys.length.between?(1, 3), keys, 1,
3336                          "an array of one to three \
3337elements [class, :key, default]")
3338            end
3339          else
3340            name = keys.to_s
3341            get_class_or_key(args_1, Object, keys, nil)
3342          end
3343    @locals = val
3344    eval("#{name} = @locals", bind)
3345    val
3346  end
3347  remove_instance_variable("@locals")
3348  if vals.length == 1
3349    vals.first
3350  else
3351    vals
3352  end
3353end
3354
3355add_help(:load_init_file,
3356         "load_init_file(file)  \
3357Returns false if FILE doesn't exist, otherwise loads it.  \
3358FILE may reside in current working dir or in $HOME dir.")
3359def load_init_file(file)
3360  if File.exist?(file)
3361    Snd.catch do load(file) end
3362  elsif File.exist?(f = ENV["HOME"] + "/" + file)
3363    Snd.catch do load(f) end
3364  else
3365    false
3366  end
3367end
3368
3369let(-1) do |count|
3370  # see rotate_phase(func, snd, chn) in dsp.rb
3371  # it's necessary to produce a uniq method name
3372  make_proc_with_setter(:edit_list_proc_counter,
3373                        lambda do count end,
3374                        lambda do count += 1 end)
3375end
3376
3377# clm.rb ends here
3378