]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/speedquantizer.cpp
Don't use too short speed measurements for quantizer learning
[r2c2.git] / source / libr2c2 / speedquantizer.cpp
1 /* $Id$
2
3 This file is part of R²C²
4 Copyright © 2011  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include "speedquantizer.h"
9
10 using namespace std;
11 using namespace Msp;
12
13 namespace R2C2 {
14
15 SpeedQuantizer::SpeedQuantizer(unsigned n):
16         steps(n+1),
17         weight_limit(10)
18 {
19         if(n<1)
20                 throw InvalidParameterValue("Must have at leats one speed step");
21 }
22
23 void SpeedQuantizer::learn(unsigned i, float s, float w)
24 {
25         if(i>=steps.size())
26                 throw InvalidParameterValue("Speed step index out of range");
27         steps[i].add(s, w);
28 }
29
30 float SpeedQuantizer::get_speed(unsigned i) const
31 {
32         if(i==0)
33                 return 0;
34         if(steps[i].weight>=weight_limit)
35                 return steps[i].speed;
36
37         unsigned low;
38         unsigned high;
39         for(low=i; low>0; --low)
40                 if(steps[low].weight>=weight_limit)
41                         break;
42         for(high=i; high+1<steps.size(); ++high)
43                 if(steps[high].weight>=weight_limit)
44                         break;
45
46         if(steps[high].weight)
47         {
48                 if(steps[low].weight)
49                         return (steps[low].speed*(high-i)+steps[high].speed*(i-low))/(high-low);
50                 else
51                         return steps[high].speed*i/high;
52         }
53         else if(steps[low].weight)
54                 return steps[low].speed*i/low;
55         else
56                 return 0;
57 }
58
59 float SpeedQuantizer::quantize_speed(float speed) const
60 {
61         return get_speed(find_speed_step(speed));
62 }
63
64 unsigned SpeedQuantizer::find_speed_step(float speed) const
65 {
66         if(speed<=steps[1].speed*0.5)
67                 return 0;
68
69         unsigned low = 0;
70         unsigned high = 0;
71         unsigned last = 0;
72         for(unsigned i=0; (!high && i<steps.size()); ++i)
73                 if(steps[i].weight>=weight_limit)
74                 {
75                         last = i;
76                         if(steps[i].speed>=speed)
77                                 high = i;
78                         else if(steps[i].speed>steps[low].speed)
79                                 low = i;
80                 }
81
82         if(!high)
83         {
84                 unsigned limit = steps.size()/5;
85                 if(!low)
86                 {
87                         if(speed)
88                                 return limit;
89                         else
90                                 return 0;
91                 }
92                 return min(min(static_cast<unsigned>(low*speed/steps[low].speed), steps.size()-1), last+limit);
93         }
94
95         float f = (speed-steps[low].speed)/(steps[high].speed-steps[low].speed);
96         return static_cast<unsigned>(low*(1-f)+high*f+0.5);
97 }
98
99 void SpeedQuantizer::save(list<DataFile::Statement> &st) const
100 {
101         for(unsigned i=0; i<steps.size(); ++i)
102                 if(steps[i].weight)
103                         st.push_back((DataFile::Statement("step"), i, steps[i].speed, steps[i].weight));
104 }
105
106
107 SpeedQuantizer::SpeedStep::SpeedStep():
108         speed(0),
109         weight(0)
110 { }
111
112 void SpeedQuantizer::SpeedStep::add(float s, float w)
113 {
114         speed = (speed*weight+s*w)/(weight+w);
115         weight = min(weight+w, 300.0f);
116 }
117
118
119 SpeedQuantizer::Loader::Loader(SpeedQuantizer &q):
120         DataFile::ObjectLoader<SpeedQuantizer>(q)
121 {
122         add("step", &Loader::step);
123 }
124
125 void SpeedQuantizer::Loader::step(unsigned i, float s, float w)
126 {
127         if(i>=obj.steps.size())
128                 return;
129
130         obj.steps[i].speed = s;
131         obj.steps[i].weight = w;
132 }
133
134 } // namespace R2C2