Myślę, że tym, co was myli, jest to, że malejący wykładniczy ( ) nigdy nie osiąga 0, więc generator ADSR z prawdziwie wykładniczymi segmentami utknąłby; ponieważ nigdy nie osiągnie wartości docelowej. Na przykład, jeśli generator znajduje się na wysokości fazy ataku (powiedzmy y = 1 ) i musi wylądować do wartości podtrzymania przy y = 0,5 , nie może tam dotrzeć z prawdziwym wykładniczym, ponieważ prawdziwy wykładniczy wygrał t rozpadnie się na 0,5, to tylko asymptotycznie przejdzie do 0,5!mi- xy= 1y= 0,5
Jeśli spojrzysz na analogowy generator obwiedni (na przykład obwód oparty na 7555, którego wszyscy używają ), możesz zauważyć, że podczas fazy ataku, gdy kondensator ładuje się, „celuje on wyżej” niż próg używany do wskazania końca fazy ataku. W obwodzie opartym na (7) 555 zasilanym + 15 V, podczas etapu ataku kondensator jest ładowany z krokiem + 15 V, ale etap ataku kończy się, gdy zostanie osiągnięty próg + 10 V. Jest to wybór projektowy, chociaż 2/3 to „magiczna liczba” znaleziona w wielu klasycznych generatorach obwiedni, i może być to jeden z muzyków, którego znają.
Zatem funkcje, z którymi możesz chcieć sobie poradzić, nie są wykładnicze, ale są wersjami przesuniętymi / obciętymi / skalowanymi i będziesz musiał dokonać pewnych wyborów co do tego, jak „zgniecione” mają być.
W każdym razie jestem ciekawy, dlaczego próbujesz uzyskać takie formuły - być może wynika to z ograniczeń narzędzia, którego używasz do syntezy; ale jeśli próbujesz zaimplementować te, które używają języka programowania ogólnego przeznaczenia (C, Java, Python) z jakimś kodem działającym dla każdej próbki koperty i pojęciem „stan”, czytaj dalej ... Ponieważ zawsze łatwiej jest wyrażaj rzeczy jako „taki segment przejdzie od wartości, którą właśnie osiągnął, do 0”.
Moje dwie porady dotyczące wdrażania kopert.
Pierwszy z nich to nieaby spróbować skalować wszystkie nachylenia / przyrosty, aby obwiednia dokładnie osiągnęła wartości początkową i końcową. Na przykład potrzebujesz koperty, która zmienia się od 0,8 do 0,2 w ciągu 2 sekund, więc możesz mieć ochotę obliczyć przyrost o -0,3 / sekundę. Nie rób tego Zamiast tego podziel go na dwa etapy: uzyskanie rampy, która przechodzi od 0 do 1,0 w ciągu 2 sekund; a następnie zastosowanie transformacji liniowej, która odwzorowuje 0 na 0,8 i 1,0 na 0,2. Istnieją dwie zalety pracy w ten sposób - pierwsza polega na tym, że upraszcza wszelkie obliczenia w stosunku do czasów obwiedni względem rampy od 0 do 1; po drugie, jeśli zmienisz parametry obwiedni (przyrosty i czasy rozpoczęcia / zakończenia) w połowie, wszystko pozostanie dobrze zachowane. Dobrze, jeśli pracujesz nad syntezatorem, ponieważ ludzie będą prosić o podanie parametrów czasu koperty jako miejsc docelowych modulacji.
Drugim jest użycie wstępnie obliczonej tabeli odnośników z kształtami kopert. Jest obliczeniowo lżejszy, usuwa wiele nieprzyzwoitych szczegółów (na przykład nie musisz zawracać sobie głowy wykładnikiem, który nie osiąga dokładnie 0 - obetnij go według własnego uznania i przeskaluj, aby został zamapowany na [0, 1]), i bardzo trudno jest zapewnić opcję zmiany kształtów obwiedni dla każdego etapu.
Oto pseudo-kod opisanego przeze mnie podejścia.
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
To dość stare pytanie, ale chcę tylko podkreślić punkt w odpowiedzi z fenenet:
Ten proces jest czasem nazywany „łagodzeniem” i wygląda jak
* Myślę, że OP już dawno już nie ma, ale może to pomaga komuś innemu.
źródło
O komentarzu z fenomenetami: „Podczas etapu ataku kondensator jest ładowany krokiem + 15 V, ale etap ataku kończy się, gdy zostanie osiągnięty próg + 10 V. Jest to wybór projektowy, chociaż 2/3 to„ magia ” numer „znaleziony w wielu klasycznych generatorach obwiedni, i to może być ten, który znają muzycy.”:
Każda koperta, która strzela do asymptoty 15 V z celem 10 V, praktycznie tworzy atak liniowy. Tyle tylko, że 15v jest najwyższą dostępną asymptotą łatwo dostępną i jest wystarczająco zbliżona do liniowej. Oznacza to, że nie ma w tym nic „magicznego” - po prostu są tak liniowe, jak to tylko możliwe.
Nie wiem, ile klasycznych syntezatorów wykorzystuje 15 V - podejrzewam, że często występuje spadek diody lub dwa. Mój stary modułowy Baran używa 13 V dla koperty 10 V, a ja właśnie spojrzałem na układ Curtis ADSR, który używa odpowiednio 6,5 V dla koperty 5 V.
źródło
Ten kod powinien generować wykresy podobne do wykresów fenenetowych:
Jestem wdzięczny za wszelkie ulepszenia, jedną rzeczą, która może być dobrym pomysłem, jest umożliwienie, aby ostatnie trzy parametry (które określają nachylenie każdego z trzech etapów) zmieniały się między 0 a 1, gdzie 0,5 byłoby linią prostą. Ale nie widzę od razu, jak to zrobić.
Nie przetestowałem też dokładnie wszystkich przypadków użycia, na przykład jeśli jeden stopień ma zerową długość.
źródło