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