在C语言中将整数转换为WAV格式音频的方法咨询及基于RLE与差分PCM的音频压缩器样本转音频方案问询
Hey there! Let's tackle your two audio-related questions one by one—they're both core tasks for audio tooling, so I’m glad you’re building this compressor.
WAV files are just a wrapper around raw PCM (Pulse Code Modulation) audio data, plus a header that tells players how to interpret the data. Here’s a step-by-step approach to turn your integer samples into a valid WAV:
Step 1: Define the WAV Header Structure
First, you need to replicate the WAV file’s header format. It has three main chunks: RIFF (file info), fmt (audio format details), and data (the raw sample data). Here’s a C struct for it (note WAV uses little-endian byte order, so we’ll handle byte conversion later):
#include <stdio.h> #include <stdint.h> #include <endian.h> #include <limits.h> // WAV header structure typedef struct { // RIFF chunk char riff_id[4]; // "RIFF" uint32_t riff_size; // File size - 8 char wave_id[4]; // "WAVE" // fmt chunk char fmt_id[4]; // "fmt " uint32_t fmt_size; // Size of fmt chunk (16 for PCM) uint16_t audio_format; // 1 = PCM (uncompressed) uint16_t num_channels; // 1 = mono, 2 = stereo uint32_t sample_rate; // e.g., 44100, 48000 uint32_t byte_rate; // sample_rate * num_channels * bits_per_sample/8 uint16_t block_align; // num_channels * bits_per_sample/8 uint16_t bits_per_sample;// 8, 16, 24, 32 // data chunk char data_id[4]; // "data" uint32_t data_size; // Size of sample data (num_samples * num_channels * bits_per_sample/8) } WavHeader;
Step 2: Configure Audio Parameters
Set up your desired audio specs. For example, if you’re working with 16-bit mono audio at 44100 Hz:
// Calculate total data size first (example: 10000 mono samples) size_t num_samples = 10000; uint32_t data_size = num_samples * 1 * (16 / 8); // 1 channel, 16 bits per sample WavHeader header = { .riff_id = {'R', 'I', 'F', 'F'}, .wave_id = {'W', 'A', 'V', 'E'}, .fmt_id = {'f', 'm', 't', ' '}, .fmt_size = 16, .audio_format = 1, .num_channels = 1, .sample_rate = 44100, .bits_per_sample = 16, .data_id = {'d', 'a', 't', 'a'}, .data_size = data_size }; // Calculate derived values header.block_align = header.num_channels * (header.bits_per_sample / 8); header.byte_rate = header.sample_rate * header.block_align; header.riff_size = 36 + data_size; // 36 = size of fixed header sections
Step 3: Prepare Your Integer Samples
If your integer samples are in a range that doesn’t match your bit depth (e.g., 32-bit ints for 16-bit PCM), scale them to fit the target range. For 16-bit PCM, the valid range is -32768 to 32767:
// Example: Convert a 32-bit int sample to 16-bit int32_t raw_sample = 123456; int16_t pcm_sample = (int16_t)(raw_sample / (INT32_MAX / 32767.0));
Step 4: Write the Header and Data to File
Remember to convert multi-byte values to little-endian before writing (use htole16/htole32 for portability):
FILE* wav_file = fopen("output.wav", "wb"); if (!wav_file) { perror("Failed to open file"); return 1; } // Convert header fields to little-endian header.riff_size = htole32(header.riff_size); header.fmt_size = htole32(header.fmt_size); header.audio_format = htole16(header.audio_format); header.num_channels = htole16(header.num_channels); header.sample_rate = htole32(header.sample_rate); header.byte_rate = htole32(header.byte_rate); header.block_align = htole16(header.block_align); header.bits_per_sample = htole16(header.bits_per_sample); header.data_size = htole32(header.data_size); // Write header fwrite(&header, sizeof(WavHeader), 1, wav_file); // Write sample data (example: writing an array of int16_t samples) int16_t* samples = /* your prepped sample array */; fwrite(samples, sizeof(int16_t), num_samples, wav_file); fclose(wav_file);
Since you already have the decoded sample data (amplitude values with indices and counts), this is mostly the same as the first problem—you just need to make sure your samples are in a valid PCM format first:
Key Steps:
- Finalize your decoded samples: Ensure your differential PCM data is fully converted back to raw amplitude values (differential PCM stores differences between adjacent samples, so you’ll need to accumulate these to get the original waveform). For RLE, expand the run-length encoded data into a flat array of continuous samples (e.g., a run of 5 samples with value 100 becomes [100,100,100,100,100]).
- Match your bit depth and range: Scale your amplitude values to fit your target PCM bit depth (e.g., 16-bit = -32768 to 32767). If your samples are normalized (0.0 to 1.0 or -1.0 to 1.0), multiply by the max value of your bit depth to convert to integers.
- Follow the WAV creation process: Use the same header setup and file-writing code from the first question. Just plug your decoded, scaled samples into the data section of the WAV file.
Quick Notes:
- If your compressor uses custom sample ranges (e.g., 0 to 65535 for unsigned 16-bit), adjust the scaling and header’s
bits_per_sampleto match (unsigned 8-bit is common for that range, but 16-bit unsigned is also possible—just make sure the player supports it). - Double-check your channel count: If your original audio was stereo, your samples should be interleaved (left, right, left, right...) before writing to the WAV.
内容的提问来源于stack exchange,提问作者Coicu

