Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/Pitch2Chroma.cpp
Go to the documentation of this file.
00001 #include "Pitch2Chroma.h"
00002 #include <map>
00003 #include <algorithm>
00004 
00005 using std::ostringstream;
00006 using std::max;
00007 using std::min;
00008 
00009 using namespace Marsyas;
00010 
00011 Pitch2Chroma::Pitch2Chroma(mrs_string inName)
00012   :MarSystem("Pitch2Chroma",inName)
00013 {
00014   addControls();
00015 }
00016 
00017 Pitch2Chroma::Pitch2Chroma(const Pitch2Chroma& inToCopy)
00018   :MarSystem(inToCopy)
00019 {
00020   ctrl_SampleRate_ = getctrl("mrs_real/SampleRate");
00021   ctrl_LowestPitch_ = getctrl("mrs_real/LowestPitch");
00022   ctrl_NotesPerOctave_ = getctrl("mrs_natural/NotesPerOctave");
00023   ctrl_NrOfNotes_ = getctrl("mrs_natural/NrOfNotes");
00024   ctrl_RefChromaIndex_ = getctrl("mrs_natural/RefChromaIndex_");
00025 
00026   SampleRate_ = inToCopy.SampleRate_;
00027   LowestPitch_ = inToCopy.LowestPitch_;
00028   NotesPerOctave_ = inToCopy.NotesPerOctave_;
00029   NrOfNotes_ = inToCopy.NrOfNotes_;
00030   RefChromaIndex_ = inToCopy.RefChromaIndex_;
00031 }
00032 
00033 Pitch2Chroma::~Pitch2Chroma() {}
00034 
00035 MarSystem* Pitch2Chroma::clone() const
00036 {
00037   return new Pitch2Chroma(*this);
00038 }
00039 
00040 void Pitch2Chroma::addControls()
00041 {
00042   addctrl("mrs_real/SampleRate",8000.,ctrl_SampleRate_);
00043   addctrl("mrs_real/LowestPitch",27.5,ctrl_LowestPitch_);
00044   addctrl("mrs_natural/NotesPerOctave",12,ctrl_NotesPerOctave_);
00045   addctrl("mrs_natural/NrOfNotes",88,ctrl_NrOfNotes_);
00046   addctrl("mrs_natural/RefChromaIndex_",6,ctrl_RefChromaIndex_);
00047 
00048   ctrl_SampleRate_->setState(true);
00049   ctrl_LowestPitch_->setState(true);
00050   ctrl_NotesPerOctave_->setState(true);
00051   ctrl_NrOfNotes_->setState(true);
00052   ctrl_RefChromaIndex_->setState(true);
00053 
00054   SampleRate_ = 8000.;
00055   LowestPitch_ = 27.5;
00056   NotesPerOctave_ = 12;
00057   NrOfNotes_ = 88;
00058   RefChromaIndex_ = 6;
00059 }
00060 
00061 void Pitch2Chroma::myUpdate(MarControlPtr inSender)
00062 {
00063   MarSystem::myUpdate(inSender);
00064   ctrl_onObservations_->setValue(NotesPerOctave_,NOUPDATE);
00065 
00066   // Update member variables
00067   SampleRate_ = ctrl_SampleRate_->to<mrs_real>();
00068   LowestPitch_ = ctrl_LowestPitch_->to<mrs_real>();
00069   NotesPerOctave_ = ctrl_NotesPerOctave_->to<mrs_natural>();
00070   NrOfNotes_ = ctrl_NrOfNotes_->to<mrs_natural>();
00071   RefChromaIndex_ = ctrl_RefChromaIndex_->to<mrs_natural>();
00072 
00073   UpdatePitchToNoteTransform();
00074   UpdateNoteToChromaTransform();
00075 }
00076 
00077 void Pitch2Chroma::UpdatePitchToNoteTransform()
00078 {
00079   // Define pitch to note transformation
00080   PitchToNoteTransform_.create(NrOfNotes_,inObservations_);
00081   StartAndEndIndex_.create(NrOfNotes_,2);
00082 
00083   mrs_real theLOGFc = LowestPitch_;
00084   mrs_real theLOGFStep = pow(2.,1./(mrs_real)NotesPerOctave_);
00085   mrs_real theLinFStep = SampleRate_/(2.f*(mrs_real)inObservations_);
00086   for (int i=0; i<NrOfNotes_; ++i)
00087   {
00088     // Define begin and end frequency
00089     mrs_real theLOGFb = theLOGFc/sqrt(theLOGFStep);
00090     mrs_real theLOGFe = theLOGFc*sqrt(theLOGFStep);
00091 
00092     // Convert begin and end frequency to FFT index
00093     StartAndEndIndex_(i,0) = max((int)ceil(theLOGFb/theLinFStep),0);
00094     StartAndEndIndex_(i,1) = min((int)floor(theLOGFe/theLinFStep),(int)inObservations_-1);
00095 
00096     for (int j=(mrs_natural)StartAndEndIndex_(i,0); j<=(mrs_natural)StartAndEndIndex_(i,1); j++)
00097     {
00098       double theBinFreq = (mrs_real)j*theLinFStep;
00099       if (theBinFreq <= theLOGFc)
00100         // Ramp up
00101         PitchToNoteTransform_(i,j) = (theBinFreq-theLOGFb)/(theLOGFc-theLOGFb);
00102       else
00103         // Ramp down
00104         PitchToNoteTransform_(i,j) = 1.-(theBinFreq-theLOGFc)/(theLOGFe-theLOGFc);
00105     }
00106 
00107     theLOGFc *= theLOGFStep;
00108   }
00109 }
00110 
00111 void Pitch2Chroma::UpdateNoteToChromaTransform()
00112 {
00113   // Define note to chroma transformation
00114   NoteToChromaTransform_.create(NotesPerOctave_,NrOfNotes_);
00115 
00116   for (int i=0; i<NotesPerOctave_; ++i)
00117     for (int j=i; j<NrOfNotes_; j+=NotesPerOctave_)
00118     {
00119       int theChromaIndex = (7*i+RefChromaIndex_-1)%NotesPerOctave_;
00120       NoteToChromaTransform_(theChromaIndex,j) = 1.;
00121     }
00122 }
00123 
00124 void Pitch2Chroma::myProcess(realvec& inVec, realvec& outVec)
00125 {
00126   mrs_natural t,o;
00127   outVec.setval(0.);
00128   for(o=0; o<onObservations_; o++)
00129     for(t=0; t<inSamples_; t++)
00130       for(int i=0; i<NrOfNotes_; ++i)
00131         for(int j=(mrs_natural)StartAndEndIndex_(i,0); j<=(mrs_natural)StartAndEndIndex_(i,1); j++)
00132           outVec(o,t) += NoteToChromaTransform_(o,i)*
00133                          PitchToNoteTransform_(i,j)*inVec(j,t);
00134 
00135   if (outVec.sum() != 0)
00136     outVec /= outVec.sum();
00137 }