Eu acho que o que o confunde é que um exponencial decrescente ( ) nunca chega a 0; portanto, um gerador ADSR com segmentos verdadeiramente exponenciais ficaria parado; porque nunca alcançaria o valor desejado. Por exemplo, se o gerador estiver no auge da fase de ataque (digamos, ) e precisar atingir um valor de sustentação em , ele não poderá ir para lá com um exponencial verdadeiro, porque o exponencial verdadeiro venceu ' t decair para 0,5, ele só vai assintoticamente para 0,5!e−xy=1y=0.5
Se você olhar para um gerador de envelope analógico (por exemplo, o circuito baseado em 7555 que todo mundo parece usar ), poderá ver que durante a fase de ataque, quando o capacitor está carregando, ele está "mirando mais alto" do que o limite usado para indicar o fim da fase de ataque. Em um circuito baseado em (7) 555, alimentado por + 15V, durante o estágio de ataque, o capacitor é carregado com uma etapa de + 15V, mas o estágio de ataque termina quando um limite de + 10V é atingido. Esta é uma escolha de design, embora 2/3 seja o "número mágico" encontrado em muitos geradores clássicos de envelopes, e talvez seja com isso que os músicos estejam familiarizados.
Portanto, as funções com as quais você pode querer lidar não são exponenciais, mas versões alteradas / truncadas / dimensionadas, e você terá que fazer algumas escolhas sobre o quão "esmagado" deseja que elas sejam.
De qualquer forma, estou curioso para saber por que você está tentando obter essas fórmulas - talvez seja por causa dos limites da ferramenta que você está usando para síntese; mas se você estiver tentando implementar aqueles que usam uma linguagem de programação de uso geral (C, java, python) com algum código em execução para cada amostra do envelope e uma noção de "estado", continue lendo ... Porque é sempre mais fácil expressar coisas como "esse segmento passará de qualquer valor que acabou de chegar a 0".
Meus dois conselhos sobre a implementação de envelopes.
O primeiro não épara tentar dimensionar todas as inclinações / incrementos para que o envelope atinja exatamente os valores inicial e final. Por exemplo, você deseja um envelope que varia de 0,8 a 0,2 em 2 segundos, para que possa ser tentado a calcular um incremento de -0,3 / segundo. Não faça isso. Em vez disso, divida-o em duas etapas: obter uma rampa que varia de 0 a 1,0 em 2 segundos; e, em seguida, aplicando uma transformação linear que mapeia 0 a 0,8 e 1,0 a 0,2. Há duas vantagens em trabalhar dessa maneira - a primeira é que simplifica qualquer cálculo que você tenha em relação aos tempos de envelope para uma rampa de 0 a 1; a segunda é que, se você alterar os parâmetros do envelope (incrementos e horários de início / término) no meio do caminho, tudo permanecerá bem comportado. Bom se você estiver trabalhando em um sintetizador, já que as pessoas solicitarão parâmetros de tempo de envelope como destinos de modulação.
O segundo é usar a tabela de pesquisa pré-calculada com formas de envelope. É computacionalmente mais leve, remove muitos detalhes sujos (por exemplo, você não precisa se preocupar com um exponencial que não atinja exatamente 0 - truncá-lo à sua vontade e redimensioná-lo para que seja mapeado para [0, 1]), e é fácil fornecer uma opção para alterar as formas dos envelopes, para cada estágio.
Aqui está o pseudo-código da abordagem que descrevo.
render:
counter += increment[stage]
if counter > 1.0:
stage = stage + 1
start_value = value
counter = 0
position = interpolated_lookup(envelope_shape[stage], counter)
value = start_value + (target_level[stage] - start_value) * position
trigger(state):
if state = ON:
stage = ATTACK
value = 0 # for mono-style envelopes that are reset to 0 on new notes
counter = 0
else:
counter = 0
stage = RELEASE
initialization:
target_level[ATTACK] = 1.0
target_level[RELEASE] = 0.0
target_level[END_OF_RELEASE] = 0.0
increment[SUSTAIN] = 0.0
increment[END_OF_RELEASE] = 0.0
configuration:
increment[ATTACK] = ...
increment[DECAY] = ...
target_level[DECAY] = target_level[SUSTAIN] = ...
increment[RELEASE] = ...
envelope_shape[ATTACK] = lookup_table_exponential
envelope_shape[DECAY] = lookup_table_exponential
envelope_shape[RELEASE] = lookup_table_exponential
Essa é uma pergunta bastante antiga, mas eu só quero destacar um ponto na resposta das pichenettes:
Esse processo às vezes é conhecido como "flexibilização" e parece
onde e são o limite inferior e superior (os valores possíveis são , e o nível de sustentação) é algo como . Observe que você não precisa disso para a fase de ataque, pois ela já varia de a .u 0 1 f ( x ) x n 0 1l u 0 1 f(x) xn 0 1
Aqui está a sessão original do Desmos, atualizada para usar essa abordagem. Eu usei uma forma cúbica aqui, mas você * pode usar a forma que quiser, desde que produza saídas que variam de zero a uma dada entrada que varia de zero a uma.f(x)
* Acho que o OP provavelmente já está longe, mas talvez isso ajude outra pessoa.
fonte
Sobre o comentário dos pichenettes, "Durante o estágio de ataque, o capacitor é carregado com uma etapa de + 15V, mas o estágio de ataque termina quando um limite de + 10V é atingido. Essa é uma opção de design, embora 2/3 seja a" mágica número "encontrado em muitos geradores clássicos de envelopes, e é com isso que os músicos estão familiarizados".
Qualquer envelope que esteja disparando para uma assíntota de 15v com um alvo de 10v está praticamente criando um ataque linear. É apenas que 15v é a maior assíntota disponível com facilidade, e é perto o suficiente para linear. Ou seja, não há nada de "mágico" nisso - eles estão indo tão linearmente quanto possível.
Não sei quantos sintetizadores clássicos usam 15v - eu suspeitaria que geralmente há uma queda de diodo ou dois. Meu antigo módulo de Áries usa 13v para um envelope de 10v, e acabei de procurar no chip ADSR da Curtis que usa, equivalentemente, 6,5v para um envelope de 5v.
fonte
Esse código deve gerar gráficos semelhantes aos das pichenettes:
Sou grato por quaisquer melhorias, uma coisa que pode ser uma boa idéia é permitir que os três últimos parâmetros (que determinam a inclinação de cada um dos três estágios) variem entre 0 e 1, onde 0,5 seria uma linha reta. Mas não consigo ver de imediato como fazê-lo.
Também não testei completamente todos os casos de uso, por exemplo, se um estágio tem tamanho zero.
fonte