Merge commit '0.99.2'
[fmit.git] / libs / Music / Quantizer.cpp
diff --git a/libs/Music/Quantizer.cpp b/libs/Music/Quantizer.cpp
new file mode 100644 (file)
index 0000000..1e6a6c0
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2005 "Gilles Degottex"
+
+// This file is part of "Music"
+
+// "Music" is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation; either version 2.1 of the License, or
+// (at your option) any later version.
+// 
+// "Music" 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 Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+#include "Quantizer.h"
+
+#include <iostream>
+using namespace std;
+#include <Music/Music.h>
+using namespace Music;
+#include <CppAddons/Random.h>
+
+Quantizer::Quantizer(float tolerance, float min_density)
+{
+       m_min_ht = -48;
+       m_channels.resize(97);
+
+       m_tolerance = tolerance;
+       m_min_density = min_density;
+
+       m_time.start();
+}
+
+void Quantizer::quantize(const vector<bool> hts, int min_ht)
+{
+       double current_time = m_time.elapsed();
+
+       m_min_stored_recon = 1000000;
+       for(size_t ht=0; ht<hts.size(); ht++)
+       {
+               int rht = ht+min_ht-m_min_ht;
+
+               // add the new one
+               m_channels[rht].old_states.push_front(State(current_time, hts[ht]));
+
+               m_min_stored_recon = min(m_min_stored_recon, int(m_channels[rht].old_states.size()));
+
+               // update channel
+               update(rht);
+
+               // drop unused recognitions
+               while(!m_channels[rht].old_states.empty() && (current_time-m_channels[rht].old_states.back().time>m_tolerance))
+                       m_channels[rht].old_states.pop_back();
+       }
+}
+
+void Quantizer::update(int rht)
+{
+       Channel& channel = m_channels[rht];
+
+       if(!channel.old_states.empty())
+       {
+               // compute density
+               int dens = 0;
+               for(size_t i=0; i<channel.old_states.size(); i++)
+                       if(channel.old_states[i].play)
+                               dens++;
+
+               channel.reliability = float(dens)/channel.old_states.size();
+
+               // if a density is strong enough (depend of parameter dens_required)
+               if(channel.reliability>m_min_density)
+               {
+                       if(channel.state==Channel::QC_NOTHING)
+                       {
+                               channel.state = Channel::QC_STARTING;
+                               channel.duration.start();
+                               channel.lag.start();
+                       }
+
+                       if(channel.state==Channel::QC_STARTING)
+                       {
+                               if(channel.lag.elapsed()>m_tolerance)
+                               {
+                                       channel.state = Channel::QC_PLAYING;
+                                       channel.last_tag = Random::s_random.nextInt();
+                                       MFireEvent(noteStarted(channel.last_tag, rht+m_min_ht, -channel.lag.elapsed()));
+                               }
+                       }
+
+                       if(channel.state==Channel::QC_PLAYING)
+                               channel.lag.start();
+               }
+               else
+               {
+                       if(channel.state==Channel::QC_STARTING)
+                               channel.state = Channel::QC_NOTHING;
+                       else if(channel.state==Channel::QC_PLAYING && channel.lag.elapsed()>m_tolerance)
+                       {
+                               channel.state = Channel::QC_NOTHING;
+                               MFireEvent(noteFinished(channel.last_tag, rht+m_min_ht, -channel.lag.elapsed()));
+                               MFireEvent(notePlayed(rht+m_min_ht, channel.duration.elapsed()-channel.lag.elapsed(), -channel.lag.elapsed()-channel.duration.elapsed()));
+                       }
+               }
+       }
+}
+
+void Quantizer::cutAll()
+{
+       m_min_stored_recon = 0;
+       for(size_t ht=0; ht<m_channels.size(); ht++)
+       {
+               m_channels[ht].old_states.clear();
+               update(ht+m_min_ht);
+       }
+}
+