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