/********************************************************************/ /* ステレオ wav データ -> 左チャンネル, 右チャンネル 分割プログラム */ /* */ /* データ 16bit(-2^15 〜 2^15 - 1, -32768 〜 +32767, 無音 = 0) */ /* データ 8bit( 0 〜 2^8 - 1 , 0 〜 +225 , 無音 = 128) */ /* */ /* kondo@kk.iij4u.or.jp */ /* 2000.12.15 */ /********************************************************************/ #include #include #include #ifndef _MAX_PATH #define _MAX_PATH (255) #endif static char cmdname[] = "separate"; void usage(void) { fprintf(stderr, "ステレオ wav フォーマットデータ---> " "チャンネル分割プログラム...\n" "Usage: %s [Lch_file] [Rch_file]\n" "\t (Lch_file, Rch_file の指定が無い場合\n" "\t wav_file_L.wav(左), wav_file_R.wav(右) " "のファイルが作成されます)\n" "\n" "例 : %s filename.wav\n" " (filename.wav のデータを分割して\n" " filename_L.wav, filename_R.wav に書き出します)\n" " %s filename.wav output.wav\n" " (filename.wav のデータを分割して\n" " output_L.wav, output_R.wav に書き出します)\n" " %s filename.wav output.Lch.wav, output.Rch.wav\n" " (filename.wav のデータを分割して\n" " output.Lch.wav, output.Rch.wav に書き出します)\n" "\n", cmdname, cmdname, cmdname, cmdname); exit(EXIT_FAILURE); } 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); } void writeError(FILE *fp) { fprintf(stderr, "write error : %ld\n", ftell(fp)); fclose(fp); exit(EXIT_FAILURE); } /*----------------*/ /* ファイル名取得 */ /*----------------*/ int getBasename(char *dest, char *src) { int i, start, end, ret; i = -1; start = 0; end = 0; // ファイル名のはじめと終わりを検出 while (src[++i]) { if (src[i] == '\\' || src[i] == ':') { start = i + 1; end = 0; } if (src[i] == '.') { end = i; } } if (end == 0) { end = i; } // ファイル名が有る場合 if (start < end) { for (i = 0; i < end; i++) { dest[i] = src[i]; } dest[i] = '\0'; ret = 1; } else { dest[0] = '\0'; ret = 0; } return ret; } /*-----------------------------*/ /* 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]); } /*------------------------*/ /* fmt チャンクのチェック */ /*------------------------*/ void fmt_chunkRead(char *wavefile, FILE *fp, unsigned long *sr, unsigned short *bits) { short tag, channels; // 2Byte データ形式 PCM ならば 01 00 tag = get_ushort(fp); fprintf(stderr, " format tag = %u (1 = PCM)\n", tag); // 2Byte チャンネル数 モノラルならば 01 00 ステレオならば 02 00 channels = get_ushort(fp); fprintf(stderr, " channels = %u\n", channels); // 4Byte サンプリング周波数(Hz) *sr = get_ulong(fp); fprintf(stderr, " samples/sec = %lu\n", *sr); // 4Byte 1秒あたりのバイト数 fprintf(stderr, " avg. bytes/sec = %lu\n", get_ulong(fp)); // 2Byte バイト数×チャンネル数 fprintf(stderr, " block align = %u\n", get_ushort(fp)); // 2Byte 1サンプルあたりのバイト数 *bits = get_ushort(fp); fprintf(stderr, " bits/sample = %u\n", *bits); if (tag != 1) { fprintf(stderr, "\nThis program supported \"PCM format\" wav file\n"); fprintf(stderr, "%s : format tag = %d\n", wavefile, tag); exit(EXIT_FAILURE); } if (channels != 2) { fprintf(stderr, "\nThis is stereo wav file separate program\n"); fprintf(stderr, "%s : channels = %d\n", wavefile, channels); exit(EXIT_FAILURE); } if (*bits != 8 && *bits != 16) { fprintf(stderr, "\nThis program supported 16bit or 8bit wav file\n"); fprintf(stderr, "%s : bits/sample = %d\n", wavefile, *bits); exit(EXIT_FAILURE); } } /*----------------------*/ /* ファイル内容読み出し */ /*----------------------*/ void wavRead(char *wavefile, unsigned long *sr, unsigned short *bits, long *data_from, long *data_size) { long cursor, len; unsigned char s[5]; FILE *fp; if ((fp = fopen(wavefile, "rb")) == NULL) { openError(wavefile); } fprintf(stderr, "\n%s :\n", wavefile); // RIFF ヘッダ情報 // 4Byte 'R''I''F''F' if (fread(s, 4, 1, fp) != 1) { readError(fp); } if (memcmp(s, "RIFF", 4) != 0) { fprintf(stderr, "Not a 'RIFF' format\n"); fclose(fp); exit(EXIT_FAILURE); } // 4Byte これ以降のバイト数 = (ファイルサイズ - 8)(Byte) len = get_ulong(fp); fprintf(stderr, "[RIFF] (%lu bytes)\n", len); // WAVE ヘッダ情報 // 4Byte 'W''A''V''E' if (fread(s, 4, 1, fp) != 1) { readError(fp); } if (memcmp(s, "WAVE", 4) != 0) { fprintf(stderr, "Not a 'WAVE' format\n"); fclose(fp); exit(EXIT_FAILURE); } fprintf(stderr, "[WAVE]\n"); // チャンク情報 while (fread(s, 4, 1, fp) == 1) { if (memcmp(s, "fmt ", 4) == 0) { len = get_ulong(fp); fprintf(stderr, " (%ld bytes)\n", len); cursor = ftell(fp); fmt_chunkRead(wavefile, fp, sr, bits); fseek(fp, cursor + len, SEEK_SET); } else if (memcmp(s, "data", 4) == 0) { *data_size = get_ulong(fp); fprintf(stderr, " (%ld bytes)\n", *data_size); *data_from = ftell(fp); fseek(fp, *data_size + *data_from, SEEK_SET); } else { len = get_ulong(fp); s[4] = '\0'; fprintf(stderr, " <%s> (%ld bytes)\n", s, len); cursor = ftell(fp); fseek(fp, cursor + len, SEEK_SET); } } fclose(fp); } /*--------------------*/ /* 1Byte(8bit) コピー */ /*--------------------*/ void bytecopy(FILE *fp1, FILE *fp2) { char data; if (fread(&data, sizeof(char), 1, fp1) != 1) { readError(fp1); } if (fwrite(&data, sizeof(char), 1, fp2) != 1) { writeError(fp2); } } /*---------------------*/ /* wav ヘッダ 書き込み */ /*---------------------*/ long wavHeaderWrite(FILE *fp, long data_size, unsigned short ch, unsigned long sr, unsigned short bits) { unsigned long var_long; unsigned short var_short, bytes; char s[4]; // RIFF ヘッダ s[0] = 'R'; s[1] = 'I'; s[2] = 'F'; s[3] = 'F'; fwrite(s, 1, 4, fp); // ファイルサイズ var_long = data_size + 36; fwrite(&var_long, sizeof(long), 1, fp); // WAVE ヘッダ s[0] = 'W'; s[1] = 'A'; s[2] = 'V'; s[3] = 'E'; fwrite(s, 1, 4, fp); // chunkID (fmt チャンク) s[0] = 'f'; s[1] = 'm'; s[2] = 't'; s[3] = ' '; fwrite(s, 1, 4, fp); // chunkSize (fmt チャンクのバイト数 無圧縮 wav は 16) var_long = 16; fwrite(&var_long, sizeof(long), 1, fp); // wFromatTag (無圧縮 PCM = 1) var_short = 1; fwrite(&var_short, sizeof(short), 1, fp); // dwChannels (モノラル = 1, ステレオ = 2) fwrite(&ch, 2, 1, fp); // dwSamplesPerSec (サンプリングレート(Hz)) fwrite(&sr, sizeof(long), 1, fp); // wdAvgBytesPerSec (Byte/秒) bytes = bits / 8; var_long = bytes * ch * sr; fwrite(&var_long, sizeof(long), 1, fp); // wBlockAlign (Byte/サンプル*チャンネル) var_short = bytes * ch; fwrite(&var_short, sizeof(short), 1, fp); // wBitsPerSample (bit/サンプル) var_short = bits; fwrite(&var_short, sizeof(short), 1, fp); // chunkID (data チャンク) s[0] = 'd'; s[1] = 'a'; s[2] = 't'; s[3] = 'a'; fwrite(s, 1, 4, fp); // chunkSize (データ長 Byte) fwrite(&data_size, 4, 1, fp); return ftell(fp); } /*--------------------------------------*/ /* wav データ書き込み */ /* 8 bit データ 0〜255 (無音 128) */ /* 16 bit データ -32768〜32767 (無音 0) */ /*--------------------------------------*/ void wavDataWrite(FILE *orig, long from, long length, short bytes, FILE *wave1, FILE *wave2) { long i; short j; // 元ファイルのデータ開始部分 fseek(orig, from, SEEK_SET); for (i = 0; i < length / bytes; i++) { for (j = 0; j < bytes; j++) { bytecopy(orig, wave1); } for (j = 0; j < bytes; j++) { bytecopy(orig, wave2); } } } /*----------------------*/ /* ファイル内容書き出し */ /*----------------------*/ void wavWrite(char *orig_file, char *Lch_file, char *Rch_file, unsigned long sr, unsigned short bits, long from, long stereo_size) { unsigned short bytes; unsigned long mono_size; FILE *fp1, *fp2, *fp3; if ((fp2 = fopen(Lch_file, "wb")) == NULL) { openError(Lch_file); } if ((fp3 = fopen(Rch_file, "wb")) == NULL) { openError(Rch_file); } bytes = bits / 8; mono_size = stereo_size / 2; // wav ヘッダ書き込み if (wavHeaderWrite(fp2, mono_size, 1, sr, bits) != 44) { fprintf(stderr, "%s : wav header write error\n", Lch_file); exit(EXIT_FAILURE); } if (wavHeaderWrite(fp3, mono_size, 1, sr, bits) != 44) { fprintf(stderr, "%s : wav header write error\n", Rch_file); exit(EXIT_FAILURE); } if ((fp1 = fopen(orig_file, "rb")) == NULL) { openError(orig_file); } // wav データ書き込み wavDataWrite(fp1, from, mono_size, bytes, fp2, fp3); fprintf(stderr, "\n%s -> %s, %s\n", orig_file, Lch_file, Rch_file); fclose(fp1); fclose(fp2); fclose(fp3); } /**************/ /* メイン関数 */ /**************/ int main(int argc, char *argv[]) { unsigned long sampling; unsigned short bits; long from, size; char orig_file[_MAX_PATH], Lch_file[_MAX_PATH], Rch_file[_MAX_PATH], basename[_MAX_PATH]; if (argc < 2) { usage(); } else if (argc == 2) { strcpy(orig_file, argv[1]); getBasename(basename, argv[1]); sprintf(Lch_file, "%s_L.wav", basename); sprintf(Rch_file, "%s_R.wav", basename); } else if (argc == 3) { strcpy(orig_file, argv[1]); getBasename(basename, argv[2]); sprintf(Lch_file, "%s_L.wav", basename); sprintf(Rch_file, "%s_R.wav", basename); } else if (argc > 3) { strcpy(orig_file, argv[1]); strcpy(Lch_file, argv[2]); strcpy(Rch_file, argv[3]); } wavRead(orig_file, &sampling, &bits, &from, &size); wavWrite(orig_file, Lch_file, Rch_file, sampling, bits, from, size); return 0; }