ช่วยสมการสำหรับซองจดหมาย ADSR แบบเลขชี้กำลัง


11

ด้วยรหัสแอปพลิเคชันฉันได้ติดตั้งซอง ADSR แบบเส้นตรงเพื่อสร้างแอมพลิจูดของเอาต์พุตออสซิลเลเตอร์ พารามิเตอร์สำหรับการโจมตีการสลายตัวและระยะเวลาการปล่อยเช่นเดียวกับระดับการรักษาสามารถตั้งค่าบนซองจดหมายและทุกอย่างทำงานตามที่คาดไว้

อย่างไรก็ตามฉันต้องการปรับแต่งรูปร่างของทางลาดให้คล้ายกับสิ่งที่ซินธิไซเซอร์ส่วนใหญ่ใช้สำหรับการตอบสนองที่เป็นธรรมชาติมากขึ้น: ผกผันเลขชี้กำลังสำหรับการโจมตีและเลขชี้กำลังสำหรับการสลายตัวและการปลดปล่อย ฉันมีปัญหาในการทำให้สูตรถูกต้องสำหรับการคำนวณค่าผลลัพธ์ของซองจดหมายสำหรับรูปร่างของทางลาดประเภทนี้ ในการคำนวณทางลาดเชิงเส้นฉันใช้รูปแบบสองจุดเสียบค่าเริ่มต้น / สิ้นสุด /ซึ่งได้มาจากค่าพารามิเตอร์อินพุตการโจมตี / การสลายตัว / การคงอยู่ / การปล่อย ฉันไม่สามารถหาสูตรที่ถูกต้องสำหรับทางลาดแบบเอ็กซ์โปเนนเชียล (แบบมาตรฐานและแบบผกผัน) โดยใช้ค่าจุดเริ่มต้น / สิ้นสุด /เดียวกันxyxy

ฉันบันทึกเซสชั่นเครื่องคิดเลขกราฟ Desmosที่แสดงให้เห็นถึงวิธีการทางลาดเชิงเส้นที่ฉันอธิบายไว้ข้างต้น

หากใครสามารถช่วยชี้ให้ฉันในทิศทางที่ถูกต้องมันจะได้รับการชื่นชมมาก

คำตอบ:


10

ฉันคิดว่าสิ่งที่คุณสับสนคือเลขชี้กำลังลดลง ( ) ไม่ถึง 0 ดังนั้นตัวสร้าง ADSR ที่มีเซ็กเมนต์อธิบายอย่างแท้จริงจะติดอยู่ เพราะมันจะไม่ถึงค่าเป้าหมาย ตัวอย่างเช่นหากเครื่องกำเนิดไฟฟ้าอยู่ที่ระดับสูงสุดของระยะการโจมตี (พูดว่า ) และต้องลงจอดเพื่อรักษาค่าที่มันจะไม่สามารถไปที่นั่นพร้อมกับเลขชี้กำลังจริงเพราะเลขชี้กำลังที่แท้จริงชนะ ' ไม่สลายตัวถึง 0.5 มันจะไปที่ asymptotically 0.5 เท่านั้น! y = 1 y = 0.5exy=1y=0.5

หากคุณดูที่เครื่องสร้างซองจดหมายแบบแอนะล็อก (ตัวอย่างเช่นวงจรที่ใช้ 7555 ที่ทุกคนดูเหมือนจะใช้ ) คุณจะเห็นว่าในช่วงการโจมตีเมื่อตัวเก็บประจุกำลังชาร์จประจุมันคือ "เล็งที่สูงขึ้น" กว่าเกณฑ์ที่ใช้เพื่อระบุจุดสิ้นสุด ของระยะการโจมตี บนวงจรที่ใช้วงจร (7) 555 ตัวขับเคลื่อนโดย +15V ในระหว่างขั้นตอนการโจมตีตัวเก็บประจุจะถูกชาร์จด้วยขั้นตอน +15V แต่ขั้นตอนการโจมตีจะสิ้นสุดลงเมื่อถึงเกณฑ์ + 10V นี่คือตัวเลือกการออกแบบแม้ว่า2/3 จะเป็น "หมายเลขเวทมนตร์" ที่พบในเครื่องกำเนิดซองจดหมายแบบคลาสสิกจำนวนมากและนี่อาจเป็นสิ่งที่นักดนตรีคนหนึ่งคุ้นเคย

รูปร่าง ADSR บางส่วนเป็นผลมาจาก "อัตราส่วนการเล็ง" ที่แตกต่างกันระหว่างประจุ

ดังนั้นฟังก์ชั่นที่คุณอาจต้องการจัดการไม่ใช่แบบเอ็กซ์โปเนนเชียล แต่เปลี่ยน / ตัดทอน / ปรับขนาดเวอร์ชั่นของมันแล้วคุณจะต้องเลือกบางอย่างว่า "แบน" คุณต้องการให้มันเป็นอย่างไร

ฉันสงสัยอยู่แล้วว่าทำไมคุณถึงพยายามใช้สูตรดังกล่าว - อาจเป็นเพราะข้อ จำกัด ของเครื่องมือที่คุณใช้ในการสังเคราะห์ แต่ถ้าคุณกำลังพยายามที่จะใช้สิ่งเหล่านั้นโดยใช้ภาษาโปรแกรมทั่วไป (C, java, python) โดยมีโค้ดที่ใช้สำหรับแต่ละตัวอย่างของซองจดหมายและแนวคิดของ "สถานะ" อ่านต่อ ... เพราะง่ายกว่าเสมอ แสดงสิ่งต่าง ๆ ว่า "ส่วนดังกล่าวจะเปลี่ยนจากมูลค่าใด ๆ ที่เพิ่งถึง 0"

คำแนะนำสองข้อของฉันในการติดตั้งซองจดหมาย

คนแรกไม่ใช่เพื่อพยายามปรับสเกลลาด / ส่วนที่เพิ่มขึ้นทั้งหมดเพื่อให้ซองจดหมายถึงค่าเริ่มต้นและค่าสิ้นสุด ตัวอย่างเช่นคุณต้องการซองจดหมายที่เพิ่มขึ้นจาก 0.8 เป็น 0.2 ใน 2 วินาทีดังนั้นคุณอาจถูกคำนวณให้เพิ่ม -0.3 / วินาที อย่าทำอย่างนั้น ให้แบ่งออกเป็นสองขั้นตอนแทนรับทางลาดที่ไปจาก 0 ถึง 1.0 ใน 2 วินาที; จากนั้นใช้การแปลงเชิงเส้นที่แมป 0 ถึง 0.8 และ 1.0 ถึง 0.2 การทำงานด้วยวิธีนี้มีข้อดีสองข้อข้อแรกคือช่วยลดความยุ่งยากในการคำนวณใด ๆ ที่คุณจะสัมพันธ์กับเวลาของซองจดหมายไปยังทางลาดจาก 0 ถึง 1 อย่างที่สองคือถ้าคุณเปลี่ยนพารามิเตอร์ของซองจดหมาย (เพิ่มขึ้นและเวลาเริ่ม / สิ้นสุด) ตรงกลางทุกอย่างจะยังคงทำงานได้ดี ดีถ้าคุณกำลังทำงานกับ synth เพราะคนจะขอให้มีพารามิเตอร์เวลาซองจดหมายเป็นปลายทางการปรับ

ที่สองคือการใช้ตารางการค้นหาที่คำนวณล่วงหน้าด้วยรูปร่างซองจดหมาย มันเบากว่าการคำนวณใช้รายละเอียดที่สกปรกมาก (ตัวอย่างเช่นคุณไม่ต้องกังวลกับเลขยกกำลังที่ไม่ถึง 0 - ตัดมันด้วยความตั้งใจของคุณและช่วยให้มันเป็นแมป [0, 1]) และมันก็ตายง่ายที่จะให้ทางเลือกในการเปลี่ยนรูปร่างของซองจดหมายสำหรับแต่ละขั้นตอน

นี่คือรหัสหลอกสำหรับวิธีที่ฉันอธิบาย

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

ฉันดูเหมือนว่าจะแก้ปัญหาของฉันโดยใช้สมการสเกลเชิงเส้น / สมการสองจุดของ y = ((y2 - y1) / (x2 - x1)) * (x - x1) + y1, เขียนมันใหม่โดยแทนที่ตัวแปร x ด้วย e ^ x ถึง y = ((y2 - y1) / (e ^ x2 - e ^ x1)) * (e ^ x - e ^ x1) + y1 เซสชั่นเครื่องคิดเลขของฉันที่ลิงค์แสดงวิธีการนี้ เป็น gotchas ใด ๆ ของพวกเขาเพื่อสิ่งนี้ที่ฉันควรระวัง? ผลลัพธ์ดูเหมือนถูกต้องสำหรับฉัน
Gary DeReese

นี่ไม่ใช่รูปทรงซองจดหมายที่พบในสารสังเคราะห์อื่น ๆ ขึ้นอยู่กับเวลา / ตำแหน่งสัมพัทธ์ของระดับเริ่มต้นและสิ้นสุดมันสามารถกลายเป็นเส้นตรงมาก
pichenettes

@pichenettes คุณยินดีที่จะวางสคริปต์ที่สร้างซองจดหมายเหล่านั้นหรือไม่
ฉัน

3

นี่เป็นคำถามที่ค่อนข้างเก่า แต่ฉันต้องการเน้นจุดในคำตอบจาก pichenettes:

ตัวอย่างเช่นคุณต้องการซองจดหมายที่เพิ่มขึ้นจาก 0.8 เป็น 0.2 ใน 2 วินาที [... ] แบ่งออกเป็นสองขั้นตอน: รับทางลาดที่เพิ่มจาก 0 ถึง 1.0 ใน 2 วินาที; จากนั้นใช้การแปลงเชิงเส้นที่แมป 0 ถึง 0.8 และ 1.0 ถึง 0.2

บางครั้งกระบวนการนี้เรียกว่า "การทำให้สบาย" และดูเหมือนว่า

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

ที่และเป็นที่ต่ำกว่าและขอบเขตบน (ค่าที่เป็นไปได้เป็น ,และระดับรักษา) และเป็นสิ่งที่ต้องการ n โปรดทราบว่าคุณไม่จำเป็นต้องนี้สำหรับระยะโจมตีเพราะมันมีอยู่แล้วในช่วงจากที่จะ1คุณ0 1 f ( x ) x n 0 1lu01f(x)xn01

(x)

* ฉันเดาว่า OP อาจจะหายไปนาน แต่อาจช่วยคนอื่นได้


ขอบคุณสำหรับสิ่งนี้ฉันกำลังเขียนโปรแกรมตัวอย่างสำหรับ DAW ฉันเป็นนักพัฒนาและเสียบเข้ากับสูตรที่ให้ไว้ในเซสชัน Desmos และพวกเขาทำงานได้อย่างสมบูรณ์ ไม่มีซองจดหมายเชิงเส้นง่อยอีกต่อไป! :)
ดักลาส

1

เกี่ยวกับความคิดเห็นของ pichenettes "ในช่วงการโจมตีตัวเก็บประจุจะถูกชาร์จด้วยขั้นตอน +15V แต่ขั้นตอนการโจมตีจะสิ้นสุดลงเมื่อถึงขีด จำกัด + 10V แล้วนี่คือตัวเลือกการออกแบบแม้ว่า 2/3 จะเป็น" เวทมนต์ " หมายเลข "พบในเครื่องกำเนิดซองจดหมายคลาสสิกจำนวนมากและนี่อาจเป็นสิ่งที่นักดนตรีคนหนึ่งคุ้นเคย"

ซองจดหมายใด ๆ ที่กำลังถ่ายทำสำหรับเส้นกำกับ 15v กับเป้าหมาย 10v คือในทางปฏิบัติจะสร้างการโจมตีเชิงเส้น มันเป็นเพียงว่า 15v เป็นเส้นกำกับสูงสุดที่หาได้ง่ายและอยู่ใกล้กับเส้นตรง นั่นคือไม่มีอะไร "วิเศษ" เกี่ยวกับมัน - พวกเขาเพียงแค่จะเป็นเชิงเส้นเท่าที่พวกเขาจะได้รับ

ฉันไม่ทราบว่า synths คลาสสิกจำนวนเท่าใดใช้ 15v - ฉันสงสัยว่ามักจะมีไดโอดดรอปหรือสองตัว ราศีเมษแบบโมดูลาร์เก่าของฉันใช้ 13v สำหรับซองจดหมาย 10v และฉันเพิ่งค้นหาชิป Curtis ADSR ที่ใช้เทียบเท่ากับ 6.5v สำหรับซองจดหมาย 5v


1

รหัสนี้ควรสร้างแปลงคล้ายกับของ 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

ฉันรู้สึกขอบคุณสำหรับการปรับปรุงใด ๆ สิ่งหนึ่งที่อาจเป็นความคิดที่ดีคือการอนุญาตให้พารามิเตอร์สามตัวสุดท้าย (ซึ่งกำหนดความชันของแต่ละสามขั้นตอน) จะแตกต่างกันระหว่าง 0 และ 1 โดยที่ 0.5 จะเป็นเส้นตรง แต่ฉันไม่สามารถเห็นวิธีการทำในทันที

นอกจากนี้ฉันยังไม่ได้ทดสอบกรณีการใช้งานทั้งหมดอย่างละเอียดเช่นหากด่านหนึ่งมีความยาวเป็นศูนย์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.