Je pense que ce qui vous embrouille, c'est qu'une exponentielle décroissante ( ) n'atteint jamais 0, donc un générateur ADSR avec des segments vraiment exponentiels resterait bloqué; car il n'atteindrait jamais la valeur cible. Par exemple, si le générateur est à la hauteur de la phase d'attaque (disons ) et doit atterrir à une valeur de maintien à , il ne peut pas y aller avec une vraie exponentielle, car la vraie exponentielle a gagné '' t décroît à 0,5, il n'atteindra asymptotiquement qu'à 0,5! y = 1 y = 0,5e−xy=1y=0.5
Si vous regardez un générateur d'enveloppe analogique (par exemple le circuit basé sur 7555 que tout le monde semble utiliser ), vous pouvez voir que pendant la phase d'attaque, lorsque le condensateur est en charge, il "vise plus haut" que le seuil utilisé pour indiquer la fin de la phase d'attaque. Sur un circuit basé sur (7) 555 alimenté par + 15V, Pendant la phase d'attaque, le condensateur est chargé avec un pas de + 15V, mais la phase d'attaque se termine lorsqu'un seuil de + 10V a été atteint. Il s'agit d'un choix de conception, bien que 2/3 soit le "nombre magique" que l'on trouve dans de nombreux générateurs d'enveloppes classiques, et c'est peut-être celui que les musiciens connaissent.
Ainsi, les fonctions que vous voudrez peut-être traiter ne sont pas des exponentielles, mais des versions décalées / tronquées / échelles de celui-ci, et vous devrez faire des choix quant à la façon dont elles doivent être "écrasées".
Je suis quand même curieux de savoir pourquoi vous essayez d'obtenir de telles formules - c'est peut-être à cause des limites de l'outil que vous utilisez pour la synthèse; mais si vous essayez d'implémenter ceux qui utilisent un langage de programmation à usage général (C, java, python) avec du code en cours d'exécution pour chaque échantillon de l'enveloppe, et une notion d '"état", lisez la suite ... Parce qu'il est toujours plus facile de exprimer des choses comme "un tel segment passera de la valeur qu'il vient d'atteindre à 0".
Mes deux conseils sur la mise en place des enveloppes.
Le premier n'est paspour essayer de mettre à l'échelle toutes les pentes / incréments afin que l'enveloppe atteigne exactement les valeurs de début et de fin. Par exemple, vous voulez une enveloppe qui passe de 0,8 à 0,2 en 2 secondes, vous pourriez donc être tenté de calculer un incrément de -0,3 / seconde. Ne fais pas ça. Au lieu de cela, décomposez-le en deux étapes: obtenir une rampe qui passe de 0 à 1,0 en 2 secondes; puis en appliquant une transformation linéaire qui mappe 0 à 0,8 et 1,0 à 0,2. Il y a deux avantages à travailler de cette façon - le premier est qu'il simplifie tout calcul que vous aurez par rapport aux temps d'enveloppe à une rampe de 0 à 1; la seconde est que si vous modifiez les paramètres d'enveloppe (incréments et heures de début / fin) à mi-chemin, tout restera bien. Bien si vous travaillez sur un synthé, car les gens demanderont d'avoir des paramètres de temps d'enveloppe comme destinations de modulation.
La seconde consiste à utiliser une table de recherche pré-calculée avec des formes d'enveloppe. Il est plus léger sur le plan des calculs, il supprime de nombreux détails sales (par exemple, vous n'avez pas à vous soucier d'une exponentielle n'atteignant pas exactement 0 - tronquez-la à votre gré et redimensionnez-la afin qu'elle soit mappée sur [0, 1]), et il est très facile de fournir une option pour modifier les formes d'enveloppe, pour chaque étape.
Voici le pseudo-code de l'approche que je décris.
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
C'est une assez vieille question, mais je veux juste souligner un point dans la réponse des pichenettes:
Ce processus est parfois appelé «assouplissement» et ressemble à
où et sont les bornes inférieure et supérieure (les valeurs possibles étant , et le niveau de maintien) et est quelque chose comme . Notez que vous n'en avez pas besoin pour la phase d'attaque car elle va déjà de à .u 0 1 f ( x ) x n 0 1l u 0 1 f(x) xn 0 1
Voici la session Desmos originale, mise à jour pour utiliser cette approche. J'ai utilisé une forme cubique ici, mais vous * pouvez utiliser la forme que vous voulez, tant que produit des sorties allant de zéro à une entrée donnée allant de zéro à une.f(x)
* Je suppose que l'OP a probablement disparu depuis longtemps, mais peut-être que cela aide quelqu'un d'autre.
la source
À propos du commentaire de pichenettes, "Pendant la phase d'attaque, le condensateur est chargé avec un pas de + 15V, mais la phase d'attaque se termine lorsqu'un seuil de + 10V a été atteint. C'est un choix de conception, bien que 2/3 soit la" magie nombre "trouvé dans de nombreux générateurs d'enveloppes classiques, et c'est peut-être celui que les musiciens connaissent.":
Toute enveloppe qui vise une asymptote 15v avec une cible 10v crée pratiquement une attaque linéaire. C'est juste que 15v est l'asymptote la plus élevée disponible facilement, et il est assez proche de linéaire. Autrement dit, il n'y a rien de "magique" à ce sujet - ils vont juste pour aussi linéaire que possible.
Je ne sais pas combien de synthés classiques utilisent le 15v - je soupçonne qu'il y a souvent une chute de diode ou deux. Mon ancien modulaire Aries utilise du 13v pour une enveloppe de 10v, et je viens de chercher la puce Curtis ADSR qui utilise, de manière équivalente, 6,5v pour une enveloppe de 5v.
la source
Ce code devrait générer des tracés similaires à ceux des pichenettes:
Je suis reconnaissant pour toute amélioration, une chose qui peut être une bonne idée est de permettre aux trois derniers paramètres (qui déterminent la pente de chacune des trois étapes) de varier entre 0 et 1, où 0,5 serait une ligne droite. Mais je ne vois pas comment le faire.
De plus, je n'ai pas testé à fond tous les cas d'utilisation, par exemple si une étape a une longueur nulle.
la source