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

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


   1 /*
   2  * readwave.c --- 無圧縮 WAVE ファイルを読んでテキスト・ファイルにする
   3  *                動作することはまったく保証しません
   4  *
   5  *  version 2 (2003/12/21)
   6  *  version 3 (2005/7/4) "PAD " チャンクの存在を知りそれに対応
   7  *  version 4 (2013/10/26) #include 増やした。文字コードをUTF8にした。
   8  *  version 5 (2014/8/12)  FLLR チャンクの存在を知りそれに対応
   9  *
  10  *  コンパイル: gcc -o readwave readwave.c
  11  *
  12  *  使い方:
  13  *   (1) ./readwave <WAVEファイル名> <テキスト・ファイル名>
  14  *   (2) ./readwave <WAVEファイル名>
  15  *          標準出力に出力
  16  *   (3) ./readwave
  17  *          標準入力から入力、標準出力に出力
  18  *
  19  *  入手:
  20  *    http://www.math.meiji.ac.jp/~mk/program/
  21  *
  22  *  参考にした情報
  23  *   URL: http://member.nifty.ne.jp/Ryuz/programing/wavefmt.html
  24  *        -> http://homepage3.nifty.com/ryuz/programing/wavefmt.html
  25  *
  26  *  普段置いてある場所
  27  *    ~/Sotsuken/2007/sound/readwave/
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <string.h>
  33 
  34 const int verbose = 0;
  35 const int debug = 0;
  36 FILE *out;
  37 
  38 void usage(char *prog)
  39 {
  40   fprintf(stderr, "usage (1): %s\n", prog);
  41   fprintf(stderr, "usage (2): %s <wave-file-name>\n", prog);
  42   fprintf(stderr, "usage (3): %s <wave-file-name> <text-file-name>\n", prog);
  43   exit(0);
  44 }
  45 
  46 void setstring(unsigned char *buf, FILE *in, int n)
  47 {
  48   int i;
  49   for (i = 0; i < n; i++)
  50     buf[i] = getc(in);
  51   buf[n] = 0;
  52 }
  53 
  54 int readint(FILE *in)
  55 {
  56   int c1, c2, c3, c4;
  57   c1 = getc(in); c2 = getc(in); c3 = getc(in); c4 = getc(in);
  58   return c1 + 256 * (c2 + 256 * (c3 + 256 * c4));
  59 }
  60 
  61 int checkstring(unsigned char *buf, char *key)
  62 {
  63   int i, n = strlen(key);
  64   for (i = 0; i < n; i++)
  65     if (buf[i] != key[i]) {
  66       fprintf(stderr, "%s は \"%s\" と一致しない\n", buf, key);
  67       exit(1);
  68     }
  69   return 0;
  70 }
  71 
  72 void dump(unsigned char *buf, int n)
  73 {
  74   int i;
  75   printf("# ");
  76   for (i = 0; i < n; i++) {
  77     printf(" %02x", buf[i]);
  78     if ((i + 1) % 16 == 0)
  79       printf("\n# ");
  80   }
  81   printf("\n");
  82 }
  83 
  84 int read2byte(unsigned char *buf)
  85 {
  86   return buf[0] + 256 * buf[1];
  87 }
  88 
  89 int read1(FILE *in)
  90 {
  91   int c = getc(in);
  92   if (debug) {
  93     printf("%02x ", c);
  94     fprintf(out, "%02x ", c);
  95   }
  96   return c;
  97 }
  98 
  99 int read2(FILE *in)
 100 {
 101   int c1, c2, c;
 102   c1 = getc(in); c2 = getc(in);
 103   if (debug) {
 104     printf("%02x %02x ", c1, c2);
 105     fprintf(out, "%02x %02x ", c1, c2);
 106   }
 107   c = c1 + (c2 << 8);
 108   if (c >= 32768)
 109     c -= 65536;
 110   return c;
 111 }
 112 
 113 int read4byte(unsigned char *buf)
 114 {
 115   return buf[0] + 256 * (buf[1] + 256 * (buf[2] + 256 * buf[3]));
 116 }
 117 
 118 void analyze(unsigned char *buf,
 119              int *fmt_tag, int *num_channel, int *sampling_rate,
 120              int *bytes_per_seconds, int *block, int *num_bits,
 121              int *extended_information_size)
 122 {
 123   *fmt_tag = read2byte(buf);
 124   *num_channel = read2byte(buf + 2);
 125   *sampling_rate = read4byte(buf + 4);
 126   *bytes_per_seconds = read4byte(buf + 8);
 127   *block = read2byte(buf + 12);
 128   *num_bits = read2byte(buf + 14);
 129   *extended_information_size = read2byte(buf + 16);
 130 }
 131 
 132 void readpcm(FILE *in, int size, int bits, int channel)
 133 {
 134   int i, c, right;
 135   if (bits == 16) {
 136     if (channel == 2) {
 137       for (i = 0; i < size / 4; i++) {
 138         c = read2(in); right = read2(in);
 139         if (verbose) printf("%d %d\n", c, right);
 140         fprintf(out, "%d %d\n", c, right);
 141       }
 142     }
 143     else {
 144       for (i = 0; i < size / 2; i++) {
 145         c = read2(in);
 146         if (verbose) printf("%d\n", c);
 147         fprintf(out, "%d\n", c);
 148       }
 149     }
 150   }
 151   else {
 152     if (channel == 2) {
 153       for (i = 0; i < size / 2; i++) {
 154         c = read1(in); right = read1(in);
 155         if (verbose) printf("%d %d\n", c, right);
 156         fprintf(out, "%d %d\n", c, right);
 157       }
 158     }
 159     else {
 160       for (i = 0; i < size; i++) {
 161         c = read1(in);
 162         if (verbose) printf("%d\n", c);
 163         fprintf(out, "%d\n", c);
 164       }
 165     }
 166   }
 167 }
 168 
 169 /* 取り扱うファイルの名前 */
 170 char *input_fname, *output_fname, *prog_name;
 171 
 172 int main(int argc, char **argv)
 173 {
 174   int size;
 175   FILE *in;
 176   unsigned char buf[5120];
 177   int fmt_tag, num_channel, sampling_rate, bytes_per_seconds;
 178   int block, num_bits, extended_information_size;
 179   
 180   prog_name = argv[0];
 181   if (argc > 3)
 182     usage(prog_name);
 183     
 184   if (argc == 3) {
 185     output_fname = argv[2];
 186     if ((out = fopen(output_fname, "w")) == NULL) {
 187       fprintf(stderr, "%s がオープンできません。\n", output_fname);
 188       exit(1);
 189     }
 190   }
 191   else {
 192       output_fname = "stdout";
 193       out = stdout;
 194   }
 195   if (argc >= 2) {
 196     input_fname = argv[1];
 197     if ((in = fopen(input_fname, "r")) == NULL) {
 198       fprintf(stderr, "%s がオープンできません。\n", input_fname);
 199       exit(1);
 200     }
 201   }
 202   else {
 203     input_fname = "input"; in = stdin;
 204   }
 205 
 206   /* ヘッダーを読む */
 207   setstring(buf, in, 4); checkstring(buf, "RIFF");
 208   size = readint(in); printf("# RIFF データのサイズ=%d\n", size);
 209   setstring(buf, in, 4); checkstring(buf, "WAVE");
 210   setstring(buf, in, 4); checkstring(buf, "fmt ");
 211   size = readint(in); printf("# fmt データのサイズ=%d\n", size);
 212   setstring(buf, in, size); dump(buf, size);
 213   analyze(buf, &fmt_tag, &num_channel, &sampling_rate,
 214           &bytes_per_seconds, &block, &num_bits,
 215           &extended_information_size);
 216   printf("# 非圧縮PCM%s。\n", (fmt_tag == 1) ? "です" : "ではありません");
 217   printf("# %sです。\n", (num_channel == 1) ? "モノラル" : "ステレオ");
 218   printf("# サンプリング・レート(標本化周波数)=%d\n", sampling_rate);
 219   printf("# 1秒当りのバイト数=%d\n", bytes_per_seconds);
 220   printf("# ブロック境界=%d\n", block);
 221   printf("# ビット数/サンプル=%d\n", num_bits);
 222   printf("# 拡張情報サイズ=%d\n", extended_information_size);
 223   setstring(buf, in, 4);
 224   /* 以下の if を書き加えた (2005/7/4) */
 225   if (strcmp(buf, "PAD ") == 0) {
 226     printf("# PAD チャンクがあります。");
 227     size = readint(in); printf("# PAD チャンクのサイズ=%d\n", size);    
 228     setstring(buf, in, size);
 229     dump(buf, size);
 230     setstring(buf, in, 4);
 231   }
 232   if (strcmp(buf, "fact") == 0) {
 233     printf("# fact チャンクがあります。");
 234     size = readint(in); printf("# fact データのサイズ=%d\n", size);
 235 #ifdef OLD
 236     setstring(buf, in, 4);  /* 多分 BUG */
 237 #else
 238     setstring(buf, in, size);
 239 #endif
 240     dump(buf, size);
 241     setstring(buf, in, 4);
 242   }
 243   /* */
 244   if (strcmp(buf, "FLLR") == 0) {
 245     printf("# FLLR チャンクがあります。");
 246     size = readint(in); printf("# FLLR データのサイズ=%d\n", size);
 247     setstring(buf, in, size);
 248     dump(buf, size);
 249     setstring(buf, in, 4);
 250   }
 251   /* */
 252   checkstring(buf, "data");
 253   size = readint(in); printf("# data データのサイズ=%d\n", size);    
 254 
 255   /* 書き出す */
 256   fprintf(out, "#original file: %s\n", input_fname);
 257   fprintf(out, "#number of channels: %d\n", num_channel);
 258   fprintf(out, "#sampling rate: %d\n", sampling_rate);
 259   fprintf(out, "#number of bits (per sample): %d\n", num_bits);
 260   fprintf(out, "#number of samples: %d\n",
 261           size / num_channel / (num_bits / 8));
 262   readpcm(in, size, num_bits, num_channel);
 263   fclose(out);
 264 
 265   return 0;
 266 }

(2014/8/12) data が来るかというところで、FLLR というのが入ることがあり、 そういうのは読めないことが判明した。



Subsections
桂田 祐史
2016-11-16