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