Введение
Короткий звук может сообщить о завершении задачи. В этой лабораторной работе вы создадите сам звук: цикл C вычислит последовательность чисел, которая превратится в воспроизводимый файл WAV. Сначала послушайте рабочий пример на 440 Гц, измените только высоту тона, затем завершите собственную функцию генерации отсчётов для повторного использования.
Нужны знания переменных, арифметики, циклов, массивов и функций C, а также базовая навигация в терминале. Дискретизация звука, радианы и двоичный вывод объясняются здесь; указатели и обработка сигналов не требуются. Компилятор, небольшой понятный модуль записи WAV и браузерный проигрыватель, читающий только файлы, уже подготовлены. Всё аудио синтезируется самостоятельно; устройство записи не нужно. 50 минут — оценка автора с учётом чтения и обычных ошибок.
Послушайте рабочий тон
На этом шаге вы воспроизведёте рабочий тон длительностью полсекунды, затем измените одно значение, чтобы звук стал выше. Начните в Terminal. cd меняет каталог; этот абсолютный путь также возвращает в рабочий каталог после ошибки. Продолжайте работать здесь.
cd /home/labex/project/sound-studio
Отсчёт — это число со знаком, описывающее форму волны в один момент. PCM означает импульсно-кодовую модуляцию: файл непосредственно хранит эти значения. Здесь используется один канал, то есть моно, и 16 000 отсчётов в секунду. Знаковые 16-битные отсчёты представляют целые числа от -32 768 до 32 767. Положительные и отрицательные значения — две стороны волны, а ноль — её центр. Амплитуда определяет удаление значений от нуля. При прослушивании через динамики или наушники начните с комфортной громкости.
Подготовленный sample.c создаёт синусоиду 440 Гц: 440 циклов в секунду. sin, объявленный в <math.h>, принимает угол в радианах и возвращает значение от -1 до 1. Полный цикл равен 2 * pi радиан. Умножение на 10 000 даёт умеренную амплитуду. Расчёт времени рассмотрим после прослушивания.
Скомпилируйте пример. gcc компилирует C; -std=c11 выбирает C11, -Wall -Wextra включает полезные предупреждения, а -o sample задаёт имя исполняемого файла. pcm.c предоставляет запись WAV. Параметр -lm после исходных файлов подключает математическую библиотеку для sin. Эти файлы не должны вызывать предупреждений компилятора.
gcc -std=c11 -Wall -Wextra sample.c pcm.c -lm -o sample
./sample запускает исполняемый файл из текущего каталога. Он пишет двоичные байты WAV в стандартный вывод. > перенаправляет байты в файл; не запускайте программу без перенаправления: аудиобайты не являются читаемым текстом терминала. Каталог outputs уже подготовлен. Используйте новое имя:
./sample > outputs/sample-440.wav
При успехе текст не выводится. Переключитесь на вкладку Sound Studio. Нажмите Refresh files, выберите sample-440.wav в WAV file, затем нажмите Load sound. Должны появиться Ready to play и 8000 samples · 16000 Hz · 0.500 s. Нажмите Play, попробуйте Pause и Playback position. Можно перевести фокус на позицию клавишей Tab и использовать Home, End и стрелки. Встроенные аудиоэлементы могут округлять длительность меньше секунды до 0:00; текст сверху и позиция в секундах показывают точное время.
Нажмите Download WAV, чтобы сохранить настоящий файл. Проигрыватель читает созданный файл и не генерирует недостающие отсчёты. Cannot load sound означает отсутствие или неподдерживаемый формат файла. Это не ошибка соединения, при которой не открывается сама страница студии. При ошибке пути вернитесь в Terminal, используйте указанный cd, проверьте имя, повторите соответствующую команду и обновите список файлов.

Посмотрите на выбранный sample-440.wav, данные о полусекунде и элементы Play, Playback position, Download WAV.
Вернитесь в Terminal. cat отображает текст. Прочитайте короткий пример:
cat sample.c
Цикл проходит индексы отсчётов от 0 до 7999. seconds = (double)i / rate преобразует индекс во время: индекс 0 соответствует 0 секундам, индекс 160 — 0,010 секунды. (double) задаёт дробное, а не целочисленное деление. Фаза 2.0 * pi * frequency * seconds определяет угол по мере прохождения циклов. (int) преобразует масштабированное значение синуса в целое, отбрасывая дробную часть. Предоставленная wav_sample записывает два PCM-байта числа, но не выбирает число за вас.
Теперь измените только частоту. Следующая команда использует sed, текстовый редактор для конкретной замены. -i редактирует указанный файл на месте; выражение в кавычках s/old/new/ заменяет буквальный текст между первой парой косых черт текстом между второй. Изменяется только sample.c.
sed -i 's/frequency = 440/frequency = 660/' sample.c
Пересоберите программу, чтобы включить изменение, и сохраните другой файл. Первый WAV тоже оставьте.
gcc -std=c11 -Wall -Wextra sample.c pcm.c -lm -o sample
./sample > outputs/sample-660.wav
Переключитесь в Sound Studio, обновите список, загрузите и воспроизведите sample-660.wav. В нём те же 8 000 отсчётов и полсекунды, но тон выше. Изменилась лишь частота. Сохраните изменённый sample.c, исполняемый файл sample и оба WAV. Это сравнение — подготовка; далее вы создадите свою универсальную программу и отдельные результаты.
Вычислите каждый отсчёт самостоятельно
На этом шаге вы завершите write_tone, чтобы одна функция C работала с разными высотами, длительностями и амплитудами. Начните в Terminal, в /home/labex/project/sound-studio.
При 16 000 отсчётов в секунду для 300 миллисекунд нужно 16000 * 300 / 1000 = 4800 отсчётов. Миллисекунда — тысячная доля секунды. При этой частоте целые миллисекунды дают точное целое число отсчётов. Цикл от i = 0, продолжающийся при i < count, выдаёт ровно count значений; <= добавило бы лишний отсчёт.
Рассмотрим меньший пример: при восьми отсчётах в секунду синусоида с одним циклом в секунду имеет примерно значения 0, 0.71, 1, 0.71, 0, -0.71, -1, -0.71 на первых восьми индексах. Индекс продвигает время, а sin задаёт положение по вертикали. Реальная частота 16 000 Гц даёт намного больше значений за цикл.
Прочитайте предоставленные интерфейс и начальную функцию:
cat tone.h tone.c
write_tone(frequency, milliseconds, amplitude) должна сгенерировать все отсчёты. Начальная версия пишет нули: она может скомпилироваться и дать структурно правильный, но беззвучный WAV. Имя, размер и успешный выход не доказывают наличия тона.
Не меняйте main.c, tone.h, pcm.h, pcm.c, inspect_wav.py и audio.py. Подготовленный main.c читает три аргумента, проверяет их, пишет заголовок и вызывает вашу функцию. Менять его разбор аргументов на основе указателей не нужно. Ваша реализация — tone.c; браузер подготовлен.
Модуль записи отделяет упаковку от синтеза. wav_begin(count) один раз пишет заголовок; wav_sample(value) пишет одно переданное целое число. Ни одна функция не создаёт волну. Небольшой pcm.c использует putchar для байта в стандартный вывод и fputs для фиксированных имён блоков. Сначала выводится младший байт, затем старший, а не сырая структура C. Отрицательные отсчёты кодируются в 16-битном представлении; модуль отклоняет значения вне знакового диапазона, никогда не ограничивая и не подменяя их.
Он пишет следующие поля. Имя fmt включает конечный пробел.
| Поле | Значение в этой работе |
|---|---|
RIFF, size, WAVE |
Определяют контейнер WAV; size равен числу байтов файла без первых 8 |
fmt, size 16 |
Описывают следующие 16 байтов формата |
Format 1, channels 1 |
Несжатый PCM, моно |
Sample rate 16000 |
Отсчётов в секунду |
Byte rate 32000 |
16 000 кадров в секунду × 2 байта на кадр |
Block alignment 2, sample bits 16 |
Один кадр содержит один двухбайтовый отсчёт |
data, size 2 * count |
Определяют и считают реальные PCM-байты, идущие далее |
Этот предоставленный модуль можно прочитать командой cat pcm.c. Поля описывают выход; изменение одного заголовка не превращает тишину в звук.
Реализуйте короткую функцию ниже. <math.h> объявляет sin. pi — локальная дробная константа, поэтому программа не зависит от нестандартного макроса M_PI. amplitude задаёт масштаб до преобразования в целое; максимум 12 000 в анализаторе удерживает синусоидальные отсчёты внутри 16-битного диапазона. Каждый вызов начинает временной индекс с нуля.
cat > tone.c заменяет только этот исходный файл. Here-document <<'C' передаёт последующие строки в cat до последней строки с единственным C. Кавычки в разделителе сохраняют текст C буквально. Вставьте весь блок вместе с последней строкой.
cat > tone.c <<'C'
#include <math.h>
#include "tone.h"
#include "pcm.h"
void write_tone(int frequency, int milliseconds, int amplitude) {
const int rate = 16000;
const double pi = 3.14159265358979323846;
int count = rate * milliseconds / 1000;
for (int i = 0; i < count; i++) {
double seconds = (double)i / rate;
double phase = 2.0 * pi * frequency * seconds;
int sample = (int)(amplitude * sin(phase));
wav_sample(sample);
}
}
C
Скомпилируйте функцию с подготовленными вызывающим модулем и записью WAV. Если указана строка с ошибкой, исправьте tone.c или повторите блок полной замены и пересоберите. Старый исполняемый файл после неудачной сборки проверял бы старый код.
gcc -std=c11 -Wall -Wextra main.c tone.c pcm.c -lm -o tone
Программа получает частоту в Гц, длительность в целых миллисекундах, затем амплитуду. Поддерживаемые включительные диапазоны: частота 200–1200, длительность 100–1000, амплитуда 1000–12000. Создайте две новые записи:
./tone 440 300 8000 > outputs/tone-440.wav
./tone 660 500 10000 > outputs/tone-660.wav
Исследуйте реально сохранённые байты подготовленным средством чтения. python3 запускает указанный инструмент Python только для чтения; писать Python не нужно. Он сообщает об отсутствующем, неполном или неподдерживаемом файле и никогда его не восстанавливает.
python3 inspect_wav.py outputs/tone-440.wav
Ожидается:
Format: signed 16-bit mono PCM
Rate: 16000 Hz
Frames: 4800
Duration: 0.300 s
Peak: 8000
Перейдите в Sound Studio. Обновите список, загрузите и воспроизведите tone-440.wav, затем tone-660.wav. Показанные длительности — 0,300 и 0,500 секунды. Скачайте также один новый результат. Это результаты вашей функции, отдельные от sample-440.wav и sample-660.wav.

Выбор файла и Ready to play указывают на tone-660.wav; метаданные описывают реальные сохранённые отсчёты.
Оставьте tone.c, работающий исполняемый файл tone и оба новых результата. Проверка читает WAV, испытывает переданный исполняемый файл и пересобирает неизменённый исходник во временном каталоге с другими допустимыми параметрами. Работать должны все три; исходника, старого исполняемого файла или копии примера недостаточно. Допустимы эквивалентные вычисления и целочисленное округление: отклонение подобранной амплитуды — не более 2% запрошенной амплитуды плюс 2 единицы отсчёта; превышение пиков — не более 2 единиц; RMS остатков относительно синусоиды заданной частоты, то есть квадратный корень из среднего квадратов остатков, — не более 0,5% амплитуды плюс 2 единицы. RMS характеризует типичную величину ошибки отсчёта. Допуск учитывает округление, но не разрешает дополнительно менять высоту тона. Точное число кадров и формат PCM остаются обязательными. Предложенная формула уверенно укладывается в ограничения.
Проверьте длительность и исправьте отказ
На этом шаге вы используете ту же функцию для короткой некруглой длительности и отличите неверный ввод от неисправного звукового файла. Начните в Terminal.
Создайте 101 миллисекунду на 733 Гц с амплитудой 7 373. Период не обязан делить длительность сегмента без остатка; count по-прежнему определяет число отсчётов.
./tone 733 101 7373 > outputs/short-tone.wav
python3 inspect_wav.py outputs/short-tone.wav
Найдите Frames: 1616 и Duration: 0.101 s. Это напрямую следует из 16000 * 101 / 1000. Последний отсчёт находится чуть раньше конца сегмента; добавлять отсчёт в конечной точке не нужно. Резкое начало или конец могут щёлкать: первая работа ещё не применяет плавное изменение амплитуды. Следующая обучает постепенной регулировке усиления и паузам между тонами.
Следующая команда намеренно запрашивает 99 миллисекунд — меньше минимума. Используйте новое временное имя. Оболочка открывает файл перенаправления до проверки аргументов программой, поэтому отказ может оставить пустой файл; сохранность старого файла с таким именем не гарантируется.
./tone 440 99 10000 > outputs/rejected.wav
echo $? немедленно показывает исходный код завершения предыдущей команды: ноль — успех, ненулевое значение — отказ или ошибка. Не выполняйте другую команду между пробой и чтением кода.
echo $?
Ожидайте объяснение опубликованного диапазона и код 2. Это штатный отказ по входным данным, не повод сбрасывать среду. 99 — недопустимый аргумент длительности. Хорошие WAV хранятся отдельно и остаются доступны.
Перейдите в Sound Studio, обновите список, выберите и загрузите rejected.wav. Должно появиться Cannot load sound с пояснением, что это не полный поддерживаемый PCM WAV. Воспроизведение и скачивание недоступны. Пустой файл не становится тоном из-за окончания .wav.
Вернитесь в Terminal. rm -- удаляет конкретный файл после --, обозначающего конец параметров команды. Удалите только этот временный неудачный результат:
rm -- outputs/rejected.wav
Используйте поддерживаемый минимум и другое новое имя для исправления:
./tone 440 100 10000 > outputs/minimum-tone.wav
python3 inspect_wav.py outputs/minimum-tone.wav
Теперь ожидаются 1 600 кадров и 0,100 секунды. Вернитесь в Sound Studio, обновите список и воспроизведите minimum-tone.wav, затем загрузите short-tone.wav и используйте Download WAV. Для проверки клавиатуры проходите видимые элементы с Tab, нажмите Enter на Play, используйте Home, End и стрелки на ползунке позиции. Перед сменой файла поставьте воспроизведение на паузу.
Теперь есть повторно используемый исходник, соответствующий исполняемый файл и реально воспроизводимые результаты. Сохраните сравнение примеров и свои записи. Проверки работают во временных каталогах и читают существующие файлы; они не ремонтируют программу и не создают недостающую работу. Декодирование и воспроизведение браузером не доказывают подключения физического динамика, а этот ограниченный поднабор WAV не является универсальным аудиокодером.
Резюме
Вы связали временной индекс цикла C с реальным звуком. Вы изменили высоту примера, реализовали повторно используемую генерацию синусоидальных отсчётов, сохранили амплитуды в знаковом 16-битном диапазоне и записали WAV с точным числом кадров. Вы исследовали, воспроизвели и скачали настоящие файлы и восстановили работу после намеренного отказа по параметру. Далее можно объединять тоны с тишиной и плавным нарастанием и затуханием.



