美文网首页
wav音频通道数修改工具 C语言实现

wav音频通道数修改工具 C语言实现

作者: VellBibi | 来源:发表于2023-11-03 12:02 被阅读0次

前言

最近研究了下wav格式,为了巩固下对格式的认识,写了个小工具来修改音频通道数,原理很简单,看两张图就大概懂了

wav格式

信息头结构


数据排列方式


废话不多说,直接上代码

转换代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <endian.h>
#include <unistd.h>

#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT  0x20746d66
#define ID_DATA 0x61746164

struct wav_header {
    uint32_t riff_id;
    uint32_t riff_sz;
    uint32_t riff_fmt;
    uint32_t fmt_id;
    uint32_t fmt_sz;
    uint16_t audio_format;
    uint16_t num_channels;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
    uint32_t data_id;
    uint32_t data_sz;
};

int main(int argc, char **argv) {
    FILE *file;
    FILE *out;
    struct wav_header in_header;
    unsigned int channels = 2;
    char *filename;
    char *out_filename;
    int more_chunks = 1;

    if (argc < 3) {
        fprintf(stderr, "Usage: %s in.wav out.wav [-c channels] \n", argv[0]);
        return 1;
    }

    filename = argv[1];
    file = fopen(filename, "rb");
    if (!file) {
        fprintf(stderr, "Unable to open file '%s'\n", filename);
        return 1;
    }
    out_filename = argv[2];
    out = fopen(out_filename, "wb");
    if (!out) {
        fprintf(stderr, "Unable to open file '%s'\n", out_filename);
        return 1;
    }

    fread(&in_header, sizeof(in_header), 1, file);
    if ((in_header.riff_id != ID_RIFF) ||
        (in_header.riff_fmt != ID_WAVE)) {
        fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);
        fclose(file);
        return 1;
    }

    /* parse command line arguments */
    argv += 3;
    while (*argv) {
        if (strcmp(*argv, "-c") == 0) {
            argv++;
            if (*argv)
                channels = atoi(*argv);
        }
        if (*argv)
            argv++;
    }

    struct wav_header out_header;
    memcpy(&out_header, &in_header, sizeof(out_header));
    out_header.num_channels = channels;
    out_header.block_align = out_header.num_channels * (out_header.bits_per_sample / 8);
    out_header.data_sz = out_header.block_align * (in_header.data_sz / in_header.block_align);
    out_header.riff_sz = out_header.data_sz + sizeof(out_header) - 8;
    fwrite(&out_header, sizeof(struct wav_header), 1, out);

    fseek(file, sizeof(struct wav_header), SEEK_SET);
    fseek(out, sizeof(struct wav_header), SEEK_SET);
    char *buffer = malloc(in_header.block_align);
    for (int i = 0; i < in_header.data_sz; i += in_header.block_align) {
        if (fread(buffer, 1, in_header.block_align, file) != in_header.block_align) {
            fprintf(stderr, "Error read file\n");
            break;
        }
        if (in_header.num_channels > out_header.num_channels) {
            // remove channel
            if (fwrite(buffer, 1, out_header.block_align, out) != out_header.block_align) {
                fprintf(stderr, "Error write file\n");
                break;
            }
        } else if (in_header.num_channels < out_header.num_channels) {
            // add channel
            if (fwrite(buffer, 1, in_header.block_align, out) != in_header.block_align) {
                fprintf(stderr, "Error write file\n");
                break;
            }
            for (int j = 0; j < out_header.num_channels - in_header.num_channels; j++) {
                // add channel with first channel
                if (fwrite(buffer, 1, in_header.block_align / in_header.num_channels, out) !=
                    in_header.block_align / in_header.num_channels) {
                    fprintf(stderr, "Error write file\n");
                    break;
                }
            }
        }
    }
    fclose(file);
    fclose(out);

    return 0;
}

相关文章

网友评论

      本文标题:wav音频通道数修改工具 C语言实现

      本文链接:https://www.haomeiwen.com/subject/fvroidtx.html