Chris@147
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@147
|
2
|
Chris@147
|
3 /*
|
Chris@147
|
4 Sonic Visualiser
|
Chris@147
|
5 An audio file viewer and annotation editor.
|
Chris@147
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@147
|
7 This file copyright 2006 Chris Cannam.
|
Chris@147
|
8
|
Chris@147
|
9 This program is free software; you can redistribute it and/or
|
Chris@147
|
10 modify it under the terms of the GNU General Public License as
|
Chris@147
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@147
|
12 License, or (at your option) any later version. See the file
|
Chris@147
|
13 COPYING included with this distribution for more information.
|
Chris@147
|
14 */
|
Chris@147
|
15
|
Chris@147
|
16 #include "PowerOfSqrtTwoZoomConstraint.h"
|
Chris@147
|
17
|
Chris@147
|
18 #include <iostream>
|
Chris@147
|
19 #include <cmath>
|
Chris@147
|
20
|
Chris@147
|
21
|
Chris@1324
|
22 ZoomLevel
|
Chris@1324
|
23 PowerOfSqrtTwoZoomConstraint::getNearestZoomLevel(ZoomLevel requested,
|
Chris@147
|
24 RoundingDirection dir) const
|
Chris@147
|
25 {
|
Chris@147
|
26 int type, power;
|
Chris@1324
|
27 int blockSize;
|
Chris@1324
|
28
|
Chris@1324
|
29 if (requested.zone == ZoomLevel::FramesPerPixel) {
|
Chris@1324
|
30 blockSize = getNearestBlockSize(requested.level, type, power, dir);
|
Chris@1324
|
31 return { requested.zone, blockSize };
|
Chris@1324
|
32 } else {
|
Chris@1324
|
33 RoundingDirection opposite = dir;
|
Chris@1324
|
34 if (dir == RoundUp) opposite = RoundDown;
|
Chris@1324
|
35 else if (dir == RoundDown) opposite = RoundUp;
|
Chris@1324
|
36 blockSize = getNearestBlockSize(requested.level, type, power, opposite);
|
Chris@1324
|
37 if (blockSize > getMinZoomLevel().level) {
|
Chris@1324
|
38 blockSize = getMinZoomLevel().level;
|
Chris@1324
|
39 }
|
Chris@1324
|
40 if (blockSize == 1) {
|
Chris@1324
|
41 return { ZoomLevel::FramesPerPixel, 1 };
|
Chris@1324
|
42 } else {
|
Chris@1324
|
43 return { requested.zone, blockSize };
|
Chris@1324
|
44 }
|
Chris@1324
|
45 }
|
Chris@147
|
46 }
|
Chris@147
|
47
|
Chris@929
|
48 int
|
Chris@929
|
49 PowerOfSqrtTwoZoomConstraint::getNearestBlockSize(int blockSize,
|
Chris@147
|
50 int &type,
|
Chris@147
|
51 int &power,
|
Chris@147
|
52 RoundingDirection dir) const
|
Chris@147
|
53 {
|
Chris@843
|
54 // cerr << "given " << blockSize << endl;
|
Chris@147
|
55
|
Chris@929
|
56 int minCachePower = getMinCachePower();
|
Chris@147
|
57
|
Chris@929
|
58 if (blockSize < (1 << minCachePower)) {
|
Chris@147
|
59 type = -1;
|
Chris@147
|
60 power = 0;
|
Chris@147
|
61 float val = 1.0, prevVal = 1.0;
|
Chris@147
|
62 while (val + 0.01 < blockSize) {
|
Chris@147
|
63 prevVal = val;
|
Chris@1038
|
64 val *= sqrtf(2.f);
|
Chris@147
|
65 }
|
Chris@929
|
66 int rval;
|
Chris@1038
|
67 if (dir == RoundUp) rval = int(val + 0.01f);
|
Chris@1038
|
68 else if (dir == RoundDown) rval = int(prevVal + 0.01f);
|
Chris@1038
|
69 else if (val - float(blockSize) <
|
Chris@1038
|
70 float(blockSize) - prevVal) rval = int(val + 0.01f);
|
Chris@929
|
71 else rval = int(prevVal + 0.01);
|
Chris@690
|
72 // SVDEBUG << "returning " << rval << endl;
|
Chris@147
|
73 return rval;
|
Chris@147
|
74 }
|
Chris@147
|
75
|
Chris@929
|
76 int prevBase = (1 << minCachePower);
|
Chris@929
|
77 int prevPower = minCachePower;
|
Chris@929
|
78 int prevType = 0;
|
Chris@147
|
79
|
Chris@929
|
80 int result = 0;
|
Chris@147
|
81
|
Chris@147
|
82 for (unsigned int i = 0; ; ++i) {
|
Chris@147
|
83
|
Chris@147
|
84 power = minCachePower + i/2;
|
Chris@147
|
85 type = i % 2;
|
Chris@147
|
86
|
Chris@929
|
87 int base;
|
Chris@147
|
88 if (type == 0) {
|
Chris@147
|
89 base = (1 << power);
|
Chris@147
|
90 } else {
|
Chris@608
|
91 base = (((unsigned int)((1 << minCachePower) * sqrt(2.) + 0.01))
|
Chris@147
|
92 << (power - minCachePower));
|
Chris@147
|
93 }
|
Chris@147
|
94
|
Chris@690
|
95 // SVDEBUG << "Testing base " << base << endl;
|
Chris@377
|
96
|
Chris@377
|
97 if (base == blockSize) {
|
Chris@377
|
98 result = base;
|
Chris@377
|
99 break;
|
Chris@377
|
100 }
|
Chris@377
|
101
|
Chris@377
|
102 if (base > blockSize) {
|
Chris@147
|
103 if (dir == RoundNearest) {
|
Chris@147
|
104 if (base - blockSize < blockSize - prevBase) {
|
Chris@147
|
105 dir = RoundUp;
|
Chris@147
|
106 } else {
|
Chris@147
|
107 dir = RoundDown;
|
Chris@147
|
108 }
|
Chris@147
|
109 }
|
Chris@147
|
110 if (dir == RoundUp) {
|
Chris@147
|
111 result = base;
|
Chris@147
|
112 break;
|
Chris@147
|
113 } else {
|
Chris@147
|
114 type = prevType;
|
Chris@147
|
115 power = prevPower;
|
Chris@147
|
116 result = prevBase;
|
Chris@147
|
117 break;
|
Chris@147
|
118 }
|
Chris@147
|
119 }
|
Chris@147
|
120
|
Chris@147
|
121 prevType = type;
|
Chris@147
|
122 prevPower = power;
|
Chris@147
|
123 prevBase = base;
|
Chris@147
|
124 }
|
Chris@147
|
125
|
Chris@1324
|
126 if (result > getMaxZoomLevel().level) {
|
Chris@1324
|
127 result = getMaxZoomLevel().level;
|
Chris@1324
|
128 }
|
Chris@1324
|
129
|
Chris@147
|
130 return result;
|
Chris@147
|
131 }
|