http://nalab.mind.meiji.ac.jp/~mk/program/sound/readwave.c
やっつけの、リバースエンジニアリングの、あまり人に見せたくない…
ピアノの音を録音した piano.wav という WAVE ファイルの内容をテキスト・ファイルに変換してみる。
| oyabun% gcc -o readwave readwave.c oyabun% ./readwave piano.wav piano.txt oyabun% ./readwave piano.wav > piano2.txt | 
| oyabun% ls -l piano.wav piano.txt piano2.txt -rw-r--r-- 1 mk lab00 2814838 3月 6日 13:44 piano.txt -rw-r--r-- 1 mk lab00 2828151 3月 6日 13:49 piano2.txt -rw-r--r-- 1 mk lab00 1234592 1月 23日 20:39 piano.wav oyabun% head piano.txt #original file: piano.wav #number of channels: 2 #sampling rate: 44100 #number of bits (per sample): 16 #number of samples: 307017 64 64 62 62 65 62 65 63 65 60 | 
| piano2.txt (少し冗長) | 
| # RIFF データのサイズ=1234584 # fmt データのサイズ=18 # 01 00 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 # 00 00 # 非圧縮PCMです。 # ステレオです。 # サンプリング・レート(標本化周波数)=44100 # 1秒当りのバイト数=176400 # ブロック境界=4 # ビット数/サンプル=16 # 拡張情報サイズ=0 # PAD チャンクがあります。# PAD チャンクのサイズ=4042 # 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (中略) # 00 00 00 00 00 00 00 00 00 00 # fact チャンクがあります。# fact データのサイズ=4 # 49 af 04 00 # data データのサイズ=1228068 #original file: piano.wav #number of channels: 2 #sampling rate: 44100 #number of bits (per sample): 16 #number of samples: 307017 64 64 62 62 (中略 --- 結構長い) -114 -63 -111 -59 -112 -61 -109 -53 -108 -51 | 
/*
 * readwave.c --- 無圧縮 WAVE ファイルを読んでテキスト・ファイルにする
 *                動作することはまったく保証しません
 *
 *  version 2 (2003/12/21)
 *  version 3 (2005/7/4) "PAD " チャンクの存在を知りそれに対応
 *  version 4 (2013/10/26) #include 増やした。文字コードをUTF8にした。
 *  version 5 (2014/8/12)  FLLR チャンクの存在を知りそれに対応
 *  version 5.1 (2017/10/9)  www.math.meiji.ac.jp を変える
 *  version 6 (2020/12/22) LIST チャンクの存在を知りそれに対応
 *  version 7 (2020/12/24) fread() を使うようにした
 *
 *  コンパイル: gcc -o readwave readwave.c
 *
 *  使い方:
 *   (1) ./readwave <WAVEファイル名> <テキスト・ファイル名>
 *   (2) ./readwave <WAVEファイル名>
 *          標準出力に出力
 *   (3) ./readwave
 *          標準入力から入力、標準出力に出力
 *
 *  入手:
 *    http://nalab.mind.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 <string.h>
const int verbose = 1;
const int debug = 0;
FILE *out;
void usage(char *prog)
{
  fprintf(stderr, "usage (1): %s\n", prog);
  fprintf(stderr, "usage (2): %s <wave-file-name>\n", prog);
  fprintf(stderr, "usage (3): %s <wave-file-name> <text-file-name>\n", prog);
  exit(0);
}
int readint(FILE *in)
{
  int c1, c2, c3, c4;
  c1 = getc(in); c2 = getc(in); c3 = getc(in); c4 = getc(in);
  return c1 + 256 * (c2 + 256 * (c3 + 256 * c4));
}
int checkstring(unsigned char *buf, char *key)
{
  int i, n = strlen(key);
  for (i = 0; i < n; i++)
    if (buf[i] != key[i]) {
      fprintf(stderr, "%s は \"%s\" と一致しない\n", buf, key);
      exit(1);
    }
  return 0;
}
void dump(unsigned char *buf, int n)
{
  int i;
  printf("# ");
  for (i = 0; i < n; i++) {
    printf(" %02x", buf[i]);
    if ((i + 1) % 16 == 0)
      printf("\n# ");
  }
  printf("\n");
}
int read2byte(unsigned char *buf)
{
  return buf[0] + 256 * buf[1];
}
int read1(FILE *in)
{
  int c = getc(in);
  if (debug) {
    printf("%02x ", c);
    fprintf(out, "%02x ", c);
  }
  return c;
}
int read2(FILE *in)
{
  int c1, c2, c;
  c1 = getc(in); c2 = getc(in);
  if (debug) {
    printf("%02x %02x ", c1, c2);
    fprintf(out, "%02x %02x ", c1, c2);
  }
  c = c1 + (c2 << 8);
  if (c >= 32768)
    c -= 65536;
  return c;
}
int read4byte(unsigned char *buf)
{
  return buf[0] + 256 * (buf[1] + 256 * (buf[2] + 256 * buf[3]));
}
void analyze(unsigned char *buf,
             int *fmt_tag, int *num_channel, int *sampling_rate,
             int *bytes_per_seconds, int *block, int *num_bits,
             int *extended_information_size)
{
  *fmt_tag = read2byte(buf);
  *num_channel = read2byte(buf + 2);
  *sampling_rate = read4byte(buf + 4);
  *bytes_per_seconds = read4byte(buf + 8);
  *block = read2byte(buf + 12);
  *num_bits = read2byte(buf + 14);
  *extended_information_size = read2byte(buf + 16);
}
void readpcm(FILE *in, int size, int bits, int channel)
{
  int i, c, right;
  if (bits == 16) {
    if (channel == 2) {
      for (i = 0; i < size / 4; i++) {
        c = read2(in); right = read2(in);
        if (verbose) printf("%d %d\n", c, right);
        fprintf(out, "%d %d\n", c, right);
      }
    }
    else {
      for (i = 0; i < size / 2; i++) {
        c = read2(in);
        if (verbose) printf("%d\n", c);
        fprintf(out, "%d\n", c);
      }
    }
  }
  else {
    if (channel == 2) {
      for (i = 0; i < size / 2; i++) {
        c = read1(in); right = read1(in);
        if (verbose) printf("%d %d\n", c, right);
        fprintf(out, "%d %d\n", c, right);
      }
    }
    else {
      for (i = 0; i < size; i++) {
        c = read1(in);
        if (verbose) printf("%d\n", c);
        fprintf(out, "%d\n", c);
      }
    }
  }
}
/* 取り扱うファイルの名前 */
char *input_fname, *output_fname, *prog_name;
int main(int argc, char **argv)
{
  int size;
  FILE *in;
  unsigned char buf[5120];
  unsigned char *buf2;
  int fmt_tag, num_channel, sampling_rate, bytes_per_seconds;
  int block, num_bits, extended_information_size;
  
  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 がオープンできません。\n", input_fname);
      exit(1);
    }
  }
  else {
    input_fname = "input"; in = stdin;
  }
  // setstring(buf, in, 4) は fread(buf, 1, 4, in) で良いかな。
  /* ヘッダーを読む */
  fread(buf, 1, 4, in); checkstring(buf, "RIFF");
  size = readint(in); printf("# RIFF データのサイズ=%d\n", size);
  fread(buf, 1, 4, in); checkstring(buf, "WAVE");
  fread(buf, 1, 4, in); checkstring(buf, "fmt ");
  size = readint(in); printf("# fmt データのサイズ=%d\n", size);
  fread(buf, 1, size, in); dump(buf, size);
  analyze(buf, &fmt_tag, &num_channel, &sampling_rate,
          &bytes_per_seconds, &block, &num_bits,
          &extended_information_size);
  printf("# 非圧縮PCM%s。\n", (fmt_tag == 1) ? "です" : "ではありません");
  printf("# %sです。\n", (num_channel == 1) ? "モノラル" : "ステレオ");
  printf("# サンプリング・レート(標本化周波数)=%d\n", sampling_rate);
  printf("# 1秒当りのバイト数=%d\n", bytes_per_seconds);
  printf("# ブロック境界=%d\n", block);
  printf("# ビット数/サンプル=%d\n", num_bits);
  printf("# 拡張情報サイズ=%d\n", extended_information_size);
  while (1) {
    fread(buf, 1, 4, in);
    if (strncmp("data", (char *)buf, 4) == 0) {
      if (verbose)
	printf("# dataチャンク見つかった\n");
      break;
    }
    else {
      // dataチャンク以外。"PAD "とか "FLLR" とか "fact" とか "LIST" とか
      if (verbose) {
	buf[4] = 0;
	printf("# %s チャンクがある。サイズは%d\n", buf, size = readint(in));
	
	fread(buf, 1, size, in);
	dump(buf, size);
      }
      else {
	size = readint(in);
	fseek(in, size, SEEK_CUR);
      }
    }
  }
  size = readint(in);
  if (verbose)
    printf("# data データのサイズ=%d\n", size);    
  /* 書き出す */
  fprintf(out, "#original file: %s\n", input_fname);
  fprintf(out, "#number of channels: %d\n", num_channel);
  fprintf(out, "#sampling rate: %d\n", sampling_rate);
  fprintf(out, "#number of bits (per sample): %d\n", num_bits);
  fprintf(out, "#number of samples: %d\n",
          size / num_channel / (num_bits / 8));
  readpcm(in, size, num_bits, num_channel);
  fclose(out);
  return 0;
}