Bantuan dengan persamaan untuk amplop ADSR eksponensial

11

Dengan kode aplikasi, saya telah menerapkan amplop ADSR linier untuk membentuk amplitudo dari output osilator. Parameter untuk durasi serangan, peluruhan dan pelepasan serta level penopang dapat diatur pada amplop dan semuanya berfungsi seperti yang diharapkan.

Namun, saya ingin mengubah bentuk ramp dari amplop menjadi sesuatu yang menyerupai apa yang kebanyakan synthesizer gunakan untuk respons yang lebih alami: eksponensial terbalik untuk serangan dan eksponensial untuk peluruhan dan pelepasan. Saya mengalami masalah dalam mendapatkan formula yang tepat untuk menghitung nilai output amplop untuk jenis bentuk ramp ini. Untuk menghitung landai linier, saya menggunakan formulir dua titik, memasukkan nilai awal / akhir / yang diturunkan dari nilai parameter input input serangan / peluruhan / pelepasan. Sepertinya saya tidak dapat mengerjakan rumus yang benar untuk jalur eksponensial (standar dan terbalik) menggunakan nilai titik awal / akhir / sama.y x yxyxy

Saya telah menyimpan sesi Kalkulator Grafik Desmos yang menunjukkan pendekatan untuk jalur landai yang saya jelaskan di atas.

Jika ada yang bisa membantu mengarahkan saya ke arah yang benar, itu akan sangat dihargai.

Gary DeReese
sumber

Jawaban:

10

Saya pikir yang membingungkan Anda adalah bahwa penurunan eksponensial ( ) tidak pernah mencapai 0, sehingga generator ADSR dengan segmen yang benar-benar eksponensial akan tetap macet; karena tidak akan pernah mencapai nilai target. Misalnya, jika generator berada pada puncak fase serangan (katakanlah ) dan harus mendarat ke nilai yang dipertahankan pada , ia tidak dapat pergi ke sana dengan eksponensial sejati, karena eksponensial sejati menang ' t membusuk menjadi 0,5, itu hanya asimtotik pergi ke 0,5! y = 1 y = 0,5exy=1y=0.5

Jika Anda melihat generator amplop analog (misalnya rangkaian berbasis 7555 yang tampaknya semua orang gunakan ), Anda dapat melihat bahwa selama fase serangan, ketika kapasitor sedang diisi, itu "mengarah lebih tinggi" daripada ambang yang digunakan untuk menunjukkan akhir dari fase serangan. Pada (7) 555 berbasis sirkuit didukung oleh + 15V, Selama tahap serangan, kapasitor diisi dengan langkah + 15V, tetapi tahap serangan berakhir ketika ambang + 10V telah tercapai. Ini adalah pilihan desain, meskipun 2/3 adalah "angka ajaib" yang ditemukan di banyak generator amplop klasik, dan ini mungkin satu-satunya musisi yang akrab dengannya.

Beberapa bentuk ADSR dihasilkan dari "rasio tujuan" yang berbeda selama pengisian kapasitor

Dengan demikian, fungsi yang mungkin ingin Anda tangani bukanlah versi eksponensial, tetapi versi yang digeser / terpotong / skala, dan Anda harus membuat beberapa pilihan tentang seberapa "terjepit" Anda inginkan.

Saya tetap penasaran mengapa Anda mencoba untuk mendapatkan formula seperti itu - mungkin itu karena batas alat yang Anda gunakan untuk sintesis; tetapi jika Anda mencoba untuk mengimplementasikan yang menggunakan bahasa pemrograman tujuan umum (C, java, python) dengan beberapa kode berjalan untuk setiap sampel amplop, dan gagasan "negara", baca terus ... Karena selalu lebih mudah untuk mengungkapkan hal-hal sebagai "segmen tersebut akan berubah dari nilai apa pun yang baru saja mencapai 0".

Dua saran saya tentang penerapan amplop.

Yang pertama bukanuntuk mencoba skala semua kemiringan / peningkatan sehingga amplop tepat mencapai nilai awal dan akhir. Misalnya Anda menginginkan amplop yang bergerak dari 0,8 menjadi 0,2 dalam 2 detik, jadi Anda mungkin tergoda untuk menghitung kenaikan -0,3 / detik. Jangan lakukan itu. Sebagai gantinya, bagi menjadi dua langkah: dapatkan tanjakan yang bergerak dari 0 hingga 1.0 dalam 2 detik; dan kemudian menerapkan transformasi linear yang memetakan 0 hingga 0,8 dan 1,0 hingga 0,2. Ada dua keuntungan untuk bekerja dengan cara ini - yang pertama adalah bahwa hal itu menyederhanakan perhitungan yang akan Anda miliki relatif terhadap waktu amplop ke ramp dari 0 ke 1; yang kedua adalah bahwa jika Anda mengubah parameter amplop (kenaikan dan waktu mulai / akhir) di tengah-tengah semuanya akan tetap berperilaku baik. Baik jika Anda mengerjakan synth, karena orang akan meminta parameter waktu amplop sebagai tujuan modulasi.

Yang kedua adalah menggunakan tabel pencarian pra-komputasi dengan bentuk amplop. Ini lebih ringan secara komputasi, mengeluarkan banyak detail kotor (misalnya Anda tidak perlu repot dengan eksponensial yang tidak mencapai 0 persis - terpotong sesuai keinginan dan skala ulang sehingga dipetakan ke [0, 1]), dan itu sangat mudah untuk memberikan opsi untuk mengubah bentuk amplop, untuk setiap tahap.

Berikut adalah pseudo-code untuk pendekatan yang saya jelaskan.

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
pichenettes
sumber
Saya sepertinya menyelesaikan masalah saya dengan mengambil skala linier / persamaan dua titik dari y = ((y2 - y1) / (x2 - x1)) * (x - x1) + y1, menulis ulang dengan mengganti variabel x dengan e ^ x ke y = ((y2 - y1) / (e ^ x2 - e ^ x1)) * (e ^ x - e ^ x1) + y1. Sesi kalkulator saya di tautan menggambarkan pendekatan ini. Apakah mereka punya Gotcha untuk ini yang harus saya ketahui? Hasilnya tampak benar bagi saya.
Gary DeReese
Ini bukan bentuk amplop yang ditemukan pada synthesizer lain. Bergantung pada waktu / posisi relatif dari level awal dan akhir, ini dapat menjadi sangat linier.
pichenettes
@pichenettes, mungkin Anda bersedia menempelkan skrip yang menghasilkan amplop itu?
P i
3

Ini adalah pertanyaan yang cukup lama, tetapi saya hanya ingin menyoroti satu hal dalam jawaban dari pichenettes:

Misalnya Anda menginginkan amplop yang bergerak dari 0,8 menjadi 0,2 dalam 2 detik [...] pilah menjadi dua langkah: dapatkan tanjakan yang berjalan dari 0 hingga 1,0 dalam 2 detik; dan kemudian menerapkan transformasi linear yang memetakan 0 hingga 0,8 dan 1,0 hingga 0,2.

Proses ini kadang-kadang dikenal sebagai "pelonggaran," dan terlihat seperti

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

di mana dan adalah batas bawah dan atas (nilai yang mungkin adalah , , dan level penopang) dan adalah sesuatu seperti . Perhatikan bahwa Anda tidak memerlukan ini untuk fase serangan karena sudah berkisar dari hingga .u 0 1 f ( x ) x n 0 1lu01f(x)xn01

Inilah sesi Desmos asli, yang diperbarui untuk menggunakan pendekatan ini. Saya menggunakan bentuk kubik di sini, tetapi Anda * dapat menggunakan bentuk apa pun yang Anda suka, selama menghasilkan output mulai dari nol hingga satu input yang diberikan mulai dari nol hingga satu.f(x)

* Saya kira OP mungkin sudah lama hilang, tapi mungkin ini membantu orang lain.

Tamu
sumber
Terima kasih untuk ini, saya memprogram sampler untuk DAW saya seorang pengembang, dan terhubung ke formula yang disediakan di sesi Desmos dan mereka bekerja dengan sempurna. Tidak ada lagi amplop linear yang timpang! :)
Douglas
1

Tentang komentar pichenettes, "Selama tahap serangan, kapasitor diisi dengan langkah + 15V, tetapi tahap serangan berakhir ketika ambang + 10V telah tercapai. Ini adalah pilihan desain, meskipun 2/3 adalah" sihir " angka "ditemukan di banyak generator amplop klasik, dan ini mungkin satu-satunya musisi yang akrab dengannya.":

Setiap amplop yang memotret untuk asimtot 15v dengan target 10v, praktis, menciptakan serangan linier. Hanya saja 15v adalah asimtot tertinggi yang tersedia dengan mudah, dan cukup dekat dengan linier. Artinya, tidak ada "keajaiban" tentang hal itu — mereka hanya berjalan se linear yang bisa mereka dapatkan.

Saya tidak tahu berapa banyak synth klasik yang menggunakan 15v — saya menduga sering ada satu atau dua dioda drop. Modular Aries lama saya menggunakan 13v untuk amplop 10v, dan saya baru saja mencari chip Curtis ADSR yang menggunakan, setara, 6,5v untuk amplop 5v.

Nigel Redmon
sumber
1

Kode ini harus menghasilkan plot yang mirip dengan pichenettes:

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

Saya bersyukur atas perbaikan apa pun, satu hal yang mungkin merupakan ide yang baik adalah membiarkan tiga parameter terakhir (yang menentukan kecuraman masing-masing dari tiga tahap) bervariasi antara 0 dan 1, di mana 0,5 akan menjadi garis lurus. Tapi saya tidak bisa melihat langsung bagaimana melakukannya.

Juga saya belum menguji secara menyeluruh semua kasus penggunaan, misalnya jika satu tahap memiliki panjang nol.

P i
sumber