File Coverage

blib/lib/Video/Function.pm
Criterion Covered Total %
statement 9 157 5.7
branch 0 66 0.0
condition 0 14 0.0
subroutine 3 19 15.7
pod 0 16 0.0
total 12 272 4.4


line stmt bran cond sub pod time code
1             package Video::Function;
2              
3 2     2   10 use vars qw($VERSION @EXPORT);
  2         3  
  2         142  
4             $VERSION = 0.01;
5             @EXPORT = qw(new sum show zero compress truncate);
6              
7 2     2   10 use strict;
  2         5  
  2         82  
8 2     2   1790 use Math::Round qw(nearest_ceil nearest_floor nearest);
  2         28567  
  2         4007  
9              
10             sub new {
11 0     0 0   my ($class, $resolution, $length) = @_;
12 0   0       my $self = bless {}, ref($class) || $class;
13 0           $self->{'function'} = {};
14              
15             #number of divisions in a sec
16 0 0         $self->{'resolution'} = $resolution if $resolution;
17              
18 0   0       $self->{'length'} = $length || -1;
19              
20 0           return $self;
21             }
22              
23             sub setlength {
24 0     0 0   my ($self, $length) = @_;
25 0 0         $self->{'length'} = $length if $length;
26 0           return 1;
27             }
28              
29             sub compress {
30 0     0 0   my ($self, $desiredlength, $method) = @_;
31 0           my $original = $self->{'function'};
32 0           $self->{'desiredlength'} = $desiredlength;
33              
34 0 0         if ($desiredlength > $self->{'length'}) {
35 0           my $multiplier = $desiredlength/$self->{'length'};
36 0           $self->multiply($multiplier);
37 0           print "warning: making coolness function longer, method is irrelevant\n";
38             }
39              
40 0 0         if ($method eq "simple") {
41 0           my $multiplier = $desiredlength / ($self->{'length'});
42 0           $self->multiply($multiplier);
43             }
44              
45 0 0         if ($method eq "cutoff") {
46 0           my $cutoff = 0;
47 0           my $delta = 0.1;
48 0   0       while (($desiredlength < $self->sumsel($cutoff, "greater"))
49             and ($cutoff <= 1)) {
50 0           $cutoff += $delta;
51             }
52 0           my %function = %{$self->{'function'}};
  0            
53 0           foreach my $point (keys %function) {
54 0 0         if ($function{$point} < $cutoff) {
55 0           $function{$point} = 0;
56             }
57             }
58 0           %{$self->{'function'}} = %function;
  0            
59             }
60             }
61              
62             sub multiply {
63 0     0 0   my ($self, $multiplier) = @_;
64 0           my %function = %{$self->{'function'}};
  0            
65 0           foreach my $point (keys %function) {
66 0           $function{$point} *= $multiplier;
67 0 0         if ($function{$point} > 1) {
68 0           $function{$point} = 1;
69             }
70             }
71 0           %{$self->{'function'}} = %function;
  0            
72             }
73              
74             sub sum {
75 0     0 0   my ($self) = @_;
76 0           return $self->sumsel(0,"greater");
77             }
78              
79             sub sumsel {
80 0     0 0   my ($self, $cutoff, $sign) = @_;
81 0           my $sum = 0;
82 0           foreach my $value (values %{$self->{'function'}}) {
  0            
83 0 0         if ($sign eq "greater") {
84 0 0         if ($value >= $cutoff) {
85 0           $sum += $value;
86             }
87             }
88 0 0         if ($sign eq "less") {
89 0 0         if ($value <= $cutoff) {
90 0           $sum += $value;
91             }
92             }
93             }
94 0           return $sum/$self->{'resolution'};
95             }
96              
97             sub zero {
98 0     0 0   my ($self) = @_;
99 0           my $length = $self->{'length'};
100 0           my $resolution = $self->{'resolution'};
101 0           for (my $i=0; $i<$length; $i+=(1/$resolution)) {
102 0           my $big = scalar keys %{$self->{'function'}};
  0            
103 0           $i = nearest(1/$resolution, $i);
104 0 0         unless (defined $self->{'function'}{$i}) {
105 0           $self->{'function'}{$i} = 0;
106             }
107             }
108 0           return $self;
109             }
110              
111             sub truncate {
112 0     0 0   my ($self) = @_;
113 0           my $length = $self->{'length'};
114 0           foreach my $index (keys %{$self->{'function'}}) {
  0            
115 0 0         if ($index < 0) {
116 0           delete ${$self-{'function'}}{$index};
  0            
117 0           print "truncated negative index\n";
118             }
119 0 0         if ($index > $length) {
120 0           delete ${$self->{'function'}}{$index};
  0            
121             }
122             }
123 0           return $self;
124             }
125              
126             sub show {
127 0     0 0   my ($self) = @_;
128 0           my @unsorted = keys %{$self->{'function'}};
  0            
129 0           my @sorted = sort {$a<=>$b} @unsorted;
  0            
130 0           my $data = "";
131 0           foreach my $key (@sorted) {
132 0           $data .= sprintf("%3.2f \t %1.3f\n", $key, $self->{'function'}{$key});
133             }
134 0           return $data;
135             }
136              
137             sub apply {
138 0     0 0   my ($self, $time, $value) = @_;
139 0           $time = nearest(1/($self->{'resolution'}), $time);
140 0 0         if ($time < 0) { $time = 0; }
  0            
141 0           $self->{'function'}{$time} = max($self->{'function'}{$time},
142             $value
143             );
144             }
145              
146             sub applybunch {
147 0     0 0   my ($self, $event) = @_;
148 0           my $eventtime = $event->{'time'};
149 0           my $zerooverride = $event->{'zerooverride'};
150              
151 0 0         $event->{'cool'} = 0 if not defined $event->{'cool'};
152             #scale keypress (key between 1 and 9) to fit between 0 and 1
153 0 0         $event->{'cool'} = ($event->{'cool'}/9) if $event->{'cool'} > 1;
154              
155 0 0         if (defined $event->{'type'}) {
156              
157 0 0         if ($event->{'type'} eq 'long') {
158 0 0 0       if ( defined $event->{'endtime'} and
159             defined $event->{'cool'}
160             ) {
161 0           my $numsteps = ($event->{'endtime'} - $eventtime)
162             * $self->{'resolution'};
163 0           foreach my $step (0 .. $numsteps) {
164 0           $self->apply(nearest(1/$self->{'resolution'},
165             $eventtime + ($step/$self->{'resolution'})
166             ),
167             $event->{'cool'}
168             );
169             }
170 0 0         if (defined $event->{'envelope'}) {
171 0           $self->fillin($event->{'time'}, $event->{'envelope'}, $event->{'zerooverride'}, $event->{'cool'}, -1);
172 0           $self->fillin($event->{'endtime'}, $event->{'envelope'}, $event->{'zerooverride'}, $event->{'cool'}, 1);
173             }
174             }
175             else {
176 0           die __PACKAGE__ . ": problem with long event, no endtime or no coolness, can't build coolness function";
177             }
178             }
179 0 0         if ($event->{'type'} ne 'long') {
180 0           $self->fillin($event->{'time'}, $event->{'envelope'}, $event->{'zerooverride'}, $event->{'cool'});
181             }
182              
183              
184             }
185             #if type not defined, then can't apply envelope because don't know how
186              
187             }
188              
189              
190             sub fillin {
191 0     0 0   my ($self, $eventtime, $points, $zerooverride, $scaleto, $direction) = @_;
192 0           my $resolution = $self->{'resolution'};
193 0           my @ordered = sort {$a <=> $b} (keys %$points);
  0            
194 0           my $first = nearest_ceil(1/$resolution, $ordered[0] + $eventtime);
195 0           my $last = nearest_floor(1/$resolution, $ordered[-1] + $eventtime);
196              
197 0           my $counter = $ordered[0];
198 0           my $point = $first;
199 0           while ($point <= $last) {
200 0           $counter += 1/($resolution);
201 0           $point += 1/($resolution);
202              
203 0           my $prev = getprev($counter, @ordered);
204 0           my %previous = ('time' => $prev,
205             'value' => $$points{$prev},
206             );
207 0           my $next = getnext($counter, @ordered);
208 0           my %next = ('time' => $next,
209             'value' => $$points{$next},
210             );
211 0           my $value = interpolate($counter, \%previous, \%next);
212 0 0         $value *= $scaleto if $scaleto;
213 0           $point = nearest(1/$resolution, $point);
214            
215 0 0         if ($point >= 0) {
216 0           $self->{'function'}{$point} = max($self->{'function'}{$point},
217             $value,
218             $zerooverride
219             );
220             }
221            
222            
223             }
224             }
225              
226             sub interpolate {
227 0     0 0   my ($point, $previous, $next) = @_;
228 0           my $timeratio = ( $point - $$previous{'time'} )
229             / ( $$next{'time'} - $$previous{'time'} );
230 0 0         my $mult = ( $$next{'value'} - $$previous{'value'} ) if $$next{'value'};
231 0 0         $mult = $$previous{'value'} unless $$next{'value'}; #ew
232 0           my $add = ( $$previous{'value'} );
233 0           return $timeratio * $mult + $add;
234             }
235              
236              
237             sub getnext {
238 0     0 0   my ($point, @ordered) = @_;
239 0           foreach my $compare (@ordered) {
240 0 0         return $compare if $compare >= $point;
241             }
242 0           return -99999;
243             }
244              
245             sub getprev {
246 0     0 0   my ($point, @ordered) = @_;
247 0           foreach my $compare (reverse @ordered) {
248 0 0         return $compare if $compare < $point;
249             }
250 0           return -99999;
251             }
252              
253             sub max {
254 0     0 0   my ($first, $second, $zerooverride) = @_;
255 0 0         return 0 if $zerooverride;
256 0 0 0       return 0 if not $first and not $second;
257 0 0         return $second if not $first;
258 0 0         return $first if not $second;
259 0 0         if ($first > $second) {return $first;}
  0            
260 0           return $second;
261             }
262             1;