使用C语言反转音频文件

cld4siwp  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(92)

有人能告诉我我在这段代码中做错了什么吗?它编译,但它不正确的反向音频文件。它确实扭转了文件排序的不正确的音频是明确的。这是cs50x课程的习题4。我觉得TODO #8有点不对劲。

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

#include "wav.h"

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("entre input and output file names\n");
        return 1;
    }

    // Open input file for reading
    // TODO #2
    char *infile = argv[1];
    char *outfile = argv[2];

    FILE *inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        printf("error opening file\n");
        fclose(inptr);
        return 2;
    }

    // Read header
    // TODO #3
    WAVHEADER wv;
    fread(&wv, sizeof(WAVHEADER), 1, inptr);
    long position = ftell(inptr);

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

    if (check_format(wv) == -1)
    {
        printf("input is not a wav.h file\n");
        fclose(inptr);
        return 3;
    }

    // Open output file for writing
    // TODO #5
    FILE *outptr = fopen(outfile, "wb");
    if (outptr == NULL)
    {
        printf("error opening output file\n");
        fclose(outptr);
        fclose(inptr);
        return 4;
    }

    // Write header to file
    // TODO #6
    fwrite(&wv, sizeof(WAVHEADER), 1, outptr);

    // Use get_block_size to calculate size of block
    // TODO #7
    int blsize = get_block_size(wv);

    // Write reversed audio to file
    // TODO #8
    DWORD bufferSize = wv.subchunk2Size;

    int16_t *audio = malloc(bufferSize);
    fseek(inptr, blsize, SEEK_END);
    fseek(outptr, position, SEEK_SET);

    for (int i = 0; i < bufferSize / blsize; i++)
    {
        fread(&audio[i], blsize, 1, inptr);
        fseek(inptr, (-2) * blsize, SEEK_CUR);

        fwrite(&audio[i], blsize, 1, outptr);
    }

    fclose(outptr);
    fclose(inptr);
    free(audio);
}

int check_format(WAVHEADER header)
{
    // TODO #4
    char elmnts[] = {'W', 'A', 'V', 'E', '\0'};
    for (int i = 0; i < 4; i++)
    {
        if (elmnts[i] != header.format[i])
        {
            return -1;
        }
    }
    return 0;
}

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

不知道该怎么办。请帮帮忙。

lymgl2op

lymgl2op1#

以下是添加到代码区域的一些注解:

#include <stdint.h> // Will not be needed

int main(int argc, char *argv[])
{
    /* ... */
    FILE *inptr = fopen(infile, "r"); // Windows requires "rb"
    if (inptr == NULL)
    {
        printf("error opening file\n");
        fclose(inptr); // open didn't succeed. No need for fclose()
        return 2;
    }

    /* ... */
    long position = ftell(inptr); // unnecessary
    /* ... */

    FILE *outptr = fopen(outfile, "wb"); // Good! "binary"
    if (outptr == NULL)
    {
        printf("error opening output file\n");
        fclose(outptr); // unnecessary
        fclose(inptr); // good!
        return 4;
    }
    fwrite(&wv, sizeof(WAVHEADER), 1, outptr); // Good!

    /* ... */

    DWORD bufferSize = wv.subchunk2Size; // DWORD = 32bit unsigned

    int16_t *audio = malloc(bufferSize); // why int16_t? Guessing?
    fseek(inptr, blsize, SEEK_END);
    fseek(outptr, position, SEEK_SET); // unnecessary

    for (int i = 0; i < bufferSize / blsize; i++)
    {
        fread(&audio[i], blsize, 1, inptr); // why only 1 sample each time?
        fseek(inptr, (-2) * blsize, SEEK_CUR); // Good try!
        fwrite(&audio[i], blsize, 1, outptr);
    }
    /* ... */
}

要打开一个二进制文件,特别是在Windows上,使用“rb”(或“rb”,就像你做的那样!).
没有伤害,但不要close()文件没有成功打开。
您分配一个能够容纳文件中所有样本的区域,然后分别读取/写入每个样本,其中涉及大量看似神秘的fseek()。有个更简单的方法!

size_t bufferSize = (size_t)wv.subchunk2Size; // for big numbers

    char *audio = malloc( bufferSize ); // ptr to individual bytes
    /* omitting verification for brevity */

    fread( audio, 1, bufferSize, inptr ); // load everything!
    fclose( inptr ); // finished with input file, thanks

    char *smpl = audio + bufferSize; // point 1 byte beyond end of buffer

    // Now, skip BACKWARDS through the buffer, one sample at a time
    while( (smpl -= blsize) >= audio )
        fwrite( smpl, 1, blsize, outptr ); // and output each sample
    // then close the output file and free the allocated block

我希望这能帮助你理解如何使用C的功能和利用可用的动态内存。
(You应该添加更多的验证,以确保fread()加载了所有请求,并且每个fwrite()也能正常工作。)

相关问题