/******************************************************************/ /* wav ヘッダ情報出力プログラム */ /* [RIFF] [WAVE] */ /* 主なチャンク */ /* : フォーマット定義(必須) */ /* : 波形データ(必須) */ /* : サンプル数 */ /* : 各種情報 */ /* : 表示情報 */ /* */ /* 2001.05.03 */ /* kondo@kk.iij4u.or.jp */ /*******************************************************************/ #include #include #include void openError(char *filename) { fprintf(stderr, "cannot open file : %s\n", filename); exit(EXIT_FAILURE); } void readError(FILE *fp) { fprintf(stderr, "read error : %ld\n", ftell(fp)); fclose(fp); exit(EXIT_FAILURE); } /*-----------------------------*/ /* 4Byte 読み込み 10進数に変換 */ /*-----------------------------*/ unsigned long get_ulong(FILE *fp) { unsigned char s[4]; if (fread(s, 4, 1, fp) != 1) { readError(fp); } return (s[0] + 256L * (s[1] + 256L * (s[2] + 256L * s[3]))); } /*-----------------------------*/ /* 2Byte 読み込み 10進数に変換 */ /*-----------------------------*/ unsigned short get_ushort(FILE *fp) { unsigned char s[2]; if (fread(s, 2, 1, fp) != 1) { readError(fp); } return (s[0] + 256U * s[1]); } /*----------------------*/ /* chunkID と chunkSize */ /*----------------------*/ long chunkSize(FILE *fp, char *chunkID) { if (fread(chunkID, 4, 1, fp) != 1) { return -1; } return get_ulong(fp); } /*---------------------------*/ /* format チャンクのチェック */ /*---------------------------*/ void fmt_chunkRead(FILE *fp) { short tag; // 2Byte wFormatTag フォーマット形式 tag = get_ushort(fp); switch (tag) { case 0: printf(" unknown format\n"); break; case 1: printf(" PCM format\n"); break; case 2: printf(" MS ADPCM format\n"); break; case 6: printf(" A-Law format\n"); break; case 7: printf(" mu-Law format\n"); break; default: printf(" format tag = %u\n", tag); break; } // 2Byte wChannels チャンネル数 printf(" channels = %u\n", get_ushort(fp)); // 4Byte dwSamplesPerSec サンプリングレート printf(" samples/sec = %lu\n", get_ulong(fp)); // 4Byte dwAvgBytesPerSec データ速度 printf(" avg. bytes/sec = %lu\n", get_ulong(fp)); // 2Byte wBlockAlign ブロックサイズ printf(" block align = %u\n", get_ushort(fp)); // 2Byte wBitsPerSample サンプルあたりのビット数 printf(" bits/sample = %u\n", get_ushort(fp)); } /*------------------------*/ /* cue チャンクのチェック */ /*------------------------*/ void cue_chunkRead(FILE *fp) { long i, CuePoints; unsigned char s[5]; // 4Byte dwCuePoints CuePoints = get_ulong(fp); for (i = 0; i < CuePoints; i++) { // 4Byte dwIdentifier printf(" #%lu: ", get_ulong(fp)); // 4Byte dwPosition printf("position %lu, ", get_ulong(fp)); // 4Byte fccChunk if (fread(s, 4, 1, fp) != 1) { readError(fp); } s[4] = '\0'; printf("'%s', ", s); // 4Byte dwChunkStart printf("chunk start %lu, ", get_ulong(fp)); // 4Byte dwBlockStart printf("block start %lu, ", get_ulong(fp)); // 4Byte dwSampleOffset printf("sample offset %lu\n", get_ulong(fp)); } } void plstchunkRead(FILE *fp) { long i, segments; // 4Byte dwSegments segments = get_ulong(fp); for (i = 0; i < segments; i++) { // 4Byte dwIdentifier printf(" #%lu: ", get_ulong(fp)); // 4Byte dwLength printf("%lu samples, ", get_ulong(fp)); // 4Byte dwRepeats printf("%lu repeats\n", get_ulong(fp)); } } /*-------------------------*/ /* fact チャンクのチェック */ /*-------------------------*/ void factchunkRead(FILE *fp) { // サンプル数 printf(" samples = %ld\n", get_ulong(fp)); } /*-------------------------*/ /* INFO チャンクのチェック */ /*-------------------------*/ void INFOchunkRead(FILE *fp) { long i, size, cursor; char ID[5]; size = chunkSize(fp, ID); cursor = ftell(fp); if (size % 2 == 1) { size += 1; } // artist アーティスト名 if (strncmp(ID, "IART", 4) == 0) { printf(" arist : "); } // commisioned コミッション else if (strncmp(ID, "ICMS", 4) == 0) { printf(" commissioned : "); } // comment コメント else if (strncmp(ID, "ICMT", 4) == 0) { printf(" comments : "); } // copyright 著作権情報 else if (strncmp(ID, "ICOP", 4) == 0) { printf(" copyright : "); } // creation date 作成日 else if (strncmp(ID, "ICRD", 4) == 0) { printf(" creation date : "); } // name 名前 else if (strncmp(ID, "INAM", 4) == 0) { printf(" name : "); } // product 製品名 else if (strncmp(ID, "IPRD", 4) == 0) { printf(" product : "); } // genre ジャンル else if (strncmp(ID, "IGNR", 4) == 0) { printf(" genre : "); } // engineer エンジニア名 else if (strncmp(ID, "IENG", 4) == 0) { printf(" engineer : "); } // source オリジナルを作成した人名 else if (strncmp(ID, "ISRC", 4) == 0) { printf(" source : "); } // software 作成に使用したソフトウェア else if (strncmp(ID, "ISFT", 4) == 0) { printf(" software : "); } // keywords キーワード else if (strncmp(ID, "IKEY", 4) == 0) { printf(" keywords : "); } // technician 技術者名 else if (strncmp(ID, "ITCH", 4) == 0) { printf(" technician : "); } // subject タイトル else if (strncmp(ID, "ISBJ", 4) == 0) { printf(" subject : "); } else { ID[4] = '\0'; printf(" %s :", ID); } for (i = 0; i < size; i++) { printf("%c", fgetc(fp)); } printf("\n"); fseek(fp, cursor + size, SEEK_SET); } /*----------------------------------*/ /* Associated Data チャンクチェック */ /*----------------------------------*/ void adtlchunkRead(FILE *fp) { long size, cursor; char ID[5]; char c; size = chunkSize(fp, ID); cursor = ftell(fp); if (size % 2 == 1) { size += 1; } ID[4] = '\0'; printf(" <%s>\n", ID); // Label チャンク if (strncmp(ID, "labl", 4) == 0) { printf(" #%ld: \"", get_ulong(fp)); } // Note チャンク else if (strncmp(ID, "note", 4) == 0) { printf(" #%ld: \"", get_ulong(fp)); } // Labeled Text チャンク else if (strncmp(ID, "ltxt", 4) == 0) { printf(" #%ld: ", get_ulong(fp)); printf("%ld, \"", get_ulong(fp)); } // Embeddid File チャンク else if (strncmp(ID, "file", 4) == 0) { printf(" #%ld: ", get_ulong(fp)); printf("%ld, \"", get_ulong(fp)); } while ((c = (char) fgetc(fp)) != '\0') { printf("%c", c); } printf("\"\n"); fseek(fp, cursor + size, SEEK_SET); } /*------------------------*/ /* LISTチャンクのチェック */ /*------------------------*/ void LISTchunkRead(FILE *fp, long region) { long size, cursor; unsigned char ID[5]; if (fread(ID, 4, 1, fp) != 1) { readError(fp); } ID[4] = '\0'; printf(" '%s'\n", ID); // INFOチャンク if (strncmp(ID, "INFO", 4) == 0) { while (ftell(fp) < region) { INFOchunkRead(fp); } } // adtlチャンク else if (strncmp(ID, "adtl", 4) == 0) { while (ftell(fp) < region) { adtlchunkRead(fp); } } else { while (ftell(fp) < region) { size = chunkSize(fp, ID); cursor = ftell(fp); ID[4] = '\0'; if (size % 2 == 1) { size += 1; } printf(" <%s>\n", ID); fseek(fp, cursor + size, SEEK_SET); } } } /*-------------------------*/ /* DISP チャンクのチェック */ /*-------------------------*/ void DISPchunkRead(FILE *fp) { char c; unsigned long type; type = get_ulong(fp); // テキスト情報 if (type == 1) { printf(" \""); while ((c = (char) fgetc(fp)) != '\0') { printf("%c", c); } printf("\"\n"); } else { printf(" type = %ld\n", type); } } /*----------------------*/ /* ファイル情報読み出し */ /*----------------------*/ void wavRead(FILE *fp) { long cursor, size; unsigned char ID[5]; // 4Byte RIFF ヘッダ情報 "RIFF" if ((size = chunkSize(fp, ID)) <= 0) { readError(fp); } if (strncmp(ID, "RIFF", 4) != 0) { fprintf(stderr, "Not a 'RIFF' format : %s\n", ID); fclose(fp); exit(EXIT_FAILURE); } printf("[RIFF] (%lu bytes)\n", size); // 4Byte WAVE ヘッダ情報 'W''A''V''E' if (fread(ID, 4, 1, fp) != 1) { readError(fp); } if (strncmp(ID, "WAVE", 4) != 0) { fprintf(stderr, "Not a 'WAVE' format : %s\n", ID); fclose(fp); exit(EXIT_FAILURE); } printf("[WAVE]\n"); // チャンク情報 while ((size = chunkSize(fp, ID)) > 0) { cursor = ftell(fp); ID[4] = '\0'; printf(" <%s> (%ld bytes)\n", ID, size); // 奇数長の場合 0を詰めて偶数長にする if (size % 2 == 1) { size += 1; } if (strncmp(ID, "fmt ", 4) == 0) { fmt_chunkRead(fp); } else if (strncmp(ID, "fact", 4) == 0) { factchunkRead(fp); } else if (strncmp(ID, "cue ", 4) == 0) { cue_chunkRead(fp); } else if (strncmp(ID, "LIST", 4) == 0) { LISTchunkRead(fp, cursor + size); } else if (strncmp(ID, "DISP", 4) == 0) { DISPchunkRead(fp); } else if (strncmp(ID, "plst", 4) == 0) { plstchunkRead(fp); } else if (strncmp(ID, "data", 4) == 0) { ; } fseek(fp, cursor + size, SEEK_SET); } } /**************/ /* メイン関数 */ /**************/ int main(int argc, char *argv[]) { FILE *fp; if (argc != 2) { fprintf(stderr, "wav ヘッダ情報出力プログラム...\n" "Usage: %s \n" "チャンクの種類\n" " : フォーマット定義(必須)\n" " : 波形データ(必須)\n" " : 全サンプル数\n" " : 各種情報\n" " : 表\示情報\n" , argv[0]); exit(EXIT_FAILURE); } if ((fp = fopen(argv[1], "rb")) == NULL) { openError(argv[1]); } printf("\n%s :\n", argv[1]); wavRead(fp); fclose(fp); return EXIT_SUCCESS; }