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