100[ms]ごとにWAVEファイルを分割したファイルが研究で必要になって,WAVファイルをms単位で分割できるソフトを探してみたんだけど,なかなか見つからない.(単に探し方が下手なだけ)
sec単位とかならあるんだけどなー.
ということで,研究ほっぽり投げてがーっと書いた.
久々にWAVEヘッダーいじった.完全に忘れてた.これはあかん.
必要な部分しか書いてないので,8/16bit, RIFF/Linear-PCMのみ,factチャンク未対応.
エラー処理も未対策,テストもそんなにしていないのであくまでなんかの参考までに(情報系の大学生とか.ならんか)
利用例
./msplitter -i input.wav -o output/out -t 100
オプション
ーi: 入力WAVEファイル名
ーo: 出力WAVEファイル名(拡張子含めない).連番で出力される
ーt: 分割するインターバル [ms]
// msplitter.c #include <stdio.h> #include <stdlib.h> #include <string.h> // めんどくさいので一箇所に集める typedef struct { char inputfile[64], outputfile[64]; unsigned long bytes, samplingrate, wavesize, dataspeed, sample, offset; unsigned short fmtid, channels, blocksize, bitsample; } Wav; // prototype call int main(int argc, char *argv[]); int cmdline_parser(int argc, char *argv[], Wav *wh); void kill(char *msg, char *type); void fread2(void *buf, size_t size, size_t n, FILE *fp); void read_waveheader(Wav *wh, FILE *fp); void write_waveheader(Wav *wh, FILE *fp); int main(int argc, char *argv[]) { Wav wh; // get splittime and filename from commandline int splittime = cmdline_parser(argc, argv, &wh); int i, cnt=0, offset; FILE *fp; unsigned char *wavedata; // 8bit signed short *wavedata16; // 16bit char outputfile_number[64]; setvbuf(stdout,0,_IONBF,0); // for console2, mintty printf("msplitter (c) 2012 hurikake\n"); printf("*-------------------------------------------------*\n"); printf("input: %s, output: %s*****.wav\n", wh.inputfile, wh.outputfile); printf("splittime: %d [ms]\n",splittime); if((fp = fopen(wh.inputfile, "rb")) == NULL) kill("open error",""); // read waveheader read_waveheader(&wh, fp); // read wavedata if(wh.bitsample == 8) { if( (wavedata = (char *) malloc(wh.wavesize * sizeof(char))) == NULL) kill("malloc error","char"); } else { if( (wavedata16 = (short *) malloc(wh.wavesize * sizeof(short))) == NULL) kill("malloc error","short"); } printf("channel: %d\n",wh.channels); printf("sampling rate: %d [Hz]\n",wh.samplingrate); printf("bit: %d [bit]\n",wh.bitsample); printf("wavesize: %d [byte] \n",wh.wavesize); // 1 (or 2) byte(s) read for wavesize (times) if(wh.bitsample == 8) fread2(wavedata, sizeof(char), wh.wavesize, fp); else fread2(wavedata16, sizeof(short), wh.wavesize / sizeof(short), fp); fclose(fp); // 1 file sample: (splittime / 1000) * samplingrate [sample] wh.sample = (int) ( ((double)splittime / 1000.0) * wh.samplingrate); printf("frame ( * channel) : %d [sample]\n", wh.sample); // file save // 1 file size (without 44byte: wave header) wh.offset = wh.sample * wh.channels * (wh.bitsample / 8); printf("offset : %d [byte]\n", wh.offset); printf("*-------------------------------------------------*\n"); for(i=0; i<wh.wavesize; i+=wh.offset) { // last part of file if( (wh.wavesize-i) < wh.offset) wh.offset = wh.wavesize - i; // make file name sprintf(outputfile_number, "%s%05d.wav", wh.outputfile, cnt); // file make if( (fp = fopen(outputfile_number, "wb")) == NULL) kill("filewrite error","fopen"); write_waveheader(&wh, fp); // 8bit or 16bit if(wh.bitsample == 8) fwrite(&wavedata[i], wh.offset, 1, fp); else fwrite(&wavedata16[i/(wh.bitsample/8)], wh.offset, 1, fp); fclose(fp); if(cnt%10 == 0) printf("\n"); cnt++; printf("(^^) "); } if(wh.bitsample == 8) free(wavedata); else free(wavedata16); printf("\n\nsuccess! %d file(s) created\n", cnt); return 0; } int cmdline_parser(int argc, char *argv[], Wav *wh) { // -i input filename // -o output filename (without extension) // -t split time (ms) // return: splittime int i, splittime; for(i=1;i<argc;i++) { if(argv[i][0] != '-') break; if(++i>=argc) exit(0); switch(argv[i-1][1]) { case 'i': strcpy(wh->inputfile, argv[i]); break; case 'o': strcpy(wh->outputfile, argv[i]); break; case 't': splittime = atoi(argv[i]); break; default: fprintf(stderr,"unknown option: -%c\n", argv[i-1][1]); exit(0); break; } } return splittime; } // error void kill(char *msg, char *type) { fprintf(stderr, "%s: %s\n", msg, type); exit(EXIT_FAILURE); return; } // fread (error check version) void fread2(void *buf, size_t size, size_t n, FILE *fp) { int a; if((a=fread(buf, size, n, fp)) < n) { kill("fread error", ""); } return; } void read_waveheader(Wav *wh, FILE *fp) { int i; unsigned char temp[4]; char chkchunk[4][4] = { {'R','I','F','F'}, {'d','u','m','m'}, // dummy {'W','A','V','E'}, {'f','m','t',' '}, }; // ヘッダーの16byte分読み込み&存在チェック for(i=0;i<4;i++) { fread2(temp, 4, 1, fp); // i = 1: filesize if( (i != 1) && (memcmp(temp, chkchunk[i], 4) != 0) ) kill("does not exist", chkchunk[i]); } // read bytes fread2(&wh->bytes, 4, 1, fp); // read fmtID fread2(&wh->fmtid, 2, 1, fp); // read channels fread2(&wh->channels, 2, 1, fp); // read sampling rate fread2(&wh->samplingrate, 4, 1, fp); // read dataspeed fread2(&wh->dataspeed, 4, 1, fp); // read blocksize fread2(&wh->blocksize, 2, 1, fp); // read bitsample fread2(&wh->bitsample, 2, 1, fp); // read 'data' fread2(temp, 4, 1, fp); if((memcmp(temp, "data", 4) != 0)) kill("does not exist", "data"); // read wavesize fread2(&wh->wavesize, 4, 1, fp); return; } void write_waveheader(Wav *wh, FILE *fp) { unsigned long byte = 44 + wh->offset - 8; fwrite("RIFF", 4, 1, fp); fwrite(&byte, 4, 1, fp); fwrite("WAVEfmt ", 8, 1, fp); fwrite(&wh->bytes, 4, 1, fp); fwrite(&wh->fmtid, 2, 1, fp); fwrite(&wh->channels, 2, 1, fp); fwrite(&wh->samplingrate, 4, 1, fp); fwrite(&wh->dataspeed, 4, 1, fp); fwrite(&wh->blocksize, 2, 1, fp); fwrite(&wh->bitsample, 2, 1, fp); fwrite("data", 4, 1, fp); fwrite(&wh->offset, 4, 1, fp); return; }
改めて見るとめっちゃ読みにくい.
wh.sample が1分割分のサンプル数(チャンネル数やビット数は考慮していない),wh.offset が1分割分のバイト数(考慮後).すなわちwh.offset [byte]の波形サイズで,wh.offset + 44 [byte]のファイルが生成される.44byte分はWAVヘッダーの分.
ちなみにwh.offset = wh.sample * ビット数/8 * チャンネル数 である.8bit,monoのファイルなら1サンプル=1バイトだからそのまま.16bit,stereoなら1サンプル=4バイト.
汚いけどこれで一応8bit,stereoのファイルを100msごとに分割できた.
あと実行してみてるとわかるけど遊び心で進捗に顔文字入れたらめっちゃうざい感じになったので各自直してください.
実行例
$ ./msplitter -i apart.wav -o apart -t 20000
msplitter (c) 2012 hurikake
*-----------------------------------------*
input: apart.wav, output: apart*****.wav
splittime: 20000 [ms]
channel: 2
sampling rate: 44100 [Hz]
bit: 16 [bit]
wavesize: 68125680 [byte]
sample ( * channel) : 882000 [sample]
offset : 3528000 [byte]
*-----------------------------------------*(^^) (^^) (^^) (^^) (^^) (^^) (^^) (^^) (^^) (^^)
(^^) (^^) (^^) (^^) (^^) (^^) (^^) (^^) (^^) (^^)success! 20 file(s) created