Почему EnvGen перезапускается при каждой итерации цикла и как предотвратить такое поведение?

Как я могу использовать EnvGen в цикле таким образом, чтобы он не перезапускался при каждой итерации цикла?

Для чего он мне нужен: кусочный синтез. Я хочу, например. 50 мс xfade между первым и вторым Klang, затем xfade 50 мс между вторым и третьим Klang, затем xfade 50 мс между третьим и четвертым Klang и так далее, и я хочу, чтобы эта конкатенация в целом модулировалась огибающей.

К сожалению, EnvGen, кажется, перезапускается с самого начала на каждой итерации цикла, который воспроизводит последовательные пары Klang. Я хочу poiiiinnnnnnnnnng, но что бы я ни пытался, все, что я получаю, это поп-поп-поп-попопо.

2019 РЕДАКТИРОВАТЬ:

Хорошо, поскольку никто не ответил на вопрос «как достичь цели», я сейчас понижаю этот вопрос до простого «почему этот конкретный подход не работает», также меняя заголовок.

Прежде чем я вставлю код, небольшое пояснение: это очень упрощенный пример. В то время как моим первоначальным желанием было модулировать сложный, кусочно-генерируемый звук с помощью огибающей, этот упрощенный пример только «вырезает» 100-мс сегменты из вывода SinOsc, просто чтобы искусственно создать ситуацию «кусочно-генерируемой».

Что происходит в этой программе, так это то, что EnvGen перезапускается при каждой итерации цикла: конверт перезапускается с t=0. Я ожидаю получить один экспоненциально затухающий звук продолжительностью 1 с, как если бы вы перебирали струну. То, что я получаю, представляет собой серию 100-мс «пингов» из-за перезапуска конверта в начале каждой итерации цикла.

Как предотвратить это?

Вот код:

//Exponential decay over 1 second
var envelope = {EnvGen.kr(Env.new([1,0.001],[1],curve: 'exp'), timeScale: 1, doneAction: 2)};

var myTask = Task({

    //A simple tone
    var oscillator = {SinOsc.ar(880,0,1);};

    var scissor;

    //Prepare a scissor that will cut 100ms of the oscillator signal
    scissor = {EnvGen.kr(Env.new([1,0],[1],'hold'),timeScale: 0.1)};
    10.do({

        var scissored,modulated;

        //Cut the signal with the scisor
        scissored = oscillator*scissor;

        //Try modulating with the envelope. The goal is to get a single 1s exponentially decaying ping.
        modulated = {scissored*envelope};

        //NASTY SURPRISE: envelope seems to restart here every iteration!!!
        //How do I prevent this and allow the envelope to live its whole
        //one-second life while the loop and the Task dance around it in 100ms steps?
        modulated.play;

        0.1.wait;
    });
});

myTask.play;

(Эта проблема, с которой я сначала безуспешно боролся МЕСЯЦАМИ, на самом деле заставила меня отложить свои усилия по изучению SuperCollider на ДВА ГОДА, и теперь я продолжаю с того места, где остановился.)


person Szczepan Hołyszewski    schedule 08.09.2017    source источник
comment
Этот вопрос может стать немного яснее, если вы добавите пример кода?   -  person les_h    schedule 03.12.2017
comment
Нет, не было бы. Вопрос в том, как достичь X, а не в том, почему этот конкретный подход не работает. Я явно не хочу, чтобы потенциальные ответчики сосредотачивались на исправлении моего конкретного подхода. Мне нужен совет о том, как достичь цели, даже если этот ответ потребует от меня смены парадигмы, изучения целого нового большого сегмента языка SuperCollider и насильственного выворачивания моего кода наизнанку.   -  person Szczepan Hołyszewski    schedule 16.12.2017
comment
Я мог бы добавить, что за 3 месяца с тех пор, как я задал вопрос, я не продвинулся ни на дюйм в решении этой проблемы, что является убедительным признаком того, что подход EnvGen-in-a-loop, вероятно, в корне неверен, и я должен отказаться от него вообще.   -  person Szczepan Hołyszewski    schedule 16.12.2017
comment
Легче (для меня) указать, почему конкретный подход не работает, чем писать пример вашей идеи синтеза с нуля. Кажется, вы можете захотеть создать синтезатор, который воспроизводит кланг, который появляется и исчезает, а затем использовать что-то вроде Pbind для перехода между ними, с \legato в паре с числом ›1. вы можете отправить их на шину, которая идет к другому синтезатору, который запускает огибающую сигнала.   -  person les_h    schedule 09.03.2018


Ответы (1)


Ты здесь работаешь как-то необычно.

С SuperCollider сдвиг парадигмы, который вы ищете, заключается в создании SynthDef как отдельных объектов:

s.waitForBoot ({
    b = Bus.new('control');
    
    SynthDef(\scissors, {arg bus;
        var env;
        env = EnvGen.kr(Env.linen);
        //EnvGen.kr(Env.new([1,0.001],[1],curve: 'exp'), timeScale: 1, doneAction: 2);
        
        Out.kr(bus, env);
    }).add;
    
    
    SynthDef(\oscillator, {arg bus, out=0, freq=440, amp = 0.1;
        
        var oscillator, scissored;
        oscillator = SinOsc.ar(freq,0,1);
        scissored = oscillator * In.kr(bus) * amp;
        
        Out.ar(out, scissored);
    }).add;
    
    s.sync;
    
    Task({
        Synth(\scissors, [\bus, b]);
        s.sync;
        10.do({|i|
            
            Synth(\oscillator, [\bus, b, \freq, 100 * (i+1)]);
            0.1.wait;
        });
    }).play
});

Я изменил на более длинную огибающую и изменил высоту тона, чтобы вы могли слышать начало всех осцилляторов.

Что я сделал, так это определил два SynthDef и шину.

У первого SynthDef есть огибающая, которую я удлинил для слышимости. Он записывает значение этого конверта в шину. Таким образом, любой другой SynthDef, который хочет использовать этот общий конверт, может получить его, прочитав шину.

Второй SynthDef имеет SinOsc. Мы умножаем выход этого на вход шины. Это использует общую огибающую для изменения амплитуды.

Это работает, но если вы запустите его во второй раз, вы получите еще один неприятный сюрприз! Осцилляторы SynthDefs не закончились, и вы услышите их снова. Чтобы решить эту проблему, вам нужно дать им свои собственные конверты или что-то еще с помощью doneAction. В противном случае они будут жить вечно. Наложение огибающих на каждый отдельный синтезатор осциллятора также является хорошим способом сформировать начало каждого из них.

Другая новая вещь, которую вы можете заметить в этом примере, — это строки s.sync;. Основная особенность SuperCollider заключается в том, что звуковой сервер и язык являются отдельными процессами. Эта строка гарантирует, что сервер подключится, поэтому мы не пытаемся использовать ресурсы на стороне сервера, пока они не будут готовы. Это разделение клиент/сервер также является причиной того, что лучше определить synthdef перед их использованием.

Надеюсь, что долгое ожидание ответа не отбило вас навсегда. Возможно, вам будет полезно ознакомиться с некоторыми учебными пособиями и начать работу таким образом.

person Les_h    schedule 07.12.2020