You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 17:43:16