Creo que lo que te confunde es que un exponencial decreciente ( ) nunca llega a 0, por lo que un generador ADSR con segmentos verdaderamente exponenciales se quedaría estancado; porque nunca alcanzaría el valor objetivo. Por ejemplo, si el generador está a la altura de la fase de ataque (digamos ) y tiene que aterrizar a un valor sostenido en , no puede ir allí con un exponencial verdadero, porque el exponencial verdadero ganó ' t decae a 0.5, ¡solo asintóticamente irá a 0.5! y = 1 y = 0.5e−xy=1y=0.5
Si observa un generador de envolvente analógico (por ejemplo, el circuito basado en 7555 que todo el mundo parece usar ), puede ver que durante la fase de ataque, cuando el condensador se está cargando, "apunta más alto" que el umbral utilizado para indicar el final de la fase de ataque. En un (7) circuito basado en 555 alimentado por + 15V, durante la etapa de ataque, el condensador se carga con un paso de + 15V, pero la etapa de ataque termina cuando se alcanza un umbral de + 10V. Esta es una opción de diseño, aunque 2/3 es el "número mágico" que se encuentra en muchos generadores de sobres clásicos, y este podría ser el único con el que los músicos están familiarizados.
Por lo tanto, las funciones con las que puede querer tratar no son exponenciales, sino versiones desplazadas / truncadas / escaladas, y tendrá que tomar algunas decisiones sobre qué tan "aplastadas" quiere que sean.
De todos modos, tengo curiosidad de por qué está tratando de obtener tales fórmulas, tal vez sea por los límites de la herramienta que está utilizando para la síntesis; pero si está tratando de implementar aquellos que usan un lenguaje de programación de propósito general (C, java, python) con algún código en ejecución para cada muestra del sobre y una noción de "estado", siga leyendo ... Porque siempre es más fácil expresa cosas como "dicho segmento pasará del valor que acaba de alcanzar a 0".
Mis dos consejos sobre la implementación de sobres.
El primero no espara intentar escalar todas las pendientes / incrementos para que la envolvente alcance exactamente los valores inicial y final. Por ejemplo, si desea un sobre que vaya de 0,8 a 0,2 en 2 segundos, por lo que podría verse tentado a calcular un incremento de -0.3 / segundo. No hagas eso. En su lugar, divídalo en dos pasos: obtener una rampa que va de 0 a 1.0 en 2 segundos; y luego aplicando una transformación lineal que asigna 0 a 0.8 y 1.0 a 0.2. Hay dos ventajas para trabajar de esta manera: la primera es que simplifica cualquier cálculo que tenga en relación con los tiempos de envolvente a una rampa de 0 a 1; el segundo es que si cambia los parámetros de envolvente (incrementos y tiempos de inicio / finalización) a mitad de camino, todo se comportará bien. Es bueno si está trabajando en un sintetizador, ya que las personas pedirán tener parámetros de tiempo de envolvente como destinos de modulación.
El segundo es usar una tabla de búsqueda precalculada con formas de envolvente. Es computacionalmente más liviano, elimina muchos detalles sucios (por ejemplo, no tiene que molestarse con un exponencial que no alcanza exactamente 0 - truncarlo a su antojo y reescalarlo para que se asigne a [0, 1]), y es muy fácil proporcionar una opción para alterar las formas de los sobres, para cada etapa.
Aquí está el pseudocódigo para el enfoque que describo.
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
Esta es una pregunta bastante antigua, pero solo quiero resaltar un punto en la respuesta de pichenettes:
Este proceso a veces se conoce como "facilitación" y parece
donde y son el límite inferior y superior (los valores posibles son , y el nivel de sostenido) es algo así como . Tenga en cuenta que no necesita esto para la fase de ataque, ya que oscila entre y .u 0 1 f ( x ) x n 0 1l u 0 1 f(x) xn 0 1
Aquí está la sesión original de Desmos, actualizada para usar este enfoque. Utilicé una forma cúbica aquí, pero usted * podría usar la forma que desee, siempre que produzca salidas que van de cero a una entrada dada que varía de cero a uno.f(x)
* Supongo que el OP probablemente ya no existe, pero quizás esto ayude a alguien más.
fuente
Sobre el comentario de pichenettes, "Durante la etapa de ataque, el condensador se carga con un paso de + 15V, pero la etapa de ataque termina cuando se alcanza un umbral de + 10V. Esta es una opción de diseño, aunque 2/3 es la" magia " número "encontrado en muchos generadores de sobres clásicos, y este podría ser el único con el que los músicos están familiarizados":
Cualquier sobre que dispare para una asíntota de 15v con un objetivo de 10v está, prácticamente, creando un ataque lineal. Es solo que 15v es la asíntota más alta disponible fácilmente, y está lo suficientemente cerca de lineal. Es decir, no hay nada "mágico" al respecto, solo van por lo más lineal posible.
No sé cuántos sintetizadores clásicos usan 15v. Sospecho que a menudo hay una caída de diodos o dos. Mi antiguo módulo modular Aries usa 13v para un sobre de 10v, y acabo de buscar el chip Curtis ADSR que usa, de manera equivalente, 6.5v para un sobre de 5v.
fuente
Este código debería generar tramas similares a las de las pichenettes:
Estoy agradecido por cualquier mejora, una cosa que puede ser una buena idea es permitir que los últimos tres parámetros (que determinan la inclinación de cada una de las tres etapas) varíen entre 0 y 1, donde 0.5 sería una línea recta. Pero no puedo ver de antemano cómo hacerlo.
Además, no he probado exhaustivamente todos los casos de uso, por ejemplo, si una etapa tiene una longitud cero.
fuente