view hs.h @ 11:977f541d6683

GPL and cosmetic changes
author Wen X <xue.wen@elec.qmul.ac.uk>
date Wed, 10 Aug 2011 12:33:35 +0100
parents 5f3c32dc6e17
children
line wrap: on
line source
/*
    Harmonic sinusoidal modelling and tools

    C++ code package for harmonic sinusoidal modelling and relevant signal processing.
    Centre for Digital Music, Queen Mary, University of London.
    This file copyright 2011 Wen Xue.

    This program is 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.
*/
#ifndef hsH
#define hsH

/**
  \file hs.h - harmonic sinusoid model

  Further reading: Wen X. and M. Sandler, "Sinusoid modeling in a harmonic context," in Proc. DAFx'07, Bordeaux, 2007.
*/

//---------------------------------------------------------------------------
#include <string.h>
#include "arrayalloc.h"
#include "align8.h"
#include "fft.h"
#include "quickspec.h"

#ifndef __BORLANDC__
#include "tstream.h"
#else
#include <Classes.hpp>
#endif

#define ATOM_LOCALANCHOR 1
#define HS_CONSTF 1
#define MAX_CAND 64
#define STIFF_B_MAX 0.01

enum atomtype //type flags of an HS atom
{
  atAnchor,   //"anchor" is an atom whose validity is taken for granted, e.g. user input
  atPeak,     //an atom whose frequency is an actual spectral peak
  atInfered,  //an atom which has no spectral peak and whose frequency is inferred from other atoms
  atMuted,    //an atom which is being muted
  atBuried    //an atom which is buried in background noise
};

struct atom   //an atom of a harmonic sinusoid
{
  double t;   //time
  double s;   //scale
  double f;   //digital frequency
  double a;   //amplitude
  double p;   //phase angle
  int pin;    //partial index
  atomtype type;  //atom type
  int tags;   //additional info on atom type
  float r1;
};

struct candid //candidate atom
{
  int p;      //partial index
  double f;   //frequency
  double df;  //delta freqdel folk
  double s;   //score in partial-sum
  int prev;   //index of last partial f-df
  int type;   //0: f0, 1: local maximum, 2: not a maxixum
  double ms;
};

struct dsparams1      //argument structure for calling ds1()
{
  double s;           //score
  double lastene;     //energy of last frame
  double currentacce; //energy of this frame, currently accumulated
  int p;              //partial index
  int lastP;          //number of efficient partials in last frame
  double* lastvfp;    //amplitude estimates of partials at last frame
};

struct NMResults      //note match output structure
{
  double* fp;         //frequencies, in bins
  double* vfp;        //amplitudes
  double* pfp;        //phase angles
  atomtype* ptype;    //atom types
};

struct NMSettings     //note match algorithm settings
{
  double c[4];        //cosine-family window specifiers
  int M;              //ditto
  double iH2;         //ditto
  double hB;          //spectral truncation half width
  int maxp;           //maximal number of partials
  double maxB;        //stiffness coefficient upper bound
  double epf;         //frequency estimation error tolerance for LSE estimation
  double epf0;        //input frequency error bound for harmonic grouping
  double delm;        //frequency error bound for harmonic grouping
  double delp;        //pitch jump upper bound
  double minf0;       //minimal fundamental frequency
  double maxf0;       //maximal fundamental frequency
  int pin0;           //input partial index
  bool forcepin0;     //force the peak nearest to input frequency as an atom
  bool pin0asanchor;  //mark atom found near the input frequency as anchor
  int pcount;         //number of "pinned" (anchor) partials
  int* pin;           //partial indices of pinned partials
  double* pinf;       //frequencies of pinned partials
  int* pinfr;         //frame indices of pinned partials, used in multi-frame constant-pitch note match
};


/**
  stiffcandid is the harmonic atom class used internally by harmonic grouping and tracking routines. Literally
  it means "candidate harmonic atoms on a stiff string model". The stiff string is the main harmonic model used
  by me for describing frequency relations between partials of a harmonic sound.

  stiffcandid is superceded by TTempAtom class.
*/

class stiffcandid
{
public:
  int P;  //number of partial estimates located
  int* p;   //partial indices of located partials, sizeof(int)*P
  double* f;  //frequencies of located partials, sizeof(double)*P
  double s; //score in partial-sum
  //{N; F, G}: the feasible polygonal area of (F, G) given the P partials, where F=F0*F0, G=F0*B
  int N;
  double* F;  //sizeof(double)*N
  double* G;  //sizeof(double)*N

  stiffcandid(int Wid); //create empty with minimal info
  stiffcandid(int Wid, int ap, double af, double errf); //create empty with pitch range
  stiffcandid(int Wid, int ap, double af, double errf, double ds); //create with 1 atom
  stiffcandid(stiffcandid* prev, int ap, double af, double errf, double ds); //create by updating with new atom
  ~stiffcandid();
};


/**
  THS is the data structure hosting a harmonic sinusoid representation. Its key members include the number
  of partials, number of frames, and all its atoms (sinusoid parameters of all partials at measurement points).
*/
class THS
{
public:
  int Channel;      //channel id: THS describes a harmonic sinusoid in single channel
  int M;            //number of partials
  int Fr;           //number of frames
  atom** Partials;  //atoms, [M][Fr]

  int* BufM[128];   //a buffer for algorithmic use

  int isconstf;     //constant frequencies flag

  double** startamp;//onset amplifiers, optional
  int st_start;     //position of the first onset amplifying point
  int st_offst;     //interval of onset amplifying points
  int st_count;     //number of onset amplifying points

  //constructors and destructor
  THS();
  THS(int aM, int aFr);
  THS(THS* HS);
  THS(THS* HS, double start, double end);
  ~THS();

  int StartPos();   //start position
  int EndPos();     //end position
  int EndPosEx();   //extended end position
  int StdOffst();   //hop size

  void ClearBufM(); //free buffers registered in BufM[]
  void Resize(int aM, int aFr, bool copydata=false, bool forcealloc=false); //change size (M or Fr)

  //I/O routines
  int WriteHdrToStream(TStream* Stream);
  int ReadHdrFromStream(TStream* Stream);
  int WriteAtomToStream(TStream* Stream, atom* atm);
  int ReadAtomFromStream(TStream* Stream, atom* atm);
  int WriteToStream(TStream* Stream);
  int ReadFromStream(TStream* Stream);
};


/**
  TPolygon is a polygon class. This class itself does not enforce convexness. However, when used for solving
  the stiff string model, all polygons are convex, as they are the results of current a first convex polygon
  by straight lines.

  For the convenience of computation, the sequence of vertices are arranged so that they come in clockwise
  order starting from the leftmost (smallest x coordinate) vertex; in case two vertices are both leftmost
  the upper (larger y coordinate) one is placed at the start and the lower one is placed at the end.
*/

class TPolygon
{
public:
  int N;      //number of vertices (equals number of edges)
  double* X;  //x-coordinates of vertices
  double* Y;  //y-coordinates of vertices
  TPolygon(int cap);
  TPolygon(int cap, TPolygon* R);
  ~TPolygon();
}; 


/**
  TTempAtom is an atom class within the stiff-stirng harmonic atom context used internally by harmonic
  grouping and tracking routines. Literally it means "a temporary atom", and truly it hosts most info
  one expects of a potential atom. TTempAtom replaces stiffcandid class in harmonic sinusoid group and
  tracking algorithms, due to the advanges that it carries atom information (frequency, amplitude, etc.)
  as well as harmonic atom information (link to other atom, the F-G polygon), and is therefore both an
  individual atom and a harmonic atom containing all atoms tracked down through the linked list Prev.
*/

class TTempAtom
{
public:
  int pind;     //partial index
  double f;     //frequency
  double a;     //amplitude
  double s;     //scale
  double rsr;   //residue-sinusoid ratio
  TTempAtom* Prev;  //previous atom
  TPolygon *R;  //F-G polygon for harmonic group
  union {double acce; int tag[2];};

  TTempAtom(double af, double ef, double maxB); //create empty with frequency range
  TTempAtom(int apin, double af, double ef, double maxB); //create empty with frequency range
  TTempAtom(TPolygon* AR, double delf1, double delf2, double minf); //create empty with extended R
  TTempAtom(int apind, double af, double ef, double aa, double as, double maxB);  //create with one partial
  TTempAtom(TTempAtom* APrev, bool DupR); //create duplicate
  TTempAtom(TTempAtom* APrev, int apind, double af, double ef, double aa, double as, bool updateR=true); //duplicate and add one partial
  ~TTempAtom();
};

//--internal function--------------------------------------------------------
double ds0(double, void*); //a score function, internal use only

//--general polygon routines-------------------------------------------------
void areaandcentroid(double& A, double& cx, double& cy, int N, double* x, double* y); //compute area and centroid
void cutcvpoly(int& N, double* x, double* y, double A, double B, double C, bool protect=false); //sever polygon by line
double maximalminimum(double& x, double& y, int N, double* sx, double* sy); //maximum inscribed circle

//--F-G polygon routines-----------------------------------------------------
void CutR(TPolygon* R, int apind, double af, double ef, bool protect=false);
void ExBStiff(double& Bmin, double& Bmax, int N, double* F, double* G);
void ExFmStiff(double& Fmin, double& Fmax, int m, int N, double* F, double* G);
void ExtendR(TPolygon* R, double delf1, double delf2, double minf);
void InitializeR(TPolygon* R, double af, double ef, double maxB);
void InitializeR(TPolygon* R, int apind, double af, double ef, double maxB);

//--internal structure conversion routines-----------------------------------
void AtomsToPartials(int k, atom* part, int& M, int& Fr, atom**& partials, int offst);
int NMResultToAtoms(int M, atom* HP, int t, int wid, NMResults results);
int NMResultToPartials(int M, int fr, atom** Partials, int t, int wid, NMResults results);

//--batch sinusoid estimation routines---------------------------------------
double PeakShapeC(double f, int Fr, int N, cdouble** x, int B, int M, double* c, double iH2);
double PeakShapeC(double f, int Fr, int N, cfloat** x, int B, int M, double* c, double iH2);
int QuickPeaks(double* f, double* a, int N, cdouble* x, int M, double* c, double iH2, double mina, int binst=-1, int binen=-1, int B=5, double* rsr=0);
int QuickPeaks(double* f, double* a, int Fr, int N, cdouble** x, int fr0, int r0, int M, double* c, double iH2, double mina, int binst=-1, int binen=-1, int B=5, double* rsr=0);

//--harmonic atom detection (harmonic grouping) routines---------------------
double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int pc, double* fps, double* vps, int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results, int lastp, double* lastvfp, double (*computes)(double a, void* params)=ds0, int forceinputlocalfr=-1); //basic grouping without rsr
double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int pc, double* fps, double* vps, double* rsr, int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results, int lastp, double* lastvfp, double (*computes)(double a, void* params)=ds0, int forceinputlocalfr=-1); //basic grouping with rsr
double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results, int lastp, double* lastvfp, double (*deltas)(double a, void* params)=ds0, bool forceinputlocalfr=false, int startfr=-1, int validfrrange=0); //basic grouping with rsr - wrapper
double NoteMatchStiff3(TPolygon* R, int peak0, int pin0, cdouble* x, int pc, double* fps, double* vps, int N, NMSettings* settings, double* vfp, int** pitchind, int newpc); //grouping with given pitch, single-frame

//--harmonic sinusoid tracking routines--------------------------------------
int FindNote(int _t, double _f, int& M, int& Fr, atom**& partials, int frst, int fren, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings); //harmonic sinusoid tracking (forward and backward tracking)
int FindNoteConst(int _t, double _f, int& M, int& Fr, atom**& partials, int frst, int fren, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings, double brake); //constant-pitch harmonic sinusoid tracking
int FindNoteF(atom* part, double& starts, TPolygon* R, int startp, double* startvfp, int frst, int fren, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings, double brake); //forward harmonic sinusoid tracking
int FindNoteFB(int frst, TPolygon* Rst, double* vfpst, int fren, TPolygon* Ren, double* vfpen, int M, atom** partials, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings); //forward-backward harmonic sinusoid tracking
void NoteMatchStiff3FB(int& pitchcount, TPolygon**& R, double**& vfp, double*& sc, int* newpitches, int* prev, int pc, double* fps, double* vps, cdouble* x, int wid, int maxpitch, NMSettings* settings); //single DP step of FindNoteFB()

//--harmonic sinusoid synthesis routines-------------------------------------
double* SynthesisHS(int pm, int pfr, atom** partials, int& dst, int& den, bool* terminatetag=0);
double* SynthesisHS(THS* HS, int& dst, int& den, bool* terminatetag=0);
double* SynthesisHS2(int M, int Fr, atom** partials, int& dst, int& den, bool* terminatetag=0);
double* SynthesisHSp(int pm, int pfr, atom** partials, int& dst, int& den, double** startamp=0, int st_start=0, int st_offst=0, int st_count=0);
double* SynthesisHSp(THS* HS, int& dst, int& den);

//--other functions----------------------------------------------------------
void ReEstHS1(THS* HS, __int16* Data16); //reestimation of HS

#endif