C语言WAV音频反转程序无法创建/写入output.wav问题排查
WAV音频反转程序无法生成output.wav文件问题排查
我编写了一个用于反转.wav音频文件的C程序,但无论如何都无法生成output.wav文件。推测问题出在文件写入信息的环节,可能是内存操作或逻辑错误导致。尝试过用errno调试但无帮助,也未出现预期的"Couldn't create file"提示,因此聚焦于文件写入相关的代码逻辑排查。
问题代码
WavHeader.h
#include <stdint.h> typedef uint8_t BYTE; typedef uint16_t WORD; typedef uint32_t DWORD; typedef struct { BYTE chunkID[4]; DWORD chunkSize; BYTE format[4]; BYTE subchunk1ID[4]; DWORD subchunk1Size; WORD audioFormat; WORD numChannels; DWORD sampleRate; DWORD byteRate; WORD blockAlign; WORD bitsPerSample; BYTE subchunk2ID[4]; DWORD subchunk2Size; } __attribute__((__packed__)) WAVHEADER;
reverse.c
#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include "wav.h" // Number of bytes in .wav header const int HEADER_SIZE = 44; int check_format(WAVHEADER header); int get_block_size(WAVHEADER header); int main(int argc, char *argv[]) { // Ensure proper usage if (argc != 3) { printf("Usage: ./reverse input.wav output.wav\n"); return 1; } // Open input file for reading FILE *input = fopen(argv[1], "rb"); if (input == NULL) { printf("Could not open file.\n"); return 1; } // Read header WAVHEADER header; fread(&header, 1, HEADER_SIZE, input); // Use check_format to ensure WAV format int result = check_format(header); if (result == 0) { return 0; // format is okay } if (result != 0) { printf("File is unsupported format, ensure it extension is a .WAV\n"); return 1; } // Open output file for writing FILE *output = fopen(argv[2], "w"); if (output == NULL) { fclose(input); printf("Could not create file.\n"); return 1; } // Write header to file fwrite(&header, 1, HEADER_SIZE, output); // Use get_block_size to calculate size of block int block = get_block_size(header); // Write reversed audio to file int16_t *buffer = malloc(block); // Allocate memory for the audio buffer if (buffer == NULL) { printf("Memory allocation error.\n"); fclose(input); fclose(output); return 1; } fseek(input, HEADER_SIZE, SEEK_SET); // Calculate the number of audio blocks in the file long numBlocks = (header.subchunk2Size) / block; // Read audio blocks from input, reverse, and write to output for (long i = 0; i < numBlocks; i++) { fseek(input, -(i + 1) * block, SEEK_END); fread(buffer, block, 1, input); fwrite(buffer, block, 1, output); } // clean up free(buffer); fclose(input); fclose(output); return 0; } int check_format(WAVHEADER header) { if (header.format[0] == 'W' && header.format[1] == 'A' && header.format[2] == 'V' && header.format[3] == 'E') { return 0; // if format is correct } else return 1; // if format is not .WAV } int get_block_size(WAVHEADER header) { int blockSize = header.numChannels * (header.bitsPerSample / 8); return blockSize; }
核心问题与修复方案
1. 头文件引用错误
reverse.c中#include "wav.h",但实际头文件名为WavHeader.h,编译时会找不到头文件,导致WAVHEADER类型未定义,程序无法编译通过。
修复:将引用改为#include "WavHeader.h"(确保文件名大小写与实际一致)。
2. 格式检查逻辑完全颠倒
check_format函数返回0表示格式正确,但main函数中判断result == 0时直接return 0退出程序,导致格式正确的情况下根本不会执行后续的文件写入操作,这是生成不了输出文件的关键原因。
修复:调整逻辑:
int result = check_format(header); if (result != 0) { printf("File is unsupported format, ensure it extension is a .WAV\n"); fclose(input); return 1; } // 格式正确,继续执行后续逻辑
3. 输出文件打开模式错误
用"w"模式打开二进制文件会导致系统自动转换换行符(比如Windows下将\n转为\r\n),破坏WAV文件的二进制结构,甚至导致写入失败。
修复:用二进制写入模式"wb"打开输出文件:
FILE *output = fopen(argv[2], "wb");
4. 内存分配类型不匹配
int16_t* buffer仅适用于16位采样的WAV文件,如果是8位或24位采样,类型会不匹配,可能导致内存访问错误。
修复:改用通用的uint8_t*:
uint8_t *buffer = malloc(block);
5. 音频读取逻辑优化
原循环中频繁从文件末尾反向偏移fseek,效率较低且存在边界风险。可以先将所有音频数据读入内存,再反转写入:
// 读取所有音频数据到内存 uint8_t *audio_data = malloc(header.subchunk2Size); if (audio_data == NULL) { /* 错误处理 */ } fread(audio_data, 1, header.subchunk2Size, input); // 反转写入:从最后一个block开始往前写 for (long i = numBlocks - 1; i >= 0; i--) { fwrite(audio_data + i * block, block, 1, output); } free(audio_data);
修复后的完整reverse.c示例
#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include "WavHeader.h" // Number of bytes in .wav header const int HEADER_SIZE = 44; int check_format(WAVHEADER header); int get_block_size(WAVHEADER header); int main(int argc, char *argv[]) { // Ensure proper usage if (argc != 3) { printf("Usage: ./reverse input.wav output.wav\n"); return 1; } // Open input file for reading FILE *input = fopen(argv[1], "rb"); if (input == NULL) { printf("Could not open file.\n"); return 1; } // Read header WAVHEADER header; fread(&header, 1, HEADER_SIZE, input); // Use check_format to ensure WAV format int result = check_format(header); if (result != 0) { printf("File is unsupported format, ensure it extension is a .WAV\n"); fclose(input); return 1; } // Open output file for writing FILE *output = fopen(argv[2], "wb"); if (output == NULL) { fclose(input); printf("Could not create file.\n"); return 1; } // Write header to file fwrite(&header, 1, HEADER_SIZE, output); // Use get_block_size to calculate size of block int block = get_block_size(header); // Allocate memory for audio data uint8_t *audio_data = malloc(header.subchunk2Size); if (audio_data == NULL) { printf("Memory allocation error.\n"); fclose(input); fclose(output); return 1; } // Read all audio data fread(audio_data, 1, header.subchunk2Size, input); // Calculate the number of audio blocks in the file long numBlocks = (header.subchunk2Size) / block; // Write reversed audio blocks to output for (long i = numBlocks - 1; i >= 0; i--) { fwrite(audio_data + i * block, block, 1, output); } // Clean up free(audio_data); fclose(input); fclose(output); return 0; } int check_format(WAVHEADER header) { return (header.format[0] == 'W' && header.format[1] == 'A' && header.format[2] == 'V' && header.format[3] == 'E') ? 0 : 1; } int get_block_size(WAVHEADER header) { return header.numChannels * (header.bitsPerSample / 8); }
内容的提问来源于stack exchange,提问作者webmessiah
相关产品推荐
相关产品推荐

