xue@11: xue@9: /* xue@9: Sample program: analysis of harmonic sinusoid in low-noise monophonic context. xue@9: xue@9: Syntax: xue@9: (executable path) filename ... xue@9: xue@9: filename: path input wave form audio file, 16-bit PCM xue@9: setting: optional algorithmic parameters; search "stricmp" in the source code for a complete list xue@9: value: non-default values given to the algorithmic parameters xue@9: xue@9: Output: xue@9: a *.evt file containing RIFF chunks, each starting with id "EVT\0" and hosting a harmonic sinusoid. xue@9: xue@9: The "EVT\0" chunk body contains a header ("HDR\0") chunk followed by atom ("ATM\0") chunks. xue@9: xue@9: The "HDR\0" chunk body contains 4 __int32 values: channel index, number of partials, number of xue@9: measurement points (frames), and a tag. xue@9: xue@9: The "ATM\0" chunk body contains an atom structure (see hs.h). xue@9: xue@9: */ xue@9: xue@9: #include xue@9: #include "arrayalloc.h" xue@9: #include "hs.h" xue@9: #include "matrix.h" xue@9: #include "quickspec.h" xue@9: #include "procedures.h" xue@9: #include "vibrato.h" xue@9: #include xue@9: #include xue@9: #include xue@9: xue@9: //structure hosting wave header data xue@9: struct wavehdr xue@9: { xue@9: __int16 fmttag; xue@9: __int16 channels; xue@9: __int32 samplespersec; xue@9: __int32 bytespersec; xue@9: __int16 blockalign; xue@9: __int16 bitspersample; xue@9: }; xue@9: xue@9: //tells if a wave header contains consistent data xue@9: bool isvalidwavehdr(wavehdr* hdr) xue@9: { xue@9: if (hdr->fmttag!=1) return false; xue@9: if (hdr->bitspersample!=8 && hdr->bitspersample!=16) return false; xue@9: if (hdr->channels*hdr->bitspersample!=hdr->blockalign*8) return false; xue@9: if (hdr->samplespersec*hdr->blockalign!=hdr->bytespersec) return false; xue@9: return true; xue@9: } xue@9: xue@9: //structure hosting a waveform audio xue@9: struct waveaudio xue@9: { xue@9: union xue@9: { xue@9: wavehdr hdr; xue@9: struct xue@9: { xue@9: __int16 fmttag; xue@9: __int16 channels; xue@9: __int32 samplespersec; xue@9: __int32 bytespersec; xue@9: __int16 blockalign; xue@9: __int16 bitspersample; xue@9: }; xue@9: }; xue@9: int length; xue@9: union xue@9: { xue@9: unsigned char* data; xue@9: unsigned char* data8; xue@9: __int16* data16; xue@9: }; xue@9: waveaudio(){memset(this, 0, sizeof(waveaudio));} xue@9: ~waveaudio(){delete[] data;} xue@9: }; xue@9: xue@9: void freewaveaudio(waveaudio* wa) xue@9: { xue@9: delete[] wa->data; xue@9: memset(wa, 0, sizeof(waveaudio)); xue@9: } xue@9: xue@9: //error messages for reading waveform audio file xue@9: enum err_wavefile xue@9: { xue@9: err_success, xue@9: err_RIFF_hdr, xue@9: err_wave_hdr, xue@9: err_data_hdr, xue@9: err_data_chunk, xue@9: err_io xue@9: }; xue@9: xue@9: //reads wave header from file stream xue@9: int loadwavehdr(wavehdr* hdr, FILE* fp) xue@9: { xue@9: int rc, hdrlen; xue@9: char s[5]; xue@9: xue@9: rc=fread(s, 1, 4, fp); s[4]=0; xue@9: if (rc<4) return err_wave_hdr; xue@9: if (strcmp(s, "WAVE")) return err_wave_hdr; xue@9: xue@9: rc=fread(s, 1, 4, fp); s[4]=0; xue@9: if (rc<4) return err_wave_hdr; xue@9: if (strcmp(s, "fmt ")) return err_wave_hdr; xue@9: xue@9: rc=fread(&hdrlen, 1, 4, fp); xue@9: if (rc<4) return err_wave_hdr; xue@9: if (hdrlen<16) return err_wave_hdr; xue@9: xue@9: rc=fread(hdr, 1, sizeof(wavehdr), fp); xue@9: if (rc16) xue@9: { xue@9: rc=fseek(fp, hdrlen-16, SEEK_CUR); xue@9: if (rc!=0) return err_wave_hdr; xue@9: } xue@9: xue@9: return err_success; xue@9: } xue@9: xue@9: //reads waveform audio, including header, from a file stream xue@9: int loadwaveaudio(waveaudio* wa, FILE* fp) xue@9: { xue@9: int rc, mainlen; xue@9: char s[5]; xue@9: wavehdr hdr; xue@9: xue@9: rc=fread(s, 1, 4, fp); s[4]=0; xue@9: if (rc<4) return err_RIFF_hdr; xue@9: if (strcmp(s, "RIFF")) return err_RIFF_hdr; xue@9: xue@9: rc=fread(&mainlen, 1, 4, fp); xue@9: if (rc<4) return err_RIFF_hdr; xue@9: xue@9: rc=loadwavehdr(&hdr, fp); xue@9: if (rc!=err_success) return rc; xue@9: xue@9: rc=fread(s, 1, 4, fp); s[4]=0; xue@9: if (rc<4) return err_data_hdr; xue@9: if (strcmp(s, "data")) return err_data_hdr; xue@9: xue@9: rc=fread(&mainlen, 1, 4, fp); xue@9: if (rc<4) return err_data_hdr; xue@9: xue@9: if (mainlen<=0) return err_data_hdr; xue@9: xue@9: unsigned char* data=new unsigned char[mainlen]; xue@9: rc=fread(data, 1, mainlen, fp); xue@9: if (rchdr=hdr; xue@9: wa->length=rc/hdr.blockalign; xue@9: delete[] wa->data; xue@9: wa->data=data; xue@9: xue@9: return err_success; xue@9: } xue@9: xue@9: //reads waveform audio, including header, from a file xue@9: int loadwavefile(waveaudio* wa, char* filename) xue@9: { xue@9: FILE* fp; xue@9: if ((fp=fopen(filename, "rb"))==NULL) return err_io; xue@9: int result=loadwaveaudio(wa, fp); xue@9: fclose(fp); xue@9: return result; xue@9: } xue@9: xue@9: //returns new file path with the specific extension replacing the original one xue@9: char* ChangeFileExt(char* FileName, char* Ext) xue@9: { xue@9: char* oldext=strrchr(FileName, '.'); xue@9: int namelen=strlen(FileName)-strlen(oldext); xue@9: char* dest=new char[namelen+strlen(Ext)+1]; xue@9: memcpy(dest, FileName, namelen); dest[namelen]=0; xue@9: strcat(dest, Ext); xue@9: return dest; xue@9: } xue@9: xue@9: //ACPower for __int16 data input xue@9: double ACPower(__int16* data, int Count) xue@9: { xue@9: if (Count<=0) return 0; xue@9: double power=0, avg=0, tmp; xue@9: for (int i=0; i=autocor[m]) {cont=1; break;} xue@9: if (cont==0) xue@9: { xue@9: if (prd==0 || autocor[m]>autocor[prd]*1.05) prd=m; xue@9: } xue@9: m++; xue@9: } xue@9: } xue@9: xue@9: double pitchbin=0; xue@9: if (prd>=minT && prd<=maxT) xue@9: { xue@9: double mshift; hsr=QIE(&autocor[prd], mshift); pitchbin=wid/(prd+mshift); xue@9: } xue@9: else{hsr=0;} xue@9: delete[] autocor; xue@9: return pitchbin; xue@9: } xue@9: xue@9: //main function xue@9: int main(int argc, char* argv[]) xue@9: { xue@9: //read audio file xue@9: if (argc<2){printf("Please specify input wave file."); getch(); return 0;} xue@9: printf("Loading wave file %s... ", argv[1]); xue@9: waveaudio* wa=new waveaudio; xue@9: int waverr=loadwavefile(wa, argv[1]); printf("[%d]\n", waverr); xue@9: if (waverr!=err_success){printf("Aborted: error loading wave file."); getch(); return 0;} xue@9: if (wa->bitspersample!=16){printf("Aborted: this program accepts 16-bit pcm only."); getch(); return 0;} xue@9: xue@9: int length=wa->length, sps=wa->samplespersec; xue@9: __int16* data16=wa->data16; xue@9: if (wa->channels>1) xue@9: { xue@9: printf("Extracting channel 0... "); xue@9: for (int i=1; ichannels]; xue@9: printf("[0]\n"); xue@9: } xue@9: wa->data=0; xue@9: delete wa; xue@9: xue@9: //default settings xue@9: int maxhscount=100; xue@9: float wid_s=0.02, offstwidratio=0.5; xue@9: float dur_s=0.5; xue@9: float intv_s=0.05; //duration, in seconds, to scan for peaks xue@9: float minf0=55, maxf0=3520; xue@9: WindowType wintype=wtHann; xue@9: xue@9: NMSettings settings; memset(&settings, 0, sizeof(NMSettings)); xue@9: settings.hB=3; //spectral truncation half width xue@9: settings.maxp=50; //maximal number of partials xue@9: settings.maxB=0.001; //stiffness coefficient upper bound xue@9: settings.epf=1e-4; //frequency estimation error tolerance for LSE estimation xue@9: settings.epf0=1; //input frequency error bound for harmonic grouping xue@9: settings.delm=1.1; //frequency error bound for harmonic grouping xue@9: settings.delp=1.1; //pitch jump upper bound xue@9: xue@9: double mina=0.5; xue@9: xue@9: //user settings through commandline arguments xue@9: for (int i=2; i