Wav文件写入和播放倍增时间

时间:2015-09-11 11:30:51

标签: c wav pcm

我有一个要求,我需要多次写一个wav(带有pcma数据)文件。

说我有一个文件 audio-g711a.wav 。我想把它写成一个新文件,说 audio-g711a-out.wav 2次。当我播放 audio-g711a-out.wav 时,它的播放时间应该是原始文件的两倍。

我确实使用下面的代码编写。但是它的播放时间与原始文件的持续时间完全相同(我希望播放时间翻倍)。

代码如下。

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

#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int g_count = 0;

void init_config(int argc,char **argv);
void rewrite_file(int count);

int main(int argc, char **argv)
{
    init_config(argc, argv);
    printf("Count = %d\n", g_count);
    rewrite_file(g_count);
    return 0;
}

void rewrite_file(int count)
{
    int index;
    char arr[101];
    FILE *fd_in;
    FILE *fd_out;
    size_t len;
    unsigned long chunk_size;

    index = 0;
    fd_in = fopen("./audio-g711a.wav", "r");
    fd_out = fopen("./audio-g711a-out.wav", "w+");

rw_again:    
    index++;
    len = fread(arr, 1, 100, fd_in);
    while(len == 100)
    {
        fwrite(arr, 1, 100, fd_out);
        len = fread(arr, 1, 100, fd_in);
    }
    fwrite(arr, 1, len, fd_out);
    if(count > index)
    {
        printf("Completed %d round of operation of %d total rounds.\n", index, count);
        fclose(fd_in);
        fd_in = fopen("./audio-g711a.wav", "r");
        goto rw_again;
    }

    return;
}

void init_config(int argc,char **argv)
{
    int ch;

    while ((ch = getopt(argc, argv, "v:n:N:X")) != -1)
    {
        switch (ch)
        {
            case 'n':
            case 'N':
            {
                g_count = atoi(optarg);
            }
            break;

            default:
            break;

        }
    }

    return;
}

要执行此操作,可以执行./a.out -n 2

在一些R&amp; D之后,我意识到wav文件有某种标题。当我第二次写时,我又在写标题了。这可能导致文件无法进一步播放。我写第二次时停止写标题部分(44字节)。这并没有解决问题。

有人可以指导我如何实现至少2次写wav文件。

更新
工作代码如下所示。

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

#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int g_count = 0;

void init_config(int argc,char **argv);
void rewrite_file(int count);

int main(int argc, char **argv)
{
    init_config(argc, argv);
    printf("Count = %d\n", g_count);
    rewrite_file(g_count);
    return 0;
}

void rewrite_file(int count)
{
    int index;
    char arr[101];
    FILE *fd_in;
    FILE *fd_out;
    size_t len;
    unsigned short data_index = 0;
    index = 0;
    fd_in = fopen("./audio-g711a.wav", "r");
    fd_out = fopen("./audio-g711a-out.wav", "w+");

    // copy header
    len = fread(arr, 1, 40, fd_in);
    fwrite(arr, 1, len, fd_out);

    if( strncmp("data", (arr+36), 4) == 0 )
    {
        data_index = 40;
    }
    else
    {
        len = fread(arr, 1, 14, fd_in);
        fwrite(arr, 1, len, fd_out);

        if( strncmp("data", (arr+10), 4) == 0 )
        {
            data_index = 54;
        }
    }


    // update header
    uint32_t dl;
    fseek(fd_in, data_index, SEEK_SET);
    fseek(fd_out, data_index, SEEK_SET);
    fread(&dl, sizeof(dl), 1, fd_in);
    dl *= count;
    fwrite(&dl, sizeof(dl), 1, fd_out);

    // copy data
rw_again:
    index++;
    fseek(fd_in, (4 + data_index), SEEK_SET);
    len = fread(arr, 1, 100, fd_in);
    while(len > 0)
    {
        fwrite(arr, 1, len, fd_out);
        len = fread(arr, 1, 100, fd_in);
    }
    fwrite(arr, 1, len, fd_out);
    if(count > index)
    {
        printf("Completed %d round of operation of %d total rounds.\n", index, count);
        fclose(fd_in);
        fd_in = fopen("./audio-g711a.wav", "r");
        goto rw_again;
    }

    fclose(fd_in);
    fclose(fd_out);

    return;
}
void init_config(int argc,char **argv)
{
    int ch;

    while ((ch = getopt(argc, argv, "v:n:N:X")) != -1)
    {
        switch (ch)
        {
            case 'n':
            case 'N':
            {
                g_count = atoi(optarg);
            }
            break;

            default:
            break;

        }
    }

    return;
}

2 个答案:

答案 0 :(得分:1)

wav文件有一个标题和一个数据部分:

[HEADER][DATA]

正如您所做的那样,简单副本会生成以下文件格式:

[HEADER][DATA][HEADER][DATA]

您需要的是:

[HEADER][DATADATA]
     ^
     |
     +--- chunksize at offset 40 updated 

这是一个快速黑客:

void rewrite_file(int count)
{
    int index;
    char arr[101];
    FILE *fd_in;
    FILE *fd_out;
    size_t len;
    unsigned long chunk_size;

    index = 0;
    fd_in = fopen("./audio-g711a.wav", "r");
    fd_out = fopen("./audio-g711a-out.wav", "w+");

    // copy header
    len = fread(arr, 1, 40, fd_in);
    fwrite(arr, 1, len, fd_out);

    // update header
    uint32_t dl;
    fseek(fd_in, 40, SEEK_SET);
    fseek(fd_out, 40, SEEK_SET);
    fread(&dl, sizeof(dl), 1, fd_in);
    dl *= count;
    fwrite(&dl, sizeof(dl), 1, fd_out);

    // copy data
rw_again:
    index++;
    fseek(fd_in, 44, SEEK_SET);
    len = fread(arr, 1, 100, fd_in);
    while(len > 0)
    {
        fwrite(arr, 1, len, fd_out);
        len = fread(arr, 1, 100, fd_in);
    }
    fwrite(arr, 1, len, fd_out);
    if(count > index)
    {
        printf("Completed %d round of operation of %d total rounds.\n", index, count);
        fclose(fd_in);
        fd_in = fopen("./audio-g711a.wav", "r");        
        goto rw_again;
    }

    fclose(fd_in);
    fclose(fd_out);

    return;
}

<强>更新

如果wav文件中包含“&f”事实&#39;块(非PCM格式),则数据块大小偏移量不是40,而是例如54。因此,最好搜索数据&#39; -tag来计算数据块偏移量,而不是将40作为幻数。

答案 1 :(得分:1)

你需要加倍数据&#34;数据&#34;的一部分子块。

读取总chunksize(偏移量4)。

读取数据子块大小(偏移量40)。

这两个值应该增加子块大小(如果子块大小值中包含4个字节,则可能为-4)。

数据子块的数据部分(从偏移44开始)应加倍(写入两次)。