bess1.rb 5.31 KB
Newer Older
1
# bess1.rb -- examples from clm-2/rt.lisp and clm-2/bess5.cl
2

3 4 5
# Translator: Michael Scholz <mi-scholz@users.sourceforge.net>
# Created: 2002/09/15 19:11:12
# Changed: 2018/01/11 20:05:09
6
#
7 8 9
# snd-ruby-xm -batch bess1.rb -e agn
# or
# snd-ruby-xm bess1.rb
10

11 12 13
require "snd-xm"
require "v"
require "env"
14

15 16 17 18 19 20
class FM_Forever2
  FM2name = "FM Forever!"
  FM2info = "\
bess1.rb provides mono real time output to DAC.
Frequency, amplitude, FM index, and tempo
can be controlled via slider."
21

22 23 24 25 26 27 28 29 30 31
  def initialize
    @tempo = 0.1
    @freq = 1.0
    @amp = 1.0
    @index = 1.0
    @low_tempo = 0.05
    @high_tempo = 0.5
    @low_freq = 0.1
    @high_freq = 4.0
    @high_index = 2.0
32
  end
33 34 35 36 37 38 39 40 41 42 43 44 45
  
  def start_dac(&body)
    set_playing(false)
    freq = @freq
    amp = @amp
    tempo = @tempo
    index = @index
    s1, s2, s3, s4 = false
    reset_cb = lambda do |w, c, i|
      set_scale_value(s1.scale, @freq = freq, 100.0)
      set_scale_value(s2.scale, @amp = amp, 100.0)
      set_scale_value(s3.scale, @tempo = tempo, 100.0)
      set_scale_value(s4.scale, @index = index, 100.0)
46
    end
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
    help_cb = lambda do |w, c, i| info_dialog(FM2name, FM2info) end
    #
    # -batch sets XtSetMappedWhenManaged(shell, 0)
    # The "Quit Snd" button is only realized if -batch was given.
    #
    if get_xtvalue(main_widgets[Top_level_shell], RXmNmappedWhenManaged)
      clear_cb = false
    else
      clear_cb = lambda do |w, c, i| exit(0) end
    end
    d = make_dialog(FM2name,
                    :reset_cb, reset_cb,
                    :clear_cb, clear_cb,
                    :help_cb, help_cb) do |w, c, i|
      if set_playing(!playing)
        play(body)
        d.doit_string("Pause")
64
      else
65
        d.doit_string("Play")
66 67
      end
    end
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    name = "carrier freqency"
    s1 = d.add_slider(name, @low_freq, freq, @high_freq, 100) do |w, c, i|
      @freq = get_scale_value(w, i, 100.0)
    end
    name = "amplitude"
    s2 = d.add_slider(name, 0, amp, 1, 100) do |w, c, i|
      @amp = get_scale_value(w, i, 100.0)
    end
    name = "tempo"
    s3 = d.add_slider(name, @low_tempo, tempo, @high_tempo, 100) do |w, c, i|
      @tempo = get_scale_value(w, i, 100.0)
    end
    name = "fm index"
    s4 = d.add_slider(name, 0, index, @high_index, 100) do |w, c, i|
      @index = get_scale_value(w, i, 100.0)
    end
    if clear_cb
      d.clear_string("Quit Snd")
86
    end
87 88 89
    d.doit_string("Play")
    set_sensitive(d.okay_button, true)
    RXtManageChild(d.dialog)
90 91
  end

92 93 94 95 96 97
  # see clm-2/bess5.cl
  def make_agn
    lim = 256
    mode = [0, 0, 2, 4, 11, 11, 5, 6, 7, 9, 2, 0, 0]
    @octs = Array.new(lim + 1) do |i|
      4 + 2 * rbell(rbm_random(1.0)).floor
98
    end
99 100 101 102 103 104 105
    @pits = Array.new(lim + 1) do |i|
      mode[(12.0 * rbm_random(1.0)).floor]
    end
    @rhys = Array.new(lim + 1) do |i|
      4 + 6 * rbm_random(1.0).floor
    end
    @begs = Array.new(lim + 1) do |i|
106
      if rbm_random(1.0) < 0.9
107
        4 + 2 * rbm_random(1.0).floor
108
      else
109
        6 * rbm_random(4.0).floor
110 111
      end
    end
112 113
    @amps = Array.new(lim + 1) do |i|
      1 + 8 * rbell(rbm_random(1.0)).floor
114
    end
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    @cellctr = 0
    @cellsiz = 1
    @cellbeg = 0
    @whichway = 1
    @beg = 0.0
    @len = 0
    @v = lambda do |y| 0.0 end
  end

  def agn
    if @len > 1
      @len -= 1
    else
      bg = @beg
      @beg += [0.025, @tempo * (0.95 + rbm_random(0.1)) * @begs[@cellctr]].max
      dur = [0.025, @tempo * (0.85 + rbm_random(0.1)) * @rhys[@cellctr]].max
      freq = @freq * 16.351 * tune(@pits[@cellctr]) * 2.0 ** @octs[@cellctr]
      amp = @amp * [0.003, @amps[@cellctr] * 0.01].max
      ind = @index * rbm_random(1.0) * 3.0
      @len = seconds2samples(dur)
      @v = make_fm_violin(bg, dur, freq, amp, :fm_index, ind)
      @cellctr += 1
      if @cellctr > (@cellsiz + @cellbeg)
        @cellbeg += 1
        if rbm_random(1.0) > 0.5
          @cellsiz += @whichway
141
        end
142 143 144 145 146 147
        if @cellsiz > 10 and rbm_random(1.0) > 0.99
          @whichway = -2
        elsif @cellsiz > 6 and rbm_random(1.0) > 0.999
          @whichway = -1
        elsif @cellsiz < 4
          @whichway = 1
148
        end
149 150
        @beg += rbm_random(1.0)
        @cellctr = @cellbeg
151 152
      end
    end
153
    @v.call(0)
154 155
  end

156 157 158
  private
  def rbm_random(r)
    mus_random(r).abs
159
  end
160 161 162 163 164
    
  def tune(r)
    [1.0, 256.0 / 243, 9.0 / 8, 32.0 / 27, 81.0 / 64,
     4.0 / 3, 1024.0 / 729, 3.0 / 2, 128.0 / 81, 27.0 / 16,
     16.0 / 9, 243.0 / 128, 2.0].at(r % 12) * 2.0 ** r.divmod(12).first
165 166
  end
  
167 168
  def rbell(x)
    envelope_interp(x * 100.0, [0, 0.0, 10, 0.25, 90, 1.0, 100, 1.0])
169
  end
170
end
171

172 173 174 175 176
def agn
  f = FM_Forever2.new
  f.make_agn
  f.start_dac do f.agn end
end
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
# see clm-2/rt.lisp
def rt_test(time = 30)
  lim = 256
  mode = [0, 12, 2, 4, 14, 4, 5, 5, 0, 7, 7, 11, 11]
  pits = Array.new(lim + 1) do
    mus_random(12.0).abs.floor
  end
  begs = Array.new(lim + 1) do
    1 + mus_random(3.0).abs.floor
  end
  with_dac do
    cellbeg = 0
    cellsiz = 6
    cellctr = 0
    mytempo = 0.3
    beg = 0.0
    while beg < time and cellctr < lim
      dur = mytempo * begs[cellctr + 1]
      beg += dur
      frq = 16.351 * 16.0 * 2.0 ** (mode[pits[cellctr]] / 12.0)
      cellctr += 1
      if cellctr > (cellsiz + cellbeg)
        cellbeg += 1 if mus_random(1.0).abs > 0.5
        cellsiz += 1 if mus_random(1.0).abs > 0.5
        cellctr = cellbeg
203
      end
204
      fm_violin(beg, dur, frq, 0.25)
205 206 207 208
    end
  end
end

209 210
# agn
# rt_test
211 212

# bess1.rb ends here