Available Languages?:

Пример использования OSA: QUARTET

Проект

Программа quartet синтезирует мелодию по заданным нотам (используется фрагмент произведения И.С.Баха N1067). Файл quartet4.rar нужно распаковать в папку "C:\TEST\QUARTET". В папке проект для PIC16F628A.

Программа генерирует 4-канальную мелодию, используя 8-разрядный ШИМ с частотой 78 КГц. Мелодия играется четырьмя инструментами: басс, скрипка и 2 гитары (конечно, названия условны, т.к. звуки не очень похожи на настоящие инструменты). Каждый канал может быть включен или выключен с помощью переключателей.

Вот MP3 (скачать), записанный с выхода этого устройства.

Принципиальная схема

Ниже приведена схема включения ПИКа. 8-разрядный цифровой ШИМ-сигнал сглаживается RC-фильтром R22-C3 и через резистор R24 (для регулирования громкости) поступает на наушники.

quartet_pwm.jpg

Переключатель SW1 включает/отключает басс.
Переключатель SW2 включает/отключает скрипку.
Переключатель SW3 включает/отключает первую гитару.
Переключатель SW4 включает/отключает вторую гитару.

Описание работы

Программа состоит из следующих файлов:

  • quartet_main.c - основная программа: задачи, функции по чтению нот.
  • music.c - формальное описание музыки: содержит 4 массива с нотами для каждого канала.
  • sinus.c - содержит по одному периоду синуса для каждого иструмента. Из этих таблиц генерируется сигнал.
  • interrupt.c - содержит код синтезатора звука. Он весь помещен в прерывание по TMR2 (вызывается раз в 100 мкс).

Ниже подробно рассмотрим работу задач из файла quartet_main.c.

Наша программа состоит из 5 задач. Грубо говоря, 4 задачи - музыканты, каждый со своим инструментом, и 5-я задача - дирижер, который синхронизирует работу первых 4-х.

Управление звуком

Для уравления звуком в прорамме определен тип TSound, который содержит всю информацию о звуке для "музыканта":

  • какую ноту играем;
  • и из какой нотной тетради;
  • держим ли паузу;
  • повторяем ли фрагмент;

для "дирижера":

  • когда он должен дать следующую команду;
  • закончились ли ноты у "музыканта";

для синтезатора:

  • частота текущей ноты;
  • текущее время ее звучания (для правильного формирования огибающей);

"Музыканты"

В программе 4 "музыканта": Task_BASS, Task_VIOLIN, Task_GUITAR1, Task_GUITAR2. Все "музыканты" постоянно находятся в режиме ожидания команды от "дирижера" (в виде бинарного семафора). Получив команду, "музыкант" вычитывает следующую ноту из своего нотного стана, играет ее (формирует данные для синтезатора звука в interrupt.c).

Обработка ноты происходит в функции NoteWork(), куда в качестве параметра передается переменная управления звуком TSound. По ней вычитывается следуюая нота (или инструкция: повтор, пауза и пр.) и выполняются операции по формированию указаний синтезатору, а также формируется длительность текущей ноты (паузы), которая уменьшается на 1 каждый раз при получении команды от "дирижeра".

Когда "музыкант" доходит до конца нотной тетради, он сообщает "дирижеру", что у него закончились ноты (сбрасывает флаг в переменной flag_Playing). После чего становится в ожидание команды от "дирижера" начать музыку сначала (в виде бинарного семафора). Получив эту команду, "музыкант" переходит в начало нотной теради (переменная управления звуком переинициализируется) и передает команду "дирижера" следующему "музыканту".

"Дирижер"

Задача Task_CONDUCTOR ("дирижер") имеет низший приоритет, чтобы не мешать выполнению задач "музыкантов". Дирижер" отсчитывает такты (как метроном) и следит за тем, чтобы музыканты вовремя получали команды. Задача "дирижер" запускается один раз в 150 мс и при каждом запуске проверяет состояние проигрываемой мелодии. Как только "дирижер" замечает, что все "музыканты" доиграли свои партии до конца (т.е. все биты во флаге flag_Playing сброшены), он дает команду "музыкантам" играть сначала.

Два слова о синтезаторе

Синтезатор реализован в функции прерывания в файле interrupt.c. Подпрограмма пробегается по всем четырем переменным управления звуком и формирует цифровой сигнал. Для формирования цифрового сигнала у синтезатора есть:

  • три таблицы "паттернов": bass[], violin[], guitar[] - где записано по одному периоду синусоиды с разными частотными характеристиками;
  • формулы для формирования огибающей сигнала (помечены комментариями FORMING_SIGNAL_xxx): атака, спад, сустейн.
  • макрос быстрого перемножения (signed char)*(unsigned char), чтобы перемножать синусоиду на амплитуду огибающей.

Все четыре мгновенных значения амплитуды для каждого инструмента суммируются, делятся на 4 и записываются в переменную m_cDAC, которая при следующем входе в прерывание будет скопирована в буферный регистр PWM CCPR1L (два младших разряда копируются в биты CCP1X и CCP1Y регистра CCP1CON).

О нотах

Здесь приведу немного информации на случай, если кому-то захочется свою мелодию запрограммировать).

В файле music.c есть буквенные определения нот (C0 - до первой октавы, C0_ - до диез первой октавы, D0 - ре и т.д.) Всего в программе выделены частоты под 4 с половиной октавы (57 нот). Но при задании ноты в нотном стане (в массивах notelist_xxx) для задания номера ноты (макрос play()) используются только 5 бит, т.е. можно пронумеровать только 32 ноты. Поэтому введена возможность установки базовой октавы (макрос setbase()). Длительность ноты задается только двумя битами, поэтому всего 4 варианта длительностей. Если нужно нота большей длительности, то следует ее либо добить паузой (макрос pause()), либо командой продолжения звучания (макрос playmore()). Список нот должен заканчиваться макросом stop(), чтобы "музыканты" не обращались к неинициализированным ячейкам пямяти.

 
osa/ref/appendix/quartet.txt · Последние изменения: 07.10.2010 13:54 (внешнее изменение)
 
Creative Commons License Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki