Import upstream version 0.99.2
[fmit.git] / libs / Music / Quantizer.cpp
1 // Copyright 2005 "Gilles Degottex"
2
3 // This file is part of "Music"
4
5 // "Music" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or
8 // (at your option) any later version.
9 // 
10 // "Music" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 // 
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
20 #include "Quantizer.h"
21
22 #include <iostream>
23 using namespace std;
24 #include <Music/Music.h>
25 using namespace Music;
26 #include <CppAddons/Random.h>
27
28 Quantizer::Quantizer(float tolerance, float min_density)
29 {
30         m_min_ht = -48;
31         m_channels.resize(97);
32
33         m_tolerance = tolerance;
34         m_min_density = min_density;
35
36         m_time.start();
37 }
38
39 void Quantizer::quantize(const vector<bool> hts, int min_ht)
40 {
41         double current_time = m_time.elapsed();
42
43         m_min_stored_recon = 1000000;
44         for(size_t ht=0; ht<hts.size(); ht++)
45         {
46                 int rht = ht+min_ht-m_min_ht;
47
48                 // add the new one
49                 m_channels[rht].old_states.push_front(State(current_time, hts[ht]));
50
51                 m_min_stored_recon = min(m_min_stored_recon, int(m_channels[rht].old_states.size()));
52
53                 // update channel
54                 update(rht);
55
56                 // drop unused recognitions
57                 while(!m_channels[rht].old_states.empty() && (current_time-m_channels[rht].old_states.back().time>m_tolerance))
58                         m_channels[rht].old_states.pop_back();
59         }
60 }
61
62 void Quantizer::update(int rht)
63 {
64         Channel& channel = m_channels[rht];
65
66         if(!channel.old_states.empty())
67         {
68                 // compute density
69                 int dens = 0;
70                 for(size_t i=0; i<channel.old_states.size(); i++)
71                         if(channel.old_states[i].play)
72                                 dens++;
73
74                 channel.reliability = float(dens)/channel.old_states.size();
75
76                 // if a density is strong enough (depend of parameter dens_required)
77                 if(channel.reliability>m_min_density)
78                 {
79                         if(channel.state==Channel::QC_NOTHING)
80                         {
81                                 channel.state = Channel::QC_STARTING;
82                                 channel.duration.start();
83                                 channel.lag.start();
84                         }
85
86                         if(channel.state==Channel::QC_STARTING)
87                         {
88                                 if(channel.lag.elapsed()>m_tolerance)
89                                 {
90                                         channel.state = Channel::QC_PLAYING;
91                                         channel.last_tag = Random::s_random.nextInt();
92                                         MFireEvent(noteStarted(channel.last_tag, rht+m_min_ht, -channel.lag.elapsed()));
93                                 }
94                         }
95
96                         if(channel.state==Channel::QC_PLAYING)
97                                 channel.lag.start();
98                 }
99                 else
100                 {
101                         if(channel.state==Channel::QC_STARTING)
102                                 channel.state = Channel::QC_NOTHING;
103                         else if(channel.state==Channel::QC_PLAYING && channel.lag.elapsed()>m_tolerance)
104                         {
105                                 channel.state = Channel::QC_NOTHING;
106                                 MFireEvent(noteFinished(channel.last_tag, rht+m_min_ht, -channel.lag.elapsed()));
107                                 MFireEvent(notePlayed(rht+m_min_ht, channel.duration.elapsed()-channel.lag.elapsed(), -channel.lag.elapsed()-channel.duration.elapsed()));
108                         }
109                 }
110         }
111 }
112
113 void Quantizer::cutAll()
114 {
115         m_min_stored_recon = 0;
116         for(size_t ht=0; ht<m_channels.size(); ht++)
117         {
118                 m_channels[ht].old_states.clear();
119                 update(ht+m_min_ht);
120         }
121 }
122