Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 生成错误的WAV文件_C_File_Audio_Wav_Portaudio - Fatal编程技术网

C 生成错误的WAV文件

C 生成错误的WAV文件,c,file,audio,wav,portaudio,C,File,Audio,Wav,Portaudio,我有一些代码可以使用捕获音频,然后尝试将其打包到。然后我尝试将该文件转换为,但它一直告诉我它不是有效的.wav文件 wav.h: #include <stdint.h> #include <string.h> /** * @struct WaveHeader * @brief A basic WAVE header */ typedef struct { char RIFF_marker[4]; uint32_t file_size; c

我有一些代码可以使用捕获音频,然后尝试将其打包到。然后我尝试将该文件转换为,但它一直告诉我它不是有效的
.wav
文件

wav.h

#include <stdint.h>
#include <string.h>

/**
 * @struct WaveHeader
 * @brief A basic WAVE header
 */

typedef struct
{
    char RIFF_marker[4];
    uint32_t file_size;
    char filetype_header[4];
    char format_marker[4];
    uint32_t data_header_length;
    uint16_t format_type;
    uint16_t number_of_channels;
    uint32_t sample_rate;
    uint32_t bytes_per_second;
    uint16_t bytes_per_frame;
    uint16_t bits_per_sample;
} WaveHeader;

WaveHeader *genericWAVHeader(uint32_t sample_rate, uint16_t bit_depth, uint16_t channels);
WaveHeader *retrieveWAVHeader(const void *ptr);
int writeWAVHeader(FILE* fd, WaveHeader *hdr);
int recordWAV(const char *fileName, WaveHeader *hdr, uint32_t duration);
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <unistd.h>
#include <math.h>
#include "wav.h"

typedef struct
{
    int frameIndex;  /* Index into sample array. */
    int maxFrameIndex;
    char* recordedSamples;
} PAData;

WaveHeader *genericWAVHeader(uint32_t sample_rate, uint16_t bit_depth, uint16_t channels)
{
    WaveHeader *hdr = malloc(sizeof(*hdr));
    if (!hdr) return NULL;

    memcpy(&hdr->RIFF_marker, "RIFF", 4);
    memcpy(&hdr->filetype_header, "WAVE", 4);
    memcpy(&hdr->format_marker, "fmt ", 4);
    hdr->data_header_length = 16;
    hdr->format_type = 1;
    hdr->number_of_channels = channels;
    hdr->sample_rate = sample_rate;
    hdr->bytes_per_second = sample_rate * channels * bit_depth / 8;
    hdr->bytes_per_frame = channels * bit_depth / 8;
    hdr->bits_per_sample = bit_depth;

    return hdr;
}
int writeWAVHeader(FILE* fd, WaveHeader *hdr)
{
    if (!hdr) return -1;

    fwrite(&hdr->RIFF_marker, sizeof(*hdr->RIFF_marker), sizeof(&hdr->RIFF_marker), fd);
    fwrite(&hdr->file_size, sizeof(hdr->file_size), sizeof(&hdr->file_size), fd);
    fwrite(&hdr->filetype_header, sizeof(*hdr->filetype_header), sizeof(&hdr->filetype_header), fd);
    fwrite(&hdr->format_marker, sizeof(*hdr->format_marker), sizeof(&hdr->format_marker), fd);
    fwrite(&hdr->data_header_length, sizeof(hdr->data_header_length), sizeof(&hdr->data_header_length), fd);
    fwrite(&hdr->format_type, sizeof(hdr->format_type), sizeof(&hdr->format_type), fd);
    fwrite(&hdr->number_of_channels, sizeof(hdr->number_of_channels), sizeof(&hdr->number_of_channels), fd);
    fwrite(&hdr->sample_rate, sizeof(hdr->sample_rate), sizeof(&hdr->sample_rate), fd);
    fwrite(&hdr->bytes_per_second, sizeof(hdr->bytes_per_second), sizeof(&hdr->bytes_per_second), fd);
    fwrite(&hdr->bytes_per_frame, sizeof(hdr->bytes_per_frame), sizeof(&hdr->bytes_per_frame), fd);
    fwrite(&hdr->bits_per_sample, sizeof(hdr->bits_per_sample), sizeof(&hdr->bits_per_sample), fd);
    fwrite("data", 1, sizeof("data") - 1, fd);

    uint32_t data_size = hdr->file_size - 36;
    fwrite(&data_size, sizeof(data_size), sizeof(&data_size), fd);

    return 0;
}

static int recordCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
    PAData *data = (PAData*) userData;
    const char *rptr = (const char*) inputBuffer;
    char *wptr = &data->recordedSamples[data->frameIndex * 2 /*channels*/];
    long framesToCalc;
    int finished;
    unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;

    (void) outputBuffer; /* Prevent unused variable warnings. */
    (void) timeInfo;
    (void) statusFlags;
    (void) userData;

    if(framesLeft < framesPerBuffer)
    {
        framesToCalc = framesLeft;
        finished = paComplete;
    }
    else
    {
        framesToCalc = framesPerBuffer;
        finished = paContinue;
    }

    if(!inputBuffer)
    {
        for(long i = 0; i < framesToCalc; i++)
        {
            *wptr++ = 0;  /* left */
            *wptr++ = 0;  /* right */
        }
    }
    else
    {
        for(long i = 0; i < framesToCalc; i++)
        {
            *wptr++ = *rptr++;  /* left */
            *wptr++ = *rptr++;  /* right */
        }
    }
    data->frameIndex += framesToCalc;
    return finished;
}

int recordWAV(const char *fileName, WaveHeader *hdr, uint32_t duration)
{
    PaStreamParameters inputParameters;
    PaStream* stream;
    PaError err = paNoError;
    PAData data;
    int totalFrames;
    int numSamples;
    int numBytes;
    char max, val;
    double average;
    printf("%d", hdr->bytes_per_second);
    data.maxFrameIndex = totalFrames = duration * hdr->sample_rate; /* Record for a few seconds. */
    data.frameIndex = 0;
    numSamples = totalFrames * hdr->number_of_channels;
    numBytes = numSamples;
    data.recordedSamples = malloc(numBytes);
    if(!data.recordedSamples)
    {
        printf("Could not allocate record array.\n");
        goto done;
    }
    for(int i = 0; i < numSamples; i++) data.recordedSamples[i] = 0;

    if((err = Pa_Initialize())) goto done;

    inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
    if (inputParameters.device == paNoDevice) {
        fprintf(stderr,"Error: No default input device.\n");
        goto done;
    }
    inputParameters.channelCount = 2;                    /* stereo input */
    inputParameters.sampleFormat = 1;
    inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
    inputParameters.hostApiSpecificStreamInfo = NULL;

    /* Record some audio. -------------------------------------------- */
    err = Pa_OpenStream(&stream, &inputParameters, NULL, hdr->sample_rate, paFramesPerBufferUnspecified, paClipOff, recordCallback, &data);
    if(err) goto done;
    if((err = Pa_StartStream(stream))) goto done;
    puts("Now recording!! Please speak into the microphone.");

    while((err = Pa_IsStreamActive(stream)) == 1)
    {
        Pa_Sleep(1000);
        printf("index = %d\n", data.frameIndex);
    }
    if( err < 0 ) goto done;

    err = Pa_CloseStream(stream);
    if(err) goto done;

    /* Measure maximum peak amplitude. */
    max = 0;
    average = 0.0;
    for(int i = 0; i < numSamples; i++)
    {
        val = data.recordedSamples[i];
        val = abs(val);
        if( val > max )
        {
            max = val;
        }
        average += val;
    }

    average /= (double)numSamples;

    {
        FILE* fid = fopen(fileName, "wb");
        if(!fid) printf("Could not open file.");
        else
        {
            writeWAVHeader(fid, hdr);
            fwrite(data.recordedSamples, hdr->number_of_channels, totalFrames, fid);
            fclose(fid);
        }
    }

done:
    Pa_Terminate();
    if(data.recordedSamples)       /* Sure it is NULL or valid. */
        free(data.recordedSamples);
    if(err)
    {
        fprintf(stderr, "An error occured while using the portaudio stream\n");
        fprintf(stderr, "Error number: %d\n", err);
        fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
        err = 1;          /* Always return 0 or 1, but no other return codes. */
    }
    return err;
}
我在该文件上运行的一些测试:

$xxd-g1 test.wav |头
0000000:52 49 46 00 00 00 30 00 00 00 30 57 41 56 45里夫…0…0波
0000010:66 6d 74 20 10 00 00 01 00 02 00 e0 ab 00 00 fmt。。。。。。。。。。。。
0000020:80 af 02 00 04 00 10 00 57 41 56 45 66 6d 74 20……波
0000030:66 6d 74 20 10 00 00 10 00 00 01 00 02 00 fmt。。。。。。。。。。。。
0000040:e0 ab 00 80 af 02 00 04 00 10 00 00 80。。。。。。。。。。。。。。。。
0000050:37 3d 04 10 00 00 03 00 01 00 02 00 e0 ab 00 00 7=。。。。。。。。。。。。。。
0000060:80 af 02 00 04 00 10 00 02 00 e0 ab 00 00 80 af。。。。。。。。。。。。。。。。
0000070:02 00 04 00 10 00 00 00 e0 ab 00 00 80 af 02 00。。。。。。。。。。。。。。。。
0000080:04 00 10 00 00 00 00 80 37 3d 04 10 00 00 03 00…….7=。。。。。。
0000090:00 00 00 00 00 80 af 02 00 04 00 10 00。。。。。。。。。。。。。。。。
$file test.wav
test.wav:RIFF(小端)数据
$stat-f%s test.wav
统计:%s:格式错误

我不太确定我会错在哪里。我没有正确地写出数据吗?

我不知道它的其余部分,但是您的
fwrite
s应该是这样的:

fwrite( hdr->RIFF_marker,        sizeof(hdr->RIFF_marker),        1, fd);
fwrite(&hdr->file_size,          sizeof(hdr->file_size),          1, fd);
fwrite( hdr->filetype_header,    sizeof(hdr->filetype_header),    1, fd);
fwrite( hdr->format_marker,      sizeof(hdr->format_marker),      1, fd);
fwrite(&hdr->data_header_length, sizeof(hdr->data_header_length), 1, fd);
fwrite(&hdr->format_type,        sizeof(hdr->format_type),        1, fd);
fwrite(&hdr->number_of_channels, sizeof(hdr->number_of_channels), 1, fd);
fwrite(&hdr->sample_rate,        sizeof(hdr->sample_rate),        1, fd);
fwrite(&hdr->bytes_per_second,   sizeof(hdr->bytes_per_second),   1, fd);
fwrite(&hdr->bytes_per_frame,    sizeof(hdr->bytes_per_frame),    1, fd);
fwrite(&hdr->bits_per_sample,    sizeof(hdr->bits_per_sample),    1, fd);
fwrite("data", 4, 1, fd);

wav文件格式是联机的。一个字节一个字节地浏览,找出错误所在。仔细阅读你的
fwrite
s。那里有错误。特别是,第三个参数不应该是地址!它实际上应该是
1
。第二个4字节的长度应该是little endian。“WAVE”应该从字节8开始。我没有试图超越这一点。@HotLicks Endianness不是问题所在,正如ooga所证明的那样。也许你下次应该试着走得更远一点。我只是按照规范来做。如果你使用big-endian,标记应该是RIFX。这会生成一个
.wav
文件,但它的所有内容都是静态的。@syb0rg该代码正确地写入了数据,但我没有查看wav文件的结构。你必须检查一下。因为这产生了一个有效的
.wav
文件,所以你回答了我的问题。