changeset 1324:d4a28d1479a8 zoom

Some hackery toward having a zoomlevel type
author Chris Cannam
date Mon, 12 Dec 2016 15:18:52 +0000
parents 4dbb7a7c9c28
children 710e6250a401
files base/BaseTypes.h base/ZoomConstraint.h data/model/PowerOfSqrtTwoZoomConstraint.cpp data/model/PowerOfSqrtTwoZoomConstraint.h data/model/PowerOfTwoZoomConstraint.cpp data/model/PowerOfTwoZoomConstraint.h data/model/ReadOnlyWaveFileModel.cpp
diffstat 7 files changed, 149 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/base/BaseTypes.h	Fri Dec 09 19:04:33 2016 +0000
+++ b/base/BaseTypes.h	Mon Dec 12 15:18:52 2016 +0000
@@ -12,8 +12,8 @@
     COPYING included with this distribution for more information.
 */
 
-#ifndef BASE_TYPES_H
-#define BASE_TYPES_H
+#ifndef SV_BASE_TYPES_H
+#define SV_BASE_TYPES_H
 
 #include <cstdint>
 
@@ -46,5 +46,57 @@
 */
 typedef double sv_samplerate_t;
 
+
+/** Display zoom level. Can be an integer number of samples per pixel,
+ *  or an integer number of pixels per sample.
+ */
+struct ZoomLevel {
+
+    enum Zone {
+        FramesPerPixel, // zoomed out (as in classic SV)
+        PixelsPerFrame  // zoomed in beyond 1-1 (interpolating the waveform)
+    };
+    Zone zone;
+    int level;
+
+    bool operator<(const ZoomLevel &other) const {
+        if (zone == FramesPerPixel) {
+            if (other.zone == zone) {
+                return level < other.level;
+            } else {
+                return false;
+            }
+        } else {
+            if (other.zone == zone) {
+                return level > other.level;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    ZoomLevel incremented() const {
+        if (zone == FramesPerPixel) {
+            return { zone, level + 1 };
+        } else if (level == 1) {
+            return { FramesPerPixel, 2 };
+        } else if (level == 2) {
+            return { FramesPerPixel, 1 };
+        } else {
+            return { zone, level - 1 };
+        }
+    }
+
+    ZoomLevel decremented() const {
+        if (zone == PixelsPerFrame) {
+            return { zone, level + 1 };
+        } else if (level == 1) {
+            return { PixelsPerFrame, 2 };
+        } else {
+            return { zone, level - 1 };
+        }
+    }
+};
+
 #endif
 
--- a/base/ZoomConstraint.h	Fri Dec 09 19:04:33 2016 +0000
+++ b/base/ZoomConstraint.h	Mon Dec 12 15:18:52 2016 +0000
@@ -13,11 +13,13 @@
     COPYING included with this distribution for more information.
 */
 
-#ifndef _ZOOM_CONSTRAINT_H_
-#define _ZOOM_CONSTRAINT_H_
+#ifndef SV_ZOOM_CONSTRAINT_H
+#define SV_ZOOM_CONSTRAINT_H
 
 #include <stdlib.h>
 
+#include "BaseTypes.h"
+
 /**
  * ZoomConstraint is a simple interface that describes a limitation on
  * the available zoom sizes for a view, for example based on cache
@@ -39,30 +41,42 @@
     };
 
     /**
-     * Given the "ideal" block size (frames per pixel) for a given
-     * zoom level, return the nearest viable block size for this
-     * constraint.
+     * Given an "ideal" zoom level (frames per pixel or pixels per
+     * frame) for a given zoom level, return the nearest viable block
+     * size for this constraint.
      *
      * For example, if a block size of 1523 frames per pixel is
      * requested but the underlying model only supports value
      * summaries at powers-of-two block sizes, return 1024 or 2048
      * depending on the rounding direction supplied.
      */
-    virtual int getNearestBlockSize(int requestedBlockSize,
-				       RoundingDirection = RoundNearest)
+    virtual ZoomLevel getNearestZoomLevel(ZoomLevel requestedZoomLevel,
+                                          RoundingDirection = RoundNearest)
 	const
     {
-	if (requestedBlockSize > getMaxZoomLevel()) return getMaxZoomLevel();
-	else return requestedBlockSize;
+        if (getMaxZoomLevel() < requestedZoomLevel) return getMaxZoomLevel();
+	else return requestedZoomLevel;
     }
 
     /**
+     * Return the minimum zoom level within range for this constraint.
+     * Individual views will probably want to limit this, for example
+     * in order to ensure that at least one or two samples fit in the
+     * current window size, or in order to save on interpolation cost.
+     */
+    virtual ZoomLevel getMinZoomLevel() const {
+        return { ZoomLevel::PixelsPerFrame, 16384 };
+    }
+    
+    /**
      * Return the maximum zoom level within range for this constraint.
      * This is quite large -- individual views will probably want to
      * limit how far a user might reasonably zoom out based on other
      * factors such as the duration of the file.
      */
-    virtual int getMaxZoomLevel() const { return 4194304; } // 2^22, arbitrarily
+    virtual ZoomLevel getMaxZoomLevel() const {
+        return { ZoomLevel::FramesPerPixel, 4194304 }; // 2^22, arbitrarily
+    }
 };
 
 #endif
--- a/data/model/PowerOfSqrtTwoZoomConstraint.cpp	Fri Dec 09 19:04:33 2016 +0000
+++ b/data/model/PowerOfSqrtTwoZoomConstraint.cpp	Mon Dec 12 15:18:52 2016 +0000
@@ -19,13 +19,30 @@
 #include <cmath>
 
 
-int
-PowerOfSqrtTwoZoomConstraint::getNearestBlockSize(int blockSize,
+ZoomLevel
+PowerOfSqrtTwoZoomConstraint::getNearestZoomLevel(ZoomLevel requested,
 						  RoundingDirection dir) const
 {
     int type, power;
-    int rv = getNearestBlockSize(blockSize, type, power, dir);
-    return rv;
+    int blockSize;
+
+    if (requested.zone == ZoomLevel::FramesPerPixel) {
+        blockSize = getNearestBlockSize(requested.level, type, power, dir);
+        return { requested.zone, blockSize };
+    } else {
+        RoundingDirection opposite = dir;
+        if (dir == RoundUp) opposite = RoundDown;
+        else if (dir == RoundDown) opposite = RoundUp;
+        blockSize = getNearestBlockSize(requested.level, type, power, opposite);
+        if (blockSize > getMinZoomLevel().level) {
+            blockSize = getMinZoomLevel().level;
+        }
+        if (blockSize == 1) {
+            return { ZoomLevel::FramesPerPixel, 1 };
+        } else {
+            return { requested.zone, blockSize };
+        }
+    }
 }
 
 int
@@ -106,6 +123,9 @@
 	prevBase = base;
     }
 
-    if (result > getMaxZoomLevel()) result = getMaxZoomLevel();
+    if (result > getMaxZoomLevel().level) {
+        result = getMaxZoomLevel().level;
+    }
+
     return result;
 }   
--- a/data/model/PowerOfSqrtTwoZoomConstraint.h	Fri Dec 09 19:04:33 2016 +0000
+++ b/data/model/PowerOfSqrtTwoZoomConstraint.h	Mon Dec 12 15:18:52 2016 +0000
@@ -21,17 +21,17 @@
 class PowerOfSqrtTwoZoomConstraint : virtual public ZoomConstraint
 {
 public:
-    virtual int getNearestBlockSize(int requestedBlockSize,
-				       RoundingDirection dir = RoundNearest)
-	const;
-    
-    virtual int getNearestBlockSize(int requestedBlockSize,
-				       int &type,
-				       int &power,
-				       RoundingDirection dir = RoundNearest)
-	const;
+    virtual ZoomLevel getNearestZoomLevel(ZoomLevel requested,
+                                          RoundingDirection dir = RoundNearest)
+	const override;
 	
     virtual int getMinCachePower() const { return 6; }
+
+    virtual int getNearestBlockSize(int requestedBlockSize,
+                                    int &type,
+                                    int &power,
+                                    RoundingDirection dir = RoundNearest)
+	const;
 };
 
 #endif
--- a/data/model/PowerOfTwoZoomConstraint.cpp	Fri Dec 09 19:04:33 2016 +0000
+++ b/data/model/PowerOfTwoZoomConstraint.cpp	Mon Dec 12 15:18:52 2016 +0000
@@ -15,6 +15,34 @@
 
 #include "PowerOfTwoZoomConstraint.h"
 
+ZoomLevel
+PowerOfTwoZoomConstraint::getNearestZoomLevel(ZoomLevel requested,
+                                              RoundingDirection dir) const
+{
+    int blockSize;
+
+    if (requested.zone == ZoomLevel::FramesPerPixel) {
+        blockSize = getNearestBlockSize(requested.level, dir);
+        if (blockSize > getMaxZoomLevel().level) {
+            blockSize = getMaxZoomLevel().level;
+        }
+        return { requested.zone, blockSize };
+    } else {
+        RoundingDirection opposite = dir;
+        if (dir == RoundUp) opposite = RoundDown;
+        else if (dir == RoundDown) opposite = RoundUp;
+        blockSize = getNearestBlockSize(requested.level, opposite);
+        if (blockSize > getMinZoomLevel().level) {
+            blockSize = getMinZoomLevel().level;
+        }
+        if (blockSize == 1) {
+            return { ZoomLevel::FramesPerPixel, 1 };
+        } else {
+            return { requested.zone, blockSize };
+        }
+    }
+}
+
 int
 PowerOfTwoZoomConstraint::getNearestBlockSize(int req,
 					      RoundingDirection dir) const
@@ -41,7 +69,7 @@
 	}
     }
 
-    if (result > getMaxZoomLevel()) result = getMaxZoomLevel();
+    if (result > getMaxZoomLevel().level) result = getMaxZoomLevel().level;
     return result;
 }
 
--- a/data/model/PowerOfTwoZoomConstraint.h	Fri Dec 09 19:04:33 2016 +0000
+++ b/data/model/PowerOfTwoZoomConstraint.h	Mon Dec 12 15:18:52 2016 +0000
@@ -21,8 +21,13 @@
 class PowerOfTwoZoomConstraint : virtual public ZoomConstraint
 {
 public:
-    virtual int getNearestBlockSize(int requestedBlockSize,
-				       RoundingDirection dir = RoundNearest)
+    virtual ZoomLevel getNearestZoomLevel(ZoomLevel requested,
+                                          RoundingDirection dir = RoundNearest)
+	const override;
+
+protected:
+    virtual int getNearestBlockSize(int requested,
+                                    RoundingDirection dir = RoundNearest)
 	const;
 };
 
--- a/data/model/ReadOnlyWaveFileModel.cpp	Fri Dec 09 19:04:33 2016 +0000
+++ b/data/model/ReadOnlyWaveFileModel.cpp	Mon Dec 12 15:18:52 2016 +0000
@@ -327,6 +327,7 @@
     int power = m_zoomConstraint.getMinCachePower();
     int roundedBlockSize = m_zoomConstraint.getNearestBlockSize
         (desired, cacheType, power, ZoomConstraint::RoundDown);
+
     if (cacheType != 0 && cacheType != 1) {
         // We will be reading directly from file, so can satisfy any
         // blocksize requirement