C语言实现双声道WAV文件反转失败,check50未通过求助
C语言反转双声道WAV文件check50未通过问题
问题描述
- 用C语言实现双声道.wav文件反转时,check50检测未通过,提示
reverse.c未按指定要求反转升音阶文件,但音频听起来像是已经反转 - 尝试拆分左右声道后交换写入顺序(先右后左/先左后右),均未通过检测
- 最后一次
fseek()调用用变量i调整指针到最后未读取的sampleFrame,确保每次迭代中fread仅读取一个块
原代码
#include <stdint.h> #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include "wav.h" const int HEADERSIZE = 44; bool check_format(WAVHEADER header); int get_block_size(WAVHEADER header); int main(int argc, char *argv[]) { // #1 Ensure proper usage if (argc != 3) { printf("usage: reverse input.wav output.wav\n"); return 1; } // #2 Open input file for reading FILE *input = fopen(argv[1], "rb"); if (input == NULL) { printf("error opening input file!\n"); return 2; } // #3 Read header(of type struct WAVHEADER) from input file WAVHEADER header; fread(&header, sizeof(header), 1, input); // #4 Use check_format to ensure WAV format int fileFormat = check_format(header); // #5 Open output file for writing FILE *output = fopen(argv[2], "wb"); if (output == NULL) { printf("error opening output file!\n"); return 3; } // #6 Write header to file fwrite(&header, sizeof(header), 1, output); // #7 Use get_block_size() to calculate size of block int blockSize = get_block_size(header); // calculate number of blocks in a WAv file int nBlocks; fseek(input, 0, SEEK_END); nBlocks = (ftell(input) - HEADERSIZE) / blockSize; // #8 Write reversed audio to file // declare array to store each block we read-in // type array[size] to hold blockAlign or audio block BYTE sampleFrame[blockSize]; // seek pointer to lasst blockSize of input file fseek(input, -blockSize - 1, SEEK_END); int i = 1; for (int i = 0; i < nBlocks; i++) { // read audioBlock from input file fread(sampleFrame, sizeof(BYTE), blockSize, input); // write it to the output file fwrite(sampleFrame, sizeof(BYTE), blockSize, output); // adjust fseek call to start at next unread sampleFrame fseek(input, (-i * blockSize), SEEK_END); } // #9 close opened files fclose(output); fclose(input); } bool check_format(WAVHEADER header) { // check correct wav format and return TRUE char format[4]; for(int i = 0; i < 4; i++) { format[i] = header.format[i]; } if (strcmp(format, "WAVE") == 0) { // return true:1 return true; } // else return false:0 ? return false; } int get_block_size(WAVHEADER header) { // printf("channels: %i, bps: %i\n", header.numChannels, (header.bitsPerSample / 8)); int blockSize = header.numChannels * (header.bitsPerSample / 8); // => byte; return blockSize; }
问题分析与修复方案
1. 初始fseek位置错误
原代码中fseek(input, -blockSize - 1, SEEK_END);多减了1字节,直接导致第一个读取的块位置偏移,应该改为fseek(input, -blockSize, SEEK_END);,定位到最后一个完整块的起始位置。
2. 循环内fseek逻辑错误
循环里的fseek(input, (-i * blockSize), SEEK_END);计算逻辑混乱,每次读完一个块后,需要从当前位置往前跳2倍blockSize(因为已经读取了一个块,要回到上一个未读块的起始点),更稳妥的方式是直接通过块索引计算绝对位置:
fseek(input, HEADERSIZE + (nBlocks - i - 1) * blockSize, SEEK_SET);
这种写法逻辑清晰,避免指针偏移计算错误。
3. check_format函数的潜在问题
原代码手动复制header.format到数组后用strcmp比较,但数组没有添加字符串终止符\0,会触发未定义行为。改用memcmp直接比较4字节数据更安全:
bool check_format(WAVHEADER header) { return memcmp(header.format, "WAVE", 4) == 0; }
4. 未处理check_format的返回值
原代码调用check_format后没有判断结果,若输入不是WAV文件会继续执行,不符合要求,需添加判断逻辑:
if (!check_format(header)) { printf("Input is not a WAV file!\n"); fclose(input); return 4; }
修复后的完整代码
#include <stdint.h> #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include "wav.h" const int HEADERSIZE = 44; bool check_format(WAVHEADER header); int get_block_size(WAVHEADER header); int main(int argc, char *argv[]) { // #1 Ensure proper usage if (argc != 3) { printf("usage: reverse input.wav output.wav\n"); return 1; } // #2 Open input file for reading FILE *input = fopen(argv[1], "rb"); if (input == NULL) { printf("error opening input file!\n"); return 2; } // #3 Read header(of type struct WAVHEADER) from input file WAVHEADER header; fread(&header, sizeof(header), 1, input); // #4 Use check_format to ensure WAV format if (!check_format(header)) { printf("Input is not a WAV file!\n"); fclose(input); return 4; } // #5 Open output file for writing FILE *output = fopen(argv[2], "wb"); if (output == NULL) { printf("error opening output file!\n"); fclose(input); return 3; } // #6 Write header to file fwrite(&header, sizeof(header), 1, output); // #7 Use get_block_size() to calculate size of block int blockSize = get_block_size(header); // calculate number of blocks in a WAV file fseek(input, 0, SEEK_END); int fileSize = ftell(input); int nBlocks = (fileSize - HEADERSIZE) / blockSize; // #8 Write reversed audio to file BYTE sampleFrame[blockSize]; for (int i = 0; i < nBlocks; i++) { // 定位到当前要读取的块(从后往前数第i+1个) fseek(input, HEADERSIZE + (nBlocks - i - 1) * blockSize, SEEK_SET); fread(sampleFrame, blockSize, 1, input); fwrite(sampleFrame, blockSize, 1, output); } // #9 close opened files fclose(output); fclose(input); return 0; } bool check_format(WAVHEADER header) { return memcmp(header.format, "WAVE", 4) == 0; } int get_block_size(WAVHEADER header) { return header.numChannels * (header.bitsPerSample / 8); }
内容的提问来源于stack exchange,提问作者AbuAminu
相关产品推荐
相关产品推荐

