我在Racket中编写了这个程序,它从一组15个音符中生成32个随机音符,然后播放它们。每个音符的持续时间应为0.25秒。当我运行它时会产生延迟,这使得旋律听起来很不错。
它如何正常运行?
这是该计划:
#lang racket
(provide (all-defined-out))
(require rsound)
(require rsound/piano-tones)
(define-syntax-rule (note y x)
(begin
(play (piano-tone y))
(sleep x)
(stop)))
(define (random-element list)
(list-ref list (random (length list))))
(define-syntax-rule (random-note)
(note (random-element '(40 42 43 45 47 48 50 52 54 55 57 59 60 62 64)) 0.25))
(for ([i 32])
(random-note))
答案 0 :(得分:4)
首先,来自piano-tone
的注释实际上不会被截断,尽管您可以使用clip
函数执行此操作。
其次,您的问题在于您依赖计算机执行代码的速度,这本质上是不一致的。
更好的方法是使用make-pstream
。并将笔记排队以便稍后运行。这样,当音符播放时,基于你的处理器就不会有差距。
(另外,当您使用它们时,可以使用旁注in-range
来加速循环。)
把它们放在一起(使用剪辑剪掉你的音符),你的程序看起来就像这样(为了简洁,我使用了幻数,显然你想要通过实际的计算来获得0.25秒):
#lang racket
(require rsound
rsound/piano-tones)
(define stream (make-pstream))
(define count 10000)
(define (note y x)
(pstream-queue stream (clip (piano-tone y) 0 10000) count)
(set! count (+ count x)))
(define (random-element list)
(list-ref list (random (length list))))
(define (random-note)
(note (random-element '(40 42 43 45 47 48 50 52 54 55 57 59 60 62 64)) 10000))
(for ([i (in-range 32)])
(random-note))
最后,如果要将这些全部包装到单个可执行文件中,程序将在队列完成之前终止。因此,在程序结束时进行一个等待队列完成的繁忙循环(使用pstream-queue-callback
)。
将此添加到程序的末尾:
(define ok-to-exit? #f)
(pstream-queue-callback stream (lambda () (set! ok-to-exit? #t)) count)
(let loop ()
(sleep 0.1)
(unless ok-to-exit?
(loop)))