Аудио
Для кого этот документ
- Студентам курса "Периферийные устройства"
- Необходимое ПО: Quartus II
Ввод, обработка и вывод аудиоинформации
Цель работы: изучение использования аудио кодека для записи и воспроизведения звука, а также генерации звука определенной частоты.
1. Подготовка к лабораторной работе
Для выполнения лабораторной работы необходимо изучить по материалам лекций и предложенной литературы:
- Способы представления звуковых сигналов в цифровой форме.
- Принцип работы и назначение регистров и отдельных полей аудио порта. Эта информация содержится в описании процессорной системы. Включите ее в отчет.
- Уясните содержимое программы Media.c и включите ее в отчет.
- Уясните пункты заданий методических указаний и напишите программные заготовки для их выполнения.
2. Порядок выполнения лабораторной работы
Часть 1. Запись и воспроизведение звука
-
Подключите к стенду микрофон и динамики. Микрофон подключается к разъему MIC розового цвета, наушники – к разъему LINE-OUT зеленого цвета.
-
Напишите программу на языке программирования Си, которая записывает звуки с помощью микрофона и воспроизводит их, используя динамики, подключенные к стенду. Аудио кодек, установленный на стенде, производит оцифровку звукового сигнала каждую 1/48000 секунды. Длительность звуковой записи должна составлять 10 секунд.
При нажатии кнопки KEY1 выполняется очистка входных аудио буферов. Затем программа проверяет, имеются ли данные во входных аудио буферах, и сохраняет их в памяти. Во время записи звука должен гореть светодиод LED0.
При нажатии кнопки KEY2 программа выполняет очистку выходных аудио буферов и осуществляет запись в них данных, сохраненных в памяти при записи звука. Во время воспроизведения записи должен гореть светодиод LED1.
Часть 2. Добавление аудио эффектов
-
Модифицируйте программу из предыдущей части таким образом, чтобы при установленном в верхнее положение переключателе SW0 воспроизведение аудиозаписи замедлялось, при установленном в верхнее положение переключателе SW1 – ускорялось. Для замедления воспроизведения необходимо повторять запись каждого оцифрованного значения в выходной буфер, для ускорения – пропускать каждое второе значение.
-
Модифицируйте программу из предыдущего пункта. При установке переключателя SW2 в верхнее положение на воспроизводимую аудиозапись накладывается эффект эхо. Для этого, при записи в выходной буфер оцифрованного значения на него накладывается ранее оцифрованное значение, но имеющее меньшее значение громкости.
Часть 3. Генерация звука определенной частоты
-
Подключите клавиатуру к разъему PS/2.
-
Напишите программу, реализующую музыкальный синтезатор. Пока нажата клавиша на клавиатуре, воспроизводится звук определенной частоты. В таблице представлено значение частоты звука и соответствующая ей клавиша на клавиатуре.
| Клавиша | Частота звука, Гц |
|---|---|
| a | 262 |
| w | 278 |
| s | 292 |
| e | 310 |
| d | 328 |
| f | 348 |
| t | 370 |
| g | 392 |
| y | 416 |
| h | 440 |
| u | 466 |
| j | 494 |
Для генерации синусоидального сигнала заданной частоты необходимо получить набор значений точек синусоиды, полученных через равные промежутки времени. Значения точек вычисляются по формуле:
A * sin(2π * t / T)
где:
- A – амплитуда сигнала (громкость звука);
- T – период сигнала;
- t – время.
Вычисление данных значений можно производить в любых средах программирования. Полученные значения необходимо разместить в заголовочном файле и подключить его в программе для процессора NIOS II с помощью директивы #include. Для размещения значений каждой частоты необходимо создать отдельный массив. Каждый массив содержит 24000 значений.
При нажатии и удерживании клавиши, в выходной аудио буфер записываются значения из соответствующего массива.
Важно: Необходимо в меню Program Settings в поле Additional compiler flags для установки максимального уровня оптимизации указать значение
-O3.
3. Отчетные материалы
Отчетные материалы должны содержать:
- Цель лабораторной работы.
- Материалы, связанные с подготовкой к работе, включая теоретическую часть.
- Информацию по выполнению каждого пункта задания. Причем в отчете должны содержаться выполняемые Вами действия, наблюдаемые результаты, и Ваши объяснения.
- Написанные Вами фрагменты программ.
- Краткое заключение.
4. Приложение
В приложении содержится фрагмент программы media.c, выполняющий запись и воспроизведение звуковых сигналов.
Листинг 1
Исходный файл программы media.c
#define BUF_SIZE 500000 // примерно 10 секунд записи (@ 48K samples/sec)
#define BUF_THRESHOLD 96 // 75% заполненности аудио буфера
void HEX_PS2(char, char, char);
void check_KEYs( int *, int *, int * );
int main(void)
{
volatile int * green_LED_ptr = (int *) 0x10000010;
volatile int * audio_ptr = (int *) 0x10003040;
volatile int * PS2_ptr = (int *) 0x10000100;
/* Используется для аудио записи/воспроизведения */
int fifospace, leftdata, rightdata;
int record = 0, play = 0, buffer_index = 0;
int left_buffer[BUF_SIZE];
int right_buffer[BUF_SIZE];
/* Используется для PS/2 порта */
int PS2_data, RVALID;
char byte1 = 0, byte2 = 0, byte3 = 0;
record = 0;
play = 0;
*(PS2_ptr) = 0xFF; // Сброс PS/2 порта
while(1)
{
check_KEYs ( &record, &play, &buffer_index ); //Определяем, какая клавиша была нажата
if (record)
{
*(green_LED_ptr) = 0x1; // Зажигаем светодиод LEDG[0]
fifospace = *(audio_ptr + 1); // читаем fifospace регистр
if ( (fifospace & 0x000000FF) > BUF_THRESHOLD ) // проверяем значение поля RARC
{
// Сохраняем данные из аудио буферов
while ( (fifospace & 0x000000FF) && (buffer_index < BUF_SIZE) )
{
left_buffer[buffer_index] = *(audio_ptr + 2);
right_buffer[buffer_index] = *(audio_ptr + 3);
++buffer_index;
if (buffer_index == BUF_SIZE)
{
// Завершаем запись аудио
record = 0;
*(green_LED_ptr) = 0x0; // выключаем светодиод LEDG
}
fifospace = *(audio_ptr + 1); // читаем fifospace регистр
}
}
}
else if (play)
{
*(green_LED_ptr) = 0x2; // зажигаем светодиод LEDG_1
fifospace = *(audio_ptr + 1); // читаем fifospace регистр
if ( (fifospace & 0x00FF0000) > BUF_THRESHOLD ) // проверяем поле WSRC
{
// Записываем данные в буферы
while ( (fifospace & 0x00FF0000) && (buffer_index < BUF_SIZE) )
{
*(audio_ptr + 2) = left_buffer[buffer_index];
*(audio_ptr + 3) = right_buffer[buffer_index];
++buffer_index;
if (buffer_index == BUF_SIZE)
{
// Завершаем вопроизведение
play = 0;
*(green_LED_ptr) = 0x0; // выключаем светодиод LEDG
}
fifospace = *(audio_ptr + 1); // читаем fifospace регистр
}
}
}
}
}
/****************************************************************************************
* Определение, какая кнопка на стенде была нажата
****************************************************************************************/
void check_KEYs(int * KEY1, int * KEY2, int * counter)
{
volatile int * KEY_ptr = (int *) 0x10000050;
volatile int * audio_ptr = (int *) 0x10003040;
int KEY_value;
KEY_value = *(KEY_ptr); // Считываем значение регистра данных кнопок
while (*KEY_ptr); // Ожидаем появления данных
if (KEY_value == 0x2) // Если была нажата кнопка KEY1
{
// Сбрасываем счетчик
*counter = 0;
// Очищаем входные аудио буферы
*(audio_ptr) = 0x4;
*(audio_ptr) = 0x0;
*KEY1 = 1;
}
else if (KEY_value == 0x4) // Если была нажата кнопка KEY2
{
// Сбрасываем счетчик
*counter = 0;
// Очищаем выходные аудио буферы
*(audio_ptr) = 0x8;
*(audio_ptr) = 0x0;
*KEY2 = 1;
}
}
Чеклист выполнения
- Работа выполнена
- Отчет подготовлен