#include #include #include #include #include #include #include #include /* WAVE ファイルの情報を格納する構造体 */ typedef struct { FILE* fp; /* ファイル構造体 */ short is_pcm; /* PCM フォーマットの場合は 1、それ以外は 0 */ short channel; /* モノラルの場合は 1、ステレオの場合は 2 */ int rate; /* サンプリング周波数 */ short bits; /* 量子化ビット数 */ long offset; /* ファイル先頭から PCM データまでのオフセット */ int len; /* PCM データ部の長さ */ } WAVE; /* 関数プロトタイプ */ static int vocancel_read_file( char* fname, WAVE* wave ); static int vocancel_mix_and_write( char* fname, WAVE* inwave ); static void vocancel_progress( int* processed, int current, WAVE* wave ); int main( int argc, char** argv ) { WAVE wave; if ( argc != 3 ) { fprintf( stderr, "usage : vocancel filetoread filetowrite\n" ); return 1; } /* WAVE ファイルヘッダの読み込み */ if ( vocancel_read_file( argv[1], &wave ) != 0 ) { fprintf( stderr, "Failed to read specified WAVE file" ": %s\n", argv[1] ); return 1; } /* ステレオ => モノラル変換 */ printf( "Now canceling center sound ...\n" ); if ( vocancel_mix_and_write( argv[2], &wave ) != 0 ) { fprintf( stderr, "Failed to write monoral WAVE file" ": %s\n", argv[2] ); fclose( wave.fp ); return 1; } fclose( wave.fp ); printf( "\ndone.\n" ); return 0; } /* * WAVE ファイル情報を読み込む */ static int vocancel_read_file( char* fname, WAVE* wave ) { char buf[32]; int len; if ( ( wave->fp = fopen( fname, "r" ) ) == NULL ) { fprintf( stderr, "Failed to open %s\n", fname ); return -1; } /* * 先頭 4 バイトが "RIFF" であることを確認 * 更に 4 バイトスキップしておく */ fread( buf, 8, 1, wave->fp ); if ( strncmp( buf, "RIFF", 4 ) != 0 ) { fprintf( stderr, "Specified file is not RIFF file.\n" ); fclose( wave->fp ); return -1; } /* 次の 4 バイトが "WAVE" であることを確認 */ fread( buf, 4, 1, wave->fp ); if ( strncmp( buf, "WAVE", 4 ) != 0 ) { fprintf( stderr, "Specified file is not WAVE file.\n" ); fclose( wave->fp ); return -1; } /* fmt チャンクを探す */ while ( 1 ) { fread( buf, 8, 1, wave->fp ); len = *( int* )( &buf[4] ); if ( strncmp( buf, "fmt ", 4 ) != 0 ) { if ( fseek( wave->fp, len, SEEK_CUR ) == -1 ) { fprintf( stderr, "Failed to find fmt chunk.\n" ); fclose( wave->fp ); return -1; } } else { break; } } /* WAVE フォーマットを読み込む */ fread( buf, len, 1, wave->fp ); wave->is_pcm = *( ( short* )( &buf[0] ) ); wave->channel = *( ( short* )( &buf[2] ) ); wave->rate = *( ( int* )( &buf[4] ) ); wave->bits = *( ( short* )( &buf[14] ) ); if ( wave->is_pcm != 1 ) { wave->is_pcm = 0; } /* data チャンクを探す */ while ( 1 ) { fread( buf, 8, 1, wave->fp ); len = *( int* )( &buf[4] ); if ( strncmp( buf, "data", 4 ) != 0 ) { if ( fseek( wave->fp, len, SEEK_CUR ) == -1 ) { fprintf( stderr, "Failed to find data chunk.\n" ); fclose( wave->fp ); return -1; } } else { break; } } wave->len = len; if ( ( wave->offset = ftell( wave->fp ) ) == -1 ) { fprintf( stderr, "Failed to find offset of PCM data.\n" ); fclose( wave->fp ); return -1; } return 0; } #define BUFSIZE 128000 /* * 指定ファイルに、左右のチャンネルを合成したモノラル WAVE データを出力する。 */ static int vocancel_mix_and_write( char* fname, WAVE* in ) { /* * wave_len は WAVE ファイルの先頭から 4 バイト目のデータ * head_len は WAVE ファイルの先頭から 16 バイト目のデータ * data_len は PCM データ部のデータ長 */ int wave_len; int head_len; int data_len; int byte_sec; int byte_dat; int tmpval; int processed = 0; int len = 0; int i; char ibuf[ BUFSIZE ]; char obuf[ BUFSIZE ]; short channel = 1; short out; short in_l; short in_r; FILE* fp; if ( ( fp = fopen( fname, "w" ) ) == NULL ) { fprintf( stderr, "Failed to open %s\n", fname ); return -1; } /* ステレオでない場合は、左右のチャンネルの合成処理が出来ないため終了 */ if ( in->channel != 2 ) { fprintf( stderr, "Specified WAVE file is not stereo.\n" ); fclose( fp ); return -1; } /* 16 ビットのデータかどうか確認 */ if ( in->bits != 16 ) { fprintf( stderr, "Specified WAVE file is not 16 bits data.\n" ); fclose( fp ); return -1; } data_len = in->len / 2; head_len = 18; wave_len = ( data_len + 8 ) + head_len + 12; byte_sec = in->rate * in->bits / 8; byte_dat = in->bits / 8; /* PCM データの直前までのデータを書き込む */ fwrite( "RIFF", strlen( "RIFF" ), 1, fp ); fwrite( &wave_len, 4, 1, fp ); fwrite( "WAVE", strlen( "WAVE" ), 1, fp ); fwrite( "fmt ", strlen( "fmt " ), 1, fp ); fwrite( &head_len, 4, 1, fp ); fwrite( &in->is_pcm, 2, 1, fp ); fwrite( &channel, 2, 1, fp ); fwrite( &in->rate, 4, 1, fp ); fwrite( &byte_sec, 4, 1, fp ); fwrite( &byte_dat, 2, 1, fp ); fwrite( &in->bits, 2, 1, fp ); tmpval = ( short )head_len; fwrite( &tmpval, 2, 1, fp ); fwrite( "data", strlen( "data" ), 1, fp ); fwrite( &data_len, 4, 1, fp ); /* PCM データを合成しながら書き込む */ fflush( stdout ); vocancel_progress( &processed, 0, in ); while ( 1 ) { len = fread( ibuf, 1, BUFSIZE, in->fp ); if ( len < BUFSIZE && ferror( in->fp ) ) { fprintf( stderr, "Error occured.\n" ); fclose( fp ); return -1; } for ( i = 0; i < len; i += 4 ) { memcpy( &in_l, &ibuf[i], 2 ); memcpy( &in_r, &ibuf[i + 2], 2 ); tmpval = in_l - in_r; if ( tmpval > 0 && tmpval > SHRT_MAX ) { out = SHRT_MAX; } else if ( tmpval < 0 && tmpval < SHRT_MIN ) { out = SHRT_MIN; } else { out = tmpval; } memcpy( &obuf[ i / 2 ], &out, 2 ); } fwrite( &obuf, len / 2, 1, fp ); vocancel_progress( &processed, len, in ); if ( len < BUFSIZE ) { break; } } fclose( fp ); return 0; } /* * 進捗率の表示 */ static void vocancel_progress( int* processed, int current, WAVE* wave ) { int progress; *processed += current; progress = (int)( ( ( double )*processed / ( double )wave->len ) * 100 ); printf( "\r%3d%% processed.", progress ); fflush( stdout ); } /* End of vocancel.c */