声音动力模型与代码

发布时间:2024年01月04日

这个模型展示了乌龟可以制作有趣和多样的声音,或者如果你喜欢的话,音乐。它利用一些简单的物理学原理制作了可以扭转、旋转、转动、抽搐和弹跳的“机器”。当机器的一部分接触到墙壁、天花板或地板时,它会发出声音。声音的音调取决于触碰的位置。

你可以从一个标准的机器开始,或者随机生成一个。你可以通过改变每个部分的特性来改变和构建机器。你可以坐下来让机器自己演奏,也可以使用鼠标移动它们来控制声音。

如何工作

这些机器由杠杆组成。杠杆可以是不同的大小,并受到重力(与其大小成比例)和摩擦的影响。

每个杠杆都有一个或两个“钩”来连接它与相邻的杠杆。每个杠杆都会努力移动和旋转,以保持其钩连接(或至少朝向)其邻居的钩。

一些杠杆有额外的约束。一个杠杆可以固定在位置上,所以它不能移动。它也可以旋转,就好像由电机驱动一样。

规则并不完美;例如,有时杠杆会分开。尽管如此,行为通常都是令人惊讶地逼真,足以产生有趣的运动,从而产生有趣的声音。

如何使用

按下SETUP...按钮之一来创建一个机器。如果你想要,首先改变NUM-LEVERS来获取更多或更少的杠杆。

按下GO来启动机器。你应该开始听到声音,尽管如果你的机器从未接触到墙壁(或天花板或地板),你将听不到任何声音。

你可以使用鼠标通过点击来选择一个杠杆,或者通过拖动来移动一个杠杆。被选中的杠杆周围有一个圆圈。

一旦你选中了一个杠杆,左侧的各种控件让你改变该杠杆的属性。这里不会详细描述它们;玩一玩,亲自看看它们的作用。

一些影响整个系统的参数位于左下角和右侧。F是摩擦力,G是重力。还有旋转的控件。

你可以使用INSTRUMENT滑块来选择乐器,让杠杆演奏不同的乐器。

如果你制作了一个特别喜欢的机器,你可以使用文件菜单上的Export World和Import World来保存并重新加载它。

注意事项

杠杆遵循的简单规则产生了一些看起来非常逼真的行为。

有些机器什么也不做。其他机器做简单、重复的运动。还有一些则非常混乱。

代码

extensions [sound]

globals [
  selected    ;; lever that is currently selected
  dragged     ;; lever that is currently being dragged
]

breed [levers lever]
levers-own [
  neighbor1 neighbor2  ;; each holds an adjacent lever (or nobody)
  fixed?               ;; if true, lever only turns, never changes position
  spin                 ;; -1, 0, or 1
  len                  ;; this times SCALE slider equals size
  new-xcor new-ycor    ;; next values for xcor and ycor
  new-heading          ;; next value for heading
  xvel yvel            ;; x and y velocities
]

;;;
;;; SETUP PROCEDURES
;;;

to setup-begin
  clear-all
  set-default-shape levers "lever"
  create-ordered-levers num-levers [
    set heading 180
    set new-xcor 0
    set ycor ((who / num-levers) * world-height + min-pycor ) * -0.8
    set new-ycor ycor
    set fixed? false
    set len 0.5
    set neighbor1 turtle (who - 1)
    set neighbor2 turtle (who + 1)
  ]
  ask lever 0 [ set fixed? true ]
end

to setup-dangle
  setup-begin
  ask turtle (num-levers - 4) [
    set len len * 2
    set spin 1
  ]
  setup-finish
end

to setup-finish
  set selected last sort levers  ;; select last lever
  ask levers [ lever-display ]
  reset-ticks
end

to setup-chaos-tentacle
  setup-begin
  ask levers
    [ set len (num-levers - who) * 0.1
      set spin (who mod 2) * 2 - 1
    ]
  ask first sort levers
    [ set new-xcor 0
      set new-ycor 0
      setxy 0 0
      set fixed? true
    ]
  setup-finish
end

to setup-crazy-machine
  setup-begin
  ask levers
    [ ; choose random location, in the inner area of the world
      set new-xcor (random-float 1.6 - 0.8) * max-pxcor
      set new-ycor (random-float 1.6 - 0.8) * max-pycor
      setxy new-xcor new-ycor
      set fixed? (random 5 = 0)
      set spin one-of [-1 0 1]
      set len precision (0.5 + 0.5 * random 4) 1
      lever-display
    ]
  setup-finish
end

;;;
;;; RUNTIME PROCEDURES
;;;

to go
  ask levers [ monitor-mouse ]
  ask levers [ lever! ]
  ask levers [ lever-display ]
  tick
end

to lever!
  ifelse self = dragged
  [ ; if being dragged, then go there the mouse tells you
    set new-xcor mouse-xcor
    set new-ycor mouse-ycor
  ]
  [
    if not fixed?
    [ set xvel (xvel * f) + ((n1x2 - x1) + (n2x1 - x2)) * 0.5
      set yvel (yvel * f) + ((n1y2 - y1) + (n2y1 - y2)) * 0.5
      set yvel yvel - g * len
      set new-xcor xcor + xvel
      set new-ycor ycor + yvel
      if abs new-xcor > max-pxcor [ set xvel xvel * -0.99
                                    set new-xcor max-pxcor * sign new-xcor + xvel
                                    bonk! ycor ]
      if abs new-ycor > max-pycor [ set yvel yvel * -0.99
                                    set new-ycor max-pycor * sign new-ycor + yvel
                                    bonk! xcor ]
    ]
  ]
  ; calculate new heading of lever
  ; if node2 of neighbor1 is overlapping center, keep same heading
  ; otherwise, find heading to hook 2 of neighbor1
  let a 180 + heading
  let b heading
  if distancexy n1x2 n1y2 > 0
    [ set a 180 + towardsxy n1x2 n1y2 ]
  ; likewise hook 1 of neighbor2
  if distancexy n2x1 n2y1 > 0
    [ set b towardsxy n2x1 n2y1 ]
  ; use trig to take mean of a and b
  set new-heading atan (sin a + sin b)
                       (cos a + cos b)
                  + spin * spin-speed
end

to lever-display
  setxy new-xcor new-ycor
  set heading new-heading
  set size 2 * scale * len
  let -s ""
  ifelse self = selected
  [ set -s "-s"
    let new-label (word "selected: " who " - " (precision len 2) " ")
    ask patch max-pxcor max-pycor [ set plabel new-label ]
    set label (word who " - " (precision len 2) " "  " ---->     ")
  ]
  [ set label "" ]
  set shape (word "lever"
                  ifelse-value fixed? ["-f"] [""]
                  item (spin + 1) ["-ws" "" "-cw"]
                  -s)
end

;; lever procedures; these report the x and y coordinates
;; of this lever's hooks
to-report x1 report xcor - dx * scale * len end
to-report y1 report ycor - dy * scale * len end
to-report x2 report xcor + dx * scale * len end
to-report y2 report ycor + dy * scale * len end

;; lever procedures; these report the x and y coordinates
;; of our neighbor's hooks. if no neighbor, use own hook.
to-report n1x1 ifelse neighbor1 = nobody [ report x2 ] [ report [x1] of neighbor1 ] end
to-report n1y1 ifelse neighbor1 = nobody [ report y2 ] [ report [y1] of neighbor1 ] end
to-report n1x2 ifelse neighbor1 = nobody [ report x1 ] [ report [x2] of neighbor1 ] end
to-report n1y2 ifelse neighbor1 = nobody [ report y1 ] [ report [y2] of neighbor1 ] end
to-report n2x1 ifelse neighbor2 = nobody [ report x2 ] [ report [x1] of neighbor2 ] end
to-report n2y1 ifelse neighbor2 = nobody [ report y2 ] [ report [y1] of neighbor2 ] end
to-report n2x2 ifelse neighbor2 = nobody [ report x1 ] [ report [x2] of neighbor2 ] end
to-report n2y2 ifelse neighbor2 = nobody [ report y1 ] [ report [y2] of neighbor2 ] end

to-report sign [a]
  ifelse a = 0
    [ report 0 ]
    [ ifelse a < 0 [ report -1 ]
                   [ report 1 ] ]
end

;;;
;;; SELECTION & DRAGGING PROCEDURES
;;;

to monitor-mouse
  let mouse-here? abs (mouse-xcor - xcor) < scale / 2 and
                  abs (mouse-ycor - ycor) < scale / 2
  ifelse mouse-here?
  [ if color != white [ set color white ] ]
  [ if color = white  [ set color item (who mod 14) base-colors ] ]
  ifelse mouse-down?
  [ if dragged = nobody and mouse-here?
    [ set dragged self
      set selected self
    ]
  ]
  [ set dragged nobody ]
end

to select-lever [which-lever]
  let new lever (which-lever + [who] of selected)
  if new != nobody [ set selected new ]
end

;;;
;;; SOUND PROCEDURES
;;;

to bonk! [coordinate]
  sound:play-note my-instrument (pitch coordinate) 90 0.05
end

to-report pitch [coordinate]  ;; lever procedure
  report 16 + round (96 * (coordinate + max-pxcor) / world-width)
end

to-report my-instrument  ;; lever procedure
  report item ((who + instrument) mod length sound:instruments)
              sound:instruments
end


; Copyright 2005 Uri Wilensky. Includes code by James P. Steiner.
; See Info tab for full copyright and license.

尝试

尝试所有不同的SETUP按钮。

尝试左侧的所有杠杆控件。

探索右侧参数的影响。

看看能否制作一些有些重复但也有些不可预测和混乱的机器。有时这些会产生最令人愉悦的“音乐”。

使用命令中心,告诉乌龟放下它们的笔(使用pen-down命令,简写为pd)。这会产生一些令人愉悦的图案。使用clear-drawing(简写为cd)开始一幅新的图画。

扩展模型

相同的基本物理引擎可以用来产生声音,有无限的可能性。杠杆可以:

  • 演奏不同的乐器,而不是都是相同的乐器。
  • 除了音调外,还能发出打击乐声音。
  • 即使不碰到墙壁也能发出声音
  • 发出取决于它们特性的声音

等等。

你能让模型的声音变得多么“正常”和“音乐化”?目前模型的规则并不是基于音阶或音调的;通过更仔细地选择音调,你也许可以制作出更少奇怪、更像人类创作的音乐。你也可以尝试通过将声音与规律的节拍相协调,产生更规律的节奏。

另一方面,你也可以采取相反的方法,看看你能让声音变得多么狂野、不同和不寻常。制作一些你以前从未听过的东西!

文章来源:https://blog.csdn.net/weixin_44956825/article/details/135353159
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。