2016-01-22 8 views
2

Я написал эту программу в Racket, которая генерирует 32 случайных ноты из набора из 15 нот, а затем воспроизводит их. Продолжительность каждой ноты должна составлять 0,25 секунды. Когда я бегу, это дает латентность, которая заставляет звук мелодии отключиться.Racket latency с rsound

Как он может работать нормально?

Это программа:

#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)) 

ответ

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))) 
+1

Спасибо! Но теперь у меня другая проблема. Я преобразовал его в исполняемый файл, и он завершает работу до того, как будет запущен цикл for. Что я могу сделать для всех заметок, которые будут воспроизводиться? –

+1

Что происходит, скорее всего, что make-pstream происходит в другом потоке, и основной поток не ждет его завершения до его выхода. Вероятно, самый простой способ исправить это - добавить «pstream-queue-callback» в конце вашей песни, которая сигнализирует о завершении программы. Я отвечу на этот вопрос. –

+0

(Кроме того, вы могли бы просто «поспать», но это может закончиться до того, как ваша программа закончит игру. –