Blog Metlivi

Como pausar uma posição de modulação e retomá-la no sentido inverso no próximo disparo no SuperCollider

Para pausar uma posição de modulação e retomá-la no sentido inverso, mantenha o gerador de fase em execução com um incremento de zero e, no próximo disparo, altere esse incremento para um valor negativo. Deixe a entrada de reinicialização de fase desconectada desses disparos para que o movimento continue a partir da posição mantida.

Este tutorial cria esse comportamento no SuperCollider: uma varredura ascendente de altura é pausada no primeiro disparo e refaz seu percurso no segundo. Ele é voltado a um designer de som que deseja um gesto de modulação repetível, controlado por eventos sucessivos. O mesmo sinal de fase poderá depois controlar outro parâmetro.

29 de outubro de 20266 min de leituraPor Metlivi Editorial Team
Seção 1

O que deve ser preservado durante a pausa?

Trate a modulação como duas operações conectadas: uma posição percorre um ciclo e um mapeamento converte essa posição em um valor útil de parâmetro. Aqui, a posição vai de zero em direção a um, e o mapeamento a converte em frequência do oscilador.

O Phasor do SuperCollider fornece a posição. Seu argumento rate especifica o incremento por amostra; já sua entrada de disparo salta para resetPos. São controles separados, portanto um disparo usado para mudar a direção também não deve reinicializar a posição. Documentação do Phasor

A implementação mantém um nível interno e adiciona a ele a taxa. Com base nesse comportamento, uma taxa zero mantém o nível, enquanto uma taxa negativa o reduz. O patch abaixo aplica isso diretamente, preservando o estado do gerador durante toda a pausa. Implementação de TriggerUGens.cpp do SuperCollider 3.14.0

Seção 2

O que cada disparo sucessivo deve fazer?

Defina a sequência de eventos antes de conectar o som. Neste patch, o movimento começa imediatamente para a frente. Cada disparo seguinte avança um estado:

Disparos recebidos Estado Multiplicador de direção
0 Mover para a frente +1
1 Manter a posição atual 0
2 Retomar no sentido inverso −1
3 Manter a posição atual 0
4 Retomar para a frente +1

Esse ciclo de quatro estados separa os dois estados de pausa: um precede o movimento no sentido inverso e o outro, o movimento para a frente. Isso torna os gestos repetidos previsíveis sem exigir outro botão de direção.

PulseCount é incrementado quando sua entrada muda de não positiva para positiva. Obter o resto da divisão da contagem por quatro produz os índices repetidos de 0 a 3. Em seguida, Select escolhe o multiplicador correspondente de [1, 0, -1, 0]. Essas são as funções documentadas de PulseCount e Select.

Seção 3

Como montar o patch completo?

Use uma instalação local do SuperCollider com uma saída de áudio funcionando; o exemplo segue a documentação da versão 3.14.0. Ele usa geradores unitários integrados e produz o próprio som, portanto não são necessários arquivos de amostra nem extensões. Avalie o bloco inteiro uma vez e aguarde a mensagem de pronto.

waitForBoot inicia o servidor, caso necessário. A definição é enviada antes da criação do synth, com s.sync aguardando a conclusão das operações pendentes no servidor. Consulte a documentação do Server e a documentação do SynthDef.

(
s = Server.default;
s.waitForBoot({
    SynthDef(\pauseReverseMod, {
        |out = 0, t_step = 0, cycleSeconds = 8, amp = 0.08|
        var state, direction, increment, phase, frequency, sound;

        state = PulseCount.kr(t_step) % 4;
        direction = Select.kr(state, [1, 0, -1, 0]);

        // A full 0..1 traversal takes cycleSeconds seconds.
        increment = direction * SampleDur.ir
            / cycleSeconds.max(0.01);

        // State-changing triggers never reset this phase.
        phase = Phasor.ar(
            trig: 0,
            rate: increment,
            start: 0,
            end: 1,
            resetPos: 0
        );

        frequency = LinExp.ar(phase, 0, 1, 220, 880);
        sound = SinOsc.ar(frequency, 0, amp);
        Out.ar(out, sound ! 2);

        Poll.kr(Impulse.kr(2), state, "state");
        Poll.kr(Impulse.kr(2), A2K.kr(phase), "phase");
    }).add;

    s.sync;
    ~pauseReverseSynth = Synth(\pauseReverseMod);
    "Ready: evaluate ~pauseReverseSynth.set(\\t_step, 1);".postln;
});
)

O incremento é a direção multiplicada pela duração da amostra e dividida pela duração do ciclo. SampleDur retorna o inverso da taxa de amostragem do servidor, portanto a configuração de oito segundos não pressupõe uma taxa de amostragem específica. Documentação do SampleDur

O mapeamento de altura abrange de 220 a 880 Hz. LinExp converte um intervalo de entrada linear em um intervalo de saída exponencial; seus valores de destino nas extremidades devem ser diferentes de zero e ter o mesmo sinal. Ambos os valores usados aqui atendem a esse requisito. Documentação do LinExp

Conferi o exemplo do SuperCollider com a documentação consultada. O ambiente de pesquisa não tinha o runtime do SuperCollider disponível, então não executei nem ouvi este patch. Uma verificação aritmética determinística separada confirmou a sequência de direções e o comportamento de manutenção com incremento zero.

Seção 4

Como pausar e retomar no sentido inverso?

Após a mensagem de pronto, deixe a altura subir por cerca de dois segundos. Em seguida, avalie este comando de interação uma vez:

~pauseReverseSynth.set(\t_step, 1);

O estado deve passar a 1, e a fase impressa deve se estabilizar em um valor. Aguarde um instante e avalie o mesmo comando novamente. O estado deve passar a 2, e a fase deve diminuir a partir da posição mantida. Uma terceira avaliação mantém a varredura descendente; uma quarta a inicia novamente para a frente.

O prefixo t_ faz de t_step um controle de disparo. Ao defini-lo, é gerado um impulso à taxa de controle, permitindo reutilizar o mesmo comando sem enviar manualmente um zero separado entre avaliações comuns, espaçadas. Documentação de controle de disparo do SynthDef

Como cálculo ilustrativo de tempo, um ciclo de oito segundos avança 0,125 do seu intervalo por segundo. Portanto, uma pausa após dois segundos mantém aproximadamente 0,25. Após qualquer duração de pausa, um segundo de movimento no sentido inverso o leva a aproximadamente 0,125. Esses valores são expectativas calculadas; o tempo entre os comandos determina a posição real em que o movimento para.

Para terminar, avalie o comando de limpeza:

~pauseReverseSynth.free;
Seção 5

Como verificar se a posição realmente ficou parada?

Use a fase impressa como principal diagnóstico. Durante o movimento para a frente, ela deve aumentar; em qualquer um dos estados de pausa, deve permanecer constante; durante o movimento no sentido inverso, deve diminuir até alcançar o limite do ciclo.

O patch imprime duas vezes por segundo, portanto a exibição amostra o comportamento em vez de mostrar todas as amostras. Observe várias leituras consecutivas durante a pausa e compare-as com as primeiras leituras descendentes após a retomada. Poll serve para depurar valores de geradores unitários; remova as duas linhas de consulta ao adaptar a definição para uso regular. Documentação do Poll

Este teste fornece mais informações do que apenas ouvir. Um som constante indica que o destino parou de mudar, enquanto uma leitura de fase estável confirma que a posição subjacente também parou. Manter o mapeamento fixo durante todo o teste facilita a interpretação do resultado.

Seção 6

Por que o patch pode reiniciar, saltar ou não detectar um disparo?

Ele reinicia ao retomar. Verifique se o evento também chega à entrada de disparo do Phasor. Essa entrada reinicializa explicitamente a posição. Neste patch, ela permanece em zero, enquanto os eventos alimentam apenas o contador de estados. Documentação do Phasor

Ele salta depois de chegar a um extremo. Este exemplo faz um loop deliberadamente. A implementação envolve a fase dentro do intervalo configurado, inclusive durante o movimento negativo. Quando o movimento no sentido inverso passa de zero, a fase retorna para perto do limite superior, causando um salto de altura com este mapeamento em rampa. Primeiro, teste a pausa e a inversão longe desse limite. Implementação do Phasor

Vários comandos rápidos não produzem vários estados. O contador precisa de transições distintas para o estado positivo. Os controles de disparo operam à taxa de controle, portanto não presuma que vários comandos recebidos em um único bloco de controle se tornarão eventos separados. Comece com comandos deliberados e espaçados; para sequências cronometradas com precisão, projete a fonte de eventos para gerar pulsos distintos. Documentação do PulseCount, documentação do SynthDef

O som muda enquanto a fase está pausada. Verifique se você também está mudando o mapeamento de destino ou outro parâmetro de som. Neste teste, mantenha fixos os extremos de altura e use a fase impressa para isolar o transporte da modulação.

O gesto completo consiste em avançar, pausar, retroceder, pausar e avançar novamente. Quando essa sequência funcionar corretamente, mantenha o contador de estados e o gerador de fase como uma fonte de modulação reutilizável e altere o mapeamento de destino para adequá-lo ao som que você está criando.

Seção 7

Fontes

Leituras relacionadas

Continue explorando o tema