4.3 拙作 writewave.c (テキスト・ファイル→WAVE)

writewave は、 readwave の出力を読んで WAVE ファイルを作成する。 (完全な逆変換と言うわけではなく、ヘッダーが軽くなります。)

http://nalab.mind.meiji.ac.jp/~mk/program/sound/writewave.c

コンパイルと色々な使い方
oyabun% gcc -o writewave writewave.c
oyabun% ./readwave piano.wav piano.txt
oyabun% ./readwave piano.wav > piano2.txt
oyabun% ./writewave piano.txt piano1.wav
oyabun% ./writewave piano2.txt > piano2.wav
oyabun% ./readwave piano.wav | ./writewave > piano3.wav


/*
 * writewave.c --- 無圧縮PCMデータ(テキスト・ファイル)からWAVEファイルを作る
 *  version 1 (2003/12/21)
 *  version 2 (2013/10/26)
 *    ラベルの後に ; を入れた (コンパイル・エラー回避)。
 *    文字コードを UTF8 にした。
 *
 *  コンパイル: gcc -o writewave writewave.c
 *
 *  使い方:
 *   (1): ./writewave <テキスト・ファイル名> <WAVEファイル名>
 *   (2): ./writewave <テキスト・ファイル名>
 *           標準出力に出力
 *   (3): ./writewave
 *           標準入力から入力、標準出力に出力
 *
 *  入手:
 *    http://www.math.meiji.ac.jp/~mk/program/
 *
 *  参考にした情報
 *   URL: http://member.nifty.ne.jp/Ryuz/programing/wavefmt.html
 *        -> http://homepage3.nifty.com/ryuz/programing/wavefmt.html
 *
 *  普段置いてある場所
 *    ~/Sotsuken/2007/sound/readwave/
 */

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

int verbose = 1;

#define fwrite16(out,n) {fputc((n)&0xff,(out));fputc(((n)>>8)&0xff,(out));}

#define fwrite32(out,n) {fputc((n)&0xff,(out));fputc(((n)>>8)&0xff,(out));\
fputc(((n)>>16)&0xff,(out));fputc(((n)>>24)&0xff,(out));}

void usage(char *prog_name)
{
  fprintf(stderr, "usage: %s <txt-file> <wave-file>", prog_name);
  exit(1);
}

int main(int argc, char **argv)
{
  int num_channels, num_bits, num_samples, sampling_rate;
  FILE *in,*out;
  char buf[4096], original_fname[1024];
  char *prog_name, *input_fname, *output_fname;
  int left, right, c;
  int ready = 0, len;
  int fmt_size, fmt_tag, bytes_per_seconds, block, extended_information_size,
    data_size, riff_size;
  static char label[5][32] =
  {"#original file: ",
   "#number of channels: ",
   "#number of bits (per sample): ",
   "#number of samples: ", "#sampling rate: "};

  prog_name = argv[0];

  if (argc > 3) {
    usage(prog_name);
  }
  if (argc == 3) {
    output_fname = argv[2];
    if ((out = fopen(output_fname, "w")) == NULL) {
      fprintf(stderr, "出力ファイル %s がオープンできません。\n",
              output_fname);
      exit(1);
    }
  }
  else {
    output_fname = "stdout";
    out = stdout;
  }
  if (argc >= 2) {
    input_fname = argv[1];
    if ((in = fopen(input_fname, "r")) == NULL) {
      fprintf(stderr, "入力ファイル %s がオープンできません。",
              input_fname);
      exit(1);
    }
  }
  else {
    input_fname = "stdin";
    in = stdin;
  }
  while (fgets(buf, sizeof(buf), in) != NULL) {
    if (buf[0] == '#') {
      switch (buf[1]) {
      case 'o':
        if (strncmp(buf, label[0], len = strlen(label[0])) == 0) {
          sscanf(buf + len, "%s", original_fname);
          ready |= 0x01;
        }
        break;
      case 'n':
        if (strncmp(buf, label[1], len = strlen(label[1])) == 0) {
          sscanf(buf + len, "%d", &num_channels);
          ready |= 0x02;
        }
        else if (strncmp(buf, label[2], len = strlen(label[2])) == 0) {
          sscanf(buf + len, "%d", &num_bits);
          ready |= 0x04;
        }
        else if (strncmp(buf, label[3], len = strlen(label[3])) == 0) {
          sscanf(buf + len, "%d", &num_samples);
          ready |= 0x08;
        }
        else {
          fprintf(stderr, "unknown: %s\n", buf);
        }
        break;
      case 's':
        if (strncmp(buf, label[4], len = strlen(label[4])) == 0) {
          sscanf(buf + len, "%d", &sampling_rate);
          ready |= 0x10;
        }
        break;
      default:
        ;
        /* 何もしない */
      }
      if (ready == 0x1f) {
        if (verbose) {
          fprintf(stderr, "original file: %s\n", original_fname);
          fprintf(stderr, "number of channels: %d\n", num_channels);
          fprintf(stderr, "number of bits: %d\n", num_bits);
          fprintf(stderr, "number of samples: %d\n", num_samples);
          fprintf(stderr, "sampling rate: %d\n", sampling_rate);
        }
        break;
      }
    }
    else {
      /* パラメーターが揃わない (ready == 0x1f にならない) うちに
       * 生データが来たらエラーだ */
      printf("ready=%0x\n", ready);
      fprintf(stderr, "%s\n", buf);
      exit(1);
    }
  }

  /* fmt チャンク */
  fmt_size = 18; /* 2+2+4+4+2+2+2 */
  fmt_tag = 1; /* 無圧縮 PCM */
  bytes_per_seconds = sampling_rate * (num_bits / 8) * num_channels;
  block = 1; /* ブロック境界(何のこと?) */
  extended_information_size = 0;
  /* fact チャンクつけない */
  /* data チャンク */
  data_size = num_samples * (num_bits / 8) * num_channels;
  /* */
  riff_size = fmt_size + data_size;

  /* ヘッダーを書く */
  fprintf(out, "RIFF");
  fwrite32(out, riff_size);
  fprintf(out, "WAVE");
  fprintf(out, "fmt ");
  fwrite32(out, fmt_size);
  fwrite16(out, fmt_tag);           /* 2bytes */
  fwrite16(out, num_channels);      /* 2bytes */
  fwrite32(out, sampling_rate);     /* 4bytes */
  fwrite32(out, bytes_per_seconds); /* 4bytes */
  fwrite16(out, block);             /* 2bytes */
  fwrite16(out, num_bits);          /* 2bytes */
  fwrite16(out, extended_information_size); /* 2bytes */
  fprintf(out, "data");
  fwrite32(out, data_size);

  if (num_channels == 2 && num_bits == 16)
    while (fgets(buf, sizeof(buf), in) != NULL) {
      sscanf(buf, "%d%d", &left, &right);
      fputc(left & 0xff, out); fputc((left >> 8) & 0xff, out);
      fputc(right & 0xff, out); fputc((right >> 8) & 0xff, out);
    }
  else if (num_channels == 2 && num_bits == 8)
    while (fgets(buf, sizeof(buf), in) != NULL) {
      sscanf(buf, "%d%d", &left, &right);
      fputc(left & 0xff, out);
      fputc(right & 0xff, out);
    }
  else if (num_channels == 1 && num_bits == 16)
    while (fgets(buf, sizeof(buf), in) != NULL) {
      sscanf(buf, "%d", &c);
      fputc(c & 0xff, out); fputc((c >> 8) & 0xff, out);
    }
  else if (num_channels == 1 && num_bits == 8)
    while (fgets(buf, sizeof(buf), in) != NULL) {
      sscanf(buf, "%d", &c);
      fputc(c & 0xff, out);
    }
  fclose(out);
  return 0;
}

桂田 祐史
2018-12-12