Как мне создать этот тиковый звук в JavaScript? - PullRequest
6 голосов
/ 21 июня 2019

На a.bestmetronome.com у них есть метроном, который генерирует тики на основе шума.

Однако я не мог понять, как генерируются «галочки». Хотя я смог разработать генератор тиков из Audacity:

;; Metronome tick by Steve Daulton.
(defun metronome-tick (hz peak)
    (let* ((ln 300)
        (sig-array (make-array ln))
        (x 1))
    ;; generate some 'predictable' white noise
    (dotimes (i ln)
        (setf x (rem (* 479 x) 997))
        (setf (aref sig-array i) (- (/ x 500.0) 1)))
        (setf sig (sim (s-rest-abs 0.2)
            (snd-from-array 0 44100 sig-array)))
    (setf sig
        (mult (abs-env (pwev 10 (/ ln 44100.0) 2 1 0))
            (highpass8  (lowpass2 sig (* 2 hz) 6)
                        hz)))
    (let ((gain (/ (peak sig 300))))
    ; The '1.11' factor makes up for gain reduction in 'resample'
    (mult (abs-env (pwlv 1.11 0.02 1.11 0.05 0 ))
        (jcrev (mult peak gain sig) 0.01 0.1)))))

;; Single tick generator:
(defun get-metronome-tick (hz gain)
    (resample
        (sound-srate-abs 44100 (metronome-tick hz gain))
        *sound-srate*))

А вот тик, который у меня сейчас есть, внутри функции, которая его генерирует:

function scheduleNote(beatNumber, time)
{
    // push the note on the queue, even if we're not playing.
    notesInQueue.push({
        note: beatNumber, 
        time: time
    });

    if (beatNumber % 4 === 0)          // beat 0 == high pitche
    {
        var fader = actx.createGain();
        fader.gain.value = 2;
        fader.connect(distor);

        var oscil0 = actx.createOscillator();
        oscil0.frequency.value = noteFreq[0];
        oscil0.connect(fader);

        var oscil1 = actx.createOscillator();
        oscil1.frequency.value = noteFreq[0] * 2;
        oscil1.connect(fader);

        oscil0.start(time);
        oscil1.start(time);
        oscil0.frequency.exponentialRampToValueAtTime(noteFreq[1], time + noteLength);
        oscil1.frequency.exponentialRampToValueAtTime(noteFreq[1] * 2, time + noteLength);
        fader.gain.linearRampToValueAtTime(0, time + noteLength);
        oscil0.stop(time + noteLength);
        oscil1.stop(time + noteLength);
    }
}

Однако скрипт для генерации самих тиков написан на языке Найквиста, основанном на Лиспе. Как я могу написать что-то на JavaScript, которое выполняет то же, что и генератор Lisp / Nyquist, но с использованием функций AudioContext и Web Audio?

Я пробовал множество онлайн-инструментов для перевода, но ни один из них, казалось, не достиг того, что мне нужно Кроме того, как я могу убедиться, что пустой буфер, с которого я начинаю (который заполнен образцом шума, сгенерированным приведенным выше кодом), запускается точно в соответствии с переменной time в JS?

«Высокий проход 8» может быть сделан с помощью createBiquadFilter(), и шум может создаваться, начиная со случайных чисел. Я раньше работал с Web Audio API и сделал из него генератор шума и тона. Однако на этой задаче я застрял.


В качестве альтернативы я попытался найти источник a.bestmetronome.com, но, по-видимому, они используют Flash для генерации своих звуков, и я не смог найти объект ActiveX, который фактически генерировал тики. Как я мог воспроизвести способ, которым они генерировали тиков? (Также с использованием API Web Audio)

1 Ответ

1 голос
/ 01 июля 2019

Код Найквиста, как написано в вопросе, не будет работать, потому что функция s-rest-abs не была определена. Эта версия может быть запущена в эффекте «Nyquist Prompt» Audacity (см .: https://manual.audacityteam.org/man/nyquist_prompt.html)

;version 4
;type generate

;; Metronome tick by Steve Daulton.
(defun metronome-tick (hz peak)
    (let* ((ln 300)
        (sig-array (make-array ln))
        (x 1))
    ;; generate some 'predictable' white noise
(dotimes (i ln)
    (setf x (rem (* 479 x) 997))
    (setf (aref sig-array i) (- (/ x 500.0) 1)))
        (setf sig (sim (abs-env (s-rest 0.2))
            (snd-from-array 0 44100 sig-array)))
    (setf sig
        (mult (abs-env (pwev 10 (/ ln 44100.0) 2 1 0))
            (highpass8  (lowpass2 sig (* 2 hz) 6)
                        hz)))
    (let ((gain (/ (peak sig 300))))
    ; The '1.11' factor makes up for gain reduction in 'resample'
    (mult (abs-env (pwlv 1.11 0.02 1.11 0.05 0 ))
        (jcrev (mult peak gain sig) 0.01 0.1)))))

;; Single tick generator:
(defun get-metronome-tick (hz gain)
    (resample
        (sound-srate-abs 44100 (metronome-tick hz gain))
        *sound-srate*))

(get-metronome-tick 440 0.8)

Последняя строка вызывает функцию "get-metronome-tick".

(Как автор генератора Audacity Rhythm Track, я был бы рад предоставить более подробную информацию о том, что именно делает этот код, хотя я не думаю, что это необходимо в контексте вопроса.)

Как видно из запуска этого кода в Nyquist Prompt Audacity, он генерирует последовательность из 2200 значений выборки (50 мс при частоте выборки 44100 Гц). Он был написан таким образом, чтобы весь плагин мог распространяться в одном небольшом текстовом файле.

Я не эксперт по JS, но я ожидаю, что в JS / HTML5 было бы проще просто создать небольшой аудиофайл для данных примера. Поскольку очень высокие частоты не требуются, это может быть очень маленький файл с низкой частотой дискретизации (скажем, 550 выборок с частотой дискретизации 11025 Гц) или в сжатом формате, таком как OGG или MP3. Файл можно создать в Audacity, сгенерировав галочку с указанным выше кодом, а затем экспортировав.

Звук может быть загружен чем-то вроде:

<audio src="tickSound.ogg" type="audio/ogg"></audio>

Смотри также: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Using_Web_Audio_API

и

https://www.w3.org/TR/webaudio/

...