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,5e−xy=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.
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