Звук скрипки программы Трио. Сценарий 43
Публикую текст сценария, алгоритм, по которому проводится вычисление амплитуды звука, а также текст функции, которая интерпретирует строку с мнемонической записью огибающей звука.
Текст сценария взят из модуля MUZ3, поэтому цифра 3 в названиях глобальных переменных, таких, например, как W3W или ARE3 означают просто номер модуля.
В модулях MUZ2 и MUZ1 сценарии аналогичны, с единственным исключением - там MU2 = 20.1 что создаёт в звуке лёгкое амплитудное вибрато.
Вспомогательная программа, устанавливающая тембр, извлекает дробную часть числа и цифры, входящие в целую часть числа (деля их на десять), в отдельные ячейки массива, которые после этого считываются в сценарии.
СЦЕНАРИЙ
Case 43 'viola поющая
MU2 = 20.001: AU2 = 4: DU2 = 150.999: If UD3b > 0 Then DU2 = UD3b '30.99 для короткого звука
B = 0.2: DK1 = 0.99: If By3 < 0 Then DU2 = 5.995: By3 = 0: AU2 = 6: B = 0.4 'b -лок.удар
DU3 = 10.999: If UD3c > 0 Then DU3 = UD3c
If ARE3 = 10 Then MU3 = 67.06: AU3 = 3: If Len(A3rr$) > 2 Then Arr$ = A3rr$
NDc = -1: Call Swv(0, 600.25): Call Swv(1, UW3 + UV3): 'начальный ТЕМБР
V = UX3: If By3 > 0 Then V = By3: By3 = 0 'огибающая звука: By имеет приоритет над UX
NDcn% = 1: dND = 0.2: ADSR$ = "10=7-9-94": If V = 1 Then ADSR$ = A31r$ '\\\\\\ ADSR$ краткое
If V = 2 Then ADSR$ = A32r$
If V = 3 Then ADSR$ = A33r$
If V > 0 Then 'в начале огибающей перед знаком $ может идти настройка тембра
E1 = InStr(ADSR$, "$"): If E1 > 0 Then Call Swv(1, Val(ADSR$)): ADSR$ = Mid(ADSR$, E1 + 1)
NDc = Val(ADSR$): DU2 = NDc + 0.99: End If
mod2 = 30 + wv(3) * 10: Vi = wv(0): Vh = wv(1): Eo = wv(2) 'окончательная установка тембра
If Rv3 > 0 Then B = Rv3 - Int(Rv3): If B > 0.6 Then B = 0.6 'rД.B B=0-.6 лок.регулировка эхо
RR(0) = 0: If Rv3 >= 1 Then V = FNRR(0, 3300.2 + B): V = FNRR(0, 4500.2 + B) 'Д=1 +дальнее эхо
V = FNRR(FS, 1209.3 + B): V = FNRR(FS, 926.2 + B): V = FNRR(FS, 540.1 + B): V = FNRR(20, -9)
Case -43: Vo = Eo + 0.3 * FNTIM(3, T) + 0.2 * FNTIM(8, T): If FS < 440 Then Vo = Vo * FS / 440 '\\\\\
E1 = 1: E1 = 1.2 + 0.2 * FNTIM(4, T): E2 = 1.1 + 0.3 * FNTIM(9, T)
If NT = NDc Then 'обработка огибающей
V = FNenv(ADSR$, NDcn%, FS): NDcn% = NDcn% + 1 + Len(comA$): 'следующий номер в ADSR$
Do While Len(comA$) > 0: Select Case Left(comA$, 1)
Case ".": If dND > 0.098 Then dND = dND - 0.05 'укорочение длительности фрагмента огибающей
Case ">": Vi = Vi / 1.12: Case "<": Vi = Vi * 1.12
Case "/": DT = DT * 1.0504631: Case "\": DT = DT / 1.0504631: Case "|": DT = DT0
Case "Ы": DT0 = DT: W3W = 5.5: Case "ы": DT0 = DT: W3W = 5.25: Case "_": DT = DT0: W3W = 0 'вибрато
End Select: comA$ = Mid(comA$, 2): Loop:
If V >= 0 Then NDc = Int(NDc + dND * FS): If V > 0 Then DU2 = V
dND = 0.2: End If
If W3W > 1 And AW < 1 Then AW = AW + 0.05 'плавное вхождение в вибрато
If W3W > 1 Then DT = DT0 * (1 + AW * (W3W - Int(W3W)) * 0.1 * FNTIM(Int(W3W), T)) 'вибрато
___________
АЛГОРИТМ вычисления амплитуды A2
Case 36 ' viola 36 /\_A_/\_A_/\_A_
B = 1 / Vi: B = B ^ 3: V = X - Vo: If V < 0 Then V = 2 + V
If V > 2 Then V = V - 2
V = V - 1: A2 = (V * V * V - V) / 0.3849 + 1: If A2 < 0 Then A2 = 0
A2 = (A2 / 2) ^ B
A2h = 0: V = X - 2 * Vo: If V < 0 Then V = 2 + V
If V > 2 Then V = V - 2
V = V - 1: A2h = (V * V * V - V) / 0.3849 + 1: If A2h < 0 Then A2h = 0
A2h = (A2h / 2) ^ B
A2 = A2 + A2h * Vh
B = (1 / B) ^ 0.737: A2 = A2 - B / (1 + B)
Case 37 ' viola 37 _/\_/\_ другой пичок
V = X - Vo: If V < 0 Then V = 2 + V
If V > 2 Then V = V - 2
V = V - 1: B = E1: If V > 0 Then B = 2 - E1 'при E1=1 пичок симметричный
A2 = V * B / Vi: A2 = (A2 * A2 + 0.9) ^ 8 + 1
A2 = 1.428 / A2: A2 = (A2 + A2 ^ 4) / 2
A2h = 0: V = X - 2 * Vo: If V < 0 Then V = 2 + V
If V > 2 Then V = V - 2
V = V - 1: B = E2: If V > 0 Then B = 2 - E2 'при E2=1 пичок симметричный
A2h = V * B / Vi: A2h = (A2h * A2h + 0.9) ^ 8 + 1
A2h = 1.428 / A2h: A2h = (A2h + A2h ^ 4) / 2
A2 = A2 + A2h * Vh
____________
ФУНКЦИЯ FNenv, интерпретирующая строку ADSR$,
вычисляет коэффициент ослабления для фрагмента огибающей,
возвращает -1 если строка окончена, и 0 если фрагмент продолжается
Public Function FNenv(C$, N%, F As Double) As Double
Dim S$: Dim A$: Dim B$: Dim N1%: Dim L%: Dim AA As Single: Dim BB As Single
Dim I%: Dim dI%:
comA$ = "": FNenv = -1: S$ = C$: I% = InStr(S$, "=")
If I% > 0 Then S$ = Mid(S$, I% + 1): L% = Len(S$): N1% = N% Else Exit Function
Menv1:
If N1% > L% Then Exit Function Else A$ = Mid(S$, N1%, 1)
AA = Val(A$): If AA > 0 And I% > 0 Then I% = 0: dI% = 4: GoTo Menv2
If A$ = "-" And I% > 0 Then N1% = N1% + 1: I% = 0: GoTo Menv1
If A$ = "-" Then FNenv = 0: Exit Function
If AA = 0 Then comA$ = comA$ + A$: N1% = N1% + 1: GoTo Menv1
FNenv = 0: Exit Function
Menv2:
N1% = N1% + 1: If N1% > L% Then FNenv = -1: Exit Function
B$ = Mid(S$, N1%, 1): If B$ = "-" Then I% = I% + dI%: dI% = 4: GoTo Menv2
BB = Val(B$): If B$ = "." And dI% > 1 Then dI% = dI% - 1
If BB = 0 Then
I% = 0 Then comA$ = comA$ + B$
GoTo Menv2: End If
I% = I% + dI%: AA = BB / AA: AA = Log(AA) / (I% * 0.05 * F)
FNenv = Exp(AA)
End Function
_________
'===== Подпрограмма, устанавливающая тембр
' имеет два режима работы: 0 -установить, 1 -заменить.
Public Sub Swv(K%, A As Single) 'извлечение параметров тембра
Dim B As Single, B1 As Single, R As Single, I As Integer, M As Integer
M = K%: B = A: For I = 0 To 6
B1 = Int(B): R = B - B1: If M = 1 And R > 0 Then wv(I) = R
If M = 0 Then wv(I) = R: If R = 0 Then wv(I) = 1
B = B1 / 10
Next I
End Sub
_____________________
Свидетельство о публикации №219031700719