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



Subsections
桂田 祐史
2017-10-09