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; }