Tôi nghĩ rằng điều khiến bạn bối rối là số mũ giảm dần ( ) không bao giờ đạt đến 0, do đó, một trình tạo ADSR với các phân đoạn theo cấp số nhân thực sự sẽ bị kẹt; bởi vì nó sẽ không bao giờ đạt được giá trị mục tiêu. Ví dụ: nếu máy phát ở độ cao của pha tấn công (giả sử ) và phải hạ cánh xuống giá trị bền vững ở , thì nó không thể đi đến đó với số mũ thực sự, bởi vì số mũ thực sự đã thắng ' T phân rã thành 0,5, nó sẽ chỉ bất thường đến 0,5! y = 1 y = 0,5e−xy=1y=0.5
Nếu bạn nhìn vào một bộ tạo phong bì tương tự (ví dụ như mạch dựa trên 7555 mà mọi người dường như sử dụng ), bạn có thể thấy rằng trong giai đoạn tấn công, khi tụ điện đang sạc, nó "nhắm cao hơn" so với ngưỡng được sử dụng để chỉ ra điểm kết thúc của giai đoạn tấn công. Trên một mạch dựa trên (7) 555 được cung cấp bởi + 15V, Trong giai đoạn tấn công, tụ điện được sạc với bước + 15V, nhưng giai đoạn tấn công kết thúc khi đạt đến ngưỡng + 10V. Đây là một lựa chọn thiết kế, mặc dù 2/3 là "số ma thuật" được tìm thấy trong nhiều trình tạo phong bì cổ điển và đây có thể là một nhạc sĩ quen thuộc.
Do đó, các chức năng bạn có thể muốn xử lý không phải là số mũ, mà là các phiên bản đã thay đổi / cắt bớt / chia tỷ lệ của nó, và bạn sẽ phải đưa ra một số lựa chọn về việc bạn muốn chúng bị "đè bẹp" như thế nào.
Dù sao tôi cũng tò mò về lý do tại sao bạn đang cố gắng để có được các công thức như vậy - có thể đó là do giới hạn của công cụ bạn đang sử dụng để tổng hợp; nhưng nếu bạn đang cố gắng thực hiện những ngôn ngữ đó bằng ngôn ngữ lập trình mục đích chung (C, java, python) với một số mã chạy cho từng mẫu của phong bì và một khái niệm về "trạng thái", hãy đọc tiếp ... Bởi vì nó luôn dễ dàng hơn diễn đạt những điều như "phân khúc như vậy sẽ đi từ bất kỳ giá trị nào nó vừa đạt đến 0".
Hai lời khuyên của tôi về việc thực hiện phong bì.
Người đầu tiên khôngđể cố gắng chia tỷ lệ tất cả các độ dốc / gia số sao cho đường bao chính xác đạt đến giá trị bắt đầu và kết thúc. Ví dụ: bạn muốn một phong bì đi từ 0,8 đến 0,2 trong 2 giây, do đó bạn có thể muốn tính toán mức tăng -0,3 / giây. Đừng làm vậy. Thay vào đó, hãy chia nó thành hai bước: lấy đoạn đường nối đi từ 0 đến 1 trong 2 giây; và sau đó áp dụng một biến đổi tuyến tính ánh xạ 0 đến 0,8 và 1,0 đến 0,2. Có hai ưu điểm để làm việc theo cách này - thứ nhất là đơn giản hóa mọi tính toán mà bạn có liên quan đến thời gian phong bì đến đoạn đường nối từ 0 đến 1; thứ hai là nếu bạn thay đổi các tham số phong bì (gia số và thời gian bắt đầu / kết thúc) giữa chừng thì mọi thứ sẽ vẫn hoạt động tốt. Tốt nếu bạn đang làm việc trên một synth, vì mọi người sẽ yêu cầu có các tham số thời gian phong bì làm đích điều chế.
Thứ hai là sử dụng bảng tra cứu được tính toán trước với hình dạng phong bì. Nó nhẹ hơn về mặt tính toán, nó lấy ra nhiều chi tiết bẩn (ví dụ: bạn không phải bận tâm với số mũ không đạt 0 chính xác - cắt nó theo ý thích của bạn và giải thích nó để nó được ánh xạ tới [0, 1]), và thật dễ dàng để cung cấp một tùy chọn để thay đổi hình dạng phong bì, cho từng giai đoạn.
Đây là mã giả cho cách tiếp cận tôi mô tả.
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