C语言读写32位wav文件

Read and write 32bit wav file in C

我正在用 C 语言制作一个读写 32 位 wav 文件的小程序。

但是,我遇到了一个问题。

编译后,有时程序运行良好,但有时却无法运行......如:

我真的堆在这里... 有人知道解决办法吗??

下面是我的程序

↓ wave32.h ↓

typedef struct
{
  int fs; 
  int bits;
  int length;
  double *s; 
} MONO_PCM;

void wave_read_32bit_mono(MONO_PCM *pcm, char *file_name)
{
  FILE *fp;
  char riff_chunk_ID[4];
  long riff_chunk_size;
  char file_format_type[4];
  char fmt_chunk_ID[4];
  long fmt_chunk_size;
  short wave_format_type;
  short channel;
  long samples_per_sec;
  long bytes_per_sec;
  short block_size;
  short bits_per_sample;
  char data_chunk_ID[4];
  long data_chunk_size;
  int data;
  int n;

  fp = fopen(file_name, "rb");

  fread(riff_chunk_ID, 1, 4, fp);
  fread(&riff_chunk_size, 4, 1, fp);
  fread(file_format_type, 1, 4, fp);
  fread(fmt_chunk_ID, 1, 4, fp);
  fread(&fmt_chunk_size, 4, 1, fp);
  fread(&wave_format_type, 2, 1, fp);
  fread(&channel, 2, 1, fp);
  fread(&samples_per_sec, 4, 1, fp);
  fread(&bytes_per_sec, 4, 1, fp);
  fread(&block_size, 2, 1, fp);
  fread(&bits_per_sample, 2, 1, fp);
  fread(data_chunk_ID, 1, 4, fp);
  fread(&data_chunk_size, 4, 1, fp);


  pcm->fs = samples_per_sec;
  pcm->bits = bits_per_sample;
  pcm->length = data_chunk_size / 4;
  pcm->s = calloc(pcm->length, sizeof(double));

  for (n = 0; n < pcm->length; n++)
  {
    fread(&data, 4, 1, fp);
    pcm->s[n] =  ( (double)data / 2147483648.0 ) ;
  }

  fclose(fp);
}
void wave_write_32bit_mono(MONO_PCM *pcm, char *file_name)
{
  FILE *fp;
  char riff_chunk_ID[4];
  long riff_chunk_size;
  char file_format_type[4];
  char fmt_chunk_ID[4];
  long fmt_chunk_size;
  short wave_format_type;
  short channel;
  long samples_per_sec;
  long bytes_per_sec;
  short block_size;
  short bits_per_sample;
  char data_chunk_ID[4];
  long data_chunk_size;
  double s;
  int data;
  int n;

  riff_chunk_ID[0] = 'R';
  riff_chunk_ID[1] = 'I';
  riff_chunk_ID[2] = 'F';
  riff_chunk_ID[3] = 'F';
  riff_chunk_size = 36 + pcm->length * 2;
  file_format_type[0] = 'W';
  file_format_type[1] = 'A';
  file_format_type[2] = 'V';
  file_format_type[3] = 'E';

  fmt_chunk_ID[0] = 'f';
  fmt_chunk_ID[1] = 'm';
  fmt_chunk_ID[2] = 't';
  fmt_chunk_ID[3] = ' ';
  fmt_chunk_size = 16;
  wave_format_type = 1;
  channel = 1;
  samples_per_sec = pcm->fs;
  bytes_per_sec = pcm->fs * pcm->bits / 8;
  block_size = pcm->bits / 8;
  bits_per_sample = pcm->bits;

  data_chunk_ID[0] = 'd';
  data_chunk_ID[1] = 'a';
  data_chunk_ID[2] = 't';
  data_chunk_ID[3] = 'a';
  data_chunk_size = pcm->length * 4;

  fp = fopen(file_name, "wb");

  fwrite(riff_chunk_ID, 1, 4, fp);
  fwrite(&riff_chunk_size, 4, 1, fp);
  fwrite(file_format_type, 1, 4, fp);
  fwrite(fmt_chunk_ID, 1, 4, fp);
  fwrite(&fmt_chunk_size, 4, 1, fp);
  fwrite(&wave_format_type, 2, 1, fp);
  fwrite(&channel, 2, 1, fp);
  fwrite(&samples_per_sec, 4, 1, fp);
  fwrite(&bytes_per_sec, 4, 1, fp);
  fwrite(&block_size, 2, 1, fp);
  fwrite(&bits_per_sample, 2, 1, fp);
  fwrite(data_chunk_ID, 1, 4, fp);
  fwrite(&data_chunk_size, 4, 1, fp);

  for (n = 0; n < pcm->length; n++)
  {
    s = (pcm->s[n]) * 2147483648.0;


    if (s > 2147483647.0)
    {
      s = 2147483647.0;
    }
    else if (s < -2147483647.0)
    {
      s = -2147483647.0;
    }

    data = (int)(s + 0.5);
    fwrite(&data, 4, 1, fp);
  }

  fclose(fp);
}

↓ wave32.c ↓

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "wave32.h"

int main(void)
{
  MONO_PCM pcm0, pcm1;
  int n;

  wave_read_32bit_mono(&pcm0, "sine32.wav"); // 1 sec sine wave 

  pcm1.fs = pcm0.fs;
  pcm1.bits = pcm0.bits;
  pcm1.length = pcm0.length;
  pcm1.s = calloc(pcm1.length, sizeof(double));

  for (n = 0; n < pcm1.length; n++)
  {

    pcm1.s[n] = pcm0.s[n];

  }

  wave_write_32bit_mono(&pcm1, "b.wav");

  free(pcm0.s);
  free(pcm1.s);

  return 0;
}

我猜你的平台有 8 个字节的 long。

您可以简单地检查它:

printf("Long= %zu bytes - int= %zu bytes\n", sizeof(long), sizeof(int));

那么当你使用时,例如

fread(&riff_chunk_size, 4, 1, fp);

由于字节顺序,您错误地读取了该值。

将所有 long 类型切换为 int 或更好的添加

#include <stdint.h>

并将您的变量类型更改为:

  • long -> int32_t
  • int -> int32_t
  • short -> int16_t