Содержание

Пример использования 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.

Наша программа состоит из 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. Подпрограмма пробегается по всем четырем переменным управления звуком и формирует цифровой сигнал. Для формирования цифрового сигнала у синтезатора есть:

Все четыре мгновенных значения амплитуды для каждого инструмента суммируются, делятся на 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(), чтобы "музыканты" не обращались к неинициализированным ячейкам пямяти.