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

C语言实现WAV音频反转生成文件无声音问题求助

WAV音频反转程序生成无声音文件的排查与修复

我用C语言写了一个反转WAV音频片段并生成新WAV文件的程序,能成功生成输出文件,但文件没有声音。已经确认输入是WAV格式,计算了音频块大小,尝试从输入文件末尾开始逐块写入输出文件,要求保留每个音频块的声道顺序(比如双声道文件中,最后一个输入块的左声道要成为第一个输出块的左声道),但结果异常,需要排查问题原因。

原代码

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include "wav.h"
#include <string.h>

typedef uint8_t BYTE;

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
    // TODO #1
    if (argc != 3)
    {
        printf("usage: ./reverse input.wav output.wav\n");
        return 1;
    }

    // Open input file for reading
    // TODO #2
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("could not open file\n");
        return 2;
    }

    // Read header into an array
    // TODO #3
    WAVHEADER header;
    fread(&header, HEADER_SIZE, 1, input);

    // Use check_format to ensure WAV format
    // TODO #4

    if (check_format(header) == 5)
    {
        printf("Incorrect file format\n");
        return 3;
    }

    // Open output file for writing
    // TODO #5
    FILE *output = fopen(argv[2], "w");
    if (output == NULL)
    {
        printf("could not open file\n");
        return 4;
    }

    // Write header to file
    // TODO #6
    fwrite(&header, HEADER_SIZE, 1, output);

    // Use get_block_size to calculate size of block
    // TODO #7
    int block_size = get_block_size(header);
    printf("block size is: %d\n", block_size);

    // Write reversed audio to file
    // TODO #8
    fseek(input, 0, SEEK_END);
    long here = ftell(input);

    while (here > HEADER_SIZE)
    {
        int *Buffer[4];
        fread(Buffer, 4, 1, input);
        fwrite(Buffer, 4, 1, output);

        fseek(input, -4, SEEK_CUR);
        here -= 4;
    }
    fclose(input);
    fclose(output);
}


int check_format(WAVHEADER header)
{
    // TODO #4
    BYTE *format = header.format;

    if (format[0] == 'W' && format[1] == 'A' && format[2] == 'V' && format[3] == 'E')
    {
        printf("is a wave file\n");
        return 0;
    }
    else
    {
        printf("Bad\n");
        return 5;
    }
}

int get_block_size(WAVHEADER header)
{
    // TODO #7
    int block_size = header.numChannels * (header.bitsPerSample / 8);
    return block_size;
}

问题排查与修复要点

  • 文件打开模式错误:WAV是二进制文件,必须用"rb"(读二进制)和"wb"(写二进制)模式打开,原代码用"r"和"w"会导致系统处理换行符,破坏音频二进制数据。
  • 缓冲区定义错误:原代码中int *Buffer[4];是指针数组,不是存储音频数据的缓冲区,会导致非法内存读写,应改为与block_size匹配的字节数组或动态分配内存。
  • 硬编码块大小:原代码硬编码读写4字节,没有使用计算出的block_size,无法适配不同声道数、不同位深的WAV文件。
  • 反转逻辑错误:原代码的文件指针移动逻辑错误,没有正确定位到上一个音频块的起始位置,导致读取的数据混乱。

修复后的代码

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "wav.h"
#include <string.h>

typedef uint8_t BYTE;

const int HEADER_SIZE = 44;

int check_format(WAVHEADER header);
int get_block_size(WAVHEADER header);

int main(int argc, char *argv[])
{
    // 检查参数数量
    if (argc != 3)
    {
        printf("usage: ./reverse input.wav output.wav\n");
        return 1;
    }

    // 以二进制模式打开输入文件
    FILE *input = fopen(argv[1], "rb");
    if (input == NULL)
    {
        printf("could not open input file\n");
        return 2;
    }

    // 读取WAV头部
    WAVHEADER header;
    fread(&header, HEADER_SIZE, 1, input);

    // 验证WAV格式
    if (!check_format(header))
    {
        printf("Incorrect file format\n");
        fclose(input);
        return 3;
    }

    // 以二进制模式打开输出文件
    FILE *output = fopen(argv[2], "wb");
    if (output == NULL)
    {
        printf("could not open output file\n");
        fclose(input);
        return 4;
    }

    // 写入头部到输出文件
    fwrite(&header, HEADER_SIZE, 1, output);

    // 计算音频块大小
    int block_size = get_block_size(header);
    printf("block size is: %d\n", block_size);

    // 分配音频块缓冲区
    BYTE *buffer = malloc(block_size);
    if (buffer == NULL)
    {
        printf("memory allocation failed\n");
        fclose(input);
        fclose(output);
        return 5;
    }

    // 定位到输入文件末尾,开始反转读取
    fseek(input, 0, SEEK_END);
    long current_pos = ftell(input);

    // 从最后一个音频块开始,向前遍历
    while (current_pos > HEADER_SIZE)
    {
        // 回退一个块大小,定位到当前块的起始位置
        fseek(input, -block_size, SEEK_CUR);
        // 读取一个音频块
        fread(buffer, block_size, 1, input);
        // 写入到输出文件
        fwrite(buffer, block_size, 1, output);
        // 回退两个块大小:读完后指针已移动block_size,需再退block_size到上一个块起始
        fseek(input, -block_size * 2, SEEK_CUR);
        current_pos -= block_size;
    }

    // 释放资源
    free(buffer);
    fclose(input);
    fclose(output);
    return 0;
}

int check_format(WAVHEADER header)
{
    // 验证WAV格式标识
    return (header.format[0] == 'W' && header.format[1] == 'A' && 
            header.format[2] == 'V' && header.format[3] == 'E');
}

int get_block_size(WAVHEADER header)
{
    // 计算每个音频块的大小:声道数 × 每个样本的字节数
    return header.numChannels * (header.bitsPerSample / 8);
}

内容的提问来源于stack exchange,提问作者Diaplo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:31:08