Как я могу имитировать поведение триггера VC модульного синтеза с помощью API WebAudio? - PullRequest
0 голосов
/ 20 мая 2019

У меня есть эта картинка: http://bourt.com/color/slide.html. Если щелкнуть левой кнопкой мыши по кругу, будет слышен щелчок.Я хочу, чтобы щелчки оставались постоянными до тех пор, пока я не отпущу кнопку мыши, и чтобы интервал между щелчками уменьшался при перемещении круга вверх, до точки, где щелчки образуют тон.

Я могу получитьСуть того, что мне нужно, простым тоном (http://bourt.com/color/slide1.html),, но я бы хотел, чтобы LFO активировал конверт, который я использую для создания клика.

Это легко сделать в VCV, гдеЯ прототипировал это: enter image description here

Но я не могу понять, как имитировать поведение запуска конверта с помощью LFO. Как я понимаю, одним из вариантов является использованиеAnalyserNode.getFloatTimeDomainData(), найдите пики и соответствующим образом запланируйте клики.Другим было бы вообще отказаться от концепции LFO и использовать ScriptProcessor в качестве временного микшера, добавляя клики в буфер вручную. Но это большая чертова работа для чего-то, чтоконцептуально очень просто.

Так что я все еще надеюсь, что можно каким-то образом использовать осциллятор для запуска щелчков и изменять частотуэтот осциллятор с положением круга.Это так?

(мне известно о Повести о двух часах , но я не думаю, что этот вид планирования будет работать для верхней части ползунка, где щелчки такблизко, что они создают тон.)

Ответы [ 2 ]

0 голосов
/ 24 мая 2019

После попытки применения метода планирования setTimeout() стало ясно, что единственный способ добиться этого - использовать ScriptProcessorNode и добавлять клики в аудио-буфер самостоятельно. Это похоже на метод планирования, но все сэмплы должны обрабатываться вручную, что является болью, но это то, что я в итоге сделал.

Для любопытных вот как выглядит код (важные части):

var clickProc       = null;
var clickBuffer     = null;

var clickSample     = 0;
var remSamples      = 0;

var remBuffer       = null;
var remBufferLength = 0;


remBuffer = new Float32Array(2048);
clickProc = ac.createScriptProcessor(2048, 1, 1);


clickProc.onaudioprocess = function (e)
{
    var output = e.outputBuffer.getChannelData(0);
    var click  = clickBuffer.getChannelData(0);


    for (var i = 0; i < output.length; i++)
        output[i] = 0;


    if (remBufferLength > 0)
    {
        for (i = 0; i < remBufferLength; i++)
            output[i] = remBuffer[i];

        remBufferLength = 0;
    }


    for (i = 0; i < remBuffer.length; i++)
        remBuffer[i] = 0;


    if (clickSample >= output.length)
        clickSample -= output.length;


    while (clickSample < output.length)
    {
        var c;

        for (c = 0; c < click.length && clickSample < output.length; c++, clickSample++)
            output[clickSample] = Math.min(Math.max(0, output[clickSample] + click[c]), 1);

        remSamples = click.length - c;

        clickSample -= c;
        clickSample += Math.max(1, Math.floor(clickInterval * ac.sampleRate));


        if (c < click.length)
        {
            var remLength = click.length - c;

            for (i = 0; i < remLength; i++, c++)
                remBuffer[i] = Math.min(Math.max(0, remBuffer[i] + click[c]), 1);

            remBufferLength = Math.max(remBufferLength, remLength);
        }
    }
};

clickProc.connect(ac.destination);

0 голосов
/ 20 мая 2019

Использование логических схем (например, на основе LFO) было бы действительно болезненным. Я предлагаю вам использовать метод, основанный на setTimeout, чтобы регистрировать будущие клики, но при этом использовать звуковые часы в качестве эталона для запуска воспроизведения. Однажды я построил аудиотрекер в JS, и это было самое простое решение. Мой собственный код довольно грязный, но я нашел отличный пример здесь

...