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