📄 mp_notes.c
字号:
/*..........................................................................*//* *//* L a s t W a v e P a c k a g e 'mp' 2.1 *//* *//* Copyright (C) 2000 Remi Gribonval, Emmanuel Bacry and Javier Abadia.*//* email : remi.gribonval@inria.fr *//* email : lastwave@cmap.polytechnique.fr *//* *//*..........................................................................*//* *//* This program is a free software, you can redistribute it and/or *//* modify it under the terms of the GNU General Public License as *//* published by the Free Software Foundation; either version 2 of the *//* License, or (at your option) any later version *//* *//* This program is distributed in the hope that it will be useful, *//* but WITHOUT ANY WARRANTY; without even the implied warranty of *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *//* GNU General Public License for more details. *//* *//* You should have received a copy of the GNU General Public License *//* along with this program (in a file named COPYRIGHT); *//* if not, write to the Free Software Foundation, Inc., *//* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* *//*..........................................................................*/ #include "lastwave.h"#include "mp_book.h"/* javi: dealing with notes */typedef struct note{ LWFLOAT onset; LWFLOAT end; LWFLOAT pitch;} *NOTE;extern void Notes(BOOK book,int nMin,int nMax,NOTE *note);extern int SearchNote(BOOK book,ATOM mainAtom,int numAtom,int *flagNotes,LWFLOAT *pp, LWFLOAT * bb, LWFLOAT * ee);extern void ComputeEnergyProfile(BOOK book,ATOM mainAtom,SIGNAL energyProfile);extern int MarkAtoms(BOOK book,ATOM mainAtom,int numAtom,int *flagNotes,LWFLOAT * begin,LWFLOAT end);extern void NotesSynthesis(NOTE *note,SIGNAL synthesis,BOOK book,int attack);extern void AddAtomEnergyEnvelope(SIGNAL energyEnvelope,ATOM atom,ATOM mainAtom);extern void GetBestPartial(MOLECULE molecule,ATOM bestPartial);extern void GetFundamental(MOLECULE molecule,ATOM bestPartial);extern void GetNearestPartial(MOLECULE molecule,ATOM mainAtom,ATOM nearestPartial);extern void GetBeginEndNote(SIGNAL energyProfile,ATOM atom,LWFLOAT energyTh,LWFLOAT *beginNote,LWFLOAT *endNote,LWFLOAT *endMark);extern LWFLOAT GetEnergyMax(SIGNAL energyProfile,ATOM atom);extern NOTE NewNote(void); extern void DeleteNote(NOTE note); // The parameters for the note detection algorithmstatic LWFLOAT minNoteDuration = 0.03; /* Delta t_min : minimum duration of the notes */static LWFLOAT stopCoeff2Ratio = 0.01; /* ?? When to stop in the book */static LWFLOAT maxFundRatio = 0.03; /* ?? Minimum energy of the fundamental (compared to the most energetic one) */static LWFLOAT thresholdNoteDB = -14; /* theta_beg = theta_end : Used to find begining and end of a note */static LWFLOAT freqSigmaFact = 8; /* Controls the bandwidth (in Hertz) * of a FoF at octave 12 (windowSize 4096) * and sampling frequency 16000 */static LWFLOAT markRatio = 0.00002; /* Controls how different from the * fundamental frequency the frequency * of a marked atom can be */static LWFLOAT deltaFreq = 5;NOTE NewNote(void) { NOTE notes;#ifdef DEBUGALLOC DebugType = "Note";#endif notes = (NOTE) Malloc(sizeof(struct note)); notes->onset = 0.0; notes->end = 0.0; notes->pitch = 0.0; return(notes);} void DeleteNote(NOTE n){#ifdef DEBUGALLOC DebugType = "Note";#endif Free(n);}// COMMANDvoid C_Notes(char **argv) { int nMax,nMin; BOOK book = NULL; NOTE note[500],*note1; char flagSynthesis; int i; char opt; SIGNAL synSig; char **list,**list1; int attack; LISTV reslist; LISTV res; argv = ParseArgv(argv,tBOOK,&book,-1); CheckBookNotEmpty(book); /* Default values */ nMin = 0; nMax = book->size-1; flagSynthesis = NO; /* Reading options */ while(( opt = ParseOption(&argv))) { switch(opt) { case 'n' : /* nMin nMax */ argv = ParseArgv(argv,tINT,&nMin,tINT_,-1,&nMax,-1); if(nMax == -1) nMax = nMin; break; case 's' : /* synthesis of the notes */ argv = ParseArgv(argv,tSIGNAL,&synSig,tINT_,1000,&attack,tLIST,&list,-1); flagSynthesis = YES; break; default : ErrorOption(opt); } } NoMoreArgs(argv);/* Printf("nMin:%d , nMax:%d\n",nMin,nMax); */ // Synthesis if asked if (flagSynthesis) { note1 = note; while (*list) { *note1 = NewNote(); ParseList(*list,&list1); ParseArgv(list1,tFLOAT,&((*note1)->pitch),tFLOAT,&((*note1)->onset),tFLOAT,&((*note1)->end),0); note1++; list++; } *note1 = NULL; NotesSynthesis(note,synSig,book,attack); for (i=0;note[i]!=NULL;i++) { DeleteNote(note[i]); } return; } // Computing the notes from the molecules of the book Notes(book,nMin,nMax,note); // Setting the resulting list reslist = TNewListv(); for (i=0;note[i]!=NULL;i++) { res = TNewListv(); AppendFloat2Listv(res,note[i]->pitch); AppendFloat2Listv(res,note[i]->onset); AppendFloat2Listv(res,note[i]->end); AppendValue2Listv(reslist,(VALUE)res); DeleteNote(note[i]); }}static int *blackList = NULL;void Notes(BOOK book,int nMin,int nMax,NOTE *note){ unsigned long n; int i; int minOctave; int flagNote = NO; LWFLOAT maxMoleculeCoeff2,maxFundCoeff2; static MOLECULE molecule = NULL; static ATOM fundamental = NULL; int noteNum; LWFLOAT pp,ee,bb; noteNum = 0; note[0] = NULL; CheckBookNotEmpty(book); /* Initializing */ if (fundamental == NULL) { fundamental = NewAtom(); molecule = NewMolecule(); } if (blackList != NULL) Free(blackList); blackList = IntAlloc(book->size); for (i = 0;i < book->size;i++) *(blackList + i) = 0; minOctave = (int) floor(log(floor(minNoteDuration/(book->dx)))/log(2)); Printf("minOctave:%d\n",minOctave); molecule = GetBookMolecule(book,0); GetFundamental(molecule,fundamental); maxMoleculeCoeff2 = molecule->coeff2; maxFundCoeff2 = fundamental->coeff2; /* Main loop to search notes */ for (n=nMin; n<=nMax; n++) { if (*(blackList+n-1)) continue; molecule = GetBookMolecule(book,n); // Condition to stop the notes search if ( molecule->coeff2 < maxMoleculeCoeff2*stopCoeff2Ratio ) break; // Else we take the fundamental in the current molecule GetFundamental(molecule,fundamental); // We don't take into account small atoms /* ????? bof */ if (fundamental->windowSize <= 1<<minOctave) continue; if (fundamental->coeff2 < maxFundCoeff2*maxFundRatio) continue; /* ShortPrintAtom(fundamental); */ Printf("ATOM:%d ->\n",n); flagNote = SearchNote(book,fundamental,n,blackList,&pp,&bb,&ee); if (!flagNote) continue; if (ee-bb < minNoteDuration ) { Printf("\tToo small!\n"); continue; } Printf(" NOTE:%d (pitch:%f, begin:%f, end:%f)\n",noteNum+1,pp,bb,ee); note[noteNum] = NewNote(); note[noteNum]->onset = bb; note[noteNum]->end = ee; note[noteNum]->pitch = pp; noteNum++; note[noteNum] = NULL; }}void NotesSynthesis(NOTE *note,SIGNAL synthesis,BOOK book,int attack){ int i,j; int begin,end; LWFLOAT dx; SizeSignal(synthesis,book->signalSize,YSIG); ZeroSig(synthesis); synthesis->dx = book->dx; synthesis->x0 = book->x0; dx = synthesis->dx; for (i=0;note[i]!=NULL;i++) { begin = (int) ((note[i]->onset)/dx); end = (int) ((note[i]->end)/dx); for (j=begin;j<=begin+attack;j++) { synthesis->Y[j] += (1-cos(0.5*M_PI*(j-begin)/((LWFLOAT) attack)))*sin(2*M_PI*(note[i]->pitch)*j*dx); } for (;j<=end-attack;j++) { synthesis->Y[j] += sin(2*M_PI*(note[i]->pitch)*j*dx); } for (;j<=end;j++) { synthesis->Y[j] += (1-cos(.5*M_PI*(end-j)/((LWFLOAT) attack)))*sin(2*M_PI*(note[i]->pitch)*j*dx); } }}int SearchNote(BOOK book,ATOM mainAtom,int numAtom,int *flagNotes,LWFLOAT *pp, LWFLOAT * bb, LWFLOAT * ee){ static SIGNAL energyProfile = NULL; int foundAtoms; LWFLOAT pitchNote,pitchNoteId; LWFLOAT beginNote,endNote; LWFLOAT beginNoteId,endNoteId,endMarkId; /* Init the energy profile signal */ if (energyProfile == NULL) energyProfile = NewSignal(); /* Compute the energy profile */ ComputeEnergyProfile(book,mainAtom,energyProfile); /* we find the onset and the end of the note taking into account a threshold of energy */ GetBeginEndNote(energyProfile,mainAtom,thresholdNoteDB,&beginNoteId,&endNoteId,&endMarkId); pitchNote = FreqId2Freq(mainAtom,mainAtom->freqId); pitchNoteId = mainAtom->freqId; beginNote = mainAtom->dx*beginNoteId; endNote = mainAtom->dx*endNoteId; /* Printf("\tNOTE:( pitch: %f(%d), begin: %f(%d), end: %f(%d) )\n",pitchNote,(int)(mainAtom->freqId),beginNote,(int)(beginNoteId),endNote,(int)(endNoteId)); */ *pp = pitchNote; *bb = beginNote; *ee = MAX(endNote,beginNote+mainAtom->dx*0.5*mainAtom->windowSize); /* look for atoms which seem to belong to the same note */ foundAtoms = MarkAtoms(book,mainAtom,numAtom,flagNotes,&beginNoteId,endMarkId); Printf("foundAtoms:%d\n",foundAtoms); if (foundAtoms > 0) { Printf("\n"); return(YES); } else { Printf("\t\tNOT A NOTE!\n"); return(NO); }}void ComputeEnergyProfile(BOOK book,ATOM mainAtom,SIGNAL energyProfile){ static ATOM partial = NULL; static MOLECULE moleculeSearch = NULL; unsigned long n; int i; LWFLOAT energyMax; // Allocation (once) if (partial == NULL) { partial = NewAtom(); moleculeSearch = NewMolecule(); } // Initialize the energyProfile SizeSignal(energyProfile,book->signalSize,YSIG); energyProfile->dx = book->dx; energyProfile->x0 = book->x0; for (i = 0; i <energyProfile->size; i++) energyProfile->Y[i] = 1e-7; /* Now we add the envelope of the others atoms with a frequency correction */ for (n = 0; n<book->size; n++) { moleculeSearch = GetBookMolecule(book,n); /* we take the best partial in this molecule */ GetNearestPartial(moleculeSearch,mainAtom,partial); /* we add the envelope of the best partial */ AddAtomEnergyEnvelope(energyProfile,partial,mainAtom); } /* linear -> dB */ energyMax = GetEnergyMax(energyProfile,mainAtom); for (i = 0; i <energyProfile->size; i++) energyProfile->Y[i] = 10*log10(energyProfile->Y[i]/energyMax);} /* COMMAND */void C_CreateProfile(char **argv){ BOOK book; SIGNAL signal; unsigned long n; MOLECULE molecule; static ATOM atom = NULL; LWFLOAT delta; LWFLOAT begin,end,end1; if (atom == NULL) { atom = NewAtom(); } argv = ParseArgv(argv,tBOOK,&book,tSIGNAL,&signal,tINT,&n,tFLOAT_,deltaFreq,&delta,0); deltaFreq = delta; molecule = GetBookMolecule(book,n); GetFundamental(molecule,atom); ComputeEnergyProfile(book,atom,signal); GetBeginEndNote(signal,atom,thresholdNoteDB,&begin,&end,&end1);// /*signal->Y[(int) (begin+.5)] = 10; signal->Y[(int) (end+.5)] = 10; */}int MarkAtoms(BOOK book,ATOM mainAtom,int numAtom,int *flagNotes,LWFLOAT * beginNoteId,LWFLOAT endNoteId){ static ATOM partial = NULL; static MOLECULE moleculeSearch = NULL; static ATOM fund = NULL; unsigned long n; int timesFreq; int foundAtoms; int partialSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -