Üstel ADSR zarfı için denklemlerle ilgili yardım


11

Uygulama kodu ile, bir osilatörün çıkış genliğini şekillendirmek için doğrusal bir ADSR zarfı uyguladım. Saldırı, bozulma ve serbest bırakma süresinin yanı sıra sürdürme seviyesi parametreleri zarf üzerinde ayarlanabilir ve her şey beklendiği gibi çalışır.

Ancak, zarfın rampa şekillerini çoğu sentezleyicinin daha doğal bir tepki için kullandığı şeye benzeyen bir değişiklik yapmak istiyorum: saldırı için ters üstel ve çürüme ve serbest bırakma için üstel. Bu tür rampa şekilleri için zarf çıktı değerlerini hesaplamak için formüllerimi doğru şekilde almakta sorun yaşıyorum. Doğrusal rampaları hesaplamak için , saldırı / bozulma / sürdürme / bırakma giriş parametresi değerlerinden türetilen başlangıç ​​/ bitiş / y değerlerini ekleyerek iki noktalı formu kullanıyorum . Aynı başlangıç ​​/ bitiş x / y noktası değerlerini kullanarak üstel (standart ve ters) rampalar için doğru formülü çalışamıyorum .xyxy

Yukarıda tarif ettiğim doğrusal rampaların yaklaşımını gösteren bir Desmos Grafik Hesap Makinesi oturumu kaydettim .

Biri beni doğru yönde göstermeye yardımcı olabilirse, çok takdir edilecektir.

Yanıtlar:


10

exy=1y=0.5

Analog bir zarf üretecine bakarsanız (örneğin, herkesin kullandığı 7555 tabanlı devre ), saldırı aşamasında, kapasitör şarj olurken, sonu belirtmek için kullanılan eşikten daha yüksek "nişan aldığını" görebilirsiniz. saldırı aşaması. + 15V ile çalışan bir (7) 555 tabanlı devrede, Saldırı aşamasında, kapasitör + 15V'lik bir adımla şarj edilir, ancak + 10V eşiğine ulaşıldığında saldırı aşaması sona erer. Bu, bir tasarım seçimidir, ancak 2/3, birçok klasik zarf üreticisinde bulunan "sihirli sayı" dır ve bu, müzisyenlerin aşina olduğu bir kişi olabilir.

Kapasitör şarjı sırasında farklı "amaç oranından" kaynaklanan bazı ADSR şekilleri

Bu nedenle, uğraşmak isteyebileceğiniz işlevler üstel değildir, ancak kaydırılmış / kesilmiş / ölçeklendirilmiş versiyonlarıdır ve bunların nasıl "ezilmesini" istediğiniz konusunda bazı seçimler yapmanız gerekir.

Zaten neden bu formülleri almaya çalıştığınızı merak ediyorum - belki de sentez için kullandığınız aracın sınırları nedeniyle; ancak, genel amaçlı bir programlama dili (C, java, python) kullananları, zarfın her bir örneği için çalışan bir kod ve "durum" kavramı ile uygulamaya çalışıyorsanız, okumaya devam edin ... "böyle bir segment henüz 0'a ulaştığı değerden gidecek" şeklinde ifade eder.

Zarfları uygulama konusunda iki tavsiyem.

İlki değilzarfın başlangıç ​​ve bitiş değerlerine tam olarak ulaşması için tüm eğimleri / artışları ölçeklemeye çalışmak. Örneğin, 2 saniyede 0,8 ile 0,2 arasında değişen bir zarf istersiniz, bu nedenle -0,3 / saniyelik bir artış hesaplamak isteyebilirsiniz. Bunu yapma. Bunun yerine, iki adıma ayırın: 2 saniyede 0'dan 1.0'a kadar giden bir rampa almak; ve daha sonra, 0 ila 0.8 ve 1.0 ila 0.2'yi eşleyen bir doğrusal dönüşümün uygulanması. Bu şekilde çalışmanın iki avantajı vardır - birincisi, zarf sürelerine göreceli herhangi bir hesaplamayı 0'dan 1'e kadar bir rampaya basitleştirmesidir; ikincisi, zarf parametrelerini (artışlar ve başlangıç ​​/ bitiş zamanları) yarıya kadar değiştirirseniz, her şey iyi durumda kalacaktır. Bir synth üzerinde çalışıyorsanız iyi olur, çünkü insanlar modülasyon hedefleri olarak zarf süresi parametrelerine sahip olmayı isteyecektir.

İkincisi, zarf şekilleri ile önceden hesaplanmış arama tablosu kullanmaktır. Hesaplama açısından daha hafiftir, birçok kirli ayrıntıyı alır (örneğin, tam olarak 0'a ulaşmayan bir üstel ile uğraşmanıza gerek yoktur - kaprisinize göre kesin ve [0, 1] ile eşlenecek şekilde yeniden ölçeklendirin), ve her aşama için zarf şekillerini değiştirme seçeneği sunmak çok kolaydır.

İşte tarif ettiğim yaklaşımın sözde kodu.

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

Sorunumu, doğrusal ölçek / y = ((y2 - y1) / (x2 - x1)) * (x - x1) + y1 iki nokta denklemini alarak, x değişkenlerini e ile değiştirerek çözmüş gibiydim ^ x ila y = ((y2 - y1) / (e ^ x2 - e ^ x1)) * (e ^ x - e ^ x1) + y1. Bağlantıdaki hesap oturumu bu yaklaşımı gösteriyor. Bunları bilmem gereken herhangi bir şey var mı? Sonuçlar benim için doğru görünüyor.
Gary DeReese

Bu, diğer sentezleyicilerde bulunan zarf şekli değildir. Başlangıç ​​ve bitiş seviyesinin zamanına / göreceli konumuna bağlı olarak, çok doğrusal hale gelebilir.
Haziran'da pichenettes

@pichenettes, bu zarfları üreten komut dosyasını yapıştırmak ister misiniz?
P i

3

Bu oldukça eski bir soru, ama sadece pichenettes'in cevabındaki bir noktayı vurgulamak istiyorum:

Örneğin 2 saniyede 0,8 ile 0,2 arasında değişen bir zarf istersiniz [...] iki adıma ayırın: 2 saniyede 0 ile 1,0 arasında değişen bir rampa almak; ve daha sonra, 0 ila 0.8 ve 1.0 ila 0.2'yi eşleyen bir doğrusal dönüşümün uygulanması.

Bu süreç bazen "gevşetme" olarak bilinir ve şöyle görünür

g(x,l,u)=f(xlul)(ul)+l

lu01f(x)xn01

f(x)

* Sanırım OP muhtemelen çoktan gitti, ama belki bu başka birine yardımcı olur.


Bunun için teşekkür ederim, geliştirici olduğum bir DAW için bir örnekleyici programlıyordum ve Desmos oturumunda sağlanan formülleri taktım ve mükemmel çalıştılar. Artık topal doğrusal zarf yok! :)
Douglas

1

Pichenettes'in yorumu hakkında, "Saldırı aşamasında kapasitör + 15V'lik bir adımla şarj edilir, ancak + 10V eşiğine ulaşıldığında saldırı aşaması sona erer. 2/3" büyüsü " numarası "birçok klasik zarf üreticisi bulunur ve bu müzisyenlerin aşina olduğu tek kişi olabilir.":

10v'lik bir hedefe sahip 15v'lik bir asimptot için çekim yapan herhangi bir zarf, pratik olarak doğrusal bir saldırı oluşturur. Sadece 15v kolayca mevcut olan en yüksek asimptottur ve lineer olmak için yeterince yakındır. Yani, onun hakkında "sihir" diye bir şey yoktur - sadece alabildikleri kadar doğrusal olacaklardır.

Kaç klasik synth'in 15v kullandığını bilmiyorum - genellikle bir veya iki diyot düşüşünden şüpheleniyorum. Eski Koç modülerim 10v zarf için 13v kullanıyor ve ben 5V zarf için eşdeğer 6.5v kullanan Curtis ADSR çipini aradım.


1

Bu kod, pichenette'dekilere benzer grafikler oluşturmalıdır:

def ASD_envelope( nSamps, tAttack, tRelease, susPlateau, kA, kS, kD ):
    # number of samples for each stage
    sA = int( nSamps * tAttack )
    sD = int( nSamps * (1.-tRelease) )
    sS = nSamps - sA - sD

    # 0 to 1 over N samples, weighted with w
    def weighted_exp( N, w ):
        t = np.linspace( 0, 1, N )
        E = np.exp( w * t ) - 1
        E /= max(E)
        return E

    A = weighted_exp( sA, kA )
    S = weighted_exp( sS, kS )
    D = weighted_exp( sD, kD )

    A = A[::-1]
    A = 1.-A

    S = S[::-1]
    S *= 1-susPlateau
    S += susPlateau

    D = D[::-1]
    D *= susPlateau

    env = np.concatenate( [A,S,D] )

    # plot
    tEnv = np.linspace( 0, nSamps, len(env) )
    plt.plot( tEnv, env )
    plt.savefig( "OUT/EnvASD.png" )
    plt.close()

    return env

Herhangi bir iyileştirme için minnettarım, iyi bir fikir olabilecek bir şey, son üç parametrenin (üç aşamanın her birinin dikliğini belirleyen) 0 ile 1 arasında değişmesine izin vermek, burada 0.5 düz bir çizgi olacaktır. Ama nasıl yapılacağını açıkça göremiyorum.

Ayrıca, örneğin bir aşama sıfır uzunluğu varsa, tüm kullanım durumlarını tam olarak test etmedim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.