Перейти к основному содержимому

Аудио

Для кого этот документ

  • Студентам курса "Периферийные устройства"
  • Необходимое ПО: Quartus II

Ввод, обработка и вывод аудиоинформации

Цель работы: изучение использования аудио кодека для записи и воспроизведения звука, а также генерации звука определенной частоты.

1. Подготовка к лабораторной работе

Для выполнения лабораторной работы необходимо изучить по материалам лекций и предложенной литературы:

  1. Способы представления звуковых сигналов в цифровой форме.
  2. Принцип работы и назначение регистров и отдельных полей аудио порта. Эта информация содержится в описании процессорной системы. Включите ее в отчет.
  3. Уясните содержимое программы Media.c и включите ее в отчет.
  4. Уясните пункты заданий методических указаний и напишите программные заготовки для их выполнения.

2. Порядок выполнения лабораторной работы

Часть 1. Запись и воспроизведение звука

  1. Подключите к стенду микрофон и динамики. Микрофон подключается к разъему MIC розового цвета, наушники – к разъему LINE-OUT зеленого цвета.

  2. Напишите программу на языке программирования Си, которая записывает звуки с помощью микрофона и воспроизводит их, используя динамики, подключенные к стенду. Аудио кодек, установленный на стенде, производит оцифровку звукового сигнала каждую 1/48000 секунды. Длительность звуковой записи должна составлять 10 секунд.

    При нажатии кнопки KEY1 выполняется очистка входных аудио буферов. Затем программа проверяет, имеются ли данные во входных аудио буферах, и сохраняет их в памяти. Во время записи звука должен гореть светодиод LED0.

    При нажатии кнопки KEY2 программа выполняет очистку выходных аудио буферов и осуществляет запись в них данных, сохраненных в памяти при записи звука. Во время воспроизведения записи должен гореть светодиод LED1.

Часть 2. Добавление аудио эффектов

  1. Модифицируйте программу из предыдущей части таким образом, чтобы при установленном в верхнее положение переключателе SW0 воспроизведение аудиозаписи замедлялось, при установленном в верхнее положение переключателе SW1 – ускорялось. Для замедления воспроизведения необходимо повторять запись каждого оцифрованного значения в выходной буфер, для ускорения – пропускать каждое второе значение.

  2. Модифицируйте программу из предыдущего пункта. При установке переключателя SW2 в верхнее положение на воспроизводимую аудиозапись накладывается эффект эхо. Для этого, при записи в выходной буфер оцифрованного значения на него накладывается ранее оцифрованное значение, но имеющее меньшее значение громкости.

Часть 3. Генерация звука определенной частоты

  1. Подключите клавиатуру к разъему PS/2.

  2. Напишите программу, реализующую музыкальный синтезатор. Пока нажата клавиша на клавиатуре, воспроизводится звук определенной частоты. В таблице представлено значение частоты звука и соответствующая ей клавиша на клавиатуре.

КлавишаЧастота звука, Гц
a262
w278
s292
e310
d328
f348
t370
g392
y416
h440
u466
j494

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

A * sin(2π * t / T)

где:

  • A – амплитуда сигнала (громкость звука);
  • T – период сигнала;
  • t – время.

Вычисление данных значений можно производить в любых средах программирования. Полученные значения необходимо разместить в заголовочном файле и подключить его в программе для процессора NIOS II с помощью директивы #include. Для размещения значений каждой частоты необходимо создать отдельный массив. Каждый массив содержит 24000 значений.

При нажатии и удерживании клавиши, в выходной аудио буфер записываются значения из соответствующего массива.

Важно: Необходимо в меню Program Settings в поле Additional compiler flags для установки максимального уровня оптимизации указать значение -O3.

3. Отчетные материалы

Отчетные материалы должны содержать:

  1. Цель лабораторной работы.
  2. Материалы, связанные с подготовкой к работе, включая теоретическую часть.
  3. Информацию по выполнению каждого пункта задания. Причем в отчете должны содержаться выполняемые Вами действия, наблюдаемые результаты, и Ваши объяснения.
  4. Написанные Вами фрагменты программ.
  5. Краткое заключение.

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;
}
}

Чеклист выполнения

  • Работа выполнена
  • Отчет подготовлен