Моделирование звука альта

  В предыдущих статьях рассказывалось об успешном  моделировании звуков фортепьяно и звука аккордеона. В этом моделировании, при несколько различных подходах к нему, удавалось находить некую особую форму звука, обеспечивающую удовлетворительное и похожее звучание для каждого инструмента, и как-то удалось обойтись без привлечения эха.
  Но моделирование звука альта пошло по другому пути. 
  Оказалось, что в аспекте математического моделирования альт - инструмент с очень простым звуком, и с очень непростым эхом. Но, давайте, я расскажу всё по порядку, и с самого начала, так, будто Вы прошлых статей не читали. А заодно вспомним о WAV файлах и способе записи звука в них, и о том, как с помощью компьютера можно делать такие файлы.


КАК СДЕЛАТЬ ЗВУК И ПОМЕСТИТЬ ЕГО В ФАЙЛ

  Давайте, напишем небольшую программу для этого.
  Если мы хотим сделать звук альта или скрипки, то для этого нам понадобится ревербератор, а ревербератор будет использовать большой массив, в который будут помещаться амплитуды звуков для создания эха. Укажем размер этого массива:
DIM R(5000)

  Прежде чем помещать звук в файл, файл следует открыть и указать на начало записи. В Турбо Бейсике это делается так:
OPEN "B",#1,"r.wav" ' - открываем файл "r.wav" и присваиваем ему внутренний номер #1
  SEEK #1,44 ' - устанавливаем поинтер файла #1 на 44, это первый байт первого семпла для записи звука.
  Кроме того заведём переменную VEL и запишем в неё число 32000:
VEL=32000 '- мы указываем на скорость записи или скорость раздачи семплов, она будет равна 32000 семплов/сек

  В звуковых файлах с расширением WAV  звуки находятся в виде последовательности семплов. Семпл, это единица звука. Для обычной монозаписи это два байта - строка из двух символов, коды которых используются для составления целого числа. Например, строка из 2-х пробелов "  " (а мы знаем, что код пробела равен 32) будет интерпретирована как положительное число 32*256+32=8224.

  Один семпл => два байта => число от -16384 до 16384, которое называется текущей амплитудой звука.
  Величины большие и труднопредставимые, легче иметь дело с числами в пределах от единицы до четырёх.
  Поэтому мы будем стараться создавать звук  с небольшой амплитудой - около единицы, в пределах не более 4-х.  А потом умножать созданную нами амплитуду на 4000, записывая полученное значение в виде целого числа M%, потом - переводить целое число в двухбайтовую символьную запись семпла, потом - записывать полученный семпл в файл.
 Всё это делается так:
    M%=INT(4000*FNS1(260.74,6)) : PUT$ #1,MKI$(M%) 

здесь следует обратить внимание на обращение   FNS1(260.74,6) - мы обращается к функции создания звука, и указываем параметры 260.74 - частота ноты До первой октавы, 6 - сценарий, по которому будет создаваться звук.
В результате этого обращения мы получим в приведённой выше строке, в скобках, на месте FNS1 некое число - вычисленную функцией FNS1 амплитуду звука.
  Умножаем её на 4000, с помощью функции INT переводим в целочисленную форму и присваиваем полученное целое значение переменной  M%.
  Следующий в строке за двоеточием оператор PUT$ #1 добавляет в наш файл один семпл - символьное значение целого числа, содержащегося в переменной M%. Перевод из целой формы в символьную делает специальная функция Бейсика MKI$().

   Мы записали в файл "r.wav" первый семпл звука До. Только первый. Но таких семплов  нужно очень много, смотрите, какая скорость записи - 32000 семплов для каждой секунды звучания.
  Но тут всё совсем просто. Только нужно не забыть сообщить функции создания звука, чтобы она приготовилась работать с самого начала возникновения звука, а не с его середины.
 
   A=FNS1(0,0) - по такому обращения функция ничего не делает,
но запоминает  параметры 0 и 0. Обратимся затем к функции по-другому - FNS1(260.74,6) она вновь запомнит значения 260.74 и 6, но уже начнёт делать звук. И начнёт делать звук с начала - прочитает сценарий номер 6, организует постепенное нарастание звука, подключит на начальной стадии развития звука дополнительные обертоны, приготовится создавать разные звуковые нюансы - сделает все так, как записано в начальной установке по сценарию номер 6.
    При последующих таких же обращениях она поймёт, что параметры не изменились, и не начнёт с начала, а будет продолжать развивать звук и возвратит амплитуду следующего семпла. И так 64000 раз подряд, если хотите, чтобы звук альта звучал 2 секунды.

    Это не значит, что все 2 секунды мы будем слышать один и тот же занудный звук. Нет, звук будет меняться, и не только потому, что параметры его изменения были взяты из сценария 6 при первом обращении.
    После отработки каждого периода звука, а длина периода составляет VEL/F семплов - для  частоты F=440 Гц на каждый период приходится чуть меньше 73-х семплов, - после отработки каждого периода происходит прочтение второй части сценария (если она есть и помечена отрицательным номером -6). В момент этого прочтения и в подходящее для этого время (а время, отсчитанное от начала звука содержится в переменной T) можно кое-что поменять.
  Например, можно начать постепенно, с каждым новым периодом, изменять шаг между семплами по переменной T.
  Этот шаг был установлен при первом обращении по формуле DT=1/VEL. Идя по переменной T с таким шагом и проводя на каждом новом шаге вычисления амплитуды, мы проходим путь от начала периода до его конца за время 1/F  (время одного периода звукового колебания) и создаём на этом пути VEL/F семплов.
   Но если мы увеличиваем шаг DT, то уменьшаем количество семплов, создаваемых за один период, а поскольку раздача семплов будет идти всё с той же частотой 32000 семпла в секунду, то на слух увеличение шага продвижения по координате T будет восприниматься, как повышение частоты звука. Таким способом, начав постепенно увеличивать шаг DT через некоторое время после начала звука можно организовать глиссандо по частоте вверх.
  В общем, сложных возможностей всяких много. Но показываю наш простой, начальный участок программы:

DIM R(5000)
OPEN "B",#1,"r.wav"
 SEEK #1,44
VEL=32000 : A=FNSS3(0,0)
FOR I=1 TO 64000 : M%=INT(4000*FNSS3(260.74,9)) : PUT$ #1,MKI$(M%) : NEXT I
GOSUB 1000
CLOSE #1 : STOP
...
далее идут многие строки, описывающие функцию FNS1, о ней см. в статье -
 http://www.proza.ru/2016/03/05/1095
 
подпрограмма 1000, определяющая длину файла и записывающая в начало файла его "шапку",
некоторые вспомогательные функции,
и описание функции FNR1(A,N) - ревербератор, о котором говорилось в статье -
 http://www.proza.ru/2016/03/07/1229

   Хотите сделать в записи несколько звуков - пожалуйста, напишите несколько строк FOR... указывая в них для функции FNS1 другие параметры.
   Хотите повторить тот же звук, не прибегая к начальной установке A=FNS1(0,0)?
   Измените совсем немного частоту в новой строке, напишите не 260.74, а 269.75 - для слуха разницы никакой, а функция FNS1 подумает, что это совершенно новая частота, и начнёт звук с его начала.

   Хотите вставить небольшие паузы? Вставьте строки:
         FOR I=1 TO 1000 : PUT$ #1,MKI$(0) : NEXT I
можете таким способом записать альтовое звучание нескольких нот, а затем, в звуковом редакторе, присоединить к ней другую, ранее созданную запись - и получите небольшую мелодию.
  Итак, мы вернулись к разговору об альте и о его звуке.


ОЧЕНЬ ПРОСТОЙ ЗВУК АЛЬТА

  Звук альта до ужаса простой, вот он -  /\____/\____/\____/\____ треугольная форма звука, сосредоточенная в первом периоде колебания. Я пробовал разные варианты - и асимметричные, и сглаженные вершинки, и несколько переколебаний - разницы никакой. Но тембр звучания зависит от ширины основания треугольника - чем уже основание, тем резче звук. Обозначим ширину основания треугольника буквами Vi и введём соответствующую переменную.
   Мы говорили о том, что период звукового колебания соответствует интервалу изменения переменной T от начала периода до его конца.
   Чтобы унифицировать выработку формы сигнала для различных частот, интервалу времени от начала, и до конца каждого периода ставится в соответствие внутренняя переменная X с интервалом изменения от 0 до 2-х.
   Присвоение Vi=.4 установит  для звука альта ширину основания треугольника и укажет на положение его вершины X=.2
   Совсем простенький фрагмент программы нарисует профиль амплитуды звука:

  CASE 3  ' viola  /\___/\___/\___
     IF X<Vi THEN
       IF X<Vi/2 THEN A2=2*X/Vi ELSE A2=2*(Vi-X)/Vi
       ELSE : A2=0
     END IF
     A=A-Vi/4  'эта последняя строка выравнивает площадь профиля относительно нулевого уровня амплитуд.
   Выравнивать профиль относительно нулевого уровня вовсе не обязательно - звучит точно так же, просто не очень естественно и непривычно видеть. что все выбросы и пики звука идут в одну сторону от нулевой линии.

   Звук альта получился простенький. И звучит он также простенько, и сходство со звуком настоящего альта у нашего звука не очень уж.
   Я решил пойти навстречу реальному звука и изобразить в форме звука простейшую физику процесса. Взгляните на рисунок - средний график, там, где написано Vo=0. Посмотрите на ход колебания от координаты X=0 до координаты X=2.

   В точке X=0 смычок захватил струну и потащил её вверх. На вершине своего отклонения струна сорвалась и пролетела обратно, и, по инерции, - ещё немного.
   Что происходит со струной потом - не совсем понятно. Она может совершать переколебания, прежде чем опять сцепиться со смычком, а может затормозиться трением о смычок и, не совершая дополнительных колебаний, вернуться к нулевой линии, так, как показано на рисунке. Я выбрал последний, простейший вариант и описал его следующим алгоритмом, по которому и был получен график рисунка, его средняя часть:

   CASE 31  ' viola 31 /\,__/\,__/\,___
     IF Vi<.01 THEN Vi=.01
     B=0 : IF Vi<=1 THEN B=.5*Vi*Vi/(2-Vi)
     IF X<Vi+B THEN
       IF X<Vi/2 THEN A2=2*X/Vi ELSE A2=2*(Vi-X)/Vi
       ELSE : A2=0 : IF Vi<=1 THEN A2=2*B*(X-2)/Vi/(2-Vi-B)
     END IF

  Звук на слух практически не изменился нисколько.
  Я пропустил звук через ревербератор. После треугольного пичка появились его уменьшенные копии - такие же треугольные эхо.
  Звук стал глубже, но он оставался монотонным, несмотря на то, что эхо чувствовалось.
  И я понял - пичок нужно двигать. И в самом деле, смычок не подцепляет струну в строго определённые моменты времени, это случается то раньше, то несколько позже.
  Следующий фрагмент программы позволяет смещать пичок на величину Vo вправо, так как это показано на верхнем графике рисунка, или влево - как на нижнем.

  CASE 32,33,34  ' viola 31 _/\,__/\,__/\,__
     V=X-Vo : IF V<0 THEN V=2+V
     IF mod2=32 THEN IF V>2 THEN V=V-2
     IF Vi<.01 THEN Vi=.01
     B=0 : IF Vi<=1 THEN B=.5*Vi*Vi/(2-Vi)
     IF V<Vi+B THEN
       IF V<Vi/2 THEN A2=2*V/Vi ELSE A2=2*(Vi-V)/Vi
       ELSE : A2=0 : IF Vi<=1 THEN A2=2*B*(V-2)/Vi/(2-Vi-B)
     END IF
     IF mod2=34 AND Vh>1 THEN 'case 34 _/``\,__/``\,__/``\,__
        IF A2>0 THEN A2=A2*Vh : IF A2>1 THEN A2=1
        IF A2<0 THEN A2=A2*(2*Vh-1)/Vh
     END IF

  Выбор CASE 32 просто перемещает пичок, CASE 33 при смещении за ноль срезает пичок, создавая вертикальный фронт, что придаёт звуку резкость с металлическим призвуком. CASE 34 увеличивает пичок по вертикали в Vh раз и срезает вершину на уровне 1. Получается пичок с плоской вершиной и задающий несколько другой тембр звучания.

  Но это - подробности. Нас интересует результат движения пичков.
  Результат обнадёживающий, звук получается более динамичный и живой.
  На осциллограммах рисунка справа Вы можете видеть общий профиль двух динамичных звуков, а также формы колебаний для CASE 32 (сверху) и CASE 33 (звонкое эхо).
На осциллограммах заметно, что пички эха внутри периодов не являются  точным повторением друг друга. Их форма и амплитуда меняются.

  Запись становления звука альта путём добавления эха и включения динамики пичков можно прослушать тут - https://yadi.sk/d/2_JJD1REpzBGm
 Первые 4 звука - исходная чистая форма без эха.
 Вторые 4 звука - статичные пички с эхом.
 Третьи звуки - динамичные пички по CASE 32 с тем же эхом.
 Четвёртые 4 звука - то же для CASE 33 (звонкое эхо)
 
 Последние две группы звуков - агрессивный звук альта без эха и с эхом.
 Агрессивный звук альта включает в себя два квазиобертона (4 и 8), один из которых короткозвучащий и басовитый благодаря отрицательному значению фактора DU7.
Звуки эти сделаны по следующему сценарию (без эха):

  CASE 6 'agressive alt sound
      MU2=INT(32*F/220)+.1 : AU2=4 : DU2=160.998
      mod2=33 : Vi=.35 ': Vh=.5
      MU5=-304 : AU5=1 : DU5=.998 : oKA=5
      MU7=-308 : AU7=5 : DU7=-.85  : DK1=.94
      V=FNR1(F,101006.4) : V=FNR1(2,102006.4) : V=FNR1(25,-12)
  CASE -6 : IF NT=100 THEN MU2=MU2*2-.1
      Vo=.1*FNTIM(16/(1+T),T)

  В сценарии для оживления звука кроме обертонов MU5 и MU7 использовано также вибрато MU2 и его замедление по прошествии 100-го периода. Последняя строка с помощью периодической функции FNTIM передвигает пичок в пределах +-.1 с начальной частотой 16 Гц, постепенно уменьшая частоту передвижения (до 8 Гц через секунду развития звука).
  Задание oKA=5 указывает на длительность фазы атаки (число периодов = 5) при развитии обертонов.
==============

P.S.
Со времени написания этой статьи прошло 3 года, музыкальный проект получил дальнейшее развитие. Программы переведены из Турбо_Бейсика на платформу Визуал_Бейсик_6, получили хорошую эргономику и расширение Help, в котором объясняется, как они работают.
Скачать все программы проекта можно тут - http://yadi.sk/d/VEN-Ok3B3NiUqj
Там же есть обзорные статьи по современному состоянию проекта.
__________
      23.04.2019


Рецензии