changeset 1262:c4f873749ab5 3.0-integration

RealTime fixes to comply with new, more demanding tests; also run same (failing) tests on Vamp SDK version
author Chris Cannam
date Tue, 15 Nov 2016 16:12:48 +0000
parents 968d54d893d2
children abfc498c52bc
files base/RealTimeSV.cpp base/test/TestOurRealTime.h base/test/TestRealTime.h base/test/TestVampRealTime.h base/test/files.pri base/test/svcore-base-test.cpp
diffstat 6 files changed, 877 insertions(+), 441 deletions(-) [+]
line wrap: on
line diff
--- a/base/RealTimeSV.cpp	Mon Nov 14 17:54:22 2016 +0000
+++ b/base/RealTimeSV.cpp	Tue Nov 15 16:12:48 2016 +0000
@@ -449,20 +449,21 @@
 {
     if (frame < 0) return -frame2RealTime_i(-frame, iSampleRate);
 
-    RealTime rt;
-    sv_frame_t sec = frame / iSampleRate;
-    rt.sec = int(sec);
+    int sec = int(frame / iSampleRate);
     frame -= sec * iSampleRate;
-    rt.nsec = (int)(((double(frame) * 1000000.0) / double(iSampleRate)) * 1000.0);
-    return rt;
+    int nsec = int((double(frame) / double(iSampleRate)) * ONE_BILLION + 0.5);
+    // Use ctor here instead of setting data members directly to
+    // ensure nsec > ONE_BILLION is handled properly.  It's extremely
+    // unlikely, but not impossible.
+    return RealTime(sec, nsec);
 }
 
 sv_frame_t
 RealTime::realTime2Frame(const RealTime &time, sv_samplerate_t sampleRate)
 {
     if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
-    double s = time.sec + double(time.nsec + 1) / 1000000000.0;
-    return sv_frame_t(s * sampleRate);
+    double s = time.sec + double(time.nsec) / 1000000000.0;
+    return sv_frame_t(s * sampleRate + 0.5);
 }
 
 RealTime
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base/test/TestOurRealTime.h	Tue Nov 15 16:12:48 2016 +0000
@@ -0,0 +1,473 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef TEST_OUR_REALTIME_H
+#define TEST_OUR_REALTIME_H
+
+#include <QObject>
+#include <QtTest>
+#include <QDir>
+
+#include <iostream>
+
+#include "../RealTime.h"
+
+using namespace std;
+
+#define ONE_MILLION 1000000
+#define ONE_BILLION 1000000000
+
+class TestOurRealTime : public QObject
+{
+    Q_OBJECT
+
+    void compareTexts(string s, const char *e) {
+        QCOMPARE(QString(s.c_str()), QString(e));
+    }
+
+    typedef sv_frame_t frame_type;
+                                 
+private slots:
+
+    void zero()
+    {
+	QCOMPARE(RealTime(0, 0), RealTime::zeroTime);
+	QCOMPARE(RealTime(0, 0).sec, 0);
+	QCOMPARE(RealTime(0, 0).nsec, 0);
+	QCOMPARE(RealTime(0, 0).msec(), 0);
+	QCOMPARE(RealTime(0, 0).usec(), 0);
+    }
+
+    void ctor()
+    {
+	QCOMPARE(RealTime(0, 0), RealTime(0, 0));
+
+	// wraparounds
+	QCOMPARE(RealTime(0, ONE_BILLION/2), RealTime(1, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2), RealTime(-1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(1, ONE_BILLION), RealTime(2, 0));
+	QCOMPARE(RealTime(1, -ONE_BILLION), RealTime(0, 0));
+	QCOMPARE(RealTime(-1, ONE_BILLION), RealTime(0, 0));
+	QCOMPARE(RealTime(-1, -ONE_BILLION), RealTime(-2, 0));
+
+	QCOMPARE(RealTime(2, -ONE_BILLION*2), RealTime(0, 0));
+	QCOMPARE(RealTime(2, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(-2, ONE_BILLION*2), RealTime(0, 0));
+	QCOMPARE(RealTime(-2, ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
+	
+	QCOMPARE(RealTime(0, 1).sec, 0);
+	QCOMPARE(RealTime(0, 1).nsec, 1);
+	QCOMPARE(RealTime(0, -1).sec, 0);
+	QCOMPARE(RealTime(0, -1).nsec, -1);
+	QCOMPARE(RealTime(1, -1).sec, 0);
+	QCOMPARE(RealTime(1, -1).nsec, ONE_BILLION-1);
+	QCOMPARE(RealTime(-1, 1).sec, 0);
+	QCOMPARE(RealTime(-1, 1).nsec, -ONE_BILLION+1);
+	QCOMPARE(RealTime(-1, -1).sec, -1);
+	QCOMPARE(RealTime(-1, -1).nsec, -1);
+	
+	QCOMPARE(RealTime(2, -ONE_BILLION*2).sec, 0);
+	QCOMPARE(RealTime(2, -ONE_BILLION*2).nsec, 0);
+	QCOMPARE(RealTime(2, -ONE_BILLION/2).sec, 1);
+	QCOMPARE(RealTime(2, -ONE_BILLION/2).nsec, ONE_BILLION/2);
+
+	QCOMPARE(RealTime(-2, ONE_BILLION*2).sec, 0);
+	QCOMPARE(RealTime(-2, ONE_BILLION*2).nsec, 0);
+	QCOMPARE(RealTime(-2, ONE_BILLION/2).sec, -1);
+	QCOMPARE(RealTime(-2, ONE_BILLION/2).nsec, -ONE_BILLION/2);
+    }
+    
+    void fromSeconds()
+    {
+	QCOMPARE(RealTime::fromSeconds(0), RealTime(0, 0));
+
+	QCOMPARE(RealTime::fromSeconds(0.5).sec, 0);
+	QCOMPARE(RealTime::fromSeconds(0.5).nsec, ONE_BILLION/2);
+	QCOMPARE(RealTime::fromSeconds(0.5).usec(), ONE_MILLION/2);
+	QCOMPARE(RealTime::fromSeconds(0.5).msec(), 500);
+	
+	QCOMPARE(RealTime::fromSeconds(0.5), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime::fromSeconds(1), RealTime(1, 0));
+	QCOMPARE(RealTime::fromSeconds(1.5), RealTime(1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime::fromSeconds(-0.5).sec, 0);
+	QCOMPARE(RealTime::fromSeconds(-0.5).nsec, -ONE_BILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-0.5).usec(), -ONE_MILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-0.5).msec(), -500);
+	
+	QCOMPARE(RealTime::fromSeconds(-1.5).sec, -1);
+	QCOMPARE(RealTime::fromSeconds(-1.5).nsec, -ONE_BILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-1.5).usec(), -ONE_MILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-1.5).msec(), -500);
+	
+	QCOMPARE(RealTime::fromSeconds(-0.5), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime::fromSeconds(-1), RealTime(-1, 0));
+	QCOMPARE(RealTime::fromSeconds(-1.5), RealTime(-1, -ONE_BILLION/2));
+    }
+
+    void fromMilliseconds()
+    {
+	QCOMPARE(RealTime::fromMilliseconds(0), RealTime(0, 0));
+	QCOMPARE(RealTime::fromMilliseconds(500), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime::fromMilliseconds(1000), RealTime(1, 0));
+	QCOMPARE(RealTime::fromMilliseconds(1500), RealTime(1, ONE_BILLION/2));
+
+    	QCOMPARE(RealTime::fromMilliseconds(-0), RealTime(0, 0));
+	QCOMPARE(RealTime::fromMilliseconds(-500), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime::fromMilliseconds(-1000), RealTime(-1, 0));
+	QCOMPARE(RealTime::fromMilliseconds(-1500), RealTime(-1, -ONE_BILLION/2));
+    }
+    
+    void fromTimeval()
+    {
+	struct timeval tv;
+
+	tv.tv_sec = 0; tv.tv_usec = 0;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, 0));
+	tv.tv_sec = 0; tv.tv_usec = ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, ONE_BILLION/2));
+	tv.tv_sec = 1; tv.tv_usec = 0;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(1, 0));
+	tv.tv_sec = 1; tv.tv_usec = ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(1, ONE_BILLION/2));
+
+	tv.tv_sec = 0; tv.tv_usec = -ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, -ONE_BILLION/2));
+	tv.tv_sec = -1; tv.tv_usec = 0;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(-1, 0));
+	tv.tv_sec = -1; tv.tv_usec = -ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(-1, -ONE_BILLION/2));
+    }
+
+    void fromXsdDuration()
+    {
+	QCOMPARE(RealTime::fromXsdDuration("PT0"), RealTime::zeroTime);
+	QCOMPARE(RealTime::fromXsdDuration("PT0S"), RealTime::zeroTime);
+	QCOMPARE(RealTime::fromXsdDuration("PT10S"), RealTime(10, 0));
+	QCOMPARE(RealTime::fromXsdDuration("PT10.5S"), RealTime(10, ONE_BILLION/2));
+	QCOMPARE(RealTime::fromXsdDuration("PT1.5S").sec, 1);
+	QCOMPARE(RealTime::fromXsdDuration("PT1.5S").msec(), 500);
+	QCOMPARE(RealTime::fromXsdDuration("-PT1.5S").sec, -1);
+	QCOMPARE(RealTime::fromXsdDuration("-PT1.5S").msec(), -500);
+	QCOMPARE(RealTime::fromXsdDuration("PT1M30.5S"), RealTime(90, ONE_BILLION/2));
+	QCOMPARE(RealTime::fromXsdDuration("PT1H2M30.5S"), RealTime(3750, ONE_BILLION/2));
+    }
+
+    void toDouble()
+    {
+	QCOMPARE(RealTime(0, 0).toDouble(), 0.0);
+	QCOMPARE(RealTime(0, ONE_BILLION/2).toDouble(), 0.5);
+	QCOMPARE(RealTime(1, 0).toDouble(), 1.0);
+	QCOMPARE(RealTime(1, ONE_BILLION/2).toDouble(), 1.5);
+
+	QCOMPARE(RealTime(0, -ONE_BILLION/2).toDouble(), -0.5);
+	QCOMPARE(RealTime(-1, 0).toDouble(), -1.0);
+	QCOMPARE(RealTime(-1, -ONE_BILLION/2).toDouble(), -1.5);
+    }
+
+    void assign()
+    {
+	RealTime r;
+	r = RealTime(0, 0);
+	QCOMPARE(r, RealTime::zeroTime);
+	r = RealTime(0, ONE_BILLION/2);
+        QCOMPARE(r.sec, 0);
+        QCOMPARE(r.nsec, ONE_BILLION/2);
+	r = RealTime(-1, -ONE_BILLION/2);
+        QCOMPARE(r.sec, -1);
+        QCOMPARE(r.nsec, -ONE_BILLION/2);
+    }
+
+    void plus()
+    {
+	QCOMPARE(RealTime(0, 0) + RealTime(0, 0), RealTime(0, 0));
+
+	QCOMPARE(RealTime(0, 0) + RealTime(0, ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime(0, ONE_BILLION/2) + RealTime(0, ONE_BILLION/2), RealTime(1, 0));
+	QCOMPARE(RealTime(1, 0) + RealTime(0, ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, 0) + RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(-1, 0));
+	QCOMPARE(RealTime(-1, 0) + RealTime(0, -ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
+
+    	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(0, 0));
+	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, ONE_BILLION/2) + RealTime(-1, 0), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) + RealTime(1, 0), RealTime(0, ONE_BILLION/2));
+    }
+    
+    void minus()
+    {
+	QCOMPARE(RealTime(0, 0) - RealTime(0, 0), RealTime(0, 0));
+
+	QCOMPARE(RealTime(0, 0) - RealTime(0, ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, ONE_BILLION/2) - RealTime(0, ONE_BILLION/2), RealTime(0, 0));
+	QCOMPARE(RealTime(1, 0) - RealTime(0, ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, 0) - RealTime(0, -ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(0, 0));
+	QCOMPARE(RealTime(-1, 0) - RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+
+    	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(2, 0));
+	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(2, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, ONE_BILLION/2) - RealTime(-1, 0), RealTime(1, ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) - RealTime(1, 0), RealTime(-1, -ONE_BILLION/2));
+    }
+
+    void negate()
+    {
+	QCOMPARE(-RealTime(0, 0), RealTime(0, 0));
+	QCOMPARE(-RealTime(1, 0), RealTime(-1, 0));
+	QCOMPARE(-RealTime(1, ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
+	QCOMPARE(-RealTime(-1, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+    }
+
+    void compare()
+    {
+	int sec, nsec;
+	for (sec = -2; sec <= 2; sec += 2) {
+	    for (nsec = -1; nsec <= 1; nsec += 1) {
+		QCOMPARE(RealTime(sec, nsec) < RealTime(sec, nsec), false);
+		QCOMPARE(RealTime(sec, nsec) > RealTime(sec, nsec), false);
+		QCOMPARE(RealTime(sec, nsec) == RealTime(sec, nsec), true);
+		QCOMPARE(RealTime(sec, nsec) != RealTime(sec, nsec), false);
+		QCOMPARE(RealTime(sec, nsec) <= RealTime(sec, nsec), true);
+		QCOMPARE(RealTime(sec, nsec) >= RealTime(sec, nsec), true);
+	    }
+	}
+	RealTime prev(-3, 0);
+	for (sec = -2; sec <= 2; sec += 2) {
+	    for (nsec = -1; nsec <= 1; nsec += 1) {
+
+		RealTime curr(sec, nsec);
+
+		QCOMPARE(prev < curr, true);
+		QCOMPARE(prev > curr, false);
+		QCOMPARE(prev == curr, false);
+		QCOMPARE(prev != curr, true);
+		QCOMPARE(prev <= curr, true);
+		QCOMPARE(prev >= curr, false);
+
+		QCOMPARE(curr < prev, false);
+		QCOMPARE(curr > prev, true);
+		QCOMPARE(curr == prev, false);
+		QCOMPARE(curr != prev, true);
+		QCOMPARE(curr <= prev, false);
+		QCOMPARE(curr >= prev, true);
+
+		prev = curr;
+	    }
+	}
+    }
+
+    void frame()
+    {
+        int frames[] = {
+            0, 1, 2047, 2048, 6656,
+            32767, 32768, 44100, 44101,
+            999999999, 2000000000
+        };
+        int n = sizeof(frames)/sizeof(frames[0]);
+
+        int rates[] = {
+            1, 2, 8000, 22050,
+            44100, 44101, 192000, 2000000001
+        };
+        int m = sizeof(rates)/sizeof(rates[0]);
+
+        vector<vector<RealTime>> realTimes = {
+            { { 0, 0 }, { 1, 0 }, { 2047, 0 }, { 2048, 0 },
+              { 6656, 0 }, { 32767, 0 }, { 32768, 0 }, { 44100, 0 },
+              { 44101, 0 }, { 999999999, 0 }, { 2000000000, 0 } },
+            { { 0, 0 }, { 0, 500000000 }, { 1023, 500000000 }, { 1024, 0 },
+              { 3328, 0 }, { 16383, 500000000 }, { 16384, 0 }, { 22050, 0 },
+              { 22050, 500000000 }, { 499999999, 500000000 }, { 1000000000, 0 } },
+            { { 0, 0 }, { 0, 125000 }, { 0, 255875000 }, { 0, 256000000 },
+              { 0, 832000000 }, { 4, 95875000 }, { 4, 96000000 }, { 5, 512500000 },
+              { 5, 512625000 }, { 124999, 999875000 }, { 250000, 0 } },
+            { { 0, 0 }, { 0, 45351 }, { 0, 92834467 }, { 0, 92879819 },
+              { 0, 301859410 }, { 1, 486031746 }, { 1, 486077098 }, { 2, 0 },
+              { 2, 45351 }, { 45351, 473877551 }, { 90702, 947845805 } },
+            { { 0, 0 }, { 0, 22676 }, { 0, 46417234 }, { 0, 46439909 },
+              { 0, 150929705 }, { 0, 743015873 }, { 0, 743038549 }, { 1, 0 },
+              { 1, 22676 }, { 22675, 736938776 }, { 45351, 473922902 } },
+            { { 0, 0 }, { 0, 22675 }, { 0, 46416181 }, { 0, 46438856 },
+              { 0, 150926283 }, { 0, 742999025 }, { 0, 743021700 }, { 0, 999977325 },
+              { 1, 0 }, { 22675, 222761389 }, { 45350, 445568128 } },
+            { { 0, 0 }, { 0, 5208 }, { 0, 10661458 }, { 0, 10666667 },
+              { 0, 34666667 }, { 0, 170661458 }, { 0, 170666667 }, { 0, 229687500 },
+              { 0, 229692708 }, { 5208, 333328125 }, { 10416, 666666667 } },
+            { { 0, 0 }, { 0, 0 }, { 0, 1023 }, { 0, 1024 },
+              { 0, 3328 }, { 0, 16383 }, { 0, 16384 }, { 0, 22050 },
+              { 0, 22050 }, { 0, 499999999 }, { 1, 0 } }
+        };
+        
+        for (int i = 0; i < n; ++i) {
+            frame_type frame = frames[i];
+            for (int j = 0; j < m; ++j) {
+                int rate = rates[j];
+
+                cerr << "frame = " << frame << ", rate = " << rate << endl;
+                
+                RealTime rt = RealTime::frame2RealTime(frame, rate);
+                QCOMPARE(rt.sec, realTimes[j][i].sec);
+                QCOMPARE(rt.nsec, realTimes[j][i].nsec);
+
+                cerr << "rt = " << rt << endl;
+                cerr << "rate = " << rate << endl;
+
+                frame_type conv = RealTime::realTime2Frame(rt, rate);
+                cerr << "conv = " << conv << endl;
+                
+                rt = RealTime::frame2RealTime(-frame, rate);
+                frame_type negconv = RealTime::realTime2Frame(rt, rate);
+                cerr << "negconv = " << negconv << endl;
+
+                if (rate > ONE_BILLION) {
+                    // We no longer have enough precision in RealTime
+                    // for this absurd sample rate, so a round trip
+                    // conversion may round
+                    QVERIFY(abs(frame - conv) < 2);
+                    QVERIFY(abs(-frame - negconv) < 2);
+                } else {
+                    QCOMPARE(conv, frame);
+                    QCOMPARE(negconv, -frame);
+                }
+            }
+        }
+    }
+
+    // Our own RealTime has toMSText, toFrameText, toSecText
+    
+    void toText()
+    {
+        // we want to use QStrings, because then the Qt test library
+        // will print out any conflicts. The compareTexts function
+        // does this for us
+
+        int halfSec = ONE_BILLION/2; // nsec
+        
+        RealTime rt = RealTime(0, 0);
+        compareTexts(rt.toMSText(false, false), "0");
+        compareTexts(rt.toMSText(true, false), "0.000");
+        compareTexts(rt.toMSText(false, true), "0");
+        compareTexts(rt.toMSText(true, true), "0.000");
+        compareTexts(rt.toFrameText(24, false), "0:00");
+        compareTexts(rt.toFrameText(24, true), "0:00");
+        compareTexts(rt.toSecText(), "0s");
+
+        rt = RealTime(1, halfSec);
+        compareTexts(rt.toMSText(false, false), "1.5");
+        compareTexts(rt.toMSText(true, false), "1.500");
+        compareTexts(rt.toMSText(false, true), "1.5");
+        compareTexts(rt.toMSText(true, true), "1.500");
+        compareTexts(rt.toFrameText(24, false), "1:12");
+        compareTexts(rt.toFrameText(24, true), "1:12");
+        compareTexts(rt.toFrameText(25, false), "1:12");
+        compareTexts(rt.toFrameText(25, true), "1:12");
+        compareTexts(rt.toSecText(), "1s");
+
+        rt = RealTime::fromSeconds(-1.5);
+        compareTexts(rt.toMSText(false, false), "-1.5");
+        compareTexts(rt.toMSText(true, false), "-1.500");
+        compareTexts(rt.toMSText(false, true), "-1.5");
+        compareTexts(rt.toMSText(true, true), "-1.500");
+        compareTexts(rt.toFrameText(24, false), "-1:12");
+        compareTexts(rt.toFrameText(24, true), "-1:12");
+        compareTexts(rt.toSecText(), "-1s");
+
+        rt = RealTime(1, 1000);
+        compareTexts(rt.toMSText(false, false), "1");
+        compareTexts(rt.toFrameText(24, false), "1:00");
+        compareTexts(rt.toFrameText(ONE_MILLION, false), "1:000001");
+        compareTexts(rt.toSecText(), "1s");
+
+        rt = RealTime(1, 100000);
+        compareTexts(rt.toFrameText(ONE_MILLION, false), "1:000100");
+        compareTexts(rt.toSecText(), "1s");
+
+        rt = RealTime::fromSeconds(60);
+        compareTexts(rt.toMSText(false, false), "60");
+        compareTexts(rt.toMSText(true, false), "60.000");
+        compareTexts(rt.toMSText(false, true), "1:00");
+        compareTexts(rt.toMSText(true, true), "1:00.000");
+        compareTexts(rt.toFrameText(24, false), "60:00");
+        compareTexts(rt.toFrameText(24, true), "1:00:00");
+        compareTexts(rt.toSecText(), "1:00");
+
+        rt = RealTime::fromSeconds(61.05);
+        compareTexts(rt.toMSText(false, false), "61.05");
+        compareTexts(rt.toMSText(true, false), "61.050");
+        compareTexts(rt.toMSText(false, true), "1:01.05");
+        compareTexts(rt.toMSText(true, true), "1:01.050");
+        compareTexts(rt.toFrameText(24, false), "61:01");
+        compareTexts(rt.toFrameText(24, true), "1:01:01");
+        compareTexts(rt.toSecText(), "1:01");
+        
+        rt = RealTime::fromSeconds(601.05);
+        compareTexts(rt.toMSText(false, false), "601.05");
+        compareTexts(rt.toMSText(true, false), "601.050");
+        compareTexts(rt.toMSText(false, true), "10:01.05");
+        compareTexts(rt.toMSText(true, true), "10:01.050");
+        compareTexts(rt.toFrameText(24, false), "601:01");
+        compareTexts(rt.toFrameText(24, true), "10:01:01");
+        compareTexts(rt.toSecText(), "10:01");
+        
+        rt = RealTime::fromSeconds(3600);
+        compareTexts(rt.toMSText(false, false), "3600");
+        compareTexts(rt.toMSText(true, false), "3600.000");
+        compareTexts(rt.toMSText(false, true), "1:00:00");
+        compareTexts(rt.toMSText(true, true), "1:00:00.000");
+        compareTexts(rt.toFrameText(24, false), "3600:00");
+        compareTexts(rt.toFrameText(24, true), "1:00:00:00");
+        compareTexts(rt.toSecText(), "1:00:00");
+
+        // For practical reasons our time display always rounds down
+        rt = RealTime(3599, ONE_BILLION-1);
+        compareTexts(rt.toMSText(false, false), "3599.999");
+        compareTexts(rt.toMSText(true, false), "3599.999");
+        compareTexts(rt.toMSText(false, true), "59:59.999");
+        compareTexts(rt.toMSText(true, true), "59:59.999");
+        compareTexts(rt.toFrameText(24, false), "3599:23");
+        compareTexts(rt.toFrameText(24, true), "59:59:23");
+        compareTexts(rt.toSecText(), "59:59");
+
+        rt = RealTime::fromSeconds(3600 * 4 + 60 * 5 + 3 + 0.01);
+        compareTexts(rt.toMSText(false, false), "14703.01");
+        compareTexts(rt.toMSText(true, false), "14703.010");
+        compareTexts(rt.toMSText(false, true), "4:05:03.01");
+        compareTexts(rt.toMSText(true, true), "4:05:03.010");
+        compareTexts(rt.toFrameText(24, false), "14703:00");
+        compareTexts(rt.toFrameText(24, true), "4:05:03:00");
+        compareTexts(rt.toSecText(), "4:05:03");
+
+        rt = RealTime::fromSeconds(-(3600 * 4 + 60 * 5 + 3 + 0.01));
+        compareTexts(rt.toMSText(false, false), "-14703.01");
+        compareTexts(rt.toMSText(true, false), "-14703.010");
+        compareTexts(rt.toMSText(false, true), "-4:05:03.01");
+        compareTexts(rt.toMSText(true, true), "-4:05:03.010");
+        compareTexts(rt.toFrameText(24, false), "-14703:00");
+        compareTexts(rt.toFrameText(24, true), "-4:05:03:00");
+        compareTexts(rt.toSecText(), "-4:05:03");
+    }
+};
+
+#endif
+
--- a/base/test/TestRealTime.h	Mon Nov 14 17:54:22 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,431 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/*
-    Sonic Visualiser
-    An audio file viewer and annotation editor.
-    Centre for Digital Music, Queen Mary, University of London.
-    
-    This program is free software; you can redistribute it and/or
-    modify it under the terms of the GNU General Public License as
-    published by the Free Software Foundation; either version 2 of the
-    License, or (at your option) any later version.  See the file
-    COPYING included with this distribution for more information.
-*/
-
-#ifndef TEST_REALTIME_H
-#define TEST_REALTIME_H
-
-#include "../RealTime.h"
-
-#include <QObject>
-#include <QtTest>
-#include <QDir>
-
-#include <iostream>
-
-using namespace std;
-
-class TestRealTime : public QObject
-{
-    Q_OBJECT
-
-    void compareTexts(string s, const char *e) {
-        QCOMPARE(QString(s.c_str()), QString(e));
-    }
-
-private slots:
-
-#define ONE_MILLION 1000000
-#define ONE_BILLION 1000000000
-    
-    void zero()
-    {
-	QCOMPARE(RealTime(0, 0), RealTime::zeroTime);
-	QCOMPARE(RealTime(0, 0).sec, 0);
-	QCOMPARE(RealTime(0, 0).nsec, 0);
-	QCOMPARE(RealTime(0, 0).msec(), 0);
-	QCOMPARE(RealTime(0, 0).usec(), 0);
-    }
-
-    void ctor()
-    {
-	QCOMPARE(RealTime(0, 0), RealTime(0, 0));
-
-	// wraparounds
-	QCOMPARE(RealTime(0, ONE_BILLION/2), RealTime(1, -ONE_BILLION/2));
-	QCOMPARE(RealTime(0, -ONE_BILLION/2), RealTime(-1, ONE_BILLION/2));
-
-	QCOMPARE(RealTime(1, ONE_BILLION), RealTime(2, 0));
-	QCOMPARE(RealTime(1, -ONE_BILLION), RealTime(0, 0));
-	QCOMPARE(RealTime(-1, ONE_BILLION), RealTime(0, 0));
-	QCOMPARE(RealTime(-1, -ONE_BILLION), RealTime(-2, 0));
-
-	QCOMPARE(RealTime(2, -ONE_BILLION*2), RealTime(0, 0));
-	QCOMPARE(RealTime(2, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
-
-	QCOMPARE(RealTime(-2, ONE_BILLION*2), RealTime(0, 0));
-	QCOMPARE(RealTime(-2, ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
-	
-	QCOMPARE(RealTime(0, 1).sec, 0);
-	QCOMPARE(RealTime(0, 1).nsec, 1);
-	QCOMPARE(RealTime(0, -1).sec, 0);
-	QCOMPARE(RealTime(0, -1).nsec, -1);
-	QCOMPARE(RealTime(1, -1).sec, 0);
-	QCOMPARE(RealTime(1, -1).nsec, ONE_BILLION-1);
-	QCOMPARE(RealTime(-1, 1).sec, 0);
-	QCOMPARE(RealTime(-1, 1).nsec, -ONE_BILLION+1);
-	QCOMPARE(RealTime(-1, -1).sec, -1);
-	QCOMPARE(RealTime(-1, -1).nsec, -1);
-	
-	QCOMPARE(RealTime(2, -ONE_BILLION*2).sec, 0);
-	QCOMPARE(RealTime(2, -ONE_BILLION*2).nsec, 0);
-	QCOMPARE(RealTime(2, -ONE_BILLION/2).sec, 1);
-	QCOMPARE(RealTime(2, -ONE_BILLION/2).nsec, ONE_BILLION/2);
-
-	QCOMPARE(RealTime(-2, ONE_BILLION*2).sec, 0);
-	QCOMPARE(RealTime(-2, ONE_BILLION*2).nsec, 0);
-	QCOMPARE(RealTime(-2, ONE_BILLION/2).sec, -1);
-	QCOMPARE(RealTime(-2, ONE_BILLION/2).nsec, -ONE_BILLION/2);
-    }
-    
-    void fromSeconds()
-    {
-	QCOMPARE(RealTime::fromSeconds(0), RealTime(0, 0));
-
-	QCOMPARE(RealTime::fromSeconds(0.5).sec, 0);
-	QCOMPARE(RealTime::fromSeconds(0.5).nsec, ONE_BILLION/2);
-	QCOMPARE(RealTime::fromSeconds(0.5).usec(), ONE_MILLION/2);
-	QCOMPARE(RealTime::fromSeconds(0.5).msec(), 500);
-	
-	QCOMPARE(RealTime::fromSeconds(0.5), RealTime(0, ONE_BILLION/2));
-	QCOMPARE(RealTime::fromSeconds(1), RealTime(1, 0));
-	QCOMPARE(RealTime::fromSeconds(1.5), RealTime(1, ONE_BILLION/2));
-
-	QCOMPARE(RealTime::fromSeconds(-0.5).sec, 0);
-	QCOMPARE(RealTime::fromSeconds(-0.5).nsec, -ONE_BILLION/2);
-	QCOMPARE(RealTime::fromSeconds(-0.5).usec(), -ONE_MILLION/2);
-	QCOMPARE(RealTime::fromSeconds(-0.5).msec(), -500);
-	
-	QCOMPARE(RealTime::fromSeconds(-1.5).sec, -1);
-	QCOMPARE(RealTime::fromSeconds(-1.5).nsec, -ONE_BILLION/2);
-	QCOMPARE(RealTime::fromSeconds(-1.5).usec(), -ONE_MILLION/2);
-	QCOMPARE(RealTime::fromSeconds(-1.5).msec(), -500);
-	
-	QCOMPARE(RealTime::fromSeconds(-0.5), RealTime(0, -ONE_BILLION/2));
-	QCOMPARE(RealTime::fromSeconds(-1), RealTime(-1, 0));
-	QCOMPARE(RealTime::fromSeconds(-1.5), RealTime(-1, -ONE_BILLION/2));
-    }
-
-    void fromMilliseconds()
-    {
-	QCOMPARE(RealTime::fromMilliseconds(0), RealTime(0, 0));
-	QCOMPARE(RealTime::fromMilliseconds(500), RealTime(0, ONE_BILLION/2));
-	QCOMPARE(RealTime::fromMilliseconds(1000), RealTime(1, 0));
-	QCOMPARE(RealTime::fromMilliseconds(1500), RealTime(1, ONE_BILLION/2));
-
-    	QCOMPARE(RealTime::fromMilliseconds(-0), RealTime(0, 0));
-	QCOMPARE(RealTime::fromMilliseconds(-500), RealTime(0, -ONE_BILLION/2));
-	QCOMPARE(RealTime::fromMilliseconds(-1000), RealTime(-1, 0));
-	QCOMPARE(RealTime::fromMilliseconds(-1500), RealTime(-1, -ONE_BILLION/2));
-    }
-    
-    void fromTimeval()
-    {
-	struct timeval tv;
-
-	tv.tv_sec = 0; tv.tv_usec = 0;
-	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, 0));
-	tv.tv_sec = 0; tv.tv_usec = ONE_MILLION/2;
-	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, ONE_BILLION/2));
-	tv.tv_sec = 1; tv.tv_usec = 0;
-	QCOMPARE(RealTime::fromTimeval(tv), RealTime(1, 0));
-	tv.tv_sec = 1; tv.tv_usec = ONE_MILLION/2;
-	QCOMPARE(RealTime::fromTimeval(tv), RealTime(1, ONE_BILLION/2));
-
-	tv.tv_sec = 0; tv.tv_usec = -ONE_MILLION/2;
-	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, -ONE_BILLION/2));
-	tv.tv_sec = -1; tv.tv_usec = 0;
-	QCOMPARE(RealTime::fromTimeval(tv), RealTime(-1, 0));
-	tv.tv_sec = -1; tv.tv_usec = -ONE_MILLION/2;
-	QCOMPARE(RealTime::fromTimeval(tv), RealTime(-1, -ONE_BILLION/2));
-    }
-
-    void fromXsdDuration()
-    {
-	QCOMPARE(RealTime::fromXsdDuration("PT0"), RealTime::zeroTime);
-	QCOMPARE(RealTime::fromXsdDuration("PT0S"), RealTime::zeroTime);
-	QCOMPARE(RealTime::fromXsdDuration("PT10S"), RealTime(10, 0));
-	QCOMPARE(RealTime::fromXsdDuration("PT10.5S"), RealTime(10, ONE_BILLION/2));
-	QCOMPARE(RealTime::fromXsdDuration("PT1.5S").sec, 1);
-	QCOMPARE(RealTime::fromXsdDuration("PT1.5S").msec(), 500);
-	QCOMPARE(RealTime::fromXsdDuration("-PT1.5S").sec, -1);
-	QCOMPARE(RealTime::fromXsdDuration("-PT1.5S").msec(), -500);
-	QCOMPARE(RealTime::fromXsdDuration("PT1M30.5S"), RealTime(90, ONE_BILLION/2));
-	QCOMPARE(RealTime::fromXsdDuration("PT1H2M30.5S"), RealTime(3750, ONE_BILLION/2));
-    }
-
-    void toDouble()
-    {
-	QCOMPARE(RealTime(0, 0).toDouble(), 0.0);
-	QCOMPARE(RealTime(0, ONE_BILLION/2).toDouble(), 0.5);
-	QCOMPARE(RealTime(1, 0).toDouble(), 1.0);
-	QCOMPARE(RealTime(1, ONE_BILLION/2).toDouble(), 1.5);
-
-	QCOMPARE(RealTime(0, -ONE_BILLION/2).toDouble(), -0.5);
-	QCOMPARE(RealTime(-1, 0).toDouble(), -1.0);
-	QCOMPARE(RealTime(-1, -ONE_BILLION/2).toDouble(), -1.5);
-    }
-
-    void assign()
-    {
-	RealTime r;
-	r = RealTime(0, 0);
-	QCOMPARE(r, RealTime::zeroTime);
-	r = RealTime(0, ONE_BILLION/2);
-	QCOMPARE(r.toDouble(), 0.5);
-	r = RealTime(-1, -ONE_BILLION/2);
-	QCOMPARE(r.toDouble(), -1.5);
-    }
-
-    void plus()
-    {
-	QCOMPARE(RealTime(0, 0) + RealTime(0, 0), RealTime(0, 0));
-
-	QCOMPARE(RealTime(0, 0) + RealTime(0, ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
-	QCOMPARE(RealTime(0, ONE_BILLION/2) + RealTime(0, ONE_BILLION/2), RealTime(1, 0));
-	QCOMPARE(RealTime(1, 0) + RealTime(0, ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
-
-	QCOMPARE(RealTime(0, 0) + RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
-	QCOMPARE(RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(-1, 0));
-	QCOMPARE(RealTime(-1, 0) + RealTime(0, -ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
-
-    	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
-	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(0, 0));
-	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
-
-	QCOMPARE(RealTime(0, ONE_BILLION/2) + RealTime(-1, 0), RealTime(0, -ONE_BILLION/2));
-	QCOMPARE(RealTime(0, -ONE_BILLION/2) + RealTime(1, 0), RealTime(0, ONE_BILLION/2));
-    }
-    
-    void minus()
-    {
-	QCOMPARE(RealTime(0, 0) - RealTime(0, 0), RealTime(0, 0));
-
-	QCOMPARE(RealTime(0, 0) - RealTime(0, ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
-	QCOMPARE(RealTime(0, ONE_BILLION/2) - RealTime(0, ONE_BILLION/2), RealTime(0, 0));
-	QCOMPARE(RealTime(1, 0) - RealTime(0, ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
-
-	QCOMPARE(RealTime(0, 0) - RealTime(0, -ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
-	QCOMPARE(RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(0, 0));
-	QCOMPARE(RealTime(-1, 0) - RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
-
-    	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
-	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(2, 0));
-	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(2, ONE_BILLION/2));
-
-	QCOMPARE(RealTime(0, ONE_BILLION/2) - RealTime(-1, 0), RealTime(1, ONE_BILLION/2));
-	QCOMPARE(RealTime(0, -ONE_BILLION/2) - RealTime(1, 0), RealTime(-1, -ONE_BILLION/2));
-    }
-
-    void negate()
-    {
-	QCOMPARE(-RealTime(0, 0), RealTime(0, 0));
-	QCOMPARE(-RealTime(1, 0), RealTime(-1, 0));
-	QCOMPARE(-RealTime(1, ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
-	QCOMPARE(-RealTime(-1, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
-    }
-
-    void compare()
-    {
-	int sec, nsec;
-	for (sec = -2; sec <= 2; sec += 2) {
-	    for (nsec = -1; nsec <= 1; nsec += 1) {
-		QCOMPARE(RealTime(sec, nsec) < RealTime(sec, nsec), false);
-		QCOMPARE(RealTime(sec, nsec) > RealTime(sec, nsec), false);
-		QCOMPARE(RealTime(sec, nsec) == RealTime(sec, nsec), true);
-		QCOMPARE(RealTime(sec, nsec) != RealTime(sec, nsec), false);
-		QCOMPARE(RealTime(sec, nsec) <= RealTime(sec, nsec), true);
-		QCOMPARE(RealTime(sec, nsec) >= RealTime(sec, nsec), true);
-	    }
-	}
-	RealTime prev(-3, 0);
-	for (sec = -2; sec <= 2; sec += 2) {
-	    for (nsec = -1; nsec <= 1; nsec += 1) {
-
-		RealTime curr(sec, nsec);
-
-		QCOMPARE(prev < curr, true);
-		QCOMPARE(prev > curr, false);
-		QCOMPARE(prev == curr, false);
-		QCOMPARE(prev != curr, true);
-		QCOMPARE(prev <= curr, true);
-		QCOMPARE(prev >= curr, false);
-
-		QCOMPARE(curr < prev, false);
-		QCOMPARE(curr > prev, true);
-		QCOMPARE(curr == prev, false);
-		QCOMPARE(curr != prev, true);
-		QCOMPARE(curr <= prev, false);
-		QCOMPARE(curr >= prev, true);
-
-		prev = curr;
-	    }
-	}
-    }
-
-    void frame()
-    {
-        int frames[] = {
-            0, 1, 2047, 2048, 6656,
-            32767, 32768, 44100, 44101, 999999999
-        };
-        int n = sizeof(frames)/sizeof(frames[0]);
-
-        int rates[] = {
-            1, 2, 8000, 22050, 44100, 44101, 192000
-        };
-        int m = sizeof(rates)/sizeof(rates[0]);
-
-        vector<vector<RealTime>> realTimes = {
-            { { 0, 0 }, { 1, 0 }, { 2047, 0 }, { 2048, 0 }, { 6656, 0 }, { 32767, 0 }, { 32768, 0 }, { 44100, 0 }, { 44101, 0 }, { 999999999, 0 } },
-            { { 0, 0 }, { 0, 500000000 }, { 1023, 500000000 }, { 1024, 0 }, { 3328, 0 }, { 16383, 500000000 }, { 16384, 0 }, { 22050, 0 }, { 22050, 500000000 }, { 499999999, 500000000 } },
-            { { 0, 0 }, { 0, 125000 }, { 0, 255875000 }, { 0, 256000000 }, { 0, 832000000 }, { 4, 95875000 }, { 4, 96000000 }, { 5, 512500000 }, { 5, 512625000 }, { 124999, 999875000 } },
-            { { 0, 0 }, { 0, 45351 }, { 0, 92834467 }, { 0, 92879819 }, { 0, 301859410 }, { 1, 486031746 }, { 1, 486077098 }, { 2, 0 }, { 2, 45351 }, { 45351, 473877551 } },
-            { { 0, 0 }, { 0, 22676 }, { 0, 46417234 }, { 0, 46439909 }, { 0, 150929705 }, { 0, 743015873 }, { 0, 743038549 }, { 1, 0 }, { 1, 22676 }, { 22675, 736938776 } },
-            { { 0, 0 }, { 0, 22675 }, { 0, 46416181 }, { 0, 46438856 }, { 0, 150926283 }, { 0, 742999025 }, { 0, 743021700 }, { 0, 999977325 }, { 1, 0 }, { 22675, 222761389 } },
-            { { 0, 0 }, { 0, 5208 }, { 0, 10661458 }, { 0, 10666667 }, { 0, 34666667 }, { 0, 170661458 }, { 0, 170666667 }, { 0, 229687500 }, { 0, 229692708 }, { 5208, 333328125 } },
-        };
-        
-        for (int i = 0; i < n; ++i) {
-            sv_frame_t frame = frames[i];
-            for (int j = 0; j < m; ++j) {
-                int rate = rates[j];
-
-                RealTime rt = RealTime::frame2RealTime(frame, rate);
-                QCOMPARE(rt.sec, realTimes[j][i].sec);
-                QCOMPARE(rt.nsec, realTimes[j][i].nsec);
-
-                sv_frame_t conv = RealTime::realTime2Frame(rt, rate);
-                QCOMPARE(frame, conv);
-
-                rt = RealTime::frame2RealTime(-frame, rate);
-                conv = RealTime::realTime2Frame(rt, rate);
-                QCOMPARE(-frame, conv);
-            }
-        }
-    }
-    
-    void toText()
-    {
-        // we want to use QStrings, because then the Qt test library
-        // will print out any conflicts. The compareTexts function
-        // does this for us
-
-        int halfSec = ONE_BILLION/2; // nsec
-        
-        RealTime rt = RealTime(0, 0);
-        compareTexts(rt.toMSText(false, false), "0");
-        compareTexts(rt.toMSText(true, false), "0.000");
-        compareTexts(rt.toMSText(false, true), "0");
-        compareTexts(rt.toMSText(true, true), "0.000");
-        compareTexts(rt.toFrameText(24, false), "0:00");
-        compareTexts(rt.toFrameText(24, true), "0:00");
-        compareTexts(rt.toSecText(), "0s");
-
-        rt = RealTime(1, halfSec);
-        compareTexts(rt.toMSText(false, false), "1.5");
-        compareTexts(rt.toMSText(true, false), "1.500");
-        compareTexts(rt.toMSText(false, true), "1.5");
-        compareTexts(rt.toMSText(true, true), "1.500");
-        compareTexts(rt.toFrameText(24, false), "1:12");
-        compareTexts(rt.toFrameText(24, true), "1:12");
-        compareTexts(rt.toFrameText(25, false), "1:12");
-        compareTexts(rt.toFrameText(25, true), "1:12");
-        compareTexts(rt.toSecText(), "1s");
-
-        rt = RealTime::fromSeconds(-1.5);
-        compareTexts(rt.toMSText(false, false), "-1.5");
-        compareTexts(rt.toMSText(true, false), "-1.500");
-        compareTexts(rt.toMSText(false, true), "-1.5");
-        compareTexts(rt.toMSText(true, true), "-1.500");
-        compareTexts(rt.toFrameText(24, false), "-1:12");
-        compareTexts(rt.toFrameText(24, true), "-1:12");
-        compareTexts(rt.toSecText(), "-1s");
-
-        rt = RealTime(1, 1000);
-        compareTexts(rt.toMSText(false, false), "1");
-        compareTexts(rt.toFrameText(24, false), "1:00");
-        compareTexts(rt.toFrameText(ONE_MILLION, false), "1:000001");
-        compareTexts(rt.toSecText(), "1s");
-
-        rt = RealTime(1, 100000);
-        compareTexts(rt.toFrameText(ONE_MILLION, false), "1:000100");
-        compareTexts(rt.toSecText(), "1s");
-
-        rt = RealTime::fromSeconds(60);
-        compareTexts(rt.toMSText(false, false), "60");
-        compareTexts(rt.toMSText(true, false), "60.000");
-        compareTexts(rt.toMSText(false, true), "1:00");
-        compareTexts(rt.toMSText(true, true), "1:00.000");
-        compareTexts(rt.toFrameText(24, false), "60:00");
-        compareTexts(rt.toFrameText(24, true), "1:00:00");
-        compareTexts(rt.toSecText(), "1:00");
-
-        rt = RealTime::fromSeconds(61.05);
-        compareTexts(rt.toMSText(false, false), "61.05");
-        compareTexts(rt.toMSText(true, false), "61.050");
-        compareTexts(rt.toMSText(false, true), "1:01.05");
-        compareTexts(rt.toMSText(true, true), "1:01.050");
-        compareTexts(rt.toFrameText(24, false), "61:01");
-        compareTexts(rt.toFrameText(24, true), "1:01:01");
-        compareTexts(rt.toSecText(), "1:01");
-        
-        rt = RealTime::fromSeconds(601.05);
-        compareTexts(rt.toMSText(false, false), "601.05");
-        compareTexts(rt.toMSText(true, false), "601.050");
-        compareTexts(rt.toMSText(false, true), "10:01.05");
-        compareTexts(rt.toMSText(true, true), "10:01.050");
-        compareTexts(rt.toFrameText(24, false), "601:01");
-        compareTexts(rt.toFrameText(24, true), "10:01:01");
-        compareTexts(rt.toSecText(), "10:01");
-        
-        rt = RealTime::fromSeconds(3600);
-        compareTexts(rt.toMSText(false, false), "3600");
-        compareTexts(rt.toMSText(true, false), "3600.000");
-        compareTexts(rt.toMSText(false, true), "1:00:00");
-        compareTexts(rt.toMSText(true, true), "1:00:00.000");
-        compareTexts(rt.toFrameText(24, false), "3600:00");
-        compareTexts(rt.toFrameText(24, true), "1:00:00:00");
-        compareTexts(rt.toSecText(), "1:00:00");
-
-        // For practical reasons our time display always rounds down
-        rt = RealTime(3599, ONE_BILLION-1);
-        compareTexts(rt.toMSText(false, false), "3599.999");
-        compareTexts(rt.toMSText(true, false), "3599.999");
-        compareTexts(rt.toMSText(false, true), "59:59.999");
-        compareTexts(rt.toMSText(true, true), "59:59.999");
-        compareTexts(rt.toFrameText(24, false), "3599:23");
-        compareTexts(rt.toFrameText(24, true), "59:59:23");
-        compareTexts(rt.toSecText(), "59:59");
-
-        rt = RealTime::fromSeconds(3600 * 4 + 60 * 5 + 3 + 0.01);
-        compareTexts(rt.toMSText(false, false), "14703.01");
-        compareTexts(rt.toMSText(true, false), "14703.010");
-        compareTexts(rt.toMSText(false, true), "4:05:03.01");
-        compareTexts(rt.toMSText(true, true), "4:05:03.010");
-        compareTexts(rt.toFrameText(24, false), "14703:00");
-        compareTexts(rt.toFrameText(24, true), "4:05:03:00");
-        compareTexts(rt.toSecText(), "4:05:03");
-
-        rt = RealTime::fromSeconds(-(3600 * 4 + 60 * 5 + 3 + 0.01));
-        compareTexts(rt.toMSText(false, false), "-14703.01");
-        compareTexts(rt.toMSText(true, false), "-14703.010");
-        compareTexts(rt.toMSText(false, true), "-4:05:03.01");
-        compareTexts(rt.toMSText(true, true), "-4:05:03.010");
-        compareTexts(rt.toFrameText(24, false), "-14703:00");
-        compareTexts(rt.toFrameText(24, true), "-4:05:03:00");
-        compareTexts(rt.toSecText(), "-4:05:03");
-    }
-};
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base/test/TestVampRealTime.h	Tue Nov 15 16:12:48 2016 +0000
@@ -0,0 +1,386 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef TEST_VAMP_REALTIME_H
+
+#include <QObject>
+#include <QtTest>
+#include <QDir>
+
+#include <iostream>
+
+#include <vamp-hostsdk/RealTime.h>
+
+using namespace std;
+
+#define ONE_MILLION 1000000
+#define ONE_BILLION 1000000000
+
+class TestVampRealTime : public QObject
+{
+    Q_OBJECT
+
+    void compareTexts(string s, const char *e) {
+        QCOMPARE(QString(s.c_str()), QString(e));
+    }
+
+    typedef Vamp::RealTime RealTime;
+    typedef long frame_type;
+			   
+private slots:
+
+    void zero()
+    {
+	QCOMPARE(RealTime(0, 0), RealTime::zeroTime);
+	QCOMPARE(RealTime(0, 0).sec, 0);
+	QCOMPARE(RealTime(0, 0).nsec, 0);
+	QCOMPARE(RealTime(0, 0).msec(), 0);
+	QCOMPARE(RealTime(0, 0).usec(), 0);
+    }
+
+    void ctor()
+    {
+	QCOMPARE(RealTime(0, 0), RealTime(0, 0));
+
+	// wraparounds
+	QCOMPARE(RealTime(0, ONE_BILLION/2), RealTime(1, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2), RealTime(-1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(1, ONE_BILLION), RealTime(2, 0));
+	QCOMPARE(RealTime(1, -ONE_BILLION), RealTime(0, 0));
+	QCOMPARE(RealTime(-1, ONE_BILLION), RealTime(0, 0));
+	QCOMPARE(RealTime(-1, -ONE_BILLION), RealTime(-2, 0));
+
+	QCOMPARE(RealTime(2, -ONE_BILLION*2), RealTime(0, 0));
+	QCOMPARE(RealTime(2, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(-2, ONE_BILLION*2), RealTime(0, 0));
+	QCOMPARE(RealTime(-2, ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
+	
+	QCOMPARE(RealTime(0, 1).sec, 0);
+	QCOMPARE(RealTime(0, 1).nsec, 1);
+	QCOMPARE(RealTime(0, -1).sec, 0);
+	QCOMPARE(RealTime(0, -1).nsec, -1);
+	QCOMPARE(RealTime(1, -1).sec, 0);
+	QCOMPARE(RealTime(1, -1).nsec, ONE_BILLION-1);
+	QCOMPARE(RealTime(-1, 1).sec, 0);
+	QCOMPARE(RealTime(-1, 1).nsec, -ONE_BILLION+1);
+	QCOMPARE(RealTime(-1, -1).sec, -1);
+	QCOMPARE(RealTime(-1, -1).nsec, -1);
+	
+	QCOMPARE(RealTime(2, -ONE_BILLION*2).sec, 0);
+	QCOMPARE(RealTime(2, -ONE_BILLION*2).nsec, 0);
+	QCOMPARE(RealTime(2, -ONE_BILLION/2).sec, 1);
+	QCOMPARE(RealTime(2, -ONE_BILLION/2).nsec, ONE_BILLION/2);
+
+	QCOMPARE(RealTime(-2, ONE_BILLION*2).sec, 0);
+	QCOMPARE(RealTime(-2, ONE_BILLION*2).nsec, 0);
+	QCOMPARE(RealTime(-2, ONE_BILLION/2).sec, -1);
+	QCOMPARE(RealTime(-2, ONE_BILLION/2).nsec, -ONE_BILLION/2);
+    }
+    
+    void fromSeconds()
+    {
+	QCOMPARE(RealTime::fromSeconds(0), RealTime(0, 0));
+
+	QCOMPARE(RealTime::fromSeconds(0.5).sec, 0);
+	QCOMPARE(RealTime::fromSeconds(0.5).nsec, ONE_BILLION/2);
+	QCOMPARE(RealTime::fromSeconds(0.5).usec(), ONE_MILLION/2);
+	QCOMPARE(RealTime::fromSeconds(0.5).msec(), 500);
+	
+	QCOMPARE(RealTime::fromSeconds(0.5), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime::fromSeconds(1), RealTime(1, 0));
+	QCOMPARE(RealTime::fromSeconds(1.5), RealTime(1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime::fromSeconds(-0.5).sec, 0);
+	QCOMPARE(RealTime::fromSeconds(-0.5).nsec, -ONE_BILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-0.5).usec(), -ONE_MILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-0.5).msec(), -500);
+	
+	QCOMPARE(RealTime::fromSeconds(-1.5).sec, -1);
+	QCOMPARE(RealTime::fromSeconds(-1.5).nsec, -ONE_BILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-1.5).usec(), -ONE_MILLION/2);
+	QCOMPARE(RealTime::fromSeconds(-1.5).msec(), -500);
+	
+	QCOMPARE(RealTime::fromSeconds(-0.5), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime::fromSeconds(-1), RealTime(-1, 0));
+	QCOMPARE(RealTime::fromSeconds(-1.5), RealTime(-1, -ONE_BILLION/2));
+    }
+
+    void fromMilliseconds()
+    {
+	QCOMPARE(RealTime::fromMilliseconds(0), RealTime(0, 0));
+	QCOMPARE(RealTime::fromMilliseconds(500), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime::fromMilliseconds(1000), RealTime(1, 0));
+	QCOMPARE(RealTime::fromMilliseconds(1500), RealTime(1, ONE_BILLION/2));
+
+    	QCOMPARE(RealTime::fromMilliseconds(-0), RealTime(0, 0));
+	QCOMPARE(RealTime::fromMilliseconds(-500), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime::fromMilliseconds(-1000), RealTime(-1, 0));
+	QCOMPARE(RealTime::fromMilliseconds(-1500), RealTime(-1, -ONE_BILLION/2));
+    }
+    
+    void fromTimeval()
+    {
+	struct timeval tv;
+
+	tv.tv_sec = 0; tv.tv_usec = 0;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, 0));
+	tv.tv_sec = 0; tv.tv_usec = ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, ONE_BILLION/2));
+	tv.tv_sec = 1; tv.tv_usec = 0;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(1, 0));
+	tv.tv_sec = 1; tv.tv_usec = ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(1, ONE_BILLION/2));
+
+	tv.tv_sec = 0; tv.tv_usec = -ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(0, -ONE_BILLION/2));
+	tv.tv_sec = -1; tv.tv_usec = 0;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(-1, 0));
+	tv.tv_sec = -1; tv.tv_usec = -ONE_MILLION/2;
+	QCOMPARE(RealTime::fromTimeval(tv), RealTime(-1, -ONE_BILLION/2));
+    }
+
+    void assign()
+    {
+	RealTime r;
+	r = RealTime(0, 0);
+	QCOMPARE(r, RealTime::zeroTime);
+	r = RealTime(0, ONE_BILLION/2);
+        QCOMPARE(r.sec, 0);
+        QCOMPARE(r.nsec, ONE_BILLION/2);
+	r = RealTime(-1, -ONE_BILLION/2);
+        QCOMPARE(r.sec, -1);
+        QCOMPARE(r.nsec, -ONE_BILLION/2);
+    }
+
+    void plus()
+    {
+	QCOMPARE(RealTime(0, 0) + RealTime(0, 0), RealTime(0, 0));
+
+	QCOMPARE(RealTime(0, 0) + RealTime(0, ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime(0, ONE_BILLION/2) + RealTime(0, ONE_BILLION/2), RealTime(1, 0));
+	QCOMPARE(RealTime(1, 0) + RealTime(0, ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, 0) + RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(-1, 0));
+	QCOMPARE(RealTime(-1, 0) + RealTime(0, -ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
+
+    	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(0, 0));
+	QCOMPARE(RealTime(1, 0) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2) + RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, ONE_BILLION/2) + RealTime(-1, 0), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) + RealTime(1, 0), RealTime(0, ONE_BILLION/2));
+    }
+    
+    void minus()
+    {
+	QCOMPARE(RealTime(0, 0) - RealTime(0, 0), RealTime(0, 0));
+
+	QCOMPARE(RealTime(0, 0) - RealTime(0, ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+	QCOMPARE(RealTime(0, ONE_BILLION/2) - RealTime(0, ONE_BILLION/2), RealTime(0, 0));
+	QCOMPARE(RealTime(1, 0) - RealTime(0, ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, 0) - RealTime(0, -ONE_BILLION/2), RealTime(0, ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(0, 0));
+	QCOMPARE(RealTime(-1, 0) - RealTime(0, -ONE_BILLION/2), RealTime(0, -ONE_BILLION/2));
+
+    	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(2, 0));
+	QCOMPARE(RealTime(1, 0) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2) - RealTime(0, -ONE_BILLION/2), RealTime(2, ONE_BILLION/2));
+
+	QCOMPARE(RealTime(0, ONE_BILLION/2) - RealTime(-1, 0), RealTime(1, ONE_BILLION/2));
+	QCOMPARE(RealTime(0, -ONE_BILLION/2) - RealTime(1, 0), RealTime(-1, -ONE_BILLION/2));
+    }
+
+    void negate()
+    {
+	QCOMPARE(-RealTime(0, 0), RealTime(0, 0));
+	QCOMPARE(-RealTime(1, 0), RealTime(-1, 0));
+	QCOMPARE(-RealTime(1, ONE_BILLION/2), RealTime(-1, -ONE_BILLION/2));
+	QCOMPARE(-RealTime(-1, -ONE_BILLION/2), RealTime(1, ONE_BILLION/2));
+    }
+
+    void compare()
+    {
+	int sec, nsec;
+	for (sec = -2; sec <= 2; sec += 2) {
+	    for (nsec = -1; nsec <= 1; nsec += 1) {
+		QCOMPARE(RealTime(sec, nsec) < RealTime(sec, nsec), false);
+		QCOMPARE(RealTime(sec, nsec) > RealTime(sec, nsec), false);
+		QCOMPARE(RealTime(sec, nsec) == RealTime(sec, nsec), true);
+		QCOMPARE(RealTime(sec, nsec) != RealTime(sec, nsec), false);
+		QCOMPARE(RealTime(sec, nsec) <= RealTime(sec, nsec), true);
+		QCOMPARE(RealTime(sec, nsec) >= RealTime(sec, nsec), true);
+	    }
+	}
+	RealTime prev(-3, 0);
+	for (sec = -2; sec <= 2; sec += 2) {
+	    for (nsec = -1; nsec <= 1; nsec += 1) {
+
+		RealTime curr(sec, nsec);
+
+		QCOMPARE(prev < curr, true);
+		QCOMPARE(prev > curr, false);
+		QCOMPARE(prev == curr, false);
+		QCOMPARE(prev != curr, true);
+		QCOMPARE(prev <= curr, true);
+		QCOMPARE(prev >= curr, false);
+
+		QCOMPARE(curr < prev, false);
+		QCOMPARE(curr > prev, true);
+		QCOMPARE(curr == prev, false);
+		QCOMPARE(curr != prev, true);
+		QCOMPARE(curr <= prev, false);
+		QCOMPARE(curr >= prev, true);
+
+		prev = curr;
+	    }
+	}
+    }
+
+    void frame()
+    {
+        int frames[] = {
+            0, 1, 2047, 2048, 6656,
+            32767, 32768, 44100, 44101,
+            999999999, 2000000000
+        };
+        int n = sizeof(frames)/sizeof(frames[0]);
+
+        int rates[] = {
+            1, 2, 8000, 22050,
+            44100, 44101, 192000, 2000000001
+        };
+        int m = sizeof(rates)/sizeof(rates[0]);
+
+        vector<vector<RealTime>> realTimes = {
+            { { 0, 0 }, { 1, 0 }, { 2047, 0 }, { 2048, 0 },
+              { 6656, 0 }, { 32767, 0 }, { 32768, 0 }, { 44100, 0 },
+              { 44101, 0 }, { 999999999, 0 }, { 2000000000, 0 } },
+            { { 0, 0 }, { 0, 500000000 }, { 1023, 500000000 }, { 1024, 0 },
+              { 3328, 0 }, { 16383, 500000000 }, { 16384, 0 }, { 22050, 0 },
+              { 22050, 500000000 }, { 499999999, 500000000 }, { 1000000000, 0 } },
+            { { 0, 0 }, { 0, 125000 }, { 0, 255875000 }, { 0, 256000000 },
+              { 0, 832000000 }, { 4, 95875000 }, { 4, 96000000 }, { 5, 512500000 },
+              { 5, 512625000 }, { 124999, 999875000 }, { 250000, 0 } },
+            { { 0, 0 }, { 0, 45351 }, { 0, 92834467 }, { 0, 92879819 },
+              { 0, 301859410 }, { 1, 486031746 }, { 1, 486077098 }, { 2, 0 },
+              { 2, 45351 }, { 45351, 473877551 }, { 90702, 947845805 } },
+            { { 0, 0 }, { 0, 22676 }, { 0, 46417234 }, { 0, 46439909 },
+              { 0, 150929705 }, { 0, 743015873 }, { 0, 743038549 }, { 1, 0 },
+              { 1, 22676 }, { 22675, 736938776 }, { 45351, 473922902 } },
+            { { 0, 0 }, { 0, 22675 }, { 0, 46416181 }, { 0, 46438856 },
+              { 0, 150926283 }, { 0, 742999025 }, { 0, 743021700 }, { 0, 999977325 },
+              { 1, 0 }, { 22675, 222761389 }, { 45350, 445568128 } },
+            { { 0, 0 }, { 0, 5208 }, { 0, 10661458 }, { 0, 10666667 },
+              { 0, 34666667 }, { 0, 170661458 }, { 0, 170666667 }, { 0, 229687500 },
+              { 0, 229692708 }, { 5208, 333328125 }, { 10416, 666666667 } },
+            { { 0, 0 }, { 0, 0 }, { 0, 1023 }, { 0, 1024 },
+              { 0, 3328 }, { 0, 16383 }, { 0, 16384 }, { 0, 22050 },
+              { 0, 22050 }, { 0, 499999999 }, { 1, 0 } }
+        };
+        
+        for (int i = 0; i < n; ++i) {
+            frame_type frame = frames[i];
+            for (int j = 0; j < m; ++j) {
+                int rate = rates[j];
+
+                cerr << "frame = " << frame << ", rate = " << rate << endl;
+                
+                RealTime rt = RealTime::frame2RealTime(frame, rate);
+                QCOMPARE(rt.sec, realTimes[j][i].sec);
+                QCOMPARE(rt.nsec, realTimes[j][i].nsec);
+
+                cerr << "rt = " << rt << endl;
+                cerr << "rate = " << rate << endl;
+
+                frame_type conv = RealTime::realTime2Frame(rt, rate);
+                cerr << "conv = " << conv << endl;
+                
+                rt = RealTime::frame2RealTime(-frame, rate);
+                frame_type negconv = RealTime::realTime2Frame(rt, rate);
+                cerr << "negconv = " << negconv << endl;
+
+                if (rate > ONE_BILLION) {
+                    // We no longer have enough precision in RealTime
+                    // for this absurd sample rate, so a round trip
+                    // conversion may round
+                    QVERIFY(abs(frame - conv) < 2);
+                    QVERIFY(abs(-frame - negconv) < 2);
+                } else {
+                    QCOMPARE(conv, frame);
+                    QCOMPARE(negconv, -frame);
+                }
+            }
+        }
+    }
+
+    // Vamp SDK version just has toText, which is like our own
+    // toMSText with true for its second arg
+    
+    void toText()
+    {
+        // we want to use QStrings, because then the Qt test library
+        // will print out any conflicts. The compareTexts function
+        // does this for us
+
+        int halfSec = ONE_BILLION/2; // nsec
+        
+        RealTime rt = RealTime(0, 0);
+        compareTexts(rt.toText(false), "0");
+        compareTexts(rt.toText(true), "0.000");
+
+        rt = RealTime(1, halfSec);
+        compareTexts(rt.toText(false), "1.5");
+        compareTexts(rt.toText(true), "1.500");
+
+        rt = RealTime::fromSeconds(-1.5);
+        compareTexts(rt.toText(false), "-1.5");
+        compareTexts(rt.toText(true), "-1.500");
+
+        rt = RealTime::fromSeconds(60);
+        compareTexts(rt.toText(false), "1:00");
+        compareTexts(rt.toText(true), "1:00.000");
+
+        rt = RealTime::fromSeconds(61.05);
+        compareTexts(rt.toText(false), "1:01.05");
+        compareTexts(rt.toText(true), "1:01.050");
+        
+        rt = RealTime::fromSeconds(601.05);
+        compareTexts(rt.toText(false), "10:01.05");
+        compareTexts(rt.toText(true), "10:01.050");
+        
+        rt = RealTime::fromSeconds(3600);
+        compareTexts(rt.toText(false), "1:00:00");
+        compareTexts(rt.toText(true), "1:00:00.000");
+
+        // For practical reasons our time display always rounds down
+        rt = RealTime(3599, ONE_BILLION-1);
+        compareTexts(rt.toText(false), "59:59.999");
+        compareTexts(rt.toText(true), "59:59.999");
+
+        rt = RealTime::fromSeconds(3600 * 4 + 60 * 5 + 3 + 0.01);
+        compareTexts(rt.toText(false), "4:05:03.01");
+        compareTexts(rt.toText(true), "4:05:03.010");
+
+        rt = RealTime::fromSeconds(-(3600 * 4 + 60 * 5 + 3 + 0.01));
+        compareTexts(rt.toText(false), "-4:05:03.01");
+        compareTexts(rt.toText(true), "-4:05:03.010");
+    }
+};
+
+#endif
+
--- a/base/test/files.pri	Mon Nov 14 17:54:22 2016 +0000
+++ b/base/test/files.pri	Tue Nov 15 16:12:48 2016 +0000
@@ -1,7 +1,8 @@
 TEST_HEADERS = \
 	     TestRangeMapper.h \
 	     TestPitch.h \
-	     TestRealTime.h \
+	     TestOurRealTime.h \
+	     TestVampRealTime.h \
 	     TestStringBits.h
 	     
 TEST_SOURCES += \
--- a/base/test/svcore-base-test.cpp	Mon Nov 14 17:54:22 2016 +0000
+++ b/base/test/svcore-base-test.cpp	Tue Nov 15 16:12:48 2016 +0000
@@ -13,8 +13,9 @@
 
 #include "TestRangeMapper.h"
 #include "TestPitch.h"
-#include "TestRealTime.h"
 #include "TestStringBits.h"
+#include "TestOurRealTime.h"
+#include "TestVampRealTime.h"
 
 #include <QtTest>
 
@@ -39,7 +40,12 @@
 	else ++bad;
     }
     {
-	TestRealTime t;
+        TestOurRealTime t;
+	if (QTest::qExec(&t, argc, argv) == 0) ++good;
+	else ++bad;
+    }
+    {
+        TestVampRealTime t;
 	if (QTest::qExec(&t, argc, argv) == 0) ++good;
 	else ++bad;
     }