Introducción
Un sonido breve puede avisar de que una tarea ha terminado. En este laboratorio crearás el propio sonido: un bucle de C calcula una secuencia de números que se convierte en un archivo WAV reproducible. Primero escucha un ejemplo funcional de 440 Hz, cambia solo su tono y después completa tu propia función de muestreo reutilizable.
Necesitas conocer variables, aritmética, bucles, arreglos y funciones de C, además de la navegación básica en la terminal. Aquí se presentan el muestreo de audio, los radianes y la salida binaria; no se requieren punteros ni procesamiento de señales. Están preparados el compilador, un pequeño escritor WAV transparente y un reproductor web que solo lee archivos. Todo el audio se sintetiza originalmente; no hace falta un dispositivo de grabación. Los 50 minutos son una estimación del autor que incluye lectura y errores habituales.
Escucha un tono funcional
En este paso reproducirás un tono funcional de medio segundo y cambiarás un valor para hacerlo más agudo. Empieza en Terminal. cd cambia de directorio; esta ruta absoluta también permite recuperar el directorio de trabajo si te equivocas. Mantén aquí tu trabajo.
cd /home/labex/project/sound-studio
Una muestra es un número con signo que describe la onda en un instante. PCM significa modulación por impulsos codificados: el archivo almacena directamente estos valores. Este laboratorio usa un canal, llamado mono, y 16.000 muestras por segundo. Sus muestras de 16 bits con signo representan enteros de -32.768 a 32.767. Los valores positivos y negativos son los dos lados de la onda; cero es el centro. La amplitud controla cuánto se alejan de cero. Si escuchas con altavoces o auriculares, empieza con un volumen cómodo.
El archivo preparado sample.c genera una onda sinusoidal de 440 Hz: 440 ciclos por segundo. sin, declarado en <math.h>, recibe un ángulo en radianes y devuelve un valor entre -1 y 1. Un ciclo completo equivale a 2 * pi radianes. Multiplicar por 10.000 ajusta la forma a una amplitud moderada. Veremos el cálculo del tiempo después de escuchar el resultado.
Compila el ejemplo proporcionado. gcc compila C; -std=c11 selecciona C11, -Wall -Wextra activa advertencias útiles y -o sample nombra el ejecutable. pcm.c proporciona el escritor WAV. -lm, colocado después de los archivos fuente, enlaza la biblioteca matemática usada por sin. Estos archivos no deberían producir advertencias del compilador.
gcc -std=c11 -Wall -Wextra sample.c pcm.c -lm -o sample
./sample ejecuta el programa de este directorio. Escribe bytes binarios WAV en la salida estándar. > redirige esos bytes a un archivo; no ejecutes el programa sin redirección, porque los bytes de audio no son texto legible en la terminal. outputs es un directorio ya preparado. Usa este nombre nuevo:
./sample > outputs/sample-440.wav
Si funciona, no imprime texto. Cambia a la pestaña Sound Studio. Pulsa Refresh files, elige sample-440.wav en WAV file y pulsa Load sound. La página debe indicar Ready to play y 8000 samples · 16000 Hz · 0.500 s. Pulsa Play y prueba Pause y Playback position. Puedes enfocar el control de posición con Tab y usar Home, End y las flechas. Los controles de audio nativos pueden redondear una duración inferior a un segundo a 0:00; el texto superior y la posición en segundos muestran el tiempo preciso.
Pulsa Download WAV para guardar el archivo real. El reproductor lee el archivo que creaste; no genera muestras ausentes. Cannot load sound indica que falta un archivo o que no es compatible. Es distinto de un error de conexión que impide abrir la propia página. Si te equivocas de ruta, vuelve a Terminal, usa el comando cd anterior, comprueba el nombre, repite el comando correspondiente y actualiza la lista.

Observa el archivo seleccionado sample-440.wav, los datos de medio segundo y los controles Play, Playback position y Download WAV.
Vuelve a Terminal. cat muestra texto. Lee el ejemplo breve:
cat sample.c
El bucle recorre los índices de muestra de 0 a 7999. seconds = (double)i / rate convierte un índice en tiempo: el índice 0 corresponde a 0 segundos y el 160 a 0,010 segundos. (double) solicita división decimal en lugar de división entera. La fase, 2.0 * pi * frequency * seconds, cuenta el ángulo a través de los ciclos. (int) convierte el seno escalado en un entero descartando la parte fraccionaria. La función proporcionada wav_sample escribe los dos bytes PCM de ese número; no elige el número por ti.
Cambia ahora solo la frecuencia. El siguiente comando usa sed, un editor de texto para una sustitución concreta. -i modifica el archivo indicado en su ubicación; la expresión entre comillas s/old/new/ sustituye el texto literal entre el primer par de barras por el texto entre el segundo par. Solo modifica sample.c.
sed -i 's/frequency = 440/frequency = 660/' sample.c
Compila de nuevo para incluir el cambio en el ejecutable y guarda otro archivo. Conserva también el primer WAV.
gcc -std=c11 -Wall -Wextra sample.c pcm.c -lm -o sample
./sample > outputs/sample-660.wav
Cambia a Sound Studio, actualiza, carga sample-660.wav y reprodúcelo. Tiene las mismas 8.000 muestras y medio segundo de duración, pero un tono más agudo. Solo cambió la frecuencia. Conserva el archivo editado sample.c, el ejecutable sample y ambos archivos. Esta comparación es una preparación; a continuación crearás tu programa reutilizable y sus resultados separados.
Calcula cada muestra por tu cuenta
En este paso completarás write_tone para que una función de C funcione con distintos tonos, duraciones y amplitudes. Empieza en Terminal, en /home/labex/project/sound-studio.
A 16.000 muestras por segundo, 300 milisegundos necesitan 16000 * 300 / 1000 = 4800 muestras. Un milisegundo es la milésima parte de un segundo. Con esta frecuencia de muestreo, las duraciones en milisegundos enteros tienen un número entero exacto de muestras. Un bucle que empieza en i = 0 y continúa mientras i < count emite exactamente count valores; usar <= añadiría una muestra no deseada.
Imagina un ejemplo mucho menor: con ocho muestras por segundo, una onda sinusoidal de un ciclo por segundo tiene aproximadamente los valores 0, 0.71, 1, 0.71, 0, -0.71, -1, -0.71 en sus ocho primeros índices. El índice hace avanzar el tiempo y sin proporciona la posición vertical. Nuestra frecuencia real de 16.000 Hz ofrece muchos más valores por ciclo.
Lee la interfaz y la función inicial proporcionadas:
cat tone.h tone.c
write_tone(frequency, milliseconds, amplitude) debe generar todas las muestras. La versión inicial escribe ceros, así que puede compilar y producir un WAV estructuralmente válido pero silencioso. Ni el nombre, ni el tamaño, ni una salida exitosa prueban que haya un tono.
Mantén sin cambios main.c, tone.h, pcm.h, pcm.c, inspect_wav.py y audio.py. El archivo preparado main.c lee tres argumentos, los valida, escribe la cabecera y llama a tu función. No necesitas modificar su analizador de argumentos basado en punteros. tone.c es tu implementación; el navegador ya está preparado.
El escritor separa el empaquetado de la síntesis. wav_begin(count) escribe la cabecera una vez; wav_sample(value) escribe un entero suministrado. Ninguno genera una onda. El pequeño archivo pcm.c usa putchar para escribir un byte en la salida estándar y fputs para escribir nombres fijos de bloques. Emite primero el byte bajo y luego el alto, en vez de volcar una estructura de C. Las muestras negativas se codifican con su representación de 16 bits; el escritor rechaza valores fuera del intervalo con signo y nunca los recorta ni sustituye.
Estos son los campos que escribe. El nombre fmt incluye su espacio final.
| Campo | Significado en este laboratorio |
|---|---|
RIFF, size, WAVE |
Identifican un contenedor WAV; size equivale a los bytes del archivo menos los primeros 8 |
fmt, size 16 |
Describen los 16 bytes de formato siguientes |
Format 1, channels 1 |
PCM sin compresión, mono |
Sample rate 16000 |
Muestras por segundo |
Byte rate 32000 |
16.000 tramas por segundo × 2 bytes por trama |
Block alignment 2, sample bits 16 |
Una trama contiene una muestra de dos bytes |
data, size 2 * count |
Identifican y cuentan los bytes PCM reales que siguen |
Puedes leer este envoltorio proporcionado con cat pcm.c. Sus campos describen la salida; cambiar solo la cabecera no convierte muestras silenciosas en sonido.
Implementa la función breve siguiente. <math.h> declara sin. pi es una constante decimal local, por lo que el programa no depende de la macro no estándar M_PI. amplitude es un factor aplicado antes de convertir a entero; el máximo de 12.000 del analizador mantiene estas muestras sinusoidales dentro del intervalo de 16 bits. Cada llamada empieza su índice temporal en cero.
cat > tone.c reemplaza únicamente este archivo fuente. El here-document <<'C' envía a cat las líneas siguientes hasta la línea final que contiene solo C. Las comillas del delimitador conservan literalmente el texto C. Pega todo el bloque, incluida esa última línea.
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
Compila tu función con el llamador y el escritor preparados. Si la compilación indica un error de línea, corrige tone.c o repite su bloque completo de sustitución y vuelve a compilar. Ejecutar un binario antiguo tras un fallo de compilación probaría código antiguo.
gcc -std=c11 -Wall -Wextra main.c tone.c pcm.c -lm -o tone
El ejecutable recibe frecuencia en Hz, duración en milisegundos enteros y amplitud, en ese orden. Los intervalos admitidos, incluidos los extremos, son frecuencia 200–1200, duración 100–1000 y amplitud 1000–12000. Crea dos salidas nuevas con tu programa:
./tone 440 300 8000 > outputs/tone-440.wav
./tone 660 500 10000 > outputs/tone-660.wav
Usa el lector preparado para inspeccionar los bytes realmente guardados. python3 ejecuta la herramienta Python de solo lectura indicada; no tienes que escribir Python. Notifica un error si falta el archivo, está incompleto o no es compatible y nunca lo regenera.
python3 inspect_wav.py outputs/tone-440.wav
Resultado esperado:
Format: signed 16-bit mono PCM
Rate: 16000 Hz
Frames: 4800
Duration: 0.300 s
Peak: 8000
Cambia a Sound Studio. Actualiza, carga tone-440.wav y reprodúcelo; después carga y reproduce tone-660.wav. Las duraciones mostradas son 0,300 y 0,500 segundos. Descarga también una de estas salidas nuevas. Son resultados de tu función, distintos de sample-440.wav y sample-660.wav.

El archivo seleccionado y el mensaje Ready to play identifican tone-660.wav; los metadatos describen las muestras realmente guardadas.
Conserva tone.c, el ejecutable funcional tone y ambas salidas nuevas. La comprobación lee los WAV guardados, prueba el ejecutable entregado y recompila tu fuente sin modificar en un directorio desechable con otros parámetros válidos. Los tres deben funcionar; no bastan la fuente por sí sola, un ejecutable antiguo ni una copia del ejemplo. Se aceptan matemáticas y redondeos enteros equivalentes: la amplitud ajustada puede diferir hasta el 2% de la solicitada más 2 unidades de muestra; los picos pueden superar la solicitud como máximo en 2 unidades; y el residuo RMS (raíz de la media de los cuadrados) respecto a una senoide de la frecuencia solicitada puede ser como máximo el 0,5% de la amplitud más 2 unidades. Este residuo representa un error de muestra de tamaño medio. La tolerancia numérica permite diferencias de redondeo, pero no da permiso adicional para cambiar el tono solicitado. Siguen siendo obligatorios el número exacto de tramas y el formato PCM. La fórmula proporcionada cumple holgadamente estos límites.
Comprueba el tiempo y recupérate de un rechazo
En este paso usarás la misma función con una duración breve no redonda y distinguirás una entrada no válida de un archivo de sonido defectuoso. Empieza en Terminal.
Genera 101 milisegundos a 733 Hz con amplitud 7.373. Un ciclo no tiene que dividir exactamente la duración del segmento; count sigue definiendo el número de muestras.
./tone 733 101 7373 > outputs/short-tone.wav
python3 inspect_wav.py outputs/short-tone.wav
Busca Frames: 1616 y Duration: 0.101 s. Se deducen directamente de 16000 * 101 / 1000. La última muestra ocurre justo antes del final del segmento; no añadas una muestra en el extremo. Un inicio o final brusco puede producir un chasquido porque este primer laboratorio aún no atenúa la amplitud. El siguiente laboratorio guiado enseña cambios graduales de ganancia y pausas entre tonos.
El siguiente comando solicita intencionalmente 99 milisegundos, menos del mínimo admitido. Usa un nombre nuevo y desechable. El shell abre un archivo redirigido antes de que el programa valide los argumentos, así que un rechazo puede dejar un archivo vacío; no garantiza conservar un archivo anterior con ese mismo nombre.
./tone 440 99 10000 > outputs/rejected.wav
echo $? muestra inmediatamente el estado de salida nativo del comando anterior: cero significa éxito y un valor distinto de cero indica rechazo o fallo. No ejecutes otro comando entre la prueba y la lectura del estado.
echo $?
Debes ver la explicación del intervalo publicado y el estado 2. Es un rechazo normal de entrada, no un motivo para reiniciar el entorno. 99 es el argumento de duración no válido. Los WAV buenos existentes son archivos separados y siguen disponibles.
Cambia a Sound Studio, actualiza, selecciona rejected.wav y cárgalo. La página debe mostrar Cannot load sound y explicar que no es un WAV PCM completo y compatible. La reproducción y la descarga permanecen deshabilitadas. Un archivo vacío no se convierte en un tono porque su nombre termine en .wav.
Vuelve a Terminal. rm -- elimina el archivo exacto situado después de --, que termina las opciones del comando. Elimina solo esta salida fallida y desechable:
rm -- outputs/rejected.wav
Recupérate usando el mínimo admitido y otro nombre de salida nuevo:
./tone 440 100 10000 > outputs/minimum-tone.wav
python3 inspect_wav.py outputs/minimum-tone.wav
Ahora debes obtener 1.600 tramas y 0,100 segundos. Vuelve a Sound Studio, actualiza y reproduce minimum-tone.wav; después carga short-tone.wav y usa Download WAV. Para comprobar el teclado, recorre los controles visibles con Tab, usa Enter sobre Play y las teclas Home, End y las flechas en el deslizador de posición. Pausa antes de cambiar de archivo.
Ahora tienes un archivo fuente reutilizable, un ejecutable que coincide con él y salidas realmente reproducibles. Conserva la comparación del ejemplo y tus propias salidas. Las comprobaciones se ejecutan en directorios desechables y leen los archivos reales; no reparan el programa ni crean lo que falta. La decodificación y reproducción del navegador no prueban que haya un altavoz físico conectado, y este subconjunto WAV acotado no es un codificador de audio general.
Resumen
Conectaste el índice temporal de un bucle de C con un sonido real. Cambiaste el tono de un ejemplo, implementaste un muestreo sinusoidal reutilizable, mantuviste las amplitudes dentro del intervalo de 16 bits con signo y guardaste WAV con un número exacto de tramas. Inspeccionaste, reprodujiste y descargaste archivos reales y te recuperaste de un rechazo intencional de parámetros. A continuación podrás combinar tonos con silencio y fundidos graduales.



