Wav文件写入和播放多重时间

时间:2022-02-13 19:42:54

I have a requirement, where I need to write a wav (with pcma data) file multiple times.

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

Say I have a file audio-g711a.wav. I want to write it to a new file say audio-g711a-out.wav 2 times. When I play audio-g711a-out.wav , it should play twice the longer duration than that of original file.

假设我有一个文件audio-g711 .wav。我想把它写入一个新的文件比如audio-g711a-out。wav 2倍。当我玩audio-g711a-out。wav,它的播放时间应该是原始文件的两倍。

I did write using below code. However it plays for exactly same duration as that of original file (I was expecting it to play double the duration).

我确实是用下面的代码写的。不过,它的播放时间与原始文件的播放时间完全相同(我原以为它的播放时间是原始文件的两倍)。

Code is as below.

代码如下。

#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;
}

To execute this, one can execute like ./a.out -n 2

要执行这个,可以像。/a那样执行。- n 2

After some R&D, I realized wav files have some sort of header. When I write second time, I am writing the header again. That may cause the file not to play further. I stopped writing the header part (44 bytes) while writing second time. This did not solve the issue.

经过一些研发,我意识到wav文件有一些头文件。当我第二次写的时候,我又在写标题了。这可能导致文件不能继续播放。我在第二次写头部分时停止了(44字节)。这并不能解决问题。

Can somebody please guide me how can I achieve writing a wav file for at least 2 times.

谁能告诉我怎么写wav文件至少2次。

Update
The working code is as given below.

更新工作代码如下所示。

#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 个解决方案

#1


1  

The wav file has a header and a data section:

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

[HEADER][DATA]

A simple copy, as you do, produces the following file format:

一个简单的拷贝,如你所做的,产生以下文件格式:

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

What you need is:

你需要的是:

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

Here is a quick hack:

这里有一个简单的技巧:

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;
}

Update:

更新:

If the wav file contains a 'fact' chunk (non-PCM formats), then data chunk size offset is not 40, but 54 for example. So it better to search the 'data'-tag to calculate the data chunk offset than to use the 40 as a magic number.

如果wav文件包含一个“事实”块(非pcm格式),那么数据块大小偏移量不是40,而是54。因此,搜索“data”标记来计算数据块偏移量比使用40作为一个神奇的数字要好。

#2


1  

You need to double the "data" part of the "data" subchunk.

您需要将“数据”子块的“数据”部分加倍。

Read the total chunksize (offset 4).

读取总chunksize(偏移4)。

Read the data subchunk size (offset 40).

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

Those two values should be increased by the subchunk size (maybe -4 if the 4 byte for the size is included in the subchunk size value).

这两个值应该通过子块大小来增加(如果将大小的4字节包含在子块大小值中,则可能是-4)。

The data part of the data subchunk (starting at offset 44) should be doubled (written twice).

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

#1


1  

The wav file has a header and a data section:

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

[HEADER][DATA]

A simple copy, as you do, produces the following file format:

一个简单的拷贝,如你所做的,产生以下文件格式:

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

What you need is:

你需要的是:

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

Here is a quick hack:

这里有一个简单的技巧:

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;
}

Update:

更新:

If the wav file contains a 'fact' chunk (non-PCM formats), then data chunk size offset is not 40, but 54 for example. So it better to search the 'data'-tag to calculate the data chunk offset than to use the 40 as a magic number.

如果wav文件包含一个“事实”块(非pcm格式),那么数据块大小偏移量不是40,而是54。因此,搜索“data”标记来计算数据块偏移量比使用40作为一个神奇的数字要好。

#2


1  

You need to double the "data" part of the "data" subchunk.

您需要将“数据”子块的“数据”部分加倍。

Read the total chunksize (offset 4).

读取总chunksize(偏移4)。

Read the data subchunk size (offset 40).

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

Those two values should be increased by the subchunk size (maybe -4 if the 4 byte for the size is included in the subchunk size value).

这两个值应该通过子块大小来增加(如果将大小的4字节包含在子块大小值中,则可能是-4)。

The data part of the data subchunk (starting at offset 44) should be doubled (written twice).

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