changeset 540:f55363ecc57d

Update subrepos, build etc to match current SV code
author Chris Cannam
date Tue, 12 Feb 2019 15:02:50 +0000
parents 23e14483c32b
children fea109b93831
files .hgignore base.pri base.pro bq-files.pri configure configure.ac noconfig.pri repoint repoint-lock.json repoint-project.json repoint.pri repoint.sml src/MainWindow.cpp
diffstat 13 files changed, 309 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Sep 14 15:15:41 2018 +0100
+++ b/.hgignore	Tue Feb 12 15:02:50 2019 +0000
@@ -26,6 +26,7 @@
 svgui
 svapp
 piper-cpp
+piper-vamp-cpp
 dataquay
 bqvec
 bqfft
@@ -35,3 +36,4 @@
 icons/scalable
 chp
 pyin
+glob:.repoint*
--- a/base.pri	Fri Sep 14 15:15:41 2018 +0100
+++ b/base.pri	Tue Feb 12 15:02:50 2019 +0000
@@ -7,7 +7,10 @@
 	bqresample \
 	bqaudioio \
 	bqaudioio/bqaudioio \
-	piper-cpp \
+	bqaudiostream \
+	bqaudiostream/bqaudiostream \
+	bqthingfactory \
+	piper-vamp-cpp \
 	checker \
 	checker/checker \
 	dataquay \
@@ -31,4 +34,4 @@
 # Defines for Dataquay
 DEFINES += USE_SORD
 
-CONFIG += qt thread warn_on stl rtti exceptions c++11
+CONFIG += qt thread warn_on stl rtti exceptions
--- a/base.pro	Fri Sep 14 15:15:41 2018 +0100
+++ b/base.pro	Tue Feb 12 15:02:50 2019 +0000
@@ -20,6 +20,10 @@
 OBJECTS_DIR = o
 MOC_DIR = o
 
+exists(repoint.pri) {
+    include(repoint.pri)
+}
+
 include(bq-files.pri)
 include(vamp-plugin-sdk-files.pri)
 include(svcore/files.pri)
--- a/bq-files.pri	Fri Sep 14 15:15:41 2018 +0100
+++ b/bq-files.pri	Tue Feb 12 15:02:50 2019 +0000
@@ -23,7 +23,11 @@
 	bqaudioio/src/JACKAudioIO.h \
 	bqaudioio/src/Log.h \
 	bqaudioio/src/PortAudioIO.h \
-	bqaudioio/src/PulseAudioIO.h
+	bqaudioio/src/PulseAudioIO.h \
+        bqaudiostream/bqaudiostream/AudioReadStream.h \
+        bqaudiostream/bqaudiostream/AudioReadStreamFactory.h \
+        bqaudiostream/bqaudiostream/Exceptions.h \
+        bqthingfactory/bqthingfactory/ThingFactory.h
 
 BQ_SOURCES += \
 	bqvec/src/Allocators.cpp \
@@ -38,5 +42,8 @@
 	bqaudioio/src/PulseAudioIO.cpp \
 	bqaudioio/src/ResamplerWrapper.cpp \
 	bqaudioio/src/SystemPlaybackTarget.cpp \
-	bqaudioio/src/SystemRecordSource.cpp
+	bqaudioio/src/SystemRecordSource.cpp \
+        bqaudiostream/src/AudioReadStream.cpp \
+        bqaudiostream/src/AudioReadStreamFactory.cpp \
+        bqaudiostream/src/AudioStreamExceptions.cpp
 
--- a/configure	Fri Sep 14 15:15:41 2018 +0100
+++ b/configure	Tue Feb 12 15:02:50 2019 +0000
@@ -632,6 +632,8 @@
 PERL
 X11_LIBS
 X11_CFLAGS
+opus_LIBS
+opus_CFLAGS
 id3tag_LIBS
 id3tag_CFLAGS
 mad_LIBS
@@ -780,6 +782,8 @@
 mad_LIBS
 id3tag_CFLAGS
 id3tag_LIBS
+opus_CFLAGS
+opus_LIBS
 X11_CFLAGS
 X11_LIBS'
 
@@ -1457,6 +1461,8 @@
   id3tag_CFLAGS
               C compiler flags for id3tag, overriding pkg-config
   id3tag_LIBS linker flags for id3tag, overriding pkg-config
+  opus_CFLAGS C compiler flags for opus, overriding pkg-config
+  opus_LIBS   linker flags for opus, overriding pkg-config
   X11_CFLAGS  C compiler flags for X11, overriding pkg-config
   X11_LIBS    linker flags for X11, overriding pkg-config
 
@@ -7071,6 +7077,161 @@
 fi
 
 
+SV_MODULE_MODULE=opus
+SV_MODULE_VERSION_TEST="opusfile"
+SV_MODULE_HEADER=opus/opusfile.h
+SV_MODULE_LIB=opusfile
+SV_MODULE_FUNC=op_read_float
+SV_MODULE_HAVE=HAVE_$(echo opus | tr 'a-z' 'A-Z')
+SV_MODULE_FAILED=1
+if test -n "$opus_LIBS" ; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: User set ${SV_MODULE_MODULE}_LIBS explicitly, skipping test for $SV_MODULE_MODULE" >&5
+$as_echo "$as_me: User set ${SV_MODULE_MODULE}_LIBS explicitly, skipping test for $SV_MODULE_MODULE" >&6;}
+   CXXFLAGS="$CXXFLAGS $opus_CFLAGS"
+   LIBS="$LIBS $opus_LIBS"
+   SV_MODULE_FAILED=""
+fi
+if test -z "$SV_MODULE_VERSION_TEST" ; then
+   SV_MODULE_VERSION_TEST=$SV_MODULE_MODULE
+fi
+if test -n "$SV_MODULE_FAILED" && test -n "$PKG_CONFIG"; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for opus" >&5
+$as_echo_n "checking for opus... " >&6; }
+
+if test -n "$opus_CFLAGS"; then
+    pkg_cv_opus_CFLAGS="$opus_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SV_MODULE_VERSION_TEST\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "$SV_MODULE_VERSION_TEST") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_opus_CFLAGS=`$PKG_CONFIG --cflags "$SV_MODULE_VERSION_TEST" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$opus_LIBS"; then
+    pkg_cv_opus_LIBS="$opus_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SV_MODULE_VERSION_TEST\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "$SV_MODULE_VERSION_TEST") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_opus_LIBS=`$PKG_CONFIG --libs "$SV_MODULE_VERSION_TEST" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        opus_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$SV_MODULE_VERSION_TEST" 2>&1`
+        else
+	        opus_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$SV_MODULE_VERSION_TEST" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$opus_PKG_ERRORS" >&5
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: Failed to find optional module $SV_MODULE_MODULE using pkg-config, trying again by old-fashioned means" >&5
+$as_echo "$as_me: Failed to find optional module $SV_MODULE_MODULE using pkg-config, trying again by old-fashioned means" >&6;}
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: Failed to find optional module $SV_MODULE_MODULE using pkg-config, trying again by old-fashioned means" >&5
+$as_echo "$as_me: Failed to find optional module $SV_MODULE_MODULE using pkg-config, trying again by old-fashioned means" >&6;}
+else
+	opus_CFLAGS=$pkg_cv_opus_CFLAGS
+	opus_LIBS=$pkg_cv_opus_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	HAVES="$HAVES $SV_MODULE_HAVE";CXXFLAGS="$CXXFLAGS $opus_CFLAGS";LIBS="$LIBS $opus_LIBS";SV_MODULE_FAILED=""
+fi
+fi
+if test -n "$SV_MODULE_FAILED"; then
+   as_ac_Header=`$as_echo "ac_cv_header_$SV_MODULE_HEADER" | $as_tr_sh`
+ac_fn_cxx_check_header_mongrel "$LINENO" "$SV_MODULE_HEADER" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  HAVES="$HAVES $SV_MODULE_HAVE";SV_MODULE_FAILED=""
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: Failed to find header $SV_MODULE_HEADER for optional module $SV_MODULE_MODULE" >&5
+$as_echo "$as_me: Failed to find header $SV_MODULE_HEADER for optional module $SV_MODULE_MODULE" >&6;}
+fi
+
+
+   if test -z "$SV_MODULE_FAILED"; then
+      if test -n "$SV_MODULE_LIB"; then
+           as_ac_Lib=`$as_echo "ac_cv_lib_$SV_MODULE_LIB''_$SV_MODULE_FUNC" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $SV_MODULE_FUNC in -l$SV_MODULE_LIB" >&5
+$as_echo_n "checking for $SV_MODULE_FUNC in -l$SV_MODULE_LIB... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$SV_MODULE_LIB  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $SV_MODULE_FUNC ();
+int
+main ()
+{
+return $SV_MODULE_FUNC ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  eval "$as_ac_Lib=yes"
+else
+  eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+  LIBS="$LIBS -l$SV_MODULE_LIB"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: Failed to find library $SV_MODULE_LIB for optional module $SV_MODULE_MODULE" >&5
+$as_echo "$as_me: Failed to find library $SV_MODULE_LIB for optional module $SV_MODULE_MODULE" >&6;}
+fi
+
+      fi
+   fi
+fi
+
+
 # Link in -lX11 if it exists -- this is for the X error handler
 
 SV_MODULE_MODULE=X11
--- a/configure.ac	Fri Sep 14 15:15:41 2018 +0100
+++ b/configure.ac	Tue Feb 12 15:02:50 2019 +0000
@@ -96,6 +96,7 @@
 SV_MODULE_OPTIONAL([fishsound],[fishsound >= 1.0.0],[fishsound/fishsound.h],[fishsound],[fish_sound_new])
 SV_MODULE_OPTIONAL([mad],[mad >= 0.15.0],[mad.h],[mad],[mad_decoder_init])
 SV_MODULE_OPTIONAL([id3tag],[id3tag >= 0.15.0],[id3tag.h],[id3tag],[id3_tag_new])
+SV_MODULE_OPTIONAL([opus],[opusfile],[opus/opusfile.h],[opusfile],[op_read_float])
 
 # Link in -lX11 if it exists -- this is for the X error handler
 SV_MODULE_OPTIONAL([X11],[x11 >= 1.0.0],[X11/X.h],[x11],[XGetErrorText])
--- a/noconfig.pri	Fri Sep 14 15:15:41 2018 +0100
+++ b/noconfig.pri	Tue Feb 12 15:02:50 2019 +0000
@@ -1,9 +1,13 @@
+
+CONFIG += c++14
 
 CONFIG += release
 
 #CONFIG -= release
 #CONFIG += debug
 
+PREFIX_PATH = /usr/local
+
 DEFINES += NDEBUG BUILD_RELEASE
 DEFINES += NO_TIMING NO_HIT_COUNTS
 
@@ -20,6 +24,7 @@
 	HAVE_LIBLO \
 	HAVE_MAD \
 	HAVE_ID3TAG \
+        HAVE_OPUS \
 	HAVE_PORTAUDIO
 
 # Default set of libs for the above. Config sections below may update
@@ -37,6 +42,8 @@
 	-lvorbis \
 	-lvorbisenc \
 	-lvorbisfile \
+        -lopusfile \
+        -lopus \
 	-logg \
 	-lmad \
 	-lid3tag \
@@ -65,6 +72,8 @@
     DEFINES -= HAVE_LIBLO
     LIBS -= -llo
     
+    # (We don't have MediaFoundation support either, with this build sadly)
+    
     LIBS += -lwinmm -lws2_32
 }
 
@@ -75,7 +84,7 @@
     # we want to do 32-bit builds with MSVC as well, then we'll
     # need to add a way to distinguish the two.
     
-    INCLUDEPATH += $$PWD/sv-dependency-builds/win64-msvc/include
+    INCLUDEPATH += $$PWD/sv-dependency-builds/win64-msvc/include $$PWD/sv-dependency-builds/win64-msvc/include/opus
 
 ## This seems to be intruding even when we're supposed to be release
 #    CONFIG(debug) {
@@ -88,13 +97,12 @@
             -L$$PWD/sv-dependency-builds/win64-msvc/lib
     }
 
-    DEFINES += NOMINMAX _USE_MATH_DEFINES CAPNP_LITE
+    DEFINES += NOMINMAX _USE_MATH_DEFINES CAPNP_LITE HAVE_MEDIAFOUNDATION
 
     QMAKE_CXXFLAGS_RELEASE += -fp:fast -gl
     QMAKE_LFLAGS_RELEASE += -ltcg
 
-    # No Ogg/FLAC support in the sndfile build on this platform yet
-    LIBS -= -lFLAC -logg -lvorbis -lvorbisenc -lvorbisfile
+    LIBS -= -lFLAC -lvorbis -lvorbisenc -lvorbisfile
 
     # These have different names
     LIBS -= -lsord-0 -lserd-0
@@ -104,17 +112,18 @@
     DEFINES -= HAVE_LIBLO
     LIBS -= -llo
     
-    LIBS += -ladvapi32 -lwinmm -lws2_32
+    LIBS += -lmfplat -lmfreadwrite -lmfuuid -lpropsys -ladvapi32 -lwinmm -lws2_32
 }
 
 macx* {
 
     # All Mac builds are 64-bit these days.
 
-    INCLUDEPATH += $$PWD/sv-dependency-builds/osx/include
+    INCLUDEPATH += $$PWD/sv-dependency-builds/osx/include $$PWD/sv-dependency-builds/osx/include/opus
     LIBS += -L$$PWD/sv-dependency-builds/osx/lib -L$$PWD
 
-    QMAKE_CXXFLAGS_RELEASE += -O3 -ffast-math
+    QMAKE_CXXFLAGS_RELEASE += -O3 -ffast-math -flto
+    QMAKE_LFLAGS_RELEASE += -O3 -flto
 
     DEFINES += HAVE_COREAUDIO HAVE_VDSP
     LIBS += \
--- a/repoint	Fri Sep 14 15:15:41 2018 +0100
+++ b/repoint	Tue Feb 12 15:02:50 2019 +0000
@@ -58,7 +58,7 @@
     # That is fixed in v5.7.1, so we could promote it up the order
     # again at some point in future
     elif echo | poly -v 2>/dev/null | grep -q 'Poly/ML'; then
-	sml="poly"
+	sml="polyml"
     elif mlton 2>&1 | grep -q 'MLton'; then
 	sml="mlton"
     # MLKit is at the bottom because it leaves compiled files around
@@ -109,7 +109,7 @@
 done
 
 case "$sml" in
-    poly)
+    polyml)
         if [ -n "$local_install" ] && polyc --help >/dev/null 2>&1 ; then
             if [ ! -x "$gen_out" ]; then
                 polyc -o "$gen_out" "$program"
--- a/repoint-lock.json	Fri Sep 14 15:15:41 2018 +0100
+++ b/repoint-lock.json	Tue Feb 12 15:02:50 2019 +0000
@@ -1,43 +1,49 @@
 {
   "libraries": {
     "vamp-plugin-sdk": {
-      "pin": "da86fb0bccb3"
+      "pin": "b650289c47b4"
     },
     "svcore": {
-      "pin": "a92e94215863"
+      "pin": "d83ab62cdc28"
     },
     "svgui": {
-      "pin": "8068a0bee550"
+      "pin": "2487521e857b"
     },
     "svapp": {
-      "pin": "9e15607531b2"
+      "pin": "6fd0ebfd2bbe"
     },
     "checker": {
-      "pin": "2e8a5f665a07"
+      "pin": "5c60e26e16ca"
     },
-    "piper-cpp": {
-      "pin": "44cb74e186a703e7e6ce403aa295913a87b88d62"
+    "piper-vamp-cpp": {
+      "pin": "0e3328c6091f59c912e25bc392a7dc75182be1c7"
     },
     "dataquay": {
       "pin": "807b55408d9e"
     },
     "bqvec": {
-      "pin": "3c9de9e7f6e8"
+      "pin": "be1ce11183f4"
     },
     "bqfft": {
       "pin": "a766fe47501b"
     },
     "bqresample": {
-      "pin": "a9a5555d9b6d"
+      "pin": "f5dee7d40378"
     },
     "bqaudioio": {
-      "pin": "138a7a8b546b"
+      "pin": "8c4162878ae6"
+    },
+    "bqaudiostream": {
+      "pin": "87dac9687fa4"
+    },
+    "bqthingfactory": {
+      "pin": "7686116dcdd5"
     },
     "sv-dependency-builds": {
-      "pin": "f1a9b270e043"
+      "pin": "2f2b27544483"
     },
     "icons/scalable": {
-      "pin": "1c6516ba7fc1"
+      "pin": "1c8844bfa946"
     },
     "pyin": {
       "pin": "550d5f186abb"
--- a/repoint-project.json	Fri Sep 14 15:15:41 2018 +0100
+++ b/repoint-project.json	Tue Feb 12 15:02:50 2019 +0000
@@ -31,11 +31,10 @@
 	    "service": "soundsoftware",
 	    "repository": "vamp-plugin-load-checker"
         },
-        "piper-cpp": {
+        "piper-vamp-cpp": {
             "vcs": "git",
 	    "service": "github",
-	    "owner": "piper-audio",
-            "repository": "piper-vamp-cpp"
+	    "owner": "piper-audio"
         },
         "dataquay": {
             "vcs": "hg",
@@ -62,6 +61,16 @@
             "service": "bitbucket",
             "owner": "breakfastquay"
         },
+        "bqaudiostream": {
+            "vcs": "hg",
+            "service": "bitbucket",
+            "owner": "breakfastquay"
+        },
+        "bqthingfactory": {
+            "vcs": "hg",
+            "service": "bitbucket",
+            "owner": "breakfastquay"
+        },
         "sv-dependency-builds": {
             "vcs": "hg",
 	    "service": "soundsoftware"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/repoint.pri	Tue Feb 12 15:02:50 2019 +0000
@@ -0,0 +1,7 @@
+
+repoint.target = $$PWD/.repoint.point
+repoint.depends = $$PWD/repoint-project.json $$PWD/repoint-lock.json
+repoint.commands = $$PWD/repoint install --directory $$PWD
+
+QMAKE_EXTRA_TARGETS += repoint
+PRE_TARGETDEPS += $$repoint.target
--- a/repoint.sml	Fri Sep 14 15:15:41 2018 +0100
+++ b/repoint.sml	Tue Feb 12 15:02:50 2019 +0000
@@ -38,7 +38,7 @@
     authorization.
 *)
 
-val repoint_version = "0.9.98"
+val repoint_version = "1.1"
 
 
 datatype vcs =
@@ -136,6 +136,7 @@
 structure RepointFilenames = struct
     val project_file = "repoint-project.json"
     val project_lock_file = "repoint-lock.json"
+    val project_completion_file = ".repoint.point"
     val user_config_file = ".repoint.json"
     val archive_dir = ".repoint-archive"
 end
@@ -215,6 +216,7 @@
     val nonempty_dir_exists : string -> bool
     val project_spec_path : string -> string
     val project_lock_path : string -> string
+    val project_completion_path : string -> string
     val verbose : unit -> bool
 end = struct
 
@@ -272,6 +274,9 @@
     fun project_lock_path rootpath =
         project_file_path rootpath (RepointFilenames.project_lock_file)
 
+    fun project_completion_path rootpath =
+        project_file_path rootpath (RepointFilenames.project_completion_file)
+
     fun trim str =
         hd (String.fields (fn x => x = #"\n" orelse x = #"\r") str)
             
@@ -2420,7 +2425,14 @@
     in
         JsonBits.save_json_to lock_file lock_json
     end
-        
+
+fun checkpoint_completion_file rootpath =
+    let val completion_file = FileBits.project_completion_path rootpath
+        val stream = TextIO.openOut completion_file
+    in
+        TextIO.closeOut stream
+    end
+                                                               
 fun pad_to n str =
     if n <= String.size str then str
     else pad_to n (str ^ " ")
@@ -2586,8 +2598,12 @@
         val _ = if List.exists (fn (_, OK _) => true | _ => false) outcomes
                 then lock_project project
                 else OS.Process.success
+        val return_code = return_code_for outcomes
     in
-        return_code_for outcomes
+        if OS.Process.isSuccess return_code
+        then checkpoint_completion_file (#rootpath context)
+        else ();
+        return_code
     end
     
 fun load_local_project pintype =
@@ -2625,18 +2641,23 @@
 fun usage () =
     (print "\nRepoint ";
      version ();
-     print ("\nA simple manager for third-party source code dependencies.\n\n"
+     print ("\n  A simple manager for third-party source code dependencies.\n"
+            ^ "  http://all-day-breakfast.com/repoint/\n\n"
             ^ "Usage:\n\n"
-            ^ "  repoint <command>\n\n"
+            ^ "  repoint <command> [<options>]\n\n"
             ^ "where <command> is one of:\n\n"
             ^ "  status   print quick report on local status only, without using network\n"
             ^ "  review   check configured libraries against their providers, and report\n"
             ^ "  install  update configured libraries according to project specs and lock file\n"
             ^ "  update   update configured libraries and lock file according to project specs\n"
-            ^ "  lock     update lock file to match local library status\n"
-            ^ "  archive  pack up project and all libraries into an archive file\n"
-            ^ "           (invoke as 'repoint archive target-file.tar.gz')\n"
-            ^ "  version  print the Repoint version number and exit\n\n");
+            ^ "  lock     rewrite lock file to match local library status\n"
+            ^ "  archive  pack up project and all libraries into an archive file:\n"
+            ^ "           invoke as 'repoint archive targetfile.tar.gz --exclude unwanted.txt'\n"
+            ^ "  version  print the Repoint version number and exit\n\n"
+            ^ "and <options> may include:\n\n"
+            ^ "  --directory <dir>\n"
+            ^ "           change to directory <dir> before doing anything; in particular,\n"
+            ^ "           expect to find project spec file in that directory\n\n");
     OS.Process.failure)
 
 fun archive target args =
@@ -2647,8 +2668,26 @@
         with_local_project USE_LOCKFILE (Archive.archive (target, xs))
       | _ => usage ()
 
+fun handleSystemArgs args =
+    let fun handleSystemArgs' leftover args =
+            case args of
+                "--directory"::dir::rest =>
+                (OS.FileSys.chDir dir;
+                 handleSystemArgs' leftover rest)
+              | arg::rest =>
+                handleSystemArgs' (leftover @ [arg]) rest
+              | [] => leftover
+    in
+        OK (handleSystemArgs' [] args)
+        handle e => ERROR (exnMessage e)
+    end
+                   
 fun repoint args =
-    let val return_code = 
+    case handleSystemArgs args of
+        ERROR e => (print ("Error: " ^ e ^ "\n");
+                    OS.Process.exit OS.Process.failure)
+      | OK args => 
+        let val return_code = 
             case args of
                 ["review"] => review ()
               | ["status"] => status ()
@@ -2660,10 +2699,9 @@
               | arg::_ => (print ("Error: unknown argument \"" ^ arg ^ "\"\n");
                            usage ())
               | _ => usage ()
-    in
-        OS.Process.exit return_code;
-        ()
-    end
+        in
+            OS.Process.exit return_code
+        end
         
 fun main () =
     repoint (CommandLine.arguments ())
--- a/src/MainWindow.cpp	Fri Sep 14 15:15:41 2018 +0100
+++ b/src/MainWindow.cpp	Tue Feb 12 15:02:50 2019 +0000
@@ -3265,10 +3265,16 @@
 
     // The step is supposed to scale and be as wide as a step of 
     // m_defaultFfwdRwdStep seconds at zoom level 720 and sr = 44100
-    int framesPerPixel = m_viewManager->getGlobalZoom();
-
-    double defaultZoom = (720 * 44100) / sr;
-    double scaler = framesPerPixel / defaultZoom;
+    
+    ZoomLevel zoom = m_viewManager->getGlobalZoom();
+    double framesPerPixel = 1.0;
+    if (zoom.zone == ZoomLevel::FramesPerPixel) {
+        framesPerPixel = zoom.level;
+    } else {
+        framesPerPixel = 1.0 / zoom.level;
+    }
+    double defaultFramesPerPixel = (720 * 44100) / sr;
+    double scaler = framesPerPixel / defaultFramesPerPixel;
     RealTime step = m_defaultFfwdRwdStep * scaler;
     
     frame = RealTime::realTime2Frame
@@ -3306,10 +3312,16 @@
 
     // The step is supposed to scale and be as wide as a step of 
     // m_defaultFfwdRwdStep seconds at zoom level 720 and sr = 44100
-    int framesPerPixel = m_viewManager->getGlobalZoom();
-
-    double defaultZoom = (720 * 44100) / sr;
-    double scaler = framesPerPixel / defaultZoom;
+
+    ZoomLevel zoom = m_viewManager->getGlobalZoom();
+    double framesPerPixel = 1.0;
+    if (zoom.zone == ZoomLevel::FramesPerPixel) {
+        framesPerPixel = zoom.level;
+    } else {
+        framesPerPixel = 1.0 / zoom.level;
+    }
+    double defaultFramesPerPixel = (720 * 44100) / sr;
+    double scaler = framesPerPixel / defaultFramesPerPixel;
     RealTime step = m_defaultFfwdRwdStep * scaler;
 
     frame = RealTime::realTime2Frame